mirror of
https://github.com/penpot/penpot.git
synced 2025-03-15 17:21:17 -05:00
⚡ Add lightweight optimization to modifiers handling
Mainly using controlled internal mutation when is possible
This commit is contained in:
parent
4a4423da70
commit
3ab67e4545
2 changed files with 103 additions and 33 deletions
|
@ -19,8 +19,7 @@
|
|||
[app.common.pages.helpers :as cph]
|
||||
[app.common.text :as txt]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
#?(:cljs [cljs.core :as c]
|
||||
:clj [clojure.core :as c])))
|
||||
[clojure.core :as c]))
|
||||
|
||||
;; --- Modifiers
|
||||
|
||||
|
@ -106,18 +105,17 @@
|
|||
[property value]
|
||||
(StructureOperation. :change-property property value nil))
|
||||
|
||||
|
||||
;; Private aux functions
|
||||
|
||||
(defn- move-vec?
|
||||
[vector]
|
||||
(or (not (mth/almost-zero? (dm/get-prop vector :x)))
|
||||
(not (mth/almost-zero? (dm/get-prop vector :y)))))
|
||||
(or (not ^boolean (mth/almost-zero? (dm/get-prop vector :x)))
|
||||
(not ^boolean (mth/almost-zero? (dm/get-prop vector :y)))))
|
||||
|
||||
(defn- resize-vec?
|
||||
[vector]
|
||||
(or (not (mth/almost-zero? (- (dm/get-prop vector :x) 1)))
|
||||
(not (mth/almost-zero? (- (dm/get-prop vector :y) 1)))))
|
||||
(or (not ^boolean (mth/almost-zero? (- (dm/get-prop vector :x) 1)))
|
||||
(not ^boolean (mth/almost-zero? (- (dm/get-prop vector :y) 1)))))
|
||||
|
||||
(defn- mergeable-move?
|
||||
[op1 op2]
|
||||
|
@ -128,22 +126,24 @@
|
|||
(defn- mergeable-resize?
|
||||
[op1 op2]
|
||||
(let [type-op1 (dm/get-prop op1 :type)
|
||||
transform-op1 (or (dm/get-prop op1 :transform) (gmt/matrix))
|
||||
transform-inv-op1 (or (dm/get-prop op1 :transform-inverse) (gmt/matrix))
|
||||
transform-op1 (d/nilv (dm/get-prop op1 :transform) gmt/base)
|
||||
transform-inv-op1 (d/nilv (dm/get-prop op1 :transform-inverse) gmt/base)
|
||||
origin-op1 (dm/get-prop op1 :origin)
|
||||
|
||||
type-op2 (dm/get-prop op2 :type)
|
||||
transform-op2 (or (dm/get-prop op2 :transform) (gmt/matrix))
|
||||
transform-inv-op2 (or (dm/get-prop op2 :transform-inverse) (gmt/matrix))
|
||||
transform-op2 (d/nilv (dm/get-prop op2 :transform) gmt/base)
|
||||
transform-inv-op2 (d/nilv (dm/get-prop op2 :transform-inverse) gmt/base)
|
||||
origin-op2 (dm/get-prop op2 :origin)]
|
||||
(and (= :resize type-op1) (= :resize type-op2)
|
||||
|
||||
(and (= :resize type-op1)
|
||||
(= :resize type-op2)
|
||||
|
||||
;; Same origin
|
||||
(gpt/close? origin-op1 origin-op2)
|
||||
^boolean (gpt/close? origin-op1 origin-op2)
|
||||
|
||||
;; Same transforms
|
||||
(gmt/close? transform-op1 transform-op2)
|
||||
(gmt/close? transform-inv-op1 transform-inv-op2))))
|
||||
^boolean (gmt/close? transform-op1 transform-op2)
|
||||
^boolean (gmt/close? transform-inv-op1 transform-inv-op2))))
|
||||
|
||||
(defn- merge-move
|
||||
[op1 op2]
|
||||
|
@ -155,14 +155,15 @@
|
|||
(defn- merge-resize
|
||||
[op1 op2]
|
||||
(let [op1-vector (dm/get-prop op1 :vector)
|
||||
op1-x (dm/get-prop op1-vector :x)
|
||||
op1-y (dm/get-prop op1-vector :y)
|
||||
op1-x (dm/get-prop op1-vector :x)
|
||||
op1-y (dm/get-prop op1-vector :y)
|
||||
|
||||
op2-vector (dm/get-prop op2 :vector)
|
||||
op2-x (dm/get-prop op2-vector :x)
|
||||
op2-y (dm/get-prop op2-vector :y)
|
||||
op2-x (dm/get-prop op2-vector :x)
|
||||
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)))
|
||||
|
||||
(defn- maybe-add-move
|
||||
|
@ -198,10 +199,7 @@
|
|||
[vector]
|
||||
(let [x (dm/get-prop vector :x)
|
||||
y (dm/get-prop vector :y)]
|
||||
(and (some? x)
|
||||
(some? y)
|
||||
(not (mth/nan? x))
|
||||
(not (mth/nan? y)))))
|
||||
(d/num? x y)))
|
||||
|
||||
;; Public builder API
|
||||
|
||||
|
@ -245,8 +243,11 @@
|
|||
(move modifiers (gpt/point x y)))
|
||||
|
||||
([modifiers vector]
|
||||
(assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector)))
|
||||
(let [modifiers (or modifiers (empty))
|
||||
(dm/assert!
|
||||
["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))
|
||||
modifiers (assoc modifiers :last-order order)]
|
||||
(cond-> modifiers
|
||||
|
@ -256,7 +257,7 @@
|
|||
(defn resize
|
||||
([modifiers vector origin]
|
||||
(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))
|
||||
modifiers (assoc modifiers :last-order order)]
|
||||
(cond-> modifiers
|
||||
|
@ -594,7 +595,72 @@
|
|||
|
||||
;; 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
|
||||
"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"
|
||||
[modifiers]
|
||||
(let [modifiers (->> (concat (dm/get-prop modifiers :geometry-parent)
|
||||
|
|
|
@ -377,7 +377,15 @@
|
|||
(update [_ state]
|
||||
(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
|
||||
([angle shapes]
|
||||
(set-rotation-modifiers angle shapes (-> shapes gsh/shapes->rect grc/rect->center)))
|
||||
|
@ -387,11 +395,7 @@
|
|||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
ids
|
||||
(->> shapes
|
||||
(remove #(get % :blocked false))
|
||||
(filter #(:rotation (get editable-attrs (:type %))))
|
||||
(map :id))
|
||||
ids (sequence xf-rotation-shape shapes)
|
||||
|
||||
get-modifier
|
||||
(fn [shape]
|
||||
|
|
Loading…
Add table
Reference in a new issue