@c gstranpt.texi
 
@c This file is part of the 3DLDF User and Reference Manual.
@c Copyright (C) 2003, 2004 Laurence D. Finston 
@c See the section "GNU Free Documentation License" in the file 
@c fdl.texi for copying conditions.

@c $Id: gstranpt.texi,v 1.6 2004/01/12 18:38:48 lfinsto1 Exp lfinsto1 $

@node Transforming Points, Transforms, Points, Top
@chapter Transforming Points

@code{Points} don't always have to remain in the same place.  There are
various ways of moving or @emph{transforming} them:
@itemize @bullet
@item
Shifting.  This is often called ``translating'', but the operation in Metafont
that performs translation is called @code{shift}, so I call it ``shifting''.

@item
Scaling.

@item
Shearing.

@item
Rotating about an axis.

@end itemize

@code{class Point} has several member functions 
for applying these @dfn{affine transformations}@c
@c
@footnote{@dfn{Affine transformations} are operations 
that have the property that parallelity of
lines is maintained.  That is, if two lines (each determined by two
points) are parallel before the transformation, they will also be
parallel after 
the transformation.  Affine transformations are discussed in many books
about computer graphics and geometry.  For 3DLDF, I've mostly used
Jones, @cite{Computer Graphics through Key Mathematics}  and Salomon, 
@cite{Computer Graphics and Geometric Modeling}.}
@c
to a @code{Point}.
@c
Most of the arguments to these functions are of 
type @code{real}.  As you may know, there is no such data type in @cpp{}.
I have defined @code{real} using @code{typedef} to be either
@code{float} or @code{double}, depending on the value of a preprocessor 
switch for conditional compilation.@c
@c
@footnote{I try to avoid the use of
preprocessor macros as much as possible, for the reasons given by
Stroustrup in the @cite{The @cpp{} Programming Language}, 
@SECT{}7.8, 
pp.@: 160--163, and 
@cite{Design and Evolution of @cpp{}}, Chapter 18, pp.@: 423--426.  
However, conditional compilation is one of
the tasks that only the preprocessor can perform.}
@c
3DLDF uses many @code{real} values and I wanted to be able to
change the precision used by making one change (in the file
@file{pspglb.web}) rather than having to examine all the places in the
program where @code{float} or @code{double} are used.  Unfortunately,
setting @code{real} to @code{double} currently doesn't work.

@menu
* Shifting Points::             
* Scaling Points::              
* Shearing Points::             
* Rotating Points::             
@end menu

@node Shifting Points, Scaling Points, Transforming Points, Transforming Points
@section Shifting

The function 
@code{shift()} 
adds its arguments to the corresponding 
@code{world_coordinates} of a @code{Point}.  In the following example, 
the function @code{show()} is used to print the @code{world_coordinates}
of @code{p0} to standard output.

@example
Point p0(0, 0, 0);
p0.shift(1, 2, 3);
p0.show("p0:");
@print{} p0: (1, 2, 3)
p0.shift(10);
p0.show("p0:");
@print{} p0: (11, 2, 3)
p0.shift(0, 20);
p0.show("p0:");
@print{} p0: (11, 22, 3)
p0.shift(0, 0, 30);
p0.show("p0:");
@print{} p0: (11, 22, 33)
@end example

@noindent
@code{shift} takes three @code{real} arguments, whereby the second and
third are optional.  To shift a @code{Point} in the direction of 
the positive or negative y-axis, and/or the positive or negative z-axis
only, then a 0 argument for the 
x direction, and possibly one for the y direction 
must be used as placeholders, as in the example above. 

@code{shift()} can be invoked with a @code{Point} argument
instead of @code{real} arguments.  In this case, the x, y, and
z-coordinates of the argument are used for shifting the @code{Point}:

@example
Point a(10, 10, 10);
Point b(1, 2, 3);
a.shift(b);
a.show("a:")
@print{} a: (11, 12, 13)
@end example

Another way of shifting @code{Points} is to use the binary @code{+=} 
operator (@code{Point::operator+=()})  with a @code{Point}
argument.

@example
Point a0(1, 1, 1);
Point a1(2, 2, 2);
a0 += a1;
a0.show("a0:");
@print{} a0: (3, 3, 3)
@end example

@node Scaling Points, Shearing Points, Shifting Points, Transforming Points
@section Scaling

The function @code{scale()} takes three @code{real} arguments.  
The x, y, and z-coordinates of the @code{Point} are 
multiplied by the first, second, and third arguments respectively.  Only
the first argument is required;  the default for the others is 1.

