@c gspict.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: gspict.texi,v 1.8 2004/01/12 18:37:07 lfinsto1 Exp lfinsto1 $
 
@node Pictures, Intersections, Solid Figures, Top
@chapter Pictures

@tindex Picture 
Applying drawing and filling operations to the drawable objects described
in the previous chapters isn't enough to produce output.  These
operations merely modify the @code{Picture} object that was passed to
them as an argument (@code{current_picture}, by default).

@code{Pictures} in 3DLDF are quite different from @code{pictures} in
MetaPost.  
When a drawing or filling operation is applied to an object @var{O}, a
copy of @var{O}, @var{C}, is allocated on the free store, a pointer to
@code{Shape} @var{S} is pointed at @var{C}, and @var{S} is pushed onto
the @code{vector<Shape*> shapes} on the @code{Picture} @var{P}, which
was passed as an argument to the drawing or filling command.  The
arguments for the pen, 
dash pattern, @code{Color}, and any others, are used to set the
corresponding data members of @var{C} (not @var{O}).  


@cindex output file  
@vindex out_stream
@c
In order to actually
cause MetaPost code to be written to the output file, it is necessary
to invoke @var{P}.@code{output()}.  Now, the appropriate version of
@code{output()} is applied to each of the objects pointed to
by a pointer on @var{P}.@code{shapes}.  @code{output()} is a pure
virtual function in @code{Shape}, so all classes derived from
@code{Shape} must have an @code{output()} function.  So, if
@code{shapes[0]} points to a @code{Path},
@code{Path::output()} is called, if 
@code{shapes[1]} points to a @code{Point},
@code{Point::output()} is called, and if @code{shapes[2]} points to an
object of a type derived from @code{Solid}, @code{Solid::output()} is
called.  
@code{Point}, @code{Path}, and @code{Solid} are namely the only classes
derived from @code{Shape} for which a version of @code{output()} is defined.  All
other @code{Shapes} are derived from one of these classes.
These @code{output()}
functions then write the MetaPost code to the 
output file through the output file stream @code{out_stream}.

@example
beginfig(1);
default_focus.set(0, 0, -10, 0, 0, 10, 10);
Circle c(origin, 3, 90);
c.draw();
c.shift(1.5);
c.draw();
current_picture.output();
endfig(1);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(0, 0, -10, 0, 0, 10, 10);} 
\immediate\write\examples{Circle c(origin, 3, 90);}
\immediate\write\examples{c.draw();}
\immediate\write\examples{c.shift(1.5);}
\immediate\write\examples{c.draw();}
\OEX{}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

The @cpp{} code for @PREFIG{} starts with the command 
@code{beginfig(1)} and ends with the command 
@code{endfig(1)}.   
They simply write ``@code{beginfig(@angles{arg})}'' and 
``@code{endfig()}'' to 
@vindex out_stream
@code{out_stream}, 
@cindex output files  
The optional 
@code{unsigned int} argument to @code{endfig()} is not written to
@code{out_stream}, it's merely 
``syntactic sugar'' for the user.
@c
@c !! TO DO:  Try to find the place in the @TeX{}book, where Knuth
@c explains what ``syntactic sugar'' is.


In MetaPost, the @code{endfig} command causes output and then clears
@code{currentpicture}.  This is not the case in 3DLDF, where
@code{Picture::output()} and @code{Picture::clear()} must
be invoked explicitly:

@example
beginfig(1);
Point p0;
Point p1(1, 2, 3);
p0.draw(p1);
current_picture.output();
endfig(1);

beginfig(2);
current_picture.clear();
Circle C(origin, 3);
C.fill();
current_picture.output();
endfig(2);
@end example

In @NEXTFIG{}, two @code{Pictures} are used within a single figure. 

@example
beginfig(1);
Picture my_picture;
default_focus.set(0, 0, -10, 0, 0, 10, 10);
Circle c(origin, 3, 90);
c.draw(my_picture);
my_picture.output();
c.shift(1.5);
c.fill(light_gray);
current_picture.output();
endfig(1);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Picture my_picture;}
\immediate\write\examples{default_focus.set(0, 0, -10, 0, 0, 10, 10);} 
\immediate\write\examples{Circle c(origin, 3, 90);}
\immediate\write\examples{c.draw(my_picture);}
\immediate\write\examples{my_picture.output();}
\immediate\write\examples{c.shift(1.5);}
\immediate\write\examples{c.fill(light_gray);}
\immediate\write\examples{current_picture.output();} 
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Multiple objects, or complex objects made up of sub-objects, can be 
stored in a @code{Picture}, so that operations can be applied to them
as a group:

@example
default_focus.set(7, 5, -10, 7, 5, 10, 10);
Cuboid c0(origin, 5, 5, 5);
c0.shift(0, 0, 3);
c0.draw();
Circle z0(c0.get_rectangle_center(0), 2.5, 90, 0, 0, 64);
z0.draw();
Circle z1(z0);
z1.shift(0, 0, -1);
z1.draw();
int i;
int j = z0.get_size();
for (i = 0; i < 8; ++i)
    z0.get_point(i * j/8).draw(z1.get_point(i * j/8));
Cuboid c1(c0.get_rectangle_center(4), 5, 3, 3);
c1.shift(0, 2.5);
c1.draw();
Rectangle r0 = *c1.get_rectangle_ptr(3);
Point p[10];
for (i = 0; i < 4; ++i)
  p[i] = r0.get_point(i);
p[4] = r0.get_mid_point(0);
p[5] = r0.get_mid_point(2);
p[6] = p[4].mediate(p[5], 2/3.0);
Circle z2(p[6], 2, 90, 90, 0, 16);
z2.draw();
Circle z3 = z2;
z3.shift(3);
z3.draw();
j = z2.get_size();
for (i = 0; i < 8; ++i)
    z2.get_point(i * j/8).draw(z3.get_point(i * j/8));
p[7] = c0.get_rectangle_center(2);
p[7].shift(-4);
p[8] = c0.get_rectangle_center(3);
p[8].shift(4);
current_picture.output();
current_picture.rotate(45, 45);
current_picture.shift(10, 0, 3);
current_picture.output();
@end example


