futurized for Python 3 compatibility

and some other minor changes of no effect
pull/12/merge
Andy 2017-02-28 23:04:37 -08:00
parent f697a91190
commit 8815ddcd52
11 changed files with 74 additions and 36 deletions

View File

@ -3,7 +3,7 @@ import codecs
import os import os
VERSION = '1.2.6' VERSION = '1.3'
AUTHOR_NAME = 'Andy Port' AUTHOR_NAME = 'Andy Port'
AUTHOR_EMAIL = 'AndyAPort@gmail.com' AUTHOR_EMAIL = 'AndyAPort@gmail.com'

View File

@ -5,6 +5,8 @@ points given by their standard representation."""
# External dependencies: # External dependencies:
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import range
from builtins import object
from math import factorial as fac, ceil, log, sqrt from math import factorial as fac, ceil, log, sqrt
from numpy import poly1d from numpy import poly1d

View File

@ -3,6 +3,7 @@ aren't specific to SVGs or related mathematical objects."""
# External dependencies: # External dependencies:
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import range
import os import os
import sys import sys
import webbrowser import webbrowser

View File

@ -4,6 +4,10 @@ Arc."""
# External dependencies # External dependencies
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import map
from builtins import zip
from builtins import range
from builtins import object
from math import sqrt, cos, sin, acos, degrees, radians, log, pi from math import sqrt, cos, sin, acos, degrees, radians, log, pi
from cmath import exp, sqrt as csqrt, phase from cmath import exp, sqrt as csqrt, phase
from collections import MutableSequence from collections import MutableSequence
@ -355,7 +359,8 @@ def inv_arclength(curve, s, s_tol=ILENGTH_S_TOL, maxits=ILENGTH_MAXITS,
if curve is a Path object, then seg is a segment in curve. if curve is a Path object, then seg is a segment in curve.
error - used to compute lengths of cubics and arcs error - used to compute lengths of cubics and arcs
min_depth - used to compute lengths of cubics and arcs min_depth - used to compute lengths of cubics and arcs
Note: This function is not designed to be efficient.""" Note: This function is not designed to be efficient, but if it's slower
than you need, make sure you have scipy installed."""
curve_length = curve.length(error=error, min_depth=min_depth) curve_length = curve.length(error=error, min_depth=min_depth)
assert curve_length > 0 assert curve_length > 0
@ -1514,7 +1519,7 @@ class Arc(object):
u1poly_mag2 = real(u1poly)**2 + imag(u1poly)**2 u1poly_mag2 = real(u1poly)**2 + imag(u1poly)**2
t2s = polyroots01(u1poly_mag2 - 1) t2s = polyroots01(u1poly_mag2 - 1)
t1s = [self.phase2t(phase(u1poly(t2))) for t2 in t2s] t1s = [self.phase2t(phase(u1poly(t2))) for t2 in t2s]
return zip(t1s, t2s) return list(zip(t1s, t2s))
elif isinstance(other_seg, Arc): elif isinstance(other_seg, Arc):
assert other_seg != self assert other_seg != self
# This could be made explicit to increase efficiency # This could be made explicit to increase efficiency
@ -2126,7 +2131,7 @@ class Path(MutableSequence):
"""returns a bounding box for the input Path object in the form """returns a bounding box for the input Path object in the form
(xmin, xmax, ymin, ymax).""" (xmin, xmax, ymin, ymax)."""
bbs = [seg.bbox() for seg in self._segments] bbs = [seg.bbox() for seg in self._segments]
xmins, xmaxs, ymins, ymaxs = zip(*bbs) xmins, xmaxs, ymins, ymaxs = list(zip(*bbs))
xmin = min(xmins) xmin = min(xmins)
xmax = max(xmaxs) xmax = max(xmaxs)
ymin = min(ymins) ymin = min(ymins)

View File

@ -3,6 +3,8 @@ segments."""
# External dependencies: # External dependencies:
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import zip
from builtins import str
from math import ceil from math import ceil
from os import getcwd, path as os_path, makedirs from os import getcwd, path as os_path, makedirs
from xml.dom.minidom import parse as md_xml_parse from xml.dom.minidom import parse as md_xml_parse
@ -74,7 +76,7 @@ def big_bounding_box(paths_n_stuff):
raise TypeError( raise TypeError(
"paths_n_stuff can only contains Path, CubicBezier, " "paths_n_stuff can only contains Path, CubicBezier, "
"QuadraticBezier, Line, and complex objects.") "QuadraticBezier, Line, and complex objects.")
xmins, xmaxs, ymins, ymaxs = zip(*bbs) xmins, xmaxs, ymins, ymaxs = list(zip(*bbs))
xmin = min(xmins) xmin = min(xmins)
xmax = max(xmaxs) xmax = max(xmaxs)
ymin = min(ymins) ymin = min(ymins)

