diff --git a/svgpathtools/pathtools.py b/svgpathtools/pathtools.py deleted file mode 100644 index 2e78452..0000000 --- a/svgpathtools/pathtools.py +++ /dev/null @@ -1,14 +0,0 @@ -"""This submodule contains additional tools for working with paths composed of -Line and CubicBezier objects. QuadraticBezier and Arc objects are only -partially supported.""" - -# External dependencies: -from __future__ import division, absolute_import, print_function - -# Internal dependencies -from .path import Path, Line, QuadraticBezier, CubicBezier, Arc - - -# Misc######################################################################### - - diff --git a/test/test_path.py b/test/test_path.py index b90754e..3d3cec3 100644 --- a/test/test_path.py +++ b/test/test_path.py @@ -3,6 +3,7 @@ from __future__ import division, absolute_import, print_function import unittest from math import sqrt, pi from operator import itemgetter +from numpy import poly1d # Internal dependencies from svgpathtools import * @@ -949,5 +950,240 @@ class Test_intersect(unittest.TestCase): self.assertTrue(len(yix), 1) ################################################################### + +class TestPathTools(unittest.TestCase): + # moved from test_pathtools.py + + 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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) + + # Input list of coefficients + bpoints = poly2bez(pcoeffs, return_bpoints=True) + self.assertAlmostEqual(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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) + + # Input list of coefficients + bpoints = poly2bez(pcoeffs, return_bpoints=True) + self.assertAlmostEqual(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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) + + # Input list of coefficients object + bpoints = poly2bez(pcoeffs, return_bpoints=True) + self.assertAlmostEqual(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() diff --git a/test/test_pathtools.py b/test/test_pathtools.py deleted file mode 100644 index ce61016..0000000 --- a/test/test_pathtools.py +++ /dev/null @@ -1,244 +0,0 @@ -# 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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) - - # Input list of coefficients - bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEqual(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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) - - # Input list of coefficients - bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEqual(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.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0) - - # Input list of coefficients object - bpoints = poly2bez(pcoeffs, return_bpoints=True) - self.assertAlmostEqual(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()