mirror of https://github.com/CGAL/cgal
2097 lines
87 KiB
Plaintext
2097 lines
87 KiB
Plaintext
%------------------------------------------------------------------------------
|
|
%KILLSTART DISS REP
|
|
%LDEL TRACE.*?\)\;
|
|
%LDEL LEDA_MEMORY.*?\)\;
|
|
\documentclass[a4paper]{article}
|
|
\usepackage{MyLweb,version}
|
|
\input{defs}
|
|
|
|
\excludeversion{ignoreindiss}
|
|
\excludeversion{ignore}
|
|
\includeversion{onlyindiss}
|
|
|
|
\begin{document}
|
|
\title{Plane Map Overlay}
|
|
\author{Michael Seel}
|
|
\maketitle
|
|
\tableofcontents
|
|
%KILLEND REP
|
|
|
|
@ \section{The manual page}
|
|
|
|
\input manpages/PM_overlayer.man
|
|
|
|
@ \newpage
|
|
\section{Implementation}
|
|
|
|
%KILLEND DISS
|
|
|
|
In this section we present a software module for the overlay of
|
|
segments and plane maps. We first give a formal introduction to the
|
|
notions and difficulties concerning overlay and support. We then
|
|
present the overlay calculation of a set of segments. We show how we
|
|
use a generic sweep module to produce the 1-skeleton of the output
|
|
plane map. In a different section we show how to add face objects to
|
|
the 1-skeleton to complete the output structure. The second operation
|
|
concerns the overlay of two plane maps. We use the same generic sweep
|
|
module with slightly more elaborate adaptation to obtain again the
|
|
1-skeleton of the overlay. The face production phase will be the same
|
|
as before. In case of the second overlay operation, our sweep adds a
|
|
transfer of information assigned to the objects of the two input plane
|
|
maps to corresponding objects in the output structure. This allows us
|
|
to use the module for binary set operations on plane map
|
|
structures. Such set operations use a selection phase on the
|
|
transferred information items. The selection phase is descibed below
|
|
in an additional section. The last part concerns structural
|
|
simplification of the output plane map. We will see that there can be
|
|
substructures in the output plane map that can be simplified without
|
|
losing any information when the plane map is interpreted as a point
|
|
set.
|
|
|
|
\subsection{Notions and definitions}
|
|
|
|
\begin{figure}[thbp]
|
|
\begin{center}
|
|
\input{segoverlay.pstex_t}\quad\input{pmoverlay.pstex_t}
|
|
\end{center}
|
|
\caption{\small The overlay of a set of segments and of two plane maps.
|
|
The left figure shows a set of dashed segments. $v_1$ is an isolated
|
|
vertex, $v_2$ is an endpoint in the interior of another segment, $v_3$
|
|
is a vertex supported by two endpoints, $v_4$ is the intersection of
|
|
the relative interiors of two segments. The edges are drawn with solid
|
|
line segments. One bounded face is greyed. The right figure shows the
|
|
1-skeleta of two plane maps. Degenerate situations are identical
|
|
vertices, vertices in the interior of edges, and overlapping edges.}
|
|
\label{fig:overlay}
|
|
\end{figure}
|
|
|
|
\newcommand{\PM}{\ensuremath{P = (V,E,F)}}
|
|
\newcommand{\PMi}{\ensuremath{P_i = (V_i,E_i,F_i)}}
|
|
\renewcommand{\Pi}{\ensuremath{P_i}}
|
|
|
|
If we consider our overlay process as a transformation of input
|
|
objects to output objects then we can define the support relation as
|
|
follows.
|
|
\begin{deff}[support]
|
|
Consider an algorithm $T$ that transforms a set of input objects $A$
|
|
to a set of output objects $B$ where each $a \in A$ and $b \in B$
|
|
represents a subset of $R^2$. We say that \emph{$a$ supports $b$} if
|
|
$b$ is a subset of $a$ with respect to the represented point sets.
|
|
\end{deff}
|
|
We will anchor this notion in the following.
|
|
|
|
\textbf{Overlay of a set of segments}\quad For a segment $s = (p,q)$,
|
|
$p$, $q$ are called the endpoints of $s$ where |p = source(s)|, |q =
|
|
target(s)|. Let us consider $s$ as a disjoint union of its endpoints
|
|
and its relative interior $\relint s$. A set of segments $S$
|
|
partitions the plane into cells of different dimensions. For each
|
|
point $r \in \R^2$ it can happen that
|
|
\begin{enumerate}\parsep0ex plus 0.0ex minus 1.0ex%
|
|
\itemsep-0.5ex\topsep-0.5ex\renewcommand{\labelenumi}{(\roman{enumi})}%
|
|
\item $r$ is equal to an endpoint of some segment $s$, or
|
|
\item $r$ is part of the relative interior of some segment $s$, or
|
|
\item $r$ is not part of any segment at all.
|
|
\end{enumerate}
|
|
Note that (i) and (ii) do not exclude each other. Now consider the
|
|
geometric structure built by all segments. The \emph{overlay} of all
|
|
segments is the subdivision of all points in $\R^2$ with respect to
|
|
the three criteria (i) to (iii) above including their topological
|
|
neighborhood and the knowledge of how parts of the segments in $S$
|
|
support the one-dimensional cells of the subdivision.
|
|
|
|
We store the overlay of $S$ in a plane map \PM{} in the standard
|
|
way. For each point $r$ in (i) there is a vertex $v$ in $V$ where the
|
|
endpoint of the segment supports the vertex. If $r$ is additionally in
|
|
the relative interior of some other segment according to (ii) then
|
|
this segment also supports $v$. For each point in (ii) that is the
|
|
unique intersection point of the relative interior of two segments
|
|
(that do not overlap) there is a vertex in $V$ and the relative
|
|
interior of each of the two segments supports that vertex. Between any
|
|
two vertices in $V$ there is a uedge $e$ in $E$ if there is a segment
|
|
$s$ that supports the straight-line embedding of $e$ according to (ii)
|
|
and there is no further vertex in the relative interior of $e$. The
|
|
latter can happen for several segments that overlap. Any point of
|
|
(iii) belongs to one of the maximal connected
|
|
sets\footnote{path-connected in the strong topological sense.} of
|
|
$\R^2 - S$ that form the faces of $P$ and is thus not supported by any
|
|
segment at all.
|
|
|
|
\textbf{Overlay of two plane maps}\quad Let $P_i = (V_i,E_i,F_i),
|
|
i=0,1$ be two plane map structures. The overlay of two plane maps
|
|
$P_0$, $P_1$ is the plane map $P$ representing the subdivision of the
|
|
plane obtained by interpreting the skeleton objects of \Pi{} according
|
|
to their embedding as trivial and non-trivial segments, constructing
|
|
the overlay of these segments and adding the faces. To make this
|
|
structure really helpful we explore the support relation between
|
|
objects of \Pi{} and $P$.
|
|
|
|
In general, each point $p$ in the plane is supported by that object of
|
|
a plane map whose corresponding point set contains $p$. The support
|
|
relation between \Pi{} and $P$ comes in two steps. Each 1-skeleton
|
|
object of \Pi{} relates to the endpoint or relative interior of a
|
|
segment that supports a skeleton object in $P$. Conversely, each
|
|
object of $P$ (vertex, edge, or face) is supported by a unique
|
|
supporting object in each of the two structures \Pi{} $(i=0,1)$. We
|
|
show that this relation is well defined.
|
|
|
|
\begin{lemma}\label{supporting lemma}
|
|
Any object of $P$ has exactly one supporting object in each of the
|
|
$P_i$.
|
|
\end{lemma}
|
|
\begin{proof}
|
|
Obviously, each point of the plane is supported by an object of
|
|
$P_i$. Therefore, we only have to argue why no two objects of $P_i$
|
|
can support one object of $P$. For vertices this is trivial. For a
|
|
uedge $e$ in $P$ there can be only one uedge or one face of $P_i$ that
|
|
supports $e$: assume that the embedding of $e$ covers points from more
|
|
than one object of $P_i$. Then, $e$ either contains a vertex or
|
|
crosses an edge in its interior. But then, the corresponding
|
|
subdivision would have prevented the creation of $e$ in $P$ in the
|
|
first place.
|
|
|
|
For a face $f$ of $P$ there can be only one face $f'$ of $P_i$ that
|
|
supports $f$: assume otherwise, that $f$ contains points from
|
|
different objects of $P_i$. As $f$ is an open connected point set it
|
|
has to cover points of at least one boundary object from the
|
|
1-skeleton of $P_i$. But this object is part of the 1-skeleton of $P$
|
|
and can therefore never be part of $f$.
|
|
\end{proof}
|
|
|
|
In our implementation we determine the support relation in two
|
|
phases. Any vertex $v$ in $V$ can be supported by a vertex $v_i$, a
|
|
uedge $e_i$, or a face $f_i$ of \Pi. If $v$ is supported by $v_i$ or
|
|
$e_i$ we obtain this information in a plane sweep process. Assume that
|
|
$v$ is supported by a face $f_i$ (then $v$ is supported by a vertex
|
|
$v_{1-i}$). During the sweep process, the determination of a support
|
|
of $f_i$ is hard, as the face objects are not in reach. We determine
|
|
$f_i$ in a postprocessing phase by a simple iteration over all
|
|
vertices. Any edge $e$ in $E$ can be supported by a uedge $e_i$ or a
|
|
face $f_i$ of \Pi. A possible support by $e_i$ is handled during the
|
|
sweep process. In case $e$ is part of a face $f_i$ (again $e$ is then
|
|
supported by an edge $e_{1-i}$) we also determine $f_i$ in the
|
|
postprocessing phase.
|
|
|
|
The support for a face $f$ in $F$ can be determined as follows.
|
|
Assume that each directed edge $e$ in $E$ knows the faces $f_i$
|
|
supporting points in a small neighborhood on its left side ($i=0,1$).
|
|
Then, $f$ can determine its two supporting faces $f_i$ via any edge in
|
|
its boundary cycle. We will enrich the edges of $E$ by such support
|
|
information and use it afterwards to transfer attributes from $f_i$ to
|
|
$f$.
|
|
|
|
\subsection{The class design}
|
|
|
|
We start with the design of the class object. Our generic overlay
|
|
class can be adapted via two interface concepts. We interface the
|
|
underlying plane map via a plane map decorator |PM_decorator_|; we
|
|
interface the underlying geometry via a geometry kernel
|
|
|Geometry_|. We inherit from |PM_decorator_| to obtain its interface
|
|
methods.
|
|
<<PM overlayer>>=
|
|
/*{\Moptions print_title=yes }*/
|
|
/*{\Msubst
|
|
PM_decorator_#PMD
|
|
Geometry_#GEO
|
|
}*/
|
|
/*{\Manpage {PM_overlayer}{PMD,GEO}{Plane Map Overlay}{O}}*/
|
|
template <typename PM_decorator_, typename Geometry_>
|
|
class PM_overlayer : public PM_decorator_ {
|
|
typedef PM_decorator_ Base;
|
|
typedef PM_overlayer<PM_decorator_,Geometry_> Self;
|
|
const Geometry_& K; // geometry reference
|
|
|
|
/*{\Mdefinition An instance |\Mvar| of data type |\Mname| is a
|
|
decorator object offering plane map overlay calculation. Overlay is
|
|
either calculated from two plane maps or from a set of segments. The
|
|
result is stored in a plane map |P| that carries the geometry and the
|
|
topology of the overlay.
|
|
|
|
The two template parameters allow to adapt the overlay calculation
|
|
to different scenarios. The template parameter |PM_decorator_| has to
|
|
be a model conforming to our plane map decorator concept
|
|
|PMDecorator|. The concept describes the interface how the
|
|
topological information stored in |P| can be extracted. The geometry
|
|
|Geometry_| has to be a model conforming to the concept
|
|
|OverlayerGeometry_2|.
|
|
|
|
The overlay of a set of segments $S$ is stored in a plane map $P =
|
|
(V,E,F)$. Vertices are either the endpoints of segments (trivial
|
|
segments are allowed) or the result of a non-degenerate internal
|
|
intersection of two segments. Between two vertices there is an edge if
|
|
there is a segment that supports the straight line embedding of $e$ and
|
|
if there is no vertex in the relative interior of the embedding of $e$.
|
|
|
|
The faces refer to the maximal connected open point sets of the
|
|
planar subdivision implied by the embedding of the vertices and edges.
|
|
Faces are bounded by possibly several face cycles\footnote{For the
|
|
definition of plane maps and their concepts see the manual page of
|
|
|PMConstDecorator|.} including isolated vertices. The overlay process
|
|
in the method |create| creates the objects, the topology of the result
|
|
and allows to link the plane map objects to input segments by means of
|
|
a data accessor. The method starts from zero- and one-dimensional
|
|
geometric objects in $S$ and produces a plane map |P| where each point
|
|
of the plane can be assigned to an object (vertex, edge, or face) of
|
|
|P|.
|
|
|
|
The overlay of two plane maps $P_i = (V_i, E_i, F_i)$ has the
|
|
additional aspect that we already start from two planar subdivisions.
|
|
We use the index $i=0,1$ defining the reference to $P_i$, unindexed
|
|
variables refer to the resulting plane map $P$. The $1$-skeleta of
|
|
the two maps subdivide the edges and faces of the complementary
|
|
structure into smaller units. This means vertices and edges of $P_i$
|
|
can split edges of $P_{1-i}$ and face cycles of $P_i$ subdivide faces
|
|
of $P_{1-i}$. The 1-skeleton $P'$ of $P$ is defined by the overlay of
|
|
the embedding of the 1-skeleta of $P_0$ and $P_1$ (Take a trivial
|
|
segment for each vertex and a segment for each edge and use the
|
|
overlay definition of a set of segments above). The faces of $P$ refer
|
|
to the maximal connected open point sets of the planar subdivision
|
|
implied by the embedding of $P'$. Each object from the output tuple
|
|
$(V,E,F)$ has a \emph{supporting} object $u_i$ in each of the two
|
|
input structures. Imagine the two maps to be transparencies, which we
|
|
stack. Then each point of the plane is covered by an object from each
|
|
of the input structures. This support relation from the input
|
|
structures to the output structure defines an information flow. Each
|
|
supporting object $u_i$ of $u$ $(i=0,1)$ carries an attribute
|
|
$|mark|(u_i)$. After the subdivision operation this attribute
|
|
is associated to the output object $u$ by $|mark|(u,i)$.}*/
|
|
|
|
/*{\Mgeneralization PM_decorator_}*/
|
|
|
|
public:
|
|
/*{\Mtypes 8}*/
|
|
typedef PM_decorator_ Decorator;
|
|
/*{\Mtypemember the plane map decorator |PM_decorator_|.}*/
|
|
typedef typename Decorator::Plane_map Plane_map;
|
|
/*{\Mtypemember the plane map type decorated by |PM_decorator_|.}*/
|
|
typedef Geometry_ Geometry;
|
|
/*{\Mtypemember the geometry kernel |Geometry_|.}*/
|
|
typedef typename Geometry::Point_2 Point;
|
|
/*{\Mtypemember the point type of the geometric kernel,
|
|
\precond |Point| equals |Plane_map::Point|.}*/
|
|
typedef typename Geometry::Segment_2 Segment;
|
|
/*{\Mtypemember the segment type of the geometric kernel.}*/
|
|
typedef typename Decorator::Mark Mark;
|
|
/*{\Mtypemember the attribute type of plane map objects.}*/
|
|
|
|
<<handles, iterators, and circulators from Decorator>>
|
|
<<info type to link edges and segments>>
|
|
|
|
/*{\Mcreation 6}*/
|
|
PM_overlayer(Plane_map& P, const Geometry& g = Geometry()) :
|
|
/*{\Mcreate |\Mvar| is a decorator object manipulating |P|.}*/
|
|
Base(P), K(g) {}
|
|
|
|
<<subdivision>>
|
|
<<selection>>
|
|
<<simplification>>
|
|
<<helping operations>>
|
|
|
|
}; // PM_overlayer<PM_decorator_,Geometry_>
|
|
|
|
|
|
@ \begin{ignoreindiss}
|
|
<<handles, iterators, and circulators from Decorator>>=
|
|
#define CGAL_USING(t) typedef typename Decorator::t t
|
|
typedef typename Decorator::Base Const_decorator;
|
|
CGAL_USING(Halfedge_handle);
|
|
CGAL_USING(Vertex_handle);
|
|
CGAL_USING(Face_handle);
|
|
CGAL_USING(Vertex_iterator);
|
|
CGAL_USING(Halfedge_iterator);
|
|
CGAL_USING(Face_iterator);
|
|
CGAL_USING(Halfedge_const_handle);
|
|
CGAL_USING(Vertex_const_handle);
|
|
CGAL_USING(Face_const_handle);
|
|
CGAL_USING(Halfedge_const_iterator);
|
|
CGAL_USING(Vertex_const_iterator);
|
|
CGAL_USING(Face_const_iterator);
|
|
CGAL_USING(Halfedge_around_vertex_circulator);
|
|
CGAL_USING(Halfedge_around_face_circulator);
|
|
CGAL_USING(Hole_iterator);
|
|
CGAL_USING(Isolated_vertex_iterator);
|
|
#undef CGAL_USING
|
|
|
|
// C++ is really friendly:
|
|
#define USECMARK(t) const Mark& mark(t h) const { return Base::mark(h); }
|
|
#define USEMARK(t) Mark& mark(t h) const { return Base::mark(h); }
|
|
USEMARK(Vertex_handle)
|
|
USEMARK(Halfedge_handle)
|
|
USEMARK(Face_handle)
|
|
USECMARK(Vertex_const_handle)
|
|
USECMARK(Halfedge_const_handle)
|
|
USECMARK(Face_const_handle)
|
|
#undef USEMARK
|
|
#undef USECMARK
|
|
|
|
/*{\Moperations 1.1 1}*/
|
|
|
|
@ \end{ignoreindiss}
|
|
|
|
@ \subsection{Overlay calculation of a list of segments}
|
|
\label{segment overlay calculation}
|
|
|
|
We want to calculate the plane map $P$ representing the overlay of a
|
|
set $S$ of segments, some of which may be trivial. This task is
|
|
basically split in \textbf{two phases}:
|
|
\begin{description}\parsep0ex plus 0.0ex minus 1.0ex%
|
|
\itemsep0ex\topsep-0.5ex%
|
|
\item[overlay of segments]--- the calculation of the 1-skeleton
|
|
$P'=(V,E)$ of a plane map via the overlay of the segments in $S$ plus
|
|
the calculation of a map $|halfedge_below|:V \rightarrow E$
|
|
\item[face creation]--- the completion of the 1-skeleton $P'$ to a
|
|
full plane map $P = (V,E,F)$ by creating all faces while using the
|
|
information of the map |halfedge_below|.
|
|
\end{description}
|
|
\repdiss{For the overlay process we use the generic segment sweep
|
|
module as presented in the technical report
|
|
\cite{TR:nefimplementation}}{For the overlay process we use the
|
|
generic segment sweep module as presented in Section \ref{generic
|
|
plane sweep}}. There we presented a generic class
|
|
|Segment_overlay_traits| realizing a generic sweep framework. To
|
|
instantiate it we have to provide three components (input, output,
|
|
geometry). In this instance, the input is an iterator pair; the
|
|
geometry is forwarded from the current class scope. Only for the
|
|
output type do we have to work a little more. We define a class
|
|
|PMO_from_segs| that fits the output concept of
|
|
|Segment_overlay_traits| and at the same time is a model for the
|
|
|Below_info| concept required for the facet creation in Section
|
|
\ref{creating face objects}. (See Figure \figref{PMO_from_segs}.)
|
|
|
|
\displayeps{PMO_from_segs}{|PMO_from_segs| realizes the |Output|
|
|
concept of the generic sweep module and the |Below_info|
|
|
concept for the facet creation phase. In the figure, |Vertex_handle|,
|
|
|Halfedge_handle|, and |Iterator| have been replaced by the short
|
|
symbols |V|, |E|, and |I|.}{10cm}
|
|
|
|
Upon creation, an object of type |PMO_from_segs| references a plane
|
|
map via a decorator |G| and obtains a data accessor object |D| of type
|
|
|DA|. |PMO_from_segs|, as a model of |SegmentOverlayOutput|, triggers
|
|
the correct update operations on the output plane map during the
|
|
sweep. See the output concept in Figure \figref{PMO_from_segs}. The
|
|
method part O1 of |SegmentOverlayOutput| takes care of the plane map
|
|
extension by new vertices and edges. The part O2 allows one to obtain
|
|
information about how the creation of the objects is linked to the
|
|
input interators. In the implementation \repdiss{}{(which we do not
|
|
show)} of |PMO_from_segs| we forward this interface to methods of the
|
|
data accessor of type DA. Finally, part O3 can be used to collect the
|
|
additional information required for the facet creation. An edge |e|
|
|
that is immediately below\footnote{along the negative $y$-axis
|
|
parallel to our sweep line.} a vertex |v| is stored in the vertex
|
|
object in a temporarily assigned data slot and can be retrieved after
|
|
the sweep. |PMO_from_segs|, as a |Below_info| model, can thus
|
|
afterwards deliver the halfedge |halfedge_below(v)| for any vertex $v$
|
|
of the plane map.
|
|
|
|
At this point our readers should take the module
|
|
@c
|
|
generic_sweep< Segment_overlay_traits<PMO_from_segs<... >... >>
|
|
|
|
@ as a black box producing the 1-skeleton of $P$ with the properties
|
|
required in Section \ref{creating face objects}. The specification of
|
|
|Segment_overlay_traits| guarantees these properties of $P$ because
|
|
|PMO_from_segs| fits the requirements of the output concept of
|
|
|Segment_overlay_traits|.
|
|
\begin{ignoreindiss}
|
|
<<PM traits classes for segment overlay>>=
|
|
template <typename PMD, typename I, typename DA>
|
|
struct PMO_from_segs {
|
|
typedef PMD Decorator;
|
|
typedef typename Decorator::Vertex_handle Vertex_handle;
|
|
typedef typename Decorator::Halfedge_handle Halfedge_handle;
|
|
typedef typename Decorator::Point Point;
|
|
const Decorator& G;
|
|
DA& D;
|
|
PMO_from_segs(const Decorator& Gi, DA& Di) :
|
|
G(Gi),D(Di) {}
|
|
|
|
<<PMO_from_segs segment overlay model interface>>
|
|
<<PMO_from_segs face creation model interface>>
|
|
<<PMO_from_segs additional interface>>
|
|
}; // PMO_from_segs
|
|
|
|
|
|
@ The creation of new objects is forwarded to the |Decorator| object
|
|
|G|. The methods of |G| are members as described in the |PM_decorator|
|
|
concept. The following methods are called during the sweep at its
|
|
event points. The first three methods trigger object creation in $P$.
|
|
We associate a |Halfedge_handle| to each vertex |v| via its generic
|
|
storage slot $|GenPtr& info(v)|$. We use a scheme in analogy to LEDA
|
|
\cite[chapter 13]{ledabook}, where information (in form of a built-in
|
|
or class type) is stored directly in the pointer if it has size not
|
|
larger than the size of a standard word. If it does not fit, the
|
|
pointer is used to reference a newly allocated information object on
|
|
the heap. The scheme is bundled in a class called |geninfo<T>|. For
|
|
more information see that manual page in the appendix.
|
|
<<PMO_from_segs segment overlay model interface>>=
|
|
Vertex_handle new_vertex(const Point& p)
|
|
{ Vertex_handle v = G.new_vertex(p);
|
|
geninfo<Halfedge_handle>::create(G.info(v));
|
|
return v;
|
|
}
|
|
|
|
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e)
|
|
{ G.link_as_target_and_append(v,e); }
|
|
|
|
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v)
|
|
{ Halfedge_handle e =
|
|
G.new_halfedge_pair_at_source(v,Decorator::BEFORE);
|
|
return e;
|
|
}
|
|
|
|
@ The treatment of the new objects is forwarded to the |DA| object
|
|
|D|. Only the below link is stored via |G|. The following methods
|
|
allow us to hook methods of |D| into the plane sweep process.
|
|
<<PMO_from_segs segment overlay model interface>>=
|
|
void supporting_segment(Halfedge_handle e, I it) const
|
|
{ D.supporting_segment(e,it); }
|
|
|
|
void trivial_segment(Vertex_handle v, I it) const
|
|
{ D.trivial_segment(v,it); }
|
|
|
|
void starting_segment(Vertex_handle v, I it) const
|
|
{ D.starting_segment(v,it); }
|
|
|
|
void passing_segment(Vertex_handle v, I it) const
|
|
{ D.passing_segment(v,it); }
|
|
|
|
void ending_segment(Vertex_handle v, I it) const
|
|
{ D.ending_segment(v,it); }
|
|
|
|
void halfedge_below(Vertex_handle v, Halfedge_handle e) const
|
|
{ geninfo<Halfedge_handle>::access(G.info(v)) = e; }
|
|
|
|
@ |PMO_from_segs| fits also the concept |Below_info| for the face
|
|
creation defined in Section \ref{creating face objects}.
|
|
<<PMO_from_segs face creation model interface>>=
|
|
Halfedge_handle halfedge_below(Vertex_handle v) const
|
|
{ return geninfo<Halfedge_handle>::access(G.info(v)); }
|
|
|
|
@ We finally add a clean up operation discarding the temporary
|
|
storage.
|
|
<<PMO_from_segs additional interface>>=
|
|
void clear_temporary_vertex_info() const
|
|
{ Vertex_handle v;
|
|
for(v = G.vertices_begin(); v!= G.vertices_end(); ++v)
|
|
geninfo<Halfedge_handle>::clear(G.info(v));
|
|
}
|
|
|
|
|
|
@ \end{ignoreindiss}
|
|
|
|
Now, the overlay creation is trivial. Just create an output decorator
|
|
object |Out| working on the plane map maintained by |PM_overlayer| and
|
|
plug it into the segment sweep overlay framework
|
|
|Segment_overlay_traits|. The used geometry is just forwarded from
|
|
|PM_overlayer|. The |create| method of |PM_overlayer| is
|
|
parameterized by the iterator type |Forward_iterator| and the data
|
|
accessor class |Object_data_accessor|.
|
|
|
|
Note that the |halfedge_below| information collected during the sweep
|
|
is associated with the vertices of the output map. The corresponding
|
|
object |Out| triggers the output creation during the sweep and
|
|
provides the halfedge-below information for the face creation in
|
|
|create_face_objects()|. |Out.clear_temporary_vertex_info()| just
|
|
discards the temporarily allocated information slots (internally
|
|
assigned to the vertices) on the heap.
|
|
<<subdivision>>=
|
|
|
|
template <typename Forward_iterator, typename Object_data_accessor>
|
|
void create(Forward_iterator start, Forward_iterator end,
|
|
Object_data_accessor& A) const
|
|
/*{\Mop produces in |P| the plane map consistent with the overlay
|
|
of the segments from the iterator range |[start,end)|. The data accessor
|
|
|A| allows to initialize created vertices and edges with respect to the
|
|
segments in the iterator range. |A| requires the following methods:\\
|
|
[[void supporting_segment(Halfedge_handle e, Forward_iterator it)]]\\
|
|
[[void trivial_segment(Vertex_handle v, Forward_iterator it)]]\\
|
|
[[void starting_segment(Vertex_handle v, Forward_iterator it)]]\\
|
|
[[void passing_segment(Vertex_handle v, Forward_iterator it)]]\\
|
|
[[void ending_segment(Vertex_handle v, Forward_iterator it)]]\\
|
|
where |supporting_segment| is called for each non-trivial segment |*it|
|
|
supporting a newly created edge |e|, |trivial_segment| is called for
|
|
each trivial segment |*it| supporting a newly created vertex |v|, and
|
|
the three last operations are called for each non-trivial segment
|
|
|*it| starting at/passing through/ending at the embedding of a newly
|
|
created vertex |v|.
|
|
\precond |Forward_iterator| has value type |Segment|.}*/
|
|
{
|
|
TRACEN("creating from iterator range");
|
|
typedef PMO_from_segs<Self,Forward_iterator,Object_data_accessor>
|
|
Output_from_segments;
|
|
typedef Segment_overlay_traits<
|
|
Forward_iterator, Output_from_segments, Geometry> seg_overlay;
|
|
typedef generic_sweep< seg_overlay > seg_overlay_sweep;
|
|
typedef typename seg_overlay::INPUT input_range;
|
|
Output_from_segments Out(*this, A);
|
|
seg_overlay_sweep SOS( input_range(start, end), Out, K);
|
|
SOS.sweep();
|
|
create_face_objects(Out);
|
|
Out.clear_temporary_vertex_info();
|
|
}
|
|
|
|
@ We summarize the calculated overlay properties and anticipate the
|
|
costs of face creation (Section \ref{creating face objects}) and of
|
|
the plane sweep phase. (see Lemma \ref{generic segment sweep
|
|
runtime}).
|
|
\begin{lemma}
|
|
Assume that |S = set [start,end)| is a set of segments and |A| is a
|
|
data accessor with the required methods (of constant cost). Then,
|
|
$|create|(start,end,A)$ constructs in $P = (V,E,F)$ the overlay plane
|
|
map of $S$. Let $n$ be the number of segments in $S$, $n_v =
|
|
\Labs{V}$, $n_e = \Labs{E}$, and $\bar{n}_e$ the sum of the support
|
|
multiplicity of each edge over all edges. Then the running time of the
|
|
overlay process is dominated by the plane sweep and is therefore
|
|
$O(n_v + \bar{n}_e + (n+n_v) \log (n+n_v))$.
|
|
\end{lemma}
|
|
|
|
|
|
@ \subsection{Overlay calculation of two plane maps}
|
|
\label{Overlay calculation of two plane maps}
|
|
|
|
We calculate the overlay $P$ of two plane maps $P_0$ and $P_1$. Both
|
|
input structures are correctly defined plane maps including incidence,
|
|
geometric embedding, and markers. In the following we use the index
|
|
$i=0,1$ showing a reference to $P_i = (V_i,E_i,F_i)$; non-indexed
|
|
variables refer to $P$.
|
|
|
|
The $1$-skeleta of the two maps $P_0$ and $P_1$ subdivide the edges
|
|
and faces of the complementary structures into smaller units. This
|
|
means vertices and edges of $P_i$ can split edges of $P_{1-i}$ and
|
|
face cycles of $P_i$ subdivide faces of $P_{1-i}$. The 1-skeleton $P'
|
|
= (V,E)$ of $P$ is defined by the overlay of the embedded 1-skeleta of
|
|
$P_0$ and $P_1$. (Take a trivial segment for each vertex and a segment
|
|
for each edge and use the overlay definition of a set of segments
|
|
above.) Additionally, we require that $P'$ has the correct order in
|
|
each adjacency list such that it is order-preserving with respect to
|
|
the embedding of the vertices.
|
|
|
|
Finally, the faces of $P$ refer to the maximal connected open point
|
|
sets of the planar subdivision implied by the embedding of $P'$. The
|
|
construction of the faces $F$ from $P'$ is described in Section
|
|
\ref{creating face objects}. Each object $u$ from the output tuple
|
|
$(V,E,F)$ has a \emph{supporting} object $u_i, i=0,1$ in each of the
|
|
two input structures. Imagine the two maps to be transparencies,
|
|
stacked one on top of the other. Then each point of the plane is
|
|
covered by an object from each of the input structures. We analyse the
|
|
support relation from input to output in order to transfer the
|
|
attributes from $u_i$ to $u$.
|
|
|
|
According to our specification, each object $u_i$ of $P_i$ carries an
|
|
attribute\footnote{we use a general attribute set, though with respect
|
|
to Nef polyhedra $|Mark| := \{|true|,|false|\}$.} $|mark|(u_i)$
|
|
($|mark|: (V_i \cup E_i \cup F_i) \to |Mark|$). We associate this
|
|
information with the output object $u$ by $|mark|(u,i)$ (an overloaded
|
|
function $|mark|: (V \cup E \cup F) \times \{0,1\} \to |Mark|$). This
|
|
two-tuple of information per object can then be processed by some
|
|
combining operation to a single value |mark(u)| later on.
|
|
|
|
We fix the following \textbf{input properties} for our structures
|
|
$P_i$. Both plane maps $(V_i, E_i, F_i)$ consist of vertices, edges,
|
|
and faces whose topology is accessible by our plane map interface and
|
|
additionally each object $u_i$ carries an attribute $|mark|(u_i)$. The
|
|
plane maps have an \emph{order-preserving} embedding and their
|
|
adjacency lists have a \emph{forward prefix}. Actually we do not use
|
|
this property of the input plane maps at this point, but it is a
|
|
general invariant of our plane map structures that makes some
|
|
intermediate actions more efficient. The overlay process consists of
|
|
\textbf{three phases}: The 1-skeleton $P'$ is produced by segment
|
|
overlay. Afterwards we create the face objects. Finally, we analyse
|
|
the support relation and transfer the marks of the input objects to
|
|
the output objects.
|
|
|
|
\begin{description}
|
|
\item[overlay of segments] --- We use our generic segment overlay
|
|
framework to calculate the overlay of a set of segments $S$. The set
|
|
$S$ consists of all segments that are the embedding of edges in $E_i$
|
|
and additionally trivial segments representing all isolated vertices
|
|
in $V_i$. The output structure $P' = (V,E)$ of the sweep phase is
|
|
just the 1-skeleton of the output plane map $P$, but of course
|
|
including an order-preserving embedding and a forward-prefix in the
|
|
adjacency lists. The objects of the 1-skeleton carry additional
|
|
structural information:
|
|
|
|
\begin{enumerate}\parsep0ex plus 0.0ex minus 1.0ex%
|
|
\itemsep0ex\topsep-0.5ex\renewcommand{\labelenumi}{I\theenumi.}%
|
|
\item Each vertex $v$ in $V$ knows a halfedge $e \in E : e =
|
|
|halfedge_below(v)|$ which is determined by the property that a
|
|
vertical ray shot from |v| along the negative $y$-axis hits |e|
|
|
first. Degeneracies are broken with an implicit perturbation scheme:
|
|
during the ray shooting all edges include their source but not their
|
|
target vertices.
|
|
\label{halfedge below}
|
|
\item For each object $u \in V \cup E$ there is a mapping to the
|
|
supporting 1-skeleton objects of the input structures. The support
|
|
information is incomplete with respect to face support.
|
|
\label{skeleton support}
|
|
\end{enumerate}
|
|
|
|
\item[face creation] --- The next phase after the sweep completes the
|
|
plane map $P$. We basically have to create the face objects and
|
|
construct their incidence structures. The face creation is done as
|
|
presented in Section \ref{creating face objects} and uses only
|
|
I\ref{halfedge below}.
|
|
\item[attribute transfer] --- The final transfer of marks uses the
|
|
embedding of the vertex list of $P$ and the additional information
|
|
I\ref{halfedge below} and I\ref{skeleton support} to define
|
|
$|mark|(u,i)$ for all objects $u$ in $P$.
|
|
\end{description}
|
|
<<subdivision>>=
|
|
|
|
void subdivide(const Plane_map& P0, const Plane_map& P1) const
|
|
/*{\Mop constructs the overlay of the plane maps |P0| and |P1| in
|
|
|P|, where all objects (vertices, halfedges, faces) of |P| are
|
|
\emph{enriched} by the marks of the supporting objects of the two
|
|
input structures: e.g. let |v| be a vertex supported by a node |v0| in
|
|
|P0| and by a face |f1| in |P1| and |D0|, |D1| be decorators of
|
|
type |PM_decorator| on |P0|,|P1|. Then |\Mvar.mark(v,0) = D0.mark(v0)|
|
|
and |\Mvar.mark(v,1) = D1.mark(f1)|.}*/
|
|
{
|
|
Const_decorator PI[2];
|
|
PI[0] = Const_decorator(P0); PI[1] = Const_decorator(P1);
|
|
<<filling the input segment list>>
|
|
<<sweeping the segments and creating the faces>>
|
|
<<transfering the marks of supporting objects>>
|
|
}
|
|
|
|
|
|
@ \subsection*{Temporary information associated with objects}
|
|
|
|
We have to associate temporary information with the objects of the
|
|
output plane map. In this section we abstractly use sets in a pseudo
|
|
code notation to underline the origin of plane map objects. The
|
|
objects from these sets are realized by the corresponding handle types
|
|
(and therefore their type does not allow us to mark their origin).
|
|
Undefined objects are detectible via default handles.
|
|
|
|
At first we interpret the input 1-skeleta geometrically. We collect a
|
|
set of trivial and non-trivial segments $S$. For each edge in $E_i$
|
|
we add a non-trivial segment to $S$ and for each isolated vertex of
|
|
$V_i$ we add a trivial segment to $S$. We store the origin of the
|
|
objects in $S$ via a function
|
|
\begin{eqnarray*}
|
|
|From| & : & S \to (V_{0,1} \cup E_{0,1}) \times \{0,1\}\\
|
|
|From|(s) & = & \begin{cases}
|
|
(v_i,i) & \text{if $s$ is a trivial segment refering to an isolated
|
|
vertex $v_i$ from $P_i$},\\
|
|
(e_i,i) & \text{if $s$ is a non-trivial segment refering to an edge
|
|
$e_i$ from $P_i$.}
|
|
\end{cases}
|
|
\end{eqnarray*}
|
|
|From| is implemented as a hash map |From| whose domain is iterators
|
|
(with value type segment) and whose value is a structure |Seg_info|
|
|
with members |v|, |e|, |i| storing the above pairs.
|
|
\begin{ignoreindiss}
|
|
<<info type to link edges and segments>>=
|
|
struct Seg_info { // to transport information from input to output
|
|
Halfedge_const_handle e;
|
|
Vertex_const_handle v;
|
|
int i;
|
|
|
|
Seg_info() : i(-1) {}
|
|
Seg_info(Halfedge_const_handle e_, int i_)
|
|
{ e=e_; i=i_; }
|
|
Seg_info(Vertex_const_handle v_, int i_)
|
|
{ v=v_; i=i_; }
|
|
Seg_info(const Seg_info& si)
|
|
{ e=si.e; v=si.v; i=si.i; }
|
|
Seg_info& operator=(const Seg_info& si)
|
|
{ e=si.e; v=si.v; i=si.i; return *this; }
|
|
LEDA_MEMORY(Seg_info)
|
|
};
|
|
|
|
@ \end{ignoreindiss}
|
|
<<info type to link edges and segments>>=
|
|
typedef std::list<Segment> Seg_list;
|
|
typedef typename Seg_list::const_iterator Seg_iterator;
|
|
typedef std::pair<Seg_iterator,Seg_iterator> Seg_it_pair;
|
|
|
|
@ In the first phase, we fill the segment input list with the
|
|
non-trivial segments underlying the edges and with a trivial segment
|
|
for each isolated vertex of the two input structures. Additionally, we
|
|
store hashed links from the iterators to the edges/vertices to store
|
|
their origins.
|
|
<<filling the input segment list>>=
|
|
Seg_list Segments; int i;
|
|
CGAL::Unique_hash_map<Seg_iterator,Seg_info> From;
|
|
for (i=0; i<2; ++i) {
|
|
Vertex_const_iterator v;
|
|
for(v = PI[i].vertices_begin(); v != PI[i].vertices_end(); ++v)
|
|
if ( PI[i].is_isolated(v) ) {
|
|
Segments.push_back(segment(PI[i],v));
|
|
From[--Segments.end()] = Seg_info(v,i);
|
|
}
|
|
Halfedge_const_iterator e;
|
|
for(e = PI[i].halfedges_begin(); e != PI[i].halfedges_end(); ++e)
|
|
if ( is_forward_edge(PI[i],e) ) {
|
|
Segments.push_back(segment(PI[i],e));
|
|
From[--Segments.end()] = Seg_info(e,i);
|
|
}
|
|
}
|
|
|
|
|
|
@ During the sweep phase we collect additional information in
|
|
temporary information containers associated with the objects $u \in V
|
|
\cup E \cup F$ of $P$.
|
|
\begin{tabbing}
|
|
|assoc_info(u)| \qquad\= creates the temporary object on the heap\\
|
|
|discard_info(u)| \> discards the object and frees the memory
|
|
\end{tabbing}
|
|
Within these objects we store the following pair of mark attributes
|
|
(indexed by $i$):
|
|
\begin{tabbing}
|
|
|Mark mark(u,i)| \qquad\= for $i=0,1$ and $u\in V \cup E \cup F$
|
|
\end{tabbing}
|
|
For each vertex $v$ we collect \emph{skeleton support} information.
|
|
\begin{tabbing}
|
|
$V_i\ |supp_vertex|(V v, int i)$ \qquad \= the vertex from $V_i$
|
|
supporting |v| if it exists, else undefined.\\ $E_i\ |supp_halfedge|(V
|
|
v, int i)$ \> the edge from $E_i$ supporting |e| if it exists, else
|
|
undefined.
|
|
\end{tabbing}
|
|
And for each edge $e$ we want to know
|
|
\begin{tabbing}
|
|
$E_i\ |supp_halfedge(E e, int i)|$\qquad\= the edge from $E_i$
|
|
supporting |e| if it exists, else undefined.\\
|
|
$|Mark incident_mark(E e, int i)|$\>
|
|
the mark of the face from $P_i$ supporting a small neighborhood
|
|
left of $e$.\\
|
|
\end{tabbing}
|
|
The information is collected during the sweep phase by a corresponding
|
|
model of the output concept used in our generic sweep framework.
|
|
\begin{onlyindiss}
|
|
We omit the realization of the above attribution. Details can be found
|
|
in the accompanying research report.
|
|
\end{onlyindiss}
|
|
\begin{ignoreindiss}
|
|
We show more details of the information association. We use a trick
|
|
via generic pointers |GenPtr| (equals |void*|). Each object |u| of |P|
|
|
has such a slot accessible via $|GenPtr& info(u)|$. We use the pointer
|
|
to reference an object storing the temporary information until the
|
|
postprocessing does not need it anymore. We have to ensure that we do
|
|
not mess around with the memory. The temporary information is
|
|
collected during the sweep operation. After the selection operation
|
|
the temporary information is discarded. To avoid superflous
|
|
indirection for the temporary information we use a scheme in analogy
|
|
to LEDA \cite[chapter 13]{ledabook}, where information (in form of a
|
|
built-in or class type) is stored directly in the pointer if it has
|
|
size not larger than the size of a standard word. If it does not fit,
|
|
the pointer is used to reference a newly allocated information object
|
|
on the heap. This scheme leaves the vertex, halfedge, and face objects
|
|
minimal in the sense that we only have one additional pointer in each
|
|
of them. The scheme is bundled in a class called |geninfo<T>|. For
|
|
more information see that manual page in the appendix.
|
|
|
|
We associate the following class to a vertex $v$. The methods below
|
|
are added to the interface of |PM_overlayer|. |vertex_info| can store
|
|
the possible supporting skeleton objects |v_supp|, |e_supp| of the
|
|
input plane maps, marks |m| corresponding to the two supporting
|
|
objects and a halfedge |e_below| of the output structure that is
|
|
vertically below $v$.
|
|
<<helping operations>>=
|
|
struct vertex_info {
|
|
Mark m[2];
|
|
Vertex_const_handle v_supp[2];
|
|
Halfedge_const_handle e_supp[2];
|
|
Halfedge_handle e_below;
|
|
vertex_info()
|
|
{ v_supp[0]=v_supp[1]=Vertex_const_handle();
|
|
e_supp[0]=e_supp[1]=Halfedge_const_handle(); }
|
|
LEDA_MEMORY(vertex_info)
|
|
};
|
|
|
|
void assoc_info(Vertex_handle v) const
|
|
{ geninfo<vertex_info>::create(info(v)); }
|
|
|
|
void discard_info(Vertex_handle v) const
|
|
{ geninfo<vertex_info>::clear(info(v)); }
|
|
|
|
vertex_info& ginfo(Vertex_handle v) const
|
|
{ return geninfo<vertex_info>::access(info(v)); }
|
|
|
|
Mark& mark(Vertex_handle v, int i) const
|
|
{ return ginfo(v).m[i]; }
|
|
|
|
Vertex_const_handle& supp_vertex(Vertex_handle v, int i) const
|
|
{ return ginfo(v).v_supp[i]; }
|
|
|
|
Halfedge_const_handle& supp_halfedge(Vertex_handle v, int i) const
|
|
{ return ginfo(v).e_supp[i]; }
|
|
|
|
Halfedge_handle& halfedge_below(Vertex_handle v) const
|
|
{ return ginfo(v).e_below; }
|
|
|
|
@ For each halfedge we store the following class. Again we provide an
|
|
interface in |PM_overlayer|. The |halfedge_info| objects store
|
|
information common to both halfedge twins (information for the uedge)
|
|
and information only concerning one halfedge. In the first case we
|
|
store the information only in the halfedge determined by the smaller
|
|
memory address which makes access unique. We provide storage |e_supp|
|
|
for the possible two input edges supporting an output edge, the marks
|
|
|m| of the two input objects supporting an output edge, and temporary
|
|
storage |mf| for the marks of the two input faces supporting points in
|
|
a small neighborhood of the edge. The boolean flag |forw| just caches
|
|
the geometric property if an edge is forward-oriented (the source is
|
|
lexicographically smaller than the target).
|
|
<<helping operations>>=
|
|
struct halfedge_info {
|
|
Mark m[2];
|
|
Mark mf[2];
|
|
Halfedge_const_handle e_supp[2];
|
|
bool forw;
|
|
halfedge_info()
|
|
{ m[0]=m[1]=mf[0]=mf[1]=Mark();
|
|
e_supp[0]=e_supp[1]=Halfedge_const_handle();
|
|
forw=false; }
|
|
LEDA_MEMORY(halfedge_info)
|
|
};
|
|
|
|
void assoc_info(Halfedge_handle e) const
|
|
{ geninfo<halfedge_info>::create(info(e));
|
|
geninfo<halfedge_info>::create(info(twin(e))); }
|
|
|
|
void discard_info(Halfedge_handle e) const
|
|
{ geninfo<halfedge_info>::clear(info(e));
|
|
geninfo<halfedge_info>::clear(info(twin(e))); }
|
|
|
|
halfedge_info& ginfo(Halfedge_handle e) const
|
|
{ return geninfo<halfedge_info>::access(info(e)); }
|
|
|
|
Mark& mark(Halfedge_handle e, int i) const
|
|
// uedge information we store in the smaller one
|
|
{ if (&*e < &*(twin(e))) return ginfo(e).m[i];
|
|
else return ginfo(twin(e)).m[i]; }
|
|
|
|
Halfedge_const_handle& supp_halfedge(Halfedge_handle e, int i) const
|
|
// uedge information we store in the smaller one
|
|
{ if (&*e < &*(twin(e))) return ginfo(e).e_supp[i];
|
|
else return ginfo(twin(e)).e_supp[i]; }
|
|
|
|
Mark& incident_mark(Halfedge_handle e, int i) const
|
|
// biedge information we store in the halfedge
|
|
{ return ginfo(e).mf[i]; }
|
|
|
|
bool& is_forward(Halfedge_handle e) const
|
|
// biedge information we store in the halfedge
|
|
{ return ginfo(e).forw; }
|
|
|
|
@ A face just obtains two mark slots |m|.
|
|
<<helping operations>>=
|
|
struct face_info {
|
|
Mark m[2];
|
|
face_info() { m[0]=m[1]=Mark(); }
|
|
LEDA_MEMORY(face_info)
|
|
};
|
|
|
|
void assoc_info(Face_handle f) const
|
|
{ geninfo<face_info>::create(info(f)); }
|
|
|
|
void discard_info(Face_handle f) const
|
|
{ geninfo<face_info>::clear(info(f)); }
|
|
|
|
face_info& ginfo(Face_handle f) const
|
|
{ return geninfo<face_info>::access(info(f)); }
|
|
|
|
Mark& mark(Face_handle f, int i) const
|
|
{ return ginfo(f).m[i]; }
|
|
|
|
@ Finally we provide an operation cleaning up the temporary attributes
|
|
allocated above.
|
|
<<helping operations>>=
|
|
void clear_associated_info_of_all_objects() const
|
|
{
|
|
Vertex_iterator vit;
|
|
for (vit = vertices_begin(); vit != vertices_end(); ++vit)
|
|
discard_info(vit);
|
|
Halfedge_iterator hit;
|
|
for (hit = halfedges_begin(); hit != halfedges_end(); ++hit)
|
|
discard_info(hit);
|
|
Face_iterator fit;
|
|
for (fit = faces_begin(); fit != faces_end(); ++fit)
|
|
discard_info(fit);
|
|
}
|
|
|
|
@ \end{ignoreindiss}
|
|
\subsection*{The sweep instantiation}
|
|
|
|
We have to provide the three components (input, output, geometry)
|
|
necessary to instantiate the traits model |Segment_\-overlay_\-traits|
|
|
for our generic plane sweep framework. The input is an iterator pair;
|
|
the geometry is forwarded from the current class scope. Again we
|
|
elaborate on the output type. We define a class |PMO_from_pm| below,
|
|
which allows us to track the support relationship from input objects
|
|
(segments handled via iterators) to the output objects (vertices and
|
|
halfedges) via the call-back methods triggered during the
|
|
sweep. Please refer to the description of
|
|
|Segment_\-overlay_\-traits|.
|
|
|
|
The methods of |PMO_from_pm| fit the output concept requirements of
|
|
|Segment_\-overlay_\-traits|. The functionality is such that the
|
|
skeleton is created and the support information is associated with the
|
|
newly created objects. |PMO_from_pm| is a class template on the global
|
|
implementation scope as the usage of local class types (within the
|
|
scope of |PM_overlayer|) is not allowed by some current C++ compilers.
|
|
|
|
\displayeps{PMO_from_pm}{|PMO_from_pm| realizes the |Output|
|
|
concept of the generic sweep module and the |Below_info|
|
|
concept for the facet creation phase. In the figure |Vertex_handle|,
|
|
|Halfedge_handle|, and |Iterator| have been replaced by the short
|
|
symbols |V|, |E|, and |I|.}{10cm}%{14cm}
|
|
|
|
\begin{onlyindiss}
|
|
We shortly describe how the temporary information associated with the
|
|
skeleton objects is retrieved from the use of |PMO_from_pm|
|
|
(cf. Figure \figref{PMO_from_pm}) as an output model in the generic
|
|
sweep. The operations in section O1 create and link new objects in $P$
|
|
and additionally use |assoc_info()| to create the temporary storage
|
|
containers. The operations in section O2 accumulate the support
|
|
information. As an example, we show how the information for
|
|
|supp_halfedge(V,int)| is collected:
|
|
@c
|
|
void PMO_from_pm<PMD,I,FROM>::passing_segment(V v, I it)
|
|
{ int i = From[it].i;
|
|
supp_halfedge(v,i) = From[it].e;
|
|
}
|
|
|
|
@ At each event of the sweep, a vertex $v$ is created in $P$ and if
|
|
$v$ lies in the interior of the segment |*it| the above operation is
|
|
called. Thereby, after the sweep all edges from $E_i$ that support a
|
|
vertex $v$ from $V$ are associated with $v$. The remaining support is
|
|
determined similarily. The operation in section O3 is realized to
|
|
collect information that allows |PMO_from_pm| to serve as a model for
|
|
the |Below_info| concept.
|
|
\end{onlyindiss}
|
|
|
|
\begin{ignoreindiss}
|
|
Note that we forward a reference to our hash map |From| to the output
|
|
decorator object. Thus we can update the support linkage from output
|
|
skeleton objects via iterators to input objects on the fly when the
|
|
sweep frameworks calls the corresponding methods of |PMO_from_pm|.
|
|
|
|
<<PM traits classes for segment overlay>>=
|
|
template <typename PMD, typename IT, typename INFO>
|
|
struct PMO_from_pm {
|
|
<<importing decorators, handles, and point type from PMD>>
|
|
const Decorator& G;
|
|
const Const_decorator* pGI[2];
|
|
CGAL::Unique_hash_map<IT,INFO>& M;
|
|
PMO_from_pm(const Decorator& Gi,
|
|
const Const_decorator* pG0,
|
|
const Const_decorator* pG1,
|
|
CGAL::Unique_hash_map<IT,INFO>& Mi) : G(Gi),M(Mi)
|
|
{ pGI[0]=pG0; pGI[1]=pG1; }
|
|
|
|
<<PMO_from_pm topological updates>>
|
|
<<PMO_from_pm vertical ray shoot knowledge>>
|
|
<<PMO_from_pm support knowledge>>
|
|
<<PMO_from_pm face creation data access>>
|
|
|
|
}; // PMO_from_pm
|
|
|
|
<<importing decorators, handles, and point type from PMD>>=
|
|
typedef PMD Decorator;
|
|
typedef typename PMD::Const_decorator Const_decorator;
|
|
typedef typename Decorator::Vertex_handle Vertex_handle;
|
|
typedef typename Decorator::Halfedge_handle Halfedge_handle;
|
|
typedef typename Decorator::Vertex_const_handle Vertex_const_handle;
|
|
typedef typename Decorator::Halfedge_const_handle Halfedge_const_handle;
|
|
typedef typename Decorator::Point Point;
|
|
|
|
@ New vertices and halfedges are created in the plane map via
|
|
a call to corresponding creation methods of the decorator. Note
|
|
that we initialize a temporary storage slot in the objects by
|
|
a call to |assoc_info|.
|
|
<<PMO_from_pm topological updates>>=
|
|
Vertex_handle new_vertex(const Point& p) const
|
|
{ Vertex_handle v = G.new_vertex(p);
|
|
G.assoc_info(v);
|
|
return v;
|
|
}
|
|
|
|
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e) const
|
|
{ G.link_as_target_and_append(v,e); }
|
|
|
|
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v) const
|
|
{ Halfedge_handle e =
|
|
G.new_halfedge_pair_at_source(v,Decorator::BEFORE);
|
|
G.assoc_info(e);
|
|
return e;
|
|
}
|
|
|
|
@ The halfedge vertically below a vertex is stored in a slot of the
|
|
temporarily associated information container of type
|
|
|vertex_info|. Access is done via the |PM_overlayer| operation
|
|
|halfedge_below()|.
|
|
<<PMO_from_pm vertical ray shoot knowledge>>=
|
|
void halfedge_below(Vertex_handle v, Halfedge_handle e) const
|
|
{ G.halfedge_below(v) = e; }
|
|
|
|
@ For a new halfedge |e| we get to know all segments |*it|
|
|
that support it. We store the information via the decorator.
|
|
There can be at most two input segments supporting an edge.
|
|
<<PMO_from_pm support knowledge>>=
|
|
void supporting_segment(Halfedge_handle e, IT it) const
|
|
{ INFO& si = M[it];
|
|
CGAL_assertion( si.e != Halfedge_const_handle() );
|
|
G.supp_halfedge(e,si.i) = si.e;
|
|
G.is_forward(e) = true;
|
|
}
|
|
|
|
|
|
@ For a vertex |v| we get to know support information. There are three
|
|
basic cases: |v| is supported by an isolated vertex, |v| is supported
|
|
by a vertex from one input structure which has incident edges
|
|
(starting or ending) during the sweep, or |v| comes to lie in the
|
|
relative interior of an input edge. In either case one of the
|
|
following operations attributes the correct support information.
|
|
<<PMO_from_pm support knowledge>>=
|
|
void trivial_segment(Vertex_handle v, IT it) const
|
|
{ INFO& si = M[it];
|
|
CGAL_assertion( si.v != Vertex_const_handle() );
|
|
G.supp_vertex(v,si.i) = si.v;
|
|
}
|
|
|
|
void starting_segment(Vertex_handle v, IT it) const
|
|
{ INFO& si = M[it];
|
|
G.supp_vertex(v,si.i) = pGI[si.i]->source(si.e);
|
|
}
|
|
|
|
void ending_segment(Vertex_handle v, IT it) const
|
|
{ INFO& si = M[it];
|
|
G.supp_vertex(v,si.i) = pGI[si.i]->target(si.e);
|
|
}
|
|
|
|
void passing_segment(Vertex_handle v, IT it) const
|
|
{ INFO& si = M[it];
|
|
G.supp_halfedge(v,si.i) = si.e;
|
|
}
|
|
|
|
@ |PMO_from_pm| also provides data access in the face creation
|
|
phase. Therefore this operation that redirects the access to
|
|
|PM_overlayer| object |G|.
|
|
<<PMO_from_pm face creation data access>>=
|
|
Halfedge_handle halfedge_below(Vertex_handle v) const
|
|
{ return G.halfedge_below(v); }
|
|
|
|
@ \end{ignoreindiss}
|
|
|
|
Now, creating the overlay is a trivial plugging of types into the
|
|
generic plane sweep framework, a creation of the sweep object with
|
|
input, output and geometry references, and a final execution of the
|
|
sweep. Afterwards, the faces are created.
|
|
<<sweeping the segments and creating the faces>>=
|
|
typedef PMO_from_pm<Self,Seg_iterator,Seg_info> Output_from_plane_maps;
|
|
typedef Segment_overlay_traits<
|
|
Seg_iterator, Output_from_plane_maps, Geometry> pm_overlay;
|
|
typedef generic_sweep< pm_overlay > pm_overlay_sweep;
|
|
Output_from_plane_maps Out(*this,&PI[0],&PI[1],From);
|
|
pm_overlay_sweep SOS(Seg_it_pair(Segments.begin(),Segments.end()),Out,K);
|
|
SOS.sweep();
|
|
create_face_objects(Out);
|
|
|
|
|
|
@ \subsection*{Transfering the marks}
|
|
|
|
After the sweep and the face creation, the input for this phase is a
|
|
plane map $P =(V,E,F)$ enriched by additional information attributed
|
|
to the 1-skeleton objects of $P$. The output vertices in $V$ are
|
|
linked to their supporting skeleton input objects (vertices and
|
|
edges). The output edges in $E$ are linked to their supporting input
|
|
edges. The support knowledge with respect to input faces is still
|
|
missing. In the following we analyse this support but do not store it
|
|
explicitly. Instead we only transfer the marks. There are several
|
|
properties of the constructed subdivision |P| that help us to do this.
|
|
\begin{itemize}\parsep0ex plus 0.0ex minus 1.0ex%
|
|
\itemsep0ex\topsep-0.5ex%
|
|
\item the vertices are constructed in the order of the sweep. By
|
|
iterating over them in their construction order we can rely on the
|
|
fact that we iterate according to the lexicographic order of their
|
|
embedding.
|
|
\item the halfedges out of a vertex |v| are ordered around |v|
|
|
counterclockwise (with respect to the embedding of their target).
|
|
We can therefore use a forward iteration to propagate face
|
|
information from bottom to top (on forward-oriented edges).
|
|
\item the first face $|faces_begin()|$ in the list of all faces is the
|
|
unbounded face. This holds for $P$, $P_0$, and $P_1$.
|
|
\end{itemize}
|
|
<<transfering the marks of supporting objects>>=
|
|
TRACEN("transfering marks");
|
|
<<initialize the outer face object>>
|
|
Vertex_iterator v, vend = vertices_end();
|
|
for (v = vertices_begin(); v != vend; ++v) {
|
|
TRACEN("mark at "<<PV(v));
|
|
<<determine mark of face below v>>
|
|
<<complete marks of vertex v>>
|
|
<<handle all forward oriented edges starting in v>>
|
|
}
|
|
<<transfer the marks to face objects>>
|
|
|
|
@ The transfer of face support marks is based on the following fact.
|
|
\displaylps{support}{The face support iteration unrolled. We examine
|
|
a position $p$ within the plane map $P$ and try to find the support by
|
|
a face $f_i$ in the plane map $P_i$. We have two vertices $v_1$ and
|
|
$v_2$ from $V$ with their forward-oriented edge bundle. The face that
|
|
supports $p$ with respect to $P_i$ can be determined by following the
|
|
dotted path until the outer unbounded face of $P_i$ is reached.}
|
|
|
|
\begin{fact}
|
|
Let $p$ be a point of the plane not part of the 1-skeleton of $P_i$,
|
|
$q$ be a point within the unbounded face of $P_i$, and $\rho$ be any
|
|
curve from $p$ to $q$ not containing any vertex of $P_i$. Assume
|
|
$\rho$ intersects an edge $e$ of the 1-skeleton of $P_i$ and let $e$
|
|
be the first such edge when following $\rho$ from $p$ to $q$. Then,
|
|
$p$ is part of the face incident to $e$. If $\rho$ does not intersect
|
|
the 1-skeleton, then $p$ is part of the unbounded face of $P_i$.
|
|
\end{fact}
|
|
The above fact is a consequence of the connectedness property of the
|
|
faces of $P_i$. We now consider point $p$ as part of $P$. For $p$ we
|
|
consider a special path $\rho$ as depicted in Figure
|
|
\figref{support}. We walk down along a vertical ray (in direction of
|
|
the negative $y$-axis). If we cross a bundle of edges incident to a
|
|
vertex $v$, the path turns just below the lowest edge and follows the
|
|
lowest edge in parallel until it is just below $v$. We iterate this
|
|
construction until it ends in a point $q$ in the unbounded face of
|
|
$P$. Each edge $e$ that is crossed by $\rho$ is supported by an edge
|
|
from either $P_i$ or $P_{1-i}$. In the former case, the first such
|
|
edge determines the face $f_i$ supporting $p$. If there is no such
|
|
edge then $p$ is supported by the unbounded face of $P_i$. We want to
|
|
determine face support for many vertices and edges, thus we do not
|
|
want to pay for such a walk for each query point $p$. Instead, we
|
|
associate with each edge $e$ face-support knowledge in the two slots
|
|
|mark(e,i)| and |incident_mark(e,i)|. The idea is that these slots
|
|
store the knowledge obtained from a reversal walk from $q$ to
|
|
$p$. Whenever our path $\rho$ crosses an edge $e$ in $P$ that is
|
|
supported by an edge $e_i$ in $P_i$, then we associate the mark
|
|
knowledge from $e_i$ plus the mark of the supporting faces from $P_i$
|
|
(of a small neighborhood left and right of $e$) with $e$. If the
|
|
information is already constructed for all edges below a query point
|
|
$p$, we can obtain the support information in constant time for
|
|
vertices via their |halfedge_below| information.
|
|
|
|
We now come to the coding. We want to complete the support marks for a
|
|
vertex |v| and the edges |e| of the adjacency list of |v| that are
|
|
forward-oriented\footnote{Backward oriented edges have forward
|
|
oriented twins.}. Consider following $\rho$ in reverse with a pen
|
|
starting in $q$. Then |m_below[2]| always stores the marks of the
|
|
faces of $P_i$ that support the position of the pen. In the beginning
|
|
|m_below[i]| stores the mark of the face $f_i$ below |v|. Note that we
|
|
obtain both marks for $i=0,1$ either from the outer input faces
|
|
surrounding the plane maps $P_i$ or from the halfedge below |v|. If
|
|
|e_below| exists then it was already treated as a forward-oriented
|
|
edge of a vertex already handled in the vertex iteration.
|
|
|
|
We initialize face support for the faces of unbounded extent. These
|
|
are always the first faces of the face list of the plane map data
|
|
type.
|
|
<<initialize the outer face object>>=
|
|
Face_iterator f = faces_begin(); assoc_info(f);
|
|
for (i=0; i<2; ++i) mark(f,i) = PI[i].mark(PI[i].faces_begin());
|
|
|
|
@ Note that the iteration over all vertices |v| has the invariant that
|
|
either |v| has no halfedge below it, or if it has a halfedge |e_below|
|
|
then |e_below| has all marks correctly assigned (|mark(e_below,i)| and
|
|
|incident_mark(e_below,i)| are set for both $i=0,1$.) Note that each
|
|
vertex $v$ of $P$ knows the halfedge below it, thus the face-support
|
|
marks can be initialized in constant time.
|
|
<<determine mark of face below v>>=
|
|
Halfedge_handle e_below = halfedge_below(v);
|
|
Mark m_below[2];
|
|
if ( e_below != Halfedge_handle() ) {
|
|
for (int i=0; i<2; ++i) {
|
|
m_below[i] = incident_mark(e_below,i);
|
|
}
|
|
} else { // e_below does not exist
|
|
for (int i=0; i<2; ++i)
|
|
m_below[i] = PI[i].mark(PI[i].faces_begin());
|
|
}
|
|
|
|
@ If the vertex |v| is not supported by a skeleton object of $P_i$
|
|
then it is supported by a face. We obtain the mark of the face from
|
|
|m_below| in this case.
|
|
<<complete marks of vertex v>>=
|
|
for (i=0; i<2; ++i)
|
|
if ( supp_halfedge(v,i) != Halfedge_const_handle() ) {
|
|
mark(v,i) = PI[i].mark(supp_halfedge(v,i));
|
|
} else if ( supp_vertex(v,i) != Vertex_const_handle() ) {
|
|
mark(v,i) = PI[i].mark(supp_vertex(v,i));
|
|
} else {
|
|
mark(v,i) = m_below[i];
|
|
}
|
|
|
|
@ We have to complete the mark information for all edges of |P|. We
|
|
do the job for all forward-oriented edges in the adjacency list of
|
|
each vertex |v|. How does a halfedge |e| of |P| obtain mark
|
|
information with respect to the two input structures $P_i$? We just
|
|
have to determine the supporting objects (edge or face) from each of
|
|
both. It is either supported by two overlapping edges $e_0, e_1$ or
|
|
only supported by one edge $e_i$ and one face $f_{1-i}$. Note that a
|
|
supporting edge $e_i$ allows access to its mark and to the two faces
|
|
incident to it and its twin. The supporting edge $e_i$ of |e| can be
|
|
obtained via |supp_halfedge(e,i)|. If $e$ is not supported by an edge
|
|
in $P_i$ then the mark of the input face can be obtained from
|
|
|m_below[i]|. Each supporting input edge $e_i$ of |e| changes
|
|
|m_below[i]| for the next output edge in the bundle iteration. If |e|
|
|
is not supported by an edge in $P_i$ then the supporting face
|
|
determines the mark of |e| and the two |incident_mark| entries. The
|
|
invariant for all edges $e$ in the iteration below is: if $e$ is not
|
|
supported by an edge $e_i$ of $P_i$ then |m_below[i]| contains the
|
|
mark of the face supporting $e$ in $P_i$.
|
|
<<handle all forward oriented edges starting in v>>=
|
|
if ( is_isolated(v) ) continue;
|
|
Halfedge_around_vertex_circulator
|
|
e(first_out_edge(v)), hend(e);
|
|
CGAL_For_all(e,hend) {
|
|
if ( is_forward(e) ) {
|
|
TRACEN(" halfedge "<<PE(e));
|
|
Halfedge_const_handle ei;
|
|
bool supported;
|
|
for (int i=0; i<2; ++i) {
|
|
supported = ( supp_halfedge(e,i) != Halfedge_const_handle() );
|
|
if ( supported ) {
|
|
ei = supp_halfedge(e,i);
|
|
TRACEN(" supp halfedge "<<i<<" "<<PE(ei));
|
|
incident_mark(twin(e),i) =
|
|
PI[i].mark(PI[i].face(PI[i].twin(ei)));
|
|
mark(e,i) = PI[i].mark(ei);
|
|
incident_mark(e,i) = m_below[i] =
|
|
PI[i].mark(PI[i].face(ei));
|
|
} else { // no support from input PI[i]
|
|
incident_mark(twin(e),i) = mark(e,i) = incident_mark(e,i) =
|
|
m_below[i];
|
|
}
|
|
}
|
|
} else break;
|
|
}
|
|
|
|
@ The last chunk of this section transfers the support marks to the
|
|
face object. For all bounded faces $f$ we just transfer the marks from
|
|
the bounding face cycle to the face. As all edges $e$ carry the
|
|
|incident_mark(e,i)| attribute this completes the structure.
|
|
<<transfer the marks to face objects>>=
|
|
for (f = ++faces_begin(); f != faces_end(); ++f) { // skip first face
|
|
assoc_info(f);
|
|
for (i=0; i<2; ++i) mark(f,i) = incident_mark(halfedge(f),i);
|
|
}
|
|
|
|
@ We can now summarize the calculated overlay properties. We
|
|
anticipate the costs of face creation as described in the next section
|
|
and the analysis of the sweep description in Lemma \ref{generic
|
|
segment sweep runtime}.
|
|
\begin{lemma}
|
|
Assume that $P_0$ and $P_1$ are plane maps whose embedding is
|
|
order-preserving and the adjacency lists have a forward prefix, then
|
|
$|subdivide|(P_0, P_1)$ constructs in $P = (V,E,F)$ the overlay plane
|
|
map of $P_0$ and $P_1$ and each object $u \in V \cup E \cup F$ carries
|
|
the mark information |mark(u,i)| from the corresponding supporting
|
|
object of the input plane map.
|
|
|
|
Let $n_i$ be the size of $P_i$ and $n$ be the size of $P$. Then the
|
|
running time of the overlay process is dominated by the plane sweep of the
|
|
skeleton objects of $P_0$ and $P_1$ and is therefore $O((n_0+n_1+n)
|
|
\log (n_0+n_1+n))$.
|
|
\end{lemma}
|
|
|
|
|
|
@ \subsection{Creating face objects}\label{creating face objects}
|
|
|
|
Input to this section is the 1-skeleton of a plane map $P' = (V,E)$
|
|
whose embedding is \emph{order-preserving} and whose adjacency lists
|
|
have a \emph{forward-prefix}. The objective of this section is to
|
|
\emph{create the face objects} that complete $P'$. The correct output
|
|
structure $P = (V,E,F)$ of this section is a plane map with the
|
|
property that there are face objects $f$ in $F$ corresponding to
|
|
maximal connected point sets that are a result of the partitioning of
|
|
the plane by the 1-skeleton $P'$. All faces are defined via their
|
|
bounding face cycles. Each face object has one halfedge link into the
|
|
one unique outer face cycle (if existing), a list of halfedges each of
|
|
which represents interior hole face cycles and a list of isolated
|
|
vertices that represent trivial face cycles. To assign face cycles to
|
|
face objects we need to know two properties of the plane map skeleton:
|
|
\begin{itemize} \parsep0ex plus 0.0ex minus 1.0ex%
|
|
\itemsep0ex\topsep-0.5ex%
|
|
\item for each face cycle we need to know if it is an outer face cycle
|
|
or a hole face cycle.
|
|
\item for two face cycles |fc1| and |fc2| we need to know if we can
|
|
connect them by a path in the plane which does not cross any other
|
|
face cycle.
|
|
\end{itemize}
|
|
|
|
We adapt an idea from \cite{mmmo:CG}. The path connectivity making
|
|
disjoint face cycles bounding the same face, can be modeled by a
|
|
vertical visibility graph of the minimal vertices\footnote{minimal
|
|
with respect to the lexicographic order of the point coordinates of
|
|
their embedding} of each face cycle. We create faces and assign face
|
|
cycles based on this property and transfer $P'$ to $P$ thereby.
|
|
|
|
Let $C$ be a set of face cycles of the plane map skeleton. For each
|
|
face cycle |c| let |MinimalHalfedge[c]| be the halfedge |e| whose
|
|
target vertex has minimal coordinates (lexicographically). Let
|
|
|FaceCycle[e]| be the face cycle containing |e|. We examine the
|
|
following implicitly defined graph $G$. Each face cycle of $P'$ is a
|
|
node of $G$. Let us link two face cycles $c_1$ and $c_2$ by an
|
|
undirected edge of $G$ if $|target|(|MinimalHalfedge|[c_1])$ has a
|
|
vertical view down to an edge of $c_2$ (in $P$). Note that face cycles
|
|
consist of halfedges and thus we have to refer to the correct one of
|
|
the two paired halfedges respecting the embedding when looking at face
|
|
cycles (our faces are left of the directed halfedges, thus consider
|
|
the bidirected twins to be separated by an infinitesimal distance,
|
|
then the visibility is uniquely defined). Note that the embedding of a
|
|
face cycle $c$ at its minimal halfedge gives us the criterion to
|
|
separate outer face cycles and hole face cycles. Whenever the
|
|
underlying line segments of $e = |MinimalHalfedge[c]|$ and |next(e)|
|
|
form a left turn |c| is an outer face cycle. When they form a right
|
|
turn the vertex |target(e)| has a free view down and thus |e| belongs
|
|
to a hole.
|
|
|
|
Note that we do not explicitly model the visibility graph. Instead the
|
|
recursive behavior of the operation |determine_face()| used below
|
|
imitates a DFS walk on the visibility graph. In the following method
|
|
we have the vertical visibility coded via a data accessor $D$
|
|
providing for all vertices $v \in V$ the knowledge about the halfedge
|
|
below $v$. |D.halfedge_below(v)| either provides the halfedge of $E$
|
|
that is hit first by a vertical ray downwards or an uninitialized
|
|
halfedge if there is none.
|
|
|
|
\displayeps{facecycles}{Face cycles bounding a face. c1 is the outer
|
|
face cycle, c2, c3, and c4 are hole cycles, c5 is an isolated vertex.
|
|
The minimal vertices of each face cycle are the origins of the dashed
|
|
vertical arrows down.}{8cm}
|
|
|
|
The following template type parameter |Below_info| has to fit the
|
|
concept |Below_info| of the Figures \figref{PMO_from_segs} and
|
|
\figref{PMO_from_pm}.
|
|
<<helping operations>>=
|
|
template <typename Below_info>
|
|
void create_face_objects(const Below_info& D) const
|
|
{
|
|
TRACEN("create_face_objects()");
|
|
CGAL::Unique_hash_map<Halfedge_handle,int> FaceCycle(-1);
|
|
std::vector<Halfedge_handle> MinimalHalfedge;
|
|
<<link halfedges to face cycles and determine minimal halfedges>>
|
|
<<create face objects for outer face cycles and create links>>
|
|
<<link holes and isolated vertices to face objects>>
|
|
}
|
|
|
|
@ We iterate over all halfedges and assign a number for each face
|
|
cycle. After the iteration for a halfedge |e| the number of its face
|
|
cycle is |FaceCycle[e]| and for a face cycle |c| we know
|
|
|MinimalHalfedge[c]|.
|
|
<<link halfedges to face cycles and determine minimal halfedges>>=
|
|
int i=0;
|
|
Halfedge_iterator e, eend = halfedges_end();
|
|
for (e=halfedges_begin(); e != eend; ++e) {
|
|
if ( FaceCycle[e] >= 0 ) continue; // already assigned
|
|
Halfedge_around_face_circulator hfc(e),hend(hfc);
|
|
Halfedge_handle e_min = e;
|
|
TRACE("face cycle "<<i<<"\n");
|
|
CGAL_For_all(hfc,hend) {
|
|
FaceCycle[hfc]=i; // assign face cycle number
|
|
if ( K.compare_xy(point(target(hfc)), point(target(e_min))) < 0 )
|
|
e_min = hfc;
|
|
TRACE(PE(hfc));
|
|
}
|
|
TRACEN("");
|
|
MinimalHalfedge.push_back(e_min); ++i;
|
|
}
|
|
|
|
@ We now know the number of face cycles |i| and we have a minimal
|
|
halfedge |e| for each face cycle. We just check the geometric
|
|
embedding of |e| and |next(e)| to characterize the face cycle (outer
|
|
or hole). Note that the two edges cannot be collinear due to the
|
|
minimality of |e| (the lexicographic minimality of the embedding of
|
|
its target vertex). Outer face cycles obtain face objects right away.
|
|
Hole cycles whose |halfedge_below| information is undefined are
|
|
associated with the unique outer face. After this chunk, |f_outer| is
|
|
the first face object |faces_begin()| in the list of all face objects,
|
|
and all outer face cycles have face objects with temporary mark
|
|
information slots expanded.
|
|
<<create face objects for outer face cycles and create links>>=
|
|
Face_handle f_outer = new_face();
|
|
for (int j=0; j<i; ++j) {
|
|
Halfedge_handle e = MinimalHalfedge[j];
|
|
TRACEN(" face cycle "<<j);TRACEN(" minimal halfedge "<<PE(e));
|
|
Point p1 = point(source(e)),
|
|
p2 = point(target(e)),
|
|
p3 = point(target(next(e)));
|
|
if ( K.left_turn(p1,p2,p3) ) { // left_turn => outer face cycle
|
|
TRACEN(" creating new face object");
|
|
Face_handle f = new_face();
|
|
link_as_outer_face_cycle(f,e);
|
|
}
|
|
}
|
|
|
|
@ Now, the only halfedges not linked are those on hole face cycles.
|
|
We use a recursive scheme to find the bounding cycle providing the
|
|
face object and finally iterate over all isolated vertices to link
|
|
them accordingly to their containing face object. Note that in this
|
|
final iteration all halfedges already have face links. This ensures
|
|
termination. The recursive operation $|determine_face|(e,\ldots)$
|
|
returns the face containing the hole cycle of |e| (see the
|
|
specification in the next section). As a postcondition of this chunk
|
|
we have all edges and isolated vertices linked to face objects, and
|
|
all face objects know their bounding face cycles.
|
|
<<link holes and isolated vertices to face objects>>=
|
|
for (e = halfedges_begin(); e != eend; ++e) {
|
|
if ( face(e) != Face_handle() ) continue;
|
|
TRACEN("linking hole "<<PE(e));
|
|
Face_handle f = determine_face(e,MinimalHalfedge,FaceCycle,D);
|
|
link_as_hole(f,e);
|
|
}
|
|
Vertex_iterator v, v_end = vertices_end();
|
|
for (v = vertices_begin(); v != v_end; ++v) {
|
|
if ( !is_isolated(v) ) continue;
|
|
Halfedge_handle e_below = D.halfedge_below(v);
|
|
if ( e_below == Halfedge_handle() )
|
|
link_as_isolated_vertex(f_outer,v);
|
|
else
|
|
link_as_isolated_vertex(face(e_below),v);
|
|
}
|
|
|
|
@ When we call |determine_face|$(e,\ldots)$ we know that the halfedge
|
|
|e| is not yet linked to a face object and thus, no halfedge in its
|
|
face cycle is linked. Thus we jump to the minimal halfedge and look
|
|
down. If we see nirvana then we have to link the unlimited face
|
|
|f_outer|. If we see a halfedge we ask for its face. If it does not
|
|
have one we recur. Note that the target vertex of the minimal
|
|
halfedge actually has a view downwards as we examine a hole face
|
|
cycle. The method |link_as_hole| does the linkage between the face
|
|
object and all edges of the face cycle. Its cost is linear in the size
|
|
of the face cycle. Note also that we do the linking bottom up along
|
|
the recursion stack for all visited hole cycles. Thus, we visit each
|
|
hole face cycle only once as afterwards each edge of the face cycle is
|
|
incident to a face.
|
|
|
|
Look at our example in Figure \figref{facecycles}. When
|
|
|determine_face| is called for an edge |e| of face cycle |c3|, then
|
|
the procedure first finds an edge of |c4|. If |c4| was not visited yet
|
|
by an earlier call, then the method recurs to |c4| before it finds the
|
|
correct face object via the outer face cycle |c1|.
|
|
<<helping operations>>=
|
|
template <typename Below_info>
|
|
Face_handle determine_face(Halfedge_handle e,
|
|
const std::vector<Halfedge_handle>& MinimalHalfedge,
|
|
const CGAL::Unique_hash_map<Halfedge_handle,int>& FaceCycle,
|
|
const Below_info& D) const
|
|
{ TRACEN("determine_face "<<PE(e));
|
|
Halfedge_handle e_min = MinimalHalfedge[FaceCycle[e]];
|
|
Halfedge_handle e_below = D.halfedge_below(target(e_min));
|
|
if ( e_below == Halfedge_handle() ) // below is nirwana
|
|
return faces_begin();
|
|
Face_handle f = face(e_below);
|
|
if (f != Face_handle()) return f; // has face already
|
|
f = determine_face(e_below, MinimalHalfedge, FaceCycle,D);
|
|
link_as_hole(f,e_below);
|
|
return f;
|
|
}
|
|
|
|
@ The explanations of the recursion condition of |determine_face| should
|
|
convince you that:
|
|
\begin{lemma}
|
|
Assume that $P'$ is the 1-skeleton of a plane map whose embedding is
|
|
order-preserving and the adjacency lists have a forward prefix. Let
|
|
additionally all vertices know the halfedge visible along a vertical
|
|
ray shot down, then |create_face_objects()| completes |P| as a plane
|
|
map with running time \emph{linear} in the size of the 1-skeleton
|
|
|P'|.
|
|
\end{lemma}
|
|
|
|
|
|
@ \subsection{Selecting marks}
|
|
|
|
For the selection we just iterate over all objects, read the marks
|
|
refering to the two input structures, apply our selection operation,
|
|
and store the mark back into the object. At this place, we discard the
|
|
additional information that was accumulated during the subdivision.
|
|
The flexibility of the operation is achieved by a template type
|
|
parameter |Selection|. An object |predicate| of type |Selection| must
|
|
provide a binary function operator returning a new mark object. The
|
|
running time of the selection phase is obviously linear in the size of
|
|
the plane map |P|. The method |discard_info| just discards the
|
|
temporarily allocated information containers associated with the
|
|
objects.
|
|
<<selection>>=
|
|
|
|
template <typename Selection>
|
|
void select(Selection& predicate) const
|
|
/*{\Mop sets the marks of all objects according to the selection
|
|
predicate |predicate|. |Selection| has to be a function object type
|
|
with a function operator\\ [[Mark operator()(Mark m0, Mark m1)]]\\ For
|
|
each object |u| of |P| enriched by the marks of the supporting objects
|
|
according to the previous procedure |subdivide|, after this operation
|
|
|\Mvar.mark(u) = predicate ( \Mvar.mark(u,0),\Mvar.mark(u,1) )|. The
|
|
additional marks are invalidated afterwards. }*/
|
|
{
|
|
Vertex_iterator vit = vertices_begin(),
|
|
vend = vertices_end();
|
|
for( ; vit != vend; ++vit) {
|
|
mark(vit) = predicate(mark(vit,0),mark(vit,1));
|
|
discard_info(vit);
|
|
}
|
|
Halfedge_iterator hit = halfedges_begin(),
|
|
hend = halfedges_end();
|
|
for(; hit != hend; ++(++hit)) {
|
|
mark(hit) = predicate(mark(hit,0),mark(hit,1));
|
|
discard_info(hit);
|
|
}
|
|
Face_iterator fit = faces_begin(),
|
|
fend = faces_end();
|
|
for(; fit != fend; ++fit) {
|
|
mark(fit) = predicate(mark(fit,0),mark(fit,1));
|
|
discard_info(fit);
|
|
}
|
|
}
|
|
|
|
@ Note that after this phase the plane map output has again the input
|
|
properties of the overlay calculation operation from Section
|
|
\ref{Overlay calculation of two plane maps}.
|
|
\begin{lemma}\label{cost of selection}
|
|
The selection phase has running time linear in the size of the plane
|
|
map.
|
|
\end{lemma}
|
|
|
|
@ \subsection{Simplification of attributed plane maps}
|
|
|
|
\displaylps{simplification}{The possible configurations for
|
|
simplification.}
|
|
|
|
In this section we examine the task of simplifying a given plane map
|
|
to reach a minimimal representation (minimimal number of objects of
|
|
the plane map structure, while the underlying attributed point set
|
|
stays the same). There are three situations where one can imagine to
|
|
simplify the structure (see Figure \figref{simplification}):
|
|
\begin{enumerate}\label{simplification criteria}
|
|
\item A vertex $v$ that is incident to two edges $e_1$, $e_2$ both
|
|
supported by the same line where all three objects have the same mark
|
|
can be unified into one edge without changing the stored point set.
|
|
(Figure \figref{simplification},A)
|
|
\item A uedge $e$ that has the same mark as the two faces $f_1$ and
|
|
$f_2$ incident to it does not contribute any structural information
|
|
and thus can be removed (Figure \figref{simplification},B).
|
|
\item A vertex $v$ where all the edges of its adjacency list and also
|
|
all incident faces have the same mark as the vertex also carries no
|
|
structural information (Figure \figref{simplification},C,D).
|
|
\end{enumerate}
|
|
|
|
\begin{onlyindiss}
|
|
Note that the simplification configurations map to the properties of
|
|
the local views of Nef faces in Lemma \ref{local view properties}.
|
|
\end{onlyindiss}
|
|
If we first remove edges of the second case then the vertices of case
|
|
three have no incident edges at all and thus can be easily identified
|
|
as isolated vertices whose surounding face has the same mark. The
|
|
first case plays a role only if one of the faces incident to the edge
|
|
carries a different mark than the edge.
|
|
|
|
We can thus easily formulate the simplification routine. However,
|
|
there are some problems with the update operations of the plane map
|
|
structure. How can we maintain the face objects and incidence links to
|
|
halfedges and vertices if we are unifying faces by deleting edges? The
|
|
trivial way does not work within our time bound. We cannot afford to
|
|
maintain the face objects in a correct status in each step of the
|
|
simplification, as this would mean repeatedly iterating over face
|
|
cycles.
|
|
|
|
Note that we cannot just discard all faces and recreate them using a
|
|
similar scheme as the one based on the |halfedge_below| information
|
|
due to the fact that referenced edges might be deleted in the
|
|
simplification process. Thereby, face creation as described in
|
|
Section \ref{creating face objects} is not possible without a new
|
|
sweep. We take a different approach. We use a unification history
|
|
stored in a partition data structure instead of the geometrically
|
|
defined |halfedge_below| information as a criterium for linking face
|
|
cycles to face objects.
|
|
|
|
All face cycles (edges and isolated vertices) reference face
|
|
objects. When we have to unify two different faces due to the deletion
|
|
of an edge separating them, we store this fact by a union operation in
|
|
a partition data structure. The face that is finally assigned to all
|
|
the face cycles of the faces in one block is the one associated with
|
|
the canonical item of the block (obtained by the find operation).
|
|
<<simplification>>=
|
|
|
|
template <typename Keep_edge>
|
|
void simplify(const Keep_edge& keep) const
|
|
/*{\Mop simplifies the structure of |P| according to the marks of
|
|
its objects. An edge |e| separating two faces |f1| and |f2| and equal
|
|
marks |mark(e) == mark(f1) == mark(f2)| is removed and the faces are
|
|
unified. An isolated vertex |v| in a face |f| with |mark(v)==mark(f)|
|
|
is removed. A vertex |v| with outdegree two, two collinear out-edges
|
|
|e1|,|e2| and equal marks |mark(v) == mark(e1) == mark(e2)| is removed
|
|
and the edges are unified. The data accessor |keep| requires the function
|
|
call operator\\[[bool operator()(Halfedge_handle e)]]\\that allows to
|
|
avoid the simplification for edge pairs referenced by |e|.}*/
|
|
{
|
|
TRACEN("simplifying");
|
|
typedef typename CGAL::Partition<Face_handle>::item partition_item;
|
|
CGAL::Unique_hash_map<Face_iterator,partition_item> Pitem;
|
|
CGAL::Partition<Face_handle> FP;
|
|
|
|
<<initialize blocks corresponding to faces>>
|
|
<<simplify via non-separating halfedges>>
|
|
<<recollect face cycles per blocks>>
|
|
<<simplify via vertices>>
|
|
<<remove superflous face objects>>
|
|
}
|
|
|
|
@ We assign one partition item to each face object and make the item
|
|
accessible to the face via a hash map. During the assignment of face
|
|
cycles to face objects we will only use links from skeleton objects
|
|
like vertices and edges to faces. We therefore can discard all face
|
|
cycle entries in the faces (the links from face objects to skeleton
|
|
objects).
|
|
<<initialize blocks corresponding to faces>>=
|
|
Face_iterator f, fend = faces_end();
|
|
for (f = faces_begin(); f!= fend; ++f) {
|
|
Pitem[f] = FP.make_block(f);
|
|
clear_face_cycle_entries(f);
|
|
}
|
|
|
|
|
|
@ Now we take care of the simplification critereon (2.) of page
|
|
\pageref{simplification criteria}. We iterate over halfedge pairs
|
|
(uedges) only. When the marks of the incident faces agree with the
|
|
mark of the uedge, we union the items of the faces if they are
|
|
different. Special treatment is required for incident vertices if they
|
|
become isolated when their last incident uedge is deleted.
|
|
<<simplify via non-separating halfedges>>=
|
|
Halfedge_iterator e = halfedges_begin(), en,
|
|
eend = halfedges_end();
|
|
for(; en=e, ++(++en), e != eend; e=en) {
|
|
if ( keep(e) ) continue;
|
|
if ( mark(e) == mark(face(e)) &&
|
|
mark(e) == mark(face(twin(e))) ) {
|
|
TRACEN("deleting "<<PE(e));
|
|
if ( !FP.same_block(Pitem[face(e)],
|
|
Pitem[face(twin(e))]) ) {
|
|
FP.union_blocks( Pitem[face(e)],
|
|
Pitem[face(twin(e))] );
|
|
TRACEN("unioning disjoint faces");
|
|
}
|
|
if ( is_closed_at_source(e) ) set_face(source(e),face(e));
|
|
if ( is_closed_at_source(twin(e)) ) set_face(target(e),face(e));
|
|
delete_halfedge_pair(e);
|
|
}
|
|
}
|
|
|
|
@ Now we recollect all face cycles and assign them to the face object
|
|
|f| that refers to the partition item obtained by a find operation. In
|
|
each face cycle we determine the halfedge |e_min| whose target has a
|
|
minimal embedding (with respect to the lexicographic order on
|
|
points). If |e_min| and |next(e_min)| form a left turn, they are part
|
|
of an outer face cycle, otherwise they are part of a hole face
|
|
cycle. We associate all edges in the face cycle with |f|.
|
|
<<recollect face cycles per blocks>>=
|
|
CGAL::Unique_hash_map<Halfedge_handle,bool> linked(false);
|
|
for (e = halfedges_begin(); e != eend; ++e) {
|
|
if ( linked[e] ) continue;
|
|
Halfedge_around_face_circulator hfc(e),hend(hfc);
|
|
Halfedge_handle e_min = e;
|
|
Face_handle f = FP.inf(FP.find(Pitem[face(e)]));
|
|
CGAL_For_all(hfc,hend) {
|
|
set_face(hfc,f);
|
|
if ( K.compare_xy(point(target(hfc)), point(target(e_min))) < 0 )
|
|
e_min = hfc;
|
|
linked[hfc]=true;
|
|
}
|
|
Point p1 = point(source(e_min)),
|
|
p2 = point(target(e_min)),
|
|
p3 = point(target(next(e_min)));
|
|
if ( K.orientation(p1,p2,p3) > 0 ) set_halfedge(f,e_min); // outer
|
|
else set_hole(f,e_min); // store as inner
|
|
}
|
|
|
|
|
|
@ After the previous simplification we still have to take care of the
|
|
vertex-related simplifications (1.) and (3.). In the case that a
|
|
vertex has out-degree two, that the two incident edges are embedded
|
|
collinearly, and that all three objects have the same mark, we remove
|
|
the vertex by joining the two uedges into one. In case that a vertex
|
|
is isolated and its mark agrees with the incident face we remove the
|
|
vertex. Otherwise, we anchor the vertex in the face by adding it to
|
|
the isolated vertex list. Note that the face link of each isolated
|
|
vertex was either already set in the face creation phase, or in the
|
|
chunk $\langle$\textit{simplify via non-separating halfedges}$\rangle$
|
|
when the last incident edge was deleted.
|
|
<<simplify via vertices>>=
|
|
Vertex_iterator v, vn, vend = vertices_end();
|
|
for(v = vertices_begin(); v != vend; v=vn) { TRACEN("at vertex "<<PV(v));
|
|
vn=v; ++vn;
|
|
if ( is_isolated(v) ) {
|
|
if ( mark(v) == mark(face(v)) ) delete_vertex_only(v);
|
|
else set_isolated_vertex(face(v),v);
|
|
} else { // v not isolated
|
|
Halfedge_handle e2 = first_out_edge(v), e1 = previous(e2);
|
|
Point p1 = point(source(e1)), p2 = point(v),
|
|
p3 = point(target(e2));
|
|
if ( has_outdeg_two(v) &&
|
|
mark(v) == mark(e1) && mark(v) == mark(e2) &&
|
|
(K.orientation(p1,p2,p3) == 0) )
|
|
merge_halfedge_pairs_at_target(e1);
|
|
}
|
|
}
|
|
|
|
@ Finally we discard all face objects that have been victims of
|
|
unification but do not represent the unified face.
|
|
<<remove superflous face objects>>=
|
|
Face_iterator fn;
|
|
for (f = faces_begin(); f != fend; f=fn) {
|
|
fn=f; ++fn;
|
|
partition_item pit = Pitem[f];
|
|
if ( FP.find(pit) != pit ) delete_face(f);
|
|
}
|
|
|
|
|
|
@ \begin{ignoreindiss}
|
|
The following operations just wrap some basic primitives which make
|
|
our code more readable.
|
|
<<helping operations>>=
|
|
Segment segment(const Const_decorator& N,
|
|
Halfedge_const_handle e) const
|
|
{ return K.construct_segment(
|
|
N.point(N.source(e)),N.point(N.target(e))); }
|
|
|
|
Segment segment(const Const_decorator& N,
|
|
Vertex_const_handle v) const
|
|
{ Point p = N.point(v);
|
|
return K.construct_segment(p,p); }
|
|
|
|
bool is_forward_edge(const Const_decorator& N,
|
|
Halfedge_const_iterator hit) const
|
|
{ Point p1 = N.point(N.source(hit));
|
|
Point p2 = N.point(N.target(hit));
|
|
return (K.compare_xy(p1,p2) < 0); }
|
|
|
|
@ \end{ignoreindiss}
|
|
The following analysis of the partition data structure is due
|
|
to Tarjan \cite{tarjan83}.
|
|
\begin{fact}
|
|
A sequence of $m$ union and find operations starting from $n$
|
|
singleton blocks can be done in time $O(m \alpha(m,n))$ with a
|
|
partition data structure that is based on union by rank and path
|
|
compression. In this time bound $\alpha$ is the very slowly growing
|
|
inverse of a suitably defined Ackermann function.
|
|
\end{fact}
|
|
|
|
We can therefore summarize the running time of the simplification
|
|
action.
|
|
\begin{lemma}
|
|
Assume that |P| is a plane map with the properties cited in the
|
|
introduction of this section. Then the method |simplify()| runs in
|
|
time $O(n\ \alpha(kn,n))$ where $n$ is the size of $P$, $kn$ is a
|
|
bound for the number of face unifications and find operations, and
|
|
$\alpha$ is the function mentioned above.
|
|
\end{lemma}
|
|
\begin{proof}
|
|
The number of edges and faces of $P$ is linear in $n$. The number of
|
|
union operations is bounded by the number of faces, and the number of
|
|
find operations is bounded by three times\footnote{look for the
|
|
|find()| and |same_block()| operations above. The latter uses two find
|
|
operations.} the number of edges plus the number of faces.
|
|
\end{proof}
|
|
Note that, after the simplification, the plane map output has again
|
|
the input properties of the overlay calculation operation from Section
|
|
\ref{Overlay calculation of two plane maps}.
|
|
\begin{ignoreindiss}
|
|
<<helping operations>>=
|
|
void assert_type_precondition() const
|
|
{ typename PM_decorator_::Point p1; Point p2;
|
|
assert_equal_types(p1,p2); }
|
|
|
|
|
|
<<PM_overlayer.h>>=
|
|
<<CGAL Header>>
|
|
#ifndef CGAL_PM_OVERLAYER_H
|
|
#define CGAL_PM_OVERLAYER_H
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Unique_hash_map.h>
|
|
#include <CGAL/Partition.h>
|
|
#include <CGAL/Nef_2/Segment_overlay_traits.h>
|
|
#include <CGAL/Nef_2/geninfo.h>
|
|
#undef _DEBUG
|
|
#define _DEBUG 13
|
|
#include <CGAL/Nef_2/debug.h>
|
|
|
|
#ifndef CGAL_USE_LEDA
|
|
#define LEDA_MEMORY(t)
|
|
#endif
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
<<PM traits classes for segment overlay>>
|
|
<<PM overlayer>>
|
|
|
|
CGAL_END_NAMESPACE
|
|
#endif // CGAL_PM_OVERLAYER_H
|
|
|
|
@ \section{Test snippets}
|
|
|
|
\subsection{A Demo of the overlayer}
|
|
|
|
<<PM_overlayer-demo.C>>=
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/leda_integer.h>
|
|
#include <CGAL/Homogeneous.h>
|
|
#include <CGAL/IO/Window_stream.h>
|
|
#include <CGAL/Nef_2/HalfedgeDS_default.h>
|
|
#include <CGAL/Nef_2/HDS_items.h>
|
|
#include <CGAL/Nef_2/PM_decorator.h>
|
|
#include <CGAL/Nef_2/PM_io_parser.h>
|
|
#include <CGAL/Nef_2/PM_overlayer.h>
|
|
#include <CGAL/Nef_2/PM_visualizor.h>
|
|
#include <CGAL/test_macros.h>
|
|
#include "Affine_geometry.h"
|
|
|
|
|
|
// GEOMETRY:
|
|
typedef CGAL::Homogeneous<leda_integer> Hom_kernel;
|
|
typedef CGAL::Affine_geometry<Hom_kernel> Aff_kernel;
|
|
typedef Aff_kernel::Segment_2 Segment;
|
|
|
|
// PLANE MAP:
|
|
struct HDS_traits {
|
|
typedef Aff_kernel::Point_2 Point;
|
|
typedef bool Mark;
|
|
};
|
|
|
|
typedef HalfedgeDS_default<HDS_traits,HDS_items> HDS;
|
|
typedef CGAL::PM_decorator< HDS > PM_dec;
|
|
typedef CGAL::PM_overlayer< PM_dec, Aff_kernel > PM_aff_overlayer;
|
|
typedef PM_dec::Halfedge_handle Halfedge_handle;
|
|
typedef PM_dec::Vertex_handle Vertex_handle;
|
|
|
|
// INPUT:
|
|
typedef std::list<Segment>::const_iterator Iterator;
|
|
|
|
struct Object_DA {
|
|
const PM_dec& D;
|
|
Object_DA(const PM_dec& Di) : D(Di) {}
|
|
void supporting_segment(Halfedge_handle e, Iterator it) const
|
|
{ D.mark(e) = true; }
|
|
void trivial_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void starting_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void passing_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void ending_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
};
|
|
|
|
|
|
struct BOP {
|
|
bool operator()(const bool& b1, const bool& b2) const
|
|
{ return b1||b2; }
|
|
};
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
SETDTHREAD(331);
|
|
CGAL::set_pretty_mode(cerr);
|
|
CGAL::Window_stream W;
|
|
W.init(-50,50,-50,1);
|
|
W.set_show_coordinates(true);
|
|
W.display();
|
|
HDS H[2], HO;
|
|
char C[2] = { '0','1' };
|
|
for (int i=0; i<2; ++i ) {
|
|
W.message("insert segments to construct a map.");
|
|
PM_aff_overlayer PMOV(H[i],Aff_kernel());
|
|
CGAL::PM_visualizor<PM_aff_overlayer,Aff_kernel> V(W,PMOV);
|
|
std::list<Segment> L;
|
|
Segment s;
|
|
std::string fname;
|
|
if ( argc == 2 ) {
|
|
fname = std::string(argv[1]);
|
|
fname += C[i];
|
|
std::ifstream log(fname.c_str());
|
|
while ( log >> s ) { L.push_back(s); W << s; }
|
|
}
|
|
while ( W >> s ) L.push_back(s);
|
|
fname = std::string(argv[0]);
|
|
fname += ".log";
|
|
fname += C[i];
|
|
std::ofstream log(fname.c_str());
|
|
for (Iterator sit = L.begin(); sit != L.end(); ++sit)
|
|
log << *sit << " ";
|
|
log.close();
|
|
Object_DA ODA(PMOV);
|
|
PMOV.create(L.begin(),L.end(),ODA);
|
|
CGAL::PM_io_parser<PM_aff_overlayer>::dump(PMOV);
|
|
V.draw_skeleton();
|
|
W.read_mouse();
|
|
W.clear();
|
|
}
|
|
PM_aff_overlayer PMOV(HO,Aff_kernel());
|
|
CGAL::PM_visualizor<PM_aff_overlayer,Aff_kernel> V(W,PMOV);
|
|
PMOV.subdivide(H[0],H[1]);
|
|
BOP bop;
|
|
PMOV.select(bop);
|
|
PMOV.simplify();
|
|
V.draw_skeleton();
|
|
CGAL::PM_io_parser<PM_aff_overlayer>::dump(PMOV);
|
|
W.read_mouse();
|
|
return 0;
|
|
}
|
|
|
|
@ \subsection{A Test of the overlayer}
|
|
|
|
<<PM_overlayer-test.C>>=
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/leda_integer.h>
|
|
#include <CGAL/Homogeneous.h>
|
|
#include <CGAL/IO/Window_stream.h>
|
|
#include <CGAL/Nef_2/HalfedgeDS_default.h>
|
|
#include <CGAL/Nef_2/HDS_items.h>
|
|
#include <CGAL/Nef_2/PM_decorator.h>
|
|
#include <CGAL/Nef_2/PM_io_parser.h>
|
|
#include <CGAL/Nef_2/PM_overlayer.h>
|
|
#include <CGAL/Nef_2/PM_visualizor.h>
|
|
#include <CGAL/test_macros.h>
|
|
#include "Affine_geometry.h"
|
|
|
|
// GEOMETRY:
|
|
typedef CGAL::Homogeneous<leda_integer> Hom_kernel;
|
|
typedef CGAL::Affine_geometry<Hom_kernel> Aff_kernel;
|
|
typedef Aff_kernel::Point_2 Point;
|
|
typedef Aff_kernel::Segment_2 Segment;
|
|
|
|
// PLANE MAP:
|
|
struct HDS_traits {
|
|
typedef Aff_kernel::Point_2 Point;
|
|
typedef bool Mark;
|
|
};
|
|
|
|
typedef CGAL::HalfedgeDS_default<HDS_traits,HDS_items> HDS;
|
|
typedef CGAL::PM_decorator< HDS > PM_dec;
|
|
typedef CGAL::PM_overlayer< PM_dec, Aff_kernel > PM_aff_overlayer;
|
|
typedef PM_dec::Halfedge_handle Halfedge_handle;
|
|
typedef PM_dec::Vertex_handle Vertex_handle;
|
|
|
|
// INPUT:
|
|
typedef std::list<Segment>::const_iterator Iterator;
|
|
|
|
struct Object_DA {
|
|
const PM_dec& D;
|
|
Object_DA(const PM_dec& Di) : D(Di) {}
|
|
void supporting_segment(Halfedge_handle e, Iterator it) const
|
|
{ D.mark(e) = true; }
|
|
void trivial_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void starting_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void passing_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
void ending_segment(Vertex_handle v, Iterator it) const
|
|
{ D.mark(v) = true; }
|
|
};
|
|
|
|
|
|
struct BOP {
|
|
bool operator()(const bool& b1, const bool& b2) const
|
|
{ return b1||b2; }
|
|
};
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
SETDTHREAD(131); // 13 = PM overlayer debug on
|
|
CGAL::set_pretty_mode(cerr);
|
|
CGAL_TEST_START;
|
|
|
|
//#define PMOVISUAL
|
|
#ifdef PMOVISUAL
|
|
CGAL::Window_stream W;
|
|
W.init(-50,50,-50,1);
|
|
W.set_show_coordinates(true);
|
|
W.display();
|
|
#endif
|
|
|
|
HDS H[2], HO, HOC;
|
|
std::list<Segment> L0,L1,L2;
|
|
L0.push_back(Segment(Point(-5,-5),Point(5,-5)));
|
|
L0.push_back(Segment(Point(5,-5),Point(5,5)));
|
|
L0.push_back(Segment(Point(5,5),Point(-5,5)));
|
|
L0.push_back(Segment(Point(-5,5),Point(-5,-5)));
|
|
L0.push_back(Segment(Point(0,0),Point(0,0)));
|
|
PM_aff_overlayer PMOV0(H[0],Aff_kernel());
|
|
Object_DA ODA0(PMOV0);
|
|
PMOV0.create(L0.begin(),L0.end(),ODA0);
|
|
//CGAL::PM_io_parser<PM_aff_overlayer>::dump(PMOV0);
|
|
|
|
L1.push_back(Segment(Point(-5,-5),Point(0,-5)));
|
|
L1.push_back(Segment(Point(0,-5),Point(0,0)));
|
|
L1.push_back(Segment(Point(0,0),Point(-5,0)));
|
|
L1.push_back(Segment(Point(-5,0),Point(-5,-5)));
|
|
L1.push_back(Segment(Point(-2,-2),Point(-2,-2)));
|
|
PM_aff_overlayer PMOV1(H[1],Aff_kernel());
|
|
Object_DA ODA1(PMOV1);
|
|
PMOV1.create(L1.begin(),L1.end(),ODA1);
|
|
//CGAL::PM_io_parser<PM_aff_overlayer>::dump(PMOV1);
|
|
|
|
PM_aff_overlayer PMOV(HO,Aff_kernel());
|
|
PMOV.subdivide(H[0],H[1]);
|
|
BOP bop;
|
|
PMOV.select(bop);
|
|
PMOV.simplify();
|
|
|
|
L2.insert(L2.end(),L0.begin(),L0.end());
|
|
L2.insert(L2.end(),L1.begin(),L1.end());
|
|
PM_aff_overlayer PMOV2(HOC,Aff_kernel());
|
|
Object_DA ODA2(PMOV2);
|
|
PMOV2.create(L2.begin(),L2.end(),ODA2);
|
|
CGAL_TEST(PMOV.number_of_vertices()==8);
|
|
CGAL_TEST(PMOV.number_of_edges()==8);
|
|
CGAL_TEST(PMOV.number_of_faces()==3);
|
|
#ifdef PMOVISUAL
|
|
CGAL::PM_visualizor<PM_aff_overlayer,Aff_kernel> V(W,PMOV);
|
|
CGAL::PM_io_parser<PM_aff_overlayer>::dump(PMOV);
|
|
V.draw_skeleton();
|
|
W.read_mouse();
|
|
#endif
|
|
CGAL_TEST_END;
|
|
return 0;
|
|
}
|
|
|
|
@ \begin{ignore}
|
|
<<CGAL Header>>=
|
|
// ============================================================================
|
|
//
|
|
// Copyright (c) 1997-2000 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// release : $CGAL_Revision$
|
|
// release_date : $CGAL_Date$
|
|
//
|
|
// file : include/CGAL/Nef_2/PM_overlayer.h
|
|
// package : Nef_2
|
|
// chapter : Nef Polyhedra
|
|
//
|
|
// source : nef_2d/PM_overlayer.lw
|
|
// revision : $Id$
|
|
// revision_date : $Date$
|
|
//
|
|
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
|
//
|
|
// implementation: Overlay module for plane maps
|
|
// ============================================================================
|
|
|
|
@ \end{ignore}
|
|
\end{ignoreindiss}
|
|
%KILLSTART DISS REP
|
|
\bibliographystyle{alpha}
|
|
\bibliography{diss,general,geo_mod,comp_geo}
|
|
\newpage
|
|
\section{Appendix}
|
|
\input manpages/OverlayerGeometry_2.man
|
|
\input manpages/PMConstDecorator.man
|
|
\input manpages/PMDecorator.man
|
|
\input manpages/geninfo.man
|
|
\end{document}
|
|
%KILLEND DISS REP
|