View File

@ -5,6 +5,7 @@ curves."""
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
# Internal Dependencies # Internal Dependencies
from builtins import range
from .path import Path, CubicBezier, Line from .path import Path, CubicBezier, Line
from .misctools import isclose from .misctools import isclose
from .paths2svg import disvg from .paths2svg import disvg

View File

@ -3,6 +3,7 @@ The main tool being the svg2paths() function."""
# External dependencies # External dependencies
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import zip
from xml.dom.minidom import parse from xml.dom.minidom import parse
from os import path as os_path, getcwd from os import path as os_path, getcwd
from shutil import copyfile from shutil import copyfile
@ -64,9 +65,9 @@ def svg2paths(svg_file_location,
def dom2dict(element): def dom2dict(element):
"""Converts DOM elements to dictionaries of attributes.""" """Converts DOM elements to dictionaries of attributes."""
keys = element.attributes.keys() keys = list(element.attributes.keys())
values = [val.value for val in element.attributes.values()] values = [val.value for val in list(element.attributes.values())]
return dict(zip(keys, values)) return dict(list(zip(keys, values)))
# Use minidom to extract path strings from input SVG # Use minidom to extract path strings from input SVG
paths = [dom2dict(el) for el in doc.getElementsByTagName('path')] paths = [dom2dict(el) for el in doc.getElementsByTagName('path')]

View File

@ -1,5 +1,6 @@
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
import numpy as np import numpy as np
from builtins import range
import unittest import unittest
from svgpathtools.bezier import * from svgpathtools.bezier import *
from svgpathtools.path import bpoints2bezier from svgpathtools.path import bpoints2bezier

View File

@ -1,13 +1,14 @@
# Note: This file was taken mostly as is from the svg.path module (v 2.0) # Note: This file was taken mostly as is from the svg.path module (v 2.0)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import zip
import unittest import unittest
from svgpathtools import * from svgpathtools import *
class TestGeneration(unittest.TestCase): class TestGeneration(unittest.TestCase):
def test_svg_examples(self): def test_path_parsing(self):
"""Examples from the SVG spec""" """Examples from the SVG spec"""
paths = [ paths = [
'M 100,100 L 300,100 L 200,300 Z', 'M 100,100 L 300,100 L 200,300 Z',
@ -26,7 +27,7 @@ class TestGeneration(unittest.TestCase):
'M 0,0 L 50,20 M 50,20 L 200,100 Z', 'M 0,0 L 50,20 M 50,20 L 200,100 Z',
'M 600,350 L 650,325 A 25,25 -30 0,1 700,300 L 750,275', 'M 600,350 L 650,325 A 25,25 -30 0,1 700,300 L 750,275',
] ]
pathsf = [ float_paths = [
'M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0', 'M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0',
'M 0.0,0.0 L 50.0,20.0 M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0', 'M 0.0,0.0 L 50.0,20.0 M 100.0,100.0 L 300.0,100.0 L 200.0,300.0 L 100.0,100.0',
'M 100.0,100.0 L 200.0,200.0', 'M 100.0,100.0 L 200.0,200.0',
@ -41,11 +42,32 @@ class TestGeneration(unittest.TestCase):
'M 200.0,300.0 Q 400.0,50.0 600.0,300.0 Q 800.0,550.0 1000.0,300.0', 'M 200.0,300.0 Q 400.0,50.0 600.0,300.0 Q 800.0,550.0 1000.0,300.0',
'M -3.4e+38,3.4e+38 L -3.4e-38,3.4e-38', 'M -3.4e+38,3.4e+38 L -3.4e-38,3.4e-38',
'M 0.0,0.0 L 50.0,20.0 L 200.0,100.0 L 50.0,20.0', 'M 0.0,0.0 L 50.0,20.0 L 200.0,100.0 L 50.0,20.0',
'M 600.0,350.0 L 650.0,325.0 A 27.9508497187,27.9508497187 -30.0 0,1 700.0,300.0 L 750.0,275.0' ('M 600.0,350.0 L 650.0,325.0 A 27.9508497187,27.9508497187 -30.0 0,1 700.0,300.0 L 750.0,275.0', # Python 2
'M 600.0,350.0 L 650.0,325.0 A 27.95084971874737,27.95084971874737 -30.0 0,1 700.0,300.0 L 750.0,275.0') # Python 3
] ]
for k, path in enumerate(paths): for path, flpath in zip(paths[::-1], float_paths[::-1]):
self.assertTrue(parse_path(path).d() in (path, pathsf[k])) # Note: Python 3 and Python 2 differ in the number of digits
# truncated when returning a string representation of a float
parsed_path = parse_path(path)
res = parsed_path.d()
if isinstance(flpath, tuple):
option3 = res == flpath[1] # Python 3
flpath = flpath[0]
else:
option3 = False
option1 = res == path
option2 = res == flpath
msg = ('\npath =\n {}\nflpath =\n {}\nparse_path(path).d() =\n {}'
''.format(path, flpath, res))
self.assertTrue(option1 or option2 or option3, msg=msg)
for flpath in float_paths[:-1]:
res = parse_path(flpath).d()
msg = ('\nflpath =\n {}\nparse_path(path).d() =\n {}'
''.format(flpath, res))
self.assertTrue(res == flpath, msg=msg)
def test_normalizing(self): def test_normalizing(self):
# Relative paths will be made absolute, subpaths merged if they can, # Relative paths will be made absolute, subpaths merged if they can,
@ -54,3 +76,7 @@ class TestGeneration(unittest.TestCase):
ps = 'M 0,0 L 340,-10 L 100,100 L 200,0' ps = 'M 0,0 L 340,-10 L 100,100 L 200,0'
psf = 'M 0.0,0.0 L 340.0,-10.0 L 100.0,100.0 L 200.0,0.0' psf = 'M 0.0,0.0 L 340.0,-10.0 L 100.0,100.0 L 200.0,0.0'
self.assertTrue(parse_path(path).d() in (ps, psf)) self.assertTrue(parse_path(path).d() in (ps, psf))
if __name__ == '__main__':
unittest.main()

View File

@ -1,5 +1,7 @@
# External dependencies # External dependencies
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import zip
from builtins import str
import unittest import unittest
from math import sqrt, pi from math import sqrt, pi
from operator import itemgetter from operator import itemgetter
@ -661,11 +663,11 @@ class TestPath(unittest.TestCase):
class Test_ilength(unittest.TestCase): class Test_ilength(unittest.TestCase):
def test_ilength(self): # See svgpathtools.notes.inv_arclength.py for information on how these
# See svgpathtools.notes.inv_arclength.py for information on how these # test values were generated (using the .length() method).
# test values were generated (using the .length() method). ##############################################################
##############################################################
# Lines def test_ilength_lines(self):
l = Line(1, 3-1j) l = Line(1, 3-1j)
nodall = Line(1+1j, 1+1j) nodall = Line(1+1j, 1+1j)
@ -678,8 +680,7 @@ class Test_ilength(unittest.TestCase):
for (l, t, s) in tests: for (l, t, s) in tests:
self.assertAlmostEqual(l.ilength(s), t) self.assertAlmostEqual(l.ilength(s), t)
############################################################### def test_ilength_quadratics(self):
# Quadratics
q1 = QuadraticBezier(200 + 300j, 400 + 50j, 600 + 300j) q1 = QuadraticBezier(200 + 300j, 400 + 50j, 600 + 300j)
q2 = QuadraticBezier(200 + 300j, 400 + 50j, 500 + 200j) q2 = QuadraticBezier(200 + 300j, 400 + 50j, 500 + 200j)
closedq = QuadraticBezier(6 + 2j, 5 - 1j, 6 + 2j) closedq = QuadraticBezier(6 + 2j, 5 - 1j, 6 + 2j)
@ -716,8 +717,7 @@ class Test_ilength(unittest.TestCase):
print(t) print(t)
raise raise
############################################################### def test_ilength_cubics(self):
# Cubics
c1 = CubicBezier(200 + 300j, 400 + 50j, 600+100j, -200) c1 = CubicBezier(200 + 300j, 400 + 50j, 600+100j, -200)
symc = CubicBezier(1-2j, 10-1j, 10+1j, 1+2j) symc = CubicBezier(1-2j, 10-1j, 10+1j, 1+2j)
closedc = CubicBezier(1-2j, 10-1j, 10+1j, 1-2j) closedc = CubicBezier(1-2j, 10-1j, 10+1j, 1-2j)
@ -741,8 +741,7 @@ class Test_ilength(unittest.TestCase):
for (c, t, s) in tests: for (c, t, s) in tests:
self.assertAlmostEqual(c.ilength(s), t) self.assertAlmostEqual(c.ilength(s), t)
############################################################### def test_ilength_arcs(self):
# Arcs
arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j) arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j)
arc2 = Arc(0j, 100 + 50j, 0, 1, 0, 100 + 50j) arc2 = Arc(0j, 100 + 50j, 0, 1, 0, 100 + 50j)
arc3 = Arc(0j, 100 + 50j, 0, 0, 1, 100 + 50j) arc3 = Arc(0j, 100 + 50j, 0, 0, 1, 100 + 50j)
@ -790,8 +789,7 @@ class Test_ilength(unittest.TestCase):
for (c, t, s) in tests: for (c, t, s) in tests:
self.assertAlmostEqual(c.ilength(s), t) self.assertAlmostEqual(c.ilength(s), t)
############################################################### def test_ilength_paths(self):
# Paths
line1 = Line(600 + 350j, 650 + 325j) line1 = Line(600 + 350j, 650 + 325j)
arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j) arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j)
cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j) cub1 = CubicBezier(650 + 325j, 25 + 25j, -30, 700 + 300j)
@ -890,10 +888,10 @@ class Test_ilength(unittest.TestCase):
(apath, 1.0, 87.81018330500885)] (apath, 1.0, 87.81018330500885)]
for (c, t, s) in tests: for (c, t, s) in tests:
self.assertAlmostEqual(c.ilength(s), t) self.assertAlmostEqual(c.ilength(s), t, msg=str((c, t, s)))
############################################################### # Exceptional Cases
# Exception Cases def test_ilength_exceptions(self):
nodalq = QuadraticBezier(1, 1, 1) nodalq = QuadraticBezier(1, 1, 1)
with self.assertRaises(AssertionError): with self.assertRaises(AssertionError):
nodalq.ilength(1) nodalq.ilength(1)

