def test_override_bounds_copy(): # Get the bounds of a Paper, modify them, then set them back changed. paper = Paper() paper.override_bounds(0, 0, 1, 1) bounds = paper.bounds() bounds.right = 5 assert_equal(paper.bounds(), Bounds(0, 0, 1, 1)) paper.override_bounds(bounds) assert_equal(paper.bounds(), Bounds(0, 0, 5, 1)) # This works on non-overridden Papers as well. paper = Paper() p = Pen() p.fill_mode() p.move_to((0.5, 0.5)) p.circle(0.5) bounds = p.paper.bounds() bounds.right = 5 assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) p.paper.override_bounds(bounds) assert_equal(p.paper.bounds(), Bounds(0, 0, 5, 1))
def draw_letter( letter, mode, fixed_width=None, show_template=False, show_bounds=False, fuse=True, ): """ Draw the given letter and return a Paper. The letter is located centered on x=0, and with y=0 as the character baseline. If `fixed_width` is specified, use that for the paper width. """ if DEBUG_OUTPUT: print(str(letter), file=sys.stderr) try: character_paper = letter.draw_character(mode, fuse=fuse) except Exception: if DEBUG_OUTPUT: traceback.print_exc() # Return an error pattern. pen = Pen() pen.fill_mode() pen.square(1) character_paper = pen.paper else: raise if fixed_width is not None: bounds = character_paper.bounds() bounds.left = -fixed_width / 2 bounds.right = +fixed_width / 2 character_paper.override_bounds(bounds) template_paper = Paper() if show_template: template_paper = draw_template_path() else: template_paper = Paper() letter_paper = Paper() letter_paper.merge(template_paper) letter_paper.merge(character_paper) # Set proper bounds for typesetting. Use the character bounds as our basis # so the template doesn't increase the size. bounds = character_paper.bounds() letter_paper.override_bounds(bounds) if show_bounds: pen = Pen() pen.fill_mode('#aaa') bounds.draw(pen) letter_paper.merge_under(pen.paper) return letter_paper
def test_override_bounds_copy(): # Get the bounds of a Paper, modify them, then set them back changed. paper = Paper() paper.override_bounds(0, 0, 1, 1) bounds = paper.bounds() bounds.right = 5 assert_equal(paper.bounds(), Bounds(0, 0, 1, 1)) paper.override_bounds(bounds) assert_equal(paper.bounds(), Bounds(0, 0, 5, 1)) # This works on non-overridden Papers as well. paper = Paper() p = Pen() p.fill_mode() p.move_to((0.5, 0.5)) p.circle(0.5) bounds = p.paper.bounds() bounds.right = 5 assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) p.paper.override_bounds(bounds) assert_equal(p.paper.bounds(), Bounds(0, 0, 5, 1))
def test_paper_merge(): # Merge two drawings together. paper = Paper() p = Pen() p.fill_mode() p.turn_to(0) p.arc_left(180, 5) p.paper.center_on_x(0) paper.merge(p.paper) p = Pen() p.fill_mode() p.turn_to(180) p.arc_left(180, 5) p.paper.center_on_x(0) paper.merge(p.paper) assert_path_data( paper, 1, [ 'M-2.5,0.0 A 5.0,5.0 0 0 0 -2.5,-10.0', 'M2.5,0.0 A 5.0,5.0 0 0 0 2.5,10.0', ] )
def test_translate(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(3) p.arc_left(90, 3) p.turn_left(90) p.move_forward(3) p.fill_mode() p.circle(0.5) p.move_forward(3) p.square(1) p.paper.translate((1, 1)) assert_equal( p.paper.svg_elements(1), [ ( '<path d="M1.0,-1.5 L1.0,-0.5 L4.0,-0.5 A 3.5,3.5 0 0 0 ' '7.5,-4.0 L6.5,-4.0 A 2.5,2.5 0 0 1 4.0,-1.5 L1.0,-1.5 z" ' 'fill="#000000" />' ), ( '<path d="M4.5,-4.0 A 0.5,0.5 0 0 0 3.5,-4.0 ' 'A 0.5,0.5 0 0 0 4.5,-4.0 z" fill="#000000" />' ), ( '<path d="M0.5,-3.5 L1.5,-3.5 L1.5,-4.5 L0.5,-4.5 L0.5,-3.5 z" ' 'fill="#000000" />' ), ] )
def test_join_paths_reference(): # Join paths in such a way that a single path object must be # used as both the "left" and "right" path in different joins. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((5, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M5,0 L4,0 L3,0 L2,0 L1,0 L0,0' )
def test_translate_override_bounds(): # Translate a paper that has overridden bounds. The bounds update as well. paper = Paper() paper.override_bounds(0, 0, 1, 1) paper.translate((3, 4)) assert_equal( paper.bounds(), Bounds(3, 4, 4, 5) ) # When bounds=False is passed, then the bounds do not update. paper = Paper() paper.override_bounds(0, 0, 1, 1) paper.translate((3, 4), bounds=False) assert_equal(paper.bounds(), Bounds(0, 0, 1, 1)) # This also works if the bounds are not overridden. p = Pen() p.fill_mode() p.move_to((0.5, 0.5)) p.circle(0.5) assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) p.paper.translate((3, 4), bounds=False) assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) assert_equal(p.last_path().bounds(), Bounds(3, 4, 4, 5))
def test_copy_log(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.line_forward(5) p2 = p1.copy(paper=True) p2.line_forward(5) assert_equal( p1.log(), [ 'fill_mode()', 'move_to((0, 0))', 'turn_to(0)', 'line_forward(5)', ] ) assert_path_data( p1, 0, 'M0,0 L5,0' ) assert_equal( p2.log(), [ 'fill_mode()', 'move_to((0, 0))', 'turn_to(0)', 'line_forward(5)', 'line_forward(5)', ] ) assert_path_data( p2, 0, 'M0,0 L5,0 L10,0' )
def test_translate(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(3) p.arc_left(90, 3) p.turn_left(90) p.move_forward(3) p.fill_mode() p.circle(0.5) p.move_forward(3) p.square(1) p.paper.translate((1, 1)) assert_equal(p.paper.svg_elements(1), [ ('<path d="M1.0,-1.5 L1.0,-0.5 L4.0,-0.5 A 3.5,3.5 0 0 0 ' '7.5,-4.0 L6.5,-4.0 A 2.5,2.5 0 0 1 4.0,-1.5 L1.0,-1.5 z" ' 'fill="#000000" />'), ('<path d="M4.5,-4.0 A 0.5,0.5 0 0 0 3.5,-4.0 ' 'A 0.5,0.5 0 0 0 4.5,-4.0 z" fill="#000000" />'), ('<path d="M0.5,-3.5 L1.5,-3.5 L1.5,-4.5 L0.5,-4.5 L0.5,-3.5 z" ' 'fill="#000000" />'), ])
def test_copy_arc_to(): p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(0) p.arc_to((5, 5)) p = p.copy(paper=True) assert_path_data(p, 0, 'M0,0 A 5,5 0 0 0 5,-5')
def test_draw_bounds(): p = Pen() p.fill_mode() Bounds(-2, -3, 1, 2).draw(p) assert_path_data( p, 0, 'M-2,3 L1,3 L1,-2 L-2,-2 L-2,3 z' )
def test_circle_bounds(): p = Pen() p.fill_mode() p.move_to((1, 1)) p.circle(1.5) assert_equal( p.paper.bounds(), Bounds(-0.5, -0.5, 2.5, 2.5) )
def test_square_bounds(): p = Pen() p.fill_mode() p.move_to((1, 1)) p.square(4) assert_equal( p.paper.bounds(), Bounds(-1, -1, 3, 3) )
def test_copy_no_paper(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.line_forward(5) p2 = p1.copy() p2.line_forward(5) assert_path_data(p1, 0, 'M0,0 L5,0') assert_path_data(p2, 0, 'M5,0 L10,0')
def test_copy_arc_to(): p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(0) p.arc_to((5, 5)) p = p.copy(paper=True) assert_path_data( p, 0, 'M0,0 A 5,5 0 0 0 5,-5' )
def test_two_pens_one_paper(): paper = Paper() p1 = Pen(paper) p2 = Pen(paper) p1.fill_mode() p2.fill_mode() p1.move_to((0, 0)) p2.move_to((0, 0)) p1.line_to((0, 1)) p2.line_to((2, 0)) assert_path_data(paper, 0, ['M0,0 L0,-1', 'M0,0 L2,0'])
def test_copy_arc(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.arc_left(90, radius=5) p2 = p1.copy(paper=True) p2.arc_left(90, radius=5) assert_path_data(p1, 0, 'M0,0 A 5,5 0 0 0 5,-5') assert_path_data(p2, 0, 'M0,0 A 5,5 0 0 0 5,-5 A 5,5 0 0 0 0,-10')
def draw(): p = Pen() p.fill_mode() p.move_to((0, 0)) p.circle(2) paper1 = p.paper p = Pen() p.fill_mode() p.move_to((3, 0)) p.circle(1) paper2 = p.paper return paper1, paper2
def draw(): p = Pen() p.fill_mode() p.move_to((0, 0)) p.circle(2) paper1 = p.paper p = Pen() p.fill_mode() p.move_to((3, 0)) p.circle(1) paper2 = p.paper return paper1, paper2
def test_two_pens_one_paper(): paper = Paper() p1 = Pen(paper) p2 = Pen(paper) p1.fill_mode() p2.fill_mode() p1.move_to((0, 0)) p2.move_to((0, 0)) p1.line_to((0, 1)) p2.line_to((2, 0)) assert_path_data( paper, 0, ['M0,0 L0,-1', 'M0,0 L2,0'] )
def test_copy_no_paper(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.line_forward(5) p2 = p1.copy() p2.line_forward(5) assert_path_data( p1, 0, 'M0,0 L5,0' ) assert_path_data( p2, 0, 'M5,0 L10,0' )
def test_copy_arc(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.arc_left(90, radius=5) p2 = p1.copy(paper=True) p2.arc_left(90, radius=5) assert_path_data( p1, 0, 'M0,0 A 5,5 0 0 0 5,-5' ) assert_path_data( p2, 0, 'M0,0 A 5,5 0 0 0 5,-5 A 5,5 0 0 0 0,-10' )
def test_paper_merge(): # Merge two drawings together. paper = Paper() p = Pen() p.fill_mode() p.turn_to(0) p.arc_left(180, 5) p.paper.center_on_x(0) paper.merge(p.paper) p = Pen() p.fill_mode() p.turn_to(180) p.arc_left(180, 5) p.paper.center_on_x(0) paper.merge(p.paper) assert_path_data(paper, 1, [ 'M-2.5,0.0 A 5.0,5.0 0 0 0 -2.5,-10.0', 'M2.5,0.0 A 5.0,5.0 0 0 0 2.5,10.0', ])
def test_copy_log(): p1 = Pen() p1.fill_mode() p1.move_to((0, 0)) p1.turn_to(0) p1.line_forward(5) p2 = p1.copy(paper=True) p2.line_forward(5) assert_equal(p1.log(), [ 'fill_mode()', 'move_to((0, 0))', 'turn_to(0)', 'line_forward(5)', ]) assert_path_data(p1, 0, 'M0,0 L5,0') assert_equal(p2.log(), [ 'fill_mode()', 'move_to((0, 0))', 'turn_to(0)', 'line_forward(5)', 'line_forward(5)', ]) assert_path_data(p2, 0, 'M0,0 L5,0 L10,0')
def test_join_paths_reference(): # Join paths in such a way that a single path object must be # used as both the "left" and "right" path in different joins. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((5, 0)) p.paper.join_paths() assert_path_data(p, 0, 'M5,0 L4,0 L3,0 L2,0 L1,0 L0,0')
def test_line_segment_bounds(): # Fill mode segment. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((2, 3)) line = p.last_segment() assert_equal( line.bounds(), Bounds(1, 0, 2, 3) ) # Stroke mode segment. p = Pen() p.stroke_mode(sqrt2) p.move_to((0, 0)) p.line_to((5, 5)) line = p.last_segment() assert_equal( line.bounds(), Bounds(-0.5, -0.5, 5.5, 5.5) )
def test_translate_override_bounds(): # Translate a paper that has overridden bounds. The bounds update as well. paper = Paper() paper.override_bounds(0, 0, 1, 1) paper.translate((3, 4)) assert_equal(paper.bounds(), Bounds(3, 4, 4, 5)) # When bounds=False is passed, then the bounds do not update. paper = Paper() paper.override_bounds(0, 0, 1, 1) paper.translate((3, 4), bounds=False) assert_equal(paper.bounds(), Bounds(0, 0, 1, 1)) # This also works if the bounds are not overridden. p = Pen() p.fill_mode() p.move_to((0.5, 0.5)) p.circle(0.5) assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) p.paper.translate((3, 4), bounds=False) assert_equal(p.paper.bounds(), Bounds(0, 0, 1, 1)) assert_equal(p.last_path().bounds(), Bounds(3, 4, 4, 5))
def test_join_paths_loop(): # Already looped paths should not be affected by join_paths. p = Pen() p.fill_mode() p.move_to((0, 0)) p.square(2) target = 'M-1,1 L1,1 L1,-1 L-1,-1 L-1,1 z' assert_path_data(p, 0, target) p.paper.join_paths() assert_path_data(p, 0, target) # Loops can also be created by joining paths. p = Pen() p.fill_mode() p.move_to((0, 0)) p.line_to((1, 0)) p.line_to((1, 1)) p.break_stroke() p.line_to((0, 1)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M1,-1 L1,0 L0,0 L0,-1 L1,-1 z' ) # The joins can get complicated. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 2)) p.break_stroke() p.move_to((4, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((2, 2)) p.paper.join_paths() assert_path_data( p, 0, 'M1,0 L2,-2 L4,0 L3,0 L2,0 L1,0 z', )
def test_join_paths_loop(): # Already looped paths should not be affected by join_paths. p = Pen() p.fill_mode() p.move_to((0, 0)) p.square(2) target = 'M-1,1 L1,1 L1,-1 L-1,-1 L-1,1 z' assert_path_data(p, 0, target) p.paper.join_paths() assert_path_data(p, 0, target) # Loops can also be created by joining paths. p = Pen() p.fill_mode() p.move_to((0, 0)) p.line_to((1, 0)) p.line_to((1, 1)) p.break_stroke() p.line_to((0, 1)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data(p, 0, 'M1,-1 L1,0 L0,0 L0,-1 L1,-1 z') # The joins can get complicated. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 2)) p.break_stroke() p.move_to((4, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((4, 0)) p.line_to((2, 2)) p.paper.join_paths() assert_path_data( p, 0, 'M1,0 L2,-2 L4,0 L3,0 L2,0 L1,0 z', )
from canoepaddle import Pen p = Pen() p.fill_mode('#84f') def petal(start_radius, distance, heading): radius = start_radius p.move_to((0, 0)) p.turn_to(heading) p.move_forward(distance) for _ in range(50): p.circle(radius) p.turn_left(12) new_radius = radius / 1.1 p.move_forward(radius + new_radius) radius = new_radius num_petals = 8 heading = 0 for _ in range(num_petals): petal(0.7, 2.0, heading) heading += (360 / num_petals) print(p.paper.format_svg())
from canoepaddle import Pen p = Pen() p.fill_mode('#84f') def petal(start_radius, distance, heading): radius = start_radius p.move_to((0, 0)) p.turn_to(heading) p.move_forward(distance) for _ in range(50): p.circle(radius) p.turn_left(12) new_radius = radius / 1.1 p.move_forward(radius + new_radius) radius = new_radius num_petals = 8 heading = 0 for _ in range(num_petals): petal(0.7, 2.0, heading) heading += (360 / num_petals) print(p.paper.format_svg())
def draw(): p = Pen() center_radius = 3.0 start_radius = radius = 100 start_width = width = 3.0 ratio = (1 / 2) ** (1/5) series = [] while radius > center_radius / sqrt2: series.append((radius, width)) radius *= ratio width *= ratio p.move_to((0, 0)) for radius, width in series: p.stroke_mode(width, 'black') p.circle(radius) # Parametric conic spirals. p.move_to((0, 0)) def spiral(theta): b = (1 / 2) ** (-2 / math.pi) r = start_radius * (b ** (-theta)) x = r * math.cos(theta) y = r * math.sin(theta) z = start_radius - r return (x, y, z) def spiral_top1(t): x, y, z = spiral(t) return x, y def spiral_top2(t): x, y, z = spiral(t) x = -x y = -y return x, y # Top spirals. p.stroke_mode(start_width, 'black') p.parametric(spiral_top1, 0, 4*math.pi, .1) p.parametric(spiral_top2, 0, 4*math.pi, .1) # Blank out the bottom triangle. p.fill_mode('white') p.move_to((0, 0)) s = start_radius + start_width p.line_to((-s, -s)) p.line_to((+s, -s)) p.line_to((0, 0)) # Horizontal lines for the bottom triangle. for radius, width in series: p.stroke_mode(width, 'black') p.move_to((-radius, -radius)) p.line_to( (+radius, -radius), start_slant=45, end_slant=-45, ) # Front spirals. def spiral_front1(t): x, y, z = spiral(t) return (x, z - start_radius) def spiral_front2(t): x, y, z = spiral(t) x = -x y = -y return (x, z - start_radius) p.move_to((0, 0)) p.stroke_mode(start_width, 'black') p.parametric(spiral_front1, 0, math.pi, .1) p.parametric(spiral_front2, math.pi, 2*math.pi, .1) p.parametric(spiral_front1, 2*math.pi, 3*math.pi, .1) # Fill in the center. p.move_to((0, 0)) p.fill_mode('black') p.circle(center_radius) return p.paper
def draw(): p = Pen() center_radius = 3.0 start_radius = radius = 100 start_width = width = 3.0 ratio = (1 / 2) ** (1/5) series = [] while radius > center_radius / sqrt2: series.append((radius, width)) radius *= ratio width *= ratio p.move_to((0, 0)) for radius, width in series: p.stroke_mode(width, 'black') p.circle(radius) # Parametric conic spirals. p.move_to((0, 0)) def spiral(theta): b = (1 / 2) ** (-2 / math.pi) r = start_radius * (b ** (-theta)) x = r * math.cos(theta) y = r * math.sin(theta) z = start_radius - r return (x, y, z) def spiral_top1(t): x, y, z = spiral(t) return x, y def spiral_top2(t): x, y, z = spiral(t) x = -x y = -y return x, y # Top spirals. p.stroke_mode(start_width, 'black') p.parametric(spiral_top1, 0, 4*math.pi, .1) p.parametric(spiral_top2, 0, 4*math.pi, .1) # Blank out the bottom triangle. p.fill_mode('white') p.move_to((0, 0)) s = start_radius + start_width p.line_to((-s, -s)) p.line_to((+s, -s)) p.line_to((0, 0)) # Horizontal lines for the bottom triangle. for radius, width in series: p.stroke_mode(width, 'black') p.move_to((-radius, -radius)) p.line_to( (+radius, -radius), start_slant=45, end_slant=-45, ) # Front spirals. def spiral_front1(t): x, y, z = spiral(t) return (x, z - start_radius) def spiral_front2(t): x, y, z = spiral(t) x = -x y = -y return (x, z - start_radius) p.move_to((0, 0)) p.stroke_mode(start_width, 'black') p.parametric(spiral_front1, 0, math.pi, .1) p.parametric(spiral_front2, math.pi, 2*math.pi, .1) p.parametric(spiral_front1, 2*math.pi, 3*math.pi, .1) # Fill in the center. p.move_to((0, 0)) p.fill_mode('black') p.circle(center_radius) return p.paper
def test_arc_segment_bounds(): # Arc which occupies its entire circle. p = Pen() p.fill_mode() p.move_to((1, 0)) p.turn_to(90) p.arc_left(359, 1) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(-1, -1, 1, 1) ) # Arc which pushes the boundary only with the endpoints. p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(30) p.move_forward(1) p.turn_left(90) p.arc_left(30, center=(0, 0)) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(0.5, 0.5, sqrt3 / 2, sqrt3 / 2) ) # Arc which pushes the boundary with the middle in one spot. p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(-45) p.move_forward(1) p.turn_left(90) p.arc_left(90, center=(0, 0)) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(sqrt2 / 2, -sqrt2 / 2, 1, sqrt2 / 2) ) # Arc which goes right. p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(45) p.arc_right(90, 3) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(0, 0, 3 * sqrt2, 3 - 1.5 * sqrt2) ) # Arc which pushes the boundary with the middle in two spots. p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(-45) p.move_forward(1) p.turn_left(90) p.arc_left(180, center=(0, 0)) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(-sqrt2 / 2, -sqrt2 / 2, 1, 1) ) # Half circle, right side p = Pen() p.fill_mode() p.move_to((0, 0)) p.turn_to(0) p.arc_right(180, 5) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(0, -10, 5, 0) ) # Thick circle, p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.move_forward(5) p.turn_left(90) p.arc_left(180, 5, start_slant=45) arc = p.last_segment() assert_equal( arc.bounds(), Bounds(-5.5, -0.5314980314970469, 5.5, 5.5) )
return numpy.column_stack((t, c, s)) def draw_parametric_func(pen, f, t_range): txy_values = f(t_range) t, x, y = txy_values[0] pen.move_to((x, y)) for t, x, y in txy_values[1:]: pen.line_to((x, y)) mod = t % 1.0 if float_equal(mod, 0) or float_equal(mod, 1.0): pen.circle(0.01) step = 0.01 t_range = numpy.arange(-4 + step, 4, step) pen = Pen() pen.stroke_mode(0.01, 'green') draw_parametric_func(pen, euler_spiral_parametric, t_range) pen.fill_mode('green') pen.move_to((0.5, 0.5)) pen.circle(0.01) pen.move_to((-0.5, -0.5)) pen.circle(0.01) print(pen.paper.format_svg(5, resolution=500)) # TODO: euler spiral solver to end at a particular point. newton-raphson method for root finding convergence?
def test_join_paths(): # Join two paths starting from the same point. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0', ) # Join two paths that end in the same point. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0', ) # Join three paths going left in normal order. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', ) # Join three paths going right in normal order. p = Pen() p.fill_mode() p.move_to((0, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((3, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0 L3,0', ) # Join three paths going left in reverse order. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((3, 0)) p.line_to((2, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0 L3,0', ) # Join three paths going right in reverse order. p = Pen() p.fill_mode() p.move_to((2, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((0, 0)) p.line_to((1, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', ) # Join multiple paths together. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((1, 1)) p.break_stroke() p.move_to((1, 1)) p.line_to((2, 1)) p.break_stroke() p.move_to((2, 2)) p.line_to((2, 1)) p.break_stroke() p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L1,-1 L2,-1 L2,-2' ) # Join three paths so one path must reverse multiple times. p = Pen() p.fill_mode() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', )
from canoepaddle import Pen p = Pen() p.fill_mode('green') p.move_to((0, 0)) p.turn_to(0) radius = 0.01 for _ in range(200): p.circle(radius) p.turn_left(20) new_radius = radius * 1.05 p.move_forward(radius + new_radius) radius = new_radius print(p.paper.format_svg())
return numpy.column_stack((t, c, s)) def draw_parametric_func(pen, f, t_range): txy_values = f(t_range) t, x, y = txy_values[0] pen.move_to((x, y)) for t, x, y in txy_values[1:]: pen.line_to((x, y)) mod = t % 1.0 if float_equal(mod, 0) or float_equal(mod, 1.0): pen.circle(0.01) step = 0.01 t_range = numpy.arange(-4 + step, 4, step) pen = Pen() pen.stroke_mode(0.01, 'green') draw_parametric_func(pen, euler_spiral_parametric, t_range) pen.fill_mode('green') pen.move_to((0.5, 0.5)) pen.circle(0.01) pen.move_to((-0.5, -0.5)) pen.circle(0.01) print(pen.paper.format_svg(5, resolution=500)) #TODO: euler spiral solver to end at a particular point. newton-raphson method for root finding convergence?
def test_join_paths(): # Join two paths starting from the same point. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0', ) # Join two paths that end in the same point. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0', ) # Join three paths going left in normal order. p = Pen() p.fill_mode() p.move_to((3, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', ) # Join three paths going right in normal order. p = Pen() p.fill_mode() p.move_to((0, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((3, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0 L3,0', ) # Join three paths going left in reverse order. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((3, 0)) p.line_to((2, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M0,0 L1,0 L2,0 L3,0', ) # Join three paths going right in reverse order. p = Pen() p.fill_mode() p.move_to((2, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((2, 0)) p.break_stroke() p.move_to((0, 0)) p.line_to((1, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', ) # Join multiple paths together. p = Pen() p.fill_mode() p.move_to((1, 0)) p.line_to((0, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((1, 1)) p.break_stroke() p.move_to((1, 1)) p.line_to((2, 1)) p.break_stroke() p.move_to((2, 2)) p.line_to((2, 1)) p.break_stroke() p.paper.join_paths() assert_path_data(p, 0, 'M0,0 L1,0 L1,-1 L2,-1 L2,-2') # Join three paths so one path must reverse multiple times. p = Pen() p.fill_mode() p.move_to((2, 0)) p.line_to((1, 0)) p.break_stroke() p.move_to((2, 0)) p.line_to((3, 0)) p.break_stroke() p.move_to((1, 0)) p.line_to((0, 0)) p.paper.join_paths() assert_path_data( p, 0, 'M3,0 L2,0 L1,0 L0,0', )