If one wants to perform scaling in either the y-dimension only, or the y
and z-dimensions only, a dummy argument of 1 must be passed for
scaling in the x-dimension.  Similarly, if one wants to perform scaling
in the z-dimension only, dummy arguments of 1 must be passed for scaling
in the x and y-dimensions.

@example
Point p0(1, 2, 3);
p0.scale(2, 3, 4);
p0.show("p0:");
@print{} p0: (2, 6, 12)
p0.scale(2);
p0.show("p0:");
@print{} p0: (4, 6, 12)
p0.scale(1, 3);
p0.show("p0:");
@print{} p0: (4, 18, 12)
p0.scale(1, 1, 3);
p0.show("p0:");
@print{} p0: (4, 18, 36)
@end example


@node Shearing Points, Rotating Points, Scaling Points, Transforming Points
@section Shearing

Shearing is more complicated than shifting or scaling.  The function
@code{shear()} takes six @code{real} arguments.
If @math{p} is a @code{Point}, then @code{p.shear(a, b, c, d, e, f)} sets
@math{x_p} to @math{x_p + ay_p + bz_p}, @math{y_p} to 
@math{y_p + cx_p + dz_p}, and  
@math{z_p} to @math{z_p + ex_p + fy_p}.
In this way, each coordinate of a @code{Point} is modified based on the
values of the other two coordinates, whereby the influence of the
other coordinates on the new value is weighted according to the
arguments. 

@example
Point p(1, 1, 1);
p.shear(1);
p.show("p:");
@print{} p: (2, 1, 1)
p.set(1, 1, 1);
p.shear(1, 1);
p.show("p:");
@print{} p: (3, 1, 1)
p.set(1, 1, 1);
p.shear(1, 1, 2, 2, 3, 3);
p.show("p:");
@print{} p: (3, 5, 7)
@end example


@c I've copied the following example from 
@c the node ``Affine Transformations for Points''.
@c
@NEXTFIG{} demonstrates the effect of shearing the points of a rectangle
in the x-y plane.

@example
Point P0;
Point P1(3);
Point P2(3, 3);
Point P3(0, 3);
Rectangle r(p0, p1, p2, p3);
r.draw();
Rectangle q(r);
q.shear(1.5);
q.draw(black, "evenly");
@end example