View File

@ -1,5 +1,6 @@
# External dependencies # External dependencies
from __future__ import division, absolute_import, print_function from __future__ import division, absolute_import, print_function
from builtins import range
import unittest import unittest
from numpy import poly1d from numpy import poly1d
@ -57,11 +58,11 @@ class TestPathTools(unittest.TestCase):
# Input poly1d object # Input poly1d object
bez = poly2bez(p) bez = poly2bez(p)
bpoints = bez.bpoints() bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients # Input list of coefficients
bpoints = poly2bez(pcoeffs, return_bpoints=True) bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
# Case: Quadratic # Case: Quadratic
pcoeffs = [(29.5+15.5j), (-31-19j), (7.5+5.5j)] pcoeffs = [(29.5+15.5j), (-31-19j), (7.5+5.5j)]
@ -71,11 +72,11 @@ class TestPathTools(unittest.TestCase):
# Input poly1d object # Input poly1d object
bez = poly2bez(p) bez = poly2bez(p)
bpoints = bez.bpoints() bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients # Input list of coefficients
bpoints = poly2bez(pcoeffs, return_bpoints=True) bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
# Case: Cubic # Case: Cubic
pcoeffs = [(-18.5-12.5j), (34.5+16.5j), (-18-6j), (6+2j)] pcoeffs = [(-18.5-12.5j), (34.5+16.5j), (-18-6j), (6+2j)]
@ -85,11 +86,11 @@ class TestPathTools(unittest.TestCase):
# Input poly1d object # Input poly1d object
bez = poly2bez(p) bez = poly2bez(p)
bpoints = bez.bpoints() bpoints = bez.bpoints()
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
# Input list of coefficients object # Input list of coefficients object
bpoints = poly2bez(pcoeffs, return_bpoints=True) bpoints = poly2bez(pcoeffs, return_bpoints=True)
self.assertAlmostEquals(distfcn(bpoints, correct_bpoints), 0) self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
def test_bpoints2bezier(self): def test_bpoints2bezier(self):
cubic_bpoints = [(6+2j), 0, (5.5+3.5j), (4+0j)] cubic_bpoints = [(6+2j), 0, (5.5+3.5j), (4+0j)]