PROBLEMS:

(1) Reflection is sucky

Reflection is currently hard to use for several reasons:
    a)  The user has to calculate a reflection transformation that depends
        on the position of the reflection surface
    b)  The translation mechanism for the reflection surface is different to
        everywhere else
    c)  The reflection surface can't be moved (relative to the reflected 
        objects) after definition

(2) Nested paths and transformations require nested Containers

Not only is this painful to set up; it is impossible for reflection surfaces
because only one ITransform slot exists.  There is also a potential
performance argument

(3) Transform / Path application order is non-obvious.

Which should come first, if a transform and a path are installed in the some
container?  Currently transforms do, but there is no reasons why paths
shouldn't.

(4) The only existing ITransform object (PyTransform) is non-obvious.

I tried to spec this to get the effects _I_ expected from composing a
translation, a rotation, and a scale.  Currently, the translation is
applied, then the scale, then the rotation.  Why should things happen in
THIS order, in particular?

(I had my reasons: in this way, a translation moves to a _particular_ spot
from the origin, without being effected by the rotation, and the scale
doesn't result in a skew.  But what if someone _wants_ a skew?)

SOLUTIONS:

(1) Autocalculate the reflection transformation.

This is possible, IF:
    a)  The reflection surface is forced to be defined in a given location
        (e.g. on the plane defined by z = 0), and transformed into place
    b)  All transforms are invertible

The required calculation is then T.R.T^(-1)

Where R is the "Reflection matrix" = 
    ( 1  0  0  0 )
    ( 0  1  0  0 )
    ( 0  0 -1  0 )
    ( 0  0  0  1 )

(2) Unify the IPath and ITransform interfaces.  This, along with the
inversion requirement, leads to an interface along the lines of:

    TransformByMe(IPath, time)
    InvertByMe(IPath, time)
    RegisterSize(IPath)
    Register(IPath, registration_obj)
    DeRegister(IPath, deregistration_obj)

The register functions already exist in the IPath interface, and are
required to allow multiple objects to follow the same path.  They are not
needed for ITransforms, so a rule of this interface would be that a
RegisterSize() of 0 implies no registration step requirement.  However,
calling Register or DeRegister should not cause problems in such objects.

This interface leads to a further problem - determining the inverse of a
path is trivial given the forward transform (and vice versa), but there is
no guarantee concerning which transform will be required first.

In particular, during normal transformation, _only_ the forward transform is
required.  However, during reflection, the inverse transform is required
_first_.

One solution to this problem is to provide a more unified interface:

GenerateTransform(IPath, time, <gen_forward>, <gen_reverse>, <apply>)

where gen_forward is 1 if the forward transform is needed, gen_reverse is 1
if the reverse transform is needed, and apply is -1 if the inverse is to be
applied 1 if the forward transform is to be applied, and 0 if no transform
is to be applied.

The register functions would still be required.

(3) Allow arbitrary nesting of ITransforms.  Transform application is in
REVERSE order. i.e. the deepest transform occurs first.
<<< QUESTION: Is branching required / sensible? >>>

This means that performing:

a = Transform(stuff)
b = Transform(more stuff)
c = a * b
apply(c)

gives the same effect as:

a = Transform(stuff)
b = Transform(more stuff)
a.append(b)
apply(a)

(4) Provide a new type, PyMatrix, that allows arbitrary composition of
Translations, Rotations and Scales.  This is largely done.
