initial commit
This commit is contained in:
85
apps/curve_subdivision.py
Normal file
85
apps/curve_subdivision.py
Normal file
@@ -0,0 +1,85 @@
|
||||
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')
|
Reference in New Issue
Block a user