0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-16 01:31:22 -05:00

Add lightweight optimization to modifiers handling

Mainly using controlled internal mutation when is possible
This commit is contained in:
Andrey Antukh 2023-06-20 11:47:19 +02:00
parent 4a4423da70
commit 3ab67e4545
2 changed files with 103 additions and 33 deletions

View file

@ -19,8 +19,7 @@
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.text :as txt] [app.common.text :as txt]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
#?(:cljs [cljs.core :as c] [clojure.core :as c]))
:clj [clojure.core :as c])))
;; --- Modifiers ;; --- Modifiers
@ -106,18 +105,17 @@
[property value] [property value]
(StructureOperation. :change-property property value nil)) (StructureOperation. :change-property property value nil))
;; Private aux functions ;; Private aux functions
(defn- move-vec? (defn- move-vec?
[vector] [vector]
(or (not (mth/almost-zero? (dm/get-prop vector :x))) (or (not ^boolean (mth/almost-zero? (dm/get-prop vector :x)))
(not (mth/almost-zero? (dm/get-prop vector :y))))) (not ^boolean (mth/almost-zero? (dm/get-prop vector :y)))))
(defn- resize-vec? (defn- resize-vec?
[vector] [vector]
(or (not (mth/almost-zero? (- (dm/get-prop vector :x) 1))) (or (not ^boolean (mth/almost-zero? (- (dm/get-prop vector :x) 1)))
(not (mth/almost-zero? (- (dm/get-prop vector :y) 1))))) (not ^boolean (mth/almost-zero? (- (dm/get-prop vector :y) 1)))))
(defn- mergeable-move? (defn- mergeable-move?
[op1 op2] [op1 op2]
@ -128,22 +126,24 @@
(defn- mergeable-resize? (defn- mergeable-resize?
[op1 op2] [op1 op2]
(let [type-op1 (dm/get-prop op1 :type) (let [type-op1 (dm/get-prop op1 :type)
transform-op1 (or (dm/get-prop op1 :transform) (gmt/matrix)) transform-op1 (d/nilv (dm/get-prop op1 :transform) gmt/base)
transform-inv-op1 (or (dm/get-prop op1 :transform-inverse) (gmt/matrix)) transform-inv-op1 (d/nilv (dm/get-prop op1 :transform-inverse) gmt/base)
origin-op1 (dm/get-prop op1 :origin) origin-op1 (dm/get-prop op1 :origin)
type-op2 (dm/get-prop op2 :type) type-op2 (dm/get-prop op2 :type)
transform-op2 (or (dm/get-prop op2 :transform) (gmt/matrix)) transform-op2 (d/nilv (dm/get-prop op2 :transform) gmt/base)
transform-inv-op2 (or (dm/get-prop op2 :transform-inverse) (gmt/matrix)) transform-inv-op2 (d/nilv (dm/get-prop op2 :transform-inverse) gmt/base)
origin-op2 (dm/get-prop op2 :origin)] origin-op2 (dm/get-prop op2 :origin)]
(and (= :resize type-op1) (= :resize type-op2)
(and (= :resize type-op1)
(= :resize type-op2)
;; Same origin ;; Same origin
(gpt/close? origin-op1 origin-op2) ^boolean (gpt/close? origin-op1 origin-op2)
;; Same transforms ;; Same transforms
(gmt/close? transform-op1 transform-op2) ^boolean (gmt/close? transform-op1 transform-op2)
(gmt/close? transform-inv-op1 transform-inv-op2)))) ^boolean (gmt/close? transform-inv-op1 transform-inv-op2))))
(defn- merge-move (defn- merge-move
[op1 op2] [op1 op2]
@ -155,14 +155,15 @@
(defn- merge-resize (defn- merge-resize
[op1 op2] [op1 op2]
(let [op1-vector (dm/get-prop op1 :vector) (let [op1-vector (dm/get-prop op1 :vector)
op1-x (dm/get-prop op1-vector :x) op1-x (dm/get-prop op1-vector :x)
op1-y (dm/get-prop op1-vector :y) op1-y (dm/get-prop op1-vector :y)
op2-vector (dm/get-prop op2 :vector) op2-vector (dm/get-prop op2 :vector)
op2-x (dm/get-prop op2-vector :x) op2-x (dm/get-prop op2-vector :x)
op2-y (dm/get-prop op2-vector :y) op2-y (dm/get-prop op2-vector :y)
vector (gpt/point (* op1-x op2-x) (* op1-y op2-y))] vector (gpt/point (* op1-x op2-x)
(* op1-y op2-y))]
(assoc op1 :vector vector))) (assoc op1 :vector vector)))
(defn- maybe-add-move (defn- maybe-add-move
@ -198,10 +199,7 @@
[vector] [vector]
(let [x (dm/get-prop vector :x) (let [x (dm/get-prop vector :x)
y (dm/get-prop vector :y)] y (dm/get-prop vector :y)]
(and (some? x) (d/num? x y)))
(some? y)
(not (mth/nan? x))
(not (mth/nan? y)))))
;; Public builder API ;; Public builder API
@ -245,8 +243,11 @@
(move modifiers (gpt/point x y))) (move modifiers (gpt/point x y)))
([modifiers vector] ([modifiers vector]
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (dm/assert!
(let [modifiers (or modifiers (empty)) ["Invalid move vector: %1,%2" (:x vector) (:y vector)]
(valid-vector? vector))
(let [modifiers (or ^boolean modifiers (empty))
order (inc (dm/get-prop modifiers :last-order)) order (inc (dm/get-prop modifiers :last-order))
modifiers (assoc modifiers :last-order order)] modifiers (assoc modifiers :last-order order)]
(cond-> modifiers (cond-> modifiers
@ -256,7 +257,7 @@
(defn resize (defn resize
([modifiers vector origin] ([modifiers vector origin]
(assert (valid-vector? vector) (dm/str "Invalid resize vector: " (:x vector) "," (:y vector))) (assert (valid-vector? vector) (dm/str "Invalid resize vector: " (:x vector) "," (:y vector)))
(let [modifiers (or modifiers (empty)) (let [modifiers (or ^boolean modifiers (empty))
order (inc (dm/get-prop modifiers :last-order)) order (inc (dm/get-prop modifiers :last-order))
modifiers (assoc modifiers :last-order order)] modifiers (assoc modifiers :last-order order)]
(cond-> modifiers (cond-> modifiers
@ -594,7 +595,72 @@
;; Main transformation functions ;; Main transformation functions
(defn transform-move!
"Transforms a matrix by the translation modifier"
[matrix modifier]
(-> (dm/get-prop modifier :vector)
(gmt/translate-matrix)
(gmt/multiply! matrix)))
(defn transform-resize!
"Transforms a matrix by the resize modifier"
[matrix modifier]
(let [tf (dm/get-prop modifier :transform)
tfi (dm/get-prop modifier :transform-inverse)
vector (dm/get-prop modifier :vector)
origin (dm/get-prop modifier :origin)
origin (if ^boolean (some? tfi)
(gpt/transform origin tfi)
origin)]
(gmt/multiply!
(-> (gmt/matrix)
(cond-> ^boolean (some? tf)
(gmt/multiply! tf))
(gmt/translate! origin)
(gmt/scale! vector)
(gmt/translate! (gpt/negate origin))
(cond-> ^boolean (some? tfi)
(gmt/multiply! tfi)))
matrix)))
(defn transform-rotate!
"Transforms a matrix by the rotation modifier"
[matrix modifier]
(let [center (dm/get-prop modifier :center)
rotation (dm/get-prop modifier :rotation)]
(gmt/multiply!
(-> (gmt/matrix)
(gmt/translate! center)
(gmt/multiply! (gmt/rotate-matrix rotation))
(gmt/translate! (gpt/negate center)))
matrix)))
(defn transform!
"Returns a matrix transformed by the modifier"
[matrix modifier]
(let [type (dm/get-prop modifier :type)]
(case type
:move (transform-move! matrix modifier)
:resize (transform-resize! matrix modifier)
:rotation (transform-rotate! matrix modifier))))
(defn modifiers->transform1
"A multiplatform version of modifiers->transform."
[modifiers]
(reduce transform! (gmt/matrix) modifiers))
(defn modifiers->transform (defn modifiers->transform
"Given a set of modifiers returns its transformation matrix"
[modifiers]
(let [modifiers (concat (dm/get-prop modifiers :geometry-parent)
(dm/get-prop modifiers :geometry-child))
modifiers (sort-by #(dm/get-prop % :order) modifiers)
]
(modifiers->transform1 modifiers)))
(defn modifiers->transform-old
"Given a set of modifiers returns its transformation matrix" "Given a set of modifiers returns its transformation matrix"
[modifiers] [modifiers]
(let [modifiers (->> (concat (dm/get-prop modifiers :geometry-parent) (let [modifiers (->> (concat (dm/get-prop modifiers :geometry-parent)

View file

@ -377,7 +377,15 @@
(update [_ state] (update [_ state]
(assoc state :workspace-modifiers (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree params)))))) (assoc state :workspace-modifiers (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree params))))))
;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). (def ^:private
xf-rotation-shape
(comp
(remove #(get % :blocked false))
(filter #(:rotation (get editable-attrs (:type %))))
(map :id)))
;; Rotation use different algorithm to calculate children
;; modifiers (and do not use child constraints).
(defn set-rotation-modifiers (defn set-rotation-modifiers
([angle shapes] ([angle shapes]
(set-rotation-modifiers angle shapes (-> shapes gsh/shapes->rect grc/rect->center))) (set-rotation-modifiers angle shapes (-> shapes gsh/shapes->rect grc/rect->center)))
@ -387,11 +395,7 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [objects (wsh/lookup-page-objects state) (let [objects (wsh/lookup-page-objects state)
ids ids (sequence xf-rotation-shape shapes)
(->> shapes
(remove #(get % :blocked false))
(filter #(:rotation (get editable-attrs (:type %))))
(map :id))
get-modifier get-modifier
(fn [shape] (fn [shape]