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