mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
✨ Paths improvements
This commit is contained in:
parent
1773de88f5
commit
0756de25f8
2 changed files with 88 additions and 53 deletions
|
@ -24,6 +24,12 @@
|
|||
shape (unchecked-get props "shape")
|
||||
color (unchecked-get props "color")
|
||||
transform (gsh/transform-matrix shape)
|
||||
path? (= :path (:type shape))
|
||||
path-data
|
||||
(mf/use-memo
|
||||
(mf/deps shape)
|
||||
#(when path? (ugp/content->path (:content shape))))
|
||||
|
||||
{:keys [id x y width height]} shape
|
||||
|
||||
outline-type (case (:type shape)
|
||||
|
@ -45,7 +51,7 @@
|
|||
:ry (/ height 2)}
|
||||
|
||||
:path
|
||||
{:d (ugp/content->path (:content shape))
|
||||
{:d path-data
|
||||
:transform nil}
|
||||
|
||||
{:x x
|
||||
|
|
|
@ -22,9 +22,8 @@
|
|||
(let [handler-vector (gpt/to-vec point handler)]
|
||||
(gpt/add point (gpt/negate handler-vector))))
|
||||
|
||||
;;;
|
||||
|
||||
(defn simplify
|
||||
"Simplifies a drawing done with the pen tool"
|
||||
([points]
|
||||
(simplify points 0.1))
|
||||
([points tolerance]
|
||||
|
@ -68,26 +67,41 @@
|
|||
(cond-> result
|
||||
(not (empty? current)) (conj current))))))
|
||||
|
||||
(defn command->param-list [{:keys [command params]}]
|
||||
(case command
|
||||
(:move-to :line-to :smooth-quadratic-bezier-curve-to)
|
||||
(let [{:keys [x y]} params] [x y])
|
||||
(defn command->param-list [command]
|
||||
(let [params (:params command)]
|
||||
(case (:command command)
|
||||
(:move-to :line-to :smooth-quadratic-bezier-curve-to)
|
||||
(str (:x params) ","
|
||||
(:y params))
|
||||
|
||||
:close-path
|
||||
[]
|
||||
:close-path
|
||||
""
|
||||
|
||||
(:line-to-horizontal :line-to-vertical)
|
||||
(let [{:keys [value]} params] [value])
|
||||
(:line-to-horizontal :line-to-vertical)
|
||||
(str (:value params))
|
||||
|
||||
:curve-to
|
||||
(let [{:keys [c1x c1y c2x c2y x y]} params] [c1x c1y c2x c2y x y])
|
||||
:curve-to
|
||||
(str (:c1x params) ","
|
||||
(:c1y params) ","
|
||||
(:c2x params) ","
|
||||
(:c2y params) ","
|
||||
(:x params) ","
|
||||
(:y params))
|
||||
|
||||
(:smooth-curve-to :quadratic-bezier-curve-to)
|
||||
(let [{:keys [cx cy x y]} params] [cx cy x y])
|
||||
(:smooth-curve-to :quadratic-bezier-curve-to)
|
||||
(str (:cx params) ","
|
||||
(:cy params) ","
|
||||
(:x params) ","
|
||||
(:y params))
|
||||
|
||||
:elliptical-arc
|
||||
(let [{:keys [rx ry x-axis-rotation large-arc-flag sweep-flag x y]} params]
|
||||
[rx ry x-axis-rotation large-arc-flag sweep-flag x y])))
|
||||
:elliptical-arc
|
||||
(str (:rx params) ","
|
||||
(:ry params) ","
|
||||
(:x-axis-rotation params) ","
|
||||
(:large-arc-flag params) ","
|
||||
(:sweep-flag params) ","
|
||||
(:x params) ","
|
||||
(:y params)))))
|
||||
|
||||
;; Path specification
|
||||
;; https://www.w3.org/TR/SVG11/paths.html
|
||||
|
@ -97,10 +111,15 @@
|
|||
(let [relative (str/starts-with? cmd "m")
|
||||
param-list (extract-params cmd [[:x :number]
|
||||
[:y :number]])]
|
||||
(for [params param-list]
|
||||
{:command :move-to
|
||||
:relative relative
|
||||
:params params})))
|
||||
|
||||
(d/concat [{:command :move-to
|
||||
:relative relative
|
||||
:params (first param-list)}]
|
||||
|
||||
(for [params (rest param-list)]
|
||||
{:command :line-to
|
||||
:relative relative
|
||||
:params params}))))
|
||||
|
||||
(defmethod parse-command "Z" [cmd]
|
||||
[{:command :close-path}])
|
||||
|
@ -156,7 +175,7 @@
|
|||
:params params})))
|
||||
|
||||
(defmethod parse-command "Q" [cmd]
|
||||
(let [relative (str/starts-with? cmd "s")
|
||||
(let [relative (str/starts-with? cmd "q")
|
||||
param-list (extract-params cmd [[:cx :number]
|
||||
[:cy :number]
|
||||
[:x :number]
|
||||
|
@ -203,7 +222,7 @@
|
|||
:elliptical-arc "A")
|
||||
command-str (if relative (str/lower command-str) command-str)
|
||||
param-list (command->param-list entry)]
|
||||
(str/fmt "%s%s" command-str (str/join " " param-list))))
|
||||
(str command-str param-list)))
|
||||
|
||||
(defn cmd-pos [prev-pos {:keys [relative params]}]
|
||||
(let [{:keys [x y] :or {x (:x prev-pos) y (:y prev-pos)}} params]
|
||||
|
@ -253,31 +272,35 @@
|
|||
"Removes some commands and convert relative to absolute coordinates"
|
||||
[commands]
|
||||
(let [simplify-command
|
||||
;; prev-cc : previous command control point for cubic beziers
|
||||
;; prev-qc : previous command control point for quadratic curves
|
||||
(fn [[pos result prev-cc prev-qc] [command prev]]
|
||||
(let [command
|
||||
;; prev-pos : previous position for the current path. Necesary for relative commands
|
||||
;; prev-start : previous move-to necesary for Z commands
|
||||
;; prev-cc : previous command control point for cubic beziers
|
||||
;; prev-qc : previous command control point for quadratic curves
|
||||
(fn [[result prev-pos prev-start prev-cc prev-qc] [command prev]]
|
||||
(let [command (assoc command :prev-pos prev-pos)
|
||||
|
||||
command
|
||||
(cond-> command
|
||||
(:relative command)
|
||||
(-> (assoc :relative false)
|
||||
(d/update-in-when [:params :c1x] + (:x pos))
|
||||
(d/update-in-when [:params :c1y] + (:y pos))
|
||||
(d/update-in-when [:params :c1x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :c1y] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :c2x] + (:x pos))
|
||||
(d/update-in-when [:params :c2y] + (:y pos))
|
||||
(d/update-in-when [:params :c2x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :c2y] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :cx] + (:x pos))
|
||||
(d/update-in-when [:params :cy] + (:y pos))
|
||||
(d/update-in-when [:params :cx] + (:x prev-pos))
|
||||
(d/update-in-when [:params :cy] + (:y prev-pos))
|
||||
|
||||
(d/update-in-when [:params :x] + (:x pos))
|
||||
(d/update-in-when [:params :y] + (:y pos))
|
||||
(d/update-in-when [:params :x] + (:x prev-pos))
|
||||
(d/update-in-when [:params :y] + (:y prev-pos))
|
||||
|
||||
(cond->
|
||||
(= :line-to-horizontal (:command command))
|
||||
(d/update-in-when [:params :value] + (:x pos))
|
||||
(d/update-in-when [:params :value] + (:x prev-pos))
|
||||
|
||||
(= :line-to-vertical (:command command))
|
||||
(d/update-in-when [:params :value] + (:y pos)))))
|
||||
(d/update-in-when [:params :value] + (:y prev-pos)))))
|
||||
|
||||
params (:params command)
|
||||
orig-command command
|
||||
|
@ -288,33 +311,33 @@
|
|||
(-> (assoc :command :line-to)
|
||||
(update :params dissoc :value)
|
||||
(assoc-in [:params :x] (:value params))
|
||||
(assoc-in [:params :y] (:y pos)))
|
||||
(assoc-in [:params :y] (:y prev-pos)))
|
||||
|
||||
(= :line-to-vertical (:command command))
|
||||
(-> (assoc :command :line-to)
|
||||
(update :params dissoc :value)
|
||||
(assoc-in [:params :y] (:value params))
|
||||
(assoc-in [:params :x] (:x pos)))
|
||||
(assoc-in [:params :x] (:x prev-pos)))
|
||||
|
||||
(= :smooth-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (smooth->curve command pos prev-cc)))
|
||||
(update :params merge (smooth->curve command prev-pos prev-cc)))
|
||||
|
||||
(= :quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (quadratic->curve pos (gpt/point params) (gpt/point (:cx params) (:cy params)))))
|
||||
(update :params merge (quadratic->curve prev-pos (gpt/point params) (gpt/point (:cx params) (:cy params)))))
|
||||
|
||||
(= :smooth-quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params merge (quadratic->curve pos (gpt/point params) (calculate-opposite-handler pos prev-qc)))))
|
||||
(update :params merge (quadratic->curve prev-pos (gpt/point params) (calculate-opposite-handler prev-pos prev-qc)))))
|
||||
|
||||
result (if (= :elliptical-arc (:command command))
|
||||
(d/concat result (arc->beziers pos command))
|
||||
(d/concat result (arc->beziers prev-pos command))
|
||||
(conj result command))
|
||||
|
||||
prev-cc (case (:command orig-command)
|
||||
next-cc (case (:command orig-command)
|
||||
:smooth-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
|
@ -326,23 +349,29 @@
|
|||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
|
||||
|
||||
prev-qc (case (:command orig-command)
|
||||
next-qc (case (:command orig-command)
|
||||
:quadratic-bezier-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
:smooth-quadratic-bezier-curve-to
|
||||
(calculate-opposite-handler pos prev-qc)
|
||||
(calculate-opposite-handler prev-pos prev-qc)
|
||||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))]
|
||||
[(cmd-pos pos command) result prev-cc prev-qc]))
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
|
||||
|
||||
next-pos (if (= :close-path (:command command))
|
||||
prev-start
|
||||
(cmd-pos prev-pos command))
|
||||
|
||||
next-start (if (= :move-to (:command command)) next-pos prev-start)]
|
||||
|
||||
[result next-pos next-start next-cc next-qc]))
|
||||
|
||||
start (first commands)
|
||||
start-pos (gpt/point (:params start))]
|
||||
|
||||
|
||||
(->> (map vector (rest commands) commands)
|
||||
(reduce simplify-command [start-pos [start] start-pos start-pos])
|
||||
(second))))
|
||||
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
|
||||
(first))))
|
||||
|
||||
(defn path->content [string]
|
||||
(let [clean-string (-> string
|
||||
|
@ -357,7 +386,7 @@
|
|||
|
||||
(defn content->path [content]
|
||||
(->> content
|
||||
(map command->string)
|
||||
(mapv command->string)
|
||||
(str/join "")))
|
||||
|
||||
(defn make-curve-params
|
||||
|
|
Loading…
Add table
Reference in a new issue