Ejemplo n.º 1
0
    def test_equality(self):
        # This is to test the __eq__ and __ne__ methods, so we can't use
        # assertEqual and assertNotEqual
        path1 = Path(
            Line(start=600 + 350j, end=650 + 325j),
            Arc(start=650 + 325j, radius=25 + 25j, rotation=-30, arc=0, sweep=1, end=700 + 300j),
            CubicBezier(start=700 + 300j, control1=800 + 400j, control2=750 + 200j, end=600 + 100j),
            QuadraticBezier(start=600 + 100j, control=600, end=600 + 300j))
        path2 = Path(
            Line(start=600 + 350j, end=650 + 325j),
            Arc(start=650 + 325j, radius=25 + 25j, rotation=-30, arc=0, sweep=1, end=700 + 300j),
            CubicBezier(start=700 + 300j, control1=800 + 400j, control2=750 + 200j, end=600 + 100j),
            QuadraticBezier(start=600 + 100j, control=600, end=600 + 300j))

        self.assertTrue(path1 == path2)
        # Modify path2:
        path2[0].start = 601 + 350j
        self.assertTrue(path1 != path2)

        # Modify back:
        path2[0].start = 600 + 350j
        self.assertFalse(path1 != path2)

        # Get rid of the last segment:
        del path2[-1]
        self.assertFalse(path1 == path2)

        # It's not equal to a list of it's segments
        self.assertTrue(path1 != path1[:])
        self.assertFalse(path1 == path1[:])
Ejemplo n.º 2
0
    def test_length(self):

        # A straight line:
        arc = CubicBezier(complex(0, 0), complex(0, 0), complex(0, 100),
                          complex(0, 100))

        self.assertAlmostEqual(arc.length(), 100)

        # A diagonal line:
        arc = CubicBezier(complex(0, 0), complex(0, 0), complex(100, 100),
                          complex(100, 100))

        self.assertAlmostEqual(arc.length(), sqrt(2 * 100 * 100))

        # A quarter circle arc with radius 100:
        kappa = 4 * (
            sqrt(2) -
            1) / 3  # http://www.whizkidtech.redprince.net/bezier/circle/

        arc = CubicBezier(complex(0, 0), complex(0, kappa * 100),
                          complex(100 - kappa * 100, 100), complex(100, 100))

        # We can't compare with pi*50 here, because this is just an
        # approximation of a circle arc. pi*50 is 157.079632679
        # So this is just yet another "warn if this changes" test.
        # This value is not to be seens as verified as correct.
        self.assertAlmostEqual(arc.length(), 157.1016698)
Ejemplo n.º 3
0
    def test_equality(self):
        # This is to test the __eq__ and __ne__ methods, so we can't use
        # assertEqual and assertNotEqual
        segment = CubicBezier(complex(600, 500), complex(600, 350),
                              complex(900, 650), complex(900, 500))

        self.assertTrue(segment ==
                        CubicBezier(600 + 500j, 600 + 350j, 900 + 650j, 900 + 500j))
        self.assertTrue(segment !=
                        CubicBezier(600 + 501j, 600 + 350j, 900 + 650j, 900 + 500j))
        self.assertTrue(segment != Line(0, 400))
Ejemplo n.º 4
0
 def test_repr(self):
     from path import Point
     path = Path(
         Line(start=600 + 350j, end=650 + 325j),
         Arc(start=650 + 325j, radius=25 + 25j, rotation=-30, arc=0, sweep=1, end=700 + 300j),
         CubicBezier(start=700 + 300j, control1=800 + 400j, control2=750 + 200j, end=600 + 100j),
         QuadraticBezier(start=600 + 100j, control=600, end=600 + 300j))
     self.assertEqual(eval(repr(path)), path)
Ejemplo n.º 5
0
 def test_equality(self):
     # This is to test the __eq__ and __ne__ methods, so we can't use
     # assertEqual and assertNotEqual
     line = Line(0j, 400 + 0j)
     self.assertTrue(line == Line(0, 400))
     self.assertTrue(line != Line(100, 400))
     self.assertFalse(line == str(line))
     self.assertTrue(line != str(line))
     self.assertFalse(CubicBezier(600 + 500j, 600 + 350j, 900 + 650j, 900 + 500j) ==
                      line)
