Newer
Older
# SPDX-License-Identifier: GPL-2.0-or-later
import re
import xml.dom.minidom
from math import cos, sin, tan, atan2, pi, ceil
import bpy
from mathutils import Vector, Matrix
from . import svg_colors
from .svg_util import (units,
srgb_to_linearrgb,
check_points_equal,
parse_array_of_floats,
read_float)
#### Common utilities ####
SVGEmptyStyles = {'useFill': None,
'fill': None}
"""
Create new curve object to hold splines in
"""
cu = bpy.data.curves.new("Curve", 'CURVE')
obj = bpy.data.objects.new("Curve", cu)
return obj
def SVGFinishCurve():
"""
Finish curve creation
"""
pass
def SVGFlipHandle(x, y, x1, y1):
"""
Flip handle around base point
"""
x = x + (x - x1)
y = y + (y - y1)
return x, y
def SVGParseCoord(coord, size):
"""
Parse coordinate component to common basis
Needed to handle coordinates set in cm, mm, inches.
token, last_char = read_float(coord)
unit = coord[last_char:].strip() # strip() in case there is a space
if unit == '%':
return float(size) / 100.0 * val
def SVGRectFromNode(node, context):
"""
Get display rectangle from node
"""
w = context['rect'][0]
h = context['rect'][1]
if node.getAttribute('viewBox'):
viewBox = node.getAttribute('viewBox').replace(',', ' ').split()
w = SVGParseCoord(viewBox[2], w)
h = SVGParseCoord(viewBox[3], h)
else:
if node.getAttribute('width'):
w = SVGParseCoord(node.getAttribute('width'), w)
if node.getAttribute('height'):
h = SVGParseCoord(node.getAttribute('height'), h)
return (w, h)
def SVGMatrixFromNode(node, context):
"""
Get transformation matrix from given node
"""
tagName = node.tagName.lower()
tags = ['svg:svg', 'svg:use', 'svg:symbol']
if tagName not in tags and 'svg:' + tagName not in tags:
return Matrix()
has_user_coordinate = (len(context['rects']) > 1)
m = Matrix()
x = SVGParseCoord(node.getAttribute('x') or '0', rect[0])
y = SVGParseCoord(node.getAttribute('y') or '0', rect[1])
w = SVGParseCoord(node.getAttribute('width') or str(rect[0]), rect[0])
h = SVGParseCoord(node.getAttribute('height') or str(rect[1]), rect[1])
m = Matrix.Translation(Vector((x, y, 0.0)))
if has_user_coordinate:
if rect[0] != 0 and rect[1] != 0:
m = m @ Matrix.Scale(w / rect[0], 4, Vector((1.0, 0.0, 0.0)))
m = m @ Matrix.Scale(h / rect[1], 4, Vector((0.0, 1.0, 0.0)))
if node.getAttribute('viewBox'):
viewBox = node.getAttribute('viewBox').replace(',', ' ').split()
vx = SVGParseCoord(viewBox[0], w)
vy = SVGParseCoord(viewBox[1], h)
vw = SVGParseCoord(viewBox[2], w)
vh = SVGParseCoord(viewBox[3], h)
if vw == 0 or vh == 0:
return m
if has_user_coordinate or (w != 0 and h != 0):
sx = w / vw
sy = h / vh
scale = min(sx, sy)
else:
scale = 1.0
w = vw
h = vh
tx = (w - vw * scale) / 2
ty = (h - vh * scale) / 2
m = m @ Matrix.Translation(Vector((tx, ty, 0.0)))
m = m @ Matrix.Translation(Vector((-vx, -vy, 0.0)))
m = m @ Matrix.Scale(scale, 4, Vector((1.0, 0.0, 0.0)))
m = m @ Matrix.Scale(scale, 4, Vector((0.0, 1.0, 0.0)))
return m
def SVGParseTransform(transform):
"""
Parse transform string and return transformation matrix
"""
m = Matrix()
r = re.compile(r'\s*([A-z]+)\s*\((.*?)\)')
for match in r.finditer(transform):
func = match.group(1)
params = match.group(2)
params = params.replace(',', ' ').split()
proc = SVGTransforms.get(func)
if proc is None:
raise Exception('Unknown trasnform function: ' + func)
return m
def SVGGetMaterial(color, context):
"""
Get material for specified color
"""
materials = context['materials']
rgb_re = re.compile(r'^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,(\d+)\s*\)\s*$')
if color in materials:
return materials[color]
diff = None
if color.startswith('#'):
color = color[1:]
if len(color) == 3:
color = color[0] * 2 + color[1] * 2 + color[2] * 2
diff = (int(color[0:2], 16), int(color[2:4], 16), int(color[4:6], 16))
elif color in svg_colors.SVGColors:
diff = svg_colors.SVGColors[color]
else:
return None
diffuse_color = ([x / 255.0 for x in diff])
if context['do_colormanage']:
Loading
Loading full blame...