@iftex
@tex 
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(7, 5, -10, 7, 5, 10, 10);}
\immediate\write\examples{Cuboid c0(origin, 5, 5, 5);}
\immediate\write\examples{c0.shift(0, 0, 3);}
\immediate\write\examples{c0.draw();}
\immediate\write\examples{Circle z0(c0.get_rectangle_center(0), 2.5, 90, 0, 0, 64);}
\immediate\write\examples{z0.draw();}
\immediate\write\examples{Circle z1(z0);}
\immediate\write\examples{z1.shift(0, 0, -1);}
\immediate\write\examples{z1.draw();}
\immediate\write\examples{int i;}
\immediate\write\examples{int j = z0.get_size();} 
\immediate\write\examples{for (i = 0; i < 8; ++i)}
\immediate\write\examples{    z0.get_point(i * j/8).draw(z1.get_point(i * j/8));}
\immediate\write\examples{Cuboid c1(c0.get_rectangle_center(4), 5, 3, 3);}
\immediate\write\examples{c1.shift(0, 2.5);}
\immediate\write\examples{c1.draw();}
\immediate\write\examples{Rectangle r0 = *c1.get_rectangle_ptr(3);}
\immediate\write\examples{Point p[10];}
\immediate\write\examples{for (i = 0; i < 4; ++i)}
\immediate\write\examples{  p[i] = r0.get_point(i);}
\immediate\write\examples{p[4] = r0.get_mid_point(0);}
\immediate\write\examples{p[5] = r0.get_mid_point(2);}
\immediate\write\examples{p[6] = p[4].mediate(p[5], 2/3.0);}
\immediate\write\examples{Circle z2(p[6], 2, 90, 90, 0, 64);}
\immediate\write\examples{z2.draw();}
\immediate\write\examples{Circle z3 = z2;}
\immediate\write\examples{z3.shift(3);}
\immediate\write\examples{z3.draw();}
\immediate\write\examples{j = z2.get_size();} 
\immediate\write\examples{for (i = 0; i < 8; ++i)}
\immediate\write\examples{    z2.get_point(i * j/8).draw(z3.get_point(i * j/8));}
\immediate\write\examples{p[7] = c0.get_rectangle_center(2);}
\immediate\write\examples{p[7].shift(-4);}
\immediate\write\examples{p[8] = c0.get_rectangle_center(3);}
\immediate\write\examples{p[8].shift(4);}
\immediate\write\examples{current_picture.output();}
\immediate\write\examples{current_picture.rotate(45, 45);}
\immediate\write\examples{current_picture.shift(10, 0, 3);}
\immediate\write\examples{current_picture.output();}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Let's say the complex object in @PREFIG{} represents a
furnace.  From the point of view of 3DLDF, however, it's not an object
at all, and the drawing consists of a collection of unrelated
@code{Cuboids}, @code{Circles}, @code{Rectangles}, and @code{Paths}.   
If we hadn't put it into a @code{Picture}, we could still have rotated
and shifted it, but only by applying the operations to each of the
sub-objects individually.

One consequence of the way @code{Pictures} are output in 3DLDF is, that
the following code will not work:

@example
beginfig(1);
Point p(1, 2);
Point q(1, 3);
out_stream << "pickup pencircle scaled .5mm;" << endl;
origin.draw(p);
out_stream << "pickup pensquare xscaled .3mm rotated 30;" << endl;
origin.draw(q);
current_picture.output();
endfig();
@end example

This is the MetaPost code that results:

@example
beginfig(1);
pickup pencircle scaled .5mm;
pickup pensquare xscaled .3mm rotated 30;
draw (0.000000cm, -3.000000cm) -- (1.000000cm, -1.000000cm);
draw (0.000000cm, -3.000000cm) -- (1.000000cm, 0.000000cm);
endfig;
@end example

It's perfectly legitimate to write 
@cindex raw MetaPost code  
raw MetaPost code to @code{out_stream}, as in lines 4 and 6 of this
example.  However, the @code{draw()} commands do not cause any output to
@code{out_stream}.  The MetaPost drawing commands are written to
@code{out_stream} when @code{current_picture.output()} is called.
Therefore, the @code{pickup} commands are ``bunched up'' before the
drawing commands.   
In this example,
setting @code{currentpen} to @code{pencircle scaled .5mm} has no effect,
because it is immediately reset to 
@code{pensquare xscaled .3mm rotated 30} in the MetaPost code, before
the @code{draw} commands.  
It is not possible to change @code{currentpen} in this way within a
@code{Picture}.  
Since the @code{draw()} commands in the 3DLDF
code didn't specify a @var{pen} argument, 
@code{currentpen} with its final value is used for both of the MetaPost
@code{draw} commands.  For any given invocation of
@code{Picture::output()}, there can only be one value of
@code{currentpen}.  All other pens must be passed as arguments to the
drawing commands.


@menu
* Projections::                 
* Focuses Getstart::            
* Surface Hiding::              
@end menu

@node Projections, Focuses Getstart, Pictures, Pictures
@section Projections

In order for a 3D graphic program to be useful, it must be able to
make two-dimensional projections of its three-dimensional constructions
so that they 
can be displayed on computer screens and printed out.  
These are some of the possible projections:

@table @asis
@item @bullet{} Parallel projection onto one of the major planes
These projections are trivial, and can be performed by 3DLDF.  They are
discussed in the following section.

@item @bullet{} Parallel projection onto another plane
@c !! TO DO: 
I haven't programmed these projections yet, but they might be useful, so
I probably will, when I get around to it.  

@item @bullet{} The perspective projection
This is the projection most people think of, when they think of
3D-graphics.  It is discussed in 
detail in @ref{The Perspective Projection}.


@item @bullet{} The isometric and axonometric projections
@c !! TO DO: 
@cindex TO DO 
These projections are important for engineering and drafting.  I have
not yet implemented them in 3DLDF, but they are on my list of ``Things
To Do''. 
@c !! Get reference, Böttcher and ?? @cite{Technisches Zeichnen}.
@end table

The function @code{Picture::output()} takes a @code{const unsigned
short} argument specifying the projection to be used.  The user should
probably avoid using explicit @code{unsigned shorts}, but should use the
constants defined for this purpose in the 
@dfn{namespace} @code{Projections}.@c
@c
@footnote{Namespaces are described in
Stroustrup, @cite{The @cpp{} Programming Language}, Chapter 8.} 
@c
The constants are @code{PERSP}, @code{PARALLEL_X_Y},
@code{PARALLEL_X_Z},
@code{PARALLEL_Z_Y}, @code{AXON}, and @code{ISO}.  The latter two should
not be used, because the axonometric and isometric projections have not
yet been implemented.

@menu
* Parallel Projections::        
* The Perspective Projection::  
@end menu
 
@node Parallel Projections, The Perspective Projection, Projections, Projections
@subsection Parallel Projections

When a @code{Picture} is projected onto the x-y plane, the
x and y-values from the @code{world_coordinates} of the @code{Points}
belonging to the objects on the
@code{Picture} are copied to
their @code{projective_coordinates}, which are 
used in the MetaPost code written to @code{out_stream}.
If a @code{Picture} @var{p} contains an object in the x-y plane,
or in a plane parallel to the x-y plane, then
the result of @code{@var{p}.output(Projections::PARALLEL_X_Y)} is more-or-less
equivalent to just using MetaPost without 3DLDF.