Ejemplo n.º 6
0
    def test_approx_circle(self):
        """This is a approximate circle drawn in Inkscape"""

        arc1 = CubicBezier(
            complex(0, 0),
            complex(0, 109.66797),
            complex(-88.90345, 198.57142),
            complex(-198.57142, 198.57142)
        )

        self.assertAlmostEqual(arc1.point(0), (0j))
        self.assertAlmostEqual(arc1.point(0.1), (-2.59896457 + 32.20931647j))
        self.assertAlmostEqual(arc1.point(0.2), (-10.12330256 + 62.76392816j))
        self.assertAlmostEqual(arc1.point(0.3), (-22.16418039 + 91.25500149j))
        self.assertAlmostEqual(arc1.point(0.4), (-38.31276448 + 117.27370288j))
        self.assertAlmostEqual(arc1.point(0.5), (-58.16022125 + 140.41119875j))
        self.assertAlmostEqual(arc1.point(0.6), (-81.29771712 + 160.25865552j))
        self.assertAlmostEqual(arc1.point(0.7), (-107.31641851 + 176.40723961j))
        self.assertAlmostEqual(arc1.point(0.8), (-135.80749184 + 188.44811744j))
        self.assertAlmostEqual(arc1.point(0.9), (-166.36210353 + 195.97245543j))
        self.assertAlmostEqual(arc1.point(1), (-198.57142 + 198.57142j))

        arc2 = CubicBezier(
            complex(-198.57142, 198.57142),
            complex(-109.66797 - 198.57142, 0 + 198.57142),
            complex(-198.57143 - 198.57142, -88.90345 + 198.57142),
            complex(-198.57143 - 198.57142, 0),
        )

        self.assertAlmostEqual(arc2.point(0), (-198.57142 + 198.57142j))
        self.assertAlmostEqual(arc2.point(0.1), (-230.78073675 + 195.97245543j))
        self.assertAlmostEqual(arc2.point(0.2), (-261.3353492 + 188.44811744j))
        self.assertAlmostEqual(arc2.point(0.3), (-289.82642365 + 176.40723961j))
        self.assertAlmostEqual(arc2.point(0.4), (-315.8451264 + 160.25865552j))
        self.assertAlmostEqual(arc2.point(0.5), (-338.98262375 + 140.41119875j))
        self.assertAlmostEqual(arc2.point(0.6), (-358.830082 + 117.27370288j))
        self.assertAlmostEqual(arc2.point(0.7), (-374.97866745 + 91.25500149j))
        self.assertAlmostEqual(arc2.point(0.8), (-387.0195464 + 62.76392816j))
        self.assertAlmostEqual(arc2.point(0.9), (-394.54388515 + 32.20931647j))
        self.assertAlmostEqual(arc2.point(1), (-397.14285 + 0j))

        arc3 = CubicBezier(
            complex(-198.57143 - 198.57142, 0),
            complex(0 - 198.57143 - 198.57142, -109.66797),
            complex(88.90346 - 198.57143 - 198.57142, -198.57143),
            complex(-198.57142, -198.57143)
        )

        self.assertAlmostEqual(arc3.point(0), (-397.14285 + 0j))
        self.assertAlmostEqual(arc3.point(0.1), (-394.54388515 - 32.20931675j))
        self.assertAlmostEqual(arc3.point(0.2), (-387.0195464 - 62.7639292j))
        self.assertAlmostEqual(arc3.point(0.3), (-374.97866745 - 91.25500365j))
        self.assertAlmostEqual(arc3.point(0.4), (-358.830082 - 117.2737064j))
        self.assertAlmostEqual(arc3.point(0.5), (-338.98262375 - 140.41120375j))
        self.assertAlmostEqual(arc3.point(0.6), (-315.8451264 - 160.258662j))
        self.assertAlmostEqual(arc3.point(0.7), (-289.82642365 - 176.40724745j))
        self.assertAlmostEqual(arc3.point(0.8), (-261.3353492 - 188.4481264j))
        self.assertAlmostEqual(arc3.point(0.9), (-230.78073675 - 195.97246515j))
        self.assertAlmostEqual(arc3.point(1), (-198.57142 - 198.57143j))

        arc4 = CubicBezier(
            complex(-198.57142, -198.57143),
            complex(109.66797 - 198.57142, 0 - 198.57143),
            complex(0, 88.90346 - 198.57143),
            complex(0, 0),
        )

        self.assertAlmostEqual(arc4.point(0), (-198.57142 - 198.57143j))
        self.assertAlmostEqual(arc4.point(0.1), (-166.36210353 - 195.97246515j))
        self.assertAlmostEqual(arc4.point(0.2), (-135.80749184 - 188.4481264j))
        self.assertAlmostEqual(arc4.point(0.3), (-107.31641851 - 176.40724745j))
        self.assertAlmostEqual(arc4.point(0.4), (-81.29771712 - 160.258662j))
        self.assertAlmostEqual(arc4.point(0.5), (-58.16022125 - 140.41120375j))
        self.assertAlmostEqual(arc4.point(0.6), (-38.31276448 - 117.2737064j))
        self.assertAlmostEqual(arc4.point(0.7), (-22.16418039 - 91.25500365j))
        self.assertAlmostEqual(arc4.point(0.8), (-10.12330256 - 62.7639292j))
        self.assertAlmostEqual(arc4.point(0.9), (-2.59896457 - 32.20931675j))
        self.assertAlmostEqual(arc4.point(1), (0j))
