diff --git a/common/src/app/common/svg/path/Parser.java b/common/src/app/common/svg/path/Parser.java
index cfceaf9443..dec9ff00fa 100644
--- a/common/src/app/common/svg/path/Parser.java
+++ b/common/src/app/common/svg/path/Parser.java
@@ -1,3 +1,11 @@
+/**
+ * Performance focused pure java implementation of the
+ * SVG path parser.
+ *
+ * @author KALEIDOS INC
+ * @license MPL-2.0
+ */
+
package app.common.svg.path;
import java.util.Arrays;
@@ -61,9 +69,11 @@ public class Parser {
command = MOVE_TO;
params = new Object[] {K_X, this.params[0], K_Y, this.params[1]};
break;
+
case 'Z':
command = CLOSE_PATH;
break;
+
case 'L':
command = LINE_TO;
params = new Object[] {K_X, this.params[0], K_Y, this.params[1]};
@@ -781,16 +791,6 @@ public class Parser {
var segments = arcToBeziers(currentX, currentY, x, y, fa, fs, rx, ry, phi);
result.addAll(segments);
-
- // if (rx == 0 || ry == 0) {
- // segment.command = 'C';
- // segment.params = new double[] {currentX, currentY, x, y, x, y};
- // result.add(segment);
- // } else if (currentX != x || currentY != y) {
- // var segments = arcToBeziers(currentX, currentY, x, y, fa, fs, rx, ry, phi);
- // result.addAll(segments);
- // }
-
currentX = x;
currentY = y;
@@ -871,7 +871,6 @@ public class Parser {
}
private static void processCurve(double[] curve, double cx, double cy, double rx, double ry, double sinPhi, double cosPhi) {
-
double x0 = curve[0] * rx;
double y0 = curve[1] * ry;
double x1 = curve[2] * rx;
@@ -911,7 +910,13 @@ public class Parser {
double x1p = ((cosPhi * (x1 - x2)) / 2) + ((sinPhi * (y1 - y2)) / 2);
double y1p = ((-sinPhi * (x1 - x2)) / 2) + ((cosPhi * (y1 - y2)) / 2);
- if (x1p == 0 || y1p == 0 || rx == 0 || ry == 0) {
+ if (x1p == 0 && y1p == 0) {
+ // we're asked to draw line to itself
+ return new ArrayList<>();
+ }
+
+ if (rx == 0 || ry == 0) {
+ // one of the radii is zero
return new ArrayList<>();
}
diff --git a/common/test/common_tests/arc_to_bezier.js b/common/src/app/common/svg/path/arc_to_bezier.js
similarity index 93%
rename from common/test/common_tests/arc_to_bezier.js
rename to common/src/app/common/svg/path/arc_to_bezier.js
index bc2c1a843a..39dc8d447f 100644
--- a/common/test/common_tests/arc_to_bezier.js
+++ b/common/src/app/common/svg/path/arc_to_bezier.js
@@ -2,7 +2,8 @@
* Arc to Bezier curves transformer
*
* Is a modified and google closure compatible version of the a2c
- * functions by https://github.com/fontello/svgpath
+ * functions by https://github.com/fontello/svgpath used as reference
+ * implementation for tests
*
* @author KALEIDOS INC
* @license MIT License
@@ -10,11 +11,11 @@
"use strict";
-goog.provide("common_tests.arc_to_bezier");
+goog.provide("app.common.svg.path.arc_to_bezier");
// https://raw.githubusercontent.com/fontello/svgpath/master/lib/a2c.js
goog.scope(function() {
- const self = common_tests.arc_to_bezier;
+ const self = app.common.svg.path.arc_to_bezier;
var TAU = Math.PI * 2;
@@ -123,7 +124,7 @@ goog.scope(function() {
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
}
- function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
+ function calculate_beziers(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
var sin_phi = Math.sin(phi * TAU / 360);
var cos_phi = Math.cos(phi * TAU / 360);
@@ -132,6 +133,8 @@ goog.scope(function() {
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
+ // console.log("L", x1p, y1p)
+
if (x1p === 0 && y1p === 0) {
// we're asked to draw line to itself
return [];
@@ -204,5 +207,5 @@ goog.scope(function() {
});
}
- self.a2c = a2c;
+ self.calculateBeziers = calculate_beziers;
});
diff --git a/common/src/app/common/svg/path/legacy_parser1.cljs b/common/src/app/common/svg/path/legacy_parser1.cljs
new file mode 100644
index 0000000000..70acc58242
--- /dev/null
+++ b/common/src/app/common/svg/path/legacy_parser1.cljs
@@ -0,0 +1,325 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.common.svg.path.legacy-parser1
+ "The first SVG Path parser implementation.
+
+ Written in a mix of CLJS and JS code and used in production until
+ 1.19, used mainly for tests."
+ (:require
+ [app.common.data :as d]
+ [app.common.geom.point :as gpt]
+ [app.common.geom.shapes.path :as upg]
+ [app.common.svg :as csvg]
+ [app.common.svg.path.arc-to-bezier :as a2b]
+ [app.common.svg.path.command :as upc]
+ [cuerdas.core :as str]))
+
+(def commands-regex #"(?i)[mzlhvcsqta][^mzlhvcsqta]*")
+
+;; 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 #"[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?")
+
+(def flag-regex #"[01]")
+
+(defn extract-params [cmd-str extract-commands]
+ (loop [result []
+ extract-idx 0
+ current {}
+ remain (-> cmd-str (subs 1) (str/trim))]
+
+ (let [[param type] (nth extract-commands extract-idx)
+ regex (case type
+ :flag flag-regex
+ #_:number num-regex)
+ match (re-find regex remain)]
+
+ (if match
+ (let [value (-> match first csvg/fix-dot-number d/read-string)
+ remain (str/replace-first remain regex "")
+ current (assoc current param value)
+ extract-idx (inc extract-idx)
+ [result current extract-idx]
+ (if (>= extract-idx (count extract-commands))
+ [(conj result current) {} 0]
+ [result current extract-idx])]
+ (recur result
+ extract-idx
+ current
+ remain))
+ (cond-> result
+ (seq current) (conj current))))))
+
+;; 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")
+ param-list (extract-params cmd [[:x :number]
+ [:y :number]])]
+
+ (into [{: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" [_]
+ [{:command :close-path}])
+
+(defmethod parse-command "L" [cmd]
+ (let [relative (str/starts-with? cmd "l")
+ param-list (extract-params cmd [[:x :number]
+ [:y :number]])]
+ (for [params param-list]
+ {:command :line-to
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "H" [cmd]
+ (let [relative (str/starts-with? cmd "h")
+ param-list (extract-params cmd [[:value :number]])]
+ (for [params param-list]
+ {:command :line-to-horizontal
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "V" [cmd]
+ (let [relative (str/starts-with? cmd "v")
+ param-list (extract-params cmd [[:value :number]])]
+ (for [params param-list]
+ {:command :line-to-vertical
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "C" [cmd]
+ (let [relative (str/starts-with? cmd "c")
+ param-list (extract-params cmd [[:c1x :number]
+ [:c1y :number]
+ [:c2x :number]
+ [:c2y :number]
+ [:x :number]
+ [:y :number]])
+ ]
+ (for [params param-list]
+ {:command :curve-to
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "S" [cmd]
+ (let [relative (str/starts-with? cmd "s")
+ param-list (extract-params cmd [[:cx :number]
+ [:cy :number]
+ [:x :number]
+ [:y :number]])]
+ (for [params param-list]
+ {:command :smooth-curve-to
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "Q" [cmd]
+ (let [relative (str/starts-with? cmd "q")
+ param-list (extract-params cmd [[:cx :number]
+ [:cy :number]
+ [:x :number]
+ [:y :number]])]
+ (for [params param-list]
+ {:command :quadratic-bezier-curve-to
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "T" [cmd]
+ (let [relative (str/starts-with? cmd "t")
+ param-list (extract-params cmd [[:x :number]
+ [:y :number]])]
+ (for [params param-list]
+ {:command :smooth-quadratic-bezier-curve-to
+ :relative relative
+ :params params})))
+
+(defmethod parse-command "A" [cmd]
+ (let [relative (str/starts-with? cmd "a")
+ param-list (extract-params cmd [[:rx :number]
+ [:ry :number]
+ [:x-axis-rotation :number]
+ [:large-arc-flag :flag]
+ [:sweep-flag :flag]
+ [:x :number]
+ [:y :number]])]
+ (for [params param-list]
+ {:command :elliptical-arc
+ :relative relative
+ :params params})))
+
+(defn smooth->curve
+ [{:keys [params]} pos handler]
+ (let [{c1x :x c1y :y} (upg/calculate-opposite-handler pos handler)]
+ {:c1x c1x
+ :c1y c1y
+ :c2x (:cx params)
+ :c2y (:cy params)}))
+
+(defn quadratic->curve
+ [sp ep cp]
+ (let [cp1 (-> (gpt/to-vec sp cp)
+ (gpt/scale (/ 2 3))
+ (gpt/add sp))
+
+ cp2 (-> (gpt/to-vec ep cp)
+ (gpt/scale (/ 2 3))
+ (gpt/add ep))]
+
+ {:c1x (:x cp1)
+ :c1y (:y cp1)
+ :c2x (:x cp2)
+ :c2y (:y cp2)}))
+
+(defn arc->beziers*
+ [from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation]
+ (a2b/calculateBeziers from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation))
+
+(defn arc->beziers [from-p command]
+ (let [to-command
+ (fn [[_ _ c1x c1y c2x c2y x y]]
+ {:command :curve-to
+ :relative (:relative command)
+ :params {:c1x c1x :c1y c1y
+ :c2x c2x :c2y c2y
+ :x x :y y}})
+
+ {from-x :x from-y :y} from-p
+ {:keys [rx ry x-axis-rotation large-arc-flag sweep-flag x y]} (:params command)
+ result (arc->beziers* from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation)]
+ (mapv to-command result)))
+
+(defn simplify-commands
+ "Removes some commands and convert relative to absolute coordinates"
+ [commands]
+ (let [simplify-command
+ ;; prev-pos : previous position for the current path. Necessary for relative commands
+ ;; prev-start : previous move-to necessary 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 prev-pos))
+ (d/update-in-when [:params :c1y] + (:y prev-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 prev-pos))
+ (d/update-in-when [:params :cy] + (:y prev-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 prev-pos))
+
+ (= :line-to-vertical (:command command))
+ (d/update-in-when [:params :value] + (:y prev-pos)))))
+
+ params (:params command)
+ orig-command command
+
+ command
+ (cond-> command
+ (= :line-to-horizontal (:command command))
+ (-> (assoc :command :line-to)
+ (update :params dissoc :value)
+ (assoc-in [:params :x] (:value params))
+ (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 prev-pos)))
+
+ (= :smooth-curve-to (:command command))
+ (-> (assoc :command :curve-to)
+ (update :params dissoc :cx :cy)
+ (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 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 prev-pos (gpt/point params) (upg/calculate-opposite-handler prev-pos prev-qc)))))
+
+ result (if (= :elliptical-arc (:command command))
+ (into result (arc->beziers prev-pos command))
+ (conj result command))
+
+ next-cc (case (:command orig-command)
+ :smooth-curve-to
+ (gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
+
+ :curve-to
+ (gpt/point (get-in orig-command [:params :c2x]) (get-in orig-command [:params :c2y]))
+
+ (:line-to-horizontal :line-to-vertical)
+ (gpt/point (get-in command [:params :x]) (get-in command [:params :y]))
+
+ (gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
+
+ 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
+ (upg/calculate-opposite-handler prev-pos 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
+ (upc/command->point 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 (cond-> start
+ (:relative start)
+ (assoc :relative false))
+
+ start-pos (gpt/point (:params start))]
+
+ (->> (map vector (rest commands) commands)
+ (reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
+ (first))))
+
+(defn parse [path-str]
+ (if (empty? path-str)
+ path-str
+ (let [clean-path-str
+ (-> path-str
+ (str/trim)
+ ;; Change "commas" for spaces
+ (str/replace #"," " ")
+ ;; Remove all consecutive spaces
+ (str/replace #"\s+" " "))
+ commands (re-seq commands-regex clean-path-str)]
+ (-> (mapcat parse-command commands)
+ (simplify-commands)))))
+
diff --git a/common/src/app/common/svg/path/legacy.cljc b/common/src/app/common/svg/path/legacy_parser2.cljc
similarity index 97%
rename from common/src/app/common/svg/path/legacy.cljc
rename to common/src/app/common/svg/path/legacy_parser2.cljc
index 5949059064..fab3f8102e 100644
--- a/common/src/app/common/svg/path/legacy.cljc
+++ b/common/src/app/common/svg/path/legacy_parser2.cljc
@@ -4,9 +4,11 @@
;;
;; Copyright (c) KALEIDOS INC
-(ns app.common.svg.path.legacy
- "The first svg path parser implementation in pure clojure, used as reference impl
- and for tests."
+(ns app.common.svg.path.legacy-parser2
+ "The second SVG Path parser implementation.
+
+ Written in crossplatform CLJC code. Used meanwhile a hight
+ performance parser is developed in the 1.20 version."
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
@@ -16,7 +18,6 @@
[app.common.svg.path.command :as upc]
[cuerdas.core :as str]))
-
(def commands-regex #"(?i)[mzlhvcsqta][^mzlhvcsqta]*")
(def regex #"[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?")
@@ -296,10 +297,10 @@
y1p (+ (/ (* (- sin-phi) (- x1 x2)) 2)
(/ (* cos-phi (- y1 y2)) 2))]
- (if (or (zero? x1p)
- (zero? y1p)
- (zero? rx)
- (zero? ry))
+ (if (or (and (zero? x1p)
+ (zero? y1p))
+ (and (zero? rx)
+ (zero? ry)))
[]
(let [
rx (mth/abs rx)
@@ -462,19 +463,10 @@
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
(first))))
-
(defn parse
[path-str]
(if (empty? path-str)
path-str
(let [commands (re-seq commands-regex path-str)]
(->> (mapcat parse-command commands)
- (simplify-commands)
- (map (fn [segment]
- ;; (prn "LEGACY:" segment)
- segment))))))
-
-
-
-
-
+ (simplify-commands)))))
diff --git a/common/src/app/common/svg/path/parser.js b/common/src/app/common/svg/path/parser.js
index d156d6ca21..804112f073 100644
--- a/common/src/app/common/svg/path/parser.js
+++ b/common/src/app/common/svg/path/parser.js
@@ -1,3 +1,11 @@
+/**
+ * Performance focused pure javascript implementation of the
+ * SVG path parser.
+ *
+ * @author KALEIDOS INC
+ * @license MPL-2.0
+ */
+
import cljs from "goog:cljs.core";
const MOVE_TO = cljs.keyword("move-to");
@@ -674,7 +682,13 @@ export function arcToBeziers(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
let x1p = (cosPhi * (x1 - x2)) / 2 + (sinPhi * (y1 - y2)) / 2;
let y1p = (-sinPhi * (x1 - x2)) / 2 + (cosPhi * (y1 - y2)) / 2;
- if (x1p === 0 || y1p === 0 || rx === 0 || ry === 0) {
+ if (x1p === 0 && y1p === 0) {
+ // we're asked to draw line to itself
+ return [];
+ }
+
+ if (rx === 0 || ry === 0) {
+ // one of the radii is zero
return [];
}
@@ -877,6 +891,7 @@ function simplifyPathData(pdata) {
currentX = x;
currentY = y;
} else if (currentX !== x || currentY !== y) {
+
var segments = arcToBeziers(currentX, currentY, x, y, fa, fs, rx, ry, phi);
result.push(...segments);
diff --git a/common/src/app/common/svg/shapes_builder.cljc b/common/src/app/common/svg/shapes_builder.cljc
index 632b1483d8..6cb5429aa6 100644
--- a/common/src/app/common/svg/shapes_builder.cljc
+++ b/common/src/app/common/svg/shapes_builder.cljc
@@ -229,6 +229,7 @@
:svg-viewbox selrect
:svg-attrs attrs
:svg-transform transform
+ :strokes []
:fills []})
(gsh/translate-to-frame origin)))))
@@ -355,9 +356,9 @@
(assoc :svg-attrs props))))))
(defn setup-fill
- [shape]
- (let [color-attr (str/trim (dm/get-in shape [:svg-attrs :fill]))
- color-attr (if (= color-attr "currentColor") clr/black color-attr)
+ [shape]
+ (let [color-attr (str/trim (dm/get-in shape [:svg-attrs :fill]))
+ color-attr (if (= color-attr "currentColor") clr/black color-attr)
color-style (str/trim (dm/get-in shape [:svg-attrs :style :fill]))
color-style (if (= color-style "currentColor") clr/black color-style)]
(cond-> shape
@@ -384,6 +385,7 @@
(update :svg-attrs dissoc :fillOpacity)
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :style :fillOpacity])
(d/parse-double 1)))))))
+
(defn- setup-stroke
[shape]
(let [attrs (get shape :svg-attrs)
@@ -422,7 +424,8 @@
(dissoc :stroke)
(dissoc :strokeLinecap)
(dissoc :strokeWidth)
- (dissoc :strokeOpacity)))))]
+ (dissoc :strokeOpacity))))
+ (d/without-nils))]
(cond-> (assoc shape :svg-attrs attrs)
(some? color)
@@ -434,7 +437,7 @@
(and (some? color) (some? width))
(assoc-in [:strokes 0 :stroke-width] width)
- (and (some? linecap) (= (:type shape) :path)
+ (and (some? linecap) (cfh/path-shape? shape)
(or (= linecap :round) (= linecap :square)))
(assoc :stroke-cap-start linecap
:stroke-cap-end linecap)
@@ -464,9 +467,6 @@
(-> (update-in [:svg-attrs :style] dissoc :mixBlendMode)
(assoc :blend-mode (-> (dm/get-in shape [:svg-attrs :style :mixBlendMode]) assert-valid-blend-mode)))))
-
-
-
(defn tag->name
"Given a tag returns its layer name"
[tag]
diff --git a/common/target/classes/app/common/svg/path/Parser$ParserImpl.class b/common/target/classes/app/common/svg/path/Parser$ParserImpl.class
index eb42edaca5..e146fff62f 100644
Binary files a/common/target/classes/app/common/svg/path/Parser$ParserImpl.class and b/common/target/classes/app/common/svg/path/Parser$ParserImpl.class differ
diff --git a/common/target/classes/app/common/svg/path/Parser$Segment.class b/common/target/classes/app/common/svg/path/Parser$Segment.class
index 646d3b8036..29c2be1117 100644
Binary files a/common/target/classes/app/common/svg/path/Parser$Segment.class and b/common/target/classes/app/common/svg/path/Parser$Segment.class differ
diff --git a/common/target/classes/app/common/svg/path/Parser.class b/common/target/classes/app/common/svg/path/Parser.class
index 13d8402cf5..351b04b772 100644
Binary files a/common/target/classes/app/common/svg/path/Parser.class and b/common/target/classes/app/common/svg/path/Parser.class differ
diff --git a/common/test/common_tests/svg_path_test.cljc b/common/test/common_tests/svg_path_test.cljc
index 3fb89c432d..19140f91e4 100644
--- a/common/test/common_tests/svg_path_test.cljc
+++ b/common/test/common_tests/svg_path_test.cljc
@@ -10,9 +10,9 @@
[app.common.pprint :as pp]
[app.common.math :as mth]
[app.common.svg.path :as svg.path]
- [app.common.svg.path.legacy :as svg.path.legacy]
+ [app.common.svg.path.legacy-parser2 :as svg.path.legacy2]
[clojure.test :as t]
- #?(:cljs [common-tests.arc-to-bezier :as impl])))
+ #?(:cljs [app.common.svg.path.legacy-parser2 :as svg.path.legacy1])))
(t/deftest parse-test-1
(let [data (str "m -994.563 4564.1423 149.3086 -52.8821 30.1828 "
@@ -23,14 +23,25 @@
result1 (->> (svg.path/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))
- result2 (->> (svg.path.legacy/parse data)
+ result2 (->> (svg.path.legacy2/parse data)
(mapv (fn [entry]
- (update entry :params #(into (sorted-map) %)))))]
+ (update entry :params #(into (sorted-map) %)))))
+
+ result3 #?(:cljs (->> (svg.path.legacy1/parse data)
+ (mapv (fn [entry]
+ (update entry :params #(into (sorted-map) %)))))
+ :clj nil)]
(t/is (= 15
(count result1)
(count result2)))
+
+ #?(:cljs
+ (t/is (= 15
+ (count result1)
+ (count result3))))
+
(dotimes [i (count result1)]
(let [item1 (nth result1 i)
item2 (nth result2 i)]
@@ -40,6 +51,14 @@
(t/is (= (:params item1)
(:params item2)))
+ #?(:cljs
+ (let [item3 (nth result3 i)]
+ (t/is (= (:command item1)
+ (:command item3)))
+ (t/is (= (:params item1)
+ (:params item3)))))
+
+
#_(println "------------------------")
#_(pp/pprint (dissoc item1 :relative))
#_(pp/pprint (dissoc item2 :prev-pos :relative))))))
@@ -92,7 +111,7 @@
result1 (->> (svg.path/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))
- result2 (->> (svg.path.legacy/parse data)
+ result2 (->> (svg.path.legacy2/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))]
@@ -108,7 +127,6 @@
(t/is (= (:command item1)
(:command item2)))
-
;; (println "================" (:command item1))
;; (pp/pprint (:params item1))
;; (println "---------")
@@ -124,7 +142,7 @@
result1 (->> (svg.path/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))
- result2 (->> (svg.path.legacy/parse data)
+ result2 (->> (svg.path.legacy2/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))]
@@ -203,7 +221,7 @@
result1 (->> (svg.path/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))
- result2 (->> (svg.path.legacy/parse data)
+ result2 (->> (svg.path.legacy2/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))]
@@ -256,7 +274,7 @@
result1 (->> (svg.path/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))
- result2 (->> (svg.path.legacy/parse data)
+ result2 (->> (svg.path.legacy2/parse data)
(mapv (fn [entry]
(update entry :params #(into (sorted-map) %)))))]
@@ -279,6 +297,61 @@
(t/is (mth/close? v (get-in item2 [:params k]) 0.000000001))
)))))
+(t/deftest parse-test-6
+ (let [data (str "M3.078 3.548v16.9a.5.5 0 0 0 1 0v-16.9a.5.5 0 0 0-1 0ZM18.422 11.5"
+ "H7.582a2.5 2.5 0 0 1-2.5-2.5V6.565a2.5 2.5 0 0 1 2.5-2.5"
+ "h10.84a2.5 2.5 0 0 1 2.5 2.5V9a2.5 2.5 0 0 1-2.5 2.5Z"
+ "M7.582 5.065a1.5 1.5 0 0 0-1.5 1.5V9a1.5 1.5 0 0 0 1.5 1.5"
+ "h10.84a1.5 1.5 0 0 0 1.5-1.5V6.565a1.5 1.5 0 0 0-1.5-1.5Z"
+ "M13.451 19.938H7.582a2.5 2.5 0 0 1-2.5-2.5V15"
+ "a2.5 2.5 0 0 1 2.5-2.5h5.869a2.5 2.5 0 0 1 2.5 2.5v2.436"
+ "a2.5 2.5 0 0 1-2.5 2.502ZM7.582 13.5a1.5 1.5 0 0 0-1.5 1.5v2.436"
+ "a1.5 1.5 0 0 0 1.5 1.5h5.869a1.5 1.5 0 0 0 1.5-1.5V15"
+ "a1.5 1.5 0 0 0-1.5-1.5Z")
+
+ result1 (->> (svg.path/parse data)
+ (mapv (fn [entry]
+ (update entry :params #(into (sorted-map) %)))))
+ result2 (->> (svg.path.legacy2/parse data)
+ (mapv (fn [entry]
+ (update entry :params #(into (sorted-map) %)))))]
+
+ (t/is (= 47
+ (count result1)
+ (count result2)))
+
+ ;; (pp/pprint result1 {:length 100})
+ ;; (pp/pprint result2 {:length 50})
+
+ (dotimes [i (count result1)]
+ (let [item1 (nth result1 i)
+ item2 (nth result2 i)
+ ]
+
+ (t/is (= (:command item1)
+ (:command item2)))
+
+ (doseq [[k v] (:params item1)]
+ (t/is (mth/close? v (get-in item2 [:params k]) 0.000000001))
+ )))
+
+ #?(:cljs
+ (let [result3 (svg.path.legacy1/parse data)]
+ (t/is (= 47
+ (count result1)
+ (count result3)))
+
+ (dotimes [i (count result1)]
+ (let [item1 (nth result1 i)
+ item3 (nth result2 i)]
+
+ (t/is (= (:command item1)
+ (:command item3)))
+
+ (t/is (= (:params item1)
+ (:params item3)))))))))
+
+
(t/deftest arc-to-bezier-1
(let [expected1 [-1.6697754290362354e-13
-5.258016244624741e-13
@@ -316,7 +389,7 @@
(nth expected2 (+ i 2))
0.0000000001))))
- (let [[result1 result2 :as total] (svg.path.legacy/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
+ (let [[result1 result2 :as total] (svg.path.legacy2/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
(t/is (= (count total) 2))
(dotimes [i (count result1)]
@@ -327,7 +400,96 @@
(dotimes [i (count result2)]
(t/is (mth/close? (nth result2 i)
(nth expected2 i)
- 0.000000000001))))))
+ 0.000000000001))))
+
+ #?(:cljs
+ (let [[result1 result2 :as total] (svg.path.legacy1/arc->beziers* 0 0 30 50 0 0 1 162.55 162.45)]
+ (t/is (= (count total) 2))
+
+ (dotimes [i (count result1)]
+ (t/is (mth/close? (nth result1 i)
+ (nth expected1 i)
+ 0.000000000001)))
+
+ (dotimes [i (count result2)]
+ (t/is (mth/close? (nth result2 i)
+ (nth expected2 i)
+ 0.000000000001)))))
+
+ ))
+
+(t/deftest arc-to-bezier-2
+ (let [expected1 [3.0779999999999994,
+ 20.448,
+ 3.0780000082296834,
+ 20.724142369096132,
+ 3.3018576309038683,
+ 20.94799998509884,
+ 3.5779999999999994,
+ 20.94799998509884]
+
+ expected2 [3.5779999999999994,
+ 20.94799998509884,
+ 3.854142369096131,
+ 20.94799998509884,
+ 4.077999991770315,
+ 20.724142369096132,
+ 4.077999999999999,
+ 20.448]]
+
+ (let [[result1 result2 :as total] (->> (svg.path/arc->beziers 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)
+ (mapv (fn [segment]
+ (vec (.-params segment)))))]
+ (t/is (= (count total) 2))
+ ;; (println "================" 11111111)
+ ;; (pp/pprint expected1 {:width 50})
+ ;; (println "------------")
+ ;; (pp/pprint result1 {:width 50})
+
+ (dotimes [i (count result1)]
+ (t/is (mth/close? (nth result1 i)
+ (nth expected1 (+ i 2))
+ 0.0000000001)))
+
+ (dotimes [i (count result2)]
+ (t/is (mth/close? (nth result2 i)
+ (nth expected2 (+ i 2))
+ 0.0000000001))))
+
+ (let [[result1 result2 :as total] (svg.path.legacy2/arc->beziers* 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)]
+ (t/is (= (count total) 2))
+
+ ;; (println "================" 11111111)
+ ;; (pp/pprint expected1 {:width 50})
+ ;; (println "------------")
+ ;; (pp/pprint (vec result1) {:width 50})
+
+ (dotimes [i (count result1)]
+ (t/is (mth/close? (nth result1 i)
+ (nth expected1 i)
+ 0.000000000001)))
+
+ (dotimes [i (count result2)]
+ (t/is (mth/close? (nth result2 i)
+ (nth expected2 i)
+ 0.000000000001))))
+
+ #?(:cljs
+ (let [[result1 result2 :as total] (svg.path.legacy1/arc->beziers* 3.078 20.448 4.077999999999999 20.448 0 0 0.5 0.5 0)]
+ (t/is (= (count total) 2))
+
+ (dotimes [i (count result1)]
+ (t/is (mth/close? (nth result1 i)
+ (nth expected1 i)
+ 0.000000000001)))
+
+ (dotimes [i (count result2)]
+ (t/is (mth/close? (nth result2 i)
+ (nth expected2 i)
+ 0.000000000001)))))
+
+ ))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -357,14 +519,14 @@
"59.9137 -301.293 -1.0595 -51.375 25.7186 -261.0492 -7.706 ")
pattern [[:x :number] [:y :number]]]
- (t/is (= expected (svg.path.legacy/extract-params cmdstr pattern)))))
+ (t/is (= expected (svg.path.legacy2/extract-params cmdstr pattern)))))
(t/deftest extract-params-legacy-2
(let [expected [{:x -994.563, :y 4564.1423 :r 0}]
cmdstr (str "m -994.563 4564.1423 0")
pattern [[:x :number] [:y :number] [:r :flag]]]
- (t/is (= expected (svg.path.legacy/extract-params cmdstr pattern)))))
+ (t/is (= expected (svg.path.legacy2/extract-params cmdstr pattern)))))
(t/deftest extract-params-legacy-3
(let [cmdstr (str "a1.42 1.42 0 00-1.415-1.416 1.42 1.42 0 00-1.416 1.416 "
@@ -382,7 +544,7 @@
[:sweep-flag :flag]
[:x :number]
[:y :number]]
- result (svg.path.legacy/extract-params cmdstr pattern)]
+ result (svg.path.legacy2/extract-params cmdstr pattern)]
(t/is (= (nth result 0)
(nth expected 0)))
diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs
index 205f83a6e4..8bd9120479 100644
--- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs
+++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs
@@ -21,6 +21,9 @@
[cuerdas.core :as str]
[rumext.v2 :as mf]))
+;; FIXME: this clearly should be renamed to something different, this
+;; namespace has also fill related code
+
(mf/defc inner-stroke-clip-path
{::mf/wrap-props false}
[{:keys [shape render-id index]}]
@@ -449,10 +452,8 @@
(obj/unset! style "fillOpacity")
(obj/set! props "fill" (dm/fmt "url(#fill-%-%)" position render-id)))
- (and ^boolean (or (obj/contains? svg-styles "fill")
- (obj/contains? svg-styles "fillOpacity"))
+ (and ^boolean (some? svg-styles)
^boolean (obj/contains? svg-styles "fill"))
-
(let [fill (obj/get svg-styles "fill")
opacity (obj/get svg-styles "fillOpacity")]
(when (some? fill)
@@ -460,8 +461,7 @@
(when (some? opacity)
(obj/set! style "fillOpacity" opacity)))
- (and ^boolean (or (obj/contains? svg-attrs "fill")
- (obj/contains? svg-attrs "fillOpacity"))
+ (and ^boolean (some? svg-attrs)
^boolean (empty? shape-fills))
(let [fill (obj/get svg-attrs "fill")
opacity (obj/get svg-attrs "fillOpacity")]
@@ -562,13 +562,6 @@
(mf/defc shape-custom-strokes
{::mf/wrap-props false}
[props]
- (let [children (unchecked-get props "children")
- shape (unchecked-get props "shape")
- position (unchecked-get props "position")
- render-id (unchecked-get props "render-id")
- props #js {:shape shape
- :position position
- :render-id render-id}]
- [:*
- [:> shape-fills props children]
- [:> shape-strokes props children]]))
+ [:*
+ [:> shape-fills props]
+ [:> shape-strokes props]])
diff --git a/frontend/src/app/main/ui/shapes/fills.cljs b/frontend/src/app/main/ui/shapes/fills.cljs
index dca1f78a9c..cea64f7ca3 100644
--- a/frontend/src/app/main/ui/shapes/fills.cljs
+++ b/frontend/src/app/main/ui/shapes/fills.cljs
@@ -17,7 +17,7 @@
(def no-repeat-padding 1.05)
-(mf/defc fills*
+(mf/defc internal-fills
{::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
@@ -120,7 +120,6 @@
(mf/defc fills
{::mf/wrap-props false}
[props]
-
(let [shape (unchecked-get props "shape")
type (dm/get-prop shape :type)
image (:fill-image shape)
@@ -132,4 +131,4 @@
(> (count fills) 1)
(some :fill-color-gradient fills)
(some :fill-image fills))
- [:> fills* props])))
+ [:> internal-fills props])))