@example
Rectangle r(origin, 3, 3, 90);
Circle c(origin, 3, 90);
c *= r.shift(0, 0, 5);
r.draw();
c.draw();
current_picture.output(Projections::PARALLEL_X_Y);
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{Rectangle r(origin, 3, 3, 90);}
\immediate\write\examples{Circle c(origin, 3, 90);}
\immediate\write\examples{c *= r.shift(0, 0, 5);}
\immediate\write\examples{r.filldraw(black, gray);}
\immediate\write\examples{c.unfilldraw(black);}
\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.53.png"
alt="[Figure 53. Not displayed.]"
/>
<br>
<br>
Fig. 53.
<br>
</p>
@end html
@end ifhtml

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

If the objects do not lie in the x-y plane, or a plane parallel to the
x-y plane, then the projection will be distorted: 

@example
current_picture.output(Projections::PARALLEL_X_Y);
@end example
 
@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Rectangle r(origin, 3, 3, 90, 60);}
\immediate\write\examples{Circle c(origin, 3, 90, 60);}
\immediate\write\examples{c *= r.shift(0, 0, 5);}
\immediate\write\examples{r.filldraw(black, gray);}
\immediate\write\examples{c.unfilldraw(black); }
\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.54.png"
alt="[Figure 54. Not displayed.]"
/>
<br>
<br>
Fig. 54.
<br>
</p>
@end html
@end ifhtml

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

@code{Picture::output()} can be called with an additional @code{real}
argument @var{factor} for magnifying or shrinking the @code{Picture}.


@c !! TO DO:  Try using the code above and removing here.  Change
@c factor, if necessary.  LDF 2003.08.15.
@c
@example
Rectangle r(origin, 4, 4, 90, 60);
Circle c(origin, 4, 90, 60);
c *= r.shift(0, 0, 5);
r.filldraw(black, gray);
c.unfilldraw(black);
current_picture.output(Projections::PARALLEL_X_Y, .5);
current_picture.shift(2.5);
current_picture.output(Projections::PARALLEL_X_Y);
current_picture.shift(1);
current_picture.output(Projections::PARALLEL_X_Y, 2);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Rectangle r(origin, 4, 4, 90, 60);}
\immediate\write\examples{Circle c(origin, 4, 90, 60);}
\immediate\write\examples{c *= r.shift(0, 0, 5);}
\immediate\write\examples{r.filldraw(black, gray);}
\immediate\write\examples{c.unfilldraw(black);}
\immediate\write\examples{Point p(origin);}
\immediate\write\examples{p.label("$.5@DBKS{}times$", "");}
\immediate\write\examples{current_picture.output(Projections::PARALLEL_X_Y, .5);}
\immediate\write\examples{current_picture.kill_labels();}
\immediate\write\examples{p.label("Normal size", "");}
\immediate\write\examples{p *= current_picture.shift(2.5);}
\immediate\write\examples{current_picture.output(Projections::PARALLEL_X_Y);}
\immediate\write\examples{current_picture.kill_labels();}
\immediate\write\examples{p.label("$2@DBKS{}times$", "");}
\immediate\write\examples{current_picture.shift(1);}
\immediate\write\examples{current_picture.output(Projections::PARALLEL_X_Y, 2);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Parallel projection onto the x-z and z-y planes are completely analogous
to parallel projection onto the x-y plane.

@node The Perspective Projection,  , Parallel Projections, Projections
@subsection The Perspective Projection

The perspective projection obeys the laws of 
@dfn{linear perspective}.
In 3DLDF, it is performed by means of a
transformation, whose effect is, to the
best of my knowledge, 
exactly equivalent to the result of a perspective projection done by
hand using vanishing points and rulers.  

It is very helpful to the artist to understand the laws of linear
perspective, and to know how to make a perspective drawing by hand.@c
@c
@footnote{There are many books on linear perspective for artists.  
I've found Gwen White's @cite{Perspective.  A Guide for Artists,
Architects and Designers} to be particularly good.  Vredeman de Vries,
@cite{Perspective} contains beautiful examples of perspective
constructions.} 
@c
However, it is a very tedious and error-prone procedure (I know, I've
done it).  One of my main motivations for writing 3DLDF was so I
wouldn't have to do it anymore.  

@c !! TO DO:  Mention somewhere, that the ground plane isn't important,
@c and that more could be said on the subject.  For example, what
@c happens when the line of sight is not parallel to the ground plane,
@c and how this is important when using rulers, but not when using
@c transformations.  LDF 2003.08.15.
@c
@NEXTFIG{} shows a perspective construction, the way it
could be done by hand.
The point of view, or @dfn{focus} is located 6cm from
the picture plane, and 4cm above the ground (or x-z) plane at the point  
(0, 4, -6). 
The rectangle @math{R} lies in the ground  plane, with the point @math{r_0} at 
(2, 0, 1.5).  The right side of @math{R}, with length = 2@dmn{cm} 
lies at an angle
of 40 to the ground line, which corresponds to the intersection line
of the ground plane with the picture plane, and the left side, with
length = 5@dmn{cm}, at an angle of  
@c
@iftex 
@tex 
$90^\circ - 40^\circ = 50^\circ$ 
@end tex
@end iftex
@c
@ifnottex 
90 degrees @math{-} 40 degrees = 50 degrees 
@end ifnottex 
@c
to the ground line. 


@c !! NOTE:  I haven't been able to get the colons lined up the way I'd
@c like for the explanations of the abbreviations.  LDF 2003.08.15.
@c
@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{persp_0(2, 1.5, 5, 2, 40, 6, 4, 6, 9, 6, 9);} 
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

While it's possible to use 3DLDF to make a perspective construction
in the traditional way, as @PREFIG{} shows, the code for @NEXTFIG{}
achieves the same result more efficiently: 

@example
default_focus.set(0, 4, -6, 0, 4, 6, 6);
Rectangle r(origin, 2, 5, 0, 40);
Point p(2, 0, 1.5);
r.shift(p - r.get_point(0));
r.draw();
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(0, 4, -6, 0, 4, 6, 6);}
\immediate\write\examples{Rectangle R(origin, 2, 5, 0, 40);}
\immediate\write\examples{Point p(2, 0, 1.5);}
\immediate\write\examples{R.shift(p - R.get_point(0));}
\immediate\write\examples{R.get_point(0).dotlabel("$r_0$", "bot");}
\immediate\write\examples{R.get_point(1).dotlabel("$r_1$", "rt");}
\immediate\write\examples{R.get_point(2).dotlabel("$r_2$");}
\immediate\write\examples{R.get_point(3).dotlabel("$r_3$", "lft");}
\immediate\write\examples{R.get_center().label("$R$", "");}
\immediate\write\examples{R.draw();}
\OEX{}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

