def test_arc_joint_continue(): p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.arc_left(90, 5) p.arc_left(90, 5) p.move_to((0, 0)) p.turn_to(0) p.arc_right(90, 5) p.arc_right(90, 5) assert_path_data( p, 0, ( 'M0,-1 L0,1 A 6,6 0 0 0 6,-5 A 6,6 0 0 0 0,-11 ' 'L0,-9 A 4,4 0 0 1 4,-5 A 4,4 0 0 1 0,-1 z ' 'M0,-1 L0,1 A 4,4 0 0 1 4,5 A 4,4 0 0 1 0,9 ' 'L0,11 A 6,6 0 0 0 6,5 A 6,6 0 0 0 0,-1 z' ), )
def test_line_line_half_illegal_joint(): # The outside edge meets, but the inside is too short to meet. p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(2) p.turn_left(165) p.line_forward(2) assert_path_data( p, 2, ( 'M0.00,-0.50 L0.00,0.50 L5.80,0.50 L0.20,-1.00 ' 'L-0.06,-0.03 L1.87,0.48 L2.00,-0.50 L0.00,-0.50 z' ) ) p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(2) p.turn_right(165) p.line_forward(2) assert_path_data( p, 2, ( 'M0.00,-0.50 L0.00,0.50 L2.00,0.50 L1.87,-0.48 ' 'L-0.06,0.03 L0.20,1.00 L5.80,-0.50 L0.00,-0.50 z' ) )
def test_joint_loop_color(): p = Pen() p.move_to((0, 0)) p.turn_to(0) # Draw a square with one side a different color. It joins to the # beginning correctly. p.stroke_mode(2.0, color='black') p.line_forward(5) p.turn_left(90) p.line_forward(5) p.turn_left(90) p.line_forward(5) p.turn_left(90) p.stroke_mode(2.0, color='red') p.line_forward(5) assert_equal(len(p.paper.paths), 1) assert_path_data( p, 0, [ 'M1,-1 L-1,1 L6,1 L6,-6 L-1,-6 L1,-4 L4,-4 L4,-1 L1,-1 z', 'M1,-4 L-1,-6 L-1,1 L1,-1 L1,-4 z', ] )
def draw(offset): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(0.5 + offset, end_slant=45) return p
def test_straight_joint_headings(): # The math in calculating joint geometry can get numerically unstable # very close to straight joints at various headings. for heading_angle in range(0, 45): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(heading_angle) p.line_forward(10) p.line_forward(10) path = p.paper.paths[0] path.render_path(2) # Doesn't crash. # Check that the joint angle is 90 degrees from the heading. assert_equal(len(p.paper.paths), 1) segments = p.paper.paths[0].segments assert_equal(len(segments), 2) s0, s1 = segments target_angle = (heading_angle + 90) % 180 joint_angle = math.degrees(vec.heading(vec.vfrom(s0.b_right, s0.b_left))) assert_almost_equal(joint_angle % 180, target_angle) joint_angle = math.degrees(vec.heading(vec.vfrom(s1.a_right, s1.a_left))) assert_almost_equal(joint_angle % 180, target_angle)
def test_color_formats(): for color, output in [ ( (1.0, 0.0, 0.0), '#ff0000', ), ( Color.from_html('red'), '#ff0000', ), ( 'green', '#008000', ), ( '#123456', '#123456', ), ]: p = Pen() p.stroke_mode(2.0, color) p.move_to((0, 0)) p.turn_to(0) p.line_forward(5) assert_equal( p.paper.svg_elements(0)[0], '<path d="M0,-1 L0,1 L5,1 L5,-1 L0,-1 z" fill="{}" />'.format(output) )
def test_joint_loop_multiple(): p = Pen() p.stroke_mode(0.2) def square(): p.turn_to(180) p.line_forward(1) p.turn_left(90) p.line_forward(1) p.turn_left(90) p.line_forward(1) p.turn_left(90) p.line_forward(1) p.move_to((0, 0)) square() p.move_to((2, 0)) square() assert_path_data( p, 1, ( 'M0.1,-0.1 L-1.1,-0.1 L-1.1,1.1 L0.1,1.1 L0.1,-0.1 z ' 'M-0.1,0.1 L-0.1,0.9 L-0.9,0.9 L-0.9,0.1 L-0.1,0.1 z ' 'M2.1,-0.1 L0.9,-0.1 L0.9,1.1 L2.1,1.1 L2.1,-0.1 z ' 'M1.9,0.1 L1.9,0.9 L1.1,0.9 L1.1,0.1 L1.9,0.1 z' ) )
def test_arc_line_half_illegal_joint(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.line_to((1, 0)) p.turn_to(180 - 15) p.arc_to((-1, 0)) line, arc = p.last_path().segments assert line.end_joint_illegal assert arc.start_joint_illegal assert_path_data(p, 2, ('M0.00,-0.50 L0.00,0.50 L2.93,0.50 ' 'A 4.36,4.36 0 0 0 -1.13,-0.48 L-0.87,0.48 ' 'A 3.36,3.36 0 0 1 0.87,0.48 L1.00,-0.50 L0.00,-0.50 z')) p = Pen() p.stroke_mode(1.0) p.move_to((-1, 0)) p.turn_to(15) p.arc_to((1, 0)) p.line_to((0, 0)) arc, line = p.paper.paths[0].segments assert arc.end_joint_illegal assert line.start_joint_illegal assert_path_data(p, 2, ('M-1.13,-0.48 L-0.87,0.48 A 3.36,3.36 0 0 1 0.87,0.48 ' 'L1.00,-0.50 L0.00,-0.50 L0.00,0.50 L2.93,0.50 ' 'A 4.36,4.36 0 0 0 -1.13,-0.48 z'))
def test_circle_line_overlap(): # Draw a circle that is above one line but below the other line. p = Pen() p.stroke_mode(1.0, color=(1.0, 0.0, 0.0)) p.move_to((0, 0)) p.turn_to(0) p.line_forward(4) p.fill_mode(color=(0.0, 1.0, 0.0)) p.move_to((2, 2)) p.circle(2) p.stroke_mode(1.0, color=(0.0, 0.0, 1.0)) p.move_to((0, 4)) p.turn_to(0) p.line_forward(4) assert_equal( p.paper.svg_elements(1), [ ( '<path d="M0.0,-0.5 L0.0,0.5 L4.0,0.5 L4.0,-0.5 L0.0,-0.5 z" ' 'fill="#ff0000" />' ), ( '<path d="M4.0,-2.0 A 2.0,2.0 0 0 0 0.0,-2.0 ' 'A 2.0,2.0 0 0 0 4.0,-2.0 z" fill="#00ff00" />' ), ( '<path d="M0.0,-4.5 L0.0,-3.5 L4.0,-3.5 L4.0,-4.5 L0.0,-4.5 z" ' 'fill="#0000ff" />' ), ] )
def test_line_line_half_illegal_joint(): # The outside edge meets, but the inside is too short to meet. p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(2) p.turn_left(165) p.line_forward(2) assert_path_data(p, 2, ('M0.00,-0.50 L0.00,0.50 L5.80,0.50 L0.20,-1.00 ' 'L-0.06,-0.03 L1.87,0.48 L2.00,-0.50 L0.00,-0.50 z')) p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(2) p.turn_right(165) p.line_forward(2) assert_path_data(p, 2, ('M0.00,-0.50 L0.00,0.50 L2.00,0.50 L1.87,-0.48 ' 'L-0.06,0.03 L0.20,1.00 L5.80,-0.50 L0.00,-0.50 z'))
def test_color_formats(): for color, output in [ ( (1.0, 0.0, 0.0), '#ff0000', ), ( Color.NewFromHtml('red'), '#ff0000', ), ( 'green', '#008000', ), ( '#123456', '#123456', ), ]: p = Pen() p.stroke_mode(2.0, color) p.move_to((0, 0)) p.turn_to(0) p.line_forward(5) assert_equal( p.paper.svg_elements(0)[0], '<path d="M0,-1 L0,1 L5,1 L5,-1 L0,-1 z" fill="{}" />'.format(output) )
def test_custom_cap(): def circle_cap(pen, end): pen.arc_to(end) p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(5) p.last_segment().end_cap = circle_cap assert_path_data( p, 0, 'M0,-1 L0,1 L5,1 A 1,1 0 0 0 5,-1 L0,-1 z' ) p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(5) p.last_segment().start_cap = circle_cap assert_path_data( p, 0, 'M0,-1 A 1,1 0 1 0 0,1 L5,1 L5,-1 L0,-1 z' )
def test_circle_degenerate(): p = Pen() p.stroke_mode(2.0) p.circle(1) assert_equal( p.paper.svg_elements(0), ['<path d="M2,0 A 2,2 0 0 0 -2,0 A 2,2 0 0 0 2,0 z" fill="#000000" />'] )
def test_arc_joint_numerical(): # Sometimes arc joints can miss the mark if they have odd float numbers. p = Pen() p.stroke_mode(0.5) p.move_to((-26.685559703113075, 65.00539003547281)) p.turn_to(202.85281173472714) p.arc_right(180, 1) # This shouldn't error: p.arc_right(50.443252846269075, center=(0.5, 0.5))
def test_straight_joint(): p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(3) p.line_forward(3) assert_path_data( p, 0, 'M0,-1 L0,1 L3,1 L6,1 L6,-1 L3,-1 L0,-1 z' )
def test_arc_sweep_bug(): p = Pen() p.stroke_mode(2.0) p.move_to((3, 0)) p.turn_to(90) p.arc_left(270, 3) assert_path_data( p, 0, 'M2,0 L4,0 A 4,4 0 1 0 0,4 L0,2 A 2,2 0 1 1 2,0 z' )
def test_arc_zero(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) # Zero-angle and zero-radius arcs have zero length, so they are not added. p.arc_left(0, radius=1) assert_equal(p.paper.paths, []) p.arc_left(90, radius=0) assert_equal(p.paper.paths, [])
def test_zero_length_side(): # It is possible and legal to create a segment that just barely goes to # zero on one side. p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(1.0, end_slant=45) assert_path_data( p, 0, 'M0,-1 L0,1 L2,-1 L0,-1 z', )
def test_arc_pie_slice(): # Draw a "pie slice" arc that is wide enough to reach all the way to the # arc center. p = Pen() p.stroke_mode(1.0) p.move_to((0.5, 0)) p.turn_to(90) p.arc_left(90, 0.5) assert_path_data( p, 0, 'M0,0 L1,0 A 1,1 0 0 0 0,-1 L0,0 z' )
def test_offwidth_arc_joins(): # Join arcs and lines of different widths. p = Pen() p.move_to((0, 0)) p.turn_to(0) p.stroke_mode(0.8) p.line_forward(5) p.turn_left(45) p.stroke_mode(3.0) p.arc_left(90, 5) p.turn_to(-180) p.line_forward(5) p.turn_left(45) p.stroke_mode(0.8) p.arc_left(45, 5) p.turn_right(90) p.stroke_mode(3.0) p.arc_right(90, 4) assert_svg_file( p, 3, 'test_offwidth_arc_joins.svg' )
def test_arc_angle(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.arc_left(90, radius=5, start_slant=45, end_slant=45) assert_path_data( p, 2, ( 'M0.53,-0.53 L-0.48,0.48 A 5.50,5.50 0 0 0 5.48,-5.48 ' 'L4.47,-4.47 A 4.50,4.50 0 0 1 0.53,-0.53 z' ), )
def test_arc_angle_error(): # Endpoints with certain angles do not go all the way across the # stroke, and are disallowed. p = Pen() p.stroke_mode(1.0) p.arc_left(90, 10, start_slant=0) seg = p.last_segment() assert seg.start_joint_illegal assert not seg.end_joint_illegal p = Pen() p.stroke_mode(1.0) p.arc_left(90, 10, end_slant=90) seg = p.last_segment() assert not seg.start_joint_illegal assert seg.end_joint_illegal p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.arc_left(90, radius=5, start_slant=25) seg = p.last_segment() assert seg.start_joint_illegal assert not seg.end_joint_illegal # A combination of angles can also create a degenerate arc. p = Pen() p.stroke_mode(1.0) p.turn_toward((1, 0)) p.turn_left(1) p.arc_to((1, 0), start_slant=40, end_slant=-40) seg = p.last_segment() assert seg.start_joint_illegal assert seg.end_joint_illegal
def test_degenerate_arc(): p = Pen() p.stroke_mode(2.0) p.move_to((-5, 0)) p.turn_to(0) p.arc_to( (5, 0), center=(0, -200), start_slant=-5, end_slant=5, ) seg = p.last_segment() assert seg.start_joint_illegal assert seg.end_joint_illegal
def test_long_line_thick(): p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) for _ in range(2): p.line_forward(5) p.turn_right(90) p.line_forward(5) p.turn_left(90) assert_path_data( p, 0, 'M0,-1 L0,1 L4,1 L4,6 L9,6 L9,10 L11,10 L11,4 L6,4 L6,-1 L0,-1 z' )
def test_break_stroke(): p = Pen() p.stroke_mode(2.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(3) p.break_stroke() p.line_forward(3) assert_path_data( p, 0, [ 'M0,-1 L0,1 L3,1 L3,-1 L0,-1 z', 'M3,-1 L3,1 L6,1 L6,-1 L3,-1 z', ] )
def test_joint(): p = Pen() p.stroke_mode(1.0) p.move_to((-6, 0)) p.turn_to(0) p.line_forward(6) p.turn_right(60) p.line_forward(6) assert_path_data( p, 2, ( 'M-6.00,-0.50 L-6.00,0.50 L-0.29,0.50 L2.57,5.45 ' 'L3.43,4.95 L0.29,-0.50 L-6.00,-0.50 z' ), )
def test_straight_offwidth_no_joint(): p = Pen() p.move_to((0, 0)) p.turn_to(0) p.stroke_mode(2.0) p.line_forward(3) p.stroke_mode(1.0) p.line_forward(3) line1, line2 = p.last_path().segments assert line1.end_joint_illegal assert line2.start_joint_illegal assert_path_data(p, 1, ('M0.0,-1.0 L0.0,1.0 L3.0,1.0 L3.0,0.5 L6.0,0.5 ' 'L6.0,-0.5 L3.0,-0.5 L3.0,-1.0 L0.0,-1.0 z'))
def test_multiple_strokes(): p = Pen() p.stroke_mode(1.0) p.turn_to(0) p.move_to((0, 0)) p.line_forward(3) p.move_to((0, 3)) p.line_forward(3) assert_path_data( p, 1, ( 'M0.0,-0.5 L0.0,0.5 L3.0,0.5 L3.0,-0.5 L0.0,-0.5 z ' 'M0.0,-3.5 L0.0,-2.5 L3.0,-2.5 L3.0,-3.5 L0.0,-3.5 z' ) )
def test_offwidth_joint(): p = Pen() p.stroke_mode(1.0) p.turn_to(0) p.move_forward(-3) p.line_forward(3) p.stroke_mode(0.5) p.turn_left(90) p.line_forward(3) assert_path_data( p, 2, ( 'M-3.00,-0.50 L-3.00,0.50 L0.25,0.50 L0.25,-3.00 ' 'L-0.25,-3.00 L-0.25,-0.50 L-3.00,-0.50 z' ), )
def test_turn_back_no_joint(): # Make a line turn back on itself, and it doesn't join. p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(10) p.turn_right(180) p.line_forward(5) line1, line2 = p.last_path().segments assert line1.end_joint_illegal assert line2.start_joint_illegal assert_path_data(p, 1, ('M0.0,-0.5 L0.0,0.5 L10.0,0.5 L10.0,-0.5 ' 'L5.0,-0.5 L5.0,0.5 L10.0,0.5 L10.0,-0.5 L0.0,-0.5 z'))
def test_change_mode(): # Change mode but don't change colors. It starts a new path. p = Pen() p.move_to((0, 0)) p.turn_to(0) p.stroke_mode(2.0, 'black') p.line_forward(5) p.fill_mode('black') p.line_forward(5) assert_equal( p.paper.svg_elements(0), [ '<path d="M0,-1 L0,1 L5,1 L5,-1 L0,-1 z" fill="#000000" />', '<path d="M5,0 L10,0" fill="#000000" />', ] )
def test_arc_line_joint(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.line_forward(3) p.turn_left(90) p.arc_left(180, 3) assert_path_data( p, 3, ( 'M0.000,-0.500 L0.000,0.500 L3.464,0.500 ' 'A 3.500,3.500 0 1 0 -3.500,0.000 L-2.500,0.000 ' 'A 2.500,2.500 0 0 1 2.449,-0.500 L0.000,-0.500 z' ), )
def test_save_mode(): p = Pen() p.stroke_mode(2.0, 'red') old_mode = p.mode p.line_forward(5) p.fill_mode('blue') p.square(2) p.set_mode(old_mode) p.line_forward(5) assert_path_data( p, 0, [ 'M0,-1 L0,1 L5,1 L5,-1 L0,-1 z', 'M4,1 L6,1 L6,-1 L4,-1 L4,1 z', 'M5,-1 L5,1 L10,1 L10,-1 L5,-1 z', ] )
def test_color_joint(): p = Pen() p.stroke_mode(1.0, 'red') p.move_to((-6, 0)) p.turn_to(0) p.line_forward(6) p.stroke_mode(1.0, 'green') p.turn_right(60) p.line_forward(6) assert_path_data( p, 2, [ 'M-6.00,-0.50 L-6.00,0.50 L-0.29,0.50 L0.29,-0.50 L-6.00,-0.50 z', 'M0.29,-0.50 L-0.29,0.50 L2.57,5.45 L3.43,4.95 L0.29,-0.50 z', ] )
def test_arc_arc_joint_off_radius(): p = Pen() p.stroke_mode(1.0) p.move_to((0, 0)) p.turn_to(0) p.arc_left(180, 1) p.arc_left(90, 2) assert_path_data( p, 1, ( 'M0.0,-0.5 L0.0,0.5 ' 'A 1.5,1.5 0 0 0 0.0,-2.5 ' 'A 2.5,2.5 0 0 0 -2.5,0.0 ' 'L-1.5,0.0 ' 'A 1.5,1.5 0 0 1 0.0,-1.5 ' 'A 0.5,0.5 0 0 1 0.0,-0.5 z' ) )