From b8817aa69c0a5c97b7277bdfa8c96e839c4cf487 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 9 Feb 2012 16:20:43 +0000 Subject: [PATCH] Replaced Object --- .../Arrangement_on_surface_2/arr_queries.tex | 423 +++++++++--------- 1 file changed, 210 insertions(+), 213 deletions(-) diff --git a/Arrangement_on_surface_2/doc_tex/Arrangement_on_surface_2/arr_queries.tex b/Arrangement_on_surface_2/doc_tex/Arrangement_on_surface_2/arr_queries.tex index be4fc18d154..0ed6e7a1609 100644 --- a/Arrangement_on_surface_2/doc_tex/Arrangement_on_surface_2/arr_queries.tex +++ b/Arrangement_on_surface_2/doc_tex/Arrangement_on_surface_2/arr_queries.tex @@ -1,195 +1,209 @@ \section{Issuing Queries on an Arrangement\label{arr_sec:queries}} -%========================================== - +% ============================================================================== One of the most important query types defined on arrangements is -the {\em point-location} query: Given a point, find the -arrangement cell that contains it. Typically, the result of a -point-location query is one of the arrangement faces, but in -degenerate situations the query point can be located on an edge or -coincide with a vertex. +the \emph{point-location} query: Given a point, find the arrangement +cell that contains it. Typically, the result of a point-location +query is one of the arrangement faces, but in degenerate situations +the query point can be located on an edge or it may coincide with a +vertex. -Point-location queries are not only common in many applications, -they also play an important role in the free insertion-functions -(see Section~\ref{arr_sec:gl_funcs}). Therefore, it is crucial to -have the ability to answer such queries effectively for any -arrangement instance. +Point-location queries are common in many applications, and also +play an important role in the incremental construction of arrangements +(and more specifically in the free insertion-functions described in +Section~\ref{arr_sec:gl_funcs}). Therefore, it is crucial to have the +ability to answer such queries effectively. \subsection{Point-Location Queries\label{arr_ssec:pl}} -%---------------------------------- +% ------------------------------------------------------------------------------ +The \ccc{Arrangement_2} class template does not support point-location +queries directly, as the arrangement representation is decoupled from +the geometric algorithms that operate on it. The \emph{2D Arrangements} +package includes a set of classe templates that are capable of +answering such queries; all are models of the concept +\ccc{ArrangementPointLocation_2}. Each model employs a different +algorithm or \emph{strategy} for answering queries. A model of this +concept must define the \ccc{locate()} member function, which accepts an +input query-point and returns a polymorphic object representing the +arrangement cell that contains this point. The returned object, which is +of type \ccc{CGAL::Object}, can be assigned to a \ccc{Face_const_handle}, +a \ccc{Halfedge_const_handle}, or a \ccc{Vertex_const_handle}, depending +on whether the query point is located inside a face, on an edge, or on a +vertex. -The arrangement package includes several classes (more precisely, -class templates parameterized by an arrangement class) that model -the \ccc{ArrangementPointLocation_2} concept. Namely, they all -have a member function called \ccc{locate(q)} that accepts a query -point $q$ and result with a \cgal\ \ccc{Object} that wraps a handle -to the arrangement cell containing the query point. This object can -be assigned to either a \ccc{Face_const_handle}, -\ccc{Halfedge_const_handle} or a \ccc{Vertex_const_handle}, depending -on whether the query point is located inside a face, on an edge or -on a vertex. +Note that the handles returned by the \ccc{locate()} functionss are +non-mutable (\ccc{const}). If necessary, such handles may +be cast to mutable handles using the \ccc{non_const_handle()} methods +\ccc{Arrangement_2::non_const_handle()} provided by the +\ccc{Arrangement_2} class. -Note that the handles returned by the \ccc{locate()} functions are -\ccc{const} (non-mutable) handles. If necessary, such handles may -be casted to mutable handles using the static functions -\ccc{Arrangement_on_surface_2::non_const_handle()} provided by the -arrangement class. +An object \ccc{pl} of any point-location class must be attached to an +\ccc{Arrangement_2} object \ccc{arr} before it is used to answer +point-location queries on \ccc{arr}. This attachment can be performed +when \ccc{pl} is constructed or at a later time using the +\ccc{pl.init(arr)} call. -An instance of any point-location class must be attached to an -\ccc{Arrangement_on_surface_2} instance so we can use it to issue point-location -queries. This attachment can be performed when the point-location -instance is constructed, or at a later time, using the \ccc{init(arr)} -method, where \ccc{arr} is the attached \ccc{Arrangement_on_surface_2} instance. -In this chapter we always use the first option. - -The following function template, which can be found in the example -file \ccc{point_location_utils.h}, accepts a point-location object -(whose type can be any of the models to the -\ccc{ArrangementPointLocation_2} concept) and a query point, and -prints out the result of the point-location query for the given -point. Observe how we use the function \ccc{CGAL::assign()} is order -to cast the resulting \ccc{CGAL::Object} into a handle to an arrangement -feature. The point-location object \ccc{pl} is assumed to be already -associated with an arrangement: +The function template listed below accepts a point-location object, +the type of which is a model of the \ccc{ArrangementPointLocation_2} +concept, and a query point. The function template issues a +point-location query for the given point, and prints out the result. +It is defined in the header file \ccc{point_location_utils.h}. +\label{lst:pl} \begin{alltt} -template -void point_location_query - (const PointLocation& pl, - const typename PointLocation::Arrangement_on_surface_2::Point_2& q) +template +void +locate_point(const PointLocation& pl, + const typename PointLocation::Arrangement_2::Point_2& q) \{ - // Perform the point-location query. - CGAL::Object obj = pl.locate (q); + CGAL::Object obj = pl.locate(q); // Perform the point-location query. // Print the result. - typedef typename PointLocation::Arrangement_on_surface_2 Arrangement_on_surface_2; + print_point_location(q, obj); +\} +\end{alltt} - typename Arrangement_on_surface_2::Vertex_const_handle v; - typename Arrangement_on_surface_2::Halfedge_const_handle e; - typename Arrangement_on_surface_2::Face_const_handle f; +The function template \ccc{locate_point()} calls an instance of the +function template \ccc{print_point_location()}, which inserts the +result of the query into the standard output-stream. It is listed +below, and defined in the header file \ccc{point_location_utils.h}. +Observe how the function \ccc{assign()} is used to cast the +resulting \ccc{CGAL::Object} into a handle to an arrangement feature. +The point-location object \ccc{pl} is assumed to be already attached +to an arrangement. + +\begin{alltt} +template +void +print_point_location(const typename PointLocation::Arrangement_2::Point_2& q + const CGAL::Object& obj) +\{ + typedef typename Arrangement_ Arrangement_2; + + typename Arrangement_2::Vertex_const_handle v; + typename Arrangement_2::Halfedge_const_handle e; + typename Arrangement_2::Face_const_handle f; std::cout << "The point " << q << " is located "; - if (CGAL::assign (f, obj)) \{ - // q is located inside a face: + if (CGAL::assign (f, obj)) \{ // q is located inside a face. if (f->is_unbounded()) std::cout << "inside the unbounded face." << std::endl; else std::cout << "inside a bounded face." << std::endl; \} - else if (CGAL::assign (e, obj)) \{ - // q is located on an edge: + else if (CGAL::assign (e, obj)) \{ // q is located on an edge. std::cout << "on an edge: " << e->curve() << std::endl; \} - else if (CGAL::assign (v, obj)) \{ - // q is located on a vertex: + else if (CGAL::assign (v, obj)) \{ // q is located on a vertex. if (v->is_isolated()) std::cout << "on an isolated vertex: " << v->point() << std::endl; else std::cout << "on a vertex: " << v->point() << std::endl; \} - else \{ - CGAL_assertion_msg (false, "Invalid object."); - \} + else CGAL_assertion_msg (false, "Invalid object."); \} \end{alltt} \subsubsection{Choosing a Point-Location Strategy\label{arr_sssec:pl_strat}} -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Each of the various point-location classes employs a different -algorithm or {\em strategy}\footnote{We use the term {\em strategy} -following the design pattern taxonomy~\cite{cgal:ghjv-dpero-95}.} -for answering queries: +% ------------------------------------------------------------------------------ +Each of the various point-location class templates employs a different +algorithm or \emph{strategy}\footnote{The term \emph{strategy} +is borrowed from the design-pattern +taxonomy~\cite[Chapter~5]{ghjv-dp-95}.} for answering queries: \begin{itemize} -\item \ccc{Arr_naive_point_location} locates the query -point naively, by exhaustively scanning all arrangement cells. -% -\item \ccc{Arr_walk_along_a_line_point_location} -simulates a traversal, in reverse order, along an imaginary vertical -ray emanating -from the query point: It starts from the unbounded face of the -arrangement and moves downward toward the query point until -locating the arrangement cell containing it. -% +\item \ccc{Arr_naive_point_location} employes the + \emph{naive} strategy. It locates the query point naively, + exhaustively scanning all arrangement cells. + % +\item \ccc{Arr_walk_along_a_line_point_location} employs + the \emph{walk-along-a-line} (or \emph{walk} for short) strategy. + It simulates a traversal, in reverse order, along an imaginary + vertical ray emanating from the query point. It starts from the + unbounded face of the arrangement and moves downward toward the + query point until locating the arrangement cell containing it. + % \item \ccc{Arr_landmarks_point_location} -uses a set of ``landmark'' points whose location in the -arrangement is known. Given a query point, it uses a \kdtree\ to -find the nearest landmark and then traverses the straight line -segment connecting this landmark to the query point. + uses a set of ``landmark'' points the location of which in the + arrangement is known. It employs the + \emph{landmark} strategy. Given a query point, it uses a + nearest-neighbor search-structure (a \kdtree{} is used by default) + to find the nearest landmark and then traverses the straight-line + segment connecting this landmark to the query point. -There are various ways to select the landmark set in the -arrangement, determined by the \ccc{Generator} template parameter. -By default, the generator -class \ccc{Arr_landmarks_vertices_generator} is used and the -arrangement vertices are the selected landmarks, but other -landmark generators, such as sampling random points or -choosing points on a grid, are also available; see the -Reference Manual for more details. -% + There are various ways to select the landmark set in the + arrangement. The selection is governed by the \ccc{Generator} + template parameter. The default generator class, namely + \ccc{Arr_landmarks_vertices_generator}, selects all the vertices of + the attached arrangement as landmarks. Additional generators that + select the set in other ways, such as by sampling random + points or choosing points on a grid, are also available; see the + Reference Manual for more details. + + The landmark strategy requires that the type of the attached + arrangement be an instance of the \ccc{Arrangement_2} + class template, where the \ccc{Traits} parameter is substituted with + a geometry-traits class that models the + \ccc{ArrangementLandmarkTraits_2} concept, which refines the basic + \ccc{ArrangementBasicTraits_2} concept; see + Section~\ref{arr_sssec:tr_lanmarks_concept} for details. Most traits + classes included in the \emph{2D Arrangement} package are models of + this refined concept. + % \item \ccc{Arr_trapezoid_ric_point_location} implements -Mulmuley's point-location algorithm~\cite{m-fppa-90} (see -also~\cite[Chapter~6]{bkos-cgaa-00}). The -arrangement faces are decomposed into simpler cells of constant -complexity known as {\em pseudo-trapezoids} and a search-structure -(a directed acyclic graph) is constructed on top of these cells, -allowing to locate the pseudo-trapezoid (hence the arrangement -cell) containing a query point in expected logarithmic time. + Mulmuley's point-location algorithm~\cite{m-fppa-90}; see + also~\cite[Chapter~6]{bkos-cgaa-00}). The arrangement faces are + decomposed into simpler cells each of constant complexity, known as + \emph{pseudo-trapezoids}, and a search structure (a directed acyclic + graph) is constructed on top of these cells, facilitating the search + of the pseudo trapezoid (hence the arrangement cell) containing a + query point in expected logarithmic time. The trapezoidal map and + the search structure are built by a algorithm (RIC). \end{itemize} -The main advantage of the first two strategies is that they do not -require any extra data, so the respective classes just store a -pointer to an arrangement object and operate directly on it. -Attaching such point-location objects to an existing arrangement -has virtually no running-time cost at all, but the query time is -linear in the size of the arrangement (the performance of the -``walk'' strategy is much better in practice, but its worst-case -performance is linear). Using these strategies is therefore -recommended only when a relatively small number of point-location -queries are issued by the application, or when the arrangement is -constantly changing (i.e., changes in the arrangement structure -are more frequent than point-location queries). +The first two strategies do not require any extra data. The class +templates that implement them store a pointer to an arrangement object +and operate directly on it. Attaching such point-location objects to +an existing arrangement has virtually no running-time cost at all, but +the query time is linear in the size of the arrangement (the +performance of the walk strategy is much better in practice, but +its worst-case performance is linear). Using these strategies is +therefore recommended only when a relatively small number of +point-location queries are issued by the application, or when the +arrangement is constantly changing (That is, changes in the arrangement +structure are more frequent than point-location queries). On the other hand, the landmarks and the trapezoid RIC strategies require auxiliary data structures on top of the arrangement, which they need to construct once they are attached to an arrangement object and need to keep up-to-date as this arrangement changes. The data structures needed by both strategies can be constructed -in $O(N \log N)$ time (where $N$ is the overall number of edges in -the arrangement), -but the construction needed by the landmark algorithm is in -practice significantly faster. In addition, although both -resulting data structures are asymptotically linear in size, the -\kdtree\ that the landmark algorithm stores needs significantly -less memory. We note that Mulmuley's algorithm guarantees a -logarithmic query time, while the query time for the landmark -strategy is only logarithmic on average --- and we may have -scenarios where the query time can be linear. In practice however, -the query times of both strategies are competitive. For a detailed -experimental comparison, see \cite{cgal:hh-eplca-05} +in $O(N \log N)$ time, where $N$ is the overall number of edges in +the arrangement, but the constant hidden in the $O()$ notation for the +trapezoidal map RIC strategy is much larger. Thus, construction needed +by the landmark algorithm is in practice significantly faster than the +construction needed by the trapezoidal map RIC strategy. In addition, +although both resulting data structures are asymptotically linear in +size, using a \kdtree{} as the nearest-neighbor search-structure that +the landmark algorithm stores significantly reduces memory consumption. +The trapezoidal map RIC algorithm has expected logarithmic query time, +while the query time for the landmark strategy may be as large as +linear. In practice however, the query times of both strategies are +competitive. For a detailed experimental comparison +see~\cite{cgal:hh-eplca-05} -The main drawback in the current implementation of the landmark -strategy, compared to the trapezoidal RIC strategy, is that while -the updating the auxiliary data structures -related to the trapezoidal decomposition is done very efficiently, -the \kdtree\ maintained by the landmark algorithm needs to be -frequently rebuilt as the arrangement changes. In addition, using -the landmark point-location class adds some extra requirement -from the traits class (that is, the traits class should be a model -of a refined concept \ccc{ArrangementLandmarkTraits_2}; see -Section~\ref{arr_sec:traits} for the details). However, most -built-in traits classes that come with the \cgal\ public release -support these extra operations. - -It is therefore recommended to use the -\ccc{Arr_landmarks_point_location} class when the application -frequently issues point-location queries on an -arrangement that only seldom changes. If the arrangement is more -dynamic and is frequently going through changes, the -\ccc{Arr_trapezoid_ric_point_location} class should be the -selected point-location strategy. +Updating the auxiliary data structures of the trapezoidal map RIC +algorithm is done very efficiently. On the other hand, updating the +nearest-neighbor search-structure of the landmark algorithm may consume +more time when the arrangement changes frequently, especially when +a \kdtree{} is used, as it must be rebuilt each time the arrangement +changes. It is therefore recommended that the +\ccc{Arr_landmarks_point_location} class template be used when the +application frequently issues point-location queries on an arrangement +that only seldom changes. If the arrangement is more dynamic and is +frequently going through changes, the \ccc{Arr_trapezoid_ric_point_location} +class template should be the selected point-location strategy. \subsubsection{An Example\label{arr_sssec:pl_ex}} -%~~~~~~~~~~~~~~~~~~~~~~~~~ - +% ------------------------------------------------------------------------------ \begin{figure}[t] \begin{ccTexOnly} \begin{center} @@ -208,96 +222,80 @@ arrangement vertices are drawn as small discs, while the query points $q_1, \ldots, q_6$ are marked with crosses.\label{arr_fig:ex_5}} \end{figure} -The following program constructs a simple arrangement of five line +The program listed below constructs a simple arrangement of five line segments that form a pentagonal face, with a single isolated -vertex in its interior, as depicted in Figure~\ref{arr_fig:ex_5} -(the arrangement construction is performed by the function -\ccc{construct_segment_arr()} whose listing is omitted here and -can be found in \ccc{point_location_utils.h}). -It then employs the naive and the landmark strategies to issue -several point-location queries on this arrangement: +vertex in its interior, as depicted in Figure~\ref{arr_fig:ex_5}. +Notice that we use the same arrangement structure in the next +three example programs. The arrangement construction is performed by +the function \ccc{construct_segment_arr()} defined in the heade file +\ccc{point_location_utils.h}. (Its listing is omitted here.) The +program employs the naive and the landmark strategies to issue +several point-location queries on this arrangement. \ccIncludeExampleCode{Arrangement_on_surface_2/point_location.cpp} -Note that the program uses the auxiliary -\ccc{point_location_query()} function template to nicely print the -result of each query. This function can be found in the header file -\ccc{point_location_utils.h}. +Note that the program uses the \ccc{locate_point()} function template +to locate a point and nicely print the result of each query; see +Page~\pageref{lst:pl}. \subsection{Vertical Ray Shooting\label{arr_ssec:ray_shoot}} -%--------------------------------- - -Another important query issued on arrangements is the vertical +% ------------------------------------------------------------------------------ +Another query frequently issued on arrangements is the vertical ray-shooting query: Given a query point, which arrangement feature -do we encounter if we shoot a vertical ray emanating upward (or -downward) from this point? In the general case the ray hits an -edge, but it is possible that it hits a vertex, or that the -arrangement does not have any feature lying directly above (or -below) the query point. +do we encounter by a vertical ray shot upward (or downward) from this +point? In the general case the ray hits an edge, but it is possible +that it hits a vertex, or that the arrangement does not have any +vertex or edge lying directly above (or below) the query point. -All point-location classes listed in the previous section are also models -of the \ccc{ArrangementVerticalRayShoot_2} concept. That is, they all -have member functions called \ccc{ray_shoot_up(q)} and -\ccc{ray_shoot_down(q)} that accept a query point $q$ and output a -\cgal\ \ccc{Object}. This can be assigned to either a -\ccc{Halfedge_const_handle} or to a \ccc{Vertex_const_handle}. -Alternatively, the returned value is a \ccc{Face_const_handle} -for the unbounded face of the arrangement, in case there is no edge -or vertex lying directly above (or below) $q$. +All point-location classes listed in the previous section are also +models of the \ccc{ArrangementVerticalRayShoot_2} concept. That is, t +hey all have member functions called \ccc{ray_shoot_up(q)} and +\ccc{ray_shoot_down(q)} that accept a query point $q$. These functions +output a polymorphic object of type \ccc{CGAL::Object}, which wraps a +\ccc{Halfedge_const_handle}, a \ccc{Vertex_const_handle}, or a +\ccc{Face_const_handle} object. The latter type is used for the +unbounded face of the arrangement, in case there is no edge or +vertex lying directly above (or below) $q$. -The following function template, \ccc{vertical_ray_shooting_query()}, -which also located in the header file \ccc{point_location_utils.h}, -accepts a vertical ray-shooting -object, whose type can be any of the models to the -\ccc{ArrangementVerticalRayShoot_2} concept and prints out the -result of the upward vertical ray-shooting operations from a given -query point. The ray-shooting object \ccc{vrs} is assumed to be -already associated with an arrangement: +The function template \ccc{vertical_ray_shooting_query()} listed +below accepts a vertical ray-shooting object, the type of which +models the \ccc{ArrangementVerticalRayShoot_2} concept. It exports +the result of the upward vertical ray-shooting operation from a +given query point to the standard output-stream. The ray-shooting +object \ccc{vrs} is assumed to be already attached to an arrangement. +The function template is defined in the header file +\ccc{point_location_utils.h}. \begin{alltt} -template -void vertical_ray_shooting_query - (const VerticalRayShoot& vrs, - const typename VerticalRayShoot::Arrangement_on_surface_2::Point_2& q) +template +shoot_vertical_ray(const Ray_shooting& vrs, + const typename Ray_shooting::Arrangement_2::Point_2& q) \{ // Perform the point-location query. CGAL::Object obj = vrs.ray_shoot_up (q); - // Print the result. - typedef typename VerticalRayShoot::Arrangement_on_surface_2 Arrangement_on_surface_2; - - typename Arrangement_on_surface_2::Vertex_const_handle v; - typename Arrangement_on_surface_2::Halfedge_const_handle e; - typename Arrangement_on_surface_2::Face_const_handle f; + typename Ray_shooting::Arrangement_2::Vertex_const_handle v; + typename Ray_shooting::Arrangement_2::Halfedge_const_handle e; + typename Ray_shooting::Arrangement_2::Face_const_handle f; std::cout << "Shooting up from " << q << " : "; - if (CGAL::assign (e, obj)) \{ - // We hit an edge: + if (CGAL::assign (e, obj)) // We hit an edge std::cout << "hit an edge: " << e->curve() << std::endl; - \} - else if (CGAL::assign (v, obj)) \{ - // We hit a vertex: - if (v->is_isolated()) - std::cout << "hit an isolated vertex: " << v->point() << std::endl; - else - std::cout << "hit a vertex: " << v->point() << std::endl; - \} - else if (CGAL::assign (f, obj)) \{ - // We did not hit anything: + else if (CGAL::assign (v, obj)) // We hit a vertex + std::cout << "hit `` << (v->is_isolated()) ? "an isolated" ? "a") + << "vertex: " << v->point() << std::endl; + else if (CGAL::assign (f, obj)) \{ // We did not hit anything CGAL_assertion (f->is_unbounded()); - std::cout << "hit nothing." << std::endl; \} - else \{ - CGAL_assertion_msg (false, "Invalid object."); - \} + else CGAL_error(); \} \end{alltt} -The following program uses the auxiliary function listed above to -perform vertical ray-shooting queries on an arrangement. -The arrangement and the query points are exactly the same as in -\ccc{point_location.cpp} (see Figure~\ref{arr_fig:ex_5}): +The program below uses the auxiliary function template listed above to +perform vertical ray-shooting queries on an arrangement. The +arrangement and the query points are exactly the same as in +\ccc{point_location.cpp}; see Figure~\ref{arr_fig:ex_5}.: \ccIncludeExampleCode{Arrangement_on_surface_2/vertical_ray_shooting.cpp} @@ -308,8 +306,7 @@ integer or from a machine \ccc{float} or \ccc{double} and performs additions, subtractions and multiplications in an exact number. \subsection{Batched Point-Location\label{arr_ssec:batched_pl}} -%---------------------------------- - +% ------------------------------------------------------------------------------ Suppose that at a given moment our application has to issue a relatively large number $m$ of point-location queries on a specific arrangement instance. It is possible of course to define