Rotate transforms now optimize angles, and have test coverage.
This commit is contained in:
parent
45bc6c0fac
commit
5987a9a271
5 changed files with 52 additions and 14 deletions
32
scour.py
32
scour.py
|
|
@ -2328,6 +2328,28 @@ def reducePrecision(element) :
|
||||||
|
|
||||||
return num
|
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):
|
def optimizeTransform(transform):
|
||||||
"""
|
"""
|
||||||
Optimises a series of transformations parsed from a single
|
Optimises a series of transformations parsed from a single
|
||||||
|
|
@ -2401,6 +2423,7 @@ def optimizeTransform(transform):
|
||||||
if len(args) == 2 and args[1] == 0:
|
if len(args) == 2 and args[1] == 0:
|
||||||
del args[1]
|
del args[1]
|
||||||
elif type == 'rotate':
|
elif type == 'rotate':
|
||||||
|
args[0] = optimizeAngle(args[0]) # angle
|
||||||
# Only the angle is required for rotations.
|
# Only the angle is required for rotations.
|
||||||
# If the coordinates are unspecified, it's the origin (0, 0).
|
# If the coordinates are unspecified, it's the origin (0, 0).
|
||||||
if len(args) == 3 and args[1] == args[2] == 0:
|
if len(args) == 3 and args[1] == args[2] == 0:
|
||||||
|
|
@ -2447,14 +2470,7 @@ def optimizeTransform(transform):
|
||||||
elif (currType == prevType == 'rotate'
|
elif (currType == prevType == 'rotate'
|
||||||
and len(prevArgs) == len(currArgs) == 1):
|
and len(prevArgs) == len(currArgs) == 1):
|
||||||
# Only coalesce if both rotations are from the origin.
|
# Only coalesce if both rotations are from the origin.
|
||||||
prevArgs[0] += currArgs[0] # angle
|
prevArgs[0] = optimizeAngle(prevArgs[0] + currArgs[0])
|
||||||
# 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
|
|
||||||
|
|
||||||
del transform[i]
|
del transform[i]
|
||||||
elif currType == prevType == 'scale':
|
elif currType == prevType == 'scale':
|
||||||
prevArgs[0] *= currArgs[0] # x
|
prevArgs[0] *= currArgs[0] # x
|
||||||
|
|
|
||||||
18
testscour.py
18
testscour.py
|
|
@ -1243,9 +1243,9 @@ class TransformRotate90(unittest.TestCase):
|
||||||
|
|
||||||
class TransformRotateCCW135(unittest.TestCase):
|
class TransformRotateCCW135(unittest.TestCase):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-neg-135.svg')
|
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-225.svg')
|
||||||
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-135)',
|
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(225)',
|
||||||
'Counter-clockwise rotation matrix not converted to rotate(-135)')
|
'Counter-clockwise rotation matrix not converted to rotate(225)')
|
||||||
|
|
||||||
class TransformRotateCCW45(unittest.TestCase):
|
class TransformRotateCCW45(unittest.TestCase):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
@ -1277,6 +1277,18 @@ class TransformTranslate(unittest.TestCase):
|
||||||
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'translate(2 3)',
|
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'translate(2 3)',
|
||||||
'Translation matrix not converted to 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):
|
class TransformRotation3Args(unittest.TestCase):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
doc = scour.scourXmlFile('unittests/transform-rotate-fold-3args.svg')
|
doc = scour.scourXmlFile('unittests/transform-rotate-fold-3args.svg')
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 293 B |
5
unittests/transform-rotate-trim-range-719.5.svg
Normal file
5
unittests/transform-rotate-trim-range-719.5.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
|
||||||
|
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="rotate(719.5)"/>
|
||||||
|
<!-- all rotation angles can be mapped to the shorter range [-90, 270[ -->
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 289 B |
5
unittests/transform-rotate-trim-range-neg-540.0.svg
Normal file
5
unittests/transform-rotate-trim-range-neg-540.0.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
|
||||||
|
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="rotate(-540.0) rotate(0)"/>
|
||||||
|
<!-- all rotation angles can be mapped to the shorter range [-90, 270[ -->
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 300 B |
Loading…
Add table
Add a link
Reference in a new issue