mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 15:39:50 -05:00
⚡ Add optimized version of apply-transform
using internal mutation
This commit is contained in:
parent
723aab6b80
commit
0b4b14af9e
3 changed files with 76 additions and 74 deletions
|
@ -272,7 +272,7 @@
|
||||||
transform (calculate-transform points center selrect)]
|
transform (calculate-transform points center selrect)]
|
||||||
[selrect transform (when (some? transform) (gmt/inverse transform))]))
|
[selrect transform (when (some? transform) (gmt/inverse transform))]))
|
||||||
|
|
||||||
(defn- adjust-shape-flips
|
(defn- adjust-shape-flips!
|
||||||
"After some tranformations the flip-x/flip-y flags can change we need
|
"After some tranformations the flip-x/flip-y flags can change we need
|
||||||
to check this before adjusting the selrect"
|
to check this before adjusting the selrect"
|
||||||
[shape points]
|
[shape points]
|
||||||
|
@ -282,88 +282,92 @@
|
||||||
|
|
||||||
;; FIXME: unroll and remove point allocation here
|
;; FIXME: unroll and remove point allocation here
|
||||||
xv1 (gpt/to-vec p0' (nth points' 1))
|
xv1 (gpt/to-vec p0' (nth points' 1))
|
||||||
xv2 (gpt/to-vec p0 (nth points 1))
|
xv2 (gpt/to-vec p0 (nth points 1))
|
||||||
dot-x (gpt/dot xv1 xv2)
|
dot-x (gpt/dot xv1 xv2)
|
||||||
|
|
||||||
yv1 (gpt/to-vec p0' (nth points' 3))
|
yv1 (gpt/to-vec p0' (nth points' 3))
|
||||||
yv2 (gpt/to-vec p0 (nth points 3))
|
yv2 (gpt/to-vec p0 (nth points 3))
|
||||||
dot-y (gpt/dot yv1 yv2)]
|
dot-y (gpt/dot yv1 yv2)]
|
||||||
|
|
||||||
(cond-> shape
|
(cond-> shape
|
||||||
(neg? dot-x)
|
(neg? dot-x)
|
||||||
(-> (update :flip-x not)
|
(-> (cr/update! :flip-x not)
|
||||||
(cr/update! :rotation -))
|
(cr/update! :rotation -))
|
||||||
|
|
||||||
(neg? dot-y)
|
(neg? dot-y)
|
||||||
(-> (update :flip-y not)
|
(-> (cr/update! :flip-y not)
|
||||||
(cr/update! :rotation -)))))
|
(cr/update! :rotation -)))))
|
||||||
|
|
||||||
(defn- apply-transform-move
|
(defn- apply-transform-move
|
||||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||||
its properties. We adjust de x,y,width,height and create a custom transform"
|
its properties. We adjust de x,y,width,height and create a custom transform"
|
||||||
[shape transform-mtx]
|
[shape transform-mtx]
|
||||||
(let [bool? (= (:type shape) :bool)
|
(let [type (dm/get-prop shape :type)
|
||||||
path? (= (:type shape) :path)
|
points (gco/transform-points (dm/get-prop shape :points) transform-mtx)
|
||||||
text? (= (:type shape) :text)
|
selrect (gco/transform-selrect (dm/get-prop shape :selrect) transform-mtx)
|
||||||
{dx :x dy :y} (gpt/transform (gpt/point) transform-mtx)
|
|
||||||
points (gco/transform-points (:points shape) transform-mtx)
|
;; NOTE: ensure we start with a fresh copy of shape for mutabilty
|
||||||
selrect (gco/transform-selrect (:selrect shape) transform-mtx)]
|
shape (cr/clone shape)
|
||||||
|
|
||||||
|
shape (if (= type :bool)
|
||||||
|
(update shape :bool-content gpa/transform-content transform-mtx)
|
||||||
|
shape)
|
||||||
|
shape (if (= type :text)
|
||||||
|
(update shape :position-data move-position-data transform-mtx)
|
||||||
|
shape)
|
||||||
|
shape (if (= type :path)
|
||||||
|
(update shape :content gpa/transform-content transform-mtx)
|
||||||
|
(cr/assoc! shape
|
||||||
|
:x (dm/get-prop selrect :x)
|
||||||
|
:y (dm/get-prop selrect :y)
|
||||||
|
:width (dm/get-prop selrect :width)
|
||||||
|
:height (dm/get-prop selrect :height)))]
|
||||||
(-> shape
|
(-> shape
|
||||||
(cond-> bool?
|
(cr/assoc! :selrect selrect)
|
||||||
(update :bool-content gpa/transform-content transform-mtx))
|
(cr/assoc! :points points))))
|
||||||
(cond-> path?
|
|
||||||
(update :content gpa/transform-content transform-mtx))
|
|
||||||
(cond-> text?
|
|
||||||
(update :position-data move-position-data dx dy))
|
|
||||||
(cond-> (not path?)
|
|
||||||
(assoc :x (:x selrect)
|
|
||||||
:y (:y selrect)
|
|
||||||
:width (:width selrect)
|
|
||||||
:height (:height selrect)))
|
|
||||||
(assoc :selrect selrect)
|
|
||||||
(assoc :points points))))
|
|
||||||
|
|
||||||
(defn- apply-transform-generic
|
(defn- apply-transform-generic
|
||||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||||
its properties. We adjust de x,y,width,height and create a custom transform"
|
its properties. We adjust de x,y,width,height and create a custom transform"
|
||||||
[shape transform-mtx]
|
[shape transform-mtx]
|
||||||
|
(let [points (-> (dm/get-prop shape :points)
|
||||||
|
(gco/transform-points transform-mtx))
|
||||||
|
|
||||||
(let [points' (:points shape)
|
;; NOTE: ensure we have a fresh shallow copy of shape
|
||||||
points (gco/transform-points points' transform-mtx)
|
shape (cr/clone shape)
|
||||||
shape (-> shape (adjust-shape-flips points))
|
shape (adjust-shape-flips! shape points)
|
||||||
bool? (= (:type shape) :bool)
|
|
||||||
path? (= (:type shape) :path)
|
|
||||||
|
|
||||||
[selrect transform transform-inverse] (calculate-geometry points)
|
center (gco/points->center points)
|
||||||
|
selrect (calculate-selrect points center)
|
||||||
|
transform (calculate-transform points center selrect)
|
||||||
|
inverse (when (some? transform) (gmt/inverse transform))
|
||||||
|
|
||||||
base-rotation (or (:rotation shape) 0)
|
]
|
||||||
modif-rotation (or (get-in shape [:modifiers :rotation]) 0)
|
|
||||||
rotation (mod (+ base-rotation modif-rotation) 360)]
|
|
||||||
|
|
||||||
(if-not (and transform transform-inverse)
|
(if-not (and (some? inverse) (some? transform))
|
||||||
;; When we cannot calculate the transformation we leave the shape as it was
|
|
||||||
shape
|
shape
|
||||||
(-> shape
|
(let [type (dm/get-prop shape :type)
|
||||||
(cond-> bool?
|
rotation (mod (+ (d/nilv (:rotation shape) 0)
|
||||||
(update :bool-content gpa/transform-content transform-mtx))
|
(d/nilv (dm/get-in shape [:modifiers :rotation]) 0))
|
||||||
(cond-> path?
|
360)
|
||||||
(update :content gpa/transform-content transform-mtx))
|
shape (if (= type :bool)
|
||||||
(cond-> (not path?)
|
(update shape :bool-content gpa/transform-content transform-mtx)
|
||||||
(assoc :x (:x selrect)
|
shape)
|
||||||
:y (:y selrect)
|
|
||||||
:width (:width selrect)
|
|
||||||
:height (:height selrect)))
|
|
||||||
(cond-> transform
|
|
||||||
(-> (assoc :transform transform)
|
|
||||||
(assoc :transform-inverse transform-inverse)))
|
|
||||||
(cond-> (not transform)
|
|
||||||
(dissoc :transform :transform-inverse))
|
|
||||||
(cond-> (some? selrect)
|
|
||||||
(assoc :selrect selrect))
|
|
||||||
|
|
||||||
(cond-> (d/not-empty? points)
|
shape (if (= type :path)
|
||||||
(assoc :points points))
|
(update shape :content gpa/transform-content transform-mtx)
|
||||||
(assoc :rotation rotation)))))
|
(cr/assoc! shape
|
||||||
|
:x (dm/get-prop selrect :x)
|
||||||
|
:y (dm/get-prop selrect :y)
|
||||||
|
:width (dm/get-prop selrect :width)
|
||||||
|
:height (dm/get-prop selrect :height)))]
|
||||||
|
(-> shape
|
||||||
|
(cr/assoc! :transform transform)
|
||||||
|
(cr/assoc! :transform-inverse inverse)
|
||||||
|
(cr/assoc! :selrect selrect)
|
||||||
|
(cr/assoc! :points points)
|
||||||
|
(cr/assoc! :rotation rotation))))))
|
||||||
|
|
||||||
(defn- apply-transform
|
(defn- apply-transform
|
||||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||||
|
|
|
@ -239,7 +239,8 @@
|
||||||
"A record specific update operation"
|
"A record specific update operation"
|
||||||
[ssym ksym f & params]
|
[ssym ksym f & params]
|
||||||
(if (:ns &env)
|
(if (:ns &env)
|
||||||
`(cljs.core/-assoc! ~ssym ~ksym (~f (. ~ssym ~(property-symbol ksym)) ~@params))
|
(let [ssym (with-meta ssym {:tag 'js})]
|
||||||
|
`(cljs.core/assoc! ~ssym ~ksym (~f (. ~ssym ~(property-symbol ksym)) ~@params)))
|
||||||
`(update ~ssym ~ksym ~f ~@params)))
|
`(update ~ssym ~ksym ~f ~@params)))
|
||||||
|
|
||||||
(defmacro define-properties!
|
(defmacro define-properties!
|
||||||
|
|
|
@ -28,16 +28,14 @@
|
||||||
([type params]
|
([type params]
|
||||||
(if (= type :path)
|
(if (= type :path)
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
(merge
|
(into {:type :path
|
||||||
{:type :path
|
:content (:content params default-path)}
|
||||||
:content (:content params default-path)}
|
params))
|
||||||
params))
|
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
(merge
|
(into {:type type
|
||||||
{:type type
|
:width 20
|
||||||
:width 20
|
:height 20}
|
||||||
:height 20}
|
params)))))
|
||||||
params)))))
|
|
||||||
|
|
||||||
(t/deftest transform-shapes
|
(t/deftest transform-shapes
|
||||||
(t/testing "Shape without modifiers should stay the same"
|
(t/testing "Shape without modifiers should stay the same"
|
||||||
|
@ -112,15 +110,14 @@
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
|
||||||
(t/testing "Transform with resize=0"
|
(t/testing "Transform with resize=0"
|
||||||
(t/are [type]
|
(let [modifiers (ctm/resize-modifiers (gpt/point 0 0) (gpt/point 0 0))
|
||||||
(let [modifiers (ctm/resize-modifiers (gpt/point 0 0) (gpt/point 0 0))
|
shape-before (create-test-shape :rect {:modifiers modifiers})
|
||||||
shape-before (create-test-shape type {:modifiers modifiers})
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
|
||||||
(t/is (close? (get-in shape-before [:selrect :width])
|
(t/is (close? (get-in shape-before [:selrect :width])
|
||||||
(get-in shape-after [:selrect :width])))
|
(get-in shape-after [:selrect :width])))
|
||||||
(t/is (close? (get-in shape-before [:selrect :height])
|
(t/is (close? (get-in shape-before [:selrect :height])
|
||||||
(get-in shape-after [:selrect :height]))))
|
(get-in shape-after [:selrect :height])))))
|
||||||
:rect :path))
|
|
||||||
|
|
||||||
(t/testing "Transform shape with rotation modifiers"
|
(t/testing "Transform shape with rotation modifiers"
|
||||||
(t/are [type]
|
(t/are [type]
|
||||||
|
|
Loading…
Add table
Reference in a new issue