@@ -99,30 +99,32 @@ def __copy__(self, *args):
99
99
100
100
def invalidate (self ):
101
101
"""
102
- Invalidate this :class:`TransformNode` and all of its
103
- ancestors. Should be called any time the transform changes.
102
+ Invalidate this :class:`TransformNode` and triggers an
103
+ invalidation of its ancestors. Should be called any
104
+ time the transform changes.
104
105
"""
105
- # If we are an affine transform being changed, we can set the
106
- # flag to INVALID_AFFINE_ONLY
107
- value = (self .is_affine ) and self .INVALID_AFFINE or self .INVALID
106
+ value = self .INVALID
107
+ if self .is_affine :
108
+ value = self .INVALID_AFFINE
109
+ return self ._invalidate_internal (value , invalidating_node = self )
108
110
109
- # Shortcut: If self is already invalid, that means its parents
110
- # are as well, so we don't need to do anything.
111
- if self ._invalid == value :
112
- return
111
+ def _invalidate_internal (self , value , invalidating_node ):
112
+ """
113
+ Called by :meth:`invalidate` and subsequently ascends the transform
114
+ stack calling each TransformNode's _invalidate_internal method.
115
+ """
116
+ # determine if this call will be an extension to the invalidation status
117
+ # if not, then a shortcut means that we needn't invoke an invalidation
118
+ # up the transform stack
119
+ # XXX This makes the invalidation sticky, once a transform has been invalidated as NON_AFFINE
120
+ # too, then it is always NON_AFFINE invalid, even when triggered with a AFFINE_ONLY invalidation.
121
+ status_changed = self ._invalid < value
113
122
114
- if not len ( self ._parents ) :
123
+ if self .pass_through or status_changed :
115
124
self ._invalid = value
116
- return
117
125
118
- # Invalidate all ancestors of self using pseudo-recursion.
119
- stack = [self ]
120
- while len (stack ):
121
- root = stack .pop ()
122
- # Stop at subtrees that have already been invalidated
123
- if root ._invalid != value or root .pass_through :
124
- root ._invalid = self .INVALID
125
- stack .extend (root ._parents .iterkeys ())
126
+ for parent in self ._parents .iterkeys ():
127
+ parent ._invalidate_internal (value = value , invalidating_node = self )
126
128
127
129
def set_children (self , * children ):
128
130
"""
@@ -1251,7 +1253,6 @@ class TransformWrapper(Transform):
1251
1253
of the same dimensions.
1252
1254
"""
1253
1255
pass_through = True
1254
- is_affine = False
1255
1256
1256
1257
def __init__ (self , child ):
1257
1258
"""
@@ -1286,6 +1287,7 @@ def _set(self, child):
1286
1287
self .transform_path_non_affine = child .transform_path_non_affine
1287
1288
self .get_affine = child .get_affine
1288
1289
self .inverted = child .inverted
1290
+ self .is_affine = child .is_affine
1289
1291
1290
1292
def set (self , child ):
1291
1293
"""
@@ -1890,6 +1892,8 @@ def __init__(self, a, b):
1890
1892
self ._b = b
1891
1893
self .set_children (a , b )
1892
1894
1895
+ is_affine = property (lambda self : self ._a .is_affine and self ._b .is_affine )
1896
+
1893
1897
def frozen (self ):
1894
1898
self ._invalid = 0
1895
1899
frozen = composite_transform_factory (self ._a .frozen (), self ._b .frozen ())
@@ -1898,6 +1902,20 @@ def frozen(self):
1898
1902
return frozen
1899
1903
frozen .__doc__ = Transform .frozen .__doc__
1900
1904
1905
+ def _invalidate_internal (self , value , invalidating_node ):
1906
+ # In some cases for a composite transform, an invalidating call to AFFINE_ONLY needs
1907
+ # to be extended to invalidate the NON_AFFINE part too. These cases are when the right
1908
+ # hand transform is non-affine and either:
1909
+ # (a) the left hand transform is non affine
1910
+ # (b) it is the left hand node which has triggered the invalidation
1911
+ if value == Transform .INVALID_AFFINE \
1912
+ and not self ._b .is_affine \
1913
+ and (not self ._a .is_affine or invalidating_node is self ._a ): # note use of is will break when using TransformWrapper
1914
+
1915
+ value = Transform .INVALID
1916
+
1917
+ Transform ._invalidate_internal (self , value = value , invalidating_node = invalidating_node )
1918
+
1901
1919
def _get_is_affine (self ):
1902
1920
return self ._a .is_affine and self ._b .is_affine
1903
1921
is_affine = property (_get_is_affine )
@@ -2229,6 +2247,7 @@ def __init__(self, path, transform):
2229
2247
self ._transformed_points = None
2230
2248
2231
2249
def _revalidate (self ):
2250
+ # only recompute if the invalidation includes the non_affine part of the transform
2232
2251
if ((self ._invalid & self .INVALID_NON_AFFINE == self .INVALID_NON_AFFINE )
2233
2252
or self ._transformed_path is None ):
2234
2253
self ._transformed_path = \
0 commit comments