Ejemplo n.º 7
0
    def test_length(self):
        # A straight line:
        arc = CubicBezier(
            complex(0, 0),
            complex(0, 0),
            complex(0, 100),
            complex(0, 100)
        )

        self.assertAlmostEqual(arc.length(), 100)

        # A diagonal line:
        arc = CubicBezier(
            complex(0, 0),
            complex(0, 0),
            complex(100, 100),
            complex(100, 100)
        )

        self.assertAlmostEqual(arc.length(), sqrt(2 * 100 * 100))

        # A quarter circle arc with radius 100:
        kappa = 4 * (sqrt(2) - 1) / 3  # http://www.whizkidtech.redprince.net/bezier/circle/

        arc = CubicBezier(
            complex(0, 0),
            complex(0, kappa * 100),
            complex(100 - kappa * 100, 100),
            complex(100, 100)
        )

        # We can't compare with pi*50 here, because this is just an
        # approximation of a circle arc. pi*50 is 157.079632679
        # So this is just yet another "warn if this changes" test.
        # This value is not verified to be correct.
        self.assertAlmostEqual(arc.length(), 157.1016698)

        # A recursive solution has also been suggested, but for CubicBezier
        # curves it could get a false solution on curves where the midpoint is on a
        # straight line between the start and end. For example, the following
        # curve would get solved as a straight line and get the length 300.
        # Make sure this is not the case.
        arc = CubicBezier(
            complex(600, 500),
            complex(600, 350),
            complex(900, 650),
            complex(900, 500)
        )
        self.assertTrue(arc.length() > 300.0)
