0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-10 08:50:57 -05:00

Adds path parser

This commit is contained in:
alonso.torres 2020-11-04 22:07:49 +01:00
parent d25dbfb09b
commit 67ed1d89ac
5 changed files with 196 additions and 6 deletions

View file

@ -1757,6 +1757,7 @@
"e" #(st/emit! (select-for-drawing :circle))
"t" #(st/emit! dwtxt/start-edit-if-selected
(select-for-drawing :text))
"w" #(st/emit! (select-for-drawing :path))
"ctrl+c" #(st/emit! copy-selected)
"ctrl+v" #(st/emit! paste)
"ctrl+x" #(st/emit! copy-selected delete-selected)

View file

@ -65,3 +65,6 @@
;; default
box/handle-drawing-box)))))
;; Export
(def close-drawing-path path/close-drawing-path)

View file

@ -19,7 +19,7 @@
(def handle-drawing-path
(letfn [(stoper-event? [{:keys [type shift] :as event}]
(or (= event :path/end-path-drawing)
(or (= event ::end-path-drawing)
(= event :interrupt)
(and (ms/mouse-event? event)
(or (= type :double-click)
@ -109,8 +109,12 @@
(rx/of finish-drawing-path
common/handle-finish-drawing))))))))
(def close-drawing-path
(defn close-drawing-path []
(ptk/reify ::close-drawing-path
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-drawing :object :close?] true))))
(assoc-in state [:workspace-drawing :object :close?] true))
ptk/WatchEvent
(watch [_ state stream]
(rx/of ::end-path-drawing))))

View file

