86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
import svgpathtools
|
|
import numpy as np
|
|
import math
|
|
|
|
def split_cubic(c, t):
|
|
c0, c1 = svgpathtools.split_bezier(c, t)
|
|
return svgpathtools.CubicBezier(c0[0], c0[1], c0[2], c0[3]), svgpathtools.CubicBezier(c1[0], c1[1], c1[2], c1[3])
|
|
|
|
def cubic_to_quadratic(curve):
|
|
# Best L2 approximation
|
|
m = (-curve.start + 3 * curve.control1 + 3 * curve.control2 - curve.end) / 4.0
|
|
return svgpathtools.QuadraticBezier(curve.start, m, curve.end)
|
|
|
|
def convert_and_write_svg(cubic, filename):
|
|
cubic_path = svgpathtools.Path(cubic)
|
|
cubic_ctrl = svgpathtools.Path(svgpathtools.Line(cubic.start, cubic.control1),
|
|
svgpathtools.Line(cubic.control1, cubic.control2),
|
|
svgpathtools.Line(cubic.control2, cubic.end))
|
|
cubic_color = (50, 50, 200)
|
|
cubic_ctrl_color = (150, 150, 150)
|
|
|
|
r = 4.0
|
|
|
|
paths = [cubic_path, cubic_ctrl]
|
|
colors = [cubic_color, cubic_ctrl_color]
|
|
dots = [cubic_path[0].start, cubic_path[0].control1, cubic_path[0].control2, cubic_path[0].end]
|
|
ncols = ['green', 'green', 'green', 'green']
|
|
nradii = [r, r, r, r]
|
|
stroke_widths = [3.0, 1.5]
|
|
|
|
def add_quadratic(q):
|
|
paths.append(q)
|
|
q_ctrl = svgpathtools.Path(svgpathtools.Line(q.start, q.control),
|
|
svgpathtools.Line(q.control, q.end))
|
|
paths.append(q_ctrl)
|
|
colors.append((200, 50, 50)) # q_color
|
|
colors.append((150, 150, 150)) # q_ctrl_color
|
|
dots.append(q.start)
|
|
dots.append(q.control)
|
|
dots.append(q.end)
|
|
ncols.append('purple')
|
|
ncols.append('purple')
|
|
ncols.append('purple')
|
|
nradii.append(r)
|
|
nradii.append(r)
|
|
nradii.append(r)
|
|
stroke_widths.append(3.0)
|
|
stroke_widths.append(1.5)
|
|
|
|
prec = 1.0
|
|
queue = [cubic]
|
|
num_quadratics = 0
|
|
while len(queue) > 0:
|
|
c = queue[-1]
|
|
queue = queue[:-1]
|
|
|
|
# Criteria for conversion
|
|
# http://caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html
|
|
p = c.end - 3 * c.control2 + 3 * c.control1 - c.start
|
|
d = math.sqrt(p.real * p.real + p.imag * p.imag) * math.sqrt(3.0) / 36
|
|
t = math.pow(1.0 / d, 1.0 / 3.0)
|
|
|
|
if t < 1.0:
|
|
c0, c1 = split_cubic(c, 0.5)
|
|
queue.append(c0)
|
|
queue.append(c1)
|
|
else:
|
|
quadratic = cubic_to_quadratic(c)
|
|
print(quadratic)
|
|
add_quadratic(quadratic)
|
|
num_quadratics += 1
|
|
print('num_quadratics:', num_quadratics)
|
|
|
|
svgpathtools.wsvg(paths,
|
|
colors = colors,
|
|
stroke_widths = stroke_widths,
|
|
nodes = dots,
|
|
node_colors = ncols,
|
|
node_radii = nradii,
|
|
filename = filename)
|
|
|
|
convert_and_write_svg(svgpathtools.CubicBezier(100+200j, 426+50j, 50+50j, 300+200j),
|
|
'results/curve_subdivision/subdiv_curve0.svg')
|
|
convert_and_write_svg(svgpathtools.CubicBezier(100+200j, 427+50j, 50+50j, 300+200j),
|
|
'results/curve_subdivision/subdiv_curve1.svg')
|