diff --git a/backend/tests/app/tests/test_common_geom.clj b/backend/tests/app/tests/test_common_geom.clj new file mode 100644 index 000000000..a333c3275 --- /dev/null +++ b/backend/tests/app/tests/test_common_geom.clj @@ -0,0 +1,94 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.tests.test_common_geom + (:require + [clojure.test :as t] + [app.common.geom.point :as gpt] + [app.common.geom.matrix :as gmt])) + +(t/deftest point-constructors-test + (t/testing "Create point with both coordinates" + (let [p (gpt/point 1 2)] + (t/is (= (:x p) 1)) + (t/is (= (:y p) 2)))) + + (t/testing "Create point with single coordinate" + (let [p (gpt/point 1)] + (t/is (= (:x p) 1)) + (t/is (= (:y p) 1)))) + + (t/testing "Create empty point" + (let [p (gpt/point)] + (t/is (= (:x p) 0)) + (t/is (= (:y p) 0))))) + +(t/deftest point-add-test + (t/testing "Adds two points together" + (let [p1 (gpt/point 1 1) + p2 (gpt/point 2 2) + p3 (gpt/add p1 p2)] + (t/is (= (:x p3) 3)) + (t/is (= (:y p3) 3))))) + +(t/deftest point-subtract-test + (t/testing "Point substraction" + (let [p1 (gpt/point 3 3) + p2 (gpt/point 2 2) + p3 (gpt/subtract p1 p2)] + (t/is (= (:x p3) 1)) + (t/is (= (:y p3) 1))))) + +(t/deftest point-distance-test + (let [p1 (gpt/point 0 0) + p2 (gpt/point 10 0) + d (gpt/distance p1 p2)] + (t/is (number? d)) + (t/is (= d 10.0)))) + +(t/deftest point-length-test + (let [p1 (gpt/point 10 0) + ln (gpt/length p1)] + (t/is (number? ln)) + (t/is (= ln 10.0)))) + +(t/deftest point-angle-test + (t/testing "Get angle a 90 degree angle" + (let [p1 (gpt/point 0 10) + angle (gpt/angle p1)] + (t/is (number? angle)) + (t/is (= angle 90.0)))) + + (t/testing "Get 45 degree angle" + (let [p1 (gpt/point 0 10) + p2 (gpt/point 10 10) + angle (gpt/angle-with-other p1 p2)] + (t/is (number? angle)) + (t/is (= angle 45.0))))) + +(t/deftest matrix-constructors-test + (let [m (gmt/matrix)] + (t/is (= (str m) "matrix(1,0,0,1,0,0)"))) + (let [m (gmt/matrix 1 1 1 2 2 2)] + (t/is (= (str m) "matrix(1,1,1,2,2,2)")))) + +(t/deftest matrix-translate-test + (let [m (-> (gmt/matrix) + (gmt/translate (gpt/point 2 10)))] + (t/is (= (str m) "matrix(1,0,0,1,2,10)")))) + +(t/deftest matrix-scale-test + (let [m (-> (gmt/matrix) + (gmt/scale (gpt/point 2)))] + (t/is (= (str m) "matrix(2,0,0,2,0,0)")))) + +(t/deftest matrix-rotate-test + (let [m (-> (gmt/matrix) + (gmt/rotate 10))] + (t/is (= (str m) "matrix(0.984807753012208,0.17364817766693033,-0.17364817766693033,0.984807753012208,0,0)")))) diff --git a/backend/tests/app/tests/test_common_geom_shapes.clj b/backend/tests/app/tests/test_common_geom_shapes.clj new file mode 100644 index 000000000..96fb1e669 --- /dev/null +++ b/backend/tests/app/tests/test_common_geom_shapes.clj @@ -0,0 +1,179 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.tests.test-common-geom-shapes + (:require + [app.common.geom.matrix :as gmt] + [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] + [app.common.pages :refer [make-minimal-shape]] + [clojure.test :as t])) + +(def default-path [{:command :move-to :params {:x 0 :y 0}} + {:command :line-to :params {:x 20 :y 20}} + {:command :line-to :params {:x 30 :y 30}} + {:command :curve-to :params {:x 40 :y 40 :c1x 35 :c1y 35 :c2x 45 :c2y 45}} + {:command :close-path}]) + +(defn add-path-data [shape] + (let [content (:content shape default-path) + selrect (gsh/content->selrect content) + points (gsh/rect->points selrect)] + (assoc shape + :content content + :selrect selrect + :points points))) + +(defn add-rect-data [shape] + (let [selrect (gsh/rect->selrect shape) + points (gsh/rect->points selrect)] + (assoc shape + :selrect selrect + :points points))) + +(defn create-test-shape + ([type] (create-test-shape type {})) + ([type params] + (-> (make-minimal-shape type) + (merge params) + (cond-> + (= type :path) (add-path-data) + (not= type :path) (add-rect-data))))) + + +(t/deftest transform-shape-tests + (t/testing "Shape without modifiers should stay the same" + (t/are [type] + (let [shape-before (create-test-shape type) + shape-after (gsh/transform-shape shape-before)] + (= shape-before shape-after)) + + :rect :path)) + + + (t/testing "Transform shape with translation modifiers" + (t/are [type] + (let [modifiers {:displacement (gmt/translate-matrix (gpt/point 10 -10))}] + (let [shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/is (not= shape-before shape-after)) + + (t/is (== (get-in shape-before [:selrect :x]) + (- 10 (get-in shape-after [:selrect :x])))) + + (t/is (== (get-in shape-before [:selrect :y]) + (+ 10 (get-in shape-after [:selrect :y])))) + + (t/is (== (get-in shape-before [:selrect :width]) + (get-in shape-after [:selrect :width]))) + + (t/is (== (get-in shape-before [:selrect :height]) + (get-in shape-after [:selrect :height]))))) + + :rect :path)) + + (t/testing "Transform with empty translation" + (t/are [type] + (let [modifiers {:displacement (gmt/matrix)} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/are [prop] + (t/is (== (get-in shape-before [:selrect prop]) + (get-in shape-after [:selrect prop]))) + :x :y :width :height :x1 :y1 :x2 :y2)) + :rect :path)) + + (t/testing "Transform shape with resize modifiers" + (t/are [type] + (let [modifiers {:resize-origin (gpt/point 0 0) + :resize-vector (gpt/point 2 2) + :resize-transform (gmt/matrix)} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/is (not= shape-before shape-after)) + + (t/is (== (get-in shape-before [:selrect :x]) + (get-in shape-after [:selrect :x]))) + + (t/is (== (get-in shape-before [:selrect :y]) + (get-in shape-after [:selrect :y]))) + + (t/is (== (* 2 (get-in shape-before [:selrect :width])) + (get-in shape-after [:selrect :width]))) + + (t/is (== (* 2 (get-in shape-before [:selrect :height])) + (get-in shape-after [:selrect :height])))) + :rect :path)) + + (t/testing "Transform with empty resize" + (t/are [type] + (let [modifiers {:resize-origin (gpt/point 0 0) + :resize-vector (gpt/point 1 1) + :resize-transform (gmt/matrix)} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/are [prop] + (t/is (== (get-in shape-before [:selrect prop]) + (get-in shape-after [:selrect prop]))) + :x :y :width :height :x1 :y1 :x2 :y2)) + :rect :path)) + + (t/testing "Transform with resize=0" + (t/are [type] + (let [modifiers {:resize-origin (gpt/point 0 0) + :resize-vector (gpt/point 0 0) + :resize-transform (gmt/matrix)} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/is (> (get-in shape-before [:selrect :width]) + (get-in shape-after [:selrect :width]))) + (t/is (> (get-in shape-after [:selrect :width]) 0)) + + (t/is (> (get-in shape-before [:selrect :height]) + (get-in shape-after [:selrect :height]))) + (t/is (> (get-in shape-after [:selrect :height]) 0))) + :rect :path)) + + (t/testing "Transform shape with rotation modifiers" + (t/are [type] + (let [modifiers {:rotation 30} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/is (not= shape-before shape-after)) + + (t/is (not (== (get-in shape-before [:selrect :x]) + (get-in shape-after [:selrect :x])))) + + (t/is (not (== (get-in shape-before [:selrect :y]) + (get-in shape-after [:selrect :y]))))) + :rect :path)) + + (t/testing "Transform shape with rotation = 0 should leave equal selrect" + (t/are [type] + (let [modifiers {:rotation 0} + shape-before (create-test-shape type {:modifiers modifiers}) + shape-after (gsh/transform-shape shape-before)] + (t/are [prop] + (t/is (== (get-in shape-before [:selrect prop]) + (get-in shape-after [:selrect prop]))) + :x :y :width :height :x1 :y1 :x2 :y2)) + :rect :path)) + + (t/testing "Transform shape with invalid selrect fails gracefuly" + (t/are [type selrect] + (let [modifiers {:displacement (gmt/matrix)} + shape-before (-> (create-test-shape type {:modifiers modifiers}) + (assoc :selrect selrect)) + shape-after (gsh/transform-shape shape-before)] + (= (:selrect shape-before) (:selrect shape-after))) + + :rect {:x 0 :y 0 :width ##Inf :height ##Inf} + :path {:x 0 :y 0 :width ##Inf :height ##Inf} + :rect nil + :path nil))) diff --git a/common/app/common/geom/shapes/path.cljc b/common/app/common/geom/shapes/path.cljc index e2fa26bc8..08378b220 100644 --- a/common/app/common/geom/shapes/path.cljc +++ b/common/app/common/geom/shapes/path.cljc @@ -102,7 +102,6 @@ (let [calc-extremities (fn [command prev] (case (:command command) - :close-path [] :move-to [(command->point command)] ;; If it's a line we add the beginning point and endpoint @@ -116,7 +115,8 @@ (curve-extremities (command->point prev) (command->point command) (command->point command :c1) - (command->point command :c2))))) + (command->point command :c2))) + [])) extremities (mapcat calc-extremities content diff --git a/common/app/common/geom/shapes/rect.cljc b/common/app/common/geom/shapes/rect.cljc index b748492da..c788bb363 100644 --- a/common/app/common/geom/shapes/rect.cljc +++ b/common/app/common/geom/shapes/rect.cljc @@ -13,6 +13,10 @@ [app.common.geom.shapes.common :as gco])) (defn rect->points [{:keys [x y width height]}] + (assert (number? x)) + (assert (number? y)) + (assert (and (number? width) (> width 0))) + (assert (and (number? height) (> height 0))) [(gpt/point x y) (gpt/point (+ x width) y) (gpt/point (+ x width) (+ y height)) diff --git a/frontend/tests/app/test_util_geom.cljs b/frontend/tests/app/test_util_geom.cljs deleted file mode 100644 index 3fdf0dc5e..000000000 --- a/frontend/tests/app/test_util_geom.cljs +++ /dev/null @@ -1,83 +0,0 @@ -(ns app.test-util-geom - (:require [cljs.test :as t :include-macros true] - [cljs.pprint :refer [pprint]] - [app.common.geom.point :as gpt] - [app.common.geom.matrix :as gmt])) - -(t/deftest point-constructors-test - (let [p (gpt/point 1 2)] - (t/is (= (:x p) 1)) - (t/is (= (:y p) 2))) - - (let [p (gpt/point 1)] - (t/is (= (:x p) 1)) - (t/is (= (:y p) 1))) - - (let [p (gpt/point)] - (t/is (= (:x p) 0)) - (t/is (= (:y p) 0)))) - -;; (t/deftest point-rotate-test -;; (let [p1 (gpt/point 10 0) -;; p2 (gpt/rotate p1 90)] -;; (t/is (= (:x p2) 0)) -;; (t/is (= (:y p2) 10)))) - -(t/deftest point-add-test - (let [p1 (gpt/point 1 1) - p2 (gpt/point 2 2) - p3 (gpt/add p1 p2)] - (t/is (= (:x p3) 3)) - (t/is (= (:y p3) 3)))) - -(t/deftest point-subtract-test - (let [p1 (gpt/point 3 3) - p2 (gpt/point 2 2) - p3 (gpt/subtract p1 p2)] - (t/is (= (:x p3) 1)) - (t/is (= (:y p3) 1)))) - -(t/deftest point-distance-test - (let [p1 (gpt/point 0 0) - p2 (gpt/point 10 0) - d (gpt/distance p1 p2)] - (t/is (number? d)) - (t/is (= d 10)))) - -(t/deftest point-length-test - (let [p1 (gpt/point 10 0) - ln (gpt/length p1)] - (t/is (number? ln)) - (t/is (= ln 10)))) - -(t/deftest point-angle-test - (let [p1 (gpt/point 0 10) - angle (gpt/angle p1)] - (t/is (number? angle)) - (t/is (= angle 90))) - (let [p1 (gpt/point 0 10) - p2 (gpt/point 10 10) - angle (gpt/angle-with-other p1 p2)] - (t/is (number? angle)) - (t/is (= angle 45)))) - -(t/deftest matrix-constructors-test - (let [m (gmt/matrix)] - (t/is (= (str m) "matrix(1,0,0,1,0,0)"))) - (let [m (gmt/matrix 1 1 1 2 2 2)] - (t/is (= (str m) "matrix(1,1,1,2,2,2)")))) - -(t/deftest matrix-translate-test - (let [m (-> (gmt/matrix) - (gmt/translate (gpt/point 2 10)))] - (t/is (= (str m) "matrix(1,0,0,1,2,10)")))) - -(t/deftest matrix-scale-test - (let [m (-> (gmt/matrix) - (gmt/scale (gpt/point 2)))] - (t/is (= (str m) "matrix(2,0,0,2,0,0)")))) - -(t/deftest matrix-rotate-test - (let [m (-> (gmt/matrix) - (gmt/rotate 10))] - (t/is (= (str m) "matrix(0.984807753012208,0.17364817766693033,-0.17364817766693033,0.984807753012208,0,0)"))))