mirror of
https://github.com/penpot/penpot.git
synced 2026-02-28 23:34:26 +00:00
✨ Use new defrecord for geom data structures
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.schema.openapi :as-alias oapi]
|
||||
@@ -27,21 +28,21 @@
|
||||
(def precision 6)
|
||||
|
||||
;; --- Matrix Impl
|
||||
(defrecord Matrix [^double a
|
||||
^double b
|
||||
^double c
|
||||
^double d
|
||||
^double e
|
||||
^double f]
|
||||
(cr/defrecord Matrix [^double a
|
||||
^double b
|
||||
^double c
|
||||
^double d
|
||||
^double e
|
||||
^double f]
|
||||
Object
|
||||
(toString [_]
|
||||
(toString [this]
|
||||
(dm/fmt "matrix(%, %, %, %, %, %)"
|
||||
(mth/to-fixed a precision)
|
||||
(mth/to-fixed b precision)
|
||||
(mth/to-fixed c precision)
|
||||
(mth/to-fixed d precision)
|
||||
(mth/to-fixed e precision)
|
||||
(mth/to-fixed f precision))))
|
||||
(mth/to-fixed (.-a this) precision)
|
||||
(mth/to-fixed (.-b this) precision)
|
||||
(mth/to-fixed (.-c this) precision)
|
||||
(mth/to-fixed (.-d this) precision)
|
||||
(mth/to-fixed (.-e this) precision)
|
||||
(mth/to-fixed (.-f this) precision))))
|
||||
|
||||
(defn matrix?
|
||||
"Return true if `v` is Matrix instance."
|
||||
@@ -51,9 +52,9 @@
|
||||
(defn matrix
|
||||
"Create a new matrix instance."
|
||||
([]
|
||||
(Matrix. 1 0 0 1 0 0))
|
||||
(pos->Matrix 1 0 0 1 0 0))
|
||||
([a b c d e f]
|
||||
(Matrix. a b c d e f)))
|
||||
(pos->Matrix a b c d e f)))
|
||||
|
||||
(def number-regex #"[+-]?\d*(\.\d+)?(e[+-]?\d+)?")
|
||||
|
||||
@@ -100,7 +101,7 @@
|
||||
(sg/small-double)
|
||||
(sg/small-double)
|
||||
(sg/small-double) )
|
||||
(sg/fmap #(apply ->Matrix %)))
|
||||
(sg/fmap #(apply pos->Matrix %)))
|
||||
::oapi/type "string"
|
||||
::oapi/format "matrix"
|
||||
::oapi/decode decode
|
||||
@@ -120,24 +121,54 @@
|
||||
(s/def ::matrix
|
||||
(s/and ::matrix-attrs matrix?))
|
||||
|
||||
|
||||
(defn close?
|
||||
[^Matrix m1 ^Matrix m2]
|
||||
(and (mth/close? (.-a m1) (.-a m2))
|
||||
(mth/close? (.-b m1) (.-b m2))
|
||||
(mth/close? (.-c m1) (.-c m2))
|
||||
(mth/close? (.-d m1) (.-d m2))
|
||||
(mth/close? (.-e m1) (.-e m2))
|
||||
(mth/close? (.-f m1) (.-f m2))))
|
||||
(and ^boolean (mth/close? (.-a m1) (.-a m2))
|
||||
^boolean (mth/close? (.-b m1) (.-b m2))
|
||||
^boolean (mth/close? (.-c m1) (.-c m2))
|
||||
^boolean (mth/close? (.-d m1) (.-d m2))
|
||||
^boolean (mth/close? (.-e m1) (.-e m2))
|
||||
^boolean (mth/close? (.-f m1) (.-f m2))))
|
||||
|
||||
(defn unit? [^Matrix m1]
|
||||
(and (some? m1)
|
||||
(mth/close? (.-a m1) 1)
|
||||
(mth/close? (.-b m1) 0)
|
||||
(mth/close? (.-c m1) 0)
|
||||
(mth/close? (.-d m1) 1)
|
||||
(mth/close? (.-e m1) 0)
|
||||
(mth/close? (.-f m1) 0)))
|
||||
(and ^boolean (some? m1)
|
||||
^boolean (mth/close? (.-a m1) 1)
|
||||
^boolean (mth/close? (.-b m1) 0)
|
||||
^boolean (mth/close? (.-c m1) 0)
|
||||
^boolean (mth/close? (.-d m1) 1)
|
||||
^boolean (mth/close? (.-e m1) 0)
|
||||
^boolean (mth/close? (.-f m1) 0)))
|
||||
|
||||
(defn multiply!
|
||||
[^Matrix m1 ^Matrix m2]
|
||||
(let [m1a (.-a m1)
|
||||
m1b (.-b m1)
|
||||
m1c (.-c m1)
|
||||
m1d (.-d m1)
|
||||
m1e (.-e m1)
|
||||
m1f (.-f m1)
|
||||
m2a (.-a m2)
|
||||
m2b (.-b m2)
|
||||
m2c (.-c m2)
|
||||
m2d (.-d m2)
|
||||
m2e (.-e m2)
|
||||
m2f (.-f m2)]
|
||||
#?@(:cljs
|
||||
[(set! (.-a m1) (+ (* m1a m2a) (* m1c m2b)))
|
||||
(set! (.-b m1) (+ (* m1b m2a) (* m1d m2b)))
|
||||
(set! (.-c m1) (+ (* m1a m2c) (* m1c m2d)))
|
||||
(set! (.-d m1) (+ (* m1b m2c) (* m1d m2d)))
|
||||
(set! (.-e m1) (+ (* m1a m2e) (* m1c m2f) m1e))
|
||||
(set! (.-f m1) (+ (* m1b m2e) (* m1d m2f) m1f))
|
||||
m1]
|
||||
:clj
|
||||
[(pos->Matrix
|
||||
(+ (* m1a m2a) (* m1c m2b))
|
||||
(+ (* m1b m2a) (* m1d m2b))
|
||||
(+ (* m1a m2c) (* m1c m2d))
|
||||
(+ (* m1b m2c) (* m1d m2d))
|
||||
(+ (* m1a m2e) (* m1c m2f) m1e)
|
||||
(+ (* m1b m2e) (* m1d m2f) m1f))])))
|
||||
|
||||
(defn multiply
|
||||
([^Matrix m1 ^Matrix m2]
|
||||
@@ -162,7 +193,7 @@
|
||||
m2e (.-e m2)
|
||||
m2f (.-f m2)]
|
||||
|
||||
(Matrix.
|
||||
(pos->Matrix
|
||||
(+ (* m1a m2a) (* m1c m2b))
|
||||
(+ (* m1b m2a) (* m1d m2b))
|
||||
(+ (* m1a m2c) (* m1c m2d))
|
||||
@@ -171,51 +202,28 @@
|
||||
(+ (* m1b m2e) (* m1d m2f) m1f)))))
|
||||
|
||||
([m1 m2 & others]
|
||||
(reduce multiply (multiply m1 m2) others)))
|
||||
|
||||
(defn multiply!
|
||||
[^Matrix m1 ^Matrix m2]
|
||||
(let [m1a (.-a m1)
|
||||
m1b (.-b m1)
|
||||
m1c (.-c m1)
|
||||
m1d (.-d m1)
|
||||
m1e (.-e m1)
|
||||
m1f (.-f m1)
|
||||
m2a (.-a m2)
|
||||
m2b (.-b m2)
|
||||
m2c (.-c m2)
|
||||
m2d (.-d m2)
|
||||
m2e (.-e m2)
|
||||
m2f (.-f m2)]
|
||||
#?@(:cljs [(set! (.-a m1) (+ (* m1a m2a) (* m1c m2b)))
|
||||
(set! (.-b m1) (+ (* m1b m2a) (* m1d m2b)))
|
||||
(set! (.-c m1) (+ (* m1a m2c) (* m1c m2d)))
|
||||
(set! (.-d m1) (+ (* m1b m2c) (* m1d m2d)))
|
||||
(set! (.-e m1) (+ (* m1a m2e) (* m1c m2f) m1e))
|
||||
(set! (.-f m1) (+ (* m1b m2e) (* m1d m2f) m1f))
|
||||
m1]
|
||||
:clj [(Matrix.
|
||||
(+ (* m1a m2a) (* m1c m2b))
|
||||
(+ (* m1b m2a) (* m1d m2b))
|
||||
(+ (* m1a m2c) (* m1c m2d))
|
||||
(+ (* m1b m2c) (* m1d m2d))
|
||||
(+ (* m1a m2e) (* m1c m2f) m1e)
|
||||
(+ (* m1b m2e) (* m1d m2f) m1f))])))
|
||||
(reduce multiply! (multiply m1 m2) others)))
|
||||
|
||||
(defn add-translate
|
||||
"Given two TRANSLATE matrixes (only e and f have significative
|
||||
values), combine them. Quicker than multiplying them, for this
|
||||
precise case."
|
||||
([{m1e :e m1f :f} {m2e :e m2f :f}]
|
||||
(Matrix. 1 0 0 1 (+ m1e m2e) (+ m1f m2f)))
|
||||
([^Matrix m1 ^Matrix m2]
|
||||
(let [m1e (dm/get-prop m1 :e)
|
||||
m1f (dm/get-prop m1 :f)
|
||||
m2e (dm/get-prop m2 :e)
|
||||
m2f (dm/get-prop m2 :f)]
|
||||
(pos->Matrix 1 0 0 1 (+ m1e m2e) (+ m1f m2f))))
|
||||
|
||||
([m1 m2 & others]
|
||||
(reduce add-translate (add-translate m1 m2) others)))
|
||||
|
||||
;; FIXME: optimize?
|
||||
|
||||
(defn substract
|
||||
[{m1a :a m1b :b m1c :c m1d :d m1e :e m1f :f}
|
||||
{m2a :a m2b :b m2c :c m2d :d m2e :e m2f :f}]
|
||||
(Matrix.
|
||||
(pos->Matrix
|
||||
(- m1a m2a) (- m1b m2b) (- m1c m2c)
|
||||
(- m1d m2d) (- m1e m2e) (- m1f m2f)))
|
||||
|
||||
@@ -227,13 +235,24 @@
|
||||
|
||||
(defn translate-matrix
|
||||
([pt]
|
||||
(assert (gpt/point? pt))
|
||||
(Matrix. 1 0 0 1
|
||||
(dm/get-prop pt :x)
|
||||
(dm/get-prop pt :y)))
|
||||
(dm/assert! (gpt/point? pt))
|
||||
(pos->Matrix 1 0 0 1
|
||||
(dm/get-prop pt :x)
|
||||
(dm/get-prop pt :y)))
|
||||
|
||||
([x y]
|
||||
(Matrix. 1 0 0 1 x y)))
|
||||
(pos->Matrix 1 0 0 1 x y)))
|
||||
|
||||
|
||||
(defn translate-matrix-neg
|
||||
([pt]
|
||||
(dm/assert! (gpt/point? pt))
|
||||
(pos->Matrix 1 0 0 1
|
||||
(- (dm/get-prop pt :x))
|
||||
(- (dm/get-prop pt :y))))
|
||||
|
||||
([x y]
|
||||
(pos->Matrix 1 0 0 1 (- x) (- y))))
|
||||
|
||||
(defn scale-matrix
|
||||
([pt center]
|
||||
@@ -241,10 +260,10 @@
|
||||
sy (dm/get-prop pt :y)
|
||||
cx (dm/get-prop center :x)
|
||||
cy (dm/get-prop center :y)]
|
||||
(Matrix. sx 0 0 sy (- cx (* cx sx)) (- cy (* cy sy)))))
|
||||
(pos->Matrix sx 0 0 sy (- cx (* cx sx)) (- cy (* cy sy)))))
|
||||
([pt]
|
||||
(assert (gpt/point? pt))
|
||||
(Matrix. (dm/get-prop pt :x) 0 0 (dm/get-prop pt :y) 0 0)))
|
||||
(dm/assert! (gpt/point? pt))
|
||||
(pos->Matrix (dm/get-prop pt :x) 0 0 (dm/get-prop pt :y) 0 0)))
|
||||
|
||||
(defn rotate-matrix
|
||||
([angle point]
|
||||
@@ -258,15 +277,15 @@
|
||||
ns (- s)
|
||||
tx (+ (* c nx) (* ns ny) cx)
|
||||
ty (+ (* s nx) (* c ny) cy)]
|
||||
(Matrix. c s ns c tx ty)))
|
||||
(pos->Matrix c s ns c tx ty)))
|
||||
([angle]
|
||||
(let [a (mth/radians angle)]
|
||||
(Matrix. (mth/cos a)
|
||||
(mth/sin a)
|
||||
(- (mth/sin a))
|
||||
(mth/cos a)
|
||||
0
|
||||
0))))
|
||||
(pos->Matrix (mth/cos a)
|
||||
(mth/sin a)
|
||||
(- (mth/sin a))
|
||||
(mth/cos a)
|
||||
0
|
||||
0))))
|
||||
|
||||
(defn skew-matrix
|
||||
([angle-x angle-y point]
|
||||
@@ -276,7 +295,7 @@
|
||||
([angle-x angle-y]
|
||||
(let [m1 (mth/tan (mth/radians angle-x))
|
||||
m2 (mth/tan (mth/radians angle-y))]
|
||||
(Matrix. 1 m2 m1 1 0 0))))
|
||||
(pos->Matrix 1 m2 m1 1 0 0))))
|
||||
|
||||
(defn rotate
|
||||
"Apply rotation transformation to the matrix."
|
||||
@@ -337,6 +356,7 @@
|
||||
(translate (gpt/negate pt)))
|
||||
mtx))
|
||||
|
||||
;; FIXME: performance
|
||||
(defn determinant
|
||||
"Determinant for the affinity transform"
|
||||
[{:keys [a b c d _ _]}]
|
||||
@@ -346,14 +366,14 @@
|
||||
"Gets the inverse of the affinity transform `mtx`"
|
||||
[{:keys [a b c d e f] :as mtx}]
|
||||
(let [det (determinant mtx)]
|
||||
(when-not (mth/almost-zero? det)
|
||||
(when-not ^boolean (mth/almost-zero? det)
|
||||
(let [a' (/ d det)
|
||||
b' (/ (- b) det)
|
||||
c' (/ (- c) det)
|
||||
d' (/ a det)
|
||||
e' (/ (- (* c f) (* d e)) det)
|
||||
f' (/ (- (* b e) (* a f)) det)]
|
||||
(Matrix. a' b' c' d' e' f')))))
|
||||
(pos->Matrix a' b' c' d' e' f')))))
|
||||
|
||||
(defn round
|
||||
[mtx]
|
||||
@@ -377,11 +397,11 @@
|
||||
point))
|
||||
|
||||
(defn move?
|
||||
[{:keys [a b c d _ _]}]
|
||||
(and (mth/almost-zero? (- a 1))
|
||||
(mth/almost-zero? b)
|
||||
(mth/almost-zero? c)
|
||||
(mth/almost-zero? (- d 1))))
|
||||
[m]
|
||||
(and ^boolean (mth/almost-zero? (- (dm/get-prop m :a) 1))
|
||||
^boolean (mth/almost-zero? (dm/get-prop m :b))
|
||||
^boolean (mth/almost-zero? (dm/get-prop m :c))
|
||||
^boolean (mth/almost-zero? (- (dm/get-prop m :d) 1))))
|
||||
|
||||
#?(:clj
|
||||
(fres/add-handlers!
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.math :as mth]
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.schema.openapi :as-alias oapi]
|
||||
@@ -29,7 +30,7 @@
|
||||
|
||||
;; --- Point Impl
|
||||
|
||||
(defrecord Point [x y])
|
||||
(cr/defrecord Point [x y])
|
||||
|
||||
(defn s
|
||||
[pt]
|
||||
@@ -62,7 +63,7 @@
|
||||
(map->Point p)
|
||||
(if (string? p)
|
||||
(let [[x y] (->> (str/split p #",") (mapv parse-double))]
|
||||
(Point. x y))
|
||||
(pos->Point x y))
|
||||
p)))
|
||||
|
||||
(encode [p]
|
||||
@@ -76,7 +77,7 @@
|
||||
:description "Point"
|
||||
:error/message "expected a valid point"
|
||||
:gen/gen (->> (sg/tuple (sg/small-int) (sg/small-int))
|
||||
(sg/fmap #(apply ->Point %)))
|
||||
(sg/fmap #(apply pos->Point %)))
|
||||
::oapi/type "string"
|
||||
::oapi/format "point"
|
||||
::oapi/decode decode
|
||||
@@ -90,7 +91,7 @@
|
||||
|
||||
(defn point
|
||||
"Create a Point instance."
|
||||
([] (Point. 0 0))
|
||||
([] (pos->Point 0 0))
|
||||
([v]
|
||||
(cond
|
||||
(point? v)
|
||||
@@ -100,12 +101,12 @@
|
||||
(point v v)
|
||||
|
||||
(point-like? v)
|
||||
(Point. (:x v) (:y v))
|
||||
(pos->Point (:x v) (:y v))
|
||||
|
||||
:else
|
||||
(ex/raise :hint "invalid arguments (on pointer constructor)" :value v)))
|
||||
([x y]
|
||||
(Point. x y)))
|
||||
(pos->Point x y)))
|
||||
|
||||
(defn close?
|
||||
[p1 p2]
|
||||
@@ -129,22 +130,24 @@
|
||||
(and (point? p1)
|
||||
(point? p2)))
|
||||
|
||||
(Point. (+ (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(+ (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
(pos->Point (+ (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(+ (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
|
||||
(defn subtract
|
||||
"Returns the subtraction of the supplied value to both
|
||||
coordinates of the point as a new point."
|
||||
[p1 p2]
|
||||
(assert (and (point? p1)
|
||||
(point? p2))
|
||||
"arguments should be pointer instance")
|
||||
(Point. (- (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(- (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
(dm/assert!
|
||||
"arguments should be pointer instance"
|
||||
(and (point? p1)
|
||||
(point? p2)))
|
||||
|
||||
(pos->Point (- (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(- (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
|
||||
(defn multiply
|
||||
"Returns the subtraction of the supplied value to both
|
||||
@@ -153,20 +156,20 @@
|
||||
(assert (and (point? p1)
|
||||
(point? p2))
|
||||
"arguments should be pointer instance")
|
||||
(Point. (* (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(* (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
(pos->Point (* (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(* (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
|
||||
(defn divide
|
||||
[p1 p2]
|
||||
(assert (and (point? p1)
|
||||
(point? p2))
|
||||
"arguments should be pointer instance")
|
||||
(Point. (/ (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(/ (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
(pos->Point (/ (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(/ (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))
|
||||
|
||||
(defn min
|
||||
([] nil)
|
||||
@@ -175,10 +178,10 @@
|
||||
(cond
|
||||
(nil? p1) p2
|
||||
(nil? p2) p1
|
||||
:else (Point. (c/min (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(c/min (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))))
|
||||
:else (pos->Point (c/min (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(c/min (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))))
|
||||
(defn max
|
||||
([] nil)
|
||||
([p1] p1)
|
||||
@@ -186,21 +189,21 @@
|
||||
(cond
|
||||
(nil? p1) p2
|
||||
(nil? p2) p1
|
||||
:else (Point. (c/max (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(c/max (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))))
|
||||
:else (pos->Point (c/max (dm/get-prop p1 :x)
|
||||
(dm/get-prop p2 :x))
|
||||
(c/max (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))))))
|
||||
(defn inverse
|
||||
[pt]
|
||||
(assert (point? pt) "point instance expected")
|
||||
(Point. (/ 1.0 (dm/get-prop pt :x))
|
||||
(/ 1.0 (dm/get-prop pt :y))))
|
||||
(pos->Point (/ 1.0 (dm/get-prop pt :x))
|
||||
(/ 1.0 (dm/get-prop pt :y))))
|
||||
|
||||
(defn negate
|
||||
[pt]
|
||||
(assert (point? pt) "point instance expected")
|
||||
(Point. (- (dm/get-prop pt :x))
|
||||
(- (dm/get-prop pt :y))))
|
||||
(pos->Point (- (dm/get-prop pt :x))
|
||||
(- (dm/get-prop pt :y))))
|
||||
|
||||
(defn distance
|
||||
"Calculate the distance between two points."
|
||||
@@ -224,8 +227,8 @@
|
||||
(dm/get-prop p2 :x))
|
||||
dy (- (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))]
|
||||
(Point. (mth/abs dx)
|
||||
(mth/abs dy))))
|
||||
(pos->Point (mth/abs dx)
|
||||
(mth/abs dy))))
|
||||
|
||||
(defn length
|
||||
[pt]
|
||||
@@ -292,8 +295,8 @@
|
||||
(assert (number? angle) "expected number")
|
||||
(let [len (length p)
|
||||
angle (mth/radians angle)]
|
||||
(Point. (* (mth/cos angle) len)
|
||||
(* (mth/sin angle) len))))
|
||||
(pos->Point (* (mth/cos angle) len)
|
||||
(* (mth/sin angle) len))))
|
||||
|
||||
(defn quadrant
|
||||
"Return the quadrant of the angle of the point."
|
||||
@@ -313,22 +316,21 @@
|
||||
([pt decimals]
|
||||
(assert (point? pt) "expected point instance")
|
||||
(assert (number? decimals) "expected number instance")
|
||||
(Point. (mth/precision (dm/get-prop pt :x) decimals)
|
||||
(mth/precision (dm/get-prop pt :y) decimals))))
|
||||
(pos->Point (mth/precision (dm/get-prop pt :x) decimals)
|
||||
(mth/precision (dm/get-prop pt :y) decimals))))
|
||||
|
||||
(defn round-step
|
||||
"Round the coordinates to the closest half-point"
|
||||
[pt step]
|
||||
(assert (point? pt) "expected point instance")
|
||||
(Point. (mth/round (dm/get-prop pt :x) step)
|
||||
(mth/round (dm/get-prop pt :y) step)))
|
||||
(pos->Point (mth/round (dm/get-prop pt :x) step)
|
||||
(mth/round (dm/get-prop pt :y) step)))
|
||||
|
||||
(defn transform
|
||||
"Transform a point applying a matrix transformation."
|
||||
[p m]
|
||||
(when (point? p)
|
||||
(if (nil? m)
|
||||
p
|
||||
(if (some? m)
|
||||
(let [x (dm/get-prop p :x)
|
||||
y (dm/get-prop p :y)
|
||||
a (dm/get-prop m :a)
|
||||
@@ -337,18 +339,51 @@
|
||||
d (dm/get-prop m :d)
|
||||
e (dm/get-prop m :e)
|
||||
f (dm/get-prop m :f)]
|
||||
(Point. (+ (* x a) (* y c) e)
|
||||
(+ (* x b) (* y d) f))))))
|
||||
(pos->Point (+ (* x a) (* y c) e)
|
||||
(+ (* x b) (* y d) f)))
|
||||
p)))
|
||||
|
||||
|
||||
(defn transform!
|
||||
[p m]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid rect and matrix instances"
|
||||
(and (some? p) (some? m)))
|
||||
|
||||
(let [x (dm/get-prop p :x)
|
||||
y (dm/get-prop p :y)
|
||||
a (dm/get-prop m :a)
|
||||
b (dm/get-prop m :b)
|
||||
c (dm/get-prop m :c)
|
||||
d (dm/get-prop m :d)
|
||||
e (dm/get-prop m :e)
|
||||
f (dm/get-prop m :f)]
|
||||
#?(:clj
|
||||
(pos->Point (+ (* x a) (* y c) e)
|
||||
(+ (* x b) (* y d) f))
|
||||
:cljs
|
||||
(do
|
||||
(set! (.-x p) (+ (* x a) (* y c) e))
|
||||
(set! (.-y p) (+ (* x b) (* y d) f))
|
||||
p))))
|
||||
|
||||
(defn matrix->point
|
||||
"Returns a result of transform an identity point with the provided
|
||||
matrix instance"
|
||||
[m]
|
||||
(let [e (dm/get-prop m :e)
|
||||
f (dm/get-prop m :f)]
|
||||
(pos->Point e f)))
|
||||
|
||||
;; Vector functions
|
||||
(defn to-vec [p1 p2]
|
||||
(subtract p2 p1))
|
||||
|
||||
(defn scale
|
||||
[p scalar]
|
||||
(Point. (* (dm/get-prop p :x) scalar)
|
||||
(* (dm/get-prop p :y) scalar)))
|
||||
(pos->Point (* (dm/get-prop p :x) scalar)
|
||||
(* (dm/get-prop p :y) scalar)))
|
||||
|
||||
(defn dot
|
||||
[p1 p2]
|
||||
@@ -361,14 +396,14 @@
|
||||
[p1]
|
||||
(let [p-length (length p1)]
|
||||
(if (mth/almost-zero? p-length)
|
||||
(Point. 0 0)
|
||||
(Point. (/ (dm/get-prop p1 :x) p-length)
|
||||
(/ (dm/get-prop p1 :y) p-length)))))
|
||||
(pos->Point 0 0)
|
||||
(pos->Point (/ (dm/get-prop p1 :x) p-length)
|
||||
(/ (dm/get-prop p1 :y) p-length)))))
|
||||
|
||||
(defn perpendicular
|
||||
[pt]
|
||||
(Point. (- (dm/get-prop pt :y))
|
||||
(dm/get-prop pt :x)))
|
||||
(pos->Point (- (dm/get-prop pt :y))
|
||||
(dm/get-prop pt :x)))
|
||||
|
||||
(defn project
|
||||
"V1 perpendicular projection on vector V2"
|
||||
@@ -419,7 +454,7 @@
|
||||
[p1 p2 t]
|
||||
(let [x (mth/lerp (dm/get-prop p1 :x) (dm/get-prop p2 :x) t)
|
||||
y (mth/lerp (dm/get-prop p1 :y) (dm/get-prop p2 :y) t)]
|
||||
(Point. x y)))
|
||||
(pos->Point x y)))
|
||||
|
||||
(defn rotate
|
||||
"Rotates the point around center with an angle"
|
||||
@@ -441,7 +476,7 @@
|
||||
y (+ (* sa (- px cx))
|
||||
(* ca (- py cy))
|
||||
cy)]
|
||||
(Point. x y)))
|
||||
(pos->Point x y)))
|
||||
|
||||
(defn scale-from
|
||||
"Moves a point in the vector that creates with center with a scale
|
||||
@@ -457,10 +492,10 @@
|
||||
[p]
|
||||
(let [x (dm/get-prop p :x)
|
||||
y (dm/get-prop p :y)]
|
||||
(Point. (if (mth/almost-zero? x) 0.001 x)
|
||||
(if (mth/almost-zero? y) 0.001 y))))
|
||||
|
||||
(pos->Point (if (mth/almost-zero? x) 0.001 x)
|
||||
(if (mth/almost-zero? y) 0.001 y))))
|
||||
|
||||
;; FIXME: perfromance
|
||||
(defn abs
|
||||
[point]
|
||||
(-> point
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]
|
||||
[app.common.record :as rc]
|
||||
[app.common.transit :as t]))
|
||||
|
||||
(defrecord Rect [x y width height x1 y1 x2 y2])
|
||||
(rc/defrecord Rect [x y width height x1 y1 x2 y2])
|
||||
|
||||
(defn rect?
|
||||
[o]
|
||||
@@ -62,10 +63,7 @@
|
||||
(when (d/num? x y width height)
|
||||
(let [w (mth/max width 0.01)
|
||||
h (mth/max height 0.01)]
|
||||
(->Rect x y w h x y (+ x w) (+ y h)))))
|
||||
|
||||
([x y w h x1 y1 x2 y2]
|
||||
(->Rect x y w h x1 y1 x2 y2)))
|
||||
(pos->Rect x y w h x y (+ x w) (+ y h))))))
|
||||
|
||||
(def empty-rect
|
||||
(make-rect 0 0 0.01 0.01))
|
||||
@@ -104,6 +102,31 @@
|
||||
:x2 (+ x w)
|
||||
:y2 (+ y h)))))
|
||||
|
||||
(defn update-rect!
|
||||
[rect type]
|
||||
(case type
|
||||
(:size :position)
|
||||
(let [x (dm/get-prop rect :x)
|
||||
y (dm/get-prop rect :y)
|
||||
w (dm/get-prop rect :width)
|
||||
h (dm/get-prop rect :height)]
|
||||
(rc/assoc! rect
|
||||
:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x w)
|
||||
:y2 (+ y h)))
|
||||
|
||||
:corners
|
||||
(let [x1 (dm/get-prop rect :x1)
|
||||
y1 (dm/get-prop rect :y1)
|
||||
x2 (dm/get-prop rect :x2)
|
||||
y2 (dm/get-prop rect :y2)]
|
||||
(rc/assoc! rect
|
||||
:x (mth/min x1 x2)
|
||||
:y (mth/min y1 y2)
|
||||
:width (mth/abs (- x2 x1))
|
||||
:height (mth/abs (- y2 y1))))))
|
||||
|
||||
(defn close-rect?
|
||||
[rect1 rect2]
|
||||
|
||||
@@ -123,7 +146,6 @@
|
||||
|
||||
(defn rect->points
|
||||
[rect]
|
||||
|
||||
(dm/assert!
|
||||
"expected rect instance"
|
||||
(rect? rect))
|
||||
@@ -140,6 +162,12 @@
|
||||
(gpt/point (+ x w) (+ y h))
|
||||
(gpt/point x (+ y h))]))))
|
||||
|
||||
(defn rect->point
|
||||
"Extract the position part of the rect"
|
||||
[rect]
|
||||
(gpt/point (dm/get-prop rect :x)
|
||||
(dm/get-prop rect :y)))
|
||||
|
||||
(defn rect->center
|
||||
[rect]
|
||||
(dm/assert! (rect? rect))
|
||||
@@ -231,17 +259,22 @@
|
||||
(when (d/num? minx miny maxx maxy)
|
||||
(make-rect minx miny (- maxx minx) (- maxy miny))))))
|
||||
|
||||
(defn center->rect [{:keys [x y]} width height]
|
||||
(when (d/num? x y width height)
|
||||
(make-rect (- x (/ width 2))
|
||||
(- y (/ height 2))
|
||||
width
|
||||
height)))
|
||||
(defn center->rect
|
||||
[point w h]
|
||||
(when (some? point)
|
||||
(let [x (dm/get-prop point :x)
|
||||
y (dm/get-prop point :y)]
|
||||
(when (d/num? x y w h)
|
||||
(make-rect (- x (/ w 2))
|
||||
(- y (/ h 2))
|
||||
w
|
||||
h)))))
|
||||
|
||||
(defn s=
|
||||
[a b]
|
||||
(mth/almost-zero? (- a b)))
|
||||
|
||||
;; FIXME: performance
|
||||
(defn overlaps-rects?
|
||||
"Check for two rects to overlap. Rects won't overlap only if
|
||||
one of them is fully to the left or the top"
|
||||
|
||||
Reference in New Issue
Block a user