This is 3DLDF.info, produced by makeinfo version 4.5 from 3DLDF.texi.

This is the 3DLDF User and Reference Manual, edition 1.1.5 for 3DLDF
1.1.5.  This manual was last updated on 14 January 2004.  3DLDF is a
GNU package for three-dimensional drawing with MetaPost output.  The
author is Laurence D. Finston.

   Copyright (C) 2003, 2004 Laurence D. Finston.

     Permission is granted to copy, distribute and/or modify this
     document under the terms of the GNU Free Documentation License,
     Version 1.2 or any later version published by the Free Software
     Foundation; with no Invariant Sections, no Front-Cover Texts, and
     no Back-Cover Texts.  A copy of the license is included in the
     section entitled "GNU Free Documentation License".
   
INFO-DIR-SECTION GNU packages
START-INFO-DIR-ENTRY
* 3DLDF: (3DLDF).            3D drawing with MetaPost output.
END-INFO-DIR-ENTRY


File: 3DLDF.info,  Node: Rectangle Reference,  Next: Regular Closed Plane Curve Reference,  Prev: Regular Polygon Reference,  Up: Top

Rectangle Reference
*******************

   Class `Rectangle' is defined in `rectangs.web', and is derived from
`Polygon', using public derivation.

   As noted above in *Note Polygon Reference; Affine Transformations:
Affine Transformations for Polygons, `class Rectangle', like `class
Reg_Polygon', currently inherits its transformation functions and
`operator*=(const Transform&)' from `Polygon'.  Consequently, the data
members of a `Rectangle', except for `center', are not recalculated
when it's transformed.  I plan to change this soon!  It will also be
necessary to add the function `Rectangle::is_rectangular()', in order
to test whether a `Rectangle' is still rectangular.

* Menu:

* Rectangle Data Members::
* Rectangle Constructors and Setting Functions::
* Rectangle Operators::
* Returning Points for Rectangles::
* Querying Rectangles::
* Ellipses for Rectangles::


File: 3DLDF.info,  Node: Rectangle Data Members,  Next: Rectangle Constructors and Setting Functions,  Prev: Rectangle Reference,  Up: Rectangle Reference

Data Members
============

 - Private variables: real axis_h
 - : real axis_v
     The lengths of the horizontal and vertical axes, respectively, of
     the `Rectangle'.  Actually, they are merely the horizontal and
     vertical axes by convention, since there are no restrictions on
     the orientation of an `Rectangle'.

     Please note that `axis_h' and `axis_v' are currently not
     recalculated, when a `Rectangle' is transformed.  I plan to do
     something about this soon.

 - Private variable: bool on_free_store
     `true', if the `Rectangle' was dynamically allocated on the free
     store, otherwise `false'.  Dynamic allocation of `Rectangles'
     should only be performed by `create_new<Rectangle>()', which sets
     `on_free_store' to `true'.


File: 3DLDF.info,  Node: Rectangle Constructors and Setting Functions,  Next: Rectangle Operators,  Prev: Rectangle Data Members,  Up: Rectangle Reference

Constructors and Setting Functions
==================================

 - Default constructor: void Rectangle (void)
     Creates an empty `Rectangle'.

 - Constructor: void Rectangle (const Point& CCENTER, const real
          AAXIS_H, const real AAXIS_V, [const real ANGLE_X = 0, [const
          real ANGLE_Y = 0, [const real ANGLE_Z = 0]]])
     Creates a `Rectangle' in the x-z plane, centered at the origin,
     with width == AAXIS_H (in the + or - x  direction), and height ==
     AAXIS_V (in the + or - z  direction).  If one or more of the
     arguments ANGLE_X, ANGLE_Y, or ANGLE_Z are used, it is rotated by
     those amounts around the appropriate axes.  Finally, the
     `Rectangle' is shifted such that its center lies at CCENTER.

          Point C(-1, -1, 1);
          Rectangle r(C, 3, 4, 30, 30, 30);

     [Figure 151 not displayed.]


 - Setting function: void set (const Point& CCENTER, const real
          AAXIS_H, const real AAXIS_V, [const real ANGLE_X = 0, [const
          real ANGLE_Y = 0, [const real ANGLE_Z = 0]]])
     Corresponds to the constructor described above.

 - Constructor: void Rectangle (const Point& P0, const Point& P1, const
          Point& P2, const Point& P3)
     Creates `Rectangle' using four `Point' arguments.  The order of
     the arguments must correspond with a path around the `Rectangle'.

     This function does not currently check that the arguments yield a
     valid `Rectangle', therefore all code using it must ensure that
     they do.

 - Setting function: void set (const Point& PT0, const Point& PT1,
          const Point& PT2, const Point& PT3)
     Corresponds to the constructor above.

 - Template specializations: Rectangle* create_new<Rectangle> (const
          Rectangle* R)
 - : Rectangle* create_new<Rectangle> (const Rectangle& R)
     Pseudo-constructors for dynamic allocation of `Rectangles'.  They
     create a `Rectangle' on the free store and allocate memory for it
     using `new(Rectangle)'.  They return a pointer to the new
     `Rectangle'.

     If R is a non-zero pointer or a reference, the new `Rectangle'
     will be a copy of R.  If the new object is not meant to be a copy
     of an existing one, `0' must be passed to
     `create_new<Rectangle>()' as its argument.  *Note Dynamic
     Allocation of Shapes::, for more information.


File: 3DLDF.info,  Node: Rectangle Operators,  Next: Returning Points for Rectangles,  Prev: Rectangle Constructors and Setting Functions,  Up: Rectangle Reference

Operators
=========

 - Assignment Operator: const Rectangle& operator= (const Rectangle& R)
     Makes the `Rectangle' a copy of R.


File: 3DLDF.info,  Node: Returning Points for Rectangles,  Next: Querying Rectangles,  Prev: Rectangle Operators,  Up: Rectangle Reference

Returning Points
================

 - Function: Point corner (unsigned short C)
     Returns the corner `Point' indicated by the argument C, which must
     be between 0 and 3.

 - `const' function: Point mid_point (unsigned short M)
     Returns the mid-point of one of the sides.  The argument C must be
     between 0 and 3.


File: 3DLDF.info,  Node: Querying Rectangles,  Next: Ellipses for Rectangles,  Prev: Returning Points for Rectangles,  Up: Rectangle Reference

