diff --git a/scour.py b/scour.py
index 6ad1c58..3be9f80 100755
--- a/scour.py
+++ b/scour.py
@@ -1482,11 +1482,11 @@ def mayContainTextNodes(node):
result = True
# Blacklisted elements. Those are guaranteed not to be text elements.
elif node.nodeName in ['rect', 'circle', 'ellipse', 'line', 'polygon',
- 'polyline', 'path', 'image', 'stop']:
+ 'polyline', 'path', 'image', 'stop']:
result = False
# Group elements. If we're missing any here, the default of True is used.
elif node.nodeName in ['g', 'clipPath', 'marker', 'mask', 'pattern',
- 'linearGradient', 'radialGradient', 'symbol']:
+ 'linearGradient', 'radialGradient', 'symbol']:
result = False
for child in node.childNodes:
if mayContainTextNodes(child):
@@ -2110,7 +2110,7 @@ def parseListOfPoints(s):
nums = []
# also, if 100-100 is found, split it into two also
- #
+ #
for i in xrange(len(ws_nums)):
negcoords = ws_nums[i].split("-")
@@ -2328,6 +2328,28 @@ def reducePrecision(element) :
return num
+def optimizeAngle(angle):
+ """
+ Because any rotation can be expressed within 360 degrees
+ of any given number, and since negative angles sometimes
+ are one character longer than corresponding positive angle,
+ we shorten the number to one in the range to [-90, 270[.
+ """
+ # First, we put the new angle in the range ]-360, 360[.
+ # The modulo operator yields results with the sign of the
+ # divisor, so for negative dividends, we preserve the sign
+ # of the angle.
+ if angle < 0: angle %= -360
+ else: angle %= 360
+ # 720 degrees is unneccessary, as 360 covers all angles.
+ # As "-x" is shorter than "35x" and "-xxx" one character
+ # longer than positive angles <= 260, we constrain angle
+ # range to [-90, 270[ (or, equally valid: ]-100, 260]).
+ if angle >= 270: angle -= 360
+ elif angle < -90: angle += 360
+ return angle
+
+
def optimizeTransform(transform):
"""
Optimises a series of transformations parsed from a single
@@ -2401,6 +2423,7 @@ def optimizeTransform(transform):
if len(args) == 2 and args[1] == 0:
del args[1]
elif type == 'rotate':
+ args[0] = optimizeAngle(args[0]) # angle
# Only the angle is required for rotations.
# If the coordinates are unspecified, it's the origin (0, 0).
if len(args) == 3 and args[1] == args[2] == 0:
@@ -2447,14 +2470,7 @@ def optimizeTransform(transform):
elif (currType == prevType == 'rotate'
and len(prevArgs) == len(currArgs) == 1):
# Only coalesce if both rotations are from the origin.
- prevArgs[0] += currArgs[0] # angle
- # Put the new angle in the range ]-360, 360[.
- # The modulo operator yields results with the sign of the
- # divisor, so for negative dividends, we preserve the sign
- # of the angle.
- if prevArgs[0] < 0: prevArgs[0] = prevArgs[0] % -360
- else: prevArgs[0] = prevArgs[0] % 360
-
+ prevArgs[0] = optimizeAngle(prevArgs[0] + currArgs[0])
del transform[i]
elif currType == prevType == 'scale':
prevArgs[0] *= currArgs[0] # x
diff --git a/testscour.py b/testscour.py
index f5084d8..8da5566 100755
--- a/testscour.py
+++ b/testscour.py
@@ -1243,9 +1243,9 @@ class TransformRotate90(unittest.TestCase):
class TransformRotateCCW135(unittest.TestCase):
def runTest(self):
- doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-neg-135.svg')
- self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-135)',
- 'Counter-clockwise rotation matrix not converted to rotate(-135)')
+ doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-225.svg')
+ self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(225)',
+ 'Counter-clockwise rotation matrix not converted to rotate(225)')
class TransformRotateCCW45(unittest.TestCase):
def runTest(self):
@@ -1277,6 +1277,18 @@ class TransformTranslate(unittest.TestCase):
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'translate(2 3)',
'Translation matrix not converted to translate(2 3)')
+class TransformRotationRange719_5(unittest.TestCase):
+ def runTest(self):
+ doc = scour.scourXmlFile('unittests/transform-rotate-trim-range-719.5.svg')
+ self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-.5)',
+ 'Transform containing rotate(719.5) not shortened to rotate(-.5)')
+
+class TransformRotationRangeCCW540_0(unittest.TestCase):
+ def runTest(self):
+ doc = scour.scourXmlFile('unittests/transform-rotate-trim-range-neg-540.0.svg')
+ self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(180)',
+ 'Transform containing rotate(-540.0) not shortened to rotate(180)')
+
class TransformRotation3Args(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-rotate-fold-3args.svg')
diff --git a/unittests/transform-matrix-is-rotate-neg-135.svg b/unittests/transform-matrix-is-rotate-225.svg
similarity index 100%
rename from unittests/transform-matrix-is-rotate-neg-135.svg
rename to unittests/transform-matrix-is-rotate-225.svg
diff --git a/unittests/transform-rotate-trim-range-719.5.svg b/unittests/transform-rotate-trim-range-719.5.svg
new file mode 100644
index 0000000..f0bb947
--- /dev/null
+++ b/unittests/transform-rotate-trim-range-719.5.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/unittests/transform-rotate-trim-range-neg-540.0.svg b/unittests/transform-rotate-trim-range-neg-540.0.svg
new file mode 100644
index 0000000..3e857f6
--- /dev/null
+++ b/unittests/transform-rotate-trim-range-neg-540.0.svg
@@ -0,0 +1,5 @@
+
+