0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 07:29:08 -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)] 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

View file

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

View file

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