@ -51,8 +51,7 @@
(fn [event]
(dom/stop-propagation event)
(st/emit! (dw/assign-cursor-tooltip nil)
#_(dd/close-drawing-path)
#_:path/end-path-drawing))
(dd/close-drawing-path)))
on-mouse-enter
(fn [event]

View file

@ -8,7 +8,10 @@
;; Copyright (c) 2016-2017 Andrey Antukh <niwi@niwi.nz>
(ns app.util.geom.path
(:require [app.util.geom.path-impl-simplify :as impl-simplify]))
(:require
[cuerdas.core :as str]
[app.common.data :as d]
[app.util.geom.path-impl-simplify :as impl-simplify]))
(defn simplify
([points]
@ -16,3 +19,183 @@
([points tolerance]
(let [points (into-array points)]
(into [] (impl-simplify/simplify points tolerance true)))))
;;
(def commands-regex #"(?i)[a-z][^a-z]*")
;; Matches numbers for path values allows values like... -.01, 10, +12.22
;; 0 and 1 are special because can refer to flags
(def num-regex #"([+-]?(([1-9]\d*(\.\d+)?)|(\.\d+)|0|1))")
(defn coord-n [size]
(re-pattern (str "(?i)[a-z]\\s*"
(->> (range size)
(map #(identity num-regex))
(str/join "\\s+")))))
(defn parse-params [cmd-str num-params]
(let [fix-starting-dot (fn [arg] (str/replace arg #"([^\d]|^)\." "$10."))]
(->> (re-seq num-regex cmd-str)
(map first)
(map fix-starting-dot)
(map d/read-string)
(partition num-params))))
(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])
:close-path
[]
(:line-to-horizontal :line-to-vertical)
(let [{:keys [value]} params] [value])
:curve-to
(let [{:keys [c1x c1y c2x c2y x y]} params] [c1x c1y c2x c2y x y])
(:smooth-curve-to :quadratic-bezier-curve-to)
(let [{:keys [cx cy x y]} params] [cx cy x y])
: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])))
;; Path specification
;; https://www.w3.org/TR/SVG11/paths.html
(defmulti parse-command (comp str/upper first))
(defmethod parse-command "M" [cmd]
(let [relative (str/starts-with? cmd "m")
params (parse-params cmd 2)]
(for [[x y] params]
{:command :move-to
:relative relative
:params {:x x :y y}})))
(defmethod parse-command "Z" [cmd]
[{:command :close-path}])
(defmethod parse-command "L" [cmd]
(let [relative (str/starts-with? cmd "l")
params (parse-params cmd 2)]
(for [[x y] params]
{:command :line-to
:relative relative
:params {:x x :y y}})))
(defmethod parse-command "H" [cmd]
(let [relative (str/starts-with? cmd "h")
params (parse-params cmd 1)]
(for [[value] params]
{:command :line-to-horizontal
:relative relative
:params {:value value}})))
(defmethod parse-command "V" [cmd]
(let [relative (str/starts-with? cmd "v")
params (parse-params cmd 1)]
(for [[value] params]
{:command :line-to-vertical
:relative relative
:params {:value value}})))
(defmethod parse-command "C" [cmd]
(let [relative (str/starts-with? cmd "c")
params (parse-params cmd 6)]
(for [[c1x c1y c2x c2y x y] params]
{:command :curve-to
:relative relative
:params {:c1x c1x
:c1y c1y
:c2x c2x
:c2y c2y
:x x
:y y}})))
(defmethod parse-command "S" [cmd]
(let [relative (str/starts-with? cmd "s")
params (parse-params cmd 4)]
(for [[cx cy x y] params]
{:command :smooth-curve-to
:relative relative
:params {:cx cx
:cy cy
:x x
:y y}})))
(defmethod parse-command "Q" [cmd]
(let [relative (str/starts-with? cmd "s")
params (parse-params cmd 4)]
(for [[cx cy x y] params]
{:command :quadratic-bezier-curve-to
:relative relative
:params {:cx cx
:cy cy
:x x
:y y}})))
(defmethod parse-command "T" [cmd]
(let [relative (str/starts-with? cmd "t")
params (parse-params cmd (coord-n 2))]
(for [[cx cy x y] params]
{:command :smooth-quadratic-bezier-curve-to
:relative relative
:params {:x x
:y y}})))
(defmethod parse-command "A" [cmd]
(let [relative (str/starts-with? cmd "a")
params (parse-params cmd 7)]
(for [[rx ry x-axis-rotation large-arc-flag sweep-flag x y] params]
{:command :elliptical-arc
:relative relative
:params {:rx rx
:ry ry
:x-axis-rotation x-axis-rotation
:large-arc-flag large-arc-flag
:sweep-flag sweep-flag
:x x
:y y}})))
(defn command->string [{:keys [command relative params] :as entry}]
(let [command-str (case command
:move-to "M"
:close-path "Z"
:line-to "L"
:line-to-horizontal "H"
:line-to-vertical "V"
:curve-to "C"
:smooth-curve-to "S"
:quadratic-bezier-curve-to "Q"
:smooth-quadratic-bezier-curve-to "T"
: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))))
(defn path->content [string]
(let [clean-string (-> string
(str/trim)
;; Change "commas" for spaces
(str/replace #"," " ")
;; Remove all consecutive spaces
(str/replace #"\s+" " "))
commands (re-seq commands-regex clean-string)]
(mapcat parse-command commands)))
(defn content->path [content]
(->> content
(map command->string)
(str/join "")))
#_(let [path "M.343 15.974a.514.514 0 01-.317-.321c-.023-.07-.026-.23-.026-1.43 0-1.468-.001-1.445.09-1.586.02-.032 1.703-1.724 3.74-3.759a596.805 596.805 0 003.7-3.716c0-.009-.367-.384-.816-.833a29.9 29.9 0 01-.817-.833c0-.01.474-.49 1.054-1.07l1.053-1.053.948.946.947.947 1.417-1.413C12.366.806 12.765.418 12.856.357c.238-.161.52-.28.792-.334.17-.034.586-.03.76.008.801.173 1.41.794 1.57 1.603.03.15.03.569 0 .718a2.227 2.227 0 01-.334.793c-.061.09-.45.49-1.496 1.54L12.734 6.1l.947.948.947.947-1.053 1.054c-.58.58-1.061 1.054-1.07 1.054-.01 0-.384-.368-.833-.817-.45-.45-.824-.817-.834-.817-.009 0-1.68 1.666-3.716 3.701a493.093 493.093 0 01-3.759 3.74c-.14.091-.117.09-1.59.089-1.187 0-1.366-.004-1.43-.027zm6.024-4.633a592.723 592.723 0 003.663-3.68c0-.02-1.67-1.69-1.69-1.69-.01 0-1.666 1.648-3.68 3.663L.996 13.297v.834c0 .627.005.839.02.854.015.014.227.02.854.02h.833l3.664-3.664z"
content (path->content path)
new-path (content->path content)
]
(prn "path" path)
(.log js/console "?? 1" (clj->js content))
(prn "?? 2" (= path new-path) new-path))