%------------------------------------------------------------------------------ %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. <>= /*{\Moptions print_title=yes }*/ /*{\Msubst PM_decorator_#PMD Geometry_#GEO }*/ /*{\Manpage {PM_overlayer}{PMD,GEO}{Plane Map Overlay}{O}}*/ template class PM_overlayer : public PM_decorator_ { typedef PM_decorator_ Base; typedef PM_overlayer 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.}*/ <> <> /*{\Mcreation 6}*/ PM_overlayer(Plane_map& P, const Geometry& g = Geometry()) : /*{\Mcreate |\Mvar| is a decorator object manipulating |P|.}*/ Base(P), K(g) {} <> <> <> <> }; // PM_overlayer @ \begin{ignoreindiss} <>= #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... >> @ 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} <>= template 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 @ 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|. For more information see that manual page in the appendix. <>= Vertex_handle new_vertex(const Point& p) { Vertex_handle v = G.new_vertex(p); geninfo::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. <>= 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::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}. <>= Halfedge_handle halfedge_below(Vertex_handle v) const { return geninfo::access(G.info(v)); } @ We finally add a clean up operation discarding the temporary storage. <>= void clear_temporary_vertex_info() const { Vertex_handle v; for(v = G.vertices_begin(); v!= G.vertices_end(); ++v) geninfo::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. <>= template 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 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} <>= 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); <> <> <> } @ \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} <>= 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} <>= typedef std::list Seg_list; typedef typename Seg_list::const_iterator Seg_iterator; typedef std::pair 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. <>= Seg_list Segments; int i; CGAL::Unique_hash_map 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|. 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$. <>= 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::create(info(v)); } void discard_info(Vertex_handle v) const { geninfo::clear(info(v)); } vertex_info& ginfo(Vertex_handle v) const { return geninfo::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). <>= 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::create(info(e)); geninfo::create(info(twin(e))); } void discard_info(Halfedge_handle e) const { geninfo::clear(info(e)); geninfo::clear(info(twin(e))); } halfedge_info& ginfo(Halfedge_handle e) const { return geninfo::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|. <>= 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::create(info(f)); } void discard_info(Face_handle f) const { geninfo::clear(info(f)); } face_info& ginfo(Face_handle f) const { return geninfo::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. <>= 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::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|. <>= template struct PMO_from_pm { <> const Decorator& G; const Const_decorator* pGI[2]; CGAL::Unique_hash_map& M; PMO_from_pm(const Decorator& Gi, const Const_decorator* pG0, const Const_decorator* pG1, CGAL::Unique_hash_map& Mi) : G(Gi),M(Mi) { pGI[0]=pG0; pGI[1]=pG1; } <> <> <> <> }; // PMO_from_pm <>= 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|. <>= 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()|. <>= 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. <>= 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. <>= 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|. <>= 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. <>= typedef PMO_from_pm 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} <>= TRACEN("transfering marks"); <> Vertex_iterator v, vend = vertices_end(); for (v = vertices_begin(); v != vend; ++v) { TRACEN("mark at "<> <> <> } <> @ 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. <>= 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. <>= 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. <>= 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$. <>= 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 "<>= 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}. <>= template void create_face_objects(const Below_info& D) const { TRACEN("create_face_objects()"); CGAL::Unique_hash_map FaceCycle(-1); std::vector MinimalHalfedge; <> <> <> } @ 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]|. <>= 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 "<>= Face_handle f_outer = new_face(); for (int j=0; j 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. <>= for (e = halfedges_begin(); e != eend; ++e) { if ( face(e) != Face_handle() ) continue; TRACEN("linking hole "<>= template Face_handle determine_face(Halfedge_handle e, const std::vector& MinimalHalfedge, const CGAL::Unique_hash_map& FaceCycle, const Below_info& D) const { TRACEN("determine_face "<>= template 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). <>= template 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::item partition_item; CGAL::Unique_hash_map Pitem; CGAL::Partition FP; <> <> <> <> <> } @ 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). <>= 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. <>= 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 "<>= CGAL::Unique_hash_map 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. <>= Vertex_iterator v, vn, vend = vertices_end(); for(v = vertices_begin(); v != vend; v=vn) { TRACEN("at vertex "<>= 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. <>= 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} <>= void assert_type_precondition() const { typename PM_decorator_::Point p1; Point p2; assert_equal_types(p1,p2); } <>= <> #ifndef CGAL_PM_OVERLAYER_H #define CGAL_PM_OVERLAYER_H #include #include #include #include #include #undef _DEBUG #define _DEBUG 13 #include #ifndef CGAL_USE_LEDA #define LEDA_MEMORY(t) #endif CGAL_BEGIN_NAMESPACE <> <> CGAL_END_NAMESPACE #endif // CGAL_PM_OVERLAYER_H @ \section{Test snippets} \subsection{A Demo of the overlayer} <>= #include #include #include #include #include #include #include #include #include #include #include #include "Affine_geometry.h" // GEOMETRY: typedef CGAL::Homogeneous Hom_kernel; typedef CGAL::Affine_geometry 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; 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::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 V(W,PMOV); std::list 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::dump(PMOV); V.draw_skeleton(); W.read_mouse(); W.clear(); } PM_aff_overlayer PMOV(HO,Aff_kernel()); CGAL::PM_visualizor V(W,PMOV); PMOV.subdivide(H[0],H[1]); BOP bop; PMOV.select(bop); PMOV.simplify(); V.draw_skeleton(); CGAL::PM_io_parser::dump(PMOV); W.read_mouse(); return 0; } @ \subsection{A Test of the overlayer} <>= #include #include #include #include #include #include #include #include #include #include #include #include "Affine_geometry.h" // GEOMETRY: typedef CGAL::Homogeneous Hom_kernel; typedef CGAL::Affine_geometry 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; 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::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 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::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::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 V(W,PMOV); CGAL::PM_io_parser::dump(PMOV); V.draw_skeleton(); W.read_mouse(); #endif CGAL_TEST_END; return 0; } @ \begin{ignore} <>= // ============================================================================ // // 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 // maintainer : Michael Seel // coordinator : Michael Seel // // 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