0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-14 02:58:39 -05:00

🐛 Fix problems with imported svgs

This commit is contained in:
alonso.torres 2021-09-28 15:55:28 +02:00
parent a189dc8243
commit 49c2cb985c
3 changed files with 69 additions and 29 deletions

View file

@ -13,23 +13,6 @@
[app.common.path.commands :as upc] [app.common.path.commands :as upc]
[app.common.path.subpaths :as ups])) [app.common.path.subpaths :as ups]))
(defn- reverse-command
"Reverses a single command"
[command]
(let [{old-x :x old-y :y} (:params command)
{:keys [x y]} (:prev command)
{:keys [c1x c1y c2x c2y]} (:params command)]
(-> command
(assoc :prev (gpt/point old-x old-y))
(update :params assoc :x x :y y)
(cond-> (= :curve-to (:command command))
(update :params assoc
:c1x c2x :c1y c2y
:c2x c1x :c2y c1y)))))
(defn add-previous (defn add-previous
([content] ([content]
(add-previous content nil)) (add-previous content nil))
@ -43,6 +26,37 @@
(some? prev) (some? prev)
(assoc :prev (gsp/command->point prev)))))))) (assoc :prev (gsp/command->point prev))))))))
(defn close-paths
"Removes the :close-path commands and replace them for line-to so we can calculate
the intersections"
[content]
(loop [head (first content)
content (rest content)
result []
last-move nil]
(if (nil? head)
result
(let [head-p (gsp/command->point head)
head (cond
(and (= :close-path (:command head))
(< (gpt/distance head-p last-move) 0.01))
nil
(= :close-path (:command head))
(upc/make-line-to last-move)
:else
head)]
(recur (first content)
(rest content)
(cond-> result (some? head) (conj head))
(if (= :move-to (:command head))
head-p
last-move))))))
(defn- split-command (defn- split-command
[cmd values] [cmd values]
(case (:command cmd) (case (:command cmd)
@ -192,8 +206,6 @@
;; Reverse second content so we can have holes inside other shapes ;; Reverse second content so we can have holes inside other shapes
(->> content-b-split (->> content-b-split
(reverse)
(mapv reverse-command)
(filter #(and (contains-segment? % content-a) (filter #(and (contains-segment? % content-a)
(not (overlap-segment? % content-a-split))))))) (not (overlap-segment? % content-a-split)))))))
@ -207,10 +219,8 @@
(defn create-exclusion [content-a content-b] (defn create-exclusion [content-a content-b]
;; Pick all segments but reverse content-b (so it makes an exclusion) ;; Pick all segments
(let [content-b' (->> (reverse content-b) (d/concat [] content-a content-b))
(mapv reverse-command))]
(d/concat [] content-a content-b')))
(defn fix-move-to (defn fix-move-to
@ -237,8 +247,13 @@
(defn content-bool-pair (defn content-bool-pair
[bool-type content-a content-b] [bool-type content-a content-b]
(let [content-a (add-previous content-a) (let [content-a (-> content-a (close-paths) (add-previous))
content-b (add-previous content-b)
content-b (-> content-b
(close-paths)
(cond-> (ups/clockwise? content-b)
(ups/reverse-content))
(add-previous))
;; Split content in new segments in the intersection with the other path ;; Split content in new segments in the intersection with the other path
[content-a-split content-b-split] (content-intersect-split content-a content-b) [content-a-split content-b-split] (content-intersect-split content-a content-b)

View file

@ -158,3 +158,27 @@
(reverse) (reverse)
(mapcat :data) (mapcat :data)
(into []))) (into [])))
;; https://mathworld.wolfram.com/PolygonArea.html
(defn clockwise?
"Check whether the first subpath is clockwise or counter-clock wise"
[content]
(let [subpath (->> content get-subpaths first :data)]
(loop [current (first subpath)
subpath (rest subpath)
first-point nil
signed-area 0]
(if (nil? current)
(> signed-area 0)
(let [{x1 :x y1 :y :as p} (upc/command->point current)
last? (nil? (first subpath))
first-point (if (nil? first-point) p first-point)
{x2 :x y2 :y} (if last? first-point (upc/command->point (first subpath)))
signed-area (+ signed-area (- (* x1 y2) (* x2 y1)))]
(recur (first subpath)
(rest subpath)
first-point
signed-area))))))

View file

@ -35,8 +35,9 @@
(map #(get childs %)) (map #(get childs %))
(filter #(not (:hidden %))) (filter #(not (:hidden %)))
(map #(stp/convert-to-path % childs)) (map #(stp/convert-to-path % childs))
(mapv :content) (map :content)
(mapv pb/add-previous))] (map pb/close-paths)
(map pb/add-previous))]
(pb/content-intersect-split content-a content-b))))] (pb/content-intersect-split content-a content-b))))]
[:g.debug-bool [:g.debug-bool
[:g.shape-a [:g.shape-a
@ -49,7 +50,7 @@
(dissoc :fill-color :fill-opacity) (dissoc :fill-color :fill-opacity)
(assoc :content content-b)) (assoc :content content-b))
:frame frame}] :frame frame}]
(for [{:keys [x y]} (gsp/content->points content-b)] (for [{:keys [x y]} (gsp/content->points (pb/close-paths content-b))]
[:circle {:cx x [:circle {:cx x
:cy y :cy y
:r 2.5 :r 2.5
@ -65,7 +66,7 @@
(dissoc :fill-color :fill-opacity) (dissoc :fill-color :fill-opacity)
(assoc :content content-a)) (assoc :content content-a))
:frame frame}] :frame frame}]
(for [{:keys [x y]} (gsp/content->points content-a)] (for [{:keys [x y]} (gsp/content->points (pb/close-paths content-a))]
[:circle {:cx x [:circle {:cx x
:cy y :cy y
:r 1.25 :r 1.25