0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-23 23:18:48 -05:00

Add optimized version of apply-transform

using internal mutation
This commit is contained in:
Andrey Antukh 2023-06-22 09:59:39 +02:00
parent 723aab6b80
commit 0b4b14af9e
3 changed files with 76 additions and 74 deletions

View file

@ -272,7 +272,7 @@
transform (calculate-transform points center selrect)]
[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
to check this before adjusting the selrect"
[shape points]
@ -282,88 +282,92 @@
;; FIXME: unroll and remove point allocation here
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)
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)]
(cond-> shape
(neg? dot-x)
(-> (update :flip-x not)
(-> (cr/update! :flip-x not)
(cr/update! :rotation -))
(neg? dot-y)
(-> (update :flip-y not)
(-> (cr/update! :flip-y not)
(cr/update! :rotation -)))))
(defn- apply-transform-move
"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"
[shape transform-mtx]
(let [bool? (= (:type shape) :bool)
path? (= (:type shape) :path)
text? (= (:type shape) :text)
{dx :x dy :y} (gpt/transform (gpt/point) transform-mtx)
points (gco/transform-points (:points shape) transform-mtx)
selrect (gco/transform-selrect (:selrect shape) transform-mtx)]
(let [type (dm/get-prop shape :type)
points (gco/transform-points (dm/get-prop shape :points) transform-mtx)
selrect (gco/transform-selrect (dm/get-prop shape :selrect) transform-mtx)
;; NOTE: ensure we start with a fresh copy of shape for mutabilty
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
(cond-> bool?
(update :bool-content gpa/transform-content transform-mtx))
(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))))
(cr/assoc! :selrect selrect)
(cr/assoc! :points points))))
(defn- apply-transform-generic
"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"
[shape transform-mtx]
(let [points (-> (dm/get-prop shape :points)
(gco/transform-points transform-mtx))
(let [points' (:points shape)
points (gco/transform-points points' transform-mtx)
shape (-> shape (adjust-shape-flips points))
bool? (= (:type shape) :bool)
path? (= (:type shape) :path)
;; NOTE: ensure we have a fresh shallow copy of shape
shape (cr/clone shape)
shape (adjust-shape-flips! shape points)
[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)
;; When we cannot calculate the transformation we leave the shape as it was
(if-not (and (some? inverse) (some? transform))
shape
(-> shape
(cond-> bool?
(update :bool-content gpa/transform-content transform-mtx))
(cond-> path?
(update :content gpa/transform-content transform-mtx))
(cond-> (not path?)
(assoc :x (:x selrect)
: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))
(let [type (dm/get-prop shape :type)
rotation (mod (+ (d/nilv (:rotation shape) 0)
(d/nilv (dm/get-in shape [:modifiers :rotation]) 0))
360)
shape (if (= type :bool)
(update shape :bool-content gpa/transform-content transform-mtx)
shape)
(cond-> (d/not-empty? points)
(assoc :points points))
(assoc :rotation rotation)))))
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
(cr/assoc! :transform transform)
(cr/assoc! :transform-inverse inverse)
(cr/assoc! :selrect selrect)
(cr/assoc! :points points)
(cr/assoc! :rotation rotation))))))
(defn- apply-transform
"Given a new set of points transformed, set up the rectangle so it keeps

View file

@ -239,7 +239,8 @@
"A record specific update operation"
[ssym ksym f & params]
(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)))
(defmacro define-properties!

View file

@ -28,16 +28,14 @@
([type params]
(if (= type :path)
(cts/setup-shape
(merge
{:type :path
:content (:content params default-path)}
params))
(into {:type :path
:content (:content params default-path)}
params))
(cts/setup-shape
(merge
{:type type
:width 20
:height 20}
params)))))
(into {:type type
:width 20
:height 20}
params)))))
(t/deftest transform-shapes
(t/testing "Shape without modifiers should stay the same"
@ -112,15 +110,14 @@
:rect :path))
(t/testing "Transform with resize=0"
(t/are [type]
(let [modifiers (ctm/resize-modifiers (gpt/point 0 0) (gpt/point 0 0))
shape-before (create-test-shape type {:modifiers modifiers})
shape-after (gsh/transform-shape shape-before)]
(t/is (close? (get-in shape-before [:selrect :width])
(get-in shape-after [:selrect :width])))
(t/is (close? (get-in shape-before [:selrect :height])
(get-in shape-after [:selrect :height]))))
:rect :path))
(let [modifiers (ctm/resize-modifiers (gpt/point 0 0) (gpt/point 0 0))
shape-before (create-test-shape :rect {:modifiers modifiers})
shape-after (gsh/transform-shape shape-before)]
(t/is (close? (get-in shape-before [:selrect :width])
(get-in shape-after [:selrect :width])))
(t/is (close? (get-in shape-before [:selrect :height])
(get-in shape-after [:selrect :height])))))
(t/testing "Transform shape with rotation modifiers"
(t/are [type]