mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 08:11:30 -05:00
118 lines
2.7 KiB
Clojure
118 lines
2.7 KiB
Clojure
(ns uxbox.util.geom.matrix
|
|
(: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]
|
|
(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))))
|
|
|
|
(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)))
|