### 8.12. `Xform.__analyze()`: Find the three components of self

This service method is called by the `.offset()`, `.angle()`, and `.mag()` methods to analyze the transform into its component parts. The first time it is called, it stores the three components into attributes `.__offset`, `.__angle`, and `.__mag`. Succeeding calls do nothing because the values don't change.

homcoord.py
```# - - -   X f o r m . _ _ a n a l y z e

def __analyze(self):
'''Compute self's net translation, rotation, and scaling.

[ if self.__offset is None ->
self.__offset  :=  net translation of self as a Pt
self.__angle  :=  net rotation of self
self.__mag  :=  net uniform scaling of self
else -> I ]
'''
```

The constructor initializes `self.__offset` to `None`, so if that attribute no longer has that value, this method has already been called, and the results have already been memoized.

homcoord.py
```        #-- 1 --
if self.__offset is not None:
return
```

To analyze the effects of a transform, we apply it to the origin and to `self.UNIT`, which is the point at a distance 1.0 along the line `x=y`.

• The translation component is the amount that the origin moves.

• Because the line from `self.ORIGIN` to `self.UNIT` has bearing 45° by definition, the rotational component of the transform is the bearing of that line after transformation, minus 45°, normalized.

• Because the distance from `self.ORIGIN` to `self.UNIT` has length 1, the uniform scaling component of the transform is the distance between those points after their transformation.

homcoord.py
```        #-- 2 --
oPrime = self.apply ( self.ORIGIN )
uPrime = self.apply ( self.UNIT )

#-- 3 --
# [ self.__offset  :=  distance from origin to oPrime
#   self.__angle  :=  (bearing from oPrime to uPrime) -