mirror of
https://github.com/penpot/penpot.git
synced 2025-05-29 18:26:12 +02:00
⚡ Performance improvements.
This commit is contained in:
parent
3ab5e11d5f
commit
76e19a4b41
9 changed files with 134 additions and 349 deletions
|
@ -434,10 +434,10 @@
|
||||||
(defn shapes->rect-shape
|
(defn shapes->rect-shape
|
||||||
[shapes]
|
[shapes]
|
||||||
(let [shapes (mapv shape->rect-shape shapes)
|
(let [shapes (mapv shape->rect-shape shapes)
|
||||||
minx (apply js/Math.min (mapv :x1 shapes))
|
minx (transduce (map :x1) min shapes)
|
||||||
miny (apply js/Math.min (mapv :y1 shapes))
|
miny (transduce (map :y1) min shapes)
|
||||||
maxx (apply js/Math.max (mapv :x2 shapes))
|
maxx (transduce (map :x2) max shapes)
|
||||||
maxy (apply js/Math.max (mapv :y2 shapes))]
|
maxy (transduce (map :y2) max shapes)]
|
||||||
{:x1 minx
|
{:x1 minx
|
||||||
:y1 miny
|
:y1 miny
|
||||||
:x2 maxx
|
:x2 maxx
|
||||||
|
@ -509,10 +509,10 @@
|
||||||
|
|
||||||
(defn- transform-rect
|
(defn- transform-rect
|
||||||
[{:keys [x y width height] :as shape} mx]
|
[{:keys [x y width height] :as shape} mx]
|
||||||
(let [tl (gpt/transform [x y] mx)
|
(let [tl (gpt/transform (gpt/point x y) mx)
|
||||||
tr (gpt/transform [(+ x width) y] mx)
|
tr (gpt/transform (gpt/point (+ x width) y) mx)
|
||||||
bl (gpt/transform [x (+ y height)] mx)
|
bl (gpt/transform (gpt/point x (+ y height)) mx)
|
||||||
br (gpt/transform [(+ x width) (+ y height)] mx)
|
br (gpt/transform (gpt/point (+ x width) (+ y height)) mx)
|
||||||
;; TODO: replace apply with transduce (performance)
|
;; TODO: replace apply with transduce (performance)
|
||||||
minx (apply min (map :x [tl tr bl br]))
|
minx (apply min (map :x [tl tr bl br]))
|
||||||
maxx (apply max (map :x [tl tr bl br]))
|
maxx (apply max (map :x [tl tr bl br]))
|
||||||
|
@ -527,10 +527,10 @@
|
||||||
(defn- transform-circle
|
(defn- transform-circle
|
||||||
[{:keys [cx cy rx ry] :as shape} xfmt]
|
[{:keys [cx cy rx ry] :as shape} xfmt]
|
||||||
(let [{:keys [x1 y1 x2 y2]} (shape->rect-shape shape)
|
(let [{:keys [x1 y1 x2 y2]} (shape->rect-shape shape)
|
||||||
tl (gpt/transform [x1 y1] xfmt)
|
tl (gpt/transform (gpt/point x1 y1) xfmt)
|
||||||
tr (gpt/transform [x2 y1] xfmt)
|
tr (gpt/transform (gpt/point x2 y1) xfmt)
|
||||||
bl (gpt/transform [x1 y2] xfmt)
|
bl (gpt/transform (gpt/point x1 y2) xfmt)
|
||||||
br (gpt/transform [x2 y2] xfmt)
|
br (gpt/transform (gpt/point x2 y2) xfmt)
|
||||||
|
|
||||||
;; TODO: replace apply with transduce (performance)
|
;; TODO: replace apply with transduce (performance)
|
||||||
x (apply min (map :x [tl tr bl br]))
|
x (apply min (map :x [tl tr bl br]))
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
[current]
|
[current]
|
||||||
(->> (rx/concat (rx/of current)
|
(->> (rx/concat (rx/of current)
|
||||||
(rx/sample 10 mouse-position))
|
(rx/sample 10 mouse-position))
|
||||||
(rx/map #(gpt/divide % @refs/selected-zoom))
|
(rx/map #(gpt/divide % (gpt/point @refs/selected-zoom)))
|
||||||
(rx/mapcat (fn [point]
|
(rx/mapcat (fn [point]
|
||||||
(if @refs/selected-alignment
|
(if @refs/selected-alignment
|
||||||
(uwrk/align-point point)
|
(uwrk/align-point point)
|
||||||
|
|
|
@ -135,7 +135,7 @@
|
||||||
|
|
||||||
mouse (->> ms/mouse-position
|
mouse (->> ms/mouse-position
|
||||||
(rx/mapcat #(conditional-align % align?))
|
(rx/mapcat #(conditional-align % align?))
|
||||||
(rx/map #(gpt/divide % zoom)))]
|
(rx/map #(gpt/divide % (gpt/point zoom))))]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(->> mouse
|
(->> mouse
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
|
@ -179,14 +179,14 @@
|
||||||
(let [{:keys [zoom flags]} (:workspace-local state)
|
(let [{:keys [zoom flags]} (:workspace-local state)
|
||||||
|
|
||||||
align? (refs/alignment-activated? flags)
|
align? (refs/alignment-activated? flags)
|
||||||
last-point (volatile! (gpt/divide @ms/mouse-position zoom))
|
last-point (volatile! (gpt/divide @ms/mouse-position (gpt/point zoom)))
|
||||||
|
|
||||||
stoper (->> (rx/filter stoper-event? stream)
|
stoper (->> (rx/filter stoper-event? stream)
|
||||||
(rx/share))
|
(rx/share))
|
||||||
|
|
||||||
mouse (->> (rx/sample 10 ms/mouse-position)
|
mouse (->> (rx/sample 10 ms/mouse-position)
|
||||||
(rx/mapcat #(conditional-align % align?))
|
(rx/mapcat #(conditional-align % align?))
|
||||||
(rx/map #(gpt/divide % zoom)))
|
(rx/map #(gpt/divide % (gpt/point zoom))))
|
||||||
|
|
||||||
points (->> stream
|
points (->> stream
|
||||||
(rx/filter ms/mouse-click?)
|
(rx/filter ms/mouse-click?)
|
||||||
|
@ -255,7 +255,7 @@
|
||||||
stoper (rx/filter stoper-event? stream)
|
stoper (rx/filter stoper-event? stream)
|
||||||
mouse (->> (rx/sample 10 ms/mouse-position)
|
mouse (->> (rx/sample 10 ms/mouse-position)
|
||||||
(rx/mapcat #(conditional-align % align?))
|
(rx/mapcat #(conditional-align % align?))
|
||||||
(rx/map #(gpt/divide % zoom)))]
|
(rx/map #(gpt/divide % (gpt/point zoom))))]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of initialize-drawing)
|
(rx/of initialize-drawing)
|
||||||
(->> mouse
|
(->> mouse
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
(defn- apply-zoom
|
(defn- apply-zoom
|
||||||
[point]
|
[point]
|
||||||
(gpt/divide point @refs/selected-zoom))
|
(gpt/divide point (gpt/point @refs/selected-zoom)))
|
||||||
|
|
||||||
;; --- Resize & Rotate
|
;; --- Resize & Rotate
|
||||||
|
|
||||||
|
@ -115,8 +115,8 @@
|
||||||
:style {:fillOpacity "1"
|
:style {:fillOpacity "1"
|
||||||
:strokeWidth "2px"
|
:strokeWidth "2px"
|
||||||
:vectorEffect "non-scaling-stroke"}
|
:vectorEffect "non-scaling-stroke"}
|
||||||
:fill "rgba(49,239,184,.7)"
|
:fill "rgba(49,239,184,.7)"
|
||||||
:stroke "#31EFB8"
|
:stroke "#31EFB8"
|
||||||
:cx cx
|
:cx cx
|
||||||
:cy cy}])
|
:cy cy}])
|
||||||
|
|
||||||
|
@ -232,7 +232,6 @@
|
||||||
|
|
||||||
;; TODO: add specs for clarity
|
;; TODO: add specs for clarity
|
||||||
|
|
||||||
|
|
||||||
(mf/defc text-edition-selection-handlers
|
(mf/defc text-edition-selection-handlers
|
||||||
[{:keys [shape zoom] :as props}]
|
[{:keys [shape zoom] :as props}]
|
||||||
(let [{:keys [x y width height] :as shape} shape]
|
(let [{:keys [x y width height] :as shape} shape]
|
||||||
|
@ -257,7 +256,6 @@
|
||||||
|
|
||||||
(mf/defc single-selection-handlers
|
(mf/defc single-selection-handlers
|
||||||
[{:keys [shape zoom] :as props}]
|
[{:keys [shape zoom] :as props}]
|
||||||
(prn "single-selection-handlers" shape)
|
|
||||||
(let [on-resize #(do (dom/stop-propagation %2)
|
(let [on-resize #(do (dom/stop-propagation %2)
|
||||||
(st/emit! (start-resize %1 #{(:id shape)} shape)))
|
(st/emit! (start-resize %1 #{(:id shape)} shape)))
|
||||||
on-rotate #(do (dom/stop-propagation %)
|
on-rotate #(do (dom/stop-propagation %)
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
(mf/defc coordinates
|
(mf/defc coordinates
|
||||||
[{:keys [zoom] :as props}]
|
[{:keys [zoom] :as props}]
|
||||||
(let [coords (some-> (use-rxsub ms/mouse-position)
|
(let [coords (some-> (use-rxsub ms/mouse-position)
|
||||||
(gpt/divide zoom)
|
(gpt/divide (gpt/point zoom zoom))
|
||||||
(gpt/round 0))]
|
(gpt/round 0))]
|
||||||
[:ul.coordinates
|
[:ul.coordinates
|
||||||
[:span {:alt "x"}
|
[:span {:alt "x"}
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.util.geom.matrix
|
(ns uxbox.util.geom.matrix
|
||||||
(:require [cuerdas.core :as str]
|
(:require [cuerdas.core :as str]
|
||||||
|
@ -13,50 +15,21 @@
|
||||||
|
|
||||||
;; --- Matrix Impl
|
;; --- Matrix Impl
|
||||||
|
|
||||||
(defrecord Matrix [a b c d e f])
|
(defrecord Matrix [a b c d e f]
|
||||||
|
|
||||||
(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 :e :f]))
|
|
||||||
|
|
||||||
Object
|
Object
|
||||||
(toString [v]
|
(toString [_]
|
||||||
(->> (str/join "," @v)
|
(str "matrix(" a "," b "," c "," d "," e "," f ")")))
|
||||||
(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 e f] v]
|
|
||||||
(Matrix. a b c d e f)))
|
|
||||||
|
|
||||||
cljs.core/IndexedSeq
|
|
||||||
(-matrix [v]
|
|
||||||
(let [[a b c d e f] v]
|
|
||||||
(Matrix. a b c d e f))))
|
|
||||||
|
|
||||||
(defn multiply
|
(defn multiply
|
||||||
([m1 m2]
|
([{m1a :a m1b :b m1c :c m1d :d m1e :e m1f :f :as m1}
|
||||||
|
{m2a :a m2b :b m2c :c m2d :d m2e :e m2f :f :as m2}]
|
||||||
(Matrix.
|
(Matrix.
|
||||||
(+ (* (:a m1) (:a m2)) (* (:c m1) (:b m2)))
|
(+ (* m1a m2a) (* m1c m2b))
|
||||||
(+ (* (:b m1) (:a m2)) (* (:d m1) (:b m2)))
|
(+ (* m1b m2a) (* m1d m2b))
|
||||||
(+ (* (:a m1) (:c m2)) (* (:c m1) (:d m2)))
|
(+ (* m1a m2c) (* m1c m2d))
|
||||||
(+ (* (:b m1) (:c m2)) (* (:d m1) (:d m2)))
|
(+ (* m1b m2c) (* m1d m2d))
|
||||||
(+ (* (:a m1) (:e m2)) (* (:c m1) (:f m2)) (:e m1))
|
(+ (* m1a m2e) (* m1c m2f) m1e)
|
||||||
(+ (* (:b m1) (:e m2)) (* (:d m1) (:f m2)) (:f m1))))
|
(+ (* m1b m2e) (* m1d m2f) m1f)))
|
||||||
|
|
||||||
([m1 m2 & others]
|
([m1 m2 & others]
|
||||||
(reduce multiply (multiply m1 m2) others)))
|
(reduce multiply (multiply m1 m2) others)))
|
||||||
|
|
||||||
|
@ -69,100 +42,28 @@
|
||||||
"Create a new matrix instance."
|
"Create a new matrix instance."
|
||||||
([]
|
([]
|
||||||
(Matrix. 1 0 0 1 0 0))
|
(Matrix. 1 0 0 1 0 0))
|
||||||
([v]
|
|
||||||
(-matrix v))
|
|
||||||
([a b c d e f]
|
([a b c d e f]
|
||||||
(Matrix. a b c d e f)))
|
(Matrix. a b c d e f)))
|
||||||
|
|
||||||
(defn translate-matrix
|
(defn translate-matrix
|
||||||
[pt]
|
[{x :x y :y :as pt}]
|
||||||
(let [pt (gpt/point pt)]
|
(assert (gpt/point? pt))
|
||||||
(Matrix. 1 0 0 1 (:x pt) (:y pt))))
|
(Matrix. 1 0 0 1 x y))
|
||||||
|
|
||||||
(defn scale-matrix
|
(defn scale-matrix
|
||||||
[s]
|
[{x :x y :y :as pt}]
|
||||||
(let [pt (gpt/point s)]
|
(assert (gpt/point? pt))
|
||||||
(Matrix. (:x pt) 0 0 (:y pt) 0 0)))
|
(Matrix. x 0 0 y 0 0))
|
||||||
|
|
||||||
(defn rotate-matrix
|
(defn rotate-matrix
|
||||||
[a]
|
[a]
|
||||||
(let [a (mth/radians a)]
|
(let [a (mth/radians a)]
|
||||||
(Matrix.
|
(Matrix. (mth/cos a)
|
||||||
(mth/cos a)
|
(mth/sin a)
|
||||||
(mth/sin a)
|
(- (mth/sin a))
|
||||||
(- (mth/sin a))
|
(mth/cos a)
|
||||||
(mth/cos a)
|
0
|
||||||
0
|
0)))
|
||||||
0)))
|
|
||||||
|
|
||||||
;; OLD
|
|
||||||
;; (defn rotate
|
|
||||||
;; "Apply rotation transformation to the matrix."
|
|
||||||
;; ([m angle]
|
|
||||||
;; (multiply m (rotate-matrix angle)))
|
|
||||||
;; ([m angle center]
|
|
||||||
;; (multiply m
|
|
||||||
;; (translate-matrix center)
|
|
||||||
;; (rotate-matrix angle)
|
|
||||||
;; (translate-matrix (gpt/negate center)))))
|
|
||||||
|
|
||||||
;; -- ROTATE
|
|
||||||
;; r = radians(r)
|
|
||||||
;; const cos = Math.cos(r)
|
|
||||||
;; const sin = Math.sin(r)
|
|
||||||
;;
|
|
||||||
;; const { a, b, c, d, e, f } = this
|
|
||||||
;;
|
|
||||||
;; this.a = a * cos - b * sin
|
|
||||||
;; this.b = b * cos + a * sin
|
|
||||||
;; this.c = c * cos - d * sin
|
|
||||||
;; this.d = d * cos + c * sin
|
|
||||||
;; this.e = e * cos - f * sin + cy * sin - cx * cos + cx
|
|
||||||
;; this.f = f * cos + e * sin - cx * sin - cy * cos + cy
|
|
||||||
|
|
||||||
;; (defn rotate
|
|
||||||
;; ([m angle] (rotate m angle (gpt/point 0 0)))
|
|
||||||
;; ([m angle center]
|
|
||||||
;; (let [{:keys [a b c d e f]} m
|
|
||||||
;; {cx :x cy :y} center
|
|
||||||
;; r (mth/radians angle)
|
|
||||||
;; cos (mth/cos r)
|
|
||||||
;; sin (mth/sin r)
|
|
||||||
;; a' (- (* a cos) (* b sin))
|
|
||||||
;; b' (+ (* b cos) (* a sin))
|
|
||||||
;; c' (- (* c cos) (* d sin))
|
|
||||||
;; d' (+ (* d cos) (* c sin))
|
|
||||||
;; e' (+ (- (* e cos) (* f sin))
|
|
||||||
;; (- (* cy sin) (* cx cos))
|
|
||||||
;; cx)
|
|
||||||
;; f' (+ (- (+ (* f cos) (* e sin))
|
|
||||||
;; (* cx sin)
|
|
||||||
;; (* cy cos))
|
|
||||||
;; cy)]
|
|
||||||
;; (Matrix. a' b' c' d' e' f'))))
|
|
||||||
|
|
||||||
|
|
||||||
;; export function rotate (angle, cx, cy) {
|
|
||||||
;; const cosAngle = cos(angle)
|
|
||||||
;; const sinAngle = sin(angle)
|
|
||||||
;; const rotationMatrix = {
|
|
||||||
;; a: cosAngle,
|
|
||||||
;; c: -sinAngle,
|
|
||||||
;; e: 0,
|
|
||||||
;; b: sinAngle,
|
|
||||||
;; d: cosAngle,
|
|
||||||
;; f: 0
|
|
||||||
;; }
|
|
||||||
;; if (isUndefined(cx) || isUndefined(cy)) {
|
|
||||||
;; return rotationMatrix
|
|
||||||
;; }
|
|
||||||
|
|
||||||
;; return transform([
|
|
||||||
;; translate(cx, cy),
|
|
||||||
;; rotationMatrix,
|
|
||||||
;; translate(-cx, -cy)
|
|
||||||
;; ])
|
|
||||||
;; }
|
|
||||||
|
|
||||||
(defn rotate
|
(defn rotate
|
||||||
"Apply rotation transformation to the matrix."
|
"Apply rotation transformation to the matrix."
|
||||||
|
@ -177,85 +78,19 @@
|
||||||
;; TODO: temporal backward compatibility
|
;; TODO: temporal backward compatibility
|
||||||
(def rotate* rotate)
|
(def rotate* rotate)
|
||||||
|
|
||||||
;; ([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))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; scaleO (x, y = x, cx = 0, cy = 0) {
|
|
||||||
;; // Support uniform scaling
|
|
||||||
;; if (arguments.length === 3) {
|
|
||||||
;; cy = cx
|
|
||||||
;; cx = y
|
|
||||||
;; y = x
|
|
||||||
;; }
|
|
||||||
|
|
||||||
;; const { a, b, c, d, e, f } = this
|
|
||||||
|
|
||||||
;; this.a = a * x
|
|
||||||
;; this.b = b * y
|
|
||||||
;; this.c = c * x
|
|
||||||
;; this.d = d * y
|
|
||||||
;; this.e = e * x - cx * x + cx
|
|
||||||
;; this.f = f * y - cy * y + cy
|
|
||||||
|
|
||||||
;; return this
|
|
||||||
;; }
|
|
||||||
|
|
||||||
;; (defn scale
|
|
||||||
;; "Apply scale transformation to the matrix."
|
|
||||||
;; ([m x] (scale m x x))
|
|
||||||
;; ([m x y]
|
|
||||||
;; (let [{:keys [a b c d e f]} m
|
|
||||||
;; cx 0
|
|
||||||
;; cy 0
|
|
||||||
;; a' (* a x)
|
|
||||||
;; b' (* b y)
|
|
||||||
;; c' (* c x)
|
|
||||||
;; d' (* d y)
|
|
||||||
;; e' (+ cx (- (* e x)
|
|
||||||
;; (* cx x)))
|
|
||||||
;; f' (+ cy (- (* f y)
|
|
||||||
;; (* cy y)))]
|
|
||||||
;; (Matrix. a' b' c' d' e f))))
|
|
||||||
|
|
||||||
(defn scale
|
(defn scale
|
||||||
"Apply scale transformation to the matrix."
|
"Apply scale transformation to the matrix."
|
||||||
([m s] (multiply m (scale-matrix s)))
|
([m scale] (multiply m (scale-matrix scale)))
|
||||||
([m s c]
|
([m scale center]
|
||||||
(multiply m
|
(multiply m
|
||||||
(translate-matrix c)
|
(translate-matrix center)
|
||||||
(scale-matrix s)
|
(scale-matrix scale)
|
||||||
(translate-matrix (gpt/negate c)))))
|
(translate-matrix (gpt/negate center)))))
|
||||||
|
|
||||||
(defn translate
|
(defn translate
|
||||||
"Apply translate transformation to the matrix."
|
"Apply translate transformation to the matrix."
|
||||||
[m pt]
|
[m pt]
|
||||||
(let [pt (gpt/point pt)]
|
(multiply m (translate-matrix pt)))
|
||||||
(multiply m (translate-matrix pt))))
|
|
||||||
|
|
||||||
(defn ^boolean invertible?
|
|
||||||
[{:keys [a b c d e f] :as m}]
|
|
||||||
(let [det (- (* a d) (* c b))]
|
|
||||||
(and (not (mth/nan? det))
|
|
||||||
(mth/finite? e)
|
|
||||||
(mth/finite? f))))
|
|
||||||
|
|
||||||
(defn invert
|
|
||||||
[{:keys [a b c d e f] :as m}]
|
|
||||||
(when (invertible? m)
|
|
||||||
(let [det (- (* a d) (* c b))]
|
|
||||||
(Matrix. (/ d det)
|
|
||||||
(/ (- b) det)
|
|
||||||
(/ (- c) det)
|
|
||||||
(/ a det)
|
|
||||||
(/ (- (* c f) (* d e)) det)
|
|
||||||
(/ (- (* b e) (* a f)) det)))))
|
|
||||||
|
|
||||||
;; --- Transit Adapter
|
;; --- Transit Adapter
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; 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) 2016-2017 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2016-2017 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.util.geom.path
|
(ns uxbox.util.geom.path
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
|
||||||
(ns uxbox.util.geom.point
|
(ns uxbox.util.geom.point
|
||||||
(:refer-clojure :exclude [divide])
|
(:refer-clojure :exclude [divide])
|
||||||
|
@ -27,13 +29,6 @@
|
||||||
(point? v)
|
(point? v)
|
||||||
v
|
v
|
||||||
|
|
||||||
(or (vector? v)
|
|
||||||
(seq? v))
|
|
||||||
(Point. (first v) (second v))
|
|
||||||
|
|
||||||
(map? v)
|
|
||||||
(Point. (:x v) (:y v))
|
|
||||||
|
|
||||||
(number? v)
|
(number? v)
|
||||||
(Point. v v)
|
(Point. v v)
|
||||||
|
|
||||||
|
@ -41,105 +36,87 @@
|
||||||
(throw (ex-info "Invalid arguments" {:v v}))))
|
(throw (ex-info "Invalid arguments" {:v v}))))
|
||||||
([x y] (Point. x y)))
|
([x y] (Point. x y)))
|
||||||
|
|
||||||
(defn rotate
|
|
||||||
"Apply rotation transformation to the point."
|
|
||||||
[p angle]
|
|
||||||
{:pre [(point? p)]}
|
|
||||||
(let [angle (mth/radians angle)
|
|
||||||
sin (mth/sin angle)
|
|
||||||
cos (mth/cos angle)]
|
|
||||||
(Point.
|
|
||||||
(-> (- (* (:x p) cos) (* (:y p) sin))
|
|
||||||
(mth/precision 6))
|
|
||||||
(-> (+ (* (:x p) sin) (* (:y p) cos))
|
|
||||||
(mth/precision 6)))))
|
|
||||||
|
|
||||||
(defn add
|
(defn add
|
||||||
"Returns the addition of the supplied value to both
|
"Returns the addition of the supplied value to both
|
||||||
coordinates of the point as a new point."
|
coordinates of the point as a new point."
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [other (point other)]
|
(assert (point? other))
|
||||||
(Point. (+ (:x p) (:x other))
|
(Point. (+ x ox) (+ y oy)))
|
||||||
(+ (:y p) (:y other)))))
|
|
||||||
|
|
||||||
(defn subtract
|
(defn subtract
|
||||||
"Returns the subtraction of the supplied value to both
|
"Returns the subtraction of the supplied value to both
|
||||||
coordinates of the point as a new point."
|
coordinates of the point as a new point."
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [other (point other)]
|
(assert (point? other))
|
||||||
(Point. (- (:x p) (:x other))
|
(Point. (- x ox) (- y oy)))
|
||||||
(- (:y p) (:y other)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn multiply
|
(defn multiply
|
||||||
"Returns the subtraction of the supplied value to both
|
"Returns the subtraction of the supplied value to both
|
||||||
coordinates of the point as a new point."
|
coordinates of the point as a new point."
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [other (point other)]
|
(assert (point? other))
|
||||||
(Point. (* (:x p) (:x other))
|
(Point. (* x ox) (* y oy)))
|
||||||
(* (:y p) (:y other)))))
|
|
||||||
|
|
||||||
(defn divide
|
(defn divide
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [other (point other)]
|
(assert (point? other))
|
||||||
(Point. (/ (:x p) (:x other))
|
(Point. (/ x ox) (/ y oy)))
|
||||||
(/ (:y p) (:y other)))))
|
|
||||||
|
|
||||||
(defn negate
|
(defn negate
|
||||||
[p]
|
[{x :x y :y :as p}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [{:keys [x y]} (point p)]
|
(Point. (- x) (- y)))
|
||||||
(Point. (- x) (- y))))
|
|
||||||
|
|
||||||
(defn distance
|
(defn distance
|
||||||
"Calculate the distance between two points."
|
"Calculate the distance between two points."
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
(let [other (point other)
|
(assert (point? p))
|
||||||
dx (- (:x p) (:x other))
|
(assert (point? other))
|
||||||
dy (- (:y p) (:y other))]
|
(let [dx (- x ox)
|
||||||
|
dy (- y oy)]
|
||||||
(-> (mth/sqrt (+ (mth/pow dx 2)
|
(-> (mth/sqrt (+ (mth/pow dx 2)
|
||||||
(mth/pow dy 2)))
|
(mth/pow dy 2)))
|
||||||
(mth/precision 6))))
|
(mth/precision 6))))
|
||||||
|
|
||||||
(defn length
|
(defn length
|
||||||
[p]
|
[{x :x y :y :as p}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(mth/sqrt (+ (mth/pow (:x p) 2)
|
(mth/sqrt (+ (mth/pow x 2)
|
||||||
(mth/pow (:y p) 2))))
|
(mth/pow y 2))))
|
||||||
|
|
||||||
(defn angle
|
(defn angle
|
||||||
"Returns the smaller angle between two vectors.
|
"Returns the smaller angle between two vectors.
|
||||||
If the second vector is not provided, the angle
|
If the second vector is not provided, the angle
|
||||||
will be measured from x-axis."
|
will be measured from x-axis."
|
||||||
([p]
|
([{x :x y :y :as p}]
|
||||||
(-> (mth/atan2 (:y p) (:x p))
|
(-> (mth/atan2 y x)
|
||||||
(mth/degrees)))
|
(mth/degrees)))
|
||||||
([p center]
|
([p center]
|
||||||
(let [center (point center)]
|
(angle (subtract p center))))
|
||||||
(angle (subtract p center)))))
|
|
||||||
|
|
||||||
(defn angle-with-other
|
(defn angle-with-other
|
||||||
"Consider point as vector and calculate
|
"Consider point as vector and calculate
|
||||||
the angle between two vectors."
|
the angle between two vectors."
|
||||||
[p other]
|
[{x :x y :y :as p} {ox :x oy :y :as other}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(let [other (point other)
|
(assert (point? other))
|
||||||
a (/ (+ (* (:x p) (:x other))
|
(let [a (/ (+ (* x ox)
|
||||||
(* (:y p) (:y other)))
|
(* y oy))
|
||||||
(* (length p) (length other)))
|
(* (length p)
|
||||||
a (mth/acos (if (< a -1)
|
(length other)))
|
||||||
-1
|
a (mth/acos (if (< a -1) -1 (if (> a 1) 1 a)))]
|
||||||
(if (> a 1) 1 a)))]
|
|
||||||
(-> (mth/degrees a)
|
(-> (mth/degrees a)
|
||||||
(mth/precision 6))))
|
(mth/precision 6))))
|
||||||
|
|
||||||
(defn update-angle
|
(defn update-angle
|
||||||
"Update the angle of the point."
|
"Update the angle of the point."
|
||||||
[p angle]
|
[p angle]
|
||||||
|
(assert (point? p))
|
||||||
|
(assert (number? angle))
|
||||||
(let [len (length p)
|
(let [len (length p)
|
||||||
angle (mth/radians angle)]
|
angle (mth/radians angle)]
|
||||||
(Point. (* (mth/cos angle) len)
|
(Point. (* (mth/cos angle) len)
|
||||||
|
@ -148,24 +125,25 @@
|
||||||
(defn quadrant
|
(defn quadrant
|
||||||
"Return the quadrant of the angle of the point."
|
"Return the quadrant of the angle of the point."
|
||||||
[{:keys [x y] :as p}]
|
[{:keys [x y] :as p}]
|
||||||
{:pre [(point? p)]}
|
(assert (point? p))
|
||||||
(if (>= x 0)
|
(if (>= x 0)
|
||||||
(if (>= y 0) 1 4)
|
(if (>= y 0) 1 4)
|
||||||
(if (>= y 0) 2 3)))
|
(if (>= y 0) 2 3)))
|
||||||
|
|
||||||
(defn round
|
(defn round
|
||||||
"Change the precision of the point coordinates."
|
"Change the precision of the point coordinates."
|
||||||
[{:keys [x y]} decimanls]
|
[{:keys [x y] :as p} decimanls]
|
||||||
|
(assert (point? p))
|
||||||
|
(assert (number? decimanls))
|
||||||
(Point. (mth/precision x decimanls)
|
(Point. (mth/precision x decimanls)
|
||||||
(mth/precision y decimanls)))
|
(mth/precision y decimanls)))
|
||||||
|
|
||||||
(defn transform
|
(defn transform
|
||||||
"Transform a point applying a matrix transfomation."
|
"Transform a point applying a matrix transfomation."
|
||||||
[pt {:keys [a b c d e f] :as m}]
|
[{:keys [x y] :as p} {:keys [a b c d e f] :as m}]
|
||||||
(let [{:keys [x y]} (point pt)]
|
(assert (point? p))
|
||||||
(Point. (+ (* x a) (* y c) e)
|
(Point. (+ (* x a) (* y c) e)
|
||||||
(+ (* x b) (* y d) f))))
|
(+ (* x b) (* y d) f)))
|
||||||
|
|
||||||
|
|
||||||
;; --- Transit Adapter
|
;; --- Transit Adapter
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
(ns uxbox.tests.test-util-geom
|
(ns uxbox.tests.test-util-geom
|
||||||
(:require [cljs.test :as t :include-macros true]
|
(:require [cljs.test :as t :include-macros true]
|
||||||
[cljs.pprint :refer [pprint]]
|
[cljs.pprint :refer [pprint]]
|
||||||
|
;; [uxbox.util.geom.point-impl :as gpt2]
|
||||||
|
;; [uxbox.util.geom.matrix-impl :as gmt2]
|
||||||
[uxbox.util.geom.point :as gpt]
|
[uxbox.util.geom.point :as gpt]
|
||||||
[uxbox.util.geom.matrix :as gmt]))
|
[uxbox.util.geom.matrix :as gmt]))
|
||||||
|
|
||||||
(t/deftest point-constructors-test
|
(t/deftest point-constructors-test
|
||||||
(let [p (gpt/point 1 2)]
|
(let [p (gpt/point 1 2)]
|
||||||
(t/is (= (:x p) 1))
|
(t/is (= (:x p) 1))
|
||||||
(t/is (= (:y p) 2))
|
(t/is (= (:y p) 2)))
|
||||||
(t/is (gpt/point? p)))
|
|
||||||
|
|
||||||
(let [p (gpt/point 1)]
|
(let [p (gpt/point 1)]
|
||||||
(t/is (= (:x p) 1))
|
(t/is (= (:x p) 1))
|
||||||
|
@ -16,34 +17,27 @@
|
||||||
|
|
||||||
(let [p (gpt/point)]
|
(let [p (gpt/point)]
|
||||||
(t/is (= (:x p) 0))
|
(t/is (= (:x p) 0))
|
||||||
(t/is (= (:y p) 0)))
|
(t/is (= (:y p) 0))))
|
||||||
|
|
||||||
(let [p (gpt/point [1 2])]
|
;; (t/deftest point-rotate-test
|
||||||
(t/is (= (:x p) 1))
|
;; (let [p1 (gpt/point 10 0)
|
||||||
(t/is (= (:y p) 2))))
|
;; p2 (gpt/rotate p1 90)]
|
||||||
|
;; (t/is (= (:x p2) 0))
|
||||||
(t/deftest point-rotate-test
|
;; (t/is (= (:y p2) 10))))
|
||||||
(let [p1 (gpt/point 10 0)
|
|
||||||
p2 (gpt/rotate p1 90)]
|
|
||||||
(t/is (= (:x p2) 0))
|
|
||||||
(t/is (= (:y p2) 10))
|
|
||||||
(t/is (gpt/point? p2))))
|
|
||||||
|
|
||||||
(t/deftest point-add-test
|
(t/deftest point-add-test
|
||||||
(let [p1 (gpt/point 1 1)
|
(let [p1 (gpt/point 1 1)
|
||||||
p2 (gpt/point 2 2)
|
p2 (gpt/point 2 2)
|
||||||
p3 (gpt/add p1 p2)]
|
p3 (gpt/add p1 p2)]
|
||||||
(t/is (= (:x p3) 3))
|
(t/is (= (:x p3) 3))
|
||||||
(t/is (= (:y p3) 3))
|
(t/is (= (:y p3) 3))))
|
||||||
(t/is (gpt/point? p3))))
|
|
||||||
|
|
||||||
(t/deftest point-subtract-test
|
(t/deftest point-subtract-test
|
||||||
(let [p1 (gpt/point 3 3)
|
(let [p1 (gpt/point 3 3)
|
||||||
p2 (gpt/point 2 2)
|
p2 (gpt/point 2 2)
|
||||||
p3 (gpt/subtract p1 p2)]
|
p3 (gpt/subtract p1 p2)]
|
||||||
(t/is (= (:x p3) 1))
|
(t/is (= (:x p3) 1))
|
||||||
(t/is (= (:y p3) 1))
|
(t/is (= (:y p3) 1))))
|
||||||
(t/is (gpt/point? p3))))
|
|
||||||
|
|
||||||
(t/deftest point-distance-test
|
(t/deftest point-distance-test
|
||||||
(let [p1 (gpt/point 0 0)
|
(let [p1 (gpt/point 0 0)
|
||||||
|
@ -69,46 +63,23 @@
|
||||||
(t/is (number? angle))
|
(t/is (number? angle))
|
||||||
(t/is (= angle 45))))
|
(t/is (= angle 45))))
|
||||||
|
|
||||||
(t/deftest point-quadrant-test
|
|
||||||
(let [p1 (gpt/point 10 10)
|
|
||||||
p2 (gpt/point -10 10)
|
|
||||||
p3 (gpt/point -10 -10)
|
|
||||||
p4 (gpt/point 10 -10)]
|
|
||||||
|
|
||||||
(t/is (= 1 (gpt/quadrant p1)))
|
|
||||||
(t/is (= 2 (gpt/quadrant p2)))
|
|
||||||
(t/is (= 3 (gpt/quadrant p3)))
|
|
||||||
(t/is (= 4 (gpt/quadrant p4)))))
|
|
||||||
|
|
||||||
|
|
||||||
(t/deftest matrix-constructors-test
|
(t/deftest matrix-constructors-test
|
||||||
(let [m (gmt/matrix)]
|
(let [m (gmt/matrix)]
|
||||||
(t/is (= @m [1 0 0 1 0 0]))
|
(t/is (= (str m) "matrix(1,0,0,1,0,0)")))
|
||||||
(t/is (gmt/matrix? m)))
|
|
||||||
(let [m (gmt/matrix 1 1 1 2 2 2)]
|
(let [m (gmt/matrix 1 1 1 2 2 2)]
|
||||||
(t/is (= @m [1 1 1 2 2 2]))
|
(t/is (= (str m) "matrix(1,1,1,2,2,2)"))))
|
||||||
(t/is (gmt/matrix? m)))
|
|
||||||
(let [m (gmt/matrix [1 1 1 2 2 2])]
|
(t/deftest matrix-translate-test
|
||||||
(t/is (= @m [1 1 1 2 2 2]))
|
(let [m (-> (gmt/matrix)
|
||||||
(t/is (gmt/matrix? m))))
|
(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
|
(t/deftest matrix-rotate-test
|
||||||
(let [m (-> (gmt/matrix)
|
(let [m (-> (gmt/matrix)
|
||||||
(gmt/rotate 10))]
|
(gmt/rotate 10))]
|
||||||
|
(t/is (str m) "matrix(0.984807753012208,0.17364817766693033,-0.17364817766693033,0.984807753012208,0,0)")))
|
||||||
(t/is (= @m [0.984807753012208
|
|
||||||
0.17364817766693033
|
|
||||||
-0.17364817766693033
|
|
||||||
0.984807753012208
|
|
||||||
0 0]))))
|
|
||||||
|
|
||||||
(t/deftest matrix-scale-test
|
|
||||||
(let [m (-> (gmt/matrix)
|
|
||||||
(gmt/scale 2))]
|
|
||||||
(t/is (= @m [2 0 0 2 0 0]))))
|
|
||||||
|
|
||||||
(t/deftest matrix-translate-test
|
|
||||||
(let [m (-> (gmt/matrix)
|
|
||||||
(gmt/translate 2 10))]
|
|
||||||
(t/is (= @m [1 0 0 1 2 10]))))
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue