cgal/Polyhedron/doc/Polyhedron/Polyhedron.txt

566 lines
24 KiB
Plaintext

namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_3D_Polyhedral_Surfaces
\anchor chapterPolyhedron
\author Lutz Kettner
\cgalAutoToc
\section sectionPolyIntro Introduction
Polyhedral surfaces in three dimensions are composed of vertices,
edges, facets and an incidence relationship on them. The organization
beneath is a halfedge data structure, which restricts the class of
representable surfaces to orientable 2-manifolds - with and without
boundary. If the surface is closed we call it a <I>polyhedron</I>, for
example, see the following model of a hammerhead:
\image html shark.png
\image latex shark.png
The polyhedral surface is realized as a container class that manages
vertices, halfedges, facets with their incidences, and that maintains
the combinatorial integrity of them. It is based on the highly
flexible design of the halfedge data structure, see the introduction
in Chapter \ref chapterHalfedgeDS "Halfedge Data Structures" and \cgalCite{k-ugpdd-99}. However, the
polyhedral surface can be used and understood without knowing the
underlying design. Some of the examples in this chapter introduce also
gradually into first applications of this flexibility.
\section PolyhedronDefinition Definition
A polyhedral surface `Polyhedron_3<PolyhedronTraits_3>` in
three dimensions consists of vertices `V`, edges `E`, facets `F` and
an incidence relation on them. Each edge is represented by two
halfedges with opposite orientations. The incidences stored with a
halfedge are illustrated in the following figure:
\image html halfedge_small.png
\image latex halfedge_small.png
Vertices represent points in space. Edges are straight line segments
between two endpoints. Facets are planar polygons without
holes. Facets are defined by the circular sequence of halfedges along
their boundary. The polyhedral surface itself can have holes (with at
least two facets surrounding it since a single facet cannot have a
hole). The halfedges along the boundary of a hole are called <I>border halfedges</I> and have no incident facet. An edge is a <I>border edge</I> if one of its halfedges is a border halfedge. A
surface is <I>closed</I> if it contains no border halfedges. A closed
surface is a boundary representation for polyhedra in three
dimensions. The convention is that the halfedges are oriented
counterclockwise around facets as seen from the outside of the
polyhedron. An implication is that the halfedges are oriented
clockwise around the vertices. The notion of the solid side of a facet
as defined by the halfedge orientation extends to polyhedral surfaces
with border edges although they do not define a closed object. If
normal vectors are considered for the facets, normals point outwards
(following the right-hand rule).
The strict definition can be found in \cgalCite{k-ugpdd-99}. One
implication of this definition is that the polyhedral surface is
always an orientable and oriented 2-manifold with border edges, i.e.,
the neighborhood of each point on the polyhedral surface is either
homeomorphic to a disc or to a half disc, except for vertices where
many holes and surfaces with boundary can join. Another implication is
that the smallest representable surface avoiding self intersections is
a triangle (for polyhedral surfaces with border edges) or a
tetrahedron (for polyhedra). Boundary representations of orientable
2-manifolds are closed under Euler operations. They are extended with
operations that create or close holes in the surface.
Other intersections besides the incidence relation are not allowed.
However, this is not automatically verified in the operations, since
self intersections are not easy to check
efficiently. `Polyhedron_3<PolyhedronTraits_3>` does only
maintain the combinatorial integrity of the polyhedral surface (using
Euler operations) and does not consider the coordinates of the points
or any other geometric information.
`Polyhedron_3<PolyhedronTraits_3>` can represent polyhedral
surfaces as well as polyhedra. The interface is designed in such a way
that it is easy to ignore border edges and work only with polyhedra.
\section PolyhedronExample Example Programs
\anchor sectionPolyExamples
The polyhedral surface is based on the highly flexible design of the
halfedge data structure. Examples for this flexibility can be found in
Section \ref PolyhedronExtending and in Section \ref HalfedgeDSExample
"Examples" of the chapter on the halfedge data structure.
This design is not a prerequisite to understand the following examples.
See also the Section \ref sectionPolyAdvanced below for some advanced
examples.
\subsection PolyhedronFirstExampleUsingDefaults First Example Using Defaults
The first example instantiates a polyhedron using a kernel as traits
class. It creates a tetrahedron and stores the reference to one of its
halfedges in a `Halfedge_handle`. Handles, also know as
<I>trivial iterators</I>, are used to keep references to halfedges,
vertices, or facets for future use. There is also a `Halfedge_iterator`
type for enumerating halfedges. Such an iterator type can be used
wherever a handle is required. Respective `Halfedge_const_handle` and
`Halfedge_const_iterator` for a constant polyhedron and similar
handles and iterators with `Vertex_` and `Facet_` prefix
are provided too.
The example continues with a test if the halfedge
actually refers to a tetrahedron. This test checks the connected
component referred to by the halfedge `h` and not the polyhedral
surface as a whole. This examples works only on the combinatorial
level of a polyhedral surface. The next example adds the geometry.
\cgalExample{Polyhedron/polyhedron_prog_simple.cpp}
\subsection PolyhedronExamplewithGeometryinVertices Example with Geometry in Vertices
We add geometry to the our construction of a tetrahedron. Four points
are passed as arguments to the construction. This example demonstrates
in addition the use of the vertex iterator and the access to the point
in the vertices. Note the natural access notation
`v->`\link CGAL::Polyhedron_3::Vertex::point() `point()`\endlink.
Similarly, all information stored in a vertex, halfedge, and facet can
be accessed with a member function given a handle or iterator. For
example, given a halfedge handle `h` we can write
`h->`\link CGAL::Polyhedron_3::Halfedge::next() `next()`\endlink
to get a halfedge handle to the next halfedge,
`h->`\link CGAL::Polyhedron_3::Halfedge::opposite() `opposite()`\endlink for
the opposite halfedge,
`h->`\link CGAL::Polyhedron_3::Halfedge::vertex() `vertex()`\endlink for the incident vertex at
the tip of `h`, and so on. The output of the program will be
\verbatim
1 0 0
0 1 0
0 0 1
0 0 0
\endverbatim
\cgalExample{Polyhedron/polyhedron_prog_tetra.cpp}
The polyhedron offers a point iterator for convenience. The above
`for` loop simplifies to a single statement by using
`std::copy` and the ostream iterator adaptor.
\code{.cpp}
std::copy( P.points_begin(), P.points_end(),
std::ostream_iterator<Point_3>(std::cout,"\n"));
\endcode
\subsection PolyhedronExampleforAffineTransformation Example for Affine Transformation
An affine transformation `A` can act as a functor transforming points
and a point iterator is conveniently defined for polyhedral surfaces.
So, assuming we want only the point coordinates of a polyhedron `P`
transformed, `std::transform` does the job in a single line.
\code{.cpp}
std::transform( P.points_begin(), P.points_end(), P.points_begin(), A);
\endcode
\subsection PolyhedronExampleComputingPlaneEquations Example Computing Plane Equations
The polyhedral surface has already provisions to store a plane
equation for each facet. However, it does not provide a function to
compute plane equations.
This example computes the plane equations of a polyhedral surface.
The actual computation is implemented in the
`Plane_equation` functor. Depending on the arithmetic
(exact/inexact) and the shape of the facets (convex/non-convex)
different methods are useful. We assume here strictly convex facets
and exact arithmetic. In our example a homogeneous representation with
`int` coordinates is sufficient. The four plane equations of the
tetrahedron are the output of the program.
\cgalExample{Polyhedron/polyhedron_prog_planes.cpp}
\subsection sectionPolyVector Example with a Vector Instead of a List Representation
The polyhedron class template has actually four parameters, where
three of them have default values. Using the default values explicitly
in our examples above for three parameter - ignoring the fourth
parameter, which would be a standard allocator for container class -
the definition of a polyhedron looks like:
\code{.cpp}
typedef CGAL::Polyhedron_3< Traits,
CGAL::Polyhedron_items_3,
CGAL::HalfedgeDS_default> Polyhedron;
\endcode
The `Polyhedron_items_3` class contains the types used for
vertices, edges, and facets. The `HalfedgeDS_default` class
defines the halfedge data structure used, which is a list-based
representation in this case. An alternative is a vector-based
representation. Using a vector provides random
access for the elements in the polyhedral surface and is more space
efficient, but elements cannot be deleted arbitrarily. Using a list
allows arbitrary deletions, but provides only bidirectional iterators
and is less space efficient. The following example creates again a
tetrahedron with given points, but in a vector-based representation.
The vector-based representation resizes automatically if the reserved
capacity is not sufficient for the new items created. Upon resizing
all handles, iterators, and circulators become invalid. Their correct
update in the halfedge data structure is costly, thus it is advisable
to reserve enough space in advance as indicated with the alternative
constructor in the comment.
\cgalAdvancedBegin
Note that the polyhedron and not the underlying halfedge data
structure triggers the resize operation, since the resize operation
requires some preconditions, such as valid incidences, to be fulfilled
that only the polyhedron can guarantee.
\cgalAdvancedEnd
\cgalExample{Polyhedron/polyhedron_prog_vector.cpp}
\subsection PolyhedronExamplewithCirculatorWritingObject Example with Circulator Writing Object File Format (OFF)
We create a tetrahedron and write it to `std::cout` using the
%Object File Format (OFF) \cgalCite{cgal:p-gmgv16-96}. This example makes use
of \stl algorithms (`std::copy`, `std::distance`), \stl `std::ostream_iterator`, and \cgal circulators. The polyhedral
surface provides convenient circulators for the counterclockwise
circular sequence of halfedges around a facet and the clockwise
circular sequence of halfedges around a vertex.
However, the computation of the vertex index in the inner loop of the
facet output is not advisable with the `std::distance` function,
since it takes linear time for non random-access iterators, which
leads to quadratic runtime. For better runtime the vertex index needs
to be stored separately and computed once before writing the
facets. It can be stored, for example, in the vertex itself or in a
hash-structure. See also Section \ref PolyhedronFile.
\cgalExample{Polyhedron/polyhedron_prog_off.cpp}
\subsection PolyhedronExampleUsingEulerOperatorstoBuild Example Using Euler Operators to Build a Cube
Euler operators are the natural way of modifying polyhedral surfaces.
We provide a set of operations for polyhedra:
\link Polyhedron_3::split_facet() split_facet()\endlink,
\link Polyhedron_3::join_facet() `join_facet()`\endlink,
\link Polyhedron_3::split_vertex() `split_vertex()`\endlink,
\link Polyhedron_3::join_vertex() `join_vertex()`\endlink,
\link Polyhedron_3::split_loop() `split_loop()`\endlink, and
\link Polyhedron_3::join_loop() `join_loop()`\endlink.
We add further convenient
operators, such as
\link Polyhedron_3::split_edge() `split_edge()`\endlink.
However, they could be implemented
using the six operators above. Furthermore, we provide more operators
to work with polyhedral surfaces with border edges, for example, creating
and deleting holes. We refer to the references manual for the
definition and illustrative figures of the Euler operators.
The following example implements a function that appends a unit cube
to a polyhedral surface. To keep track of the different steps during
the creation of the cube a sequence of sketches might help with labels
for the different handles that occur in the program code. The following
Figure shows six selected steps from the creation sequence. These steps
are also marked in the program code.
\image html make_cube.png
\image latex make_cube.png
\cgalExample{Polyhedron/polyhedron_prog_cube.cpp}
\subsection PolyhedronDraw Draw a Polyhedron
\anchor ssecDrawPolyhedron
A polyhedron can be visualized by calling the \link PkgDrawPolyhedron CGAL::draw<POLY>() \endlink function as shown in the following example. This function opens a new window showing the given polyhedron. A call to this function is blocking, that is the program continues as soon as the user closes the window.
\cgalExample{Polyhedron/draw_polyhedron.cpp}
This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time.
\cgalFigureBegin{fig_draw_polyhedron,draw_polyhedron.png}
Result of the run of the draw_polyhedron program. A window shows the polyhedron and allows to navigate through the 3D scene.
\cgalFigureEnd
\section PolyhedronFile File I/O
\anchor sectionPolyIO
The file I/O currently considers only the topology of the
surface and its point coordinates. It ignores a possible plane
equation or any user-added attributes, such as color.
The default file format supported in \cgal for output as well as for
input is the \ref IOStreamOFF, with file extension <TT>.off</TT>.
The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output.
Otherwise, the output would be free of comments. The default for writing is without comments.
Since this file format is the default format, iostream operators are provided for it.
\code{.cpp}
#include <CGAL/IO/Polyhedron_iostream.h>
template <class PolyhedronTraits_3>
ostream& operator<<( ostream& out,
const CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
template <class PolyhedronTraits_3>
istream& operator>>( istream& in,
CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
\endcode
Additional formats supported for writing are OpenInventor (<TT>.iv</TT>)
\cgalCite{cgal:w-impoo-94}, VRML 1.0 and 2.0 (<TT>.wrl</TT>)
\cgalCite{cgal:bpp-vrml-95}, \cgalCite{cgal:vrmls-97}, \cgalCite{cgal:hw-vrml2h-96},
and \ref IOStreamOBJ (<TT>.obj</TT>). Another convenient output
function writes a polyhedral surface to a Geomview process spawned
from the \cgal program. These output functions are provided as
stream operators, now acting on the stream type of the respective
format.
\code{.cpp}
#include <CGAL/IO/Polyhedron_inventor_ostream.h>
#include <CGAL/IO/Polyhedron_VRML_1_ostream.h>
#include <CGAL/IO/Polyhedron_VRML_2_ostream.h>
#include <CGAL/IO/Polyhedron_geomview_ostream.h>
template <class PolyhedronTraits_3>
Inventor_ostream& operator<<( Inventor_ostream& out,
const CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
template <class PolyhedronTraits_3>
VRML_1_ostream& operator<<( VRML_1_ostream& out,
const CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
template <class PolyhedronTraits_3>
VRML_2_ostream& operator<<( VRML_2_ostream& out,
const CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
template <class PolyhedronTraits_3>
Geomview_stream& operator<<( Geomview_stream& out,
const CGAL::Polyhedron_3<PolyhedronTraits_3>& P);
\endcode
All these file formats have in common that they represent a surface as
a set of facets. Each facet is a list of indices pointing into a set
of vertices. Vertices are represented as coordinate triples. The
file I/O for polyhedral surfaces `Polyhedron_3` imposes certain
restrictions on these formats. They must represent a permissible
polyhedral surface, e.g., a 2-manifold and no isolated vertices, see
Section \ref sectionPolyIntro.
For more information on generic polygon meshes I/O, see the section \ref IOstreamPolygonMeshIO.
\section PolyhedronExtending Extending Vertices, Halfedges, and Facets
\anchor sectionPolyExtend
In Section \ref sectionPolyVector we have seen how to change the
default list representation
\code{.cpp}
typedef CGAL::Polyhedron_3< Traits,
CGAL::Polyhedron_items_3,
CGAL::HalfedgeDS_default> Polyhedron;
\endcode
to a vector based representation of the underlying halfedge data
structure. Now we want to look a bit closer at the second template argument,
`Polyhedron_items_3`, that specifies what kind of vertex,
halfedge, and facet is used. The implementation of
`Polyhedron_items_3` looks a bit involved with nested
wrapper class templates. But ignoring this technicality, what remains
are three local typedefs that define the `Vertex`, the
`Halfedge`, and the `Face` for the polyhedral surface.
Note that we use here `Face` instead of facet. Face is the term
used for the halfedge data structure. Only the top layer of the
polyhedral surface gives alias names renaming face to facet.
\code{.cpp}
class Polyhedron_items_3 {
public:
template < class Refs, class Traits>
struct Vertex_wrapper {
typedef typename Traits::Point_3 Point;
typedef CGAL::HalfedgeDS_vertex_base<Refs, CGAL::Tag_true, Point> Vertex;
};
template < class Refs, class Traits>
struct Halfedge_wrapper {
typedef CGAL::HalfedgeDS_halfedge_base<Refs> Halfedge;
};
template < class Refs, class Traits>
struct Face_wrapper {
typedef typename Traits::Plane_3 Plane;
typedef CGAL::HalfedgeDS_face_base<Refs, CGAL::Tag_true, Plane> Face;
};
};
\endcode
If we look up in the reference manual the definitions of the three
classes used in the typedefs, we will see the confirmation that the
default polyhedron uses all supported incidences, a point in the
vertex class, and a plane equation in the face class. Note how the
wrapper class provides two template parameters, `Refs`, which
we discuss a bit later, and `Traits`, which is the geometric
traits class used by the polyhedral surface and which provides us here
with the types for the point and the plane equation.
Using this example code we can write our own items class. Instead, we
illustrate an easier way if we only want to exchange one class. We use
a simpler face without the plane equation but with a color attribute
added. To simplify the creation of a vertex, halfedge, or face class,
it is always recommended to derive from one of the given base classes.
Even if the base class would contain no data it would provide
convenient type definitions. So, we derive from the base class, repeat
the mandatory constructors if necessary - which is not the case for
faces but would be for vertices - and add the color attribute.
\code{.cpp}
template <class Refs>
struct My_face : public CGAL::HalfedgeDS_face_base<Refs> {
CGAL::Color color;
};
\endcode
The new items class is derived from the old items class and the
wrapper containing the face typedef gets overridden. Note that the
name of the wrapper and its template parameters are fixed. They cannot
be changed even if, as in this example, a template parameter is not
used.
\code{.cpp}
struct My_items : public CGAL::Polyhedron_items_3 {
template <class Refs, class Traits>
struct Face_wrapper {
typedef My_face<Refs> Face;
};
};
\endcode
When we use our new items class with the polyhedral surface, our new
face class is used in the halfedge data structure and the color
attribute is available in the type `Polyhedron_3::Facet`. However,
`Polyhedron_3::Facet` is not the same type as our local face
typedef for `My_face`, but it is derived therefrom. Thus,
everything that we put in the local face type except constructors is
then available in the `Polyhedron_::Facet` type. For more
details, see the Chapter \ref chapterHalfedgeDS "Halfedge Data Structures"
on the halfedge data structure design.
Pulling all pieces together, the full example program illustrates how easy
the color attribute can be accessed once it is defined.
\cgalExample{Polyhedron/polyhedron_prog_color.cpp}
We come back to the first template parameter, `Refs`, of the
wrapper classes. This parameter provides us with local types that
allow us to make further references between vertices, halfedges, and
facets, which have not already been prepared for in the current
design. These local types are `Polyhedron_3::Vertex_handle`,
`Polyhedron_3::Halfedge_handle`, `Polyhedron_3::Facet_handle`, and there respective
`.._const_handle`. We add now a new vertex reference to a
face class as follows. Encapsulation and access functions could be
added for a more thorough design, but we omit that here for the sake
of brevity. The integration of the face class with the items class
works as illustrated above.
\code{.cpp}
template <class Refs>
struct My_face : public CGAL::HalfedgeDS_face_base<Refs> {
typedef typename Refs::Vertex_handle Vertex_handle;
Vertex_handle vertex_ref;
};
\endcode
More advanced examples can be found in the Section \ref sectionHdsExamples
illustrating further the design of the halfedge data structure.
\section PolyhedronAdvanced Advanced Example Programs
\anchor sectionPolyAdvanced
\subsection PolyhedronExampleCreatingaSubdivisionSurface Example Creating a Subdivision Surface
This program reads a polyhedral surface from the standard input and
writes a refined polyhedral surface to the standard output. Input and
output are in the %Object File Format, OFF, with the common file
extension <TT>.off</TT>.
The refinement is a single step of the \f$ \sqrt{3}\f$-scheme for creating
a subdivision surface \cgalCite{cgal:k-s-00}. Each step subdivides a facet
into triangles around a new center vertex, smoothes the position of the
old vertices, and flips the old edges. The program is organized along
this outline. In each of these parts, the program efficiently uses the
knowledge that the newly created vertices, edges, and facets have been
added to the end of the sequences. The program needs additional
processing memory only for the smoothing step of the old vertices.
\image html subdiv_small.png
\image latex subdiv_small.png
The above figure shows three example objects, each
subdivided four times. The initial object for the left sequence is
the closed surface of three unit cubes glued together to a corner.
The example program shown here can handle only closed surfaces,
but the extended example
<TT>examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cpp</TT>
handles surfaces with boundary. So, the middle sequence starts with
the same surface where one of the facets has been removed. The boundary
subdivides to a nice circle. The third sequence creates a sharp
edge using a trick in the object presentation. The sharp edge is
actually a hole whose vertex coordinates pinch the hole shut to form an
edge. The example directory <TT>examples/Polyhedron/</TT> contains the
OFF files used here.
\cgalExample{Polyhedron/polyhedron_prog_subdiv.cpp}
\subsection PolyhedronExampleUsingtheIncrementalBuilder Example Using the Incremental Builder and Modifier Mechanism
A utility class `Polyhedron_incremental_builder_3` helps in
creating polyhedral surfaces from a list of points followed by a list
of facets that are represented as indices into the point list. This is
particularly useful for implementing file reader for common file
formats. It is used here to create a triangle.
A modifier mechanism allows to access the internal representation of
the polyhedral surface, i.e., the halfedge data structure, in a
controlled manner. A modifier is basically a callback mechanism using
a function object. When called, the function object receives the
internal halfedge data structure as a parameter and can modify it. On
return, the polyhedron can check the halfedge data structure for
validity. Such a modifier object must always return with a halfedge
data structure that is a valid polyhedral surface. The validity check is
implemented as an expensive postcondition at the end of the `Polyhedron_3::delegate()`
member function, i.e., it is not called by default, only when expensive
checks are activated.
In this example, `Build_triangle` is such a function object
derived from `Modifier_base<HalfedgeDS>`. The `Polyhedron_3::delegate()`
member function of the polyhedron accepts this function object and calls
its `Modifier_base::operator()()` with a reference to its internally used halfedge
data structure. Thus, this member function in `Build_triangle` can
create the triangle in the halfedge data structure.
\cgalExample{Polyhedron/polyhedron_prog_incr_builder.cpp}
*/
} /* namespace CGAL */