5 Affine Transformations
An affine transformation is a mapping from one coordinate system onto
another that preserves straight lines. In other words, if you take a number of
points that fall on a straight line and apply an affine transformation to their
coordinates, the transformed coordinates will describe a straight line in the
new coordinate system. General affine transformations include all the sorts of
transformations that CLIM uses, namely, translations, scaling, rotations, and
reflections.
5.1 Transformations
| transformation | [Protocol Class] |
The protocol class of all transformations. There are one or more subclasses of
transformation with implementation-dependent names that implement
transformations. The exact names of these classes is explicitly unspecified.
If you want to create a new class that behaves like a transformation, it should be a subclass of transformation. Subclasses of transformation must obey the transformation protocol.All of the instantiable transformation classes provided by CLIM are immutable.
| transformationp | object | [Predicate] |
Returns true if object is a transformation , otherwise
returns false .
| +identity-transformation+ | [Constant] |
An instance of a transformation that is guaranteed to be an identity
transformation, that is, the transformation that ``does nothing''.
5.1.1 Transformation Conditions
| transformation-error | [Error] |
The class that is the superclass of the following three conditions. This class
is a subclass of error .
| transformation-underspecified | [Error] |
The error that is signalled when make-3-point-transformation is given three
collinear image points. This condition will handle the :points initarg,
which is used to supply the points that are in error.
| reflection-underspecified | [Error] |
The error that is signalled when make-reflection-transformation is given
two coincident points. This condition will handle the :points initarg,
which is used to supply the points that are in error.
| singular-transformation | [Error] |
The error that is signalled when invert-transformation is called on a
singular transformation, that is, a transformation that has no inverse. This
condition will handle the :transformation initarg, which is used to supply
the transformation that is singular.
5.2 Transformation Constructors
The following transformation constructors do not capture any of their inputs.
The constructors all create objects that are subclasses of transformation .
| make-translation-transformation | translation-x translation-y | [Function] |
A translation is a transformation that preserves length, angle, and orientation
of all geometric entities.
make-translation-transformation returns a transformation that translates
all points by translation-x in the x direction and translation-y in the y direction. translation-x and translation-y must be real
numbers.
| make-rotation-transformation | angle &optional origin | [Function] |
| make-rotation-transformation* | angle &optional origin-x origin-y | [Function] |
A rotation is a transformation that preserves length and angles of all geometric
entities. Rotations also preserve one point (the origin) and the distance of
all entities from that point.
make-rotation-transformation returns a transformation that rotates all
points by angle (which is a real number indicating an angle in radians)
around the point origin . If origin is supplied it must be a point;
if not supplied it defaults to (0,0). origin-x and origin-y must
be real numbers, and default to 0.
| make-scaling-transformation | scale-x scale-y &optional origin | [Function] |
| make-scaling-transformation* | scale-x scale-y &optional origin-x origin-y | [Function] |
There is no single definition of a scaling transformation. Transformations that
preserve all angles and multiply all lengths by the same factor (preserving the
``shape'' of all entities) are certainly scaling transformations. However,
scaling is also used to refer to transformations that scale distances in the x
direction by one amount and distances in the y direction by another amount.
make-scaling-transformation returns a transformation that multiplies the
x-coordinate distance of every point from origin by scale-x and
the y-coordinate distance of every point from origin by scale-y .
scale-x and scale-y must be real numbers. If origin is
supplied it must be a point; if not supplied it defaults to (0,0).
origin-x and origin-y must be real numbers, and default to 0.
| make-reflection-transformation | point1 point2 | [Function] |
| make-reflection-transformation* | x1 y1 x2 y2 | [Function] |
A reflection is a transformation that preserves lengths and magnitudes of
angles, but changes the sign (or ``handedness'') of angles. If you think of the
drawing plane on a transparent sheet of paper, a reflection is a transformation
that ``turns the paper over''.
make-reflection-transformation returns a transformation that reflects every
point through the line passing through the points point1 and
point2 (or through the positions (x1,y1) and (x2,y2) in the case of
the spread version).
| make-transformation | mxx mxy myx myy tx ty | [Function] |
Returns a general transformation whose effect is:
| x' = | mxx x + mxy y + tx |
| y' = | myx x + myy y + ty |
where x and y are the coordinates of a point before the transformation and
x' and y' are the coordinates of the corresponding point after.
All of the arguments to make-transformation must be real numbers.
| make-3-point-transformation | point-1 point-2 point-3 point-1-image point-2-image point-3-image | [Function] |
Returns a transformation that takes points point-1 into
point-1-image , point-2 into point-2-image and point-3 into point-3-image . Three non-collinear points and their images under the
transformation are enough to specify any affine transformation.
If point-1 , point-2 and point-3 are collinear, the
transformation-underspecified error will be signalled. If
point-1-image , point-2-image and point-3-image are collinear,
the resulting transformation will be singular (that is, will have no inverse)
but this is not an error.
| make-3-point-transformation* | x1 y1 x2 y2 x3 y3 x1-image y1-image x2-image y2-image x3-image y3-image | [Function] |
Returns a transformation that takes the points at the positions
(x1 ,y1 ) into (x1-image ,y1-image ), (x2 ,y2 )
into (x2-image ,y2-image ) and (x3 ,y3 ) into
(x3-image ,y3-image ). Three non-collinear points and their images
under the transformation are enough to specify any affine transformation.
If the positions (x1,y1), (x2,y2) and (x3,y3) are collinear, the
transformation-underspecified error will be signalled. If
(x1-image ,y1-image ), (x2-image ,y2-image ), and
(x3-image ,y3-image ) are collinear, the resulting transformation will
be singular but this is not an error.
This is the spread version of make-3-point-transformation .
5.3 The Transformation Protocol
The following subsections describe the transformation protocol. All classes
that are subclasses of transformation must implement methods for all of
the generic functions in the following subsections.
5.3.1 Transformation Predicates
In all of the functions below, the argument named transformation must be a
transformation.
| transformation-equal | transformation1 transformation2 | [Generic function] |
Returns true if the two transformations transformation1 and
transformation2 have equivalent effects (that is, are mathematically
equal), otherwise returns false .
Implementations are encouraged to allow transformations that are not numerically
equal due to floating-point roundoff errors to be transformation-equal . An
appropriate level of ``fuzziness'' is single-float-epsilon , or some small
multiple of single-float-epsilon .
| identity-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation is equal
(in the sense of transformation-equal ) to the identity transformation,
otherwise returns false .
| invertible-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation has an
inverse, otherwise returns false .
| translation-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation is a pure
translation, that is, a transformation such that there are two distance
components dx and dy and every point (x,y) is moved to (x+dx,y+dy).
Otherwise, translation-transformation-p returns false .
| reflection-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation inverts
the ``handedness'' of the coordinate system, otherwise returns false .
Note that this is a very inclusive category---transformations are considered
reflections even if they distort, scale, or skew the coordinate system, as long
as they invert the handedness.
| rigid-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation transforms
the coordinate system as a rigid object, that is, as a combination of
translations, rotations, and pure reflections. Otherwise, it returns
false .
Rigid transformations are the most general category of transformations that
preserve magnitudes of all lengths and angles.
| even-scaling-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation multiplies
all x lengths and y lengths by the same magnitude, otherwise returns
false . It does include pure reflections through vertical and horizontal
lines.
| scaling-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation multiplies
all x lengths by one magnitude and all y lengths by another magnitude,
otherwise returns false . This category includes even scalings as a
subset.
| rectilinear-transformation-p | transformation | [Generic function] |
Returns true if the transformation transformation will
always transform any axis-aligned rectangle into another axis-aligned rectangle,
otherwise returns false . This category includes scalings as a subset,
and also includes 90 degree rotations.
Rectilinear transformations are the most general category of transformations for
which the bounding rectangle of a transformed object can be found by
transforming the bounding rectangle of the original object.
Issue: SWM
Supply this figure.
To be supplied.
Figure 5.1: The predicates for analyzing the mathematical properties of a transformation.
5.3.2 Composition of Transformations
If we transform from one coordinate system to another, then from the second to a
third coordinate system, we can regard the resulting transformation as a single
transformation resulting from composing the two component
transformations. It is an important and useful property of affine transformations
that they are closed under composition. Note that composition is not commutative;
in general, the result of applying transformation A and then applying
transformation B is not the same as applying B first, then A.
Any arbitrary transformation can be built up by composing a number of simpler
transformations, but that composition is not unique.
| compose-transformations | transformation1 transformation2 | [Generic function] |
Returns a transformation that is the mathematical composition of its arguments.
Composition is in right-to-left order, that is, the resulting transformation
represents the effects of applying the transformation transformation2 followed by the transformation transformation1 .
| invert-transformation | transformation | [Generic function] |
Returns a transformation that is the inverse of the transformation transformation . The result of composing a transformation with its inverse
is equal to the identity transformation.
If transformation is singular, invert-transformation will signal the
singular-transformation error, with a named restart that is invoked with a
transformation and makes invert-transformation return that transformation.
This is to allow a drawing application, for example, to use a generalized
inverse to transform a region through a singular transformation.
Note that with finite-precision arithmetic there are several low-level
conditions that might occur during the attempt to invert a singular or ``almost
singular'' transformation. (These include computation of a zero determinant,
floating-point underflow during computation of the determinant, or
floating-point overflow during subsequent multiplication.)
invert-transformation must signal the singular-transformation error
for all of these cases.
| compose-translation-with-transformation | transformation dx dy | [Function] |
| compose-scaling-with-transformation | transformation sx sy &optional origin | [Function] |
| compose-rotation-with-transformation | transformation angle &optional origin | [Function] |
These functions create a new transformation by composing the
transformation transformation with a given translation, scaling, or
rotation, respectively. The order of composition is that the translation,
scaling, or rotation ``transformation'' is first, followed by
transformation .
dx and dy are as for make-translation-transformation .
sx and sy are as for make-scaling-transformation .
angle and origin are as for make-rotation-transformation .
Note that these functions could be implemented by using the various constructors
and compose-transformations . They are provided, because it is common to
build up a transformation as a series of simple transformations.
| compose-transformation-with-translation | transformation dx dy | [Function] |
| compose-transformation-with-scaling | transformation sx sy &optional origin | [Function] |
| compose-transformation-with-rotation | transformation angle &optional origin | [Function] |
These functions create a new transformation by composing a given translation,
scaling, or rotation, respectively, with the transformation transformation . The order of composition is transformation is
first, followed by the translation, scaling, or rotation ``transformation''.
dx and dy are as for make-translation-transformation .
sx and sy are as for make-scaling-transformation .
angle and origin are as for make-rotation-transformation .
Note that these functions could be implemented by using the various constructors
and compose-transformations . They are provided, because it is common to
build up a transformation as a series of simple transformations.
5.3.3 Applying Transformations
Transforming a region applies a coordinate transformation to that region, thus
moving its position on the drawing plane, rotating it, or scaling it. Note that
transforming a region does not side-effect the region argument; it is free
to either create a new region or return an existing (cached) region.
These generic functions must be implemented for all classes of transformations.
Furthermore, all subclasses of region and design must implement
methods for transform-region and untransform-region . That is, methods
for the following generic functions will typically specialize both the
transformation and region arguments.
Note that, if the extended region classes are not implemented, the following
functions are not closed, that is, they may return results that are not CLIM
regions.
| transform-region | transformation region | [Generic function] |
Applies transformation to the region region , and returns the
transformed region.
| untransform-region | transformation region | [Generic function] |
This is exactly equivalent to
(transform-region (invert-transformation transformation )
region ) .
CLIM provides a default method for untransform-region on the
transformation protocol class that does exactly this.
| transform-position | transformation x y | [Generic function] |
Applies the transformation transformation to the point whose
coordinates are the real numbers x and y , and returns two values,
the transformed x coordinate and the transformed y coordinate.
transform-position is the spread version of transform-region in the
case where the region is a point.
| untransform-position | transformation x y | [Generic function] |
This is exactly equivalent to
(transform-position (invert-transformation transformation )
x y ) .
CLIM provides a default method for untransform-position on the
transformation protocol class that does exactly this.
| transform-distance | transformation dx dy | [Generic function] |
Applies the transformation transformation to the distance
represented by the real numbers dx and dy , and returns two values,
the transformed dx and the transformed dy .
A distance represents the difference between two points. It does not
transform like a point.
| untransform-distance | transformation dx dy | [Generic function] |
This is exactly equivalent to
(transform-distance (invert-transformation transformation )
dx dy ) .
CLIM provides a default method for untransform-distance on the
transformation protocol class that does exactly this.
| transform-rectangle* | transformation x1 y1 x2 y2 | [Generic function] |
Applies the transformation transformation to the rectangle
specified by the four coordinate arguments, which are real numbers. The
arguments x1 , y1 , x2 , and y1 are canonicalized in the
same way as for make-bounding-rectangle . Returns four values that specify
the minimum and maximum points of the transformed rectangle in the order
min-x , min-y , max-x , and max-y .
It is an error is transformation does not satisfy
rectilinear-transformation-p .
transform-rectangle* is the spread version of transform-region in the
case where the transformation is rectilinear and the region is a rectangle.
| untransform-rectangle* | transformation x1 y1 x2 y2 | [Generic function] |
This is exactly equivalent to
(transform-rectangle* (invert-transformation transformation )
x1 y1 x2 y2 ) .
CLIM provides a default method for untransform-rectangle* on the
transformation protocol class that does exactly this.