Ejemplo n.º 8
0
    def test_svg_examples(self):
        # M100,200 C100,100 250,100 250,200
        path1 = CubicBezier(100 + 200j, 100 + 100j, 250 + 100j, 250 + 200j)
        self.assertAlmostEqual(path1.point(0), (100 + 200j))
        self.assertAlmostEqual(path1.point(0.3), (132.4 + 137j))
        self.assertAlmostEqual(path1.point(0.5), (175 + 125j))
        self.assertAlmostEqual(path1.point(0.9), (245.8 + 173j))
        self.assertAlmostEqual(path1.point(1), (250 + 200j))

        # S400,300 400,200
        path2 = CubicBezier(250 + 200j, 250 + 300j, 400 + 300j, 400 + 200j)
        self.assertAlmostEqual(path2.point(0), (250 + 200j))
        self.assertAlmostEqual(path2.point(0.3), (282.4 + 263j))
        self.assertAlmostEqual(path2.point(0.5), (325 + 275j))
        self.assertAlmostEqual(path2.point(0.9), (395.8 + 227j))
        self.assertAlmostEqual(path2.point(1), (400 + 200j))

        # M100,200 C100,100 400,100 400,200
        path3 = CubicBezier(100 + 200j, 100 + 100j, 400 + 100j, 400 + 200j)
        self.assertAlmostEqual(path3.point(0), (100 + 200j))
        self.assertAlmostEqual(path3.point(0.3), (164.8 + 137j))
        self.assertAlmostEqual(path3.point(0.5), (250 + 125j))
        self.assertAlmostEqual(path3.point(0.9), (391.6 + 173j))
        self.assertAlmostEqual(path3.point(1), (400 + 200j))

        # M100,500 C25,400 475,400 400,500
        path4 = CubicBezier(100 + 500j, 25 + 400j, 475 + 400j, 400 + 500j)
        self.assertAlmostEqual(path4.point(0), (100 + 500j))
        self.assertAlmostEqual(path4.point(0.3), (145.9 + 437j))
        self.assertAlmostEqual(path4.point(0.5), (250 + 425j))
        self.assertAlmostEqual(path4.point(0.9), (407.8 + 473j))
        self.assertAlmostEqual(path4.point(1), (400 + 500j))

        # M100,800 C175,700 325,700 400,800
        path5 = CubicBezier(100 + 800j, 175 + 700j, 325 + 700j, 400 + 800j)
        self.assertAlmostEqual(path5.point(0), (100 + 800j))
        self.assertAlmostEqual(path5.point(0.3), (183.7 + 737j))
        self.assertAlmostEqual(path5.point(0.5), (250 + 725j))
        self.assertAlmostEqual(path5.point(0.9), (375.4 + 773j))
        self.assertAlmostEqual(path5.point(1), (400 + 800j))

        # M600,200 C675,100 975,100 900,200
        path6 = CubicBezier(600 + 200j, 675 + 100j, 975 + 100j, 900 + 200j)
        self.assertAlmostEqual(path6.point(0), (600 + 200j))
        self.assertAlmostEqual(path6.point(0.3), (712.05 + 137j))
        self.assertAlmostEqual(path6.point(0.5), (806.25 + 125j))
        self.assertAlmostEqual(path6.point(0.9), (911.85 + 173j))
        self.assertAlmostEqual(path6.point(1), (900 + 200j))

        # M600,500 C600,350 900,650 900,500
        path7 = CubicBezier(600 + 500j, 600 + 350j, 900 + 650j, 900 + 500j)
        self.assertAlmostEqual(path7.point(0), (600 + 500j))
        self.assertAlmostEqual(path7.point(0.3), (664.8 + 462.2j))
        self.assertAlmostEqual(path7.point(0.5), (750 + 500j))
        self.assertAlmostEqual(path7.point(0.9), (891.6 + 532.4j))
        self.assertAlmostEqual(path7.point(1), (900 + 500j))

        # M600,800 C625,700 725,700 750,800
        path8 = CubicBezier(600 + 800j, 625 + 700j, 725 + 700j, 750 + 800j)
        self.assertAlmostEqual(path8.point(0), (600 + 800j))
        self.assertAlmostEqual(path8.point(0.3), (638.7 + 737j))
        self.assertAlmostEqual(path8.point(0.5), (675 + 725j))
        self.assertAlmostEqual(path8.point(0.9), (740.4 + 773j))
        self.assertAlmostEqual(path8.point(1), (750 + 800j))

        # S875,900 900,800
        inversion = (750 + 800j) + (750 + 800j) - (725 + 700j)
        path9 = CubicBezier(750 + 800j, inversion, 875 + 900j, 900 + 800j)
        self.assertAlmostEqual(path9.point(0), (750 + 800j))
        self.assertAlmostEqual(path9.point(0.3), (788.7 + 863j))
        self.assertAlmostEqual(path9.point(0.5), (825 + 875j))
        self.assertAlmostEqual(path9.point(0.9), (890.4 + 827j))
        self.assertAlmostEqual(path9.point(1), (900 + 800j))