@iftex
@tex 
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Point P0;}
\immediate\write\examples{Point P1(3);}
\immediate\write\examples{Point P2(3, 3);}
\immediate\write\examples{Point P3(0, 3);}
\immediate\write\examples{Rectangle r(P0, P1, P2, P3);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{r.get_point(0).dotlabel("$P_0$ = $Q_0$ = (0, 0)", "llft");}
\immediate\write\examples{r.get_point(1).dotlabel("$P_1$ = $Q_1$ = (3, 0)", "lrt");}
\immediate\write\examples{r.get_point(2).dotlabel("$P_2$ = (3, 3)", "ulft");}
\immediate\write\examples{r.get_point(3).dotlabel("$P_3$ = (0, 3)", "ulft");}
\immediate\write\examples{r.get_center().label("$r$", "");} 
\immediate\write\examples{Rectangle q(r);}
\immediate\write\examples{q.shear(1.5);}  
\immediate\write\examples{Point q_center(q.get_center());} 
\immediate\write\examples{q_center.label("$q$", "");} 
\immediate\write\examples{q.get_point(2).dotlabel("$Q_2$ = (7.5, 3)");}
\immediate\write\examples{q.get_point(3).dotlabel("$Q_3$ = (4.5, 3)");}
\immediate\write\examples{q.draw(black, "evenly");}
\OEX{Projections::PARALLEL_X_Y}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

@ifhtml
@html
<p align="center">
<br>
<img src="./graphics/png/3DLDFmp.1.png"
alt="[Figure 1. Not displayed.]"
/>
<br>
<br>
Fig. 1.
<br>
</p>
@end html
@end ifhtml

@ifinfo
[Figure 1 not displayed.]
@end ifinfo

@node Rotating Points,  , Shearing Points, Transforming Points
@section Rotating

@c !! TO DO:  Make illustration. 

The function @code{rotate()} rotates a @code{Point} about one or more of
the main axes.
It takes three @code{real} arguments, specifying the 
angles of rotation in degrees about the x, y, and z-axes respectively.
Only the first argument is required, the other two are 0 by default.  If
rotation about the y-axis, or the y and z-axes only are required, then 0
must be used as a placeholder for the first and possibly the second
argument.  

@example
Point p(0, 1);
p.rotate(90);
p.show("p:");
@print{} p: (0, 0, -1)
p.rotate(0, 90);
p.show("p:");
@print{} p: (1, 0, 0)
p.rotate(0, 0, 90);
p.show("p:");
@print{} p: (0, 1, 0)
@end example

The rotations are performed successively about the 
x, y, and z-axes.  However, rotation is not a commutative
operation, so if rotation about the main axes in a different
order is required, then @code{rotate()} must be invoked more than once:

@example
Point A(2, 3, 4);
Point B(A);
A.rotate(30, 60, 90);
A.show("A:");
@print{} A: (-4.59808, -0.700962, 2.7141)
B.rotate(0, 0, 90);
B.rotate(0, 60);
B.rotate(30);
B.show("B:");
@print{} B: (-4.9641, 1.43301, -1.51795)
@end example
 
Rotation need not be about the main axes;  it can also be performed
about a line defined by two @code{Points}.  The function @code{rotate()}
with two @code{Point} arguments and a @code{real} argument for the
angle of rotation (in degrees) about the axis.  The @code{real} argument
is optional, with 
@DEG{180}
as the default.

@c !! TO DO:  Simplify this example.  How did I get the original values
@c for @code{p0} and @code{p1}? 
@c Make illustration larger, put values in illustration.

@example
Point p0 (-1.06066, 0, 1.06066);
Point p1 (1.06066, 0, -1.06066);
p1 *= p0.rotate(0, 30, 30);
p0.show("p0:");
@print{} p0: (-1.25477, -0.724444, 0.388228)
p1.show("p1:");
@print{} p1: (1.25477, 0.724444, -0.388228)
p0.draw(p1);
Point p2(1.06066, 0, 1.06066);
p2.show("p2:");
@print{} p2: (1.06066, 0, 1.06066)
Point p3(p2);
p3.rotate(p1, p0, 45);
p3.show("p3:");
@print{} p3 (1.09721, 1.15036, 1.17879)
Point p4(p2);
p4.rotate(p1, p0, 90);
p4.show("p4:"); 
@print{} p4: (0.882625, 2.05122, 0.485242)
Point p5(p2);
p5.rotate(p1, p0, 135);
p5.show("p5:");
@print{} p5: (0.542606, 2.17488, -0.613716)
Point p6(p2);
p6.rotate(p1, p0);
p6.show("p6:");
@print{} p6: (0.276332, 1.44889, -1.47433)
@end example

@iftex
@tex  
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(4, 5, -10, 4, 5, 10, 10);}
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{Point p0 (-1.06066, 0, 1.06066);}
\immediate\write\examples{Point p1 (1.06066, 0, -1.06066);}
\immediate\write\examples{p1 *= p0.rotate(0, 30, 30);}
\immediate\write\examples{p0.dotlabel("p0", "lft"); }
\immediate\write\examples{p1.dotlabel("p1"); }
\immediate\write\examples{p0.draw(p1);}
\immediate\write\examples{Point p2(1.06066, 0, 1.06066);}
\immediate\write\examples{p2.dotlabel("p2", "rt"); }
\immediate\write\examples{Point p3(p2);}
\immediate\write\examples{p3.rotate(p1, p0, 45);}
\immediate\write\examples{p3.dotlabel("p3", "rt"); }
\immediate\write\examples{Point p4(p2);}
\immediate\write\examples{p4.rotate(p1, p0, 90);}
\immediate\write\examples{p4.dotlabel("p4"); }
\immediate\write\examples{Point p5(p2);}
\immediate\write\examples{p5.rotate(p1, p0, 135);}
\immediate\write\examples{p5.dotlabel("p5"); }
\immediate\write\examples{Point p6(p2);}
\immediate\write\examples{p6.rotate(p1, p0);}
\immediate\write\examples{p6.dotlabel("p6", "lft"); }
\immediate\write\examples{Path pa("..", false, &p2, &p3, &p4, &p5, &p6, 0);}
\immediate\write\examples{pa.draw();}
\OEX{}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

@ifhtml
@html
<p align="center">
<br>
<img src="./graphics/png/3DLDFmp.2.png"
alt="[Figure 2. Not displayed.]"
/>
<br>
<br>
Fig. 2.
<br>
</p>
@end html
@end ifhtml

@ifinfo
[Figure 2 not displayed.]
@end ifinfo

@cindex bugs 
I have sometimes gotten erroneous results using @code{rotate()} for
rotation about two @code{Points}.  It's usually worked to reverse the
order of the @code{Point} arguments, or to change sign of the angle
argument.  I think I've fixed the problem, though.

