mirror of
https://github.com/blender/blender-addons.git
synced 2025-07-25 16:05:20 +00:00
104 lines
2.8 KiB
Python
104 lines
2.8 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import re
|
|
|
|
|
|
units = {"": 1.0,
|
|
"px": 1.0,
|
|
"in": 90.0,
|
|
"mm": 90.0 / 25.4,
|
|
"cm": 90.0 / 2.54,
|
|
"pt": 1.25,
|
|
"pc": 15.0,
|
|
"em": 1.0,
|
|
"ex": 1.0,
|
|
"INVALID": 1.0, # some DocBook files contain this
|
|
}
|
|
|
|
|
|
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+(\.\d+)?([eE][-+]?\d+)?"
|
|
match_first_comma = r"^\s*(?=,)"
|
|
match_comma_pair = r",\s*(?=,)"
|
|
match_last_comma = r",\s*$"
|
|
|
|
match_number_optional_parts = r"(-?\d+(\.\d*)?([eE][-+]?\d+)?)|(-?\.\d+([eE][-+]?\d+)?)"
|
|
re_match_number_optional_parts = re.compile(match_number_optional_parts)
|
|
|
|
array_of_floats_pattern = f"({match_number_optional_parts})|{match_first_comma}|{match_comma_pair}|{match_last_comma}"
|
|
re_array_of_floats_pattern = re.compile(array_of_floats_pattern)
|
|
|
|
def parse_array_of_floats(text):
|
|
"""
|
|
Accepts comma or space separated list of floats (without units) and returns an array
|
|
of floating point values.
|
|
"""
|
|
elements = re_array_of_floats_pattern.findall(text)
|
|
return [value_to_float(v[0]) for v in elements]
|
|
|
|
|
|
def read_float(text: str, start_index: int = 0):
|
|
"""
|
|
Reads floating point value from a string. Parsing starts at the given index.
|
|
|
|
Returns the value itself (as a string) and index of first character after the value.
|
|
"""
|
|
|
|
n = len(text)
|
|
|
|
# Skip leading whitespace characters and characters which we consider ignorable for float
|
|
# (like values separator).
|
|
while start_index < n and (text[start_index].isspace() or text[start_index] == ','):
|
|
start_index += 1
|
|
if start_index == n:
|
|
return "0", start_index
|
|
|
|
text_part = text[start_index:]
|
|
match = re_match_number_optional_parts.match(text_part)
|
|
|
|
if match is None:
|
|
raise Exception('Invalid float value near ' + text[start_index:start_index + 10])
|
|
|
|
token = match.group(0)
|
|
endptr = start_index + match.end(0)
|
|
|
|
return token, endptr
|
|
|
|
|
|
def parse_coord(coord, size):
|
|
"""
|
|
Parse coordinate component to common basis
|
|
|
|
Needed to handle coordinates set in cm, mm, inches.
|
|
"""
|
|
|
|
token, last_char = read_float(coord)
|
|
val = float(token)
|
|
unit = coord[last_char:].strip() # strip() in case there is a space
|
|
|
|
if unit == '%':
|
|
return float(size) / 100.0 * val
|
|
else:
|
|
return val * units[unit]
|
|
|
|
return val
|
|
|
|
|
|
def value_to_float(value_encoded: str):
|
|
"""
|
|
A simple wrapper around float() which supports empty strings (which are converted to 0).
|
|
"""
|
|
if len(value_encoded) == 0:
|
|
return 0
|
|
return float(value_encoded)
|