diff --git a/io_curve_svg/import_svg.py b/io_curve_svg/import_svg.py index 072bbc19d5d9c0b8f2d582e000e9b870df3027c7..95c00a8ef52633eb565f808c60f9aa2c9fbf5a82 100644 --- a/io_curve_svg/import_svg.py +++ b/io_curve_svg/import_svg.py @@ -26,6 +26,9 @@ import bpy from mathutils import Vector, Matrix from . import svg_colors +from .svg_util import (srgb_to_linearrgb, + check_points_equal, + parse_array_of_floats) #### Common utilities #### @@ -45,17 +48,6 @@ SVGUnits = {"": 1.0, SVGEmptyStyles = {'useFill': None, 'fill': None} -def srgb_to_linearrgb(c): - if c < 0.04045: - return 0.0 if c < 0.0 else c * (1.0 / 12.92) - else: - return pow((c + 0.055) * (1.0 / 1.055), 2.4) - -def check_points_equal(point_a, point_b): - return (abs(point_a[0] - point_b[0]) < 1e-6 and - abs(point_a[1] - point_b[1]) < 1e-6) - - def SVGParseFloat(s, i=0): """ Parse first float value from string @@ -1729,9 +1721,7 @@ class SVGGeometryPOLY(SVGGeometry): self._styles = SVGParseStyles(self._node, self._context) - points = self._node.getAttribute('points') - points = points.replace(',', ' ').replace('-', ' -') - points = points.split() + points = parse_array_of_floats(self._node.getAttribute('points')) prev = None self._points = [] @@ -1740,7 +1730,7 @@ class SVGGeometryPOLY(SVGGeometry): if prev is None: prev = p else: - self._points.append((float(prev), float(p))) + self._points.append((prev, p)) prev = None def _doCreateGeom(self, instancing): diff --git a/io_curve_svg/svg_util.py b/io_curve_svg/svg_util.py new file mode 100644 index 0000000000000000000000000000000000000000..a3e1613cd17403bdd4d23cfd4e8d0688bcc56d65 --- /dev/null +++ b/io_curve_svg/svg_util.py @@ -0,0 +1,50 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +import re + +def srgb_to_linearrgb(c): + if c < 0.04045: + return 0.0 if c < 0.0 else c * (1.0 / 12.92) + else: + return pow((c + 0.055) * (1.0 / 1.055), 2.4) + + +def check_points_equal(point_a, point_b): + return (abs(point_a[0] - point_b[0]) < 1e-6 and + abs(point_a[1] - point_b[1]) < 1e-6) + +match_number = r"-?\d+([eE][-+]?\d+)?" +match_first_comma = r"^\s*(?=,)" +match_comma_pair = r",\s*(?=,)" +match_last_comma = r",\s*$" + +pattern = f"({match_number})|{match_first_comma}|{match_comma_pair}|{match_last_comma}" +re_pattern = re.compile(pattern) + +def parse_array_of_floats(text): + elements = re_pattern.findall(text) + return [value_to_float(v[0]) for v in elements] + +def value_to_float(value_encoded: str): + if len(value_encoded) == 0: + return 0 + return float(value_encoded) + diff --git a/io_curve_svg/svg_util_test.py b/io_curve_svg/svg_util_test.py new file mode 100755 index 0000000000000000000000000000000000000000..b3ecda83e375b139b4dca87bf120d1e8d8b4d93d --- /dev/null +++ b/io_curve_svg/svg_util_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +from svg_util import parse_array_of_floats +import unittest + + +class ParseArrayOfFloatsTest(unittest.TestCase): + def test_empty(self): + self.assertEqual(parse_array_of_floats(""), []) + self.assertEqual(parse_array_of_floats(" "), []) + + def test_single_value(self): + self.assertEqual(parse_array_of_floats("123"), [123]) + self.assertEqual(parse_array_of_floats(" \t 123 \t"), [123]) + + def test_single_value_exponent(self): + self.assertEqual(parse_array_of_floats("12e+3"), [12000]) + self.assertEqual(parse_array_of_floats("12e-3"), [0.012]) + + def test_space_separated_values(self): + self.assertEqual(parse_array_of_floats("123 45 6 89"), + [123, 45, 6, 89]) + self.assertEqual(parse_array_of_floats(" 123 45 6 89 "), + [123, 45, 6, 89]) + + def test_comma_separated_values(self): + self.assertEqual(parse_array_of_floats("123,45,6,89"), + [123, 45, 6, 89]) + self.assertEqual(parse_array_of_floats(" 123,45,6,89 "), + [123, 45, 6, 89]) + + def test_mixed_separated_values(self): + self.assertEqual(parse_array_of_floats("123,45 6,89"), + [123, 45, 6, 89]) + self.assertEqual(parse_array_of_floats(" 123 45,6,89 "), + [123, 45, 6, 89]) + + def test_omitted_value_with_comma(self): + self.assertEqual(parse_array_of_floats("1,,3"), [1, 0, 3]) + self.assertEqual(parse_array_of_floats(",,3"), [0, 0, 3]) + + def test_sign_as_separator(self): + self.assertEqual(parse_array_of_floats("1-3"), [1, -3]) + self.assertEqual(parse_array_of_floats("1+3"), [1, 3]) + + def test_all_commas(self): + self.assertEqual(parse_array_of_floats(",,,"), [0, 0, 0, 0]) + + +if __name__ == '__main__': + unittest.main(verbosity=2)