In @TWOPREFIG{}, it was
convenient to start with the corner point @math{r_0};  
if we needed the center of  @math{R}, it would have to be found from the
corner points. 
However, in 3DLDF, @code{Rectangles} are most often constructed about
the center.  Therefore, in @NEXTFIG{}, @math{R} is first
constructed about the origin, with the 
rotation about the y-axis passed as an argument to the constructor.
It is then shifted such that @code{*(@var{R}.points[0])}, the first 
(or zeroth, if you will) @code{Point} on @math{R} comes to lie at 
@math{(2, 0, 1.5)}.   

Unlike the other transformations currently
used in 3DLDF, the perspective transformation is non-affine.  Affine
transformations maintain parallelity of lines, while the rules of 
perspective state that parallel lines, with one exception, appear to
recede toward a 
@c
@c !! I believe what I've put in the following footnote is correct, but
@c maybe it's not.  I've had to try to figure it out myself;  I don't
@c remember ever seeing this spelled out before.  
@c
@dfn{vanishing point}.@footnote{@c
@c
(I believe the following to be correct, but I'm not entirely sure.)
@c
@iftex
@tex
Let $\vec{v}$ be the line of sight.  By definition, the plane of
projection will be a plane $p$, such that $\vec{v}$ is normal to
$p$.  Let $q_0$ and $q_1$ be planes such that 
$q_0 \equiv q_1$ or $q_0 \parallel q_1$, and  $q_0 \perp p$. 
It follows that $q_1 \perp p$. 
Let $l_0$ and $l_1$ be lines, such that $l_0 \neq l_1$, 
$l_0 \parallel l_1$, $l_0 \in q_0$, $l_1 \in q_1$, 
$l_0 \perp \vec{v}$, and $l_1 \perp \vec{v}$.  
Under these circumstances, the projections of $l_0$ and $l_1$ in $p$
will also be parallel.  
@end tex
@end iftex
@c
@ifnottex 
Let vector @math{v} be the line of sight.  By definition, the plane of
projection will be a plane @math{p}, such that vector v is normal to
@math{p}.  Let @math{q_0} and @math{q_1} be planes such that 
@math{q_0 @equiv{} q_1} or @math{q_0 || q_1}, and  @math{q_0} is
perpendicular to @math{p}. 
It follows that @math{q_1} is perpendicular to @math{p}. 
Let @math{l_0} and @math{l_1} be lines, such that @math{l_0 != l_1}, 
@math{l_0 || l_1}, @math{l_0} lies within @math{q_0}, @math{l_1} lies
within @math{q_1}, 
@math{l_0} is perpendicular to vector v, and @math{l_1} is perpendicular
to vector v.  
Under these circumstances, the projections of @math{l_0} and @math{l_1}
in @math{p} will also be parallel.  
@end ifnottex 
@c
}


In @TWOPREFIG{}, the lines
@iftex
@tex
$\overrightarrow{r_0r_1}$ and $\overrightarrow{r_3r_2}$ 
@end tex
@end iftex
@c
@ifnottex 
from @math{r_0} to @math{r_1} and from @math{r_3} to @math{r_2} 
@end ifnottex 
@c
appear to vanish
toward the right-hand @DEG{40} vanishing point, while
@iftex
@tex
$\overrightarrow{r_0r_3}$ and $\overrightarrow{r_1r_2}$ 
@end tex
@end iftex
@c
@ifnottex 
the lines from r_0 to r_3 and from r_1 to r_2 
@end ifnottex 
@c
appear to vanish
toward the left-hand @DEG{50} vanishing point.  
The lower the angle of a
vanishing point, the further away it is from the center of vision, as
@NEXTFIG{} shows:    

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{vector<real> vps;}
\immediate\write\examples{vps.push_back(.5);}
\immediate\write\examples{vps.push_back(5);}
\immediate\write\examples{for (real r = 10; r < 90; r+=10)}
\immediate\write\examples{vps.push_back(r);}
\immediate\write\examples{vector<Point*> points =  }
\immediate\write\examples{make_perspective_frame(vps, 5, 4, 1, 16);} 
\immediate\write\examples{Point f(*points[0]);}
\immediate\write\examples{Point vp_pt_5r(*points[7]);}
\immediate\write\examples{Point vp5r(*points[8]);}
\immediate\write\examples{Point vp10r(*points[9]);}
\immediate\write\examples{Point p10r(vp10r - f);}
\immediate\write\examples{Point p_pt_5r(vp_pt_5r - f);}
\immediate\write\examples{Point p5r(vp5r - f);}
\immediate\write\examples{p_pt_5r.unit_vector(true);}
\immediate\write\examples{p5r.unit_vector(true);}
\immediate\write\examples{p10r.unit_vector(true);}
\immediate\write\examples{p_pt_5r *= p5r *= p10r *= 13.5;}
\immediate\write\examples{stringstream s;}
\immediate\write\examples{f.drawarrow(p_pt_5r, black, "evenly");}
\immediate\write\examples{s << "VP $0.5^@DBKS{}circ$ $(x="}
\immediate\write\examples{<< vp_pt_5r.get_x() << "@OCB{}@DBKS{}rm cm@CCB{})$";}
\immediate\write\examples{p_pt_5r.label(s.str(), "rt");}
\immediate\write\examples{s.str("");}
\immediate\write\examples{f.drawarrow(p5r, black, "evenly");}
\immediate\write\examples{s << "VP $5^@DBKS{}circ$ $(x="}
\immediate\write\examples{<< vp5r.get_x() << "@OCB{}@DBKS{}rm cm@CCB{})$";}
\immediate\write\examples{p5r.label(s.str(), "rt");}
\immediate\write\examples{s.str("");}
\immediate\write\examples{f.drawarrow(p10r, black, "evenly");}
\immediate\write\examples{s << "VP $10^@DBKS{}circ$ $(x="}
\immediate\write\examples{<< vp10r.get_x() << "@OCB{}@DBKS{}rm cm@CCB{})$";}
\immediate\write\examples{p10r.label(s.str(), "rt");}
\immediate\write\examples{s.str("");}
\OEX{Projections::PARALLEL_X_Y}
\EGRP
\SEEX{.25cm}{.5cm}{0cm}{0cm}
\fi
\PEX
@end tex
@end iftex

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

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

In @PREFIG{}, the @DEG{0.5} vanishing point is nearly 
@iftex
@tex
$5{3\over4}$
@end tex
@end iftex
@c
@ifnottex 
5 and 3/4
@end ifnottex 
@c
meters away from the CV, and a
line receding to it will be very 
nearly horizontal.  However, the distance from the focus to the CV is
only 5@dmn{cm}.  As this distance increases, the distance from the
CV to a given vanishing point increases proportionately.
If the distance is 30@dmn{cm}, a more reasonable value
for a drawing, then the x-coordinate of VP@: @DEG{10} is 170.138@dmn{cm}, that 
of VP@: @DEG{5} is 342.902@dmn{cm}, and that of VP@: @DEG{0.5} is 3437.66@dmn{cm}!  
This is the reason 
why perspective drawings done by hand rarely contain lines receding to
the horizon at low angles.

This problem doesn't arise when the perspective transformation is
used.  In this case, any angle can be calculated as easily as any other:

@example
default_focus.set(0, 4, -6, 0, 4, 6, 6);
Rectangle r;
Point center(0, 2);
r.set(center, 2, 5, 0, 0, 0.5);
r.draw();

r.set(center, 2, 5, 0, 0, 2.5);
r.draw();

r.set(center, 2, 5, 0, 0, 5);
r.draw();
current_picture.output();
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(0, 4, -6, 0, 4, 6, 6);}
\immediate\write\examples{Rectangle r;}
\immediate\write\examples{Point center(0, 2);}
\immediate\write\examples{stringstream s;}
\immediate\write\examples{r.set(center, 2, 5, 0, 0, 0.5);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{s << "$" << .5 << "^@DBKS{}circ$";}
\immediate\write\examples{center.label(s.str(), "");}
\immediate\write\examples{s.str("");}
\immediate\write\examples{center.shift(4);}
\immediate\write\examples{r.set(center, 2, 5, 0, 0, 2.5);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{s << "$" << 2.5 << "^@DBKS{}circ$";}
\immediate\write\examples{center.label(s.str(), "");}
\immediate\write\examples{s.str("");}
\immediate\write\examples{center.shift(4);}
\immediate\write\examples{r.set(center, 2, 5, 0, 0, 5);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{s << "$" << 5 << "^@DBKS{}circ$";}
\immediate\write\examples{center.label(s.str(), "");}
\immediate\write\examples{s.str("");}
\immediate\write\examples{center.shift(4);}
\OEX{}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

@node Focuses Getstart, Surface Hiding, Projections, Pictures
@section Focuses 

@vindex focus 
The perspective transformation requires a focus;  as a consequence,
outputting a @code{Picture} requires an object of class
@code{Focus}.    
@code{Picture::output()} takes an optional pointer-to-@code{Focus}
argument, which is 0 by default.  If the default is used, (or 0 is
passed explicitly), the global variable @code{default_focus} is used.  
@xref{Focus Global Variables,,Focus Reference; Global Variables}.

A @code{Focus} can be thought of as the observer of a scene, or a
camera.  It contains a @code{Point position} for its location with
respect to 3DLDF's coordinate system, and a @code{Point direction},
specifying the direction where the observer is looking, or where the
camera is pointed.  The @code{Focus} can be rotated freely about the
line 
@iftex
@tex
$\overrightarrow{PD}$, 
@end tex
@end iftex
@c
@ifnottex 
PD, 
@end ifnottex 
@c
where @math{P} stands for @code{position} and
@math{D}
for @code{direction},  
so a @code{Focus} contains a third @code{Point up}, to indicate which
direction will be ``up'' on the projection, when a @code{Picture} is
projected.  


The projection plane @math{q}
will always be perpendicular to 
@c
@iftex
@tex
$\overrightarrow{PD}$,
or to put it another way,
$\overrightarrow{PD}$
@end tex
@end iftex
@c
@ifnottex 
the line PD,
or to put it another way,
the line PD,
@end ifnottex 
@c
is normal to @math{q}.

Unlike the traditional perspective construction, where the distance from
the focus to the center of vision fixes both the location of the focus
in space, and its distance to the 
@c
picture plane,@c
@c
@footnote{I believe this
to be true, but I'm not 
@ifinfo 
100% 
@end ifinfo
@iftex 
100\% 
@end iftex
certain.}  
@c
these two parameters can be set independently when the perspective
transformation is used. 
The distance from a @code{Focus} to the picture plane is stored in the
data member @code{distance}, of type @code{real}.  

A @code{Focus} can be declared using two @code{Point} arguments for
@code{position} and @code{direction}, and a @code{real} argument for
@code{distance}, in that order.

@example
Point pos(0, 5, -10);
Point dir(0, 5, 10);
Focus f(pos, dir, 10);

Point center(2, 0, 3);
Rectangle r(center, 3, 3);
r.draw();
current_picture.output(f);
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Point pos(0, 5, -10);}
\immediate\write\examples{Point dir(0, 5, 10);}
\immediate\write\examples{Focus f(pos, dir, 10);}
\immediate\write\examples{Point center(2, 0, 3);}
\immediate\write\examples{Rectangle r(center, 3, 3);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{center.label("$r$", "");}
\immediate\write\examples{draw_axes(gray);} 
\immediate\write\examples{current_picture.output(f);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

The ``up'' direction is calculated by the @code{Focus} constructor
automatically.  An optional argument can be used to specify the angle by
which to rotate the @code{Focus} about 
@iftex
@tex
$\overrightarrow{PD}$.
@end tex
@end iftex
@c
@ifnottex 
the line PD.
@end ifnottex 

@example
Point pos(0, 5, -10);
Point dir(0, 5, 10);
Focus f(pos, dir, 10, 30);
Point center(2, 0, 3);
Rectangle r(center, 3, 3);
r.draw();
current_picture.output(f);
@end example


@iftex
@tex 
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Point pos(0, 5, -10);}
\immediate\write\examples{Point dir(0, 5, 10);}
\immediate\write\examples{Focus f(pos, dir, 10, 30);}
\immediate\write\examples{Point center(2, 0, 3);}
\immediate\write\examples{Rectangle r(center, 3, 3);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{center.label("$r$", "");}
\immediate\write\examples{draw_axes(gray);} 
\immediate\write\examples{current_picture.output(f);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Alternatively, a @code{Focus} can be declared using three @code{real}
arguments each for the x, y, and z-coordinates of @code{position} and
@code{direction}, respectively, followed by the @code{real} arguments
for @code{distance} and the angle of rotation:

@example
Focus f(3, 5, -5, 0, 3, 0, 10, 10);
Point center(2, 0, 3);
Rectangle r(center, 3, 3);
r.draw();
current_picture.output(f);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Focus f(3, 5, -5, 0, 3, 0, 10, 10);}
\immediate\write\examples{Point center(2, 0, 3);}
\immediate\write\examples{Rectangle r(center, 3, 3);}
\immediate\write\examples{r.draw();}
\immediate\write\examples{center.label("$r$", "");}
\immediate\write\examples{draw_axes(gray);} 
\immediate\write\examples{current_picture.output(f);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

@code{Focuses} contain two @code{Transforms}, @code{transform} and @code{persp}.
A @code{Focus} can be located anywhere in 3DLDF's coordinate system.
However, performing the perspective projection is more convenient, if
@code{position} and @code{direction} both lie on one of the major axes,
and the plane of projection corresponds to one of the major planes.
@code{transform} is the transformation which would have this affect on
the @code{Focus}, and is calculated by the @code{Focus} constructor.
When a @code{Picture} is output using that @code{Focus},
@code{transform} is applied to all of the @code{Shapes} on the
@code{Picture}, maintaining the relationship between the @code{Focus}
and the @code{Shapes}, while making it easier to calculate the
projection.  The @code{Focus} need never be 
transformed by @code{transform}.
The actual perspective transformation is stored 
in @code{persp}.


@code{Focuses} can be moved by using one of the setting functions, which
take the same arguments as the constructors.  
@c !! TO DO: 
Currently, there are no affine transformation functions for moving
@code{Focuses}, but I plan to add them soon.  If 3DLDF is used for
making 
@c
@cindex animation 
@c
animation, resetting the @code{Focus} can be used to simulate camera
movements:

@example
beginfig(1);
Point pos(2, 10, 3);
Point dir(2, -10, 3);
Focus f;
Point center(2, 0, 3);
for (int i = 0; i < 5; ++i)
  @OCB{} 
    f.set(pos, dir, 10, (15 * i));
    Rectangle r(center, 3, 3);
    r.draw();
    current_picture.output(f);
    current_picture.clear();
    pos.shift(1, 1, 0);
    dir.rotate(0, 0, 10);
  @CCB{}
endfig(1);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{Point pos(2, 10, 3);}
\immediate\write\examples{Point dir(2, -10, 3);}
\immediate\write\examples{Focus f;}
\immediate\write\examples{Point center(2, 0, 3);}
\immediate\write\examples{for (int i = 0; i < 5; ++i)}
\immediate\write\examples{@OCB}
\immediate\write\examples{f.set(pos, dir, 10, (15 * i));}
\immediate\write\examples{Rectangle r(center, 3, 3);}
\immediate\write\examples{r.get_point(0).label(i, "lft"); }
\immediate\write\examples{r.draw();}
\immediate\write\examples{ current_picture.output(f);}
\immediate\write\examples{    current_picture.clear();}
\immediate\write\examples{    pos.shift(1, 1, 0);}
\immediate\write\examples{    dir.rotate(0, 0, 10);}
\immediate\write\examples{  @CCB}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

In @PREFIG{}, @code{current_picture} is output 5 times within a single
MetaPost figure.  Since the file passed to MetaPost is called
@file{persp.mp}, the file of Encapsulated PostScript (EPS) code
containing @PREFIG{} is called @file{persp.1}.  
@cindex animation 
To use this technique for making an animation, it's necessary to output
the @code{Picture} into multiple MetaPost figures.

@example
Point pos(2, 10, 3);
Point dir(2, -10, 3);
Focus f;
Point center(2, 0, 3);
for (int i = 0; i < 5; ++i)
  @OCB{} 
    f.set(pos, dir, 10, (15 * i));
    Rectangle r(center, 3, 3);
    r.draw();
    beginfig(i+1);
    current_picture.output(f);
    endfig();
    current_picture.clear();
    pos.shift(1, 1, 0);
    dir.rotate(0, 0, 10);
  @CCB{}
@end example

Now, running MetaPost on @file{persp.mp} generates the EPS files
@file{persp.1}, @file{persp.2}, @file{persp.3}, @file{persp.4}, and
@file{persp.5}, containing the five separate drawings of @var{r}.  
@c
@c !! TO DO:  Add a node ``Animation''.  When I've done so, put a cross
@c reference here.  LDF 2003.08.15.


@node Surface Hiding,  , Focuses Getstart, Pictures
@section Surface Hiding

@c !! TO DO:  Write about z-buffers, and how scan converting is needed
@c to use them.  Also, show how to do surface hiding of the two
@c rectangles by hand!

In @NEXTFIG{}, @code{Circle} @var{c} lies in front of @code{Rectangle}
@var{r}. 
Since @var{c} is drawn and not filled, @var{r} is visible behind
@var{c}. 
 
@example
default_focus.set(1, 3, -5, 0, 3, 5, 10);
Point p(0, -2, 5);
Rectangle r(p, 3, 4, 90);
r.draw();
Point q(2, -2, 3);
Circle c(q, 3, 90);
c.draw();
current_picture.output();
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP
\immediate\write\examples{default_focus.set(1, 3, -5, 0, 3, 5, 10);}
\immediate\write\examples{Point p(0, -2, 5);}
\immediate\write\examples{Rectangle r(p, 3, 4, 90);}
\immediate\write\examples{p.label("$r$", "");} 
\immediate\write\examples{r.draw();}
\immediate\write\examples{Point q(2, -2, 3);}
\immediate\write\examples{Circle c(q, 3, 90);}
\immediate\write\examples{q.label("$c$", "");} 
\immediate\write\examples{c.draw();}
\OEX{}
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

If instead, @var{c} is filled or filldrawn, only the parts of @var{r} that are not
covered by @var{c} should be visible:

@example
r.draw();
c.filldraw();
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\immediate\write\examples{p.label("$r$", "");} 
\immediate\write\examples{q.label("$c$", "");} 
\immediate\write\examples{r.draw();}
\immediate\write\examples{c.filldraw();}
\OEX{}
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

What parts of @code{r} are covered depend on the point of view, i.e.,
the position and direction of the @code{Focus} used for outputting the
@code{Picture}:

@example
default_focus.set(8, 0, -5, 5, 3, 5, 10);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\immediate\write\examples{default_focus.set(8, 0, -5, 5, 3, 5, 10);}
\immediate\write\examples{r.get_point(3).mediate(p, .333).label("$r$", "");}
\immediate\write\examples{q.label("$c$", "");} 
\immediate\write\examples{r.draw();}
\immediate\write\examples{c.filldraw();}
\OEX{}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

@cindex surface hiding 
@cindex hidden surface algorithm  
@c
Determining what objects cover other objects in a program for 3D
graphics is called 
@dfn{surface hiding}, 
and is performed by a
@dfn{hidden surface algorithm}.  3DLDF currently has a very primitive 
hidden surface algorithm that only works for the most simple cases.  

@cindex painter's algorithm
@c
The hidden surface algorithm used in 3DLDF is a 
@dfn{painter's algorithm}, which means that the objects that are
furthest away from the @code{Focus} are drawn first, followed by the
objects that are closer, which may thereby cover them.  In order to make
this possible, the @code{Shapes} on a @code{Picture} must be sorted
before they are output.  They are sorted according to the z-values in
the @code{projective_coordinates} of the @code{Points} belonging to the
@code{Shape}.  This may seem strange, since the 
projection is two-dimensional and only the x and y-values from
@code{projective_coordinates} are written to @code{out_stream}.
However, the perspective transformation also produces a z-coordinate,
which indicates the distance of the @code{Points} from the @code{Focus}
in the z-dimension.  

The problem is, that all @code{Shapes}, except @code{Points} themselves,
consist of multiple @code{Points}, that may have different
z-coordinates.  3DLDF currently does not yet have a satisfactory way of
dealing with this situtation.  In order to try to cope with it, the user
can specify four different ways of sorting the @code{Shapes}:  They
can be sorted according to the maximum z-coordinate, the
minimum z-coordinate, the mean of the maximum and minimum z-coordinate 
@c
@iftex
@tex
$({\rm max} + {\rm min}) / 2$,
@end tex
@end iftex
@c
@ifnottex
@math{(max + min) / 2},
@end ifnottex 
@c
and not sorted.  
In the last case, the @code{Shapes} are output in the order of the 
drawing and filling commands in the user code.  
The z-coordinates referred to are those in
@code{projective_coordinates}, and will have been calculated for a
particular @code{Focus}.

The function @code{Picture::output()} takes a 
@code{const unsigned short} @var{sort_value} argument that specifies
which style of sorting 
should be used.  The namespace @code{Sorting} contains the following
constants which should be used for @var{sort_value}: @code{MAX_Z},
@code{MIN_Z}, @code{MEAN_Z}, and @code{NO_SORT}.  The default is
@code{MAX_Z}.

3DLDF's primitive hidden surface algorithm @emph{cannot} work for
objects that intersect.  The following examples demonstrate why not:

@example
using namespace Sorting;
using namespace Colors;
using namespace Projections;
default_focus.set(5, 3, -10, 3, 1, 1, 10, 180);
Rectangle r0(origin, 3, 4, 45);
Rectangle r1(origin, 2, 6, -45);
r0.draw();
r1.draw();
current_picture.output(default_focus, PERSP, 1, MAX_Z);
r0.show("r0:");
@print{} r0:
fill_draw_value == 0
(-1.5, -1.41421, -1.41421) -- (1.5, -1.41421, -1.41421) -- 
(1.5, 1.41421, 1.41421) -- (-1.5, 1.41421, 1.41421) 
-- cycle;

r0.show("r0:", 'p');
@print{} r0:
fill_draw_value == 0
Perspective coordinates.
(-5.05646, -4.59333, -0.040577) -- (-2.10249, -4.86501, -0.102123) -- 
(-1.18226, -1.33752, 0.156559) -- (-3.51276, -1.2796, 0.193084) 
-- cycle;

r1.show("r1:");
@print{} r1:
fill_draw_value == 0
(-1, 2.12132, -2.12132) -- (1, 2.12132, -2.12132) -- 
(1, -2.12132, 2.12132) -- (-1, -2.12132, 2.12132) 
-- cycle;

r1.show("r1:", 'p');
@print{} r1:
fill_draw_value == 0
Perspective coordinates.
(-5.09222, -0.995681, -0.133156) -- (-2.98342, -1.03775, -0.181037) -- 
(-1.39791, -4.05125, 0.208945) -- (-2.87319, -3.93975, 0.230717) 
-- cycle;
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{default_focus.set(5, 3, -10, 3, 1, 1, 10, 180);}
\immediate\write\examples{Rectangle r0(origin, 3, 4, 45);}
\immediate\write\examples{Rectangle r1(origin, 2, 6, -45);}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{r0.get_point(0).label(Point::WORLD_VALUES_Z, "lft");}
\immediate\write\examples{r0.get_point(1).label(Point::WORLD_VALUES_Z, "rt");}
\immediate\write\examples{r0.get_point(2).label(Point::WORLD_VALUES_Z, "lrt");}
\immediate\write\examples{r0.get_point(3).label(Point::WORLD_VALUES_Z, "llft");}
\immediate\write\examples{r1.get_point(0).label(Point::WORLD_VALUES_Z, "lft");}
\immediate\write\examples{r1.get_point(1).label(Point::WORLD_VALUES_Z, "rt");}
\immediate\write\examples{r1.get_point(2).label(Point::WORLD_VALUES_Z, "rt");}
\immediate\write\examples{r1.get_point(3).label(Point::WORLD_VALUES_Z, "lft");}
\immediate\write\examples{r0.get_mid_point(0).label("$r_0$", "bot");}
\immediate\write\examples{r1.get_mid_point(0).label("$r_1$");}
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{current_picture.output(default_focus, PERSP, 1, MAX_Z);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

In @PREFIG{}, the @code{Rectangles} @math{r_0} and @math{r_1} intersect along the
x-axis.  The z-values of the @code{world_coordinates} of @math{r_0} are 
-1.41421 and 1.41421 (two @code{Points} each), while those of @math{r_1}
are 2.12132 and  -2.12132.  So @math{r_1} has two @code{Points} with
z-coordinates greater than the z-coordinate of any @code{Point}
on @math{r_0}, and two @code{Points} with z-coordinates less than the
z-coordinate of any @code{Point} on @math{r_0}.  The 
@code{Points} on @math{r_0} and @math{r_1} all have different z-values in
their @code{projective_coordinates}, but @math{r_1} still has a @code{Point}
with a z-coordinate greater than that of any of the @code{Points} on
@math{r_0}, and one with a z-coordinate less than that of any of the
@code{Points} on @math{r_0}.  

In @NEXTFIG{}, the @code{Shapes} on @code{current_picture} are sorted
according to the maximum z-values of the @code{projective_coordinates}
of the @code{Points} belonging to the @code{Shapes}.  @math{r_1} is
filled and drawn first, 
because it has the @code{Point} with the positive z-coordinate of
greatest magnitude.
When subsequently @math{r_0} is drawn, it covers part of the top of 
@math{r_1}, which lies in front of @math{r_0}, and should be visible:



@example
current_picture.output(default_focus, PERSP, 1, MAX_Z);
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{default_focus.set(5, 3, -10, 3, 1, 1, 10, 180);}
\immediate\write\examples{Rectangle r0(origin, 3, 4, 45);}
\immediate\write\examples{Rectangle r1(origin, 2, 6, -45);}
\immediate\write\examples{r0.filldraw();}
\immediate\write\examples{r1.filldraw(black, gray);}
\immediate\write\examples{r0.get_mid_point(0).label("$r_0$", "bot");}
\immediate\write\examples{r1.get_mid_point(0).label("$r_1$");}
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{current_picture.output(default_focus, PERSP, 1, MAX_Z);}
%%
%% Kludge!! I clear current_picture in order to get the z-axis to be
%% drawn.  LDF 2003.08.15.
%%
\immediate\write\examples{current_picture.clear();} 
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{current_picture.output(default_focus, PERSP, 1, MAX_Z);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

In @NEXTFIG{}, the @code{Shapes} on @code{current_picture} are sorted
according to the minimum z-values of the @code{projective_coordinates}
of the @code{Points} belonging to the @code{Shapes}.  @code{r1} is drawn
and filled last, because  
it has the @code{Point} with the negative z-coordinate of greatest
magnitude.
It thereby covers the bottom part of
@code{r0}, which lies in front of @code{r1}, and should be visible.

@example
current_picture.output(default_focus, PERSP, 1, MIN_Z);
@end example


@iftex
@tex
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{default_focus.set(5, 3, -10, 3, 1, 1, 10, 180);}
\immediate\write\examples{Rectangle r0(origin, 3, 4, 45);}
\immediate\write\examples{Rectangle r1(origin, 2, 6, -45);}
\immediate\write\examples{r0.get_mid_point(0).label("$r_0$", "bot");}
\immediate\write\examples{r1.get_mid_point(0).label("$r_1$");}
\immediate\write\examples{r0.filldraw();}
\immediate\write\examples{r1.filldraw(black, gray);}
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{current_picture.output(default_focus, PERSP, 1, MIN_Z);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Neither sorting by the mean z-value in the
@code{projective_coordinates}, nor suppressing sorting does any good. 
In each case, one @code{Rectangle} is always drawn and filled last,
covering parts of the other that lie in front of the first.

3DLDF's hidden surface algorithm will fail wherever objects intersect,
not just where one extends past the other in both the positive and
negative z-directions.

@example
Rectangle r(origin, 3, 4, 45);
Circle c(origin, 2, -45);
r.filldraw();
c.filldraw(black, gray);
current_picture.output(default_focus, PERSP, 1, NO_SORT);
@end example

@iftex
@tex
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{default_focus.set(5, 3, -10, 3, 1, 1, 10, 180);}
\immediate\write\examples{Rectangle r(origin, 3, 4, 45);}
\immediate\write\examples{Circle c(origin, 2, -45);}
\immediate\write\examples{r.filldraw();}
\immediate\write\examples{c.filldraw(black, gray);}
\immediate\write\examples{draw_axes(gray);}
\immediate\write\examples{current_picture.output(default_focus, PERSP, 1, NO_SORT);}
\EGRP
\EEX 1
\fi
\PEX
@end tex
@end iftex

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

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

Even where objects don't intersect, their projections may.  In order to
handle these cases properly, it is necessary to break up the
@code{Shapes} on a @code{Picture} into smaller @code{Shapes}, until
there are none that intersect or whose projections intersect.  Then, any
of the three methods of sorting described above can be used to sort the
@code{Shapes}, and they can be output.  

Before this can be done, 3DLDF must be able to find the intersections of
all of the different kinds of @code{Shapes}.  If 3DLDF converted solids
to polyhedra and curves to sequences of line segments, this would reduce
to the problem of finding the intersections of lines and planes, however
it does not yet do this.     

Even if it did, a fully functional hidden surface algorithm must compare
each @code{Shape} on a @code{Picture} with every other @code{Shape}.
Therefore, for @math{n} @code{Shapes}, there will be 
@c
@iftex
@tex
$n!/{(n-r)!\,r!}$
@end tex
@end iftex
@c
@ifnottex 
@math{n! / ((n - r)! r!)} 
@end ifnottex 
@c
(possibly time-consuming) comparisons.  
@iftex
@tex 
The following table shows how many comparisons are needed for $n$
@code{Shapes} for several values of $n$:
\medskip
@end tex
@end iftex

@iftex
@tex 
\ifmakeexamples
\BEX
\BGRP 
\immediate\write\examples{Rectangle r0(origin, 2, .5, 90);}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{Point p0(r0.get_center());}
\immediate\write\examples{p0.label("\OCB\DBKS{tt} Shapes\CCB", "");}
\immediate\write\examples{Rectangle r1(origin, 3, .5, 90);}
\immediate\write\examples{r1.shift(r0.get_point(1) - r1.get_point(0));}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{Point p1(r1.get_center());}
\immediate\write\examples{p1.label("Comparisons", "");}
\immediate\write\examples{Transform t;}
\immediate\write\examples{t.shift(r0.get_point(0) - r0.get_point(3));}
\immediate\write\examples{p0 *= p1 *= r0 *= r1 *= t;}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{real w0 = r0.get_point(1).get_x() - r0.get_point(0).get_x();}
\immediate\write\examples{real w1 = r1.get_point(1).get_x() - r1.get_point(0).get_x();}
\immediate\write\examples{p0.shift(.375 * w0);}
\immediate\write\examples{p1.shift(.375 * w1);}
\immediate\write\examples{p0.label("10", "lft");}
\immediate\write\examples{p1.label("45", "lft");}
\immediate\write\examples{p0 *= p1 *= r0 *= r1 *= t;}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{p0.label("100", "lft");}
\immediate\write\examples{p1.label("4950", "lft");}
\immediate\write\examples{p0 *= p1 *= r0 *= r1 *= t;}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{p0.label("1000", "lft");}
\immediate\write\examples{p1.label("499,500", "lft");}
\immediate\write\examples{p0 *= p1 *= r0 *= r1 *= t;}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{p0.label("10,000", "lft");}
\immediate\write\examples{p1.label("49,995,000", "lft");}
\immediate\write\examples{p0 *= p1 *= r0 *= r1 *= t;}
\immediate\write\examples{r0.draw();}
\immediate\write\examples{r1.draw();}
\immediate\write\examples{p0.label("100,000", "lft");}
\immediate\write\examples{p1.label("$4.99995\DBKS{times} 10^9$", "lft");}
\OEX{Projections::PARALLEL_X_Y}
\EGRP
\EEX 0
\fi
\PEX 
@end tex
@end iftex

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

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

@c I've put this here, so that it doesn't interfere with the Emacs-Lisp
@c routine I'm using to insert the figure numbers for HTML and Info
@c output.  LDF 2003.12.16.
@c
@iftex 
@tex 
\smallskip
@end tex
@end iftex

Clearly, such a hidden surface
algorithm would considerably increase run-time.  

Currently, all of the @code{Shapes} on a @code{Picture} are output, as
long as they lie completely within the boundaries passed as arguments to 
@code{Picture::output()}. 
@xref{Outputting Pictures,,Pictures; Outputting}.  It
would be more efficient to suppress output for them, if they are
completely covered by other objects.  This also requires comparisions,
and could be implemented together with a fully-functional hidden surface
algorithm. 

Shadows, reflections, highlights and shading are all effects requiring
comparing each @code{Shape} with every other @code{Shape}, and could
greatly increase run-time.  

 


