Import_3ds: Fixed keyframe transformation
[blender-addons.git] / io_curve_svg / svg_util.py
blobfe3fc5f6ba4fbfe85a6df7d118d486a040977133
1 # SPDX-FileCopyrightText: 2010-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 import re
8 units = {"": 1.0,
9 "px": 1.0,
10 "in": 90.0,
11 "mm": 90.0 / 25.4,
12 "cm": 90.0 / 2.54,
13 "pt": 1.25,
14 "pc": 15.0,
15 "em": 1.0,
16 "ex": 1.0,
17 "INVALID": 1.0, # some DocBook files contain this
21 def srgb_to_linearrgb(c):
22 if c < 0.04045:
23 return 0.0 if c < 0.0 else c * (1.0 / 12.92)
24 else:
25 return pow((c + 0.055) * (1.0 / 1.055), 2.4)
28 def check_points_equal(point_a, point_b):
29 return (abs(point_a[0] - point_b[0]) < 1e-6 and
30 abs(point_a[1] - point_b[1]) < 1e-6)
32 match_number = r"-?\d+(\.\d+)?([eE][-+]?\d+)?"
33 match_first_comma = r"^\s*(?=,)"
34 match_comma_pair = r",\s*(?=,)"
35 match_last_comma = r",\s*$"
37 match_number_optional_parts = r"(-?\d+(\.\d*)?([eE][-+]?\d+)?)|(-?\.\d+([eE][-+]?\d+)?)"
38 re_match_number_optional_parts = re.compile(match_number_optional_parts)
40 array_of_floats_pattern = f"({match_number_optional_parts})|{match_first_comma}|{match_comma_pair}|{match_last_comma}"
41 re_array_of_floats_pattern = re.compile(array_of_floats_pattern)
43 def parse_array_of_floats(text):
44 """
45 Accepts comma or space separated list of floats (without units) and returns an array
46 of floating point values.
47 """
48 elements = re_array_of_floats_pattern.findall(text)
49 return [value_to_float(v[0]) for v in elements]
52 def read_float(text: str, start_index: int = 0):
53 """
54 Reads floating point value from a string. Parsing starts at the given index.
56 Returns the value itself (as a string) and index of first character after the value.
57 """
59 n = len(text)
61 # Skip leading whitespace characters and characters which we consider ignorable for float
62 # (like values separator).
63 while start_index < n and (text[start_index].isspace() or text[start_index] == ','):
64 start_index += 1
65 if start_index == n:
66 return "0", start_index
68 text_part = text[start_index:]
69 match = re_match_number_optional_parts.match(text_part)
71 if match is None:
72 raise Exception('Invalid float value near ' + text[start_index:start_index + 10])
74 token = match.group(0)
75 endptr = start_index + match.end(0)
77 return token, endptr
80 def parse_coord(coord, size):
81 """
82 Parse coordinate component to common basis
84 Needed to handle coordinates set in cm, mm, inches.
85 """
87 token, last_char = read_float(coord)
88 val = float(token)
89 unit = coord[last_char:].strip() # strip() in case there is a space
91 if unit == '%':
92 return float(size) / 100.0 * val
93 else:
94 return val * units[unit]
96 return val
99 def value_to_float(value_encoded: str):
101 A simple wrapper around float() which supports empty strings (which are converted to 0).
103 if len(value_encoded) == 0:
104 return 0
105 return float(value_encoded)