1
0
Fork 0
inkscape/share/extensions/tests/test_inkex_path_bezier.py
Daniel Baumann 02d935e272
Adding upstream version 1.4.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 23:40:13 +02:00

709 lines
25 KiB
Python

# coding=utf-8
"""
Test Inkex path parsing functionality.
"""
import math
from inkex.tester import TestCase
from inkex.paths import (
PathCommand,
Quadratic,
quadratic,
line,
move,
vert,
horz,
zoneClose,
Line,
Move,
Horz,
Vert,
ZoneClose,
Curve,
curve,
Arc,
arc,
Smooth,
smooth,
TepidQuadratic,
tepidQuadratic,
LengthSettings,
)
from inkex.transforms import Vector2d
# pylint: disable=invalid-name
class PointTests(TestCase):
"""Some more complex cubic and quadratic beziers"""
def compare_points(self, start, curve: Curve, pts):
"""Helper function to compare the point() function of a bezier curve"""
for s, x, y in pts:
self.assertAlmostTuple(
curve.point(Vector2d(), Vector2d(start), Vector2d(), s),
Vector2d(x, y),
precision=8,
)
def test_point(self):
"""Check the point computation for cubic beziers.
See https://github.com/mathandy/svgpathtools/blob/f7e074339d579d0e44d455b92ecf57f24d799fb5/test/test_path.py#L290
"""
self.compare_points(
(100, 200),
Curve(100, 100, 250, 100, 250, 200),
[
(0, 100, 200),
(0.3, 132.4, 137),
(0.5, 175, 125),
(0.9, 245.8, 173),
(1, 250, 200),
],
)
self.compare_points(
(600, 800),
Curve(625, 700, 725, 700, 750, 800),
[
(0, 600, 800),
(0.3, 638.7, 737),
(0.5, 675, 725),
(0.9, 740.4, 773),
(1, 750, 800),
],
)
def test_point_quadratic(self):
self.compare_points(
(200, 300),
Quadratic(400, 50, 600, 300),
[
(0, 200, 300),
(0.3, 320, 195),
(0.5, 400, 175),
(0.9, 560, 255),
(1, 600, 300),
],
)
self.compare_points(
(600, 300),
Quadratic(800, 550, 1000, 300),
[
(0, 600, 300),
(0.3, 720, 405),
(0.5, 800, 425),
(0.9, 960, 345),
(1, 1000, 300),
],
)
class DerivativeTests(TestCase):
"""Test derivative computation"""
def compare_derivative(
self, command, t, expected, n=1, first=Vector2d(0, 0), prev=Vector2d(0, 0)
):
"""Derivative comparison function"""
result = command.derivative(Vector2d(first), Vector2d(prev), Vector2d(), t, n)
self.assertAlmostTuple(result, expected, precision=12)
def test_line_first_derivative(self):
"""Compute derivatives of some lines"""
prev = (2, 1)
first = (5, 5)
for t in [None, 0, 0.5, 0.7, 1]:
self.compare_derivative(Line(5, 5), t, (3, 4), n=1, prev=prev)
self.compare_derivative(line(5, 5), t, (5, 5), 1, prev=prev)
self.compare_derivative(horz(5), t, (5, 0), n=1, prev=prev)
self.compare_derivative(Horz(5), t, (3, 0), n=1, prev=prev)
self.compare_derivative(vert(5), t, (0, 5), n=1, prev=prev)
self.compare_derivative(Vert(5), t, (0, 4), n=1, prev=prev)
self.compare_derivative(zoneClose(), t, (3, 4), n=1, prev=prev, first=first)
self.compare_derivative(ZoneClose(), t, (3, 4), n=1, prev=prev, first=first)
def test_line_higher_derivative(self):
"""The higher derivative is 0 for all line-like commands"""
for t in [None, 0, 0.5, 0.7, 1]:
for com in [Line(5, 5), line(5, 5), Horz(5), vert(5), ZoneClose()]:
for n in [2, 4, 200]:
self.compare_derivative(com, t, (0, 0), n, (5, 5), (2, 1))
def test_line_invalid_parameters(self):
"""Some invalid line parameters"""
# Line with zero length: derivative is undefined
with self.assertRaises(ValueError):
self.compare_derivative(Line(0, 0), 0.5, (0, 0), n=1)
# t not in [0, 1]
with self.assertRaises(ValueError):
self.compare_derivative(Line(1, 1), -0.5, (0, 0), n=1)
# n is not integer or not positive
with self.assertRaises(ValueError):
self.compare_derivative(Line(1, 1), -0.5, (0, 0), n=1.5)
with self.assertRaises(ValueError):
self.compare_derivative(Line(1, 1), -0.5, (0, 0), n=0)
class CurvatureTests(TestCase):
"""Test curvature computation"""
def compare_curvature(
self, command, t, expected, first=Vector2d(0, 0), prev=Vector2d(0, 0)
):
"""Curvature comparison function"""
result = command.curvature(Vector2d(first), Vector2d(prev), t)
self.assertAlmostEqual(result, expected, places=12)
def test_line_curvature(self):
"""The curvature is 0 for all line-like commands"""
for t in [None, 0, 0.5, 0.7, 1]:
for com in [Line(5, 5), line(5, 5), Horz(5), vert(5), ZoneClose()]:
self.compare_curvature(com, t, 0, (5, 5), (2, 1))
class NormalTests(TestCase):
"""Test Normal computation."""
def compare_normal(
self, command, t, expected, first=Vector2d(0, 0), prev=Vector2d(0, 0)
):
"""Normal comparison function"""
result = command.normal(Vector2d(first), Vector2d(prev), t)
self.assertAlmostTuple(result, expected, precision=12)
def test_line_normals(self):
"""Compute unit normals of some lines"""
prev = (2, 1)
first = (5, 5)
for t in [None, 0, 0.5, 0.7, 1]:
self.compare_normal(Line(5, 5), t, (-4 / 5, 3 / 5), prev=prev)
self.compare_normal(line(4, -3), t, (3 / 5, 4 / 5), prev=prev)
self.compare_normal(horz(5), t, (0, 1), prev=prev)
self.compare_normal(Horz(5), t, (0, 1), prev=prev)
self.compare_normal(vert(5), t, (-1, 0), prev=prev)
self.compare_normal(Vert(5), t, (-1, 0), prev=prev)
self.compare_normal(zoneClose(), t, (-4 / 5, 3 / 5), prev=prev, first=first)
self.compare_normal(ZoneClose(), t, (-4 / 5, 3 / 5), prev=prev, first=first)
class SplitTests(TestCase):
"""Test various splits"""
def compare_split(
self,
command: PathCommand,
t,
command_1,
command_2,
first=Vector2d(0, 0),
prev=Vector2d(0, 0),
prev_control=Vector2d(0, 0),
):
"""Comparison function for splitting"""
result = command.split(first, prev, prev_control, t)
print(result[0], result[1])
self.assertEqual(result[0].letter, command_1.letter)
self.assertEqual(result[1].letter, command_2.letter)
self.assertAlmostTuple(result[0].args, command_1.args)
self.assertAlmostTuple(result[1].args, command_2.args)
def test_split_line(self):
"""Splitting a relative line should return two relative lines"""
self.compare_split(
line(4, 8), 0.25, line(1, 2), line(3, 6), prev=Vector2d(5, 5)
)
def test_split_Line(self):
"""Splitting an absolute Line should return two absolute lines"""
self.compare_split(
Line(4, 6), 0.25, Line(2.5, 3), Line(4, 6), prev=Vector2d(2, 2)
)
def test_split_horz(self):
"""Splitting a relative horz should return two relative horz's"""
self.compare_split(horz(-8), 0.125, horz(-1), horz(-7), prev=Vector2d(5, 6))
def test_split_Horz(self):
"""Splitting an absolute Horz should return two absolute Horz's"""
self.compare_split(Horz(10), 0.75, Horz(8), Horz(10), prev=Vector2d(2, 7))
def test_split_vert(self):
"""Splitting a relative vert should return two relative verts"""
self.compare_split(vert(-8), 0.125, vert(-1), vert(-7), prev=Vector2d(6, 5))
def test_split_Vert(self):
"""Splitting an absolute Vert should return two absolute Verts"""
self.compare_split(Vert(-3), 0.1, Vert(6), Vert(-3), prev=Vector2d(2, 7))
def test_split_ZoneClose(self):
"""Splitting an absolute ZoneClose should return a Line and a ZoneClose"""
self.compare_split(
ZoneClose(), 0.75, Line(1.25, 1), ZoneClose(), 1 - 1j, 2 + 7j
)
def test_split_zoneClose(self):
"""Splitting a relative zoneClose should return a (relative) line and a
zoneClose"""
self.compare_split(
zoneClose(), 0.75, line(-0.75, -6), zoneClose(), 1 - 1j, 2 + 7j
)
def test_split_move(self):
"""Splitting a move is not supported, because this would change the number
of subpaths, i.e. introduce unnecessary complexity."""
with self.assertRaises(ValueError):
self.compare_split(Move(6, 6), 0.5, Move(3, 3), Move(6, 6))
with self.assertRaises(ValueError):
self.compare_split(move(6, 6), 0.5, move(3, 3), move(3, 3))
def test_split_curves(self):
"""De Casteljau"""
self.compare_split(
Curve(300 + 0j, -100 - 10j, 250 + 100j),
0.7,
Curve(225 + 30j, 81.5 + 4.1j, 99.7 + 32.59j),
Curve(107.5 + 44.8j, 145 + 67j, 250 + 100j),
0j,
50 + 100j,
)
# Same for relative
self.compare_split(
curve(250 - 100j, -150 - 110j, 200 + 0j),
0.7,
curve(175 - 70j, 31.5 - 95.9j, 49.7 - 67.41j),
curve(7.8 + 12.21j, 45.3 + 34.41j, 150.3 + 67.41j),
0j,
50 + 100j,
)
def test_split_smooth(self):
"""Same for smooth 3rd order. Can only be split into curves"""
prev = 250 + 100j
prev_prev = -100 - 10j
self.compare_split(
Smooth(0 + 250j, 400 + 150j),
0.3,
Curve(355 + 133j, 374.5 + 159.7j, 361.15 + 178.21j),
Curve(330 + 221.4j, 120 + 220j, 400 + 150j),
0j,
prev,
prev_prev,
)
self.compare_split(
Smooth(0 + 250j, 400 + 150j).to_relative(prev),
0.3,
curve(105 + 33j, 124.5 + 59.7j, 111.15 + 78.21j),
curve(-31.15 + 43.19j, -241.15 + 41.79j, 38.85 - 28.21j),
0j,
prev,
prev_prev,
)
def test_split_quadratic(self):
"""De Casteljau for 2nd order curves"""
self.compare_split(
Quadratic(300 + 0j, 10 + 10j),
0.2,
Quadratic(100 + 80j, 128.4 + 64.4j),
Quadratic(242 + 2j, 10 + 10j),
0j,
50 + 100j,
)
self.compare_split(
quadratic(250 - 100j, -40 - 90j),
0.2,
quadratic(50 - 20j, 78.4 - 35.6j),
quadratic(113.6 - 62.4j, -118.4 - 54.4j),
0j,
50 + 100j,
)
def test_split_tepid_quadratic(self):
"""Smooth 2nd order"""
self.compare_split(
TepidQuadratic(100 + 100j),
0.2,
Quadratic(-48 + 12j, -79.2 + 16.8j),
Quadratic(-204 + 36j, 100 + 100j),
0j,
10 + 10j,
300 + 0j,
)
self.compare_split(
tepidQuadratic(100 + 100j),
0.2,
quadratic(-58 + 2j, -88.8 + 7.2j),
quadratic(-123.2 + 20.8j, 188.8 + 92.8j),
0j,
10 + 10j,
300 + 0j,
)
def test_split_arc(self):
"""Splitting an Arc/arc"""
initial = 725.307482225571 - 915.5548199281527j
arc5 = Arc(
(202.79421639137703 + 148.77294617167183j),
225.6910319606926,
1,
1,
(-624.6375539637027 + 896.5483089399895j),
)
a1, a2 = arc5.split(0j, initial, 0j, 0.4)
print(a1, a2)
self.assertAlmostEqual(
arc5.cpoint(0j, initial, 0j, 0.4), a1.cpoint(0j, initial, 0j, 1), delta=TOL
)
self.assertAlmostEqual(
arc5.cpoint(0j, initial, 0j, 0.4),
a2.cpoint(0j, a1.cend_point(0j, initial), 0j, 0),
delta=TOL,
)
self.assertAlmostEqual(
arc5.cpoint(0j, initial, 0j, 1),
a2.cpoint(0j, a1.cend_point(0j, initial), 0j, 1),
delta=TOL,
)
# Same for relative arcs
arc5rel = arc(
(202.79421639137703 + 148.77294617167183j),
225.6910319606926,
1,
1,
(-624.6375539637027 + 896.5483089399895j) - initial,
)
a1, a2 = arc5rel.split(0j, initial, 0j, 0.4)
print(a1, a2)
self.assertAlmostEqual(
arc5rel.cpoint(0j, initial, 0j, 0.4),
a1.cpoint(0j, initial, 0j, 1),
delta=TOL,
)
self.assertAlmostEqual(
arc5rel.cpoint(0j, initial, 0j, 0.4),
a2.cpoint(0j, a1.cend_point(0j, initial), 0j, 0),
delta=TOL,
)
self.assertAlmostEqual(
arc5rel.cpoint(0j, initial, 0j, 1),
a2.cpoint(0j, a1.cend_point(0j, initial), 0j, 1),
delta=TOL,
)
class LengthTests(TestCase):
"""Test length computation"""
def compare_length(
self, prev, command: PathCommand, expected, t0=0, t1=1, first=Vector2d(0, 0)
):
"""Length comparison function"""
result = command.length(
Vector2d(first),
Vector2d(prev),
Vector2d(),
t0,
t1,
LengthSettings(error=1e-12),
)
self.assertAlmostEqual(result, expected, places=8)
def test_length_lines(self):
"""Test length computation for line-like commands"""
prev = (2, 1)
first = (5, 5)
self.compare_length(prev, Line(5, 5), 5)
self.compare_length(prev, Line(5, 5), 3, 0.2, 0.8)
self.compare_length(prev, line(-5, 12), 13)
self.compare_length(prev, horz(5), 4, 0, 0.8)
self.compare_length(prev, Horz(5), 3)
self.compare_length(prev, Vert(5), 3, 0.25, 1)
self.compare_length(prev, vert(5), 5)
self.compare_length(prev, ZoneClose(), 5, first=first)
self.compare_length(prev, zoneClose(), 4, 0.2, first=first)
def test_length_cubic(self):
"""based on https://github.com/mathandy/svgpathtools/blob/f7e074339d579d0e44d455b92ecf57f24d799fb5/test/test_path.py#L363"""
# A straight line
self.compare_length((0, 0), Curve(0, 0, 0, 100, 0, 100), 100)
# A diagonal line
self.compare_length((0, 0), Curve(0, 0, 100, 100, 100, 100), math.sqrt(2) * 100)
# A cubic bezier that approximates a quarter arc.
kappa = 4 * (math.sqrt(2) - 1) / 3
self.compare_length(
(0, 0),
Curve(0, 100 * kappa, 100 - 100 * kappa, 100, 100, 100),
157.10166980361998,
)
def test_length_quadratic(self):
"""based on https://github.com/mathandy/svgpathtools/blob/f7e074339d579d0e44d455b92ecf57f24d799fb5/test/test_path.py#L450"""
q1 = [(200, 300), Quadratic(400, 50, 600, 300)]
q2 = [(200, 300), Quadratic(400, 50, 500, 200)]
self.compare_length(*q1, 487.77109389525975)
self.compare_length(*q2, 379.90458193489155)
# Closed quadratic
closedq = [(6, 2), Quadratic(5, -1, 6, 2)]
self.compare_length(*closedq, 3.1622776601683795)
# lines
linq1 = [(1, 0), Quadratic(2, 0, 3, 0)]
linq2 = [(1, 3), Quadratic(2, 5, -9, -17)]
self.compare_length(*linq1, 2)
self.compare_length(*linq2, 22.73335777124786)
# all nodes on the same point
samepoint = [(1, 0), Quadratic(1, 0, 1, 0)]
self.compare_length(*samepoint, 0)
# partial length tests
self.compare_length(*q1, 212.34775387566032, 0.25, 0.75)
self.compare_length(*q2, 166.22170622052397, 0.25, 0.75)
self.compare_length(*closedq, 0.7905694150420949, 0.25, 0.75)
self.compare_length(*linq1, 1, 0.25, 0.75)
self.compare_length(*samepoint, 0, 0.25, 0.75)
class IlengthTests(TestCase):
"""Test inverse length computation"""
def compare_ilength(
self,
command,
s,
expected,
first=Vector2d(0, 0),
prev=Vector2d(0, 0),
prev_control=Vector2d(0, 0),
places=8,
):
"""Inverse Length comparison function"""
result = command.ilength(
Vector2d(first),
Vector2d(prev),
Vector2d(prev_control),
s,
)
self.assertAlmostEqual(result, expected, places=places)
def test_ilength_lines(self):
"""Test inverse length computation for line-like commands"""
prev = (2, 1)
first = (5, 5)
self.compare_ilength(Line(5, 5), 5, 1, prev=prev)
self.compare_ilength(Line(5, 5), 4, 0.8, prev=prev)
self.compare_ilength(line(-5, 12), 6.5, 0.5, prev=prev)
self.compare_ilength(horz(5), 4, 0.8, prev=prev)
self.compare_ilength(Horz(5), 2, 2 / 3, prev=prev)
self.compare_ilength(Vert(5), 3, 0.75, prev=prev)
self.compare_ilength(vert(5), 5, 1, prev=prev)
self.compare_ilength(ZoneClose(), 5, 1, prev=prev, first=first)
self.compare_ilength(zoneClose(), 4, 0.8, prev=prev, first=first)
def test_ilength_quadratics(self):
"""From https://github.com/mathandy/svgpathtools/blob/f7e074339d579d0e44d455b92ecf57f24d799fb5/test/test_path.py#L1214"""
q1 = [(200, 300), Quadratic(400, 50, 600, 300)]
q2 = [(200, 300), Quadratic(400, 50, 500, 200)]
closedq = [(6, 2), Quadratic(5, -1, 6, 2)]
linq = [(1, 3), Quadratic(2, 5, -9, -17)]
tests = [
(q1, 0.01, 6.364183310105577),
(q1, 0.1, 60.23857499635088),
(q1, 0.5, 243.8855469477619),
(q1, 0.9, 427.53251889917294),
(q1, 0.99, 481.40691058541813),
(q2, 0.01, 6.365673533661836),
(q2, 0.1, 60.31675895732397),
(q2, 0.5, 233.24592830045907),
(q2, 0.9, 346.42891253298706),
(q2, 0.99, 376.32659156736844),
(closedq, 0.01, 0.06261309767133393),
(closedq, 0.1, 0.5692099788303084),
(closedq, 0.5, 1.5811388300841898),
(closedq, 0.9, 2.5930676813380713),
(closedq, 0.99, 3.0996645624970456),
(linq, 0.01, 0.04203807797699605),
(linq, 0.1, 0.19379255804998186),
(linq, 0.5, 4.844813951249544),
(linq, 0.9, 18.0823363780483),
(linq, 0.99, 22.24410609777091),
]
for q, t, s in tests:
self.compare_ilength(q[1], s, t, prev=q[0], places=4)
rel = q[1].to_relative(Vector2d(q[0]))
self.compare_ilength(rel, s, t, prev=q[0], places=4)
def test_ilength_cubics(self):
"""From https://github.com/mathandy/svgpathtools/blob/f7e074339d579d0e44d455b92ecf57f24d799fb5/test/test_path.py#L1250"""
c1 = [(200, 300), Curve(400, 50, 600, 100, -200, 0)]
symc = [(1, -2), Curve(10, -1, 10, 1, 1, 2)]
closedc = [(1, -2), Curve(10, -1, 10, 1, 1, -2)]
tests = [
(c1, 0.01, 9.53434737943073),
(c1, 0.1, 88.89941848775852),
(c1, 0.5, 278.5750942713189),
(c1, 0.9, 651.4957786584646),
(c1, 0.99, 840.2010603832538),
(symc, 0.01, 0.2690118556702902),
(symc, 0.1, 2.45230693868727),
(symc, 0.5, 7.256147083644424),
(symc, 0.9, 12.059987228602886),
(symc, 0.99, 14.243282311619401),
(closedc, 0.01, 0.26901140075538765),
(closedc, 0.1, 2.451722765460998),
(closedc, 0.5, 6.974058969750422),
(closedc, 0.9, 11.41781741489913),
(closedc, 0.99, 13.681324783697782),
]
for q, t, s in tests:
self.compare_ilength(q[1], s, t, prev=q[0], places=4)
rel = q[1].to_relative(Vector2d(q[0]))
self.compare_ilength(rel, s, t, prev=q[0], places=4)
TOL = 1e-4
class ArcTest(TestCase):
def test_point(self):
def assert_point(arc: Arc, start: complex, at: float, point: complex):
self.assertAlmostEqual(arc.cpoint(0j, start, 0j, at), point, delta=TOL)
arc1 = Arc(100 + 50j, 0, 0, 0, 100 + 50j)
_, _, _, center, theta1, deltaTheta = arc1.parametrize(0j)
self.assertAlmostEqual(center, 100 + 0j, delta=TOL)
self.assertAlmostEqual(theta1, 180.0, delta=TOL)
self.assertAlmostEqual(deltaTheta, -90.0, delta=TOL)
for at, point in [
(0.0, 0j),
(0.1, 1.23116594049 + 7.82172325201j),
(0.2, 4.89434837048 + 15.4508497187j),
(0.3, 10.8993475812 + 22.699524987j),
(0.4, 19.0983005625 + 29.3892626146j),
(0.5, 29.2893218813 + 35.3553390593j),
(0.6, 41.2214747708 + 40.4508497187j),
(0.7, 54.6009500260 + 44.5503262094j),
(0.8, 69.0983005625 + 47.5528258148j),
(0.9, 84.3565534960 + 49.3844170298j),
(1.0, 100 + 50j),
]:
assert_point(Arc(100 + 50j, 0, 0, 0, 100 + 50j), 0j, at, point)
arc2 = Arc(100 + 50j, 0, 1, 0, 100 + 50j)
_, _, _, center, theta1, deltaTheta = arc2.parametrize(0j)
self.assertAlmostEqual(center, 50j, delta=TOL)
self.assertAlmostEqual(theta1, -90.0, delta=TOL)
self.assertAlmostEqual(deltaTheta, -270.0, delta=TOL)
for at, point in [
(0.0, 0j),
(0.1, (-45.399049974 + 5.44967379058j)),
(0.2, (-80.9016994375 + 20.6107373854j)),
(0.3, (-98.7688340595 + 42.178276748j)),
(0.4, (-95.1056516295 + 65.4508497187j)),
(0.5, (-70.7106781187 + 85.3553390593j)),
(0.6, (-30.9016994375 + 97.5528258148j)),
(0.7, (15.643446504 + 99.3844170298j)),
(0.8, (58.7785252292 + 90.4508497187j)),
(0.9, (89.1006524188 + 72.699524987j)),
(1.0, (100 + 50j)),
]:
assert_point(Arc(100 + 50j, 0, 1, 0, 100 + 50j), 0j, at, point)
arc3 = Arc(100 + 50j, 0, 0, 1, 100 + 50j)
_, _, _, center, theta1, deltaTheta = arc3.parametrize(0j)
self.assertAlmostEqual(center, 50j, delta=TOL)
self.assertAlmostEqual(theta1, -90.0, delta=TOL)
self.assertAlmostEqual(deltaTheta, 90.0, delta=TOL)
for at, point in [
(0.0, 0j),
(0.1, (15.643446504 + 0.615582970243j)),
(0.2, (30.9016994375 + 2.44717418524j)),
(0.3, (45.399049974 + 5.44967379058j)),
(0.4, (58.7785252292 + 9.54915028125j)),
(0.5, (70.7106781187 + 14.6446609407j)),
(0.6, (80.9016994375 + 20.6107373854j)),
(0.7, (89.1006524188 + 27.300475013j)),
(0.8, (95.1056516295 + 34.5491502813j)),
(0.9, (98.7688340595 + 42.178276748j)),
(1.0, (100 + 50j)),
]:
assert_point(Arc(100 + 50j, 0, 0, 1, 100 + 50j), 0j, at, point)
arc4 = Arc(100 + 50j, 0, 1, 1, 100 + 50j)
_, _, _, center, theta1, deltaTheta = arc4.parametrize(0j)
self.assertAlmostEqual(center, 100 + 0j, delta=TOL)
self.assertAlmostEqual(theta1, 180.0, delta=TOL)
self.assertAlmostEqual(deltaTheta, 270.0, delta=TOL)
for at, point in [
(0.0, 0j),
(0.1, (10.8993475812 - 22.699524987j)),
(0.2, (41.2214747708 - 40.4508497187j)),
(0.3, (84.3565534960 - 49.3844170298j)),
(0.4, (130.901699437 - 47.5528258148j)),
(0.5, (170.710678119 - 35.3553390593j)),
(0.6, (195.105651630 - 15.4508497187j)),
(0.7, (198.768834060 + 7.82172325201j)),
(0.8, (180.901699437 + 29.3892626146j)),
(0.9, (145.399049974 + 44.5503262094j)),
(1.0, (100 + 50j)),
]:
assert_point(Arc(100 + 50j, 0, 1, 1, 100 + 50j), 0j, at, point)
initial = 725.307482225571 - 915.5548199281527j
arc5 = Arc(
(202.79421639137703 + 148.77294617167183j),
225.6910319606926,
1,
1,
(-624.6375539637027 + 896.5483089399895j),
)
arc5rel = arc(
(202.79421639137703 + 148.77294617167183j),
225.6910319606926,
1,
1,
(-624.6375539637027 + 896.5483089399895j) - initial,
)
for at, point in [
(0.0, initial),
(0.0909090909091, (1023.47397369 - 597.730444283j)),
(0.181818181818, (1242.80253007 - 232.251400124j)),
(0.272727272727, (1365.52445614 + 151.273373978j)),
(0.363636363636, (1381.69755131 + 521.772981736j)),
(0.454545454545, (1290.01156757 + 849.231748376j)),
(0.545454545455, (1097.89435807 + 1107.12091209j)),
(0.636363636364, (820.910116547 + 1274.54782658j)),
(0.727272727273, (481.49845896 + 1337.94855893j)),
(0.818181818182, (107.156499251 + 1292.18675889j)),
(0.909090909091, (-271.788803303 + 1140.96977533j)),
]:
assert_point(arc5, initial, at, point)
assert_point(arc5rel, initial, at, point)