File size: 3,151 Bytes
31726e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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')