Querying
========

 - `const' functions: real get_axis_h (void)
 - : real get_axis_v (void)
     These functions return `axis_h' and `axis_v', respectively.

     Please note, that `axis_h' and `axis_v' are currently not
     recalculated, when a `Rectangle' is transformed.  I plan to do
     something about this soon.

 - `const' function: bool is_rectangular (void)
     Returns `true', if the `Rectangle' is rectangular, otherwise
     `false'.  Transformations, such as shearing, can cause
     `Rectangles' to become non-rectangular.


File: 3DLDF.info,  Node: Ellipses for Rectangles,  Prev: Querying Rectangles,  Up: Rectangle Reference

Ellipses
========

 - `const' function: Ellipse out_ellipse (`void')
     Returns the smallest `Ellipse' that surrounds the `Rectangle'.

          Point P(-1, -1, 3);
          Rectangle r(P, 3, 4, 60, 30, 15);
          Ellipse e = r.out_ellipse();
          e.filldraw(black, gray);
          r.unfilldraw(black);

     [Figure 152 not displayed.]


 - `const' function: Ellipse in_ellipse (`void')
     Returns the `Ellipse' enclosed by the `Rectangle'.

          Point P(-1, -1, 3);
          Rectangle r(P, 3, 4, 60, 30, 15);
          Ellipse e = r.in_ellipse();
          r.filldraw(black, gray);
          e.unfilldraw(black);

     [Figure 153 not displayed.]


 - `const' function: Ellipse draw_out_ellipse ([const Color&
          ddraw_color = `*Colors::default_color', [string ddashed = "",
          [string ppen = "", [Picture& picture = `current_picture']]]])
     Draws the smallest `Ellipse' that surrounds the `Rectangle'.  The
     arguments are like those of `Path::draw()' (*note Path Reference;
     Drawing and Filling: Drawing and Filling Paths.).  The return
     value is the surrounding `Ellipse'.

 - `const' function: Ellipse draw_in_ellipse ([const Color& ddraw_color
          = `*Colors::default_color', [string ddashed = "", [string
          ppen = "", [Picture& picture = `current_picture']]]])
     Draws the `Ellipse' enclosed by the `Rectangle'.  The arguments
     are like those of `Path::draw()' (*note Path Reference; Drawing
     and Filling: Drawing and Filling Paths.).  The return value is the
     enclosed `Ellipse'.


File: 3DLDF.info,  Node: Regular Closed Plane Curve Reference,  Next: Ellipse Reference,  Prev: Rectangle Reference,  Up: Top

Regular Closed Plane Curve Reference
************************************

   Class `Reg_Cl_Plane_Curve' is defined in `curves.web'.  It is
derived from `Path' using `public' derivation.

   `Reg_Cl_Plane_Curve' is not called "`Regular_Closed_Plane_Curve'"
because the longer name causes too many "Overfull boxes"(1) in the
CWEAVE output of the program code.  *Note CWEB Documentation::.

   `Reg_Cl_Plane_Curve' is meant to be used as a base class;  no
objects should be declared of type `Reg_Cl_Plane_Curve'.  Currently,
`class Ellipses' is derived from `Reg_Cl_Plane_Curve' and `class
Circle' is derived from `Ellipse'.

   At present, I have no fixed definition of what constitutes
"regularity" as far as `Reg_Cl_Plane_Curves' are concerned.  Ellipses
and circles are "regular" in the sense that they have axes of symmetry.
There must be an equation for a `Reg_Cl_Plane_Curve', such as x^2 +
y^2 = r^2 for a circle.  A derived class should have a `solve()'
function that uses this equation.
`Reg_Cl_Plane_Curve::intersection_points()' in turn uses `solve()' to
find the intersection points of a line with the `Reg_Cl_Plane_Curve'.
This way, the derived classes don't need their own functions for
finding their intersections with a line.  However, such functions can
be added, if desired.

   It is assumed that classes derived from `Reg_Cl_Plane_Curve' are
fillable, which implies that they must be closed `Paths'.
`Reg_Cl_Plane_Curves' inherit their drawing and filling functions from
`Path'.

   The constructors and setting functions of classes derived from
`Reg_Cl_Plane_Curve' must ensure that the resulting geometric figures
are planar, convex, and that the number of `Points' they contain is a
multiple of 4.  The latter assumption is of importance in
`intersection_points()', `segment()', `half()', and `quarter()'.  *Note
Regular Closed Plane Curve Reference; Intersections: Regular Closed
Plane Curve Intersections, and *Note Regular Closed Plane Curve
Reference; Segments: Regular Closed Plane Curve Segments.

* Menu:

* Regular Closed Plane Curve Data Members::
* Querying Regular Closed Plane Curves::
* Regular Closed Plane Curve Intersections::
* Regular Closed Plane Curve Segments::

   ---------- Footnotes ----------

   (1) If you don't know what "overfull boxes" are, don't worry about
it.  It has to do with TeX's line and page breaking algorithms.  If you
want to know more, see Knuth, Donald E., `The TeXbook'.


File: 3DLDF.info,  Node: Regular Closed Plane Curve Data Members,  Next: Querying Regular Closed Plane Curves,  Prev: Regular Closed Plane Curve Reference,  Up: Regular Closed Plane Curve Reference

Data Members
============

 - Protected variable: Point center
     The center of the `Reg_Cl_Plane_Curve', if it has one.

 - Protected variable: unsigned short number_of_points
     The number of `Points' on `points' in a `Reg_Cl_Plane_Curve'.


File: 3DLDF.info,  Node: Querying Regular Closed Plane Curves,  Next: Regular Closed Plane Curve Intersections,  Prev: Regular Closed Plane Curve Data Members,  Up: Regular Closed Plane Curve Reference

Querying
========

 - `const' inline virtual functions: bool is_quadratic (void)
 - : bool is_cubic (void)
 - : bool is_quartic (void)
     These functions all return `false'.  They are intended to be
     overloaded by member functions of derived classes.

 - `const' inline virtual function: real_triple get_coefficients (real
          SLOPE, real V_INTERCEPT)
     Returns a `real_triple' with all three values == `INVALID_REAL'.
     Intended to be overloaded by member functions of derived classes.

 - `const' inline virtual function: pair<real, real> solve (char
          AXIS_UNKNOWN, real KNOWN)
     Returns a `pair<real, real>' with `first' = `second' =
     `INVALID_REAL'.  Intended to be overloaded by member functions of
     derived classes.

 - `const' virtual function: signed short location (Point REF_PT, Point
          P)
     Returns a `signed short' indicating the location of P with respect
     to the `Reg_Cl_Plane_Curve', which must be planar.  The
     `Reg_Cl_Plane_Curve' constructors should ensure that
     `Reg_Cl_Plane_Curves' are, but there is no guarantee that they will
     not have been manipulated into a non-planar state, by shearing, for
     example.

     The argument REF_PT is used within the function for shifting a
     copy of the `Reg_Cl_Plane_Curve' to a convenient position.  It
     need not be the |center| of the `Reg_Cl_Plane_Curve', however,
     classes derived from `Reg_Cl_Plane_Curve' will probably have their
     own versions of `location()', which will pass `center' as the
     REF_PT argument to this function.  `Reg_Cl_Plane_Curves' need not
     have a meaningful |center|.

     `location()' returns the following values:
    -1
          P and `*this' are coplanar, and P lies outside the perimeter
          of `*this'.

    0
          P and `*this' are coplanar, and P lies on the perimeter of
          `*this'.

    1
          P and `*this' are coplanar, and P lies inside the perimeter
          of `*this'.

    -2
          P and `*this' are not coplanar.

    -3
          Something has gone terribly wrong.

    -4
          The normal to `*this' has 0 magnitude, i.e., the |Points| on
          `*this' are colinear.

    -5
          An error occurred in putting `*this' in one of the major
          planes.

 - Virtual function: Point angle_point (real ANGLE)
     Returns `INVALID_POINT'.  Intended to be overloaded by member
     functions of derived classes.


File: 3DLDF.info,  Node: Regular Closed Plane Curve Intersections,  Next: Regular Closed Plane Curve Segments,  Prev: Querying Regular Closed Plane Curves,  Up: Regular Closed Plane Curve Reference

Intersections
=============

 - `const' function: bool_point_pair intersection_points (Point REF_PT,
          Point P0, Point P1)
 - `const' function: bool_point_pair intersection_points (const Point&
          REF_PT, const Path& P)
     The version of this function taking `Point' arguments finds the
     intersection points, if any, of the `Reg_Cl_Plane_Curve' and the
     line p that passes through the `Points' p_0 and p_1.  In the other
     version, the `Path' argument must be a linear `Path', and its
     first and last `Points' are passed to the first version of this
     function as P0 and P1, respectively.

     Let C be the `Reg_Cl_Plane_Curve'.  C and p can intersect at at
     most two intersection points i_1 and i_2.  Let `bpp' be the return
     value of this function.  The intersection points need not be on
     the _line segment_ between `pt0' and `pt1'.  `bpp.first.pt' will
     be set to the first intersection point if it exists, or
     `INVALID_POINT' if it doesn't.  If the first intersection point
     exists and is on the line segment between `pt0' and `pt1'

     In [next figure] , the line AB  is normal to the `Ellipse' e, or,
     to put it another way, AB  is perpendicular to the plane of e.
     The intersection point i_0 lies within the perimeter of e.

     The line DE  is skew to the plane of e, and intersects e at i_1,
     on the perimeter of e.

          Point p0(2, 2, 3);
          Ellipse e(p0, 3, 4, 30, -60, -5.2);
          Point p1 = p0.mediate(e.get_point(11), .5);
          Point A = e.get_normal();
          A *= 2.5;
          A.shift(p1);
          Point B = A.mediate(p1, 2);
          bool_point_pair bpp = e.intersection_points(A, B);
          Point C(0, 2, 0);
          Point D(0, -3.5, 0);
          C *= D.rotate(2, 0, -5);
          C *= D.shift(e.get_point(4));
          bpp = e.intersection_points(C, D);

     [Figure 154 not displayed.]

     In [next figure] , q and e are coplanar.  In this case, only the
     intersections of q with the perimeter of e are returned by
     `intersection_points()'.

          A = p0.mediate(e.get_point(3), 1.5);
          B = p0.mediate(e.get_point(11), 1.5);
          Path q(A, B);
          bpp = e.intersection_points(q);

     [Figure 155 not displayed.]



File: 3DLDF.info,  Node: Regular Closed Plane Curve Segments,  Prev: Regular Closed Plane Curve Intersections,  Up: Regular Closed Plane Curve Reference

Segments
========

 - `const' function: Path segment (unsigned int FACTOR, [real ANGLE =
          0, [bool CLOSED = `true']])
     Returns a `Path' representing a segment of the
     `Reg_Cl_Plane_Curve'.  FACTOR must be >1 and <=
     `number_of_points'.  If it is not, an error message is issued and
     an empty `Path' is returned.

     If ANGLE is non-zero, the segment `Path' is rotated by ANGLE about
     a line from `center' in the direction of the normal to the plane
     of the `Reg_Cl_Plane_Curve'.  Please note, that a
     `Reg_Cl_Plane_Curve' must have a meaningful `center', in order for
     rotation to work.  If the absolute value of ANGLE >360, a warning
     is issued, and `fmod(ANGLE, 360)' is used.

     If CLOSED is `true', the `Path' will be a cycle, with the ends of
     the curved segment joined using the connector `--'.  The curved
     segment is joined to the line using `&' on each side.

          Circle c(origin, 4, 30, 30, 30);
          Path p = c.segment(3, 130);
          p.show("p:");
          -| p:
          points.size() == 8
          connectors.size() == 8(-0.00662541, -0.888379, -1.79185) ..
          (0.741088, -0.673392, -1.73128) ..
          (1.37598, -0.355887, -1.40714) ..
          (1.80139, 0.0157987, -0.868767) ..
          (1.95255, 0.385079, -0.198137) .. (1.80646, 0.695735, 0.502658) &
          (1.80646, 0.695735, 0.502658) --
          (-0.00662541, -0.888379, -1.79185) & cycle;

     [Figure 156 not displayed.]


 - `const' inline function: Path half ([real ANGLE = 0, [bool CLOSED =
          true]])
     Returns a `Path' using half of the `Points' on the
     `Reg_Cl_Plane_Curve'.  The effect of the arguments ANGLE and
     CLOSED is similar to that in `segment()', above.

          Ellipse e(origin, 3, 5, 20, 15, 12.5);
          Path p = e.half(0, false);

     [Figure 157 not displayed.]


 - `const' inline function: Path quarter ([real ANGLE = 0, [bool CLOSED
          = `true']])
     Returns a `Path' using a quarter of the `Points' on the
     `Reg_Cl_Plane_Curve'.  The effect of the arguments ANGLE and
     CLOSED is similar to that in `segment()', above.

          Ellipse e(origin, 3, 5, 60, 5, 2.5);
          Path p = e.quarter(180, false);

     [Figure 158 not displayed.]



File: 3DLDF.info,  Node: Ellipse Reference,  Next: Circle Reference,  Prev: Regular Closed Plane Curve Reference,  Up: Top

Ellipse Reference
*****************

   Class `Ellipse' is defined in `ellipses.web'.  It is derived from
`Reg_Cl_Plane_Curve' using public derivation.

* Menu:

* Ellipse Data Members::
* Ellipse Constructors and Setting Functions::
* Performing Transformations on Ellipses::
* Ellipse Operators::
* Labeling Ellipses::
* Affine Transformations for Ellipses::
* Querying Ellipses::
* Returning Elements and Information for Ellipses::
* Ellipse Intersections::
* Solving Ellipses::
* Rectangles for Ellipses::


File: 3DLDF.info,  Node: Ellipse Data Members,  Next: Ellipse Constructors and Setting Functions,  Prev: Ellipse Reference,  Up: Ellipse Reference

Data Members
============

 - Protected variables: Point focus0
 - : Point focus1
     The foci of the `Ellipse'.  They are located on the major axis of
     the `Ellipse' at a distance of `linear_eccentricity' from
     `center', on opposite sides of the minor axis.

 - Protected variable: real linear_eccentricity
     The linear eccentricity of the `Ellipse' e, such that e = \sqrta^2
     - b^2, where a and b are half the lengths of the major and minor
     axes, respectively.  Let h stand for `axis_h' and v for `axis_v'.
     If h>v, then a = h/2 and b = v/2.  If v>h, then a =v/2 and b =
     h/2.  If h = v, then the `Ellipse' is circular (but not an object
     of type  `Circle'!), and a = b = v/2 = h/2.

     The linear eccentricity is the distance along the major axis of the
     `Ellipse' from `center' to `focus0' and `focus1'.

 - Protected variable: real numerical_eccentricity
     The numerical eccentricity \epsilon of the `Ellipse', such that
     \epsilon = e/a < 1, where e is the linear eccentricity of the
     `Ellipse', and a is half the length of the major axis of the
     `Ellipse'.

 - Protected variables: real axis_h
 - : real axis_v
     The horizontal and vertical axes, respectively, of the `Ellipse'.

     Actually, they are only or vertical horizontal by convention,
     since there are no restrictions on the orientation of an `Ellipse'.

 - Protected static variable: unsigned short DEFAULT_NUMBER_OF_POINTS
     The number of `Points' on an `Ellipse', unless another number is
     specified when an `Ellipse' constructor is invoked.


File: 3DLDF.info,  Node: Ellipse Constructors and Setting Functions,  Next: Performing Transformations on Ellipses,  Prev: Ellipse Data Members,  Up: Ellipse Reference

Constructors and Setting Functions
==================================

 - Default constructor: void Ellipse (void)
     Creates an empty `Ellipse'.

 - Constructor: void Ellipse (const Point& CCENTER, const real AAXIS_H,
          const real AAXIS_V, [const real ANGLE_X = 0, [const real
          ANGLE_Y = 0, [const real ANGLE_Z = 0, [const unsigned short
          NNUMBER_OF_POINTS = DEFAULT_NUMBER_OF_POINTS]]]])
     Creates an `Ellipse' in the x-z plane, centered at the origin, with
     its horizontal axis == AAXIS_H and its vertical axis == AAXIS_V.
     If any of the arguments ANGLE_X, ANGLE_Y, or ANGLE_Z is non-zero,
     the `Ellipse' is rotated about the x, y, and z-axis in that order,
     by the amounts indicated by the corresponding arguments.  Finally,
     the `Ellipse' is shifted such that its center comes to lie at
     CCENTER.

          Ellipse e(origin, 6, 4);
          e.draw();

     [Figure 159 not displayed.]

          Point P(1, 1, 1);
          Ellipse e(P, 6, 4, 15, 12, 11);
          e.draw();

     [Figure 160 not displayed.]


 - Setting function: void set (const Point& CCENTER, const real
          AAXIS_H, const real AAXIS_V, [const real ANGLE_X = 0, [const
          real ANGLE_Y = 0, [const real ANGLE_Z = 0, [const unsigned
          short NNUMBER_OF_POINTS = DEFAULT_NUMBER_OF_POINTS]]]])
     Corresponds to the constructor above.

 - Template specializations: Ellipse* create_new<Ellipse> (const
          Ellipse* E)
 - : Ellipse* create_new<Ellipse> (const Ellipse& E)
     Pseudo-constructors for dynamic allocation of `Ellipses'.  They
     create a `Ellipse' on the free store and allocate memory for it
     using `new(Ellipse)'.  They return a pointer to the new `Ellipse'.

     If E is a non-zero pointer or a reference, the new `Ellipse' will
     be a copy of E.  If the new object is not meant to be a copy of an
     existing one, `0' must be passed to `create_new<Ellipse>()' as its
     argument.  *Note Dynamic Allocation of Shapes::, for more
     information.


File: 3DLDF.info,  Node: Performing Transformations on Ellipses,  Next: Ellipse Operators,  Prev: Ellipse Constructors and Setting Functions,  Up: Ellipse Reference

Performing Transformations
==========================

 - Virtual function: Transform do_transform (const Transform& T, [bool
          CHECK = `false'])
     Performs a transformation on an `Ellipse'.  The `Points' on the
     `Ellipse' are multiplied by T.  Then, if CHECK is `true',
     `is_elliptical()' is called on the `Ellipse'.  If the
     transformation has caused it to become non-elliptical, `axis_h'
     and `axis_v' are set to `INVALID_REAL', and a warning is issued to
     `stderr'.  `center', `focus0', and `focus1' are not set to
     `INVALID_POINT'.  They may may no longer really be the center and
     foci of the (non-elliptical) `Ellipse', but they may have some use
     for the programmer and/or user.

     If CHECK is `true', and the transformation does not cause `*this'
     to become non-elliptical, `axis_h', `axis_v',
     `linear_eccentricity', `numerical_eccentricity', `focus0', and
     `focus1' are recalculated.



File: 3DLDF.info,  Node: Ellipse Operators,  Next: Labeling Ellipses,  Prev: Performing Transformations on Ellipses,  Up: Ellipse Reference

Operators
=========

 - Assignment operator: Ellipse& operator= (const Ellipse& E)
     Makes the `Ellipse' a copy of E.

 - Virtual function: Transform operator*= (const Transform& T)
     Calls `do_transform(t, true)', and returns the latter's return
     value.  *Note Ellipse Reference; Performing Transformations:
     Performing Transformations on Ellipses.


File: 3DLDF.info,  Node: Labeling Ellipses,  Next: Affine Transformations for Ellipses,  Prev: Ellipse Operators,  Up: Ellipse Reference

Labeling
========

 - `const' function: void label ([const string POS = "top", [const bool
          DOT = `false', [Picture& PICTURE = `current_picture']]])
     Labels the `Points' on `points', using lowercase letters.  POS is
     used to position all of the labels.  It is currently not possible
     to have different positions for the labels.

          Ellipse e(origin, 6, 4);
          e.draw();
          e.label();

     [Figure 161 not displayed.]


 - Inline `const' function: void dotlabel ([string POS = "top",
          [Picture& PICTURE = `current_picture']])
     Like `label()', except that the `Points' are dotted.

          Ellipse e(origin, 6, 4);
          e.draw();
          e.dotlabel();

     [Figure 162 not displayed.]



File: 3DLDF.info,  Node: Affine Transformations for Ellipses,  Next: Querying Ellipses,  Prev: Labeling Ellipses,  Up: Ellipse Reference

Affine Transformations
======================

 - Virtual function: Transform rotate (const real X, [const real Y = 0,
          [const real Z = 0]])
 - Virtual function: Transform rotate (const Point& P0, const Point&
          P1, [const real ANGLE = 180])
 - Virtual function: Transform rotate (const Path& P, [const real ANGLE
          = 180])
 - Virtual function: Transform scale (real X, [real Y = 1, [real Z =
          1]])
 - Virtual function: Transform shear (real XY, [real XZ = 0, [real YX =
          0, [real YZ = 0, [real ZX = 0, [real ZY = 0]]]]])
 - Virtual function: Transform shift (real X, [real Y = 0, [real Z =
          0]])
 - Virtual function: Transform shift (const Point& P)
 - Virtual function: void shift_times (real X, [real Y = 1, [real Z =
          1]])
 - Virtual function: void shift_times (const Point& P)
     These create a `Transform' T locally, and call `do_transform(t)'.
     *Note Ellipse Reference; Performing Transformations: Performing
     Transformations on Ellipses.

     Rotating and shifting an `Ellipse' neither change the size of an
     `Ellipse', nor cause it to become non-elliptical.  However,
     scaling and shearing can have these effects.  For this reason, in
     `scale()' and `shear()', `do_transform()' is called with `true' as
     its CHECK argument, while it is `false' in `rotate()', `shift()',
     and `shift_times()'.

     If scaling or shearing is performed on an `Ellipse', and it is
     still elliptical after the transformation, `focus0', `focus1',
     `axis_h', `axis_v', `linear_eccentricity', and
     `numerical_eccentricity' are all recalculated.  If the `Ellipse'
     is non-elliptical after the transformation, `axis_h', `axis_v',
     `linear_eccentricity', and `numerical_eccentricity' are all set to
     `INVALID_REAL'.  `center', `focus0', and `focus1' are not set to
     `INVALID_POINT'.  Although they are no longer the center and foci
     of an elliptical `Ellipse', they may still have some use for the
     user or programmer.


File: 3DLDF.info,  Node: Querying Ellipses,  Next: Returning Elements and Information for Ellipses,  Prev: Affine Transformations for Ellipses,  Up: Ellipse Reference

Querying
========

 - `const' function: bool is_elliptical (void)
     Returns `true' if the `Ellipse' is elliptical, otherwise `false'.

     Certain transformations, such as shearing and scaling, can cause
     `Ellipses' to become non-elliptical.

 - Inline `const' function: bool is_quadratic (`void')
     Returns `true', because the equation for an ellipse in the x-y
     plane with its center at the origin is the quadratic equation
     x^2/a^2 + y^2/b^2 = 1 where a is half the horizontal axis and b is
     half the vertical axis.

          Ellipse e(origin, 5, 2, 90);
          e.draw();
          Point P(e.angle_point(-35));
          cout << ((P.get_x() * P.get_x())
                   / (e.get_axis_h()/2 * e.get_axis_h()/2))
                  + ((P.get_y() * P.get_y())
                     / (e.get_axis_v()/2 * e.get_axis_v()/2));
          -| 1

     [Figure 163 not displayed.]


 - `const' virtual functions: bool is_cubic (`void')
 - : bool is_quartic (`void')
     These functions both return `false', because the equation of an
     ellipse is neither a cubic nor a quartic function.


File: 3DLDF.info,  Node: Returning Elements and Information for Ellipses,  Next: Ellipse Intersections,  Prev: Querying Ellipses,  Up: Ellipse Reference

Returning Elements and Information
==================================

 - Virtual function: Point& get_center (`void')
 - `const' virtual function: Point get_center (`void')
     These functions return `center'.

 - Function: const Point& get_focus (const unsigned short S)
 - `const' function: Point get_focus (const unsigned short S)
     These functions return `focus0' or `focus1', depending on the
     value of S, which must be 0 or 1.  If S is not 0 or 1,
     `get_focus()' returns `INVALID_POINT'.

 - `const' function: real get_linear_eccentricity (void)
     Returns `linear_eccentricity'.

 - `const' function: real get_numerical_eccentricity (void)
     Returns `numerical_eccentricity'.

 - Function: real get_axis_v (`void')
 - `const' function: real get_axis_v (`void')
     Calculates and returns the value of `axis_h'.

     `get_axis_v()' first checks if the `Ellipse' is still elliptical,
     using `is_elliptical()' (*note Ellipse Reference; Querying:
     Querying Ellipses.).  Operations such as `scale()' and `shear()'
     can cause an `Ellipse' to become non-elliptical.  If this is the
     case, this function returns `INVALID_REAL'.

     If the `Ellipse' is still elliptical, `axis_v' is recalculated and
     returned.  In the non-`const' version, `axis_v' is also reset to
     the new value.

 - Function: real get_axis_h (`void')
 - `const' function: real get_axis_h (`void')
     Calculates and returns the value of `axis_h'.

     `get_axis_h()' first checks if the `Ellipse' is still elliptical,
     using `is_elliptical()' (*note Ellipse Reference; Querying:
     Querying Ellipses.).  Operations such as `scale()' and `shear()'
     can cause an `Ellipse' to become non-elliptical.  If this is the
     case, this function returns `INVALID_REAL'.

     If the `Ellipse' is still elliptical, `axis_h' is recalculated and
     returned.  In the non-`const' version, `axis_h' is also reset to
     the new value.

 - `const' virtual function: signed short location (Point P)
     Returns a value l indicating the location of the `Point' argument
     p with respect to the `Ellipse'.

     Let e stand for the `Ellipse'.  The return values are as follows:

    0
          p lies on the perimeter of e.

    1
          p lies in the plane of e, within its perimeter.

    -1
          p lies in the plane of e, outside its perimeter.

    -2
          p and e do not lie in the same plane.

    -3
          e is not elliptical, possibly due to having been transformed.

          Ellipse e(origin, 3, 5, 45, 15, 3);
          e.shift(2, 1, 1);
          Point A = e.get_point(7);
          cout << e.location(A);
          -| 0
          Point B = center.mediate(e.get_point(2));
          cout << e.location(B);
          -| 1
          Point C = center.mediate(e.get_point(2), 1.5);
          cout << e.location(C);
          -| -1
          Point D = A;
          D.shift(-2, 0, 4);
          e.location(D);
          -| WARNING! In Ellipse::location():
             Point doesn't lie in plane of Ellipse.
             Returning -2.
          e.scale(1.5, 0, 1.5);
          e.location(A);
          -| WARNING! In Ellipse::do_transform(const Transform&):
             This transformation has made *this non-elliptical!
          
             ERROR! In Ellipse::location():
             Ellipse is non-elliptical. Returning -3.

     [Figure 164 not displayed.]


 - `const' function: Point angle_point (real ANGLE)
     Returns a point on the `Ellipse' given an angle.  A `Point' P is
     set to the zeroth `Point' on the `Ellipse' and rotated about the
     line from the center of the `Ellipse' in the direction of the
     normal to the plane of the `Ellipse'.  Then, the intersection of
     the ray from the center through P and the perimeter of the
     `Ellipse' is returned.

          Ellipse e(origin, 6, 4);
          Point P = e.angle_point(135);
          current_picture.output(Projections::PARALLEL_X_Z);

     [Figure 165 not displayed.]

     [next figure]  demonstrates, that the rotation is unfortunately
     not always in the direction one would prefer.  I don't have a
     solution to this problem yet.

          Ellipse e(origin, 6, 4, 90);
          Point P = e.angle_point(135);
          Point Q = e.angle_point(-135);

     [Figure 166 not displayed.]



File: 3DLDF.info,  Node: Ellipse Intersections,  Next: Solving Ellipses,  Prev: Returning Elements and Information for Ellipses,  Up: Ellipse Reference

Intersections
=============

 - `const' virtual function: bool_point_pair intersection_points (const
          Point& P0, const Point& P1)
 - `const' virtual function: bool_point_pair intersection_points (const
          Path& P)
     These functions return the intersection points of a line with an
     `Ellipse'.  In the first version, the line is specified by the two
     `Point' arguments.  In the second version, `P.is_linear()' must
     return `true', otherwise, `intersection_points()' issues an error
     message and returns `INVALID_BOOL_POINT_PAIR'.

     If the line and the `Ellipse' are coplanar, there can be at most
     two intersection points.  Otherwise, there can be at most one.

          Ellipse e(origin, 5, 7, 30, 30, 30);
          e.shift(3, 0, 3);
          Point p0 = e.get_center().mediate(e.get_point(3));
          Point normal = e.get_normal();
          Point A = normal;
          A *= 2.5;
          A.shift(p0);
          Point B = normal;
          B *= -2.5;
          B.shift(p0);
          bool_point_pair bpp = e.intersection_points(A, B);
          bpp.first.pt.dotlabel("$i_0$", "rt");
          Point C = e.get_point(15).mediate(e.get_point(11), 1.25);
          Point D = e.get_point(11).mediate(e.get_point(15), 1.5);
          Path q = C.draw(D);
          bpp = e.intersection_points(q);
          bpp.first.pt.dotlabel("$i_1$", "llft");
          bpp.second.pt.dotlabel("$i_2$", "ulft");

     [Figure 167 not displayed.]


 - `const' virtual function: bool_point_quadruple intersection_points
          (Ellipse E, [const real STEP = 3, [bool VERBOSE = `false']])
     Returns the intersection points of two `Ellipses'.  Two `Ellipses'
     can intersect at at most four points.

     Let BPQ be the `bool_point_quadruple' returned by
     `intersection_points()'.  If one or more intersection points are
     found, the corresponding `Points' are stored in the `pt' elements
     of the four `bool_points' belonging to BPQ, otherwise
     `INVALID_POINT'.  If a `Point' is found, the `b' element of the
     `bool_point' will be `true', otherwise `false'.

     The STEP argument is used when the `Ellipses' are coplanar and
     either have different centers or the vertical axis of one
     `Ellipse' is colinear with the horizontal axis of the other (and
     vice versa).  In these cases, the intersection points must be
     found by an iterative routine.  A `Point' p travels around the
     perimeter of `*this', and its location with respect to E is
     tested.  STEP is the angle of rotation used for stepping around
     the perimeter of `*this'.  The default value, 3, should be
     adequate, unless the `Ellipses' differ greatly in size.

     If the VERBOSE argument is `true', `intersection_points()' will
     print information about the intersection points to standard output.

     In [next figure] , the `Ellipses' e and f both lie in the x-z
     plane, are centered at the origin, and intersect at four points.

          Ellipse e(origin, 5, 2);
          Ellipse f(origin, 2, 5);
          bool_point_quadruple bpq = e.intersection_points(f);
          bpq.first.pt.dotlabel(1, "llft");
          bpq.second.pt.dotlabel(2, "urt");
          bpq.third.pt.dotlabel(3, "ulft");
          bpq.fourth.pt.dotlabel(4, "lrt");

     [Figure 168 not displayed.]

     In [next figure] , e and f are coplanar, but don't lie in a major
     plane, have different centers, and only intersect at two points.

          Ellipse e(origin, 4, 2);
          Ellipse f(origin, 2, 5);
          f.shift(0, 0, 1);
          f.rotate(0, 15);
          f.shift(1, 0, 1);
          e *= f.shift(-.25, 1, -1);
          e *= f.rotate(10, -12.5, 3);
          bool_point_quadruple bpq = e.intersection_points(f, true);
          bpq.first.pt.dotlabel(1, "urt");
          bpq.second.pt.dotlabel(2, "ulft");

     [Figure 169 not displayed.]

     If the planes of the `Ellipses' are parallel, there are, of course,
     no intersection points.  If the `Ellipses' are non-coplanar, and
     their planes are not parallel to each other,
     `intersection_points()' first finds the line of intersection of the
     planes of the `Ellipses'.  It then returns the `Points' of
     intersection of this line with the `Ellipses', if they exist.  If
     the VERBOSE argument is `true', information about the `Points' is
     printed to standard output.

     In [next figure] , the two `Ellipses' lie in skew planes.  The
     plane of f intersects with e at the `Points' labelled "1" and "2",
     while the plane of e intersects with f at the `Points' labelled
     "3" and "4".

          Ellipse e(origin, 5, 3);
          Ellipse f(origin, 2, 5);
          f.rotate(0, 0, 30);
          f.rotate(0, 10);
          f.rotate(45);
          f.shift(1.5, 1);
          bool_point_quadruple bpq = e.intersection_points(f, true);
          bpq.first.pt.dotlabel(1);
          bpq.second.pt.dotlabel(2);
          bpq.third.pt.dotlabel(3, "rt");
          bpq.fourth.pt.dotlabel(4, "urt");
          -| First point lies on the perimeter of *this.
             First point lies inside e.
             Second point lies on the perimeter of *this.
             Second point lies outside e.
             Third point lies outside *this.
             Third point lies on the perimeter of e.
             Fourth point lies inside *this.
             Fourth point lies on the perimeter of e.

     [Figure 170 not displayed.]

     In [next figure] , the two `Ellipses' lie in skew planes.  The
     plane of f intersects with e at the `Points' labelled "1" and "2".
     The plane of e does not intersect with f, so `bpq.third.pt' and
     `bpq.fourth.pt' are `INVALID_POINT'.

          Ellipse e(origin, 5, 3);
          Ellipse f(origin, 2, 5, 45);
          f.shift(0, 2.5, 3);
          bool_point_quadruple bpq = e.intersection_points(f, true);
          bpq.first.pt.dotlabel(1);
          bpq.second.pt.dotlabel(2);
          -| First point lies on the perimeter of *this.
             First point lies outside e.
             Second point lies on the perimeter of *this.
             Second point lies outside e.
             Third intersection point is INVALID_POINT.
             Fourth intersection point is INVALID_POINT.

     [Figure 171 not displayed.]



File: 3DLDF.info,  Node: Solving Ellipses,  Next: Rectangles for Ellipses,  Prev: Ellipse Intersections,  Up: Ellipse Reference

Solving
=======

 - `const' function: real_pair solve (char AXIS_UNKNOWN, real KNOWN)
     Returns two possible values for either the horizontal or vertical
     coordinate.  This function assumes that the `Ellipse' lies in a
     major plane with `center' at the origin.  Code that calls it must
     ensure that these conditions are fulfilled.

     `solve()' is called in
     `Reg_Cl_Plane_Curve::intersection_points(Point, Point, Point)' and
     `Reg_Cl_Plane_Curve::location()', and resolves to this function,
     when these functions are called on an `Ellipse'.  However,
     `Ellipse::location()' overloads `Reg_Cl_Plane_Curve::location()',
     so the latter won't normally be called on an `Ellipse'.  *Note
     Regular Closed Plane Curve Reference; Intersections: Regular
     Closed Plane Curve Intersections, and *Note Regular Closed Plane
     Curve Reference; Querying: Querying Regular Closed Plane Curves.


 - `const' function: real_triple get_coefficients (real SLOPE, real
          V_INTERCEPT)
     Let x and y stand for the x and y-coordinates of a point on an
     ellipse in the x-y plane, a for half of the horizontal axis
     (`axis_h' / 2), and b for half of the vertical axis (`axis_v' / 2).

     Further, let y = mx + i be the equation of a line in the x-y
     plane, where m is the slope and i the y-intercept.

     This function returns the coefficients of the quadratic equation
     that results from replacing y with mx + i in the equation for the
     ellipse

          x^2/a^2 + y^2/b^2 = 1

     namely
          x^2/a^2 + (mx + i)^2/b^2 - 1 = 0
          == (b^2x + a^2m^2)x^2 + 2a^2imx + (a^2i^2 - a^2b^2) = 0.
     The coefficients are returned in the `real_triple' in the order
     one would expect: `r.first' is the coefficient of x^2, `r.second'
     of x and `r.third' of the constant term (x^0 == 1).

     `get_coefficients()' is called in
     `Reg_Cl_Plane_Curve::intersection_points(Point, Point, Point)', and
     resolves to this function, when the latter is called on an
     `Ellipse'.  *Note Regular Closed Plane Curve Reference;
     Intersections: Regular Closed Plane Curve Intersections.


File: 3DLDF.info,  Node: Rectangles for Ellipses,  Prev: Solving Ellipses,  Up: Ellipse Reference

Rectangles
==========

 - `const' function: Rectangle out_rectangle (`void')
     Returns the `Rectangle' that surrounds the `Ellipse'.

          Ellipse e(origin, 3, 4, 45, 30, 17);
          e.shift(1, -1, 2);
          Rectangle r = e.out_rectangle();
          r.filldraw(black, gray);
          e.unfilldraw(black);

     [Figure 172 not displayed.]


 - `const' function: Rectangle in_rectangle (`void')
     Returns the `Rectangle' enclosed within the `Ellipse'.

          Rectangle r = e.in_rectangle();
          e.filldraw(black, gray);
          r.unfilldraw(black);

     [Figure 173 not displayed.]


 - `const' function: Rectangle draw_out_rectangle ([const Color&
          DDRAW_COLOR = `*Colors::default_color', [string DDASHED = "",
          [string PPEN = "", [Picture& PICTURE = `current_picture']]]])
     Draws the `Rectangle' that surrounds the `Ellipse'.  The arguments
     are like those of `Path::draw()'.  The return value is the
     surrounding `Rectangle'.  *Note Path Reference; Drawing and
     Filling: Drawing and Filling Paths.

          Ellipse e(origin, 2.5, 5, 10, 12, 15.5);
          e.shift(-1, 1, 1);
          e.draw_out_rectangle(black, "evenly", "pencircle scaled .3mm");

     [Figure 174 not displayed.]


 - `const' function: Rectangle draw_in_rectangle ([const Color&
          DDRAW_COLOR = `*Colors::default_color', [string DDASHED = "",
          [string PPEN = "", [Picture& PICTURE = `current_picture']]]])
     Draws the `Rectangle' enclosed within the `Ellipse'.  The arguments
     are like those of `Path::draw()'.  The return value is the
     enclosed `Rectangle'.  *Note Path Reference; Drawing and Filling:
     Drawing and Filling Paths.

          Ellipse e(origin, 3.5, 6, 10, 12, 15.5);
          e.shift(-1, 1, 1);
          e.draw_in_rectangle(black, "evenly", "pencircle scaled .3mm");

     [Figure 175 not displayed.]



File: 3DLDF.info,  Node: Circle Reference,  Next: Pattern Reference,  Prev: Ellipse Reference,  Up: Top

Circle Reference
****************

   Class `Circle' is defined in `circles.web'.  It is derived from
`Ellipse', using public derivation.

   Since `Circle' is just a special kind of `Ellipse', there is often
no need to define special functions for `Circles'.

   Currently, `Circle' inherits the transformation functions and
`operator*=(const Transform&)' from `Ellipse'.  Consequently, the data
member `radius', described below, is not recalculated, when
transformations are performed on a `Circle'.  I plan to change this
soon!

* Menu:

* Circle Data Members::
* Circle Constructors and Setting Functions::
* Circle Operators::
* Querying Circles::
* Circle Intersections::


File: 3DLDF.info,  Node: Circle Data Members,  Next: Circle Constructors and Setting Functions,  Prev: Circle Reference,  Up: Circle Reference

Data Members
============

 - Private variable: real radius
     The radius of the `Circle'.


File: 3DLDF.info,  Node: Circle Constructors and Setting Functions,  Next: Circle Operators,  Prev: Circle Data Members,  Up: Circle Reference

Constructors and Setting Functions
==================================

 - Default constructor: `void' Circle (`void')
     Creates an empty `Circle'.

 - Constructor: `void' Circle (const Point& CCENTER, const real
          DDIAMETER, [const real ANGLE_X = 0, [const real ANGLE_Y = 0,
          [const real ANGLE_Z = 0, [const unsigned short
          NNUMBER_OF_POINTS = `DEFAULT_NUMBER_OF_POINTS']]]])
     Creates a `Circle' with `radius' == DDIAMETER/2 in the x-z plane
     and centered at the origin with NNUMBER_OF_POINTS `Points'.  If
     any of the arguments ANGLE_X, ANGLE_Y, or ANGLE_Z is `!= 0', the
     `Circle' is rotated around the major axes by the angles indicated
     by the arguments.  Finally, the `Circle' is shifted such that
     `center' comes to lie at CCENTER.

 - Setting function: void set (const Point& CCENTER, const real
          DDIAMETER, [const real ANGLE_X = 0, [const real ANGLE_Y = 0,
          [const real ANGLE_Z = 0]]])
     Corresponds to the constructor above.

 - Template specializations: Circle* create_new<Circle> (const Circle*
          C)
 - : Circle* create_new<Circle> (const Circle& C)
     Pseudo-constructors for dynamic allocation of `Circles'.  They
     create a `Circle' on the free store and allocate memory for it
     using `new(Circle)'.  They return a pointer to the new `Circle'.

     If C is a non-zero pointer or a reference, the new `Circle' will
     be a copy of C.  If the new object is not meant to be a copy of an
     existing one, `0' must be passed to `create_new<Circle>()' as its
     argument.  *Note Dynamic Allocation of Shapes::, for more
     information.


File: 3DLDF.info,  Node: Circle Operators,  Next: Querying Circles,  Prev: Circle Constructors and Setting Functions,  Up: Circle Reference

Operators
=========

 - Assignment operator: Circle& operator= (const Circle& C)
     Makes the `Circle' a copy of C.

 - Assignment operator: Circle& operator= (const Ellipse& E)
     Makes the `Circle' a copy of E, if E is circular.  `radius' is set
     to E.`axis_v' / 2 and `*this' is returned.

     If E is not circular, this function issues an error message and
     returns `*this'.


File: 3DLDF.info,  Node: Querying Circles,  Next: Circle Intersections,  Prev: Circle Operators,  Up: Circle Reference

Querying
========

 - `const' function: bool is_circular (void)
     Returns `true' if the `Circle' is circular, otherwise `false'.

     Certain transformations, such as shearing and scaling, can cause
     `Circles' to become non-circular.

          Circle c(origin, 3, 90);
          cout << c.is_circular();
          -| 1
          
          Circle d = c;
          d.shift(2.5);
          d.scale(2, 3);
          cout << d.is_circular();
          -| 0

     [Figure 176 not displayed.]


 - Inline function: real get_radius (`void')
     Returns `radius'.

 - Inline function: real get_diameter (`void')
     Returns 2 * `radius'.


File: 3DLDF.info,  Node: Circle Intersections,  Prev: Querying Circles,  Up: Circle Reference

Intersections
=============

 - Virtual `const' function: bool_point_quadruple intersection_points
          (const Circle& C, [const bool VERBOSE = `false'])
     Returns the intersection points of two `Circles'.

     If the `Circles' are coplanar, they can intersect at at most two
     points.  There is an easy algebraic solution for this, so in this
     case, this function is faster than
     `Ellipse::intersection_points(Ellipse, bool)', which uses an
     iterative procedure to find the points.

     If the `Circles' are non-coplanar, the intersection points of each
     `Circle' with the plane of the other `Circle' are returned, so a
     maximum of four `Points' can be found.

          Circle t(origin, 5, 90);
          Circle c(origin, 3, 90);
          c.shift(3);
          c.rotate(0, 0, 45);
          bool_point_quadruple bpq = t.intersection_points(c);
          bpq.first.pt.dotlabel("$f$");
          bpq.second.pt.dotlabel("$s$");

     [Figure 177 not displayed.]



File: 3DLDF.info,  Node: Pattern Reference,  Next: Solid Reference,  Prev: Circle Reference,  Up: Top

Pattern Reference
*****************

   There is no currently no class "`Pattern'".  If it turns out to be
useful for this purpose, I will define a `Pattern' class, and perhaps
additional derived classes.

* Menu:

* Plane Tesselations::
* Roulettes and Involutes::

