Performance improvements.

This commit is contained in:
Andrey Antukh 2020-01-16 16:22:56 +01:00
parent 3ab5e11d5f
commit 76e19a4b41
9 changed files with 134 additions and 349 deletions

View file

@ -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]))

View file

@ -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)

View file

@ -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

View file

@ -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 %)

View file

@ -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"}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]))))