Ejemplo n.º 9
0
def parse_path(pathdef, current_pos=0j):
    # In the SVG specs, initial movetos are absolute, even if
    # specified as 'm'. This is the default behavior here as well.
    # But if you pass in a current_pos variable, the initial moveto
    # will be relative to that current_pos. This is useful.
    elements = list(_tokenize_path(pathdef))
    # Reverse for easy use of .pop()
    elements.reverse()

    segments = Path()
    start_pos = None
    command = None

    while elements:

        if elements[-1] in COMMANDS:
            # New command.
            last_command = command  # Used by S and T
            command = elements.pop()
            absolute = command in UPPERCASE
            command = command.upper()
        else:
            # If this element starts with numbers, it is an implicit command
            # and we don't change the command. Check that it's allowed:
            if command is None:
                raise ValueError("Unallowed implicit command in %s, position %s" % (
                    pathdef, len(pathdef.split()) - len(elements)))

        if command == 'M':
            # Moveto command.
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if absolute:
                current_pos = pos
            else:
                current_pos += pos

            # when M is called, reset start_pos
            # This behavior of Z is defined in svg spec:
            # http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
            start_pos = current_pos

            # Implicit moveto commands are treated as lineto commands.
            # So we set command to lineto here, in case there are
            # further implicit commands after this moveto.
            command = 'L'

        elif command == 'Z':
            # Close path
            if not (current_pos == start_pos):
                segments.append(Line(current_pos, start_pos))
            segments.closed = True
            current_pos = start_pos
            start_pos = None
            command = None  # You can't have implicit commands after closing.

        elif command == 'L':
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if not absolute:
                pos += current_pos
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'H':
            x = elements.pop()
            pos = float(x) + current_pos.imag * 1j
            if not absolute:
                pos += current_pos.real
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'V':
            y = elements.pop()
            pos = current_pos.real + float(y) * 1j
            if not absolute:
                pos += current_pos.imag * 1j
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'C':
            control1 = float(elements.pop()) + float(elements.pop()) * 1j
            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control1 += current_pos
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'S':
            # Smooth curve. First control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'CS':
                # If there is no previous command or if the previous command
                # was not an C, c, S or s, assume the first control point is
                # coincident with the current point.
                control1 = current_pos
            else:
                # The first control point is assumed to be the reflection of
                # the second control point on the previous command relative
                # to the current point.
                control1 = current_pos + current_pos - segments[-1].control2

            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'Q':
            control = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control += current_pos
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'T':
            # Smooth curve. Control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'QT':
                # If there is no previous command or if the previous command
                # was not an Q, q, T or t, assume the first control point is
                # coincident with the current point.
                control = current_pos
            else:
                # The control point is assumed to be the reflection of
                # the control point on the previous command relative
                # to the current point.
                control = current_pos + current_pos - segments[-1].control

            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'A':
            radius = float(elements.pop()) + float(elements.pop()) * 1j
            rotation = float(elements.pop())
            arc = float(elements.pop())
            sweep = float(elements.pop())
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(Arc(current_pos, radius, rotation, arc, sweep, end))
            current_pos = end

    return segments
