diff --git a/src/uxbox/util/geom/matrix.cljs b/src/uxbox/util/geom/matrix.cljs new file mode 100644 index 0000000000..22b1344218 --- /dev/null +++ b/src/uxbox/util/geom/matrix.cljs @@ -0,0 +1,84 @@ +(ns uxbox.util.geom.matrix + (:require [uxbox.util.math :as mth] + [uxbox.util.geom.point :as gpt])) + +(defrecord Matrix [a b c d tx ty]) + +(defprotocol ICoerce + "Matrix coersion protocol." + (-matrix [v] "Return a matrix instance.")) + +(extend-type Matrix + cljs.core/IDeref + (-deref [v] + (mapv #(get v %) [:a :b :c :d :tx :ty]))) + +(extend-protocol ICoerce + nil + (-matrix [_] + (Matrix. 1 0 0 1 0 0)) + + Matrix + (-matrix [v] v) + + cljs.core/PersistentVector + (-matrix [v] + (let [[a b c d tx ty] v] + (Matrix. a b c d tx ty))) + + cljs.core/IndexedSeq + (-matrix [v] + (let [[a b c d tx ty] v] + (Matrix. a b c d tx ty)))) + +(defn matrix? + "Return true if `v` is Matrix instance." + [v] + (instance? Matrix v)) + +(defn matrix + "Create a new matrix instance." + ([] + (Matrix. 1 0 0 1 0 0)) + ([v] + (-matrix v)) + ([a b c d tx ty] + (Matrix. a b c d tx ty))) + +(defn rotate + "Apply rotation transformation to the matrix." + ([m angle] + (let [center (gpt/point 0 0)] + (rotate m angle center))) + ([m angle center] + (let [angle (mth/radians angle) + x (:x center) + y (:y center) + cos (mth/cos angle) + sin (mth/sin angle) + nsin (mth/neg sin) + tx (+ (- x (* x cos)) (* y sin)) + ty (- (- y (* x sin)) (* y cos)) + a (+ (* cos (:a m)) (* sin (:b m))) + b (+ (* nsin (:a m)) (* cos (:b m))) + c (+ (* cos (:c m)) (* sin (:d m))) + d (+ (* nsin (:c m)) (* cos (:d m))) + tx' (+ (:tx m) (* tx (:a m)) (* tx (:b m))) + ty' (+ (:ty m) (* tx (:c m)) (* ty (:d m)))] + (Matrix. a b c d tx ty)))) + +(defn scale + "Apply scale transformation to the matrix." + [m v] + (assoc m + :a (* (:a m) v) + :c (* (:c m) v) + :b (* (:b m) v) + :d (* (:d m) v))) + +(defn translate + "Apply translate transformation to the matrix." + [m pt] + (assoc m + :tx (+ (:tx m) (* (:x pt) (:a m)) (* (:y pt) (:b m))) + :ty (+ (:ty m) (* (:x pt) (:c m)) (* (:y pt) (:d m))))) diff --git a/test/uxbox/util/geom_tests.cljs b/test/uxbox/util/geom_tests.cljs index c716df19da..c50f351e89 100644 --- a/test/uxbox/util/geom_tests.cljs +++ b/test/uxbox/util/geom_tests.cljs @@ -81,5 +81,23 @@ (t/is (= 4 (gpt/quadrant p4))))) +(t/deftest matrix-constructors-test + (let [m (gmt/matrix)] + (t/is (= @m [1 0 0 1 0 0])) + (t/is (gmt/matrix? m))) + (let [m (gmt/matrix 1 1 1 2 2 2)] + (t/is (= @m [1 1 1 2 2 2])) + (t/is (gmt/matrix? m))) + (let [m (gmt/matrix [1 1 1 2 2 2])] + (t/is (= @m [1 1 1 2 2 2])) + (t/is (gmt/matrix? m)))) +(t/deftest matrix-rotate-test + (let [m (-> (gmt/matrix) + (gmt/rotate 10))] + (t/is (= @m [0.984807753012208 + -0.17364817766693033 + 0.17364817766693033 + 0.984807753012208 + 0 0]))))