0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-13 08:11:30 -05:00
penpot/src/uxbox/util/geom/matrix.cljs

119 lines
2.7 KiB
Text
Raw Normal View History

(ns uxbox.util.geom.matrix
2016-02-06 17:37:26 +02:00
(:require [cuerdas.core :as str]
[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]
2016-02-06 17:37:26 +02:00
(mapv #(get v %) [:a :c :b :d :tx :ty]))
Object
(toString [v]
(->> (str/join "," @v)
(str/format "matrix(%s)"))))
(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 (- 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)) (* ty (: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] (scale m v v))
([m x y]
(assoc m
:a (* (:a m) x)
:c (* (:c m) x)
:b (* (:b m) y)
:d (* (:d m) y))))
(defn translate
"Apply translate transformation to the matrix."
([m pt]
(let [pt (gpt/-point 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))))))
([m x y]
(translate m (gpt/point x y))))
2016-02-06 17:38:34 +02:00
(defn append
([m om]
(let [a1 (:a m)
b1 (:b m)
c1 (:c m)
d1 (:d m)
a2 (:a om)
b2 (:b om)
c2 (:c om)
d2 (:d om)
tx1 (:tx m)
ty1 (:ty m)
tx2 (:tx om)
ty2 (:ty om)]
(Matrix.
(+ (* a2 a1) (* c2 b1))
(+ (* b2 a1) (* d2 b1))
(+ (* a2 c1) (* c2 d1))
(+ (* b2 c1) (* d2 d1))
(+ tx1 (* tx2 a1) (* ty2 b1))
(+ ty1 (* tx2 c1) (* ty2 d1)))))
([m om & others]
(reduce append (append m om) others)))