Ejemplo n.º 10
0
    def test_svg_examples(self):
        """Examples from the SVG spec"""
        path1 = parse_path('M 100 100 L 300 100 L 200 300 z')
        self.assertEqual(
            path1,
            Path(Line(100 + 100j, 300 + 100j), Line(300 + 100j, 200 + 300j),
                 Line(200 + 300j, 100 + 100j)))

        path1 = parse_path('M 100 100 L 200 200')
        path2 = parse_path('M100 100L200 200')
        self.assertEqual(path1, path2)

        path1 = parse_path('M 100 200 L 200 100 L -100 -200')
        path2 = parse_path('M 100 200 L 200 100 -100 -200')
        self.assertEqual(path1, path2)

        path1 = parse_path("""M100,200 C100,100 250,100 250,200
                              S400,300 400,200""")
        self.assertEqual(
            path1,
            Path(CubicBezier(100 + 200j, 100 + 100j, 250 + 100j, 250 + 200j),
                 CubicBezier(250 + 200j, 250 + 300j, 400 + 300j, 400 + 200j)))

        path1 = parse_path('M100,200 C100,100 400,100 400,200')
        self.assertEqual(
            path1,
            Path(CubicBezier(100 + 200j, 100 + 100j, 400 + 100j, 400 + 200j)))

        path1 = parse_path('M100,500 C25,400 475,400 400,500')
        self.assertEqual(
            path1,
            Path(CubicBezier(100 + 500j, 25 + 400j, 475 + 400j, 400 + 500j)))

        path1 = parse_path('M100,800 C175,700 325,700 400,800')
        self.assertEqual(
            path1,
            Path(CubicBezier(100 + 800j, 175 + 700j, 325 + 700j, 400 + 800j)))

        path1 = parse_path('M600,200 C675,100 975,100 900,200')
        self.assertEqual(
            path1,
            Path(CubicBezier(600 + 200j, 675 + 100j, 975 + 100j, 900 + 200j)))

        path1 = parse_path('M600,500 C600,350 900,650 900,500')
        self.assertEqual(
            path1,
            Path(CubicBezier(600 + 500j, 600 + 350j, 900 + 650j, 900 + 500j)))

        path1 = parse_path("""M600,800 C625,700 725,700 750,800
                              S875,900 900,800""")
        self.assertEqual(
            path1,
            Path(CubicBezier(600 + 800j, 625 + 700j, 725 + 700j, 750 + 800j),
                 CubicBezier(750 + 800j, 775 + 900j, 875 + 900j, 900 + 800j)))

        path1 = parse_path('M200,300 Q400,50 600,300 T1000,300')
        self.assertEqual(
            path1,
            Path(QuadraticBezier(200 + 300j, 400 + 50j, 600 + 300j),
                 QuadraticBezier(600 + 300j, 800 + 550j, 1000 + 300j)))

        path1 = parse_path('M300,200 h-150 a150,150 0 1,0 150,-150 z')
        self.assertEqual(
            path1,
            Path(Line(300 + 200j, 150 + 200j),
                 Arc(150 + 200j, 150 + 150j, 0, 1, 0, 300 + 50j),
                 Line(300 + 50j, 300 + 200j)))

        path1 = parse_path('M275,175 v-150 a150,150 0 0,0 -150,150 z')
        self.assertEqual(
            path1,
            Path(Line(275 + 175j, 275 + 25j),
                 Arc(275 + 25j, 150 + 150j, 0, 0, 0, 125 + 175j),
                 Line(125 + 175j, 275 + 175j)))

        path1 = parse_path("""M600,350 l 50,-25 
                              a25,25 -30 0,1 50,-25 l 50,-25 
                              a25,50 -30 0,1 50,-25 l 50,-25 
                              a25,75 -30 0,1 50,-25 l 50,-25 
                              a25,100 -30 0,1 50,-25 l 50,-25""")
        self.assertEqual(
            path1,
            Path(Line(600 + 350j, 650 + 325j),
                 Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j),
                 Line(700 + 300j, 750 + 275j),
                 Arc(750 + 275j, 25 + 50j, -30, 0, 1, 800 + 250j),
                 Line(800 + 250j, 850 + 225j),
                 Arc(850 + 225j, 25 + 75j, -30, 0, 1, 900 + 200j),
                 Line(900 + 200j, 950 + 175j),
                 Arc(950 + 175j, 25 + 100j, -30, 0, 1, 1000 + 150j),
                 Line(1000 + 150j, 1050 + 125j)))