svgpathtools/test/test_pathtools.py

245 lines
9.0 KiB
Python

# External dependencies
from __future__ import division, absolute_import, print_function
import unittest
from numpy import poly1d
# Internal dependencies
from svgpathtools import *
class TestPathTools(unittest.TestCase):
def setUp(self):
self.arc1 = Arc(650+325j, 25+25j, -30.0, False, True, 700+300j)
self.line1 = Line(0, 100+100j)
self.quadratic1 = QuadraticBezier(100+100j, 150+150j, 300+200j)
self.cubic1 = CubicBezier(300+200j, 350+400j, 400+425j, 650+325j)
self.path_of_all_seg_types = Path(self.line1, self.quadratic1,
self.cubic1, self.arc1)
self.path_of_bezier_seg_types = Path(self.line1, self.quadratic1,
self.cubic1)
def test_is_bezier_segment(self):
# False
self.assertFalse(is_bezier_segment(self.arc1))
self.assertFalse(is_bezier_segment(self.path_of_bezier_seg_types))
# True
self.assertTrue(is_bezier_segment(self.line1))
self.assertTrue(is_bezier_segment(self.quadratic1))
self.assertTrue(is_bezier_segment(self.cubic1))
def test_is_bezier_path(self):
# False
self.assertFalse(is_bezier_path(self.path_of_all_seg_types))
self.assertFalse(is_bezier_path(self.line1))
self.assertFalse(is_bezier_path(self.quadratic1))
self.assertFalse(is_bezier_path(self.cubic1))
self.assertFalse(is_bezier_path(self.arc1))
# True
self.assertTrue(is_bezier_path(self.path_of_bezier_seg_types))
self.assertTrue(is_bezier_path(Path()))
def test_polynomial2bezier(self):
def distfcn(tup1, tup2):
assert len(tup1) == len(tup2)
return sum((tup1[i]-tup2[i])**2 for i in range(len(tup1)))**0.5
# Case: Line
pcoeffs = [(-1.7-2j), (6+2j)]
p = poly1d(pcoeffs)
correct_bpoints = [(6+2j), (4.3+0j)]
# Input poly1d object
bez = poly2bez(p)
bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients
bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
# Case: Quadratic
pcoeffs = [(29.5+15.5j), (-31-19j), (7.5+5.5j)]
p = poly1d(pcoeffs)
correct_bpoints = [(7.5+5.5j), (-8-4j), (6+2j)]
# Input poly1d object
bez = poly2bez(p)
bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients
bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
# Case: Cubic
pcoeffs = [(-18.5-12.5j), (34.5+16.5j), (-18-6j), (6+2j)]
p = poly1d(pcoeffs)
correct_bpoints = [(6+2j), 0j, (5.5+3.5j), (4+0j)]
# Input poly1d object
bez = poly2bez(p)
bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients object
bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0)
def test_bpoints2bezier(self):
cubic_bpoints = [(6+2j), 0, (5.5+3.5j), (4+0j)]
quadratic_bpoints = [(6+2j), 0, (5.5+3.5j)]
line_bpoints = [(6+2j), 0]
self.assertTrue(isinstance(bpoints2bezier(cubic_bpoints), CubicBezier))
self.assertTrue(isinstance(bpoints2bezier(quadratic_bpoints),
QuadraticBezier))
self.assertTrue(isinstance(bpoints2bezier(line_bpoints), Line))
self.assertSequenceEqual(bpoints2bezier(cubic_bpoints).bpoints(),
cubic_bpoints)
self.assertSequenceEqual(bpoints2bezier(quadratic_bpoints).bpoints(),
quadratic_bpoints)
self.assertSequenceEqual(bpoints2bezier(line_bpoints).bpoints(),
line_bpoints)
# def test_line2pathd(self):
# bpoints = (0+1.5j, 100+10j)
# line = Line(*bpoints)
#
# # from Line object
# pathd = line2pathd(line)
# path = parse_path(pathd)
# self.assertTrue(path[0] == line)
#
# # from list of bpoints
# pathd = line2pathd(bpoints)
# path = parse_path(pathd)
# self.assertTrue(path[0] == line)
#
# def test_cubic2pathd(self):
# bpoints = (0+1.5j, 100+10j, 150-155.3j, 0)
# cubic = CubicBezier(*bpoints)
#
# # from Line object
# pathd = cubic2pathd(cubic)
# path = parse_path(pathd)
# self.assertTrue(path[0] == cubic)
#
# # from list of bpoints
# pathd = cubic2pathd(bpoints)
# path = parse_path(pathd)
# self.assertTrue(path[0] == cubic)
def test_closest_point_in_path(self):
def distfcn(tup1, tup2):
assert len(tup1) == len(tup2)
return sum((tup1[i]-tup2[i])**2 for i in range(len(tup1)))**0.5
# Note: currently the radiialrange method is not implemented for Arc
# objects
# test_path = self.path_of_all_seg_types
# origin = -123 - 123j
# expected_result = ???
# self.assertAlmostEqual(min_radius(origin, test_path),
# expected_result)
# generic case (where is_bezier_path(test_path) == True)
test_path = self.path_of_bezier_seg_types
pt = 300+300j
expected_result = (29.382522853493143, 0.17477067969145446, 2)
result = closest_point_in_path(pt, test_path)
err = distfcn(expected_result, result)
self.assertAlmostEqual(err, 0)
# cubic test with multiple valid solutions
test_path = Path(CubicBezier(1-2j, 10-1j, 10+1j, 1+2j))
pt = 3
expected_results = [(1.7191878932122302, 0.90731678233211366, 0),
(1.7191878932122304, 0.092683217667886342, 0)]
result = closest_point_in_path(pt, test_path)
err = min(distfcn(e_res, result) for e_res in expected_results)
self.assertAlmostEqual(err, 0)
def test_farthest_point_in_path(self):
def distfcn(tup1, tup2):
assert len(tup1) == len(tup2)
return sum((tup1[i]-tup2[i])**2 for i in range(len(tup1)))**0.5
# Note: currently the radiialrange method is not implemented for Arc
# objects
# test_path = self.path_of_all_seg_types
# origin = -123 - 123j
# expected_result = ???
# self.assertAlmostEqual(min_radius(origin, test_path),
# expected_result)
# boundary test
test_path = self.path_of_bezier_seg_types
pt = 300+300j
expected_result = (424.26406871192853, 0, 0)
result = farthest_point_in_path(pt, test_path)
err = distfcn(expected_result, result)
self.assertAlmostEqual(err, 0)
# non-boundary test
test_path = Path(CubicBezier(1-2j, 10-1j, 10+1j, 1+2j))
pt = 3
expected_result = (4.75, 0.5, 0)
result = farthest_point_in_path(pt, test_path)
err = distfcn(expected_result, result)
self.assertAlmostEqual(err, 0)
def test_path_encloses_pt(self):
line1 = Line(0, 100+100j)
quadratic1 = QuadraticBezier(100+100j, 150+150j, 300+200j)
cubic1 = CubicBezier(300+200j, 350+400j, 400+425j, 650+325j)
line2 = Line(650+325j, 650+10j)
line3 = Line(650+10j, 0)
open_bez_path = Path(line1, quadratic1, cubic1)
closed_bez_path = Path(line1, quadratic1, cubic1, line2, line3)
inside_pt = 200+20j
outside_pt1 = 1000+1000j
outside_pt2 = 800+800j
boundary_pt = 50+50j
# Note: currently the intersect() method is not implemented for Arc
# objects
# arc1 = Arc(650+325j, 25+25j, -30.0, False, True, 700+300j)
# closed_path_with_arc = Path(line1, quadratic1, cubic1, arc1)
# self.assertTrue(
# path_encloses_pt(inside_pt, outside_pt2, closed_path_with_arc))
# True cases
self.assertTrue(
path_encloses_pt(inside_pt, outside_pt2, closed_bez_path))
self.assertTrue(
path_encloses_pt(boundary_pt, outside_pt2, closed_bez_path))
# False cases
self.assertFalse(
path_encloses_pt(outside_pt1, outside_pt2, closed_bez_path))
# Exception Cases
with self.assertRaises(AssertionError):
path_encloses_pt(inside_pt, outside_pt2, open_bez_path)
# Display test paths and points
# ns2d = [inside_pt, outside_pt1, outside_pt2, boundary_pt]
# ncolors = ['green', 'red', 'orange', 'purple']
# disvg(closed_path_with_arc, nodes=ns2d, node_colors=ncolors,
# openinbrowser=True)
# disvg(open_bez_path, nodes=ns2d, node_colors=ncolors,
# openinbrowser=True)
# disvg(closed_bez_path, nodes=ns2d, node_colors=ncolors,
# openinbrowser=True)
if __name__ == '__main__':
unittest.main()