diff --git a/Documentation/biblio/cgal_manual.bib b/Documentation/biblio/cgal_manual.bib index 2285b00840a..f9ec3628436 100644 --- a/Documentation/biblio/cgal_manual.bib +++ b/Documentation/biblio/cgal_manual.bib @@ -2335,6 +2335,50 @@ ADDRESS = "Saarbr{\"u}cken, Germany" series = {Texts and Monographs in Symbolic Computation} } +@article{bjrb-clvpa-87, +author = "B. Joe and R.B. Simpson", +title = "Corrections to Lee's visibility polygon algorithm", +journal = "BIT", +volume = 27, +year = 1987, +pages = "458--473" +} + +@article{ta-aeafvpprh-85 + ,author = {T. Asano} + ,title = {An Efficient Algorithm for Finding the Visibility Polygon for a Polygonal Region with Holes} + ,journal = {IEICE Transactions (1976-1990)} + ,year = 1985 + ,volume = E68 + ,number = 9 + ,pages = {557--559} +} + + +@article{aaghi-vpsesp-85, + author = {Takao Asano and + Tetsuo Asano and + Leonidas J. Guibas and + John Hershberger and + Hiroshi Imai}, + title = {Visibility-Polygon Search and Euclidean Shortest Paths}, + booktitle = {FOCS}, + year = {1985}, + pages = {155-164}, + ee = {http://doi.ieeecomputersociety.org/10.1109/SFCS.1985.65}, + crossref = {DBLP:conf/focs/FOCS26}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{dtl-voasp-83, +author = "D. T. Lee", +title = "Visibility of a simple polygon", +journal = "Computer Vision, Graphics, and Image Processing", +volume = 22, +year = 1983, +pages = "207--221" +} + % ---------------------------------------------------------------------------- % END OF BIBFILE % ---------------------------------------------------------------------------- diff --git a/Documentation/biblio/geom.bib b/Documentation/biblio/geom.bib index 668aea44180..a7ebeefdd3b 100644 --- a/Documentation/biblio/geom.bib +++ b/Documentation/biblio/geom.bib @@ -151797,4 +151797,3 @@ amplification and suppression of local contrast. Contains C code." , publisher = "Cambridge University Press" , year = 1999 } - diff --git a/Documentation/doc/Documentation/Doxyfile.in b/Documentation/doc/Documentation/Doxyfile.in index 3b98211f403..1a6d60f2432 100644 --- a/Documentation/doc/Documentation/Doxyfile.in +++ b/Documentation/doc/Documentation/Doxyfile.in @@ -104,6 +104,7 @@ IMAGE_PATH = ${CMAKE_SOURCE_DIR}/Documentation/doc/Documentation/fig \ ${CMAKE_SOURCE_DIR}/Spatial_sorting/doc/Spatial_sorting/fig \ ${CMAKE_SOURCE_DIR}/Segment_Delaunay_graph_2/doc/Segment_Delaunay_graph_2/fig \ ${CMAKE_SOURCE_DIR}/Straight_skeleton_2/doc/Straight_skeleton_2/fig \ + ${CMAKE_SOURCE_DIR}/Visibility_2/doc/Visibility_2/fig \ ${CMAKE_SOURCE_DIR}/Voronoi_diagram_2/doc/Voronoi_diagram_2/fig \ ${CMAKE_SOURCE_DIR}/Surface_mesh_simplification/doc/Surface_mesh_simplification/fig \ ${CMAKE_SOURCE_DIR}/Subdivision_method_3/doc/Subdivision_method_3/fig \ diff --git a/Documentation/doc/Documentation/dependencies b/Documentation/doc/Documentation/dependencies index 0c39215e2e6..8d6852cfc73 100644 --- a/Documentation/doc/Documentation/dependencies +++ b/Documentation/doc/Documentation/dependencies @@ -71,6 +71,7 @@ Spatial_searching Spatial_sorting Segment_Delaunay_graph_2 Straight_skeleton_2 +Visibility_2 Voronoi_diagram_2 Surface_mesh_simplification Subdivision_method_3 diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index 5dd03dd6775..894ba6f2838 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -66,6 +66,7 @@ h1 { \package_listing{Snap_rounding_2} \package_listing{Envelope_2} \package_listing{Envelope_3} +\package_listing{Visibility_2} \section PartTriangulationsAndDelaunayTriangulations Triangulations and Delaunay Triangulations diff --git a/Documentation/doxyassist.xml b/Documentation/doxyassist.xml index 1d7bbb8760b..23576d72ef5 100644 --- a/Documentation/doxyassist.xml +++ b/Documentation/doxyassist.xml @@ -718,8 +718,24 @@ namespace for the XML file to be processed properly. --> ./tags/Arrangement_on_surface_2.tag=../../CGAL.CGAL.2D-Arrangements/html + + + + 2D Visibility + ../Visibility_2/doc/Visibility_2 + + ../Visibility_2/doc/Visibility_2/ + ../Visibility_2/doc/Visibility_2/ + ./tags/Visibility_2.tag + ../Visibility_2/examples + ../Visibility_2/doc/Visibility_2/fig + + ./tags/Arrangement_on_surface_2.tag=../../CGAL.CGAL.2D-Arrangements/html + + + 2D Minkowski Sums ../Minkowski_sum_2/doc/Minkowski_sum_2 @@ -1457,6 +1473,7 @@ namespace for the XML file to be processed properly. --> ../Convex_hull_d/doc/Convex_hull_d/fig ../Envelope_2/doc/Envelope_2/fig ../Envelope_3/doc/Envelope_3/fig + ../Visibility_2/doc/Visibility_2/fig ../Generator/doc/Generator/fig ../Geomview/doc/Geomview/fig ../GraphicsView/doc/GraphicsView/fig @@ -1538,6 +1555,7 @@ namespace for the XML file to be processed properly. --> ./tags/Convex_hull_d.tag=../../CGAL.CGAL.dD-Convex-Hulls-and-Delaunay-Triangulations/html ./tags/Envelope_2.tag=../../CGAL.CGAL.2D-Envelopes/html ./tags/Envelope_3.tag=../../CGAL.CGAL.3D-Envelopes/html + ./tags/Visibility_2.tag=../../CGAL.CGAL.2D-Visibility/html ./tags/Generator.tag=../../CGAL.CGAL.Geometric-Object-Generators/html ./tags/Geomview.tag=../../CGAL.CGAL.Geomview/html ./tags/GraphicsView.tag=../../CGAL.CGAL.CGAL-and-the-Qt-Graphics-View-Framework/html diff --git a/Visibility_2/doc/OLD/ArrExtensionTraits_2.h b/Visibility_2/doc/OLD/ArrExtensionTraits_2.h new file mode 100644 index 00000000000..333689eeab5 --- /dev/null +++ b/Visibility_2/doc/OLD/ArrExtensionTraits_2.h @@ -0,0 +1,87 @@ +/*! +\ingroup PkgVisibility_2Concepts +\cgalConcept + +All visibility polgyon algorithms provided in \cgal are parameterized with a traits class 'Traits', which defines the extension of Arrangement_2 the output will have. + +\cgalHasModel `CGAL::Arr_extension_default_traits_2` + +\sa `Visibility_2` + +*/ +class ArrExtensionTraits_2 { +public : + + + +/// \name Types +/// @{ + +/*! + * The vertex handle type on which the functors will operate. + */ +typedef Hidden_type Vertex_handle; + +/*! + * The halfedge handle type on which the functors will operate. + */ +typedef Hidden_type Halfedge_handle; + +/*! + * The face handle type on which the functors will operate. + */ +typedef Hidden_type Face_handle; + +/*! + * Add auxiliary information to vertex. + */ +typedef Hidden_type Extend_vertex; + +/*! + * Add auxiliary information to halfedge. + */ +typedef Hidden_type Extend_halfedge; + +/*! + * Add auxiliary information to face. + */ +typedef Hidden_type Extend_face; + +/// \name Creation +/// @{ +/*! +default creator +*/ +ArrExtensionTraits_2 (); + +/*! +copy creator +*/ +ArrExtensionTraits_2 (const ArrExtensionTraits_2& Traits); + +/// @} + +/// \name Operations +/// The following member functions to create instances of the above predicate oject types. +/// @{ + +/*! + * + */ +Extend_vertex extend_vertex_object(); + +/*! + * + */ +Extend_halfedge extend_halfedge_object(); + +/*! + * + */ +Extend_face extend_face_object(); + +/// @} + + +} + diff --git a/Visibility_2/doc/OLD/Arr_extension_default_traits_2.h b/Visibility_2/doc/OLD/Arr_extension_default_traits_2.h new file mode 100644 index 00000000000..40d8baa9328 --- /dev/null +++ b/Visibility_2/doc/OLD/Arr_extension_default_traits_2.h @@ -0,0 +1,80 @@ +namespace CGAL { + +/*! +\ingroup PkgArrExtensionTraits + +The class `Arr_extension_default_traits_2` serves as a traits class for all visibility polygon calculation function. +This class extends the vertex, halfedges and face. User also may define their own traits class to choose which to extend. + +\cgalModels `ArrExtensionTraits_2` + +\sa `CGAL::Arr_extended_dcel` + + +*/ + +template< typename A_ > +class Arr_extension_default_traits_2 { +public: + + /// \name Types + /// @{ + /*! + * + */ + typedef A_::Vertex_iterator Vertex_iterator; + + /*! + * + */ + typedef A_::Halfedge_iterator Halfedge_iterator; + + /*! + * + */ + typedef A_::Fayce_iterator Face_iterator; + + /// @} + + /// \name Functor classes + /// @{ + + /*! + * + */ + class Extend_vertex; + + /*! + * + */ + class Extend_halfedge; + + /*! + * + */ + class Extend_face; + /// @} + + /// \name Operations + /// @{ + + /*! + * + */ + Extend_vertex extend_vertex_object(); + + /*! + * + */ + Extend_halfedge extend_halfedge_object(); + + /*! + * + */ + Extend_face extend_face_object(); + + /// @} + +}; + +} /* end namespace CGAL */ diff --git a/Visibility_2/doc/OLD/Preprocessed_rotational_sweep_visibility_2.h b/Visibility_2/doc/OLD/Preprocessed_rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..6ef04c61d65 --- /dev/null +++ b/Visibility_2/doc/OLD/Preprocessed_rotational_sweep_visibility_2.h @@ -0,0 +1,158 @@ +namespace CGAL { +/*! +\ingroup PkgVisibility_2Classes + +\brief This class is a model of the concept `Visibility_2` can answer visibility queries within +a polygon that may have holes. + +\details The class template comprises the implementation of the algorithm of Takao Asano and Tetsuo Asano \cite aaghi-vpsesp-85. The algorithm, as the name of the class template suggests, requires preprocessing. The preprocessing takes \f$ O(n^2)\f$ time and \f$ O(n^2)\f$ space, which reduces the query time to \f$O(n)\f$. + +The main preprocessing step is the dualization of all vertices of the input arrangment into an arrangment of lines. +Computing this arrangement takes \f$ O(n^2)\f$ time and \f$ O(n^2)\f$ space. +Using this arrangment it is possible to retrieve the angular order of all vertices around +a query point, which is one of the essential steps to achive linear query time. For more details we refer to \cite aaghi-vpsesp-85. + + + +\tparam Arrangement_2 is the type of input polygonal environment and output visibility polygon. + +\tparam RegularizationTag indicates whether the output should be regularized. It can be +specified by one of the following: ::Tag_true or ::Tag_false, where ::Tag_false is the default value. + + +\cgalModels `Visibility_2` + +\sa `CGAL::Simple_polygon_visibility_2` +\sa `CGAL::Rotational_sweep_visibility_2` +\sa `CGAL::Triangular_expansion_visibility_2` + + +*/ +template +class Preprocessed_rotational_sweep_visibility_2 { +public: + +/// \name Types +/// @{ + + /*! + The type of the input arrangement. + */ + typedef Arrangement_2 Arrangement_2; + + /*! + The type of the output arrangement. + */ + typedef Arrangement_2 Visibility_arrangement_2; + + /*! + The 2D point type used for the queries. + */ + typedef Arrangement_2::Point_2 Point_2; + + /*! + Face_const_handle type of the input arrangement. + */ + typedef Arrangement_2::Face_const_handle Face_const_handle; + + /*! + Halfedge_const_handle type of the input arrangement. + */ + typedef Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + + + +/// @} + + +/// \name Tags +/// @{ + /*! + Tag identifying whether the regularized visibility area is computed. + */ + typedef RegularizationTag Regularization_tag; + + /*! + Tag identifying that the class supports general polygons (i.e.\ with holes). + */ + typedef ::Tag_true Supports_general_polygon_tag; + + /*! + Tag identifying that the class supports general simple polygons. + */ + typedef ::Tag_true Supports_simple_polygon_tag; +/// @} + + + +/// \name Constructors +/// @{ + +/*! +Default constructor creates an empty `Preprocessed_rotational_sweep_visibility_2` object that is not +attached to any arrangement yet. +*/ +Preprocessed_rotational_sweep_visibility_2(); + +/*! +Constructs a `Preprocessed_rotational_sweep_visibility_2` object that is attached to `arr`. +*/ +Preprocessed_rotational_sweep_visibility_2(const Arrangement_2& arr); + +/// @} + +/// \name functions +/// @{ + +/*! +Returns whether an arrangement is attached to the visibility object +*/ + bool is_attached() const; + +/*! +Attaches the given arrangement to the visibility object and applies preprocessing. +In case the object is already attached to another arrangement, +the visibility object gets detached before being attached to `arr`. +*/ + void attach(const Arrangement_2& arr); + +/*! +Detaches the arrangement from the visibility object it is currently attached to +*/ + void detach(); + +/*! +Access to the attached arrangement +*/ + const Arrangement_2& arr() const; + +/*! +Computes the visibility region of `q` in the +face `f` of the arrangement that is attached to the visibility object. +The visibility region of `q` will be stored in `out_arr`. +\param q is the query point +\param f is the face of the arrangement in which the visibility region is computed +\param out_arr is the output arrangement +\pre `f` is a face of `arr()` and represents a valid polygon. +\pre `q` is in the interior of the given face `f` +\return a handle to the face in `out_arr` that represents the visibility region +*/ + typename Visibility_arrangement_2::Face_handle compute_visibility(const Point_2& q, const Face_const_handle f, Visibility_arrangement_2& out_arr) const; + +/*! +Computes the visibility region of `q` that is on `e`. If `q` is an interior point of `e`, the computed visibility region is restricted to the halfplane indicated by `e`. If `q` is an endpoint of `e`, the visibility region is restricted by `e` and its next. +The visibility region of `q` will be stored in `out_arr`. +\param q is the query point +\param e the halfedge on which `q` is located +\param out_arr is the output arrangement +\pre `e` is a halfedge of `arr()` +\pre `q` is on `e` +\pre `q` equals to `e->target()->point()` if `q` is an endpoint of `e` +\return a handle to the face in `out_arr` that represents the visibility region +*/ + typename Visibility_arrangement_2::Face_handle compute_visibility(const Point_2& q, const Halfedge_const_handle e, Visibility_arrangement_2& out_arr) const; + +/// @} + +}; /* end Visibility_2 */ +} /* namespace CGAL */ diff --git a/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..fbd66bc408b --- /dev/null +++ b/Visibility_2/doc/Visibility_2/CGAL/Rotational_sweep_visibility_2.h @@ -0,0 +1,77 @@ +namespace CGAL { +/*! +\ingroup PkgVisibility_2Classes + +\brief This class is a model of the concept `Visibility_2` can answer visibility queries within a polygon that may have holes. + + +\details The algorithm does not require preprocessing. It relies on the algorithm of T. Asano \cite ta-aeafvpprh-85 based on angular plane sweep, with a time complexity of \f$O (n \log n)\f$ in the number of vertices. + + +\tparam Arrangement_2_ is the type used to represent the input environment. +It must be an instance of CGAL::Arrangement_2, where its CGAL::Arrangement_2::Traits_2 must be an instance of +CGAL::Arr_segment_traits_2. + +\tparam RegularizationTag indicates whether the output should be regularized. It can be +specified by one of the following: ::Tag_true or ::Tag_false, where ::Tag_false is the default value. + + + +\cgalModels `Visibility_2` + +\sa `CGAL::Simple_polygon_visibility_2` +\sa `CGAL::Triangular_expansion_visibility_2` + +*/ +template +class Rotational_sweep_visibility_2 { +public: + +/// \name Types +/// @{ + + /*! + The type of the input arrangement. + */ + typedef Arrangement_2 Arrangement_2; + +/// @} + +/// \name Tags +/// @{ + /*! + Tag identifying whether the regularized visibility area is computed. + */ + typedef RegularizationTag Regularization_tag; + + /*! + The class supports general polygons (i.e.\ with holes). + */ + typedef ::Tag_true Supports_general_polygon_tag; + + /*! + The class supports general simple polygons. + */ + typedef ::Tag_true Supports_simple_polygon_tag; +/// @} + + +/// \name Functions +/// @{ + + +/*! +Attaches the given arrangement to the visibility object. + +This operation takes \f$O(1)\f$ as the class does no pre-processing. + +In case the object is already attached to another arrangement, +the visibility object gets detached before being attached to `arr`. +*/ + void attach(const Arrangement_2& arr); + + +/// @} + +}; /* end Visibility_2 */ +} diff --git a/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h new file mode 100644 index 00000000000..cc39a6c4b5f --- /dev/null +++ b/Visibility_2/doc/Visibility_2/CGAL/Simple_polygon_visibility_2.h @@ -0,0 +1,82 @@ +namespace CGAL { +/*! +\ingroup PkgVisibility_2Classes + +\brief This class is a model of the concept `Visibility_2` can answer visibility queries within +a simple polygon with no holes. + +\details This class implements the algorithm of B.Joe and R.B.Simpson \cite bjrb-clvpa-87. +The algorithm is a modification and extension of the linear time algorithm of Lee \cite dtl-voasp-83. +It computes the visibility region from a viewpoint that is in the interior or on the boundary of the polygon. + +While scanning the boundary the algorithm uses a stack to manipulate the vertices, and ultimately +yields the visibility region. For each scanned edge, at most 2 points are pushed onto the stack. +Overall, at most 2\f$ n \f$ points are pushed or popped. Thus, the time and space complexities of the +algorithm are \f$ O(n) \f$ even in case of degeneracies such as needles, where \f$ n \f$ +is the number of the vertices of the polygon. + +\tparam Arrangement_2_ is the type used to represent the input environment. +It must be an instance of CGAL::Arrangement_2, where its CGAL::Arrangement_2::Traits_2 must be an instance of +CGAL::Arr_segment_traits_2. + +\tparam RegularizationTag indicates whether the output should be regularized. It can be +specified by one of the following: ::Tag_true or ::Tag_false, where ::Tag_false is the default value. + + +\cgalModels `Visibility_2` + +\sa `CGAL::Rotational_sweep_visibility_2` +\sa `CGAL::Triangular_expansion_visibility_2` +*/ +template +class Simple_polygon_visibility_2 { +public: + +/// \name Types +/// @{ + + /*! + The arrangement type is used for input. + */ + typedef Arrangement_2 Arrangement_2; + +/// @} + +/// \name Tags +/// @{ + /*! + Tag identifying whether the regularized visibility area is computed. + */ + typedef RegularizationTag Regularization_tag; + + /*! + The class does not support general polygons (i.e.\ with holes). + */ + typedef ::Tag_false Supports_general_polygon_tag; + + /*! + The class supports general simple polygons. + */ + typedef ::Tag_true Supports_simple_polygon_tag; +/// @} + + +/// \name Functions +/// @{ + +/*! +Attaches the given arrangement to the visibility object. + +This operation takes \f$O(1)\f$ as the class does no pre-processing. + +In case the object is already attached to another arrangement, +the visibility object gets detached before being attached to `arr`. +*/ + void attach(const Arrangement_2& arr); + + + +/// @} + +}; /* end Visibility_2 */ +} diff --git a/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h b/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h new file mode 100644 index 00000000000..0ad7c8642e4 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/CGAL/Triangular_expansion_visibility_2.h @@ -0,0 +1,82 @@ +namespace CGAL { +/*! +\ingroup PkgVisibility_2Classes + +\brief This class is a model of the concept `Visibility_2` can answer visibility queries within a polygon that may have holes. + +\details The algorithm obtains a constrained triangulation from input arrangement, then computes visibility by +expanding the triangle that contains the query point. +Preprocessing takes \f$ O(n)\f$ time and \f$ O(n) \f$ space, where \f$ n \f$ is the number of vertices of input polygon. +The query time is \f$ O(nh)\f$, where \f$ h \f$ is the number of holes+1 of input polygon. Thus, for simple polygons +the algorithm is even linear but it can also be \f$ O(n^2)\f$ in the worst case as the number of holes can be linear in \f$ n \f$. + + +\tparam Arrangement_2_ is the type used to represent the input environment. +It must be an instance of CGAL::Arrangement_2, where its CGAL::Arrangement_2::Traits_2 must be an instance of +CGAL::Arr_segment_traits_2. + +\tparam RegularizationTag indicates whether the output should be regularized. It can be +specified by one of the following: ::Tag_true or ::Tag_false, where ::Tag_false is the default value. + +\cgalModels `Visibility_2` + +\sa `CGAL::Simple_polygon_visibility_2` +\sa `CGAL::Rotational_sweep_visibility_2` + + +*/ +template +class Triangular_expansion_visibility_2 { +public: + +/// \name Types +/// @{ + + /*! + The type of the input arrangement. + */ + typedef Arrangement_2_ Arrangement_2; + +/// @} + + +/// \name Tags +/// @{ + /*! + Tag identifying whether the regularized visibility area is computed. + */ + typedef RegularizationTag Regularization_tag; + + /*! + The class supports general polygons (i.e.\ with holes). + */ + typedef ::Tag_true Supports_general_polygon_tag; + + /*! + The class supports general simple polygons. + */ + typedef ::Tag_true Supports_simple_polygon_tag; +/// @} + + +/// \name Functions +/// @{ + +/*! +Attaches the given arrangement to the visibility object and computes the restricted triangulation. +This takes \f$ O(n) \f$ time, where \f$ n \f$ is the number of vertices. + +From this moment on the class observes changes in the arrangement. If the arrangement changes +the a new restricted triangulation is computed right before a new query. It is also possible +to force a re-computation by re-attaching the current arrangement. + +In case the object is already attached to another arrangement, +the visibility object gets detached before being attached to `arr`. +*/ +void attach(const Arrangement_2& arr); + + +/// @} + +}; /* end Visibility_2 */ +} /* namespace CGAL */ diff --git a/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h b/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h new file mode 100644 index 00000000000..7f7db7038d3 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/Concepts/Visibility_2.h @@ -0,0 +1,156 @@ + +/*! +\ingroup PkgVisibility_2Concepts +\cgalConcept + +A model of the `Visibility_2` concept can be attached to an `Arrangement_2` instance to +answer visibility queries within the faces of this arrangement. + +\cgalHasModel `CGAL::Simple_polygon_visibility_2` +\cgalHasModel `CGAL::Rotational_sweep_visibility_2` +\cgalHasModel `CGAL::Triangular_expansion_visibility_2` + +*/ +class Visibility_2 { +public: + +/// \name Types +/// @{ + + /*! + The arrangement type of the input. + */ + typedef Hidden_type Arrangement_2; + + /*! + The geometry traits class of Arrangement_2. + */ + typedef Arrangement_2::Traits_2 Traits_2; + + /*! + The 2D point type used for the queries. + */ + typedef Arrangement_2::Point_2 Point_2; + + /*! + * The face handle type of the input arrangement. + */ + typedef Arrangement_2::Face_const_handle Face_const_handle; + + /*! + * The halfedge handle type of the input arrangement. + */ + typedef Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + +/// @} + +/// \name Tags +/// @{ + /*! + Tag identifying whether the regularized visibility area is computed (either \ref CGAL::Tag_true or \ref CGAL::Tag_false). + */ + typedef Hidden_type Regularization_tag; + + /*! + Tag identifying whether general polygons (with holes) are supported (either \ref CGAL::Tag_true or \ref CGAL::Tag_false). + */ + typedef Hidden_type Supports_general_polygon_tag; + + /*! + Tag identifying whether general simple polygons are supported (either \ref CGAL::Tag_true or \ref CGAL::Tag_false). + */ + typedef Hidden_type Supports_simple_polygon_tag; +/// @} + +/// \name Constructors +/// @{ + +/*! +Default constructor creates an empty `Visibility_2` object that is not +attached to any arrangement yet. +*/ +Visibility_2(); + +/*! +Constructs a `Visibility_2` object that is attached to `arr`. +*/ +Visibility_2(const Arrangement_2& arr); + +/// @} + + +/// \name Functions +/// @{ + +/*! +Returns whether an arrangement is attached to the visibility object +*/ + bool is_attached() const; + +/*! +Attaches the given arrangement `arr` to the visibility object. +In case the object is already attached to another arrangement, +the visibility object gets detached before being attached to `arr`. +*/ + void attach(const Arrangement_2& arr); + + +/*! +Detaches the arrangement from the visibility object it is currently attached to +*/ + void detach(); + +/*! +Access to the attached arrangement +*/ + const Arrangement_2& arr() const; + +/*! +Computes the visibility region for the given query point `q` in the +face \f$ f \f$ of the arrangement that is attached to the visibility object. +The visibility region of `q` is stored in `out_arr`, that is, +all features but the unbounded face of `out_arr` represent the visibility region. + +\tparam VisibilityArrangement_2 is the type of the output arrangement representing the visibility polygon. +It must be an instance of CGAL::Arrangement_2, where its CGAL::Arrangement_2::Traits_2 +must be mutual convertible to Visibility_2::Traits_2. + +\param q is the query point +\param f is the face of the arrangement in which the visibility region is computed +\param out_arr is the output arrangement +\pre `f` is a face of `this->arr()` +\pre `q` is in the interior of the given face `f` +\return the face handle to the face in `out_arr` that represents interior of the visibility region +*/ + template + typename Visibility_arrangement_2::Face_handle + compute_visibility(const Point_2& q, const Face_const_handle f, VisibilityArrangement_2& out_arr) const; + +/*! +Computes the visibility region in `e->face()` for the given query +point `q` which must be located on `e`. +If `q` is an interior point of `e`, the computed visibility +region is restricted to the side indicated by the halfedge `e`. +If `q` is an endpoint of `e`, the visibility region is restricted by `e` and `e->next()`. +The visibility region of `q` is stored in `out_arr`, that is, +all features but the unbounded face of `out_arr` represent the visibility region. + +\tparam VisibilityArrangement_2 is the type of the output arrangement representing the visibility polygon. +It must be an instance of CGAL::Arrangement_2, where its CGAL::Arrangement_2::Traits_2 +must be mutual convertible to Visibility_2::Traits_2. +\param q is the query point +\param e the halfedge on which `q` is located +\param out_arr is the output arrangement +\pre `e` is a halfedge of `this->arr()` +\pre `q` is on `e` +\pre `q` equals to `e->target()->point()` if `q` is an endpoint of `e` +\return a handle to the face in `out_arr` that represents the interior of the visibility region +*/ + template + typename Visibility_arrangement_2::Face_handle + compute_visibility(const Point_2& q, const Halfedge_const_handle e, Visibility_arrangement_2& out_arr) const; + +/// @} + +}; /* end Visibility_2 */ + diff --git a/Visibility_2/doc/Visibility_2/Doxyfile.in b/Visibility_2/doc/Visibility_2/Doxyfile.in new file mode 100644 index 00000000000..963b8c7f059 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/Doxyfile.in @@ -0,0 +1,9 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} + +PROJECT_NAME = "CGAL ${CGAL_CREATED_VERSION_NUM} - 2D Visibility" + + +INPUT = ${CMAKE_SOURCE_DIR}/Visibility_2/doc/Visibility_2/ + + + diff --git a/Visibility_2/doc/Visibility_2/PackageDescription.txt b/Visibility_2/doc/Visibility_2/PackageDescription.txt new file mode 100644 index 00000000000..ce9f7b2f2c7 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/PackageDescription.txt @@ -0,0 +1,32 @@ +/// \defgroup PkgVisibility_2 Visibility_2 Reference + +/// \defgroup PkgVisibility_2Concepts Concepts +/// \ingroup PkgVisibility_2 + +/*! +\addtogroup PkgVisibility_2 +\cgalPkgDescriptionBegin{2D Visibility Computation,PkgVisibility_2Summary} +\cgalPkgPicture{visibility-teaser-thumbnail.png} +\cgalPkgSummaryBegin +\cgalPkgAuthors{Michael Hemmer, Kan Huang, Francisc Bungiu} +\cgalPkgDesc{This package provides several variants to compute +the visibility area of a point within polygonal regions in two dimensions.} +\cgalPkgManuals{Chapter_2D_Visibility_Computation,PkgVisibility_2} +\cgalPkgSummaryEnd +\cgalPkgShortInfoBegin +\cgalPkgSince{99.99} +\cgalPkgBib{hhb-visibility-2} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgShortInfoEnd +\cgalPkgDescriptionEnd + +\cgalClassifedRefPages + +## Concepts ## +- `Visibility_2` + +## Classes ## +- `CGAL::Simple_polygon_visibility_2` +- `CGAL::Rotational_sweep_visibility_2` +- `CGAL::Triangular_expansion_visibility_2` +*/ diff --git a/Visibility_2/doc/Visibility_2/dependencies b/Visibility_2/doc/Visibility_2/dependencies new file mode 100644 index 00000000000..9f04c30e0c4 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/dependencies @@ -0,0 +1,8 @@ +Manual +Kernel_23 +STL_Extension +Algebraic_foundations +Circulator +Stream_support +Arrangement_on_surface_2 +Boolean_set_operations_2 diff --git a/Visibility_2/doc/Visibility_2/examples.txt b/Visibility_2/doc/Visibility_2/examples.txt new file mode 100644 index 00000000000..72d4164844c --- /dev/null +++ b/Visibility_2/doc/Visibility_2/examples.txt @@ -0,0 +1,4 @@ +/*! +\example Visibility_2/simple_polygon_visibility_2.cpp +\example Visibility_2/general_polygon_example.cpp +*/ diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral-simple.png b/Visibility_2/doc/Visibility_2/fig/cathedral-simple.png new file mode 100644 index 00000000000..b4802ebd24e Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/cathedral-simple.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral-simple.svg b/Visibility_2/doc/Visibility_2/fig/cathedral-simple.svg new file mode 100644 index 00000000000..0e2617f1652 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/fig/cathedral-simple.svg @@ -0,0 +1,2354 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral.png b/Visibility_2/doc/Visibility_2/fig/cathedral.png new file mode 100644 index 00000000000..349af7a7447 Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/cathedral.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral.svg b/Visibility_2/doc/Visibility_2/fig/cathedral.svg new file mode 100644 index 00000000000..263029df7e6 --- /dev/null +++ b/Visibility_2/doc/Visibility_2/fig/cathedral.svg @@ -0,0 +1,4705 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral_2.png b/Visibility_2/doc/Visibility_2/fig/cathedral_2.png new file mode 100644 index 00000000000..e1bcaa9852b Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/cathedral_2.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/cathedral_2.svg b/Visibility_2/doc/Visibility_2/fig/cathedral_2.svg new file mode 100644 index 00000000000..531568c6ecc --- /dev/null +++ b/Visibility_2/doc/Visibility_2/fig/cathedral_2.svg @@ -0,0 +1,8690 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visibility_2/doc/Visibility_2/fig/definition.png b/Visibility_2/doc/Visibility_2/fig/definition.png new file mode 100644 index 00000000000..99f6af6a37c Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/definition.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/example1.png b/Visibility_2/doc/Visibility_2/fig/example1.png new file mode 100644 index 00000000000..e5eeb1f1775 Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/example1.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png b/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png new file mode 100644 index 00000000000..a58448aa65e Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/general_polygon_example.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/simple_example.png b/Visibility_2/doc/Visibility_2/fig/simple_example.png new file mode 100644 index 00000000000..90e1348363b Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/simple_example.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/visibility-teaser-thumbnail.png b/Visibility_2/doc/Visibility_2/fig/visibility-teaser-thumbnail.png new file mode 100644 index 00000000000..1efe7bd5b24 Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/visibility-teaser-thumbnail.png differ diff --git a/Visibility_2/doc/Visibility_2/fig/visibility-teaser.png b/Visibility_2/doc/Visibility_2/fig/visibility-teaser.png new file mode 100644 index 00000000000..fff644acee3 Binary files /dev/null and b/Visibility_2/doc/Visibility_2/fig/visibility-teaser.png differ diff --git a/Visibility_2/doc/Visibility_2/visibility_2.txt b/Visibility_2/doc/Visibility_2/visibility_2.txt new file mode 100644 index 00000000000..362c061beaa --- /dev/null +++ b/Visibility_2/doc/Visibility_2/visibility_2.txt @@ -0,0 +1,152 @@ +namespace CGAL { + +/*! +\mainpage 2D Visibility +\anchor Chapter_2D_Visibility_Computation +\cgalAutoToc + +\authors Michael Hemmer, Kan Huang, Francisc Bungiu, Ning Xu + +\cgalFigureBegin{example_figure,visibility-teaser.png} +\cgalFigureEnd + +\section visibility_2_introduction Introduction + +This package provides functionality to compute the visibility region within polygonal regions in two dimensions. +Using the terminology of the package \ref PkgBooleanSetOperations2Summary, we expect the input polygon +\f$ P \f$ to be a valid polygon or a valid polygon with holes (the definition is given below). +Given two points \f$ p \f$ and \f$ q \f$ in \f$ P \f$, they are said to be +visible to each other iff the segment \f$ pq \subset P \f$, note that \f$\partial P \subset P\f$. +For a query point \f$ q \in P \f$, the set of points that are visible from \f$ q \f$ is defined as the visibility +region of \f$ q \f$, denoted by \f$ V_q \f$ + + +Definition [Valid Polygon]: +A polygon \f$ P \f$ is valid if \f$ P \f$ is closed (\f$\partial P \subset P\f$) +and each boundary loop (only one outer boundary loop in case of no holes) is simple. +See also \ref PkgBooleanSetOperations2Summary. + + +\subsection visibility_2_degeneracies Degeneracies and Regularization + +\cgalFigureBegin{definition-fig, example1.png} +Non-regularized visibility and regularized visibility. +\cgalFigureEnd + + +As illustrated in \cgalFigureRef{definition-fig} (1) the visibility region \f$ V_q \f$ of a query point \f$ q \f$ may not be +a valid polygon. In the figure, all labeled points are collinear, which implies that the point \f$ c \f$ is visible to \f$ q \f$, that is, +the segment \f$ bc \f$ is part of the visibility area \f$ V_q \f$. +Subsequently we call such low dimensional features that are caused by degeneracies `needles`. +However, for many applications these needles are actually irrelevant. +Moreover, for some algorithms it is actually easier (and more efficient) to ignore needles +in the first place. +Therefore, this package offers also +functionality to compute the regularized visibility area +\f$ \overline{V_q} = closure(interior(V_q)) = (V_q\setminus\partial V_q) \cup \partial (V_q\setminus\partial V_q)\f$, +as it is shown in \cgalFigureRef{definition-fig} (2). For more information about regularization, refer to Chapter +\ref PkgBooleanSetOperations2Summary. + +In summary, this package provides two kinds of visibility region of point \f$ q \f$: +- Non-regularized visibility area \f$ V_q \f$. +- Regularized visibility area \f$ \overline{V_q} \f$. + + +\section visibility_2_classes Classes and Algorithms + +This package is based on the \ref PkgArrangement2Summary package and exploits several of its features. +In particular, the output is represented by an `Arrangement_2`, which enables +the representation of needles. All provided class templates follow the `Visibility_2` concept. + +Answering visibility queries is, in many ways, similar to answering point-location queries. Thus, we use the same design used +to implement point location. Each of the various visibility class templates employs a different algorithm or \em strategy +\cgalFootnote{The term \em strategy is borrowed from the design-pattern taxonomy~\cite ghjv-dpero-95. A \em strategy provides +the means to define a family of algorithms, each implemented by a separate class. All classes that implement the various +algorithms are made interchangeable, letting the algorithm in use vary according to the user choice.} for answering queries. +Similar to the point-location case, some of the strategies require preprocessing. Thus, before a visibility object is used +to answer visibility queries, it must be attached to an arrangement object (subsequently also referred to as the environment). +Afterwards the visibility object observers changes to the attached arrangement. +Clearly, it is possible to modify the arrangement after attaching the visibility object. +However, this should be avoided as this also requires an update of the auxiliary +data structures in the attached object. + +An actual query is then performed by giving the view point \f$ p \f$ and its containing face \f$ f \f$, +which must represent a valid \cgalFootnote{See the package \ref PkgBooleanSetOperations2Summary for precise definition} +polygon (\f$ f \f$ has no isolated vertices and each boundary edge of \f$ f \f$ separates it from another face). +For this purpose every model of the Visibility_2 concept provides two overloaded member functions, called `Visibility_2::compute_visibility()` +functions, that compute the visibility region of \f$ p \f$ in a bounded polygonal face \f$ f \f$: one is for the case where +\f$ p \f$ is in the interior of \f$ f \f$; the other one is for the case where \f$ p \f$ is on the boundary of \f$ f \f$. + + +The package provides the following models of the `Visibility_2` concept: + +Class | Function | Preprocessing | Query |Algorithm +-------------------------------|-----------------------------------------------------|-------------------------------|-----------------------------------|------------------------------- + `Simple_polygon_visibility_2` | simple valid polygons | No |\f$ O(n) \f$ time and \f$ O(n) \f$ space | B.Joe and R.B.Simpson \cite bjrb-clvpa-87 + `Rotational_sweep_visibility_2` | valid polygons with holes | No | \f$ O(n\log n) \f$ time and \f$ O(n) \f$ space | T.Asano \cite ta-aeafvpprh-85 +`Triangular_expansion_visibility_2` | valid polygons with holes | \f$ O(n) \f$ time and \f$ O(n) \f$ space | \f$ O(nh) \f$ time and \f$ O(n) \f$ space. | new + + +Where \f$ n \f$ is the number of vertices of \f$ f \f$ and \f$ h \f$ is the number of holes+1. + +\section benchmarks Runtime in Practice + +\cgalFigureBegin{cathedral-fig, cathedral_2.png} +Example environment representing a cathedral. +\cgalFigureEnd + +The left hand side of Figure \cgalFigureRef{cathedral-fig} depicts the outer boundary of a cathedral, +which is a simple polygon with 565 vertices. The right hand side shows the cathedral also with its inner +pillars, which is a polygon with 1153 vertices. The following table shows the total runtime to compute +all visibility polygons for all vertices of the boundary of the cathedral. + + +Boundary Cathedral | total preprocessing time | total query time | +-------------------------------|-----------------------------------------------------|-------------------------------| + `Simple_polygon_visibility_2` | - | 0.38 | + `Rotational_sweep_visibility_2` | - | 1.01 | +`Triangular_expansion_visibility_2` | 0.01 | 0.06 | + +The second table shows the same for the complete cathedral. The table does not report the time for `Simple_polygon_visibility_2` +as this algorithm can only handle simple polygons. + +Complete Cathedral | total preprocessing time | total query time | +-------------------------------|-----------------------------------------------------|-------------------------------| + `Rotational_sweep_visibility_2` | - | 1.91 | + `Triangular_expansion_visibility_2` | 0.01 | 0.04 | + +Thus, in general we recommend to use `Triangular_expansion_visibility_2` even if the polygon is simple. The main advantage +of the algorithm is its locality. After the triangle that contains the query point is located in the triangulation, +the algorithm explores neighboring triangles, but only those that are actually seen. In this sense the algorithm can be +considered as output sensitive. However, if the simple polygon is rather convex (i.e., nearly all boundary is seen) or +if only one (or very little) queries are required, using one of the algorithms that does not require preprocessing is advantageous. + + +\section simple_polygon_visibility_example Example of Visibility in a Simple Polygon +The following example shows how to obtain the regularized and non-regularized visibility regions. +\cgalExample{Visibility_2/simple_polygon_visibility_2.cpp} + +\section general_polygon_example Example of Visibility in a Polygon with Holes +The following example shows how to obtain the regularized visibility region using the model `Triangular_expansion_visibility_2`. See \cgalFigureRef{general_polygon}. The arrangement has six bounded faces and an unbounded face. The query point \f$ q \f$ is on a vertex. The red arrow denotes the halfedge \f$ \overrightarrow{pq} \f$, which also identifies the face in which the visibility region is computed. +\cgalFigureBegin{general_polygon, general_polygon_example.png} +The visibility region of \f$ q \f$ in a polygon with two holes. +\cgalFigureEnd +\cgalExample{Visibility_2/general_polygon_example.cpp} + +\section implentation_history Implementation History + +This package was first developed during Google Summer of Code 2013. Fancisc Bungju developed the Simple_polygon_visibility_2 class; Kan Huang developed the Rotational_sweep_visibility_2 class; and Michael Hemmer developed the Triangular_expansion_visibility_2 class. + +This first class, Simple_polygon_visibility_2, implements the algorithm presented by B. Joe and R.B. Simpson in 1987 \cite js-clvpa87. This algorithm is a linear time algorithm for simple polygons, fixing the errors in a previous algorithm presented by D.T. Lee in 1983. + +The second class, Rotational_sweep_visibility_2, implements the algorithm presented by T. Asano in 1985. This algorithm can be applied to polygons with holes with time complexity \f$ O(n\log n) \f$. + +The third class, Triangular_expansion_visibility_2, implements the algorithm presented by F. Bungju, et al.. This algorithm can be applied to polygons with holes with worst case running time \f$ O(n^2) \f$, but is extremely fast in practice. + +In Google Summer of Code 2014, Ning Xu became a developer for this package. He fixed bugs in the algorithm for simple polygons. + +*/ + +} + +// `Preprocessed_rotational_sweep_visibility_2` | valid polygons with holes | \f$ O(n^2) \f$ time and \f$ O(n^2) \f$ space | \f$ O(n) \f$ time and \f$ O(n) \f$ space | Takao Asano, Tetsuo Asano etc \cite aaghi-vpsesp-85 diff --git a/Visibility_2/examples/Visibility_2/general_polygon_example.cpp b/Visibility_2/examples/Visibility_2/general_polygon_example.cpp new file mode 100644 index 00000000000..38e4ae9d6da --- /dev/null +++ b/Visibility_2/examples/Visibility_2/general_polygon_example.cpp @@ -0,0 +1,56 @@ + +#include +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef Kernel::Point_2 Point_2; +typedef Kernel::Segment_2 Segment_2; +typedef CGAL::Arr_segment_traits_2 Traits_2; +typedef CGAL::Arrangement_2 Arrangement_2; +typedef Arrangement_2::Vertex_const_handle Vertex_const_handle; +typedef Arrangement_2::Halfedge_const_handle Halfedge_const_handle; +typedef Arrangement_2::Face_handle Face_handle; +typedef CGAL::Triangular_expansion_visibility_2 TEV; +int main() { + Point_2 p1(1, 2), p2(12, 3), p3(19, -2), p4(12, 6), p5(14, 14), p6(9, 5); + Point_2 h1(8,3), h2(10, 3), h3(8, 4), h4(10, 6), h5(11, 6), h6(11, 7); + Segment_2 s[12]; + s[0] = Segment_2(p1, p2); + s[1] = Segment_2(p2, p3); + s[2] = Segment_2(p3, p4); + s[3] = Segment_2(p4, p5); + s[4] = Segment_2(p5, p6); + s[5] = Segment_2(p6, p1); + + s[6] = Segment_2(h1, h2); + s[7] = Segment_2(h2, h3); + s[8] = Segment_2(h3, h1); + s[9] = Segment_2(h4, h5); + s[10] = Segment_2(h5, h6); + s[11] = Segment_2(h6, h4); + Arrangement_2 env; + CGAL::insert_non_intersecting_curves(env, &s[0], &s[12]); + //find the halfedge whose target is the query point. + Point_2 query_point = p4; + Halfedge_const_handle he = env.halfedges_begin(); + while (he->source()->point() != p3 || he->target()->point() != p4) + he++; + //visibility query + Arrangement_2 output_arr; + TEV tev(env); + Face_handle fh = tev.compute_visibility(query_point, he, output_arr); + //print out the visibility region. + std::cout << "Regularized visibility region of q has " + << output_arr.number_of_edges() + << " edges." << std::endl; + Arrangement_2::Ccb_halfedge_circulator curr = fh->outer_ccb(); + std::cout << "Traverse the face of the visibility region." << std::endl; + std::cout << "[" << curr->curve() << "]"<< std::endl; + while (++curr != fh->outer_ccb()) + std::cout << "[" << curr->curve() << "]" << std::endl; + return 0; +} diff --git a/Visibility_2/examples/Visibility_2/simple_polygon_visibility_2.cpp b/Visibility_2/examples/Visibility_2/simple_polygon_visibility_2.cpp new file mode 100644 index 00000000000..43adf31904e --- /dev/null +++ b/Visibility_2/examples/Visibility_2/simple_polygon_visibility_2.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef Kernel::Point_2 Point_2; +typedef Kernel::Segment_2 Segment_2; +typedef CGAL::Arr_segment_traits_2 Traits_2; +typedef CGAL::Arrangement_2 Arrangement_2; +typedef Arrangement_2::Edge_const_iterator Edge_const_iterator; +typedef Arrangement_2::Face_handle Face_handle; +typedef Arrangement_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; +typedef CGAL::Simple_polygon_visibility_2 + NSPV; +typedef CGAL::Simple_polygon_visibility_2 + RSPV; + +int main() { + //create environment + Point_2 p1(0, 4), p2(0, 0), p3(3, 2), p4(4, 0), p5(4, 4), p6(1, 2); + Segment_2 s[6]; + s[0] = Segment_2(p1, p2); + s[1] = Segment_2(p2, p3); + s[2] = Segment_2(p3, p4); + s[3] = Segment_2(p4, p5); + s[4] = Segment_2(p5, p6); + s[5] = Segment_2(p6, p1); + Arrangement_2 env; + CGAL::insert_non_intersecting_curves(env, &s[0], &s[6]); + //locate the query point in the arrangement + Point_2 query_point(0.5, 2); + Arrangement_2::Face_const_handle face; + CGAL::Arr_naive_point_location pl(env); + CGAL::Object obj = pl.locate(query_point); + CGAL::assign(face, obj); + //visibility query + Arrangement_2 non_regular_output; + NSPV non_regular_visibility(env); + Face_handle non_regular_fh = non_regular_visibility.compute_visibility(query_point, face, non_regular_output); + std::cout << "Non-regularized visibility region of q has " + << non_regular_output.number_of_edges() + << " edges:" << std::endl; + for (Edge_const_iterator eit = non_regular_output.edges_begin(); eit != non_regular_output.edges_end(); ++eit) + std::cout << "[" << eit->curve() << "]" << std::endl; + Arrangement_2 regular_output; + RSPV regular_visibility(env); + Face_handle regular_fh = regular_visibility.compute_visibility(query_point, face, regular_output); + Ccb_halfedge_circulator curr = regular_fh->outer_ccb(); + std::cout << "Regularized visibility region of q has " + << regular_output.number_of_edges() + << " edges:" << std::endl; + for (Edge_const_iterator eit = regular_output.edges_begin(); eit != regular_output.edges_end(); ++eit) + std::cout << "[" << eit->curve() << "]" << std::endl; + + //For a regular face, we can also get its whole boundary by traversing its outer CCB. + std::cout << "Traverse the face of the regularized visibility region:" << std::endl; + std::cout << "[" << curr->curve() << "]"<< std::endl; + while (++curr != regular_fh->outer_ccb()) + std::cout << "[" << curr->curve() << "]" << std::endl; + return 0; +} + diff --git a/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..29384febac4 --- /dev/null +++ b/Visibility_2/include/CGAL/Parallel_rotational_sweep_visibility_2.h @@ -0,0 +1,1008 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Ning Xu +// + +#ifndef CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H +#define CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H + +#include +#include +#include +#include +#include +#include + +//#define MYDEBUG +#ifdef MYDEBUG + #include + using namespace std; +#endif + +namespace CGAL { + +template < class Arrangement_2_, class RegularizationTag = CGAL::Tag_true > +class Rotational_sweep_visibility_2 +{ +public: + typedef Arrangement_2_ Arrangement_2; + typedef RegularizationTag Regularization_tag; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Traits_2 Traits_2; + typedef CGAL::Tag_true Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Ray_2 Ray_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Direction_2 Direction_2; + + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Hole_const_iterator Hole_const_iterator; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Circulator; + + +private: + template < class Arr_2_ED > + class Edge + { + public: + typedef Arr_2_ED Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Circulator; + private: + Circulator circ; + CGAL::Orientation orient; + CGAL::Orientation boundary_orient; + enum { NOT_APPLIED, INWARD, OUTWARD, IN_EDGE, AT_SOURCE, AT_TARGET } mode; + int idx; + int prev_idx; + int quad; + private: + int compute_quad( const Point_2& query_pt, const Point_2& p ) + { + CGAL::Comparison_result cx = CGAL::compare_x( query_pt, p ); + CGAL::Comparison_result cy = CGAL::compare_y( query_pt, p ); + if ( cy == CGAL::SMALLER ) { + if ( cx == CGAL::SMALLER ) + return 0; + else + return 1; + } else if ( cy == CGAL::LARGER ) { + if ( cx == CGAL::LARGER ) + return 2; + else + return 3; + } else { + if ( cx != CGAL::LARGER ) + return 0; + else + return 2; + } + } + public: + Edge ( const Point_2& query_pt, const Circulator& he, bool on_edge, bool on_vertex ) + : circ( he ) + { + if ( on_vertex ) { + orient = CGAL::COLLINEAR; + if ( query_pt == he->source()->point() ) + mode = AT_SOURCE; + else if ( query_pt == he->target()->point() ) + mode = AT_TARGET; + else + mode = IN_EDGE; + } else if ( on_edge ) { + orient = CGAL::COLLINEAR; + mode = IN_EDGE; + } else { + orient = CGAL::orientation( query_pt, + he->source()->point(), + he->target()->point() ); + if ( orient == CGAL::COLLINEAR ) { + if ( CGAL::collinear_are_ordered_along_line( query_pt, + he->source()->point(), + he->target()->point() ) ) + mode = OUTWARD; + else + mode = INWARD; + } else { + mode = NOT_APPLIED; + } + } + quad = compute_quad( query_pt, he->source()->point() ); + boundary_orient = CGAL::orientation( prev_source(), source(), target() ); + } + void set_index ( int i, int p ) + { idx = i; prev_idx = p; } + + const Point_2& source () const + { return circ->source()->point(); } + const Point_2& target () const + { return circ->target()->point(); } + const Point_2& prev_source() const + { return circ->prev()->source()->point(); } + const Point_2& next_target() const + { return circ->next()->target()->point(); } + Circulator circulator () const + { return circ; } + CGAL::Orientation orientation () const + { return orient; } + CGAL::Orientation boundary_orientation () const + { return boundary_orient; } + bool inward () const + { return ( mode == INWARD ); } + bool outward () const + { return ( mode == OUTWARD ); } + bool in_edge () const + { return ( mode == IN_EDGE ); } + bool at_source () const + { return ( mode == AT_SOURCE ); } + bool at_target () const + { return ( mode == AT_TARGET ); } + int index () const + { return idx; } + int prev_index () const + { return prev_idx; } + int quadrant () const + { return quad; } + bool angle_less_than_pi () const + { return ( quadrant() < 2 ); } + +#ifdef MYDEBUG + void trace ( ostream& os ) + { + os << "source=[" << source() << "],target=[" << target() << "],"; + os << "orientation=["; + switch( orient ) { + case CGAL::LEFT_TURN: + os << "left"; + break; + case CGAL::RIGHT_TURN: + os << "right"; + break; + case CGAL::COLLINEAR: + os << "collinear"; + break; + } + os << "],mode =["; + switch( mode ) { + case INWARD: + os << "inward"; + break; + case OUTWARD: + os << "outward"; + break; + case IN_EDGE: + os << "in_edge"; + break; + case AT_SOURCE: + os << "at_source"; + break; + case AT_TARGET: + os << "at_target"; + break; + case NOT_APPLIED: + os << "not_applied"; + break; + } + os << "]" << endl; + os << "\t\tquadrant=[" << quadrant() << "], idx=[" << index() << "], prev_idx=[" << prev_index() << "]" << endl; + } +#endif + }; + + /* + class Less_Source + Compare the halfedges with their source point by their polar angle. + The class rovides a comparator: + Less_Source( const Edge_type& he1, const Edge_type& he2 ) + where he1 and he2 are two half edges. + + Precondition: he1 != he2 + + Special cases: + 1) If two source points have the same angle, the halfedge goes outward + or makes a right turn is less than the halfedge goes inward + or makes a left turn. + If two halfedges both go outward or make a right turn, the one with + closer source point is less. + If two halfedges both go inward or make a left turn, the one with + farther source point is less. + 2) If the source of an halfedge is the query point, consider the case + as moving the source point slightly along the line through the + halfedge, either toward the target or away the target, so that + the query point is still in the face. + */ + template < class E > + class Less_Source + { + private: + typedef E Edge_type; + typedef typename E::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + private: + // less_source_at_query_pt + // Precondition: he1.source() == query_pt + bool less_source_at_query_pt( const Edge_type& he1, const Edge_type& he2 ) + { + CGAL::Orientation orient1 = he1.boundary_orientation(); + CGAL::Orientation orient2 = CGAL::orientation( he1.source(), he1.target(), he2.source() ); + if ( orient1 == CGAL::LEFT_TURN ) { + // The boundary makes a left turn at query_pt + // Consider the case as moving he1.source() slightly + // along the line through he1, away he1.target() + if ( orient2 == CGAL::COLLINEAR ) { + // he1.source(), he1.target(), he2.source() are collinear + if ( CGAL::collinear_are_ordered_along_line( he2.source(), he1.source(), he1.target() ) ) { + // he1.source() is between he1.target() and he2.source() + // he1 will be considered going inward + return false; + } else { + // he1.source(), he1.target(), he2.source() are ordered along ray + return !he2.angle_less_than_pi(); + } + } else if ( orient2 == CGAL::LEFT_TURN ) { + // he1.source(), he1.target(), he2.source() make a left turn + if ( he2.angle_less_than_pi() ) { + return false; + } else { + return ( he1.target().y() < query_pt.y() || + ( he1.target().y() == query_pt.y() && + he1.target().x() < query_pt.x() ) ); + } + } else { + // he1.source(), he1.target(), he2.source() make a right turn + if ( he2.angle_less_than_pi() ) { + return ( he1.target().y() < query_pt.y() || + ( he1.target().y() == query_pt.y() && + he1.target().x() < query_pt.x() ) ); + } else { + return true; + } + } + } else { + // The boundary makes a right turn at query_pt, + // or does not make a turn at query_pt. + // Consider the case as moving he1.source() slightly + // along the line through he1, toward he1.target() + if ( orient2 == CGAL::COLLINEAR ) { + // he1.source(), he1.target(), he2.source() are collinear + if ( CGAL::collinear_are_ordered_along_line( he2.source(), he1.source(), he1.target() ) ) { + // he1.source() is between he1.target() and he2.source() + return !he2.angle_less_than_pi(); + } else { + // he1.source(), he1.target(), he2.source() are ordered along ray + return true; + } + } else if ( orient2 == CGAL::LEFT_TURN ) { + // he1.source(), he1.target(), he2.source() make a left turn + if ( he2.angle_less_than_pi() ) { + return ( he1.target().y() > query_pt.y() || + ( he1.target().y() == query_pt.y() && + he1.target().x() > query_pt.x() ) ); + } else { + return true; + } + } else { + // he1.source(), he1.target(), he2.source() make a right turn + if ( he2.angle_less_than_pi() ) { + return false; + } else { + return ( he1.target().y() > query_pt.y() || + ( he1.target().y() == query_pt.y() && + he1.target().x() > query_pt.x() ) ); + } + } + } + } + // less + bool less ( const Edge_type& he1, const Edge_type& he2 ) + { + if ( he2.at_source() ) + return !less_source_at_query_pt( he2, he1 ); + if ( he1.at_source() ) + return less_source_at_query_pt( he1, he2 ); + + if ( he1.quadrant() != he2.quadrant() ) + return ( he1.quadrant() < he2.quadrant() ); + // In the same quadrant + CGAL::Orientation orient = CGAL::orientation( query_pt, he1.source(), he2.source() ); + if ( orient != CGAL::COLLINEAR ) { + // General case, in the same quadrant + return ( orient == CGAL::LEFT_TURN ); + } else { + // query_pt, he1.source(), he2.source() are collinear on a ray + if ( CGAL::collinear_are_ordered_along_line( query_pt, he1.source(), he2.source() ) ) { + // he1.source() is closer + return ( he1.orientation() == CGAL::RIGHT_TURN || he1.outward() ); + } else { + // he2.source() is closer + return !( he2.orientation() == CGAL::RIGHT_TURN || he2.outward() ); + } + } + } + public: + // Constructor + Less_Source( const Point_2& q ) + : query_pt( q ) + {} + // Comparator + // Precondition: he1 and he2 are not the same halfedge + bool operator () ( const Edge_type& he1, const Edge_type& he2 ) + { return less( he1, he2 ); } + private: + Point_2 query_pt; + Point_2 aux; + }; + + /* + class Less_Edge + Compare the halfedges intersecting a ray, find whose intersection point + is closer to the query point. + The class rovides a comparator: + Less_Edge( const Edge_type& he1, const Edge_type& he2 ) + where he1 and he2 are two half edges. + + Precondition: he1 != he2 + */ + template < class E > + class Less_Edge + { + private: + typedef E Edge_type; + typedef typename E::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + private: + Point_2 query_pt; + private: + // less_vertex + // Precondition: (1) he1 contains query_pt + // (2) he2 does not contain query_pt + bool less_vertex ( const Edge_type& he1, const Edge_type& he2 ) + { + assert( !(he2.at_source() || he2.at_target() || he2.in_edge() ) ); + return true; + } + // less_consecutive + // Precondition: (1) Both he1 and he2 does not contain query_pt + // (2) he1 is the previous halfedge of he2 + bool less_consecutive ( const Edge_type& he1, const Edge_type& he2 ) + { + if ( he1.outward() ) + return true; + else if ( he1.inward() ) + return false; + else if ( he1.orientation() == CGAL::LEFT_TURN ) { + return ( he2.boundary_orientation() == CGAL::RIGHT_TURN ); + } else { + // he1.orientation() == CGAL::RIGHT_TURN + return ( he2.boundary_orientation() != CGAL::RIGHT_TURN ); + } + } + // less_collinear + // Precondition: (1) Both he1 and he2 does not contain query_pt + // (2) he1 and he2 are not incident + // (3) query_pt, he1.source(), he1.target() are collinear + bool less_collinear ( const Edge_type& he1, const Edge_type& he2 ) + { + if ( he2.inward() || he2.outward() ) { + return CGAL::collinear_are_ordered_along_line( query_pt, + he1.source(), + he2.source() ); + } else { + return ( CGAL::orientation( he2.source(), he2.target(), he1.source() ) + == he2.orientation() ); + } + } + // less_general + // Precondition: (1) Both he1 and he2 does not contain query_pt + // (2) he1 and he2 are not incident + // (3) he1.orientation() == CGAL::LEFT_TURN || RIGHT_TURN + // (4) he2.orientation() == CGAL::LEFT_TURN || RIGHT_TURN + bool less_general ( const Edge_type& he1, const Edge_type& he2 ) + { + CGAL::Orientation orient1 = CGAL::orientation( he1.source(), + he1.target(), + he2.source() ); + CGAL::Orientation orient2 = CGAL::orientation( he1.source(), + he1.target(), + he2.target() ); + if ( orient1 == orient2 ) { + // he2.source() and he2.target() lies on the same side of he1 + return ( CGAL::orientation( he1.source(), he1.target(), query_pt ) + != orient1 ); + } else { + // he2.source() and he2.target() lies on the different side of he1 + return ( CGAL::orientation( he2.source(), he2.target(), he1.source() ) + == he2.orientation() ); + } + } + // less + bool less ( const Edge_type& he1, const Edge_type& he2 ) + { + if ( he1.circulator() == he2.circulator() ) + return false; + if ( he1.at_source() || he1.at_target() || he1.in_edge() ) + return less_vertex( he1, he2 ); + if ( he2.at_source() || he2.at_target() || he2.in_edge() ) + return !less_vertex( he2, he1 ); + if ( he1.index() == he2.prev_index() ) + return less_consecutive( he1, he2 ); + if ( he1.prev_index() == he2.index() ) + return !less_consecutive( he2, he1 ); + if ( he1.inward() || he1.outward() ) + return less_collinear( he1, he2 ); + if ( he2.inward() || he2.outward() ) + return !less_collinear( he2, he1 ); + return less_general( he1, he2 ); + } + public: + Less_Edge ( const Point_2& q ) + : query_pt( q ) + {} + bool operator () ( const Edge_type& he1, const Edge_type& he2 ) + { return less( he1, he2 ); } + }; + + template < class E, class Comp > + class Active_Edge + { + private: + typedef E Edge_type; + typedef Comp Sorter; + typedef typename E::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename std::set Active_edge_container; + typedef typename std::vector Edge_vector; + private: + Active_edge_container active_edges; + const Edge_vector * p_edges; + std::vector active; + public: + Active_Edge ( const Edge_vector * pe, const Sorter& s ) + : p_edges( pe ), active_edges( s ) + { active.assign( pe->size(), false ); } + + void insert ( const Edge_type& he ) + { + active_edges.insert( he ); + active[he.index()] = true; + } + void erase ( const Edge_type& he ) + { + active_edges.erase( he ); + active[he.index()] = false; + } + void replace ( const Edge_type& he1, const Edge_type& he2 ) + { + typename Active_edge_container::const_iterator ait; + ait = active_edges.find( he1 ); + assert( ait != active_edges.end() ); + const Edge_type& const_he = *ait; + Edge_type& tmp_he = const_cast(const_he); + tmp_he = he2; + active[he1.index()] = false; + active[he2.index()] = true; + } + bool is_active( int idx ) const + { return active[idx]; } + const Edge_type& closest () const + { return *(active_edges.begin()); } +#ifdef MYDEBUG + void trace ( ostream& os ) + { + typename Active_edge_container::const_iterator ait; + for( ait = active_edges.begin(); ait != active_edges.end(); ait++ ) { + cout << "Edge: " << ait->source() << " --> " << ait->target() << endl; + } + cout << "Active:[ "; + for ( int i = 0; i < active.size(); i++ ) { + if ( active[i] ) + cout << i << " "; + } + cout << "]" << endl; + } +#endif + }; + +private: + typedef Edge Edge_type; + typedef std::vector Edge_vector; + typedef typename Edge_vector::const_iterator Edge_iterator; + typedef Less_Edge Active_edge_sorter; + +private: + // do_intersect_ray + // Verify whether the halfedge he will intersect the ray obtained by + // by slightly rotating the ray (query_pt, aux ) clockwisely + bool do_intersect_ray ( const Point_2& query_pt, const Point_2& aux, const Edge_type& he ) + { + if ( he.orientation() != CGAL::COLLINEAR ) { + CGAL::Orientation orient1 = CGAL::orientation( query_pt, aux, he.source() ); + CGAL::Orientation orient2 = CGAL::orientation( query_pt, aux, he.target() ); + if ( orient1 == orient2 ) + return false; + if ( orient1 == CGAL::COLLINEAR ) { + if ( CGAL::collinear_are_ordered_along_line( aux, query_pt, he.source() ) ) + return false; + // Ray intersects he at he.source() + return ( he.orientation() == CGAL::RIGHT_TURN ); + } else if ( orient2 == CGAL::COLLINEAR ) { + if ( CGAL::collinear_are_ordered_along_line( aux, query_pt, he.target() ) ) + return false; + // Ray intersects he at he.target() + return ( he.orientation() == CGAL::LEFT_TURN ); + } else { + return ( CGAL::orientation( query_pt, aux, he.target() ) == he.orientation() ); + } + } else if ( he.inward() || he.outward() ) { + return false; + } else if ( he.at_source() ) { + CGAL::Orientation orient1 = CGAL::orientation( he.prev_source(), he.source(), he.target() ); + if ( orient1 == CGAL::LEFT_TURN ) { + // The boundary makes a left turn at the query_pt + // Consider the case as moving he.source() slightly along the line + // through he, away he.target() + CGAL::Orientation orient2 = CGAL::orientation( he.source(), he.target(), aux ); + if ( orient2 == CGAL::LEFT_TURN ) { + return false; + } else if ( orient2 == CGAL::RIGHT_TURN ) { + return true; + } else { + // he.source(), he.target(), aux ) are collinear + return !CGAL::collinear_are_ordered_along_line( aux, he.source(), he.target() ); + } + } else { + // The boundary makes a right turn or does not turn at the query_pt + // Consider the case as moving he.source() slightly along the line + // through he, toward he.target() + return false; + } + } else if ( he.at_target() ) { + CGAL::Orientation orient1 = CGAL::orientation( he.source(), he.target(), he.next_target() ); + if ( orient1 == CGAL::LEFT_TURN ) { + // The boundary makes a left turn at the query_pt + CGAL::Orientation orient2 = CGAL::orientation( he.target(), he.next_target(), aux ); + if ( orient2 == CGAL::LEFT_TURN ) { + return ( CGAL::orientation( he.source(), he.target(), aux ) == CGAL::RIGHT_TURN ); + } else if ( orient2 == CGAL::RIGHT_TURN ) { + return false; + } else { + return CGAL::collinear_are_ordered_along_line( aux, he.target(), he.next_target() ); + } + } else if ( orient1 == CGAL::RIGHT_TURN ) { + // The boundary makes a right turn at the query_pt + CGAL::Orientation orient2 = CGAL::orientation( he.target(), he.next_target(), aux ); + if ( orient2 == CGAL::LEFT_TURN ) { + return false; + } else if ( orient2 == CGAL::RIGHT_TURN ) { + return ( CGAL::orientation( he.source(), he.target(), aux ) == CGAL::RIGHT_TURN ); + } else { + return !CGAL::collinear_are_ordered_along_line( aux, he.target(), he.next_target() ); + } + } + } else { + // he.in_edge() == true + CGAL::Orientation orient1 = CGAL::orientation( query_pt, he.target(), aux ); + if ( orient1 == CGAL::LEFT_TURN ) { + return false; + } else if ( orient1 == CGAL::RIGHT_TURN ) { + return true; + } else { + return !CGAL::collinear_are_ordered_along_line( aux, query_pt, he.target() ); + } + } + } + Point_2 calculate_intersection( const Point_2& query_pt, const Point_2& aux, const Circulator& he ) + { + Ray_2 ray ( query_pt, aux ); + Segment_2 seg ( he->source()->point(), he->target()->point() ); + CGAL::Object res = CGAL::intersection( ray, seg ); + const Point_2 * ipoint = CGAL::object_cast(&res); + if ( ipoint ) { + return *ipoint; + } else { + assert( seg.has_on( query_pt ) ); + return query_pt; + } + } + void compute_visibility_partition ( const Point_2& query_pt, + Edge_iterator first, + Edge_iterator last, + std::vector& out_points ) + { + Point_2 aux; + Active_edge_sorter closer( query_pt ); + Active_Edge< Edge_type, Active_edge_sorter > active( &unsorted_edges, closer ); + + // Initialize the edges intersecting the ray + aux = first->source(); + if ( query_on_vertex && query_pt == aux ) { + CGAL::Orientation orient1 = CGAL::orientation( first->prev_source(), first->source(), first->target() ); + if ( orient1 == CGAL::LEFT_TURN ) { + aux = Point_2( query_pt.x()+query_pt.x()-first->target().x(), query_pt.y()+query_pt.y()-first->target().y() ); + } else { + aux = first->target(); + } + } + + for ( Edge_iterator eit = edges.begin(); eit != edges.end(); eit++ ) { + if ( do_intersect_ray( query_pt, aux, *eit ) ) { + active.insert( *eit ); + } + } + +#ifdef MYDEBUG +cout << "query_pt = [" << query_pt << "]" <source(); + int idx = eit->index(); + int prev = eit->prev_index(); + Circulator top = active.closest().circulator(); + assert( unsorted_edges[idx].circulator() == eit->circulator() ); + +#ifdef MYDEBUG +cout << "idx = " << idx << " , prev = " << prev << endl; +cout << "Current edge: " << eit->source() << " --> " << eit->target() << " Previous edge: " << unsorted_edges[prev].source() << " --> " << unsorted_edges[prev].target() << endl; +cout << "top: " << top->source()->point() << " --> " << top->target()->point() << endl; +#endif + + if ( active.is_active( idx ) && active.is_active( prev ) ) { + // Both edges incident to the current vertex are active +#ifdef MYDEBUG +cout << "Both Active!" << endl; +#endif + + active.erase( *eit ); + active.erase( unsorted_edges[prev] ); + if ( top != active.closest().circulator() ) { + Point_2 u; + u = calculate_intersection( query_pt, aux, active.closest().circulator() ); + if ( last_pt != eit->source() ) + out_points.push_back( eit->source() ); + out_points.push_back( u ); + last_pt = u; +#ifdef MYDEBUG +cout << "New Top! Intersection = " << u << endl; +#endif + } + } else if ( active.is_active( idx ) ) { +#ifdef MYDEBUG +cout << "Current Active!" << endl; +#endif + // Only one edge whose source is the current vertex is active. + active.replace( *eit, unsorted_edges[prev] ); + if ( top != active.closest().circulator() ) { + if ( last_pt != eit->source() ) { + out_points.push_back( eit->source() ); + last_pt = eit->source(); + } +#ifdef MYDEBUG +cout << "New Top! Intersection = " << eit->source() << endl; +#endif + } + } else if ( active.is_active( prev ) ) { +#ifdef MYDEBUG +cout << "Previous Active!" << endl; +#endif + // Only one edge whose target is the current vertex is active. + active.replace( unsorted_edges[prev], *eit ); + if ( top != active.closest().circulator() ) { + if ( last_pt != eit->source() ) { + out_points.push_back( eit->source() ); + last_pt = eit->source(); + } +#ifdef MYDEBUG +cout << "New Top! Intersection = " << eit->source() << endl; +#endif + } + } else { + // Both edges incident to the current vertex are not active +#ifdef MYDEBUG +cout << "Both Inctive!" << endl; +#endif + active.insert( *eit ); + active.insert( unsorted_edges[prev] ); + if ( top != active.closest().circulator() ) { + Point_2 u; + if ( query_on_vertex && query_pt == aux ) + u = aux; + else + u = calculate_intersection( query_pt, aux, top ); + if ( last_pt != u ) + out_points.push_back( u ); + out_points.push_back( eit->source() ); + last_pt = eit->source(); +#ifdef MYDEBUG +cout << "New Top! Intersection = " << u << endl; +#endif + } + } +#ifdef MYDEBUG +cout << "*** After Iteration ***" << endl; +active.trace( cout ); +cout << endl; +#endif + } + + if ( first_pt != last_pt ) { + if ( first_at_vertex || + ( CGAL::orientation( out_points.front(), out_points.back(), first_pt ) != CGAL::COLLINEAR ) ) + out_points.push_back( first_pt ); + } +#ifdef MYDEBUG +cout << "Visibility segments:" << endl; +for ( int i = 0; i < out_points.size(); i++ ) { + cout << out_points[i] << endl; +} +cout << endl; +#endif + } + + + template < class VARR > + typename VARR::Face_handle + compute_visibility_impl ( const Point_2& query_pt, VARR& arr_out ) + { + Point_2 aux( query_pt.x()+Number_type(1), query_pt.y() ); + Less_Source comp ( query_pt ); + // Sort halfedges with their source point by polar angle + std::sort( edges.begin(), edges.end(), comp ); +#ifdef MYDEBUG +for ( int i = 0; i < edges.size(); i++ ) { + for ( int j = 0; j < edges.size(); j++ ) { + if ( i == j ) + continue; + bool res = comp( edges[i], edges[j] ); + if ( res != ( i < j ) ) { + cout << "WRONG: Edges1: " << edges[i].source() << " --> " << edges[i].target() << " "; + cout << "Edges2: " << edges[j].source() << " --> " << edges[j].target() << " "; + if ( res ) + cout << "Result: 1<2" < vec; + compute_visibility_partition( query_pt, edges.begin(), edges.end(), vec ); + + // Construct arrangement + CGAL::Visibility_2::report_while_handling_needles + < Rotational_sweep_visibility_2 > + ( geom_traits, query_pt, vec, arr_out ); + + conditional_regularize( arr_out, Regularization_tag() ); + + edges.clear(); + unsorted_edges.clear(); + + return arr_out.faces_begin(); + } + + /*! Regularize output if flag is set to true*/ + template + void conditional_regularize(VARR& out_arr, CGAL::Tag_true) { + regularize_output(out_arr); + } + /*! No need to regularize output if flag is set to false*/ + template + void conditional_regularize(VARR& out_arr, CGAL::Tag_false) { + //do nothing + } + + /*! Regularizes the output - removes edges that have the same face on both + sides */ + template + void regularize_output(VARR& out_arr) { + typename VARR::Edge_iterator e_itr; + for (e_itr = out_arr.edges_begin() ; + e_itr != out_arr.edges_end() ; e_itr++) { + + typename VARR::Halfedge_handle he = e_itr; + typename VARR::Halfedge_handle he_twin = he->twin(); + if (he->face() == he_twin->face()) { + out_arr.remove_edge(he); + } + } + } + +public: + // Constructor + Rotational_sweep_visibility_2 () + : p_arr( NULL ), geom_traits( NULL ) + {} + Rotational_sweep_visibility_2 ( const Arrangement_2& arr ) + : p_arr( &arr ) + { geom_traits = p_arr->geometry_traits(); } + + const std::string name () + { return std::string( "R_visibility_2" ); } + bool is_attached () const + { return (p_arr != NULL); } + void attach ( const Arrangement_2& arr ) + { p_arr = &arr; geom_traits = p_arr->geometry_traits(); } + void detach () + { p_arr = NULL; geom_traits = NULL; } + const Arrangement_2& arr () const + { return *p_arr; } + + template < typename VARR > + typename VARR::Face_handle + compute_visibility ( const Point_2& query_pt, + const Halfedge_const_handle he, + VARR& arr_out ) + { + Face_const_handle f = he->face(); + assert( !f->is_unbounded() ); + + Halfedge_const_handle he2 = he; + query_on_edge = true; + query_on_vertex = false; + if ( query_pt == he2->target()->point() ) + he2 = he2->next(); + if ( query_pt == he2->source()->point() ) + query_on_vertex = true; + + arr_out.clear(); + edges.clear(); + + Circulator circ, curr; + Circulator qedge( he2 ); + Circulator qprev( he2->prev() ); + + int hole_base = 0, hole_edge = 0; + + if ( f->has_outer_ccb() ) { + curr = circ = f->outer_ccb(); + do { + bool on_edge = false, on_vertex = false; + if ( curr == qedge ) { + on_edge = true; + on_vertex = query_on_vertex; + } else if ( curr == qprev ) { + on_edge = on_vertex = query_on_vertex; + } + edges.push_back( Edge_type( query_pt, curr, on_edge, on_vertex ) ); + hole_edge++; + } while ( ++curr != circ ); + for ( int i = 0; i < hole_edge; i++ ) { + edges[hole_base+i].set_index( hole_base+i, hole_base+(i+hole_edge-1)%hole_edge ); + } + hole_base += hole_edge; + } + for ( Hole_const_iterator hi = f->holes_begin(); + hi != f->holes_end(); hi++ ) { + curr = circ = *hi; + hole_edge = 0; + do { + bool on_edge = false, on_vertex = false; + if ( curr == qedge ) { + on_edge = true; + on_vertex = query_on_vertex; + } else if ( curr == qprev ) { + on_edge = on_vertex = query_on_vertex; + } + edges.push_back( Edge_type( query_pt, curr, on_edge, on_vertex ) ); + hole_edge++; + } while ( ++curr != circ ); + for ( int i = 0; i < hole_edge; i++ ) { + edges[hole_base+i].set_index( hole_base+i, hole_base+(i+hole_edge-1)%hole_edge ); + } + hole_base += hole_edge; + } + + unsorted_edges.assign( edges.begin(), edges.end() ); + + return compute_visibility_impl( query_pt, arr_out ); + } + + template < typename VARR > + typename VARR::Face_handle + compute_visibility ( const Point_2& query_pt, + const Face_const_handle f, + VARR& arr_out ) + { + assert( !f->is_unbounded() ); + + query_on_edge = query_on_vertex = false; + arr_out.clear(); + edges.clear(); + + Circulator circ, curr; + + int hole_base = 0, hole_edge = 0; + + if ( f->has_outer_ccb() ) { + curr = circ = f->outer_ccb(); + do { + edges.push_back( Edge_type( query_pt, curr, false, false ) ); + hole_edge++; + } while ( ++curr != circ ); + for ( int i = 0; i < hole_edge; i++ ) { + edges[hole_base+i].set_index( hole_base+i, hole_base+(i+hole_edge-1)%hole_edge ); + } + hole_base += hole_edge; + } + for ( Hole_const_iterator hi = f->holes_begin(); + hi != f->holes_end(); hi++ ) { + curr = circ = *hi; + hole_edge = 0; + do { + edges.push_back( Edge_type( query_pt, curr, false, false ) ); + hole_edge++; + } while ( ++curr != circ ); + for ( int i = 0; i < hole_edge; i++ ) { + edges[hole_base+i].set_index( hole_base+i, hole_base+(i+hole_edge-1)%hole_edge ); + } + hole_base += hole_edge; + } + + unsorted_edges.assign( edges.begin(), edges.end() ); + + return compute_visibility_impl( query_pt, arr_out ); + } + +private: + const Arrangement_2 * p_arr; + const Geometry_traits_2 * geom_traits; + + bool query_on_edge; + bool query_on_vertex; + Edge_vector edges; + Edge_vector unsorted_edges; +}; // End of class Rotational_sweep_visibility_2 + +} // End namespace CGAL + +#endif diff --git a/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..730375cd1e6 --- /dev/null +++ b/Visibility_2/include/CGAL/Preprocessed_rotational_sweep_visibility_2.h @@ -0,0 +1,106 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Kan Huang +// + +#ifndef CGAL_PREPROCESSED_VISIBILITY_2_H +#define CGAL_PREPROCESSED_VISIBILITY_2_H + +#include +#include +#include +#include + +namespace CGAL { + +template +class Preprocessed_visibility_2 { + +public: + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + // Currently only consider with same type for both + typedef Arrangement_2 Input_Arrangement_2; + typedef Arrangement_2 Output_Arrangement_2; + + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Kernel Kernel; + typedef typename CGAL::Arr_linear_traits_2 Linear_traits_2; + + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Ray_2 Ray_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Line_2 Line_2; + typedef typename Geometry_traits_2::Vector_2 Vector_2; + typedef typename Geometry_traits_2::FT Number_type; + + typedef typename CGAL::Arrangement_2 Line_Arrangement_2; + + Preprocessed_visibility_2() : p_arr(NULL) {}; + + /*! Constructor given an arrangement and the Regularization tag. */ + Preprocessed_visibility_2(Input_Arrangement_2& arr/*, Regularization_tag r_t*/): p_arr(&arr) {}; + + bool is_attached() { + return (p_arr != NULL); + } + + void attach(Input_Arrangement_2& arr) { + p_arr = &arr; + } + + void detach() { + p_arr = NULL; + } + + Input_Arrangement_2 arr() { + return *p_arr; + } + + void compute_visibility(const Point_2& q, + const Face_const_handle face, + Output_Arrangement_2& out_arr + ) { + + } + + void compute_visibility(const Point_2& q, + const Halfedge_const_handle he, + Output_Arrangement_2& out_arr + ) { + +} + +private: + Input_Arrangement_2* arr; + Line_Arrangement_2 line_arr; + void preprocess() { + + } + + Line_2 dual_line(const Point_2& p) { + return Line_2(p.x(), -1, -p.y()); + } + +}; + +} // namespace CGAL + +#endif diff --git a/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h new file mode 100644 index 00000000000..fd378f8f69f --- /dev/null +++ b/Visibility_2/include/CGAL/Rotational_sweep_visibility_2.h @@ -0,0 +1,866 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Kan Huang +// + +#ifndef CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H +#define CGAL_ROTATIONAL_SWEEP_VISIBILITY_2_H + +#include +#include +#include +#include + + +namespace CGAL { + +template +class Rotational_sweep_visibility_2 { +public: + typedef Arrangement_2_ Arrangement_2; + typedef typename Arrangement_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement_2::Vertex_handle Vertex_handle; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Face_handle Face_handle; + + typedef typename Geometry_traits_2::Kernel K; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Ray_2 Ray_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Line_2 Line_2; + typedef typename Geometry_traits_2::Vector_2 Vector_2; + typedef typename Geometry_traits_2::Direction_2 Direction_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Object_2 Object_2; + + typedef RegularizationTag Regularization_tag; + typedef CGAL::Tag_true Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + +private: + typedef std::vector Points; + typedef Vertex_const_handle VH; + typedef std::vector VHs; + typedef Halfedge_const_handle EH; + typedef std::vector EHs; + + class Less_edge: public std::binary_function { + const Geometry_traits_2* geom_traits; + public: + Less_edge() {} + Less_edge(const Geometry_traits_2* traits):geom_traits(traits) {} + bool operator() (const EH e1, const EH e2) const { + if (e1 == e2) + return false; + else { + return &(*e1)<&(*e2); +// if (e1->source() == e2->source()) +// return Visibility_2::compare_xy_2(geom_traits, e1->target()->point(), e2->target()->point()) == SMALLER; +// else +// return Visibility_2::compare_xy_2(geom_traits, e1->source()->point(), e2->source()->point()) == SMALLER; + } + } + }; + + class Less_vertex: public std::binary_function { + const Geometry_traits_2* geom_traits; + public: + Less_vertex() {} + Less_vertex(const Geometry_traits_2* traits):geom_traits(traits) {} + bool operator() (const VH v1, const VH v2) const { + if (v1 == v2) + return false; + else + // I know this is dirty but it speeds up by 25%. Michael + return &(*v1)<&(*v2); +// return Visibility_2::compare_xy_2(geom_traits, v1->point(), v2->point()) == SMALLER; + } + }; + + class Closer_edge: public std::binary_function { + const Geometry_traits_2* geom_traits; + Point_2 q; + public: + Closer_edge() {} + Closer_edge(const Geometry_traits_2* traits, const Point_2& q):geom_traits(traits), q(q) {} + + int vtype(const Point_2& c, const Point_2& p) const { + switch(Visibility_2::orientation_2(geom_traits, q, c, p)) { + case COLLINEAR: + if (Visibility_2::less_distance_to_point_2(geom_traits, q, c, p)) + return 0; + else + return 3; + case RIGHT_TURN: + return 1; + case LEFT_TURN: + return 2; + } + } + bool operator() (const EH& e1, const EH& e2) const { + if (e1 == e2) + return false; + const Point_2& s1=e1->source()->point(), + t1=e1->target()->point(), + s2=e2->source()->point(), + t2=e2->target()->point(); + if (e1->source() == e2->source()) { + + int vt1 = vtype(s1, t1), + vt2 = vtype(s1, t2); + if (vt1 != vt2) + return vt1 > vt2; + else + return (Visibility_2::orientation_2(geom_traits, s1, t2, t1)== + Visibility_2::orientation_2(geom_traits, s1, t2, q)); + } + + if (e1->target() == e2->source()) { +// const Point_2& p1 = s1, +// p2 = t2, +// c = s2; + int vt1 = vtype(t1, s1), + vt2 = vtype(t1, t2); + if (vt1 != vt2) + return vt1 > vt2; + else + return (Visibility_2::orientation_2(geom_traits, s2, t2, s1)== + Visibility_2::orientation_2(geom_traits, s2, t2, q)); + } + + if (e1->source() == e2->target()) { +// const Point_2& p1 = t1, +// p2 = s2, +// c = s1; + int vt1 = vtype(s1, t1), + vt2 = vtype(s1, s2); + if (vt1 != vt2) + return vt1 > vt2; + else return (Visibility_2::orientation_2(geom_traits, s1, s2, t1)== + Visibility_2::orientation_2(geom_traits, s1, s2, q)); + } + + if (e1->target() == e2->target()) { +// const Point_2& p1 = s1, +// p2 = s2, +// c = t1; + int vt1 = vtype(t1, s1), + vt2 = vtype(t1, s2); + if (vt1 != vt2) + return vt1 > vt2; + else return (Visibility_2::orientation_2(geom_traits, t1, s2, s1)== + Visibility_2::orientation_2(geom_traits, t1, s2, q)); + } + + Orientation e1q = Visibility_2::orientation_2(geom_traits, s1, t1, q); + switch (e1q) + { + case COLLINEAR: + if (Visibility_2::collinear(geom_traits, q, s2, t2)) { + //q is collinear with e1 and e2. + return (Visibility_2::less_distance_to_point_2(geom_traits, q, s1, s2) + || Visibility_2::less_distance_to_point_2(geom_traits, q, t1, t2)); + } + else { + //q is collinear with e1 not with e2. + if (Visibility_2::collinear(geom_traits, s2, t2, s1)) + return (Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, t1)); + else + return (Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, s1)); + } + case RIGHT_TURN: + switch (Visibility_2::orientation_2(geom_traits, s1, t1, s2)) { + case COLLINEAR: + return Visibility_2::orientation_2(geom_traits, s1, t1, t2)!=e1q; + case RIGHT_TURN: + if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == LEFT_TURN) + return Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, s1); + else + return false; + case LEFT_TURN: + if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) + return Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, s1); + else + return true; + } + case LEFT_TURN: + switch (Visibility_2::orientation_2(geom_traits, s1, t1, s2)) { + case COLLINEAR: + return Visibility_2::orientation_2(geom_traits, s1, t1, t2)!=e1q; + case LEFT_TURN: + if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == RIGHT_TURN) + return Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, s1); + else + return false; + case RIGHT_TURN: + if (Visibility_2::orientation_2(geom_traits, s1, t1, t2) == LEFT_TURN) + return Visibility_2::orientation_2(geom_traits, s2, t2, q) + == Visibility_2::orientation_2(geom_traits, s2, t2, s1); + else + return true; + } + } + } + + }; + +// Using hash_map or edx causes a seg fault, did not have the time to see why. Michael +// class Hash_edge: public std::unary_function::result_type> { +// public: +// typename boost::hash::result_type +// operator() (const EH e1) const { +// return boost::hash()(&(e1->curve())); +// } +// }; + + + const Geometry_traits_2 *geom_traits; + const Arrangement_2 *p_arr; + Point_2 q; //query point + Points polygon; //visibility polygon + std::map incident_edges; //the edges that are + std::map edx; //index of active edges in the heap + // boost::unordered_map edx; //index of active edges in the heap + std::set active_edges; //a set of edges that intersect the current vision ray. + VHs vs; //angular sorted vertices + EHs bad_edges; //edges that pass the query point + VH cone_end1; //an end of visibility cone + VH cone_end2; //another end of visibility cone + int cone_end1_idx; //index of cone_end1->point() in visibility polygon + int cone_end2_idx; //index of cone_end2->point() in visibility polygon + + bool is_vertex_query; + bool is_edge_query; + bool is_face_query; + bool is_big_cone; //whether the angle of visibility_cone is greater than pi. + +public: + Rotational_sweep_visibility_2(): p_arr(NULL), geom_traits(NULL) {} + Rotational_sweep_visibility_2(const Arrangement_2& arr): p_arr(&arr) { + geom_traits = p_arr->geometry_traits(); + } + + const std::string name(){return std::string("R_visibility_2");} + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, const Halfedge_const_handle e, VARR& arr_out) { + arr_out.clear(); + bad_edges.clear(); + this->q = q; + + if (Visibility_2::compare_xy_2(geom_traits, q, e->target()->point())==EQUAL) { + is_vertex_query = true; + is_edge_query = false; + is_face_query = false; + cone_end1 = e->source(); + cone_end2 = e->next()->target(); + is_big_cone = CGAL::right_turn(cone_end1->point(), q, cone_end2->point()); + + typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr; + first = curr = e->target()->incident_halfedges(); + do { + if (curr->face() == e->face()) + bad_edges.push_back(curr); + else if (curr->twin()->face() == e->face()) + bad_edges.push_back(curr->twin()); + } while (++curr != first); + } + else { + is_vertex_query = false; + is_edge_query = true; + is_face_query = false; + cone_end1 = e->source(); + cone_end2 = e->target(); + bad_edges.push_back(e); + is_big_cone = false; + } + visibility_region_impl(e->face(), q); + + //decide which inside of the visibility butterfly is needed. + int small_idx, big_idx; + if ( cone_end1_idx < cone_end2_idx ) { + small_idx = cone_end1_idx; + big_idx = cone_end2_idx; + } + else { + small_idx = cone_end2_idx; + big_idx = cone_end1_idx; + } + int next_idx = small_idx + 1; + bool is_between; + //indicate whether the shape between small_idx and big_idx is the visibility region required. + if (CGAL::right_turn(cone_end1->point(), q, cone_end2->point())) { + is_between = false; + while (next_idx != big_idx) { + if (CGAL::left_turn(cone_end1->point(), q, polygon[next_idx]) || CGAL::left_turn(q, cone_end2->point(), polygon[next_idx])) { + is_between = true; + break; + } + next_idx++; + } + } + else { + is_between = true; + while (next_idx != big_idx) { + if (CGAL::right_turn(cone_end1->point(), q, polygon[next_idx]) || CGAL::right_turn(q, cone_end2->point(), polygon[next_idx])) { + is_between = false; + break; + } + next_idx++; + } + } + + typename Points::iterator first = polygon.begin() + small_idx; + typename Points::iterator last = polygon.begin() + big_idx; + if (is_between) { + Points polygon_out(first, last+1); + if (is_vertex_query) + polygon_out.push_back(q); + Visibility_2::report_while_handling_needles + (geom_traits, q, polygon_out, arr_out); + } + else { + Points polygon_out(polygon.begin(), first+1); + if (is_vertex_query) polygon_out.push_back(q); + for (int i = big_idx; i != polygon.size(); i++) { + polygon_out.push_back(polygon[i]); + } + Visibility_2::report_while_handling_needles + (geom_traits, q, polygon_out, arr_out); + } + + conditional_regularize(arr_out, Regularization_tag()); + + if (arr_out.faces_begin()->is_unbounded()) + return ++arr_out.faces_begin(); + else + return arr_out.faces_begin(); + } + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, const Face_const_handle f, VARR& arr_out) { + arr_out.clear(); + this->q = q; + is_vertex_query = false; + is_edge_query = false; + is_face_query = true; + + visibility_region_impl(f, q); + Visibility_2::report_while_handling_needles(geom_traits, q, polygon, arr_out); + conditional_regularize(arr_out, Regularization_tag()); + if (arr_out.faces_begin()->is_unbounded()) + return ++arr_out.faces_begin(); + else + return arr_out.faces_begin(); + } + +bool is_attached() { + return (p_arr != NULL); +} + +void attach(const Arrangement_2& arr) { + p_arr = &arr; + geom_traits = p_arr->geometry_traits(); +} + +void detach() { + p_arr = NULL; + geom_traits = NULL; +} + +const Arrangement_2& arr() { + return *p_arr; +} + +private: + //get the neighbor of v along edge e + VH get_neighbor(const EH e, const VH v) { + if (e->source() == v) + return e->target(); + else + return e->source(); + } + //check whether ray(q->dp) intersects segment(p1, p2) + bool do_intersect_ray(const Point_2& q, + const Point_2& dp, + const Point_2& p1, + const Point_2& p2) { + return (CGAL::orientation(q, dp, p1) != CGAL::orientation(q, dp, p2) && CGAL::orientation(q, p1, dp) == CGAL::orientation(q, p1, p2)); + } + + //arrange vertices that on a same vision ray in a 'funnel' order + void funnel(int i, int j) { + VHs right, left; + //whether the edges incident to a vertex block the left side and right side of current vision ray. + bool block_left(false), block_right(false); + VH former = vs[i], nb; + for (int l=i; lpoint(), nb->point())) + left_v = true; + else + right_v = CGAL::right_turn(q, vs[l]->point(), nb->point()); + } + if (has_predecessor) { + //if the current vertex connects to the vertex before by an edge, + //the vertex before can help it to block. + block_left = block_left || left_v; + block_right = block_right || right_v; + } + else { + block_left = left_v; + block_right = right_v; + } + if (block_left && block_right) { + //when both sides are blocked, there is no need to change the vertex after. + right.push_back(vs[l]); + break; + } + else { + if (block_left) + left.push_back(vs[l]); + else + right.push_back(vs[l]); + } + former = vs[l]; + } + for (int l=0; l!=right.size(); l++) + vs[i+l] = right[l]; + for (int l=0; l!=left.size(); l++) + vs[i+l+right.size()] = left[left.size()-1-l]; + } + + + + void visibility_region_impl(const Face_const_handle f, const Point_2& q) { + vs.clear(); + polygon.clear(); + active_edges = std::set(Closer_edge(geom_traits, q)); + incident_edges = std::map(Less_vertex(geom_traits)); + edx = std::map(Less_edge(geom_traits)); + + EHs relevant_edges; //all edges that can affect the visibility of query point. + Arrangement_2 bbox; + if (is_face_query) + input_face(f); + else + input_face(f, relevant_edges, bbox); + //the following code is the initiation of vision ray. the direction of the initial ray is between the direction + //from q to last vertex in vs and positive x-axis. By choosing this direction, we make + //sure that all plane is swept and there is not needle at the beginning of sweeping. + Vector_2 dir; + if (Direction_2(-1, 0) < Direction_2(Vector_2(q, vs.back()->point()))) + dir = Vector_2(1, 0) + Vector_2(q, vs.back()->point()); + else + dir = Vector_2(0, -1); + Point_2 dp = q + dir; + + //initiation of active_edges. for face queries, all edges on the boundary can affect visibility. + //for non-face queries, only relevant_edges has to be considered. + if (is_face_query) { + Ccb_halfedge_const_circulator curr = f->outer_ccb(); + Ccb_halfedge_const_circulator circ = curr; + do { + if (do_intersect_ray(q, dp, curr->target()->point(), curr->source()->point())) { + active_edges.insert(curr); + } + } while (++curr != circ); + + typename Arrangement_2::Hole_const_iterator hi; + for (hi = f->holes_begin(); hi != f->holes_end(); ++hi) { + Ccb_halfedge_const_circulator curr = circ = *hi; + do { + if (do_intersect_ray(q, dp, curr->target()->point(), curr->source()->point())) + active_edges.insert(curr); + } while (++curr != circ); + } + } + else { + for (int i=0; i!=relevant_edges.size(); i++) + if (do_intersect_ray(q, dp, relevant_edges[i]->source()->point(), relevant_edges[i]->target()->point())) + active_edges.insert(relevant_edges[i]); + } + + //angular sweep begins +// std::cout<(ctemp_eh); + temp_eh = insert_ehs.front(); + } + else { + for (int j=0; j!=remove_cnt; j++) + active_edges.erase(remove_ehs[j]); + for (int j=0; j!=insert_cnt; j++) + active_edges.insert(insert_ehs[j]); + } + + if (closest_e != *active_edges.begin()) { + //when the closest edge changed + if (is_face_query) { + if (remove_cnt > 0 && insert_cnt > 0) { + //some edges are added and some are deleted, which means the vertex swept is part of visibility polygon. + update_visibility(vh->point()); + } + if (remove_cnt == 0 && insert_cnt > 0) { + //only add some edges, means the view ray is blocked by new edges. + //therefore first add the intersection of view ray and former closet edge, then add the vertice swept. + update_visibility(ray_seg_intersection(q, + vh->point(), + closest_e->target()->point(), + closest_e->source()->point())); + update_visibility(vh->point()); + } + if (remove_cnt > 0 && insert_cnt == 0) { + //only delete some edges, means some block is moved and the view ray can reach the segments after the block. + update_visibility(vh->point()); + update_visibility(ray_seg_intersection(q, + vh->point(), + (*active_edges.begin())->target()->point(), + (*active_edges.begin())->source()->point())); + } + } + else { + //extra work here for edge/vertex query is the index of cone_end1 and cone_end2 will be recorded. + if (remove_cnt > 0 && insert_cnt > 0) { + //some edges are added and some are deleted, which means the vertice swept is part of visibility polygon. + if (update_visibility(vh->point())) { + if (vh == cone_end1) + cone_end1_idx = polygon.size()-1; + else if (vh == cone_end2) + cone_end2_idx = polygon.size()-1; + } + } + if (remove_cnt == 0 && insert_cnt > 0) { + //only add some edges, means the view ray is blocked by new edges. + //therefore first add the intersection of view ray and former closet edge, then add the vertice swept. + update_visibility(ray_seg_intersection(q, + vh->point(), + closest_e->target()->point(), + closest_e->source()->point())); + if (update_visibility(vh->point())) { + if (vh == cone_end1) + cone_end1_idx = polygon.size()-1; + else if (vh == cone_end2) + cone_end2_idx = polygon.size()-1; + } + } + if (remove_cnt > 0 && insert_cnt == 0) { + //only delete some edges, means some block is removed and the vision ray can reach the segments after the block. + if (update_visibility(vh->point())) { + if (vh == cone_end1) + cone_end1_idx = polygon.size()-1; + else if (vh == cone_end2) + cone_end2_idx = polygon.size()-1; + } + update_visibility(ray_seg_intersection(q, + vh->point(), + (*active_edges.begin())->target()->point(), + (*active_edges.begin())->source()->point())); + } + } + } + } + } + + void print_edge(const EH e) { + std::cout<source()->point()<<"->"<target()->point()<dp) and segment(s, t) + //if they are collinear then return the endpoint which is closer to q. + + Point_2 ray_seg_intersection( + const Point_2& q, const Point_2& dp, // the ray + const Point_2& s, const Point_2& t) // the segment + { + if (CGAL::collinear(q, dp, s)) { + if (CGAL::collinear(q, dp, t)) { + if (CGAL::compare_distance_to_point(q, s, t)==CGAL::SMALLER) + return s; + else + return t; + } + else + return s; + } + Ray_2 ray(q,dp); + Segment_2 seg(s,t); + CGAL::Object result = CGAL::intersection(ray, seg); + return *(CGAL::object_cast(&result)); + } + + //check if p has been discovered before, if not update the visibility polygon + bool update_visibility(const Point_2& p){ + if (polygon.empty()) { + polygon.push_back(p); + return true; + } + else if (Visibility_2::compare_xy_2(geom_traits, polygon.back(), p) != EQUAL) { + polygon.push_back(p); + return true; + } + return false; + } + + //functor to decide which vertex is swept earlier by the rotational sweeping ray + class Is_swept_earlier:public std::binary_function { + const Point_2& q; + const Geometry_traits_2* geom_traits; + public: + Is_swept_earlier(const Point_2& q, const Geometry_traits_2* traits):q(q), geom_traits(traits) {} + bool operator() (const VH v1, const VH v2) const { + const Point_2& p1 = v1->point(); + const Point_2& p2 = v2->point(); + int qua1 = quadrant(q, p1); + int qua2 = quadrant(q, p2); + if (qua1 < qua2) + return true; + if (qua1 > qua2) + return false; + if (collinear(q, p1, p2)) + return (CGAL::compare_distance_to_point(q, p1, p2) == CGAL::SMALLER); + else + return CGAL::right_turn(p1, q, p2); + } + + //return the quadrant of p with respect to o. + int quadrant(const Point_2& o, const Point_2& p) const { + typename Geometry_traits_2::Compare_x_2 compare_x = geom_traits->compare_x_2_object(); + typename Geometry_traits_2::Compare_y_2 compare_y = geom_traits->compare_y_2_object(); + + Comparison_result dx = compare_x(p, o); + Comparison_result dy = compare_y(p, o); + if (dx==LARGER && dy!=SMALLER) + return 1; + if (dx!=LARGER && dy==LARGER) + return 2; + if (dx==SMALLER && dy!=LARGER) + return 3; + if (dx!=SMALLER && dy==SMALLER) + return 4; + return 0; + } + }; + + //when the query point is in face, every edge is good. + void input_neighbor_f( const Halfedge_const_handle e) { + VH v = e->target(); + if (!incident_edges.count(v)) + vs.push_back(v); + incident_edges[v].push_back(e); + incident_edges[v].push_back(e->next()); + } + + //check if p is in the visibility cone + bool is_in_cone(const Point_2& p) const{ + if (is_big_cone) + return (!CGAL::right_turn(cone_end1->point(), q, p)) || (!CGAL::left_turn(cone_end2->point(), q, p)); + else + return (!CGAL::right_turn(cone_end1->point(), q, p)) && (!CGAL::left_turn(cone_end2->point(), q, p)); + } + + //for vertex and edge query: the visibility is limited in a cone. + void input_edge(const Halfedge_const_handle e, + EHs& good_edges) { + for (int i=0; itarget(); + VH v2 = e->source(); + //an edge will affect visibility only if it has an endpoint in the visibility cone or it crosses the boundary of the cone. + if (is_in_cone(v1->point()) || is_in_cone(v2->point()) || do_intersect_ray(q, cone_end1->point(), v1->point(), v2->point())) { + good_edges.push_back(e); + if (!incident_edges.count(v1)) + vs.push_back(v1); + incident_edges[v1].push_back(e); + if (!incident_edges.count(v2)) + vs.push_back(v2); + incident_edges[v2].push_back(e); + } + } + + //for face query: traverse the face to get all edges + //and sort vertices in counter-clockwise order. + void input_face (Face_const_handle fh) + { + Ccb_halfedge_const_circulator curr = fh->outer_ccb(); + Ccb_halfedge_const_circulator circ = curr; + do { + assert(curr->face() == fh); + input_neighbor_f(curr); + } while (++curr != circ); + + typename Arrangement_2::Hole_const_iterator hi; + for (hi = fh->holes_begin(); hi != fh->holes_end(); ++hi) { + Ccb_halfedge_const_circulator curr = *hi, circ = *hi; + do { + assert(curr->face() == fh); + input_neighbor_f(curr); + } while (++curr != circ); + } + + std::sort(vs.begin(), vs.end(), Is_swept_earlier(q, geom_traits)); + + for (int i=0; i!=vs.size(); i++) { + int j = i+1; + while (j != vs.size()) { + if (!CGAL::collinear(q, vs[i]->point(), vs[j]->point())) + break; + j++; + } + if (j-i>1) + funnel(i, j); + i = j-1; + } + } + //for vertex or edge query: traverse the face to get all edges + //and sort vertices in counter-clockwise order. + void input_face (Face_const_handle fh, + EHs& good_edges, + Arrangement_2& bbox) + { + Ccb_halfedge_const_circulator curr = fh->outer_ccb(); + Ccb_halfedge_const_circulator circ = curr; + do { + assert(curr->face() == fh); + input_edge(curr, good_edges); + } while (++curr != circ); + + typename Arrangement_2::Hole_const_iterator hi; + for (hi = fh->holes_begin(); hi != fh->holes_end(); ++hi) { + Ccb_halfedge_const_circulator curr = circ = *hi; + do { + assert(curr->face() == fh); + input_edge(curr, good_edges); + } while (++curr != circ); + } + + //create a box that cover all vertices such that during the sweeping, the vision ray will always intersect at least an edge. + //this box doesn't intersect any relevant_edge. + Points points; + for (int i=0; ipoint()); + } + points.push_back(q); + //first get the bounding box of all relevant points. + typename Geometry_traits_2::Iso_rectangle_2 bb = bounding_box(points.begin(), points.end()); + + Number_type xmin, xmax, ymin, ymax; + typename Geometry_traits_2::Compute_x_2 compute_x = geom_traits->compute_x_2_object(); + typename Geometry_traits_2::Compute_y_2 compute_y = geom_traits->compute_y_2_object(); + + //make the box a little bigger than bb so that it won't intersect any relevant_edge. + xmin = compute_x(bb.min())-1; + ymin = compute_y(bb.min())-1; + xmax = compute_x(bb.max())+1; + ymax = compute_y(bb.max())+1; + Point_2 box[4] = {Point_2(xmin, ymin), Point_2(xmax, ymin), + Point_2(xmax, ymax), Point_2(xmin, ymax)}; + Halfedge_handle e1 = bbox.insert_in_face_interior(Segment_2(box[0], box[1]), bbox.unbounded_face()); + Halfedge_handle e2 = bbox.insert_from_left_vertex(Segment_2(box[1], box[2]), e1->target()); + Halfedge_handle e3 = bbox.insert_from_right_vertex(Segment_2(box[2], box[3]), e2->target()); + bbox.insert_at_vertices(Segment_2(box[0], box[3]), e1->source(), e3->target()); + + circ = curr = e1->face()->outer_ccb(); + do { + VH v = curr->target(); + vs.push_back(v); + incident_edges[v].push_back(curr); + incident_edges[v].push_back(curr->next()); + good_edges.push_back(curr); + } while(++curr != circ); + + std::sort(vs.begin(), vs.end(), Is_swept_earlier(q, geom_traits)); + + for (int i=0; i!=vs.size(); i++) { + int j = i+1; + while (j != vs.size()) { + if (!CGAL::collinear(q, vs[i]->point(), vs[j]->point())) + break; + j++; + } + if (j-i>1) + funnel(i, j); + i = j-1; + } + } + + template + void conditional_regularize(VARR& arr_out, CGAL::Tag_true) { + regularize_output(arr_out); + } + + template + void conditional_regularize(VARR& arr_out, CGAL::Tag_false) { + //do nothing + } + + template + void regularize_output(VARR& arr_out) { + typename VARR::Edge_iterator e_itr; + for (e_itr = arr_out.edges_begin(); + e_itr != arr_out.edges_end(); + e_itr++) { + if (e_itr->face() == e_itr->twin()->face()) + arr_out.remove_edge(e_itr); + } + } +}; +} // end namespace CGAL + + + +#endif + + diff --git a/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h new file mode 100644 index 00000000000..0934d03ba1c --- /dev/null +++ b/Visibility_2/include/CGAL/Simple_polygon_visibility_2.h @@ -0,0 +1,715 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$` +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer +// Ning Xu + +#ifndef CGAL_SIMPLE_POLYGON_VISIBILITY_2_H +#define CGAL_SIMPLE_POLYGON_VISIBILITY_2_H + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +template +class Simple_polygon_visibility_2 { + +public: + // Currently only consider with same type for both + typedef Arrangement_2_ Arrangement_2; + typedef typename Arrangement_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Kernel K; + + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Face_handle Face_handle; + typedef typename Arrangement_2::Halfedge_around_vertex_const_circulator + Halfedge_around_vertex_const_circulator; + + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Ray_2 Ray_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Line_2 Line_2; + typedef typename Geometry_traits_2::Vector_2 Vector_2; + typedef typename Geometry_traits_2::Direction_2 Direction_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Object_2 Object_2; + + typedef RegularizationTag Regularization_tag; + typedef CGAL::Tag_false Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + + Simple_polygon_visibility_2() : p_arr(NULL), geom_traits(NULL) {}; + + /*! Constructor given an arrangement and the Regularization tag. */ + Simple_polygon_visibility_2(const Arrangement_2& arr): + p_arr(&arr) { + geom_traits = p_arr->geometry_traits(); + query_pt_is_vertex = false; + query_pt_is_on_halfedge = false; + } + + + const std::string name(){return std::string("S_visibility_2");} + + /*! Method to check if the visibility object is attached or not to + an arrangement*/ + bool is_attached() { + return (p_arr != NULL); + } + + /*! Attaches the visibility object to the 'arr' arrangement */ + void attach(const Arrangement_2& arr) { + p_arr = &arr; + geom_traits = p_arr->geometry_traits(); + query_pt_is_vertex = false; + query_pt_is_on_halfedge = false; + } + + /*! Detaches the visibility object from the arrangement it is + attached to*/ + void detach() { + p_arr = NULL; + geom_traits = NULL; + vertices.clear(); + query_pt_is_vertex = false; + query_pt_is_on_halfedge = false; + p_cdt = boost::shared_ptr(); + } + + /*! Getter method for the input arrangement*/ + const Arrangement_2& arr() { + return *p_arr; + } + + /*! Computes the visibility object from the query point 'q' in the face + 'face' and constructs the output in 'out_arr'*/ + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, + const Face_const_handle face, + VARR& out_arr) { + + assert(query_pt_is_vertex == false); + assert(query_pt_is_on_halfedge == false); + + // Now retrieve the circulator to first visible vertex from triangulation + Ccb_halfedge_const_circulator circ = find_visible_start(face, q); + Ccb_halfedge_const_circulator curr = circ; + Halfedge_const_handle he; + + do { + he = curr; + vertices.push_back(he->source()->point()); + } while(++curr != circ); + + vertices.push_back(vertices[0]); + + visibility_region_impl(q); + + typename std::vector points; + while (!s.empty()) { + Point_2 curr_point = s.top(); + points.push_back(curr_point); + s.pop(); + } + + std::reverse(points.begin(), points.end()); + + CGAL::Visibility_2::report_while_handling_needles + (geom_traits, + q, + points, + out_arr); + + CGAL_precondition(out_arr.number_of_isolated_vertices() == 0); + CGAL_precondition(s.size() == 0); + conditional_regularize(out_arr, Regularization_tag()); + vertices.clear(); + if (out_arr.faces_begin()->is_unbounded()) { + return ++out_arr.faces_begin(); + } + else { + return out_arr.faces_begin(); + } + } + + /*! Computes the visibility region of the query point 'q' located on the + halfedge 'he' and constructs the output in 'out_arr'*/ + template + typename VARR::Face_handle + compute_visibility( + const Point_2& q, + const Halfedge_const_handle he, + VARR& out_arr ) + { + query_pt_is_vertex = false; + query_pt_is_on_halfedge = false; + bool query_on_target = false; + + if (q != he->source()->point()) { + if (q != he->target()->point()) { + vertices.push_back(he->target()->point()); + query_pt_is_on_halfedge = true; + } + else { + query_pt_is_vertex = true; + query_on_target = true; + } + } else { + vertices.push_back( he->target()->point() ); + query_pt_is_vertex = true; + } + + Ccb_halfedge_const_circulator circ = he; + circ++; + Ccb_halfedge_const_circulator curr = circ; + + do { + Halfedge_const_handle he_handle = curr; + Point_2 curr_vertex = he_handle->target()->point(); + vertices.push_back(curr_vertex); + } while (++curr != circ); + + if ( query_on_target ) { + vertices.push_back( vertices[0] ); + } + + visibility_region_impl(q); + + typename std::vector points; + if (!s.empty()) { + Point_2 prev_pt = s.top(); + if (prev_pt != q) { + points.push_back(prev_pt); + } + else if (query_pt_is_vertex) { + points.push_back(prev_pt); + } + if (!s.empty()) { + s.pop(); + } + while(!s.empty()) { + Point_2 curr_pt = s.top(); + if (curr_pt != q) { + points.push_back(curr_pt); + } + else if (query_pt_is_vertex) { + points.push_back(curr_pt); + } + s.pop(); + } + } + + std::reverse(points.begin(), points.end()); + + CGAL::Visibility_2::report_while_handling_needles + (geom_traits, + q, + points, + out_arr); + CGAL_precondition(out_arr.number_of_isolated_vertices() == 0); + CGAL_precondition(s.size() == 0); + conditional_regularize(out_arr, Regularization_tag()); + vertices.clear(); + if (out_arr.faces_begin()->is_unbounded()) { + return ++out_arr.faces_begin(); + } + else { + return out_arr.faces_begin(); + } + } + +private: + typedef CGAL::Triangulation_vertex_base_2 Vb; + typedef CGAL::Constrained_triangulation_face_base_2 Fb; + typedef CGAL::Triangulation_data_structure_2 TDS; + typedef CGAL::No_intersection_tag Itag; + typedef CGAL::Constrained_triangulation_2 CDT; + +private: + const Arrangement_2 *p_arr; + /*! Boost pointer to the constrained Delaunay triangulation object*/ + boost::shared_ptr p_cdt; + /*! Mapping of the vertices of the input to the corresponding circulator + needed for finding the first visible vertex in case of face queries*/ + std::map + point_itr_map; + const Geometry_traits_2 *geom_traits; + /*! Stack of visibile points; manipulated when going through the sequence + of input vertices; contains the vertices of the visibility region after + the run of the algorithm*/ + std::stack s; + /*! Sequence of input vertices*/ + std::vector vertices; + /*! State of visibility region algorithm*/ + enum {LEFT, RIGHT, SCANA, SCANB, SCANC, SCAND, FINISH} upcase; + bool query_pt_is_vertex; + bool query_pt_is_on_halfedge; + + /*! Regularize output if flag is set to true*/ + template + void conditional_regularize(VARR& out_arr, CGAL::Tag_true) { + regularize_output(out_arr); + } + /*! No need to regularize output if flag is set to false*/ + template + void conditional_regularize(VARR& out_arr, CGAL::Tag_false) { + //do nothing + } + + /*! Regularizes the output - removes edges that have the same face on both + sides */ + template + void regularize_output(VARR& out_arr) { + typename VARR::Edge_iterator e_itr; + for (e_itr = out_arr.edges_begin() ; + e_itr != out_arr.edges_end() ; e_itr++) { + + typename VARR::Halfedge_handle he = e_itr; + typename VARR::Halfedge_handle he_twin = he->twin(); + if (he->face() == he_twin->face()) { + out_arr.remove_edge(he); + } + } + } + + /*! Initialized the constrained Delaunay triangulation using the edges of + the outer boundary of 'face' */ + void init_cdt(const Face_const_handle &face) { + + std::vector > constraints; + typename Arrangement_2::Ccb_halfedge_const_circulator circ = + face->outer_ccb(); + typename Arrangement_2::Ccb_halfedge_const_circulator curr = circ; + typename Arrangement_2::Halfedge_const_handle he; + + do { + he = curr; + Point_2 source = he->source()->point(); + Point_2 target = he->target()->point(); + point_itr_map.insert(std::make_pair(source, curr)); + constraints.push_back(std::make_pair(source,target)); + } while(++curr != circ); + + p_cdt = boost::shared_ptr(new CDT(constraints.begin(),constraints.end())); + } + + + /*! Finds a visible vertex from the query point 'q' in 'face' + to start the algorithm from*/ + Ccb_halfedge_const_circulator find_visible_start(Face_const_handle face, const Point_2 &q) { + init_cdt(face); + typename CDT::Face_handle fh = p_cdt->locate(q); + Point_2 start_point = fh->vertex(0)->point(); + + // Now retrieve the circulator to first visible vertex from triangulation + Ccb_halfedge_const_circulator circ = point_itr_map[start_point]; + Halfedge_const_handle he_curr = circ; + + Halfedge_around_vertex_const_circulator incident_circ = he_curr->source()->incident_halfedges(); + Halfedge_around_vertex_const_circulator incident_curr = incident_circ; + + do { + Ccb_halfedge_const_circulator curr_inc = incident_curr; + Halfedge_const_handle he_curr_inc = curr_inc; + + if (he_curr_inc->face() == face) { + Ccb_halfedge_const_circulator incident_next = incident_curr; + incident_next++; + Halfedge_const_handle he_next_inc = incident_next; + + if (CGAL::Visibility_2::orientation_2(geom_traits, + he_curr_inc->source()->point(), + he_curr_inc->target()->point(), + q) == CGAL::LEFT_TURN + || CGAL::Visibility_2::orientation_2(geom_traits, + he_next_inc->source()->point(), + he_next_inc->target()->point(), + q) == CGAL::LEFT_TURN) { + Ccb_halfedge_const_circulator result_circ = incident_next; + Halfedge_const_handle he_print = result_circ; + return result_circ; + } + } + } while (++incident_curr != incident_circ); + } + + /*! Main method of the algorithm - initializes the stack and variables + and calles the corresponding methods acc. to the algorithm's state; + 'q' - query point; + 'i' - current vertex' index + 'w' - endpoint of ray shot from query point */ + void visibility_region_impl(const Point_2& q) { + int i = 0; + Point_2 w; + CGAL::Orientation orient = CGAL::Visibility_2::orientation_2(geom_traits, + q, + vertices[0], + vertices[1]); + if ( orient != CGAL::RIGHT_TURN ) { + upcase = LEFT; + i = 1; + w = vertices[1]; + s.push(vertices[0]); + s.push(vertices[1]); + } + else { + upcase = SCANA; + i = 1; + w = vertices[1]; + s.push(vertices[0]); + } + + Ray_2 ray_origin( q, vertices[0] ); + do { + switch(upcase) { + case LEFT: + left(i, w, q); + break; + case RIGHT: + right(i, w, q); + break; + case SCANA: + scana(i, w, q); + break; + case SCANB: + scanb(i, w, q); + break; + case SCANC: + scanc(i, w, q); + break; + case SCAND: + scand(i, w, q); + break; + } + if ( upcase == LEFT ) { + Point_2 s_t = s.top(); + s.pop(); + if ( ( CGAL::Visibility_2::orientation_2 + ( geom_traits, q, vertices[0], s.top() ) == CGAL::RIGHT_TURN ) && + ( CGAL::Visibility_2::orientation_2 + ( geom_traits, q, vertices[0],s_t ) == CGAL::LEFT_TURN ) ) { + Segment_2 seg( s.top(), s_t ); + if ( CGAL::Visibility_2::do_intersect_2 + + ( geom_traits, seg, ray_origin ) ) { + Object_2 result = CGAL::Visibility_2::intersect_2 + + ( geom_traits, seg, ray_origin ); + const Point_2 * ipoint = CGAL::object_cast(&result); + assert( ipoint != NULL ); + s_t = *ipoint; + upcase = SCANB; + } + } + s.push( s_t ); + } + } while(upcase != FINISH); + } + + /*! Method that handles the left turns in the vertex algorithm */ + void left(int& i, Point_2& w, const Point_2& query_pt) { + if (i >= vertices.size() - 1) { + upcase = FINISH; + } + else { + Point_2 s_t = s.top(); + s.pop(); + Point_2 s_t_prev = s.top(); + s.push( s_t ); + CGAL::Orientation orient1 = CGAL::Visibility_2::orientation_2 + + ( geom_traits, + query_pt, + vertices[i], + vertices[i+1] ); + if ( orient1 != CGAL::RIGHT_TURN ) { + // Case L2 + upcase = LEFT; + s.push( vertices[i+1] ); + w = vertices[i+1]; + i++; + } else { + CGAL::Orientation orient2 = CGAL::Visibility_2::orientation_2 + + ( geom_traits, + s_t_prev, + vertices[i], + vertices[i+1] ); + if ( orient2 == CGAL::RIGHT_TURN ) { + // Case L3 + upcase = SCANA; + w = vertices[i+1]; + i++; + } else { + // Case L4 + upcase = RIGHT; + w = vertices[i]; + i++; + } + } + } + } + + /*! Scans the stack such that all vertices that were pushed before to the + stack and are now not visible anymore. */ + void right(int& i, Point_2& w, const Point_2& query_pt) { + Point_2 s_j; + Point_2 s_j_prev; + Point_2 u; + int mode = 0; + CGAL::Orientation orient1, orient2; + + s_j_prev = s.top(); + orient2 = CGAL::Visibility_2::orientation_2 + ( geom_traits, query_pt, s_j_prev, vertices[i] ); + while ( s.size() > 1 ) { + s_j = s_j_prev; + orient1 = orient2; + s.pop(); + s_j_prev = s.top(); + + orient2 = CGAL::Visibility_2::orientation_2 + ( geom_traits, query_pt, s_j_prev, vertices[i] ); + if ( orient1 != CGAL::LEFT_TURN && orient2 != CGAL::RIGHT_TURN ) { + mode = 1; + break; + } + + Segment_2 seg2( vertices[i-1], vertices[i] ); + Segment_2 seg( s_j_prev, s_j ); + if ( ( vertices[i-1] != s_j ) + && ( CGAL::Visibility_2::do_intersect_2 + + (geom_traits, seg, seg2) ) ) { + Object_2 result = CGAL::Visibility_2::intersect_2 + ( geom_traits, seg, seg2 ); + const Point_2 * ipoint = CGAL::object_cast(&result); + assert( ipoint != NULL ); + u = *ipoint; + mode = 2; + break; + } + } + + assert( mode != 0 ); + if ( mode == 1 ) { + orient1 = CGAL::Visibility_2::orientation_2 + ( geom_traits, query_pt, vertices[i], vertices[i+1] ); + orient2 = CGAL::Visibility_2::orientation_2 + ( geom_traits, vertices[i-1], vertices[i], vertices[i+1] ); + if ( orient1 == CGAL::RIGHT_TURN ) { + // Case R1 + // Since the next action is RIGHT, we do not compute the intersection + // of (s_j,s_j_prev) and the ray (query_pt, vertices[i]), + // thus, (s_j,s_j_prev) is not shortcutted, but it is harmless + upcase = RIGHT; + s.push( s_j ); + w = vertices[i]; + i++; + } else if ( orient2 == CGAL::RIGHT_TURN ) { + // Case R2 + Ray_2 ray( query_pt, vertices[i] ); + Segment_2 seg( s_j_prev, s_j ); + Object_2 result = CGAL::Visibility_2::intersect_2 + + ( geom_traits, seg, ray ); + const Point_2 * ipoint = CGAL::object_cast(&result); + assert( ipoint != NULL ); + u = *ipoint; + if ( s.top() != u ) { + s.push( u ); + } + upcase = LEFT; + s.push( vertices[i] ); + s.push( vertices[i+1] ); + w = vertices[i+1]; + i++; + } else { + // Case R3 + Ray_2 ray( query_pt, vertices[i] ); + Segment_2 seg( s_j_prev, s_j ); + Object_2 result = CGAL::Visibility_2::intersect_2 + + ( geom_traits, seg, ray ); + const Point_2 * ipoint = CGAL::object_cast(&result); + assert( ipoint != NULL ); + u = *ipoint; + if ( s.top() != u ) { + s.push( u ); + } + upcase = SCANC; + w = vertices[i]; + i++; + } + } else if ( mode == 2 ) { + // Case R4 + upcase = SCAND; + w = u; + } + } + + /*! Scans the vertices starting from index 'i' for the first visible vertex + out of the back hidden window */ + void scana(int& i, Point_2& w, const Point_2& query_pt) { + // Scan v_i, v_i+1, ..., v_n for the first edge to intersect (z, s_t) + Point_2 u; + int k = scan_edges( i, query_pt, s.top(), u, true ); + + CGAL::Orientation orient1 = CGAL::Visibility_2::orientation_2 + + ( geom_traits, + query_pt, + vertices[k], + vertices[k+1] ); + if ( orient1 == CGAL::RIGHT_TURN ) { + bool fwd = CGAL::Visibility_2::collinear_are_ordered_along_line_2 + + ( geom_traits, query_pt, s.top(), u ); + if ( !fwd ) { + // Case A1 + upcase = RIGHT; + i = k+1; + w = u; + } else { + // Case A2 + upcase = SCAND; + i = k+1; + w = u; + } + } else { + // Case A3 + upcase = LEFT; + i = k+1; + s.push( u ); + if ( u != vertices[k+1] ) { + s.push( vertices[k+1] ); + } + w = vertices[k+1]; + } + } + + /*! Find the first edge interecting the segment (v_0, s_t) */ + void scanb(int& i, Point_2& w, const Point_2& query_pt) { + if ( i == vertices.size() - 1 ) { + upcase = FINISH; + return; + } + Point_2 u; + int k = scan_edges( i, s.top(), vertices[0], u, false ); + if ( (k+1 == vertices.size()-1) && (vertices[0] == u) ) { + // Case B1 + upcase = FINISH; + s.push( vertices[0] ); + } else { + // Case B2 + upcase = RIGHT; + i = k+1; + w = u; + } + } + + /*! Finds the exit from a general front hidden window by finding the first + vertex to the right of the ray defined by the query_point and w*/ + void scanc(int& i, Point_2& w, const Point_2& query_pt) { + Point_2 u; + int k = scan_edges( i, s.top(), w, u, false ); + upcase = RIGHT; + i = k+1; + w = u; + } + + /*! find the first edge intersecting the given window (s_t, w) */ + void scand(int& i, Point_2& w, const Point_2& query_pt) { + Point_2 u; + int k = scan_edges( i, s.top(), w, u, false ); + upcase = LEFT; + i = k+1; + s.push( u ); + if ( u != vertices[k+1] ) { + s.push( vertices[k+1] ); + } + w = vertices[k+1]; + } + + /*! Scan edges v_i,v_{i+1},...,v_n, until find an edge intersecting given ray + or given segment. is_ray = true -> ray, false -> segment. + The intersection point is returned by u */ + int scan_edges( int i, const Point_2& ray_begin, const Point_2& ray_end, Point_2& u, bool is_ray ) { + CGAL::Orientation old_orient = CGAL::RIGHT_TURN; + Ray_2 ray( ray_begin, ray_end ); + Segment_2 s2( ray_begin, ray_end ); + int k; + Object_2 result; + for ( k = i; k+1 < vertices.size(); k++ ) { + CGAL::Orientation curr_orient = CGAL::Visibility_2::orientation_2 + ( geom_traits, + ray_begin, + ray_end, + vertices[k+1] ); + if ( curr_orient != old_orient ) { + // Orientation switch, an intersection may occur + Segment_2 seg( vertices[k], vertices[k+1] ); + if ( is_ray ) { + if (CGAL::Visibility_2::do_intersect_2 + + (geom_traits, seg, ray) ) { + result = CGAL::Visibility_2::intersect_2 + < Geometry_traits_2, Segment_2, Ray_2 > + ( geom_traits, seg, ray ); + break; + } + } else { + if (CGAL::Visibility_2::do_intersect_2 + + (geom_traits, seg, s2) ) { + result = CGAL::Visibility_2::intersect_2 + < Geometry_traits_2, Segment_2, Segment_2 > + ( geom_traits, seg, s2 ); + break; + } + } + } + old_orient = curr_orient; + } + assert( k+1( &result ); + if ( ipoint ) { + u = *ipoint; + } else { + u = vertices[k+1]; + } + return k; + } +}; + +} // namespace CGAL +#endif diff --git a/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h b/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h new file mode 100644 index 00000000000..b031b3f036a --- /dev/null +++ b/Visibility_2/include/CGAL/Triangular_expansion_visibility_2.h @@ -0,0 +1,579 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Michael Hemmer +// + +#ifndef CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H +#define CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H + +#include +#include +#include + +namespace CGAL { + +template +class Triangular_expansion_visibility_2 { + typedef typename Arrangement_2_::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Kernel K; +public: + // Currently only consider with same type for both + typedef Arrangement_2_ Arrangement_2; + typedef typename Arrangement_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Face_handle Face_handle; + typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement_2::Vertex_handle Vertex_handle; + + typedef typename K::Point_2 Point_2; + typedef typename Geometry_traits_2::Ray_2 Ray_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Line_2 Line_2; + typedef typename Geometry_traits_2::Vector_2 Vector_2; + typedef typename Geometry_traits_2::Direction_2 Direction_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Geometry_traits_2::Object_2 Object_2; + + // TODO + typedef RegularizationTag Regularization_tag; + + typedef CGAL::Tag_true Supports_general_polygon_tag; + typedef CGAL::Tag_true Supports_simple_polygon_tag; + +private: + typedef CGAL::Triangulation_vertex_base_2 Vb; + typedef CGAL::Constrained_triangulation_face_base_2 Fb; + typedef CGAL::Triangulation_data_structure_2 TDS; + typedef CGAL::No_intersection_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + +public: + const std::string name(){return std::string("T_visibility_2");} +private: + const Arrangement_2* p_arr; + boost::shared_ptr p_cdt; + std::vector needles; + +public: + Triangular_expansion_visibility_2() : p_arr(NULL){} + + /*! Constructor given an arrangement and the Regularization tag. */ + Triangular_expansion_visibility_2 (const Arrangement_2& arr) + : p_arr(&arr){ + init_cdt(); + } + + bool is_attached() { + //std::cout << "is_attached" << std::endl; + return (p_arr != NULL); + } + + void attach(const Arrangement_2& arr) { + // todo observe changes in arr; + if(p_arr != &arr){ + p_arr = &arr; + init_cdt(); + } + //std::cout << "attach done" << std::endl; + } + + void detach() { + //std::cout << "detach" << std::endl; + p_arr = NULL; + p_cdt = boost::shared_ptr(); + } + + const Arrangement_2& arr() { + return *p_arr; + } + + typename CDT::Edge get_edge(typename CDT::Face_handle fh, int i){ + return std::make_pair(fh,i); + } + + Point_2 ray_seg_intersection( + const Point_2& q, const Point_2& b, // the ray + const Point_2& s, const Point_2& t) // the segment + { + Ray_2 ray(q,b); + Segment_2 seg(s,t); + assert(typename K::Do_intersect_2()(ray,seg)); + CGAL::Object obj = typename K::Intersect_2()(ray,seg); + Point_2 result = object_cast(obj); + return result; + } + + void collect_needle( + const Point_2& q, + const typename CDT::Vertex_handle vh, + const typename CDT::Face_handle fh, + int index){ + + + // the expanded edge should not be constrained + assert(!p_cdt->is_constrained(get_edge(fh,index))); + assert(!p_cdt->is_infinite(fh)); + // go into the new face + const typename CDT::Face_handle nfh(fh->neighbor(index)); + assert(!p_cdt->is_infinite(nfh)); + + // get indices of neighbors + int nindex = nfh->index(fh); // index of new vertex and old face + int rindex = p_cdt->ccw(nindex); // index of face behind right edge + int lindex = p_cdt-> cw(nindex); // index of face behind left edge + + // get vertices seen from entering edge + const typename CDT::Vertex_handle nvh(nfh->vertex(nindex)); + const typename CDT::Vertex_handle rvh(nfh->vertex(p_cdt->cw (nindex))); + const typename CDT::Vertex_handle lvh(nfh->vertex(p_cdt->ccw(nindex))); + assert(!p_cdt->is_infinite(nvh)); + assert(!p_cdt->is_infinite(lvh)); + assert(!p_cdt->is_infinite(rvh)); + + // get edges seen from entering edge + typename CDT::Edge re = get_edge(nfh,p_cdt->ccw(nindex)); + typename CDT::Edge le = get_edge(nfh,p_cdt-> cw(nindex)); + + // do orientation computation once for new vertex + typename K::Orientation_2 orientation = + p_cdt->geom_traits().orientation_2_object(); + CGAL::Orientation orient = orientation(q,vh->point(),nvh->point()); + + + //std::cout << "\n collect_needle" <point() "<< vh->point() << std::endl; + //std::cout << "lvh->point() "<< lvh->point() << std::endl ; + //std::cout << "nvh->point() "<< nvh->point() << std::endl ; + //std::cout << "rvh->point() "<< rvh->point() << std::endl<< std::endl; + + + + switch ( orient ) { + case CGAL::COUNTERCLOCKWISE: + // looking on to the right edge + if(p_cdt->is_constrained(re)){ + if(vh!=rvh){ + Point_2 p = ray_seg_intersection(q,vh->point(),nvh->point(),rvh->point()); + //std::cout << vh->point() <<" -1- "<< p <point(),p)); + } + }else{ + collect_needle(q,vh,nfh,rindex); + } + break; + case CGAL::CLOCKWISE: + // looking on to the left edge + if(p_cdt->is_constrained(le)){ + if(vh!=lvh){ + Point_2 p = ray_seg_intersection(q,vh->point(),nvh->point(),lvh->point()); + //std::cout << vh->point() <<" -2- "<< p <point(),p)); + } + }else{ + collect_needle(q,vh,nfh,lindex); + } + break; + default: + assert(orient == CGAL::COLLINEAR); + // looking on nvh, so it must be reported + // if it wasn't already (triangles rotate around vh) + if(vh != nvh){ + //std::cout << vh->point() <<" -3- "<< nvh->point() <point(),nvh->point())); + } + // but we may also contiue looking along the vertex + if(!p_cdt->is_constrained(re)){ + collect_needle(q,nvh,nfh,rindex); + } + if(!p_cdt->is_constrained(le)){ + collect_needle(q,nvh,nfh,lindex); + } + break; + } + } + template + OIT expand_edge( + const Point_2& q, + const Point_2& left, + const Point_2& right, + typename CDT::Face_handle fh, + int index, + OIT oit){ + + // the expanded edge should not be constrained + assert(!p_cdt->is_constrained(get_edge(fh,index))); + assert(!p_cdt->is_infinite(fh)); + + // go into the new face + const typename CDT::Face_handle nfh(fh->neighbor(index)); + assert(!p_cdt->is_infinite(nfh)); + + // get indices of neighbors + int nindex = nfh->index(fh); // index of new vertex and old face + int rindex = p_cdt->ccw(nindex); // index of face behind right edge + int lindex = p_cdt-> cw(nindex); // index of face behind left edge + + // get vertices seen from entering edge + const typename CDT::Vertex_handle nvh(nfh->vertex(nindex)); + const typename CDT::Vertex_handle rvh(nfh->vertex(p_cdt->cw (nindex))); + const typename CDT::Vertex_handle lvh(nfh->vertex(p_cdt->ccw(nindex))); + assert(!p_cdt->is_infinite(nvh)); + assert(!p_cdt->is_infinite(lvh)); + assert(!p_cdt->is_infinite(rvh)); + + // get edges seen from entering edge + typename CDT::Edge re = get_edge(nfh,p_cdt->ccw(nindex)); + typename CDT::Edge le = get_edge(nfh,p_cdt-> cw(nindex)); + + // do orientation computation once for new vertex + typename K::Orientation_2 orientation = + p_cdt->geom_traits().orientation_2_object(); + CGAL::Orientation ro = orientation(q,right,nvh->point()); + CGAL::Orientation lo = orientation(q,left ,nvh->point()); + + assert(typename K::Orientation_2()(q,left ,lvh->point()) != CGAL::CLOCKWISE); + assert(typename K::Orientation_2()(q,right,rvh->point()) != CGAL::COUNTERCLOCKWISE); + + //std::cout << (ro == CGAL::COUNTERCLOCKWISE) << " " << (lo == CGAL::CLOCKWISE) << std::endl; + + + + //right edge is seen if new vertex is counter clockwise of right boarder + if(ro == CGAL::COUNTERCLOCKWISE){ + if(p_cdt->is_constrained(re)){ + // the edge is constrained + // report intersection with right boarder ray + // if it is not already the right vertex (already reported) + if(right != rvh->point()){ + *oit++ = ray_seg_intersection(q,right,nvh->point(),rvh->point()); + } + + // then report intersection with left boarder if it exists + if(lo == CGAL::COUNTERCLOCKWISE){ + *oit++ = ray_seg_intersection(q,left,nvh->point(),rvh->point()); + } + }else{ + // the edge is not a constrained + if(lo == CGAL::COUNTERCLOCKWISE){ + // no split needed and return + //std::cout<< "h1"<< std::endl; + oit = expand_edge(q,left,right,nfh,rindex,oit); + //std::cout<< "h1 done"<< std::endl; + return oit; + }else{ + // spliting at new vertex + //std::cout<< "h2"<< std::endl; + *oit++ = expand_edge(q,nvh->point(),right,nfh,rindex,oit); + //std::cout<< "h2 done"<< std::endl; + } + } + } + + + //std::cout << "q "<< q << std::endl ; + //std::cout << "lvh->point() "<< lvh->point() << std::endl; + //std::cout << "left "<< left << std::endl ; + //std::cout << "nvh->point() "<< nvh->point() << std::endl ; + //std::cout << "right "<< right << std::endl ; + //std::cout << "rvh->point() "<< rvh->point() << std::endl<< std::endl; + + + // determin whether new vertex needs to be reported + if(ro != CGAL::CLOCKWISE && lo != CGAL::COUNTERCLOCKWISE){ + *oit++ = nvh->point(); + } + if(!Regularization_tag::value){ + assert(!(ro == CGAL::COLLINEAR && lo == CGAL::COLLINEAR)); + // we have to check whether a needle starts here. + if(p_cdt->is_constrained(le) && !p_cdt->is_constrained(re) && ro == CGAL::COLLINEAR) + collect_needle(q,nvh,nfh,rindex); + if(p_cdt->is_constrained(re) && !p_cdt->is_constrained(le) && lo == CGAL::COLLINEAR) + collect_needle(q,nvh,nfh,lindex); + } + + //left edge is seen if new vertex is clockwise of left boarder + if(lo == CGAL::CLOCKWISE){ + if(p_cdt->is_constrained(le)){ + // the edge is constrained + // report interesection with right boarder if exists + if(ro == CGAL::CLOCKWISE){ + *oit++ = ray_seg_intersection(q,right,nvh->point(),lvh->point()); + } + // then report intersection with left boarder ray + // if it is not already the left vertex (already reported) + if(left != lvh->point()){ + *oit++ = ray_seg_intersection(q,left,nvh->point(),lvh->point()); + } + return oit; + }else{ + // the edge is not a constrained + if(ro == CGAL::CLOCKWISE){ + // no split needed and return + //std::cout<< "h3"<< std::endl; + oit = expand_edge(q,left,right,nfh,lindex,oit); + //std::cout<< "h3 done"<< std::endl; + return oit; + }else{ + // spliting at new vertex + //std::cout<< "h4"<< std::endl; + oit = expand_edge(q,left,nvh->point(),nfh,lindex,oit); + //std::cout<< "h4 done"<< std::endl; + return oit; + } + } + } + + return oit; + } + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, + const Face_const_handle face, + VARR& out_arr + ){ + //std::cout << "query in face interior" << std::endl; + + out_arr.clear(); + needles.clear(); + assert(!face->is_unbounded()); + + + std::vector raw_output; + typename CDT::Face_handle fh = p_cdt->locate(q); + + raw_output.push_back(fh->vertex(1)->point()); + if(!p_cdt->is_constrained(get_edge(fh,0))){ + //std::cout<< "edge 0 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(2)->point(), + fh->vertex(1)->point(), + fh,0,std::back_inserter(raw_output)); + } + + raw_output.push_back(fh->vertex(2)->point()); + if(!p_cdt->is_constrained(get_edge(fh,1))){ + //std::cout << "edge 1 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(0)->point(), + fh->vertex(2)->point(), + fh,1,std::back_inserter(raw_output)); + } + + raw_output.push_back(fh->vertex(0)->point()); + if(!p_cdt->is_constrained(get_edge(fh,2))){ + //std::cout << "edge 2 is not constrained" << std::endl; + expand_edge( + q, + fh->vertex(1)->point(), + fh->vertex(0)->point(), + fh,2,std::back_inserter(raw_output)); + } + + + return output(raw_output,out_arr); + } + + template + typename VARR::Face_handle + compute_visibility(const Point_2& q, + const Halfedge_const_handle he, + VARR& out_arr) { + //std::cout << "visibility_region he" << std::endl; + + assert(!he->face()->is_unbounded()); + out_arr.clear(); + needles.clear(); + + std::vector raw_output; + typename CDT::Locate_type location; + int index; + typename CDT::Face_handle fh = p_cdt->locate(q,location,index); + assert(location == CDT::EDGE || location == CDT::VERTEX); + // the following code tries to figure out which triangle one should start in. + + + if(location == CDT::EDGE){ + //std::cout << "query on edge" << std::endl; + // this is the easy part, there are only two possible faces + // index indicates the edge = vertex on the other side of the edge + // the next vertex in cw order should be the target of given edge + if(fh->vertex(p_cdt->cw(index))->point() != he->target()->point()){ + //std::cout << "need to swap face" << std::endl; + // take face on the other side if this is not the case + typename CDT::Face_handle nfh = fh->neighbor(index); + index = nfh->index(fh); + fh = nfh; + } + assert(fh->vertex(p_cdt->cw(index))->point() == he->target()->point()); + assert(!p_cdt->is_infinite(fh->vertex(index))); + + + // output the edge the query lies on + raw_output.push_back(he->source()->point()); + raw_output.push_back(he->target()->point()); + + if(!p_cdt->is_constrained(get_edge(fh,p_cdt->ccw(index)))){ + expand_edge( + q, + fh->vertex(index)->point(), //left + he->target()->point() , //right + fh, + p_cdt->ccw(index), + std::back_inserter(raw_output)); + } + raw_output.push_back(fh->vertex(index)->point()); + + if(!p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))){ + expand_edge( + q, + he->source()->point() , //left + fh->vertex(index)->point(), //right + fh, + p_cdt->cw(index), + std::back_inserter(raw_output)); + } + } + + if(location == CDT::VERTEX){ + //std::cout << "query on vertex" << std::endl; + + //bool query_point_on_vertex_is_not_working_yet = false; + //assert(query_point_on_vertex_is_not_working_yet); + + assert(q == he->target()->point()); + assert(fh->vertex(index)->point() == he->target()->point()); + + // push points that are seen anyway + // raw_output.push_back(he->source()->point()); inserted last + raw_output.push_back(he->target()->point()); + raw_output.push_back(he->next()->target()->point()); + + // now start in the triangle that contains he->next() + while( + p_cdt->is_infinite(fh->vertex(p_cdt->ccw(index))) || + he->next()->target()->point() != fh->vertex(p_cdt->ccw(index))->point()){ + typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); + int nindex = nfh->index(fh); + index = p_cdt->ccw(nindex); + fh = nfh; + assert(he->target()->point() == fh->vertex(index)->point()); + } + + + + + assert(he->next()->source()->point() == fh->vertex(index)->point()); + assert(he->next()->target()->point() == fh->vertex(p_cdt->ccw(index))->point()); + assert(!p_cdt->is_infinite(fh)); + assert(p_cdt->is_constrained(get_edge(fh,p_cdt->cw(index)))); + + while(he->source()->point() != fh->vertex(p_cdt->ccw(index))->point()){ + + if(!p_cdt->is_constrained(get_edge(fh,index))){ + expand_edge( + q, + fh->vertex(p_cdt-> cw(index))->point(), //left + fh->vertex(p_cdt->ccw(index))->point(), //right + fh, + index, + std::back_inserter(raw_output)); + } + // push left end point of edge into output + raw_output.push_back(fh->vertex(p_cdt-> cw(index))->point()); + + // take the next triangle around q in ccw order + typename CDT::Face_handle nfh = fh->neighbor(p_cdt->ccw(index)); + int nindex = nfh->index(fh); + index = p_cdt->ccw(nindex); + fh = nfh; + assert(fh->vertex(index)->point() == he->target()->point()); + } + } + return output(raw_output,out_arr); + } + + template + typename VARR::Face_handle + output(std::vector& raw_output, VARR& out_arr){ + + if(needles.size()>0){ + std::vector segments(needles.begin(),needles.end()); + for(unsigned int i = 0; i target(); + }else{ + v_last = out_arr.insert_from_right_vertex(Segment_2(raw_output[i], raw_output[i+1]), v_last)->target(); + } + } + out_arr.insert_at_vertices(Segment_2(raw_output.front(),raw_output.back()),v_last,v_first); + } + + assert(out_arr.number_of_faces()== 2); + + if(out_arr.faces_begin()->is_unbounded()) + return ++out_arr.faces_begin(); + else + return out_arr.faces_begin(); + } + + void init_cdt(){ + //std::cout<< "==============" < > constraints; + for(typename Arrangement_2::Edge_const_iterator eit = p_arr->edges_begin(); + eit != p_arr->edges_end(); eit++){ + Point_2 source = eit->source()->point(); + Point_2 target = eit->target()->point(); + //std::cout << source << " -- " << target << std::endl; + constraints.push_back(std::make_pair(source,target)); + } + //std::cout << "init_cdt new CDT" << std::endl; + p_cdt = boost::shared_ptr(new CDT(constraints.begin(),constraints.end())); + //std::cout << "init_cdt done" << std::endl; + //std::cout << std::endl; + } +}; + +} // namespace CGAL + +#endif //CGAL_TRIANGULAR_EXPANSION_VISIBILITY_2__H diff --git a/Visibility_2/include/CGAL/Visibility_2/visibility_utils.h b/Visibility_2/include/CGAL/Visibility_2/visibility_utils.h new file mode 100644 index 00000000000..90f092522f5 --- /dev/null +++ b/Visibility_2/include/CGAL/Visibility_2/visibility_utils.h @@ -0,0 +1,371 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer + +#ifndef CGAL_VISIBILITY_UTILS_H +#define CGAL_VISIBILITY_UTILS_H + +#include +#include +#include + +namespace CGAL { +namespace Visibility_2 { + + template +int count_edges_in_face(typename Arrangement_2::Face_const_handle fch) { + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + + Ccb_halfedge_const_circulator circ = fch->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + + int edge_cnt(0); + do { + edge_cnt++; + } while (++curr != circ); + return edge_cnt; +} + +template +void print_edge(Edge_const_iterator eit) { + std::cout << "[" << eit->curve() << "]" << std::endl; +} +template +void print_simple_face(Face_const_handle fh) { + Ccb_halfedge_const_circulator cir = fh->outer_ccb(); + Ccb_halfedge_const_circulator curr = cir; + do { + std::cout << "[" << curr->curve() << "]" << std::endl; + } while (++ curr != cir); +} + +template +void print_arrangement(const Arrangement_2& arr) { + typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator; + Edge_const_iterator eit; + std::cout << arr.number_of_edges() << " edges:" << std::endl; + for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit) + print_edge(eit); +} + +template +void print_arrangement_by_face(const Arrangement_2& arr) { + typedef typename Arrangement_2::Face_const_iterator Face_const_iterator; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + Face_const_iterator fit; + for (fit = arr.faces_begin() ; fit != arr.faces_end() ; fit++) { + if (!fit->is_unbounded()) { + std::cout << "FACE\n"; + print_simple_face(fit); + std::cout << "END FACE\n"; + } + } +} + +template +Orientation orientation_2(const Geometry_traits_2 *geom_traits, + const typename Geometry_traits_2::Point_2& p, + const typename Geometry_traits_2::Point_2& q, + const typename Geometry_traits_2::Point_2& r) { + + typename Geometry_traits_2::Orientation_2 orient = + geom_traits->orientation_2_object(); + return orient(p, q, r); +} + +template +bool less_distance_to_point_2(const Geometry_traits_2 *geom_traits, + const typename Geometry_traits_2::Point_2& p, + const typename Geometry_traits_2::Point_2& q, + const typename Geometry_traits_2::Point_2& r) { + + typename Geometry_traits_2::Less_distance_to_point_2 less_dist = + geom_traits->less_distance_to_point_2_object(); + return less_dist(p, q, r); +} + +template +bool collinear(const Geometry_traits_2 *geom_traits, + const typename Geometry_traits_2::Point_2& p, + const typename Geometry_traits_2::Point_2& q, + const typename Geometry_traits_2::Point_2& r) { + + typename Geometry_traits_2::Collinear_2 collinear_fnct = + geom_traits->collinear_2_object(); + return collinear_fnct(p, q, r); +} + +template +typename Geometry_traits_2::Object_2 intersect_2(const Geometry_traits_2 *geom_traits, + const _Curve_first& s1, + const _Curve_second& s2) { + + typedef typename Geometry_traits_2::Kernel Kernel; + const Kernel *kernel = static_cast (geom_traits); + typename Kernel::Intersect_2 intersect_fnct = kernel->intersect_2_object(); + return intersect_fnct(s1, s2); +} + +template +CGAL::Comparison_result compare_xy_2(const Geometry_traits_2 *geom_traits, + const typename Geometry_traits_2::Point_2 &p, + const typename Geometry_traits_2::Point_2 &q) { + + typename Geometry_traits_2::Compare_xy_2 cmp = + geom_traits->compare_xy_2_object(); + return cmp(p, q); +} + +template +typename Geometry_traits_2::FT compute_squared_distance_2( + const Geometry_traits_2 *geom_traits, + const Type1& p, + const Type2& seg) { + + typename Geometry_traits_2::Compute_squared_distance_2 compute_dist = + geom_traits->compute_squared_distance_2_object(); + return compute_dist(p, seg); +} + +template +bool do_intersect_2(const Geometry_traits_2 *geom_traits, + const Type1& c1, + const Type2& c2) { + + typename Geometry_traits_2::Do_intersect_2 intersect = + geom_traits->do_intersect_2_object(); + return intersect(c1, c2); +} + +template +bool collinear_are_ordered_along_line_2(const Geometry_traits_2 *geom_traits, + const typename Geometry_traits_2::Point_2 &p, + const typename Geometry_traits_2::Point_2 &q, + const typename Geometry_traits_2::Point_2 &r) { + + typename Geometry_traits_2::Collinear_are_ordered_along_line_2 coll = + geom_traits->collinear_are_ordered_along_line_2_object(); + return coll(p, q, r); +} + +template +typename Geometry_traits_2::Point_2 construct_projected_point_2( + const Geometry_traits_2 *geom_traits, + const Type1& s, + const Type2& p) { + + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typename Geometry_traits_2::Construct_projected_point_2 construct_proj = + geom_traits->construct_projected_point_2_object(); + Point_2 proj_pt = construct_proj(s.supporting_line(), p); + if (s.has_on(proj_pt)) { + return proj_pt; + } + else { + Number_type d_to_src = compute_squared_distance_2 + (geom_traits, proj_pt, s.source()); + Number_type d_to_trg = compute_squared_distance_2 + (geom_traits, proj_pt, s.target()); + if (d_to_src < d_to_trg) { + return s.source(); + } + else { + return s.target(); + } + } +} + +//construct an arrangement of visibility region from a vector of circular ordered vertices with respect to the query point +template +void report_while_handling_needles( + const typename Visibility_2::Arrangement_2::Geometry_traits_2 *geom_traits, + const typename Visibility_2::Arrangement_2::Point_2& q, + std::vector& points, + Visibility_arrangement_2& arr_out) { + + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Point_2 Point_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Vertex_handle Vertex_handle; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Direction_2 Direction_2; + + typename std::vector::size_type i = 0; + + if (points.front() == points.back()) { + points.pop_back(); + } + + while (collinear(geom_traits, + q, + points[i], + points.back())) { + + points.push_back(points[i]); + i++; + } + + points.push_back(points[i]); + + typename Visibility_arrangement_2::Halfedge_handle he_handle; + typename Visibility_arrangement_2::Vertex_handle v_trg; //the handle of vertex where the next segment is inserted + typename Visibility_arrangement_2::Vertex_handle v_fst; //the handle of vertex inserted first + typename Visibility_arrangement_2::Vertex_handle v_needle_end; //the handle of vertex of the end of a needle + + v_trg = v_fst = arr_out.insert_in_face_interior(points[i], arr_out.unbounded_face()); + //find a point that is right after a needle + while (i+1 < points.size()) { + if ( collinear(geom_traits, + points[i], + points[i+1], + q)) { + typename Visibility_arrangement_2::Vertex_handle v_needle_begin = v_trg; + std::vector forward_needle; //vertices of the needle that are not between q and v_needle_begin; their direction is leaving q; + std::vector backward_needle; //vertices of the needle that are not between q and v_needle_begin; their direction is towards q; + std::vector part_in_q_side; //vertices of the needle that are between q and v_needle_begin + part_in_q_side.push_back(points[i]); + forward_needle.push_back((points[i])); + + bool same_side_of_q = (compare_xy_2(geom_traits, points[i], q)==compare_xy_2(geom_traits, points[i], points[i+1])); + if (same_side_of_q) + part_in_q_side.push_back(points[i+1]); + else + forward_needle.push_back(points[i+1]); + i++; + while (i+1< points.size() && orientation_2(geom_traits, + points[i], + points[i+1], + q ) == CGAL::COLLINEAR) { + if (same_side_of_q) { + part_in_q_side.push_back(points[i+1]); + } + else { + if (compare_xy_2(geom_traits, part_in_q_side.front(), q) + == compare_xy_2(geom_traits, part_in_q_side.front(), points[i+1])) { + same_side_of_q = true; + part_in_q_side.push_back(points[i+1]); + } + else { + if (less_distance_to_point_2(geom_traits, q, points[i], points[i+1])) + forward_needle.push_back(points[i+1]); + else + backward_needle.push_back(points[i+1]); + } + } + i++; + } + //obtain the end point of a needle + Point_2 end_of_needle; + if (same_side_of_q) + end_of_needle = part_in_q_side.back(); + else { + if (backward_needle.empty()) { + end_of_needle = forward_needle.back(); + } + else { + end_of_needle = backward_needle.back(); + } + } + + std::reverse(backward_needle.begin(), backward_needle.end()); + std::vector merged_needle; + + // merge the forward_needle and backward_needle + unsigned int itr_fst = 0, itr_snd = 0; + while (itr_fst < forward_needle.size() && + itr_snd < backward_needle.size()) { + + if (less_distance_to_point_2(geom_traits, + q, + forward_needle[itr_fst], + backward_needle[itr_snd])) { + + merged_needle.push_back(forward_needle[itr_fst]); + itr_fst++; + } + else { + merged_needle.push_back(backward_needle[itr_snd]); + itr_snd++; + } + } + while (itr_fst < forward_needle.size()) { + merged_needle.push_back(forward_needle[itr_fst]); + itr_fst++; + } + while (itr_snd < backward_needle.size()) { + merged_needle.push_back(backward_needle[itr_snd]); + itr_snd++; + } + + for (unsigned int p = 0 ; p+1 < merged_needle.size() ; p++) { + if (CGAL::Visibility_2::compare_xy_2(geom_traits, merged_needle[p], merged_needle[p+1]) == CGAL::SMALLER) { + he_handle = arr_out.insert_from_left_vertex(Segment_2(merged_needle[p], merged_needle[p+1]), v_trg); + } + else { + he_handle = arr_out.insert_from_right_vertex(Segment_2(merged_needle[p], merged_needle[p+1]), v_trg); + } + v_trg = he_handle->target(); + if (merged_needle[p+1] == end_of_needle) { + v_needle_end = v_trg; + } + } + if (same_side_of_q) { + //insert the part of needle between q and v_needle_begin + v_trg = v_needle_begin; + for (unsigned int p = 0 ; p+1 < part_in_q_side.size() ; p++) { + if (CGAL::Visibility_2::compare_xy_2(geom_traits, part_in_q_side[p], part_in_q_side[p+1]) == CGAL::SMALLER) { + he_handle = arr_out.insert_from_left_vertex(Segment_2(part_in_q_side[p], part_in_q_side[p+1]), v_trg); + } + else { + he_handle = arr_out.insert_from_right_vertex(Segment_2(part_in_q_side[p], part_in_q_side[p+1]), v_trg); + } + v_trg = he_handle->target(); + } + } + else + v_trg = v_needle_end; + } + else { + if (CGAL::Visibility_2::compare_xy_2(geom_traits, v_trg->point(), points[i+1]) == CGAL::SMALLER) { + he_handle = arr_out.insert_from_left_vertex(Segment_2(points[i], points[i+1]), v_trg); + } + else { + he_handle = arr_out.insert_from_right_vertex(Segment_2(points[i], points[i+1]), v_trg); + } + v_trg = he_handle->target(); + i++; + } + if (i+2 == points.size()) { + //close the boundary + v_trg = he_handle->target(); + arr_out.insert_at_vertices(Segment_2(points[points.size()-2], points[points.size()-1]), v_trg, v_fst); + break; + } + } +} + +} // end namespace Visibility_2 +} // end namespace CGAL + +#endif diff --git a/Visibility_2/package_info/README b/Visibility_2/package_info/README new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Visibility_2/package_info/Visibility_2/copyright b/Visibility_2/package_info/Visibility_2/copyright new file mode 100644 index 00000000000..ef4df740e24 --- /dev/null +++ b/Visibility_2/package_info/Visibility_2/copyright @@ -0,0 +1 @@ +Braunschweig University (Germany). diff --git a/Visibility_2/package_info/Visibility_2/description.txt b/Visibility_2/package_info/Visibility_2/description.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Visibility_2/package_info/Visibility_2/license.txt b/Visibility_2/package_info/Visibility_2/license.txt new file mode 100644 index 00000000000..8bb8efcb72b --- /dev/null +++ b/Visibility_2/package_info/Visibility_2/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) diff --git a/Visibility_2/package_info/Visibility_2/maintainer b/Visibility_2/package_info/Visibility_2/maintainer new file mode 100644 index 00000000000..42bbe33488e --- /dev/null +++ b/Visibility_2/package_info/Visibility_2/maintainer @@ -0,0 +1 @@ +Michael Hemmer \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/create_benchmark_report.sh b/Visibility_2/test/Visibility_2/create_benchmark_report.sh new file mode 100755 index 00000000000..f3ae0e812da --- /dev/null +++ b/Visibility_2/test/Visibility_2/create_benchmark_report.sh @@ -0,0 +1,18 @@ +#!/bin/bash +dir="../../data/example" +nameend=".environment" +type1=S +type2=T +report_name="${type1}${type2}_report.txt" +echo "" >$report_name +for (( i=1; i<9; i=i+1)); do + file="${dir}${i}${nameend}" + for query_type in face edge vertex; do + echo "file_name: ${file}" >>$report_name + echo "query_type: ${query_type}" >>$report_name + echo "regularize: yes" >>$report_name + ./simple_benchmark $file $type1 $type2 $query_type true >>$report_name + echo "regularize: no" >>$report_name + ./simple_benchmark $file $type1 $type2 $query_type false >>$report_name + done +done \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/in1 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in1 new file mode 100644 index 00000000000..2700fe53598 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in1 @@ -0,0 +1,17 @@ +# Test case 1 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 +2 0 +4 0 +6 0 +8 0 +-10 10 +10 10 +10 -10 +-10 -10 +6 +0 1 +2 3 +4 5 +5 6 +6 7 +7 4 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/in2 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in2 new file mode 100644 index 00000000000..69304687bd6 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in2 @@ -0,0 +1,29 @@ +# Test case 2 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +16 +2 2 +2 0 +5 1 +5 0 +8 1 +8 0 +3 -1 +3 -3 +6 -2 +6 -3 +7 0 +7 -2 +-10 10 +10 10 +10 -10 +-10 -10 +10 +0 1 +2 3 +4 5 +6 7 +8 9 +10 11 +12 13 +13 14 +14 15 +15 12 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/in3 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in3 new file mode 100644 index 00000000000..39dd279c79b --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in3 @@ -0,0 +1,19 @@ +# Test case 2 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 +-1 4 +3 0 +6 4 +6 0 +5 0 +5 -4 +1 0 +-1 -4 +8 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 0 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/in4 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in4 new file mode 100644 index 00000000000..6b68c501674 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in4 @@ -0,0 +1,40 @@ +# Test case 4 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +19 +-1 3 +0 3 +0 2 +3 3 +1 1 +3 0 +4 0 +5 0 +4 -1 +7 0 +7 -4 +2 -4 +1 -2 +2 0 +-1 -4 +-10 10 +10 10 +10 -10 +-10 -10 +18 +0 1 +1 2 +1 3 +3 4 +3 5 +5 6 +7 8 +7 9 +9 10 +10 11 +11 12 +12 13 +11 14 +14 0 +15 16 +16 17 +17 18 +18 15 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/in5 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in5 new file mode 100644 index 00000000000..5e26ca7b6a7 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/in5 @@ -0,0 +1,35 @@ +# Test case 5 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +17 +5 2 +7 2 +2 1 +1 0 +2 0 +3 0 +5 0 +6 0 +7 0 +1 -2 +2 -2 +3 -2 +4 -2 +-10 10 +10 10 +10 -10 +-10 -10 +15 +0 7 +1 7 +2 3 +4 5 +6 7 +7 8 +9 4 +10 4 +11 4 +12 5 +12 6 +13 14 +14 15 +15 16 +16 13 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out1 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out1 new file mode 100644 index 00000000000..9652c0f85ea --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out1 @@ -0,0 +1,20 @@ +9 +2 0 +4 0 +6 0 +8 0 +10 0 +10 10 +-10 10 +-10 -10 +10 -10 +9 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 4 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out2 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out2 new file mode 100644 index 00000000000..1e99dfa0792 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out2 @@ -0,0 +1,35 @@ +# Non-regularized visibility result of Test case 2 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +16 +10 10 +2 2 +2 0 +5 0 +7 0 +8 0 +10 0 +7 -2 +10 -20/7 +3 -1 +6 -2 +10 -10/3 +3 -3 +10 -10 +-10 -10 +-10 10 +16 +1 0 +1 2 +2 3 +3 4 +4 5 +5 6 +4 7 +7 8 +8 11 +9 10 +10 11 +9 12 +12 13 +13 14 +14 15 +15 0 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out3 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out3 new file mode 100644 index 00000000000..cdd4288c369 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out3 @@ -0,0 +1,15 @@ +# Non-regularized visibility result of Test case 3 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +6 +-1 4 +-1 -4 +1 0 +3 0 +5 0 +6 0 +6 +0 1 +1 2 +2 3 +3 4 +4 5 +0 3 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out4 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out4 new file mode 100644 index 00000000000..0eb09835e36 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out4 @@ -0,0 +1,31 @@ +# Non-regularized visibility result of Test case 4 for arbitrary arrangement. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +14 +0 2 +0 3 +-1 3 +-1 -4 +2 -4 +1 -2 +2 0 +3 0 +4 0 +5 0 +7 0 +10 0 +3 3 +1 1 +14 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +7 12 +12 13 +1 12 diff --git a/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out5 b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out5 new file mode 100644 index 00000000000..2d97d1a932b --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/Arrangement_Test/non_regular_out5 @@ -0,0 +1,26 @@ +12 +1 0 +2 0 +3 0 +5 0 +6 0 +1 -2 +5 -10 +-10 -10 +-10 10 +10 10 +10 5 +2 1 +12 +0 1 +1 2 +2 3 +3 4 +1 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +11 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.in b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.in new file mode 100644 index 00000000000..26f74cedc8d --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.in @@ -0,0 +1,12 @@ +# Test case 1 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +4 +0 0 +8 0 +8 8 +0 8 +4 +0 1 +1 2 +2 3 +3 0 +4 4 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.out b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.out new file mode 100644 index 00000000000..068e55863cf --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_1.out @@ -0,0 +1,10 @@ +4 +0 0 +8 0 +8 8 +0 8 +4 +0 1 +1 2 +2 3 +3 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_11.dat b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_11.dat new file mode 100644 index 00000000000..230ab1db98c --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_11.dat @@ -0,0 +1,23 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 2 +8 2 + +0 +7 +0 0 +14 0 +14 7 +7 7 +6 4 +6 2 +0 2 + +0 +7 +0 0 +14 0 +14 7 +7 7 +6 4 +6 2 +0 2 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.in b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.in new file mode 100644 index 00000000000..726d765637a --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.in @@ -0,0 +1,12 @@ +# Test case 2 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +4 +0 0 +4 4 +8 4 +0 8 +4 +0 1 +1 2 +2 3 +3 0 +1 3 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.out b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.out new file mode 100644 index 00000000000..f725e56ccff --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_2.out @@ -0,0 +1,10 @@ +4 +0 0 +4 4 +32/5 24/5 +0 8 +4 +0 1 +1 2 +2 3 +3 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.in b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.in new file mode 100644 index 00000000000..af54c28320a --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.in @@ -0,0 +1,20 @@ +# Test case 2 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 +0 0 +13 0 +13 4 +11 2 +9 4 +7 2 +4 2 +0 5 +8 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 0 +2 2 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.out b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.out new file mode 100644 index 00000000000..b297b5aa35b --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_3.out @@ -0,0 +1,17 @@ +# Test case 2 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +7 +0 0 +13 0 +13 2 +11 2 +7 2 +4 2 +0 5 +7 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.in b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.in new file mode 100644 index 00000000000..0a6d3b4e5e0 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.in @@ -0,0 +1,20 @@ +# Test case 4 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 +0 0 +4 0 +8 3 +12 0 +12 3 +8 6 +4 3 +0 3 +8 +0 1 +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 0 +2 3 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.out b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.out new file mode 100644 index 00000000000..eb97ed629ba --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/simple_polygon_test_case_4.out @@ -0,0 +1,15 @@ +# Test case 4 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +6 +0 0 +4 0 +8 3 +12 3 +4 3 +0 3 +6 +0 1 +1 2 +2 3 +2 4 +4 5 +5 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_1.dat b/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_1.dat new file mode 100644 index 00000000000..4642e7f61e8 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_1.dat @@ -0,0 +1,29 @@ +# Test case 1 for non-simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 2 +2 2 + +0 +10 +0 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 +4 0 9 2 +9 2 11 0 + +0 +8 +0 0 4 0 +4 0 9 2 +9 2 11 2 +11 2 13 2 +7 2 9 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 + + diff --git a/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_2.dat b/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_2.dat new file mode 100644 index 00000000000..7a0c8b5c867 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_non_simple_polygon_2.dat @@ -0,0 +1,30 @@ +# Test case 2 for non-simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +11 2 +13 4 + +0 +10 +0 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 +4 0 9 2 +9 2 11 0 + +0 +9 +11 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 2 +7 2 9 2 +9 2 11 0 + + diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_1.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_1.dat new file mode 100644 index 00000000000..1c1831df549 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_1.dat @@ -0,0 +1,17 @@ +# Test case 1 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +4 4 +4 4 + +0 +4 +0 0 8 0 +8 0 8 8 +8 8 0 8 +0 8 0 0 + +0 +4 +0 0 8 0 +8 0 8 8 +8 8 0 8 +0 8 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_10.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_10.dat new file mode 100644 index 00000000000..45f82bd5756 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_10.dat @@ -0,0 +1,36 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 8 +9 10 + +0 +18 +0 0 3 2 +3 2 5 1 +5 1 8 1 +8 1 16 2 +16 2 16 5 +16 5 14 4 +14 4 12 7 +12 7 10 4 +10 4 8 4 +8 4 10 8 +10 8 9 10 +9 10 8 8 +8 8 6 8 +6 8 7 6 +7 6 1 6 +1 6 4 8 +4 8 0 9 +0 9 0 0 + +0 +9 +7 6 6 8 +6 8 8 8 +8 8 9 10 +9 10 10 8 +10 8 8 4 +8 4 8 1 +8 1 5 1 +5 1 23/5 6/5 +23/5 6/5 7 6 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat new file mode 100644 index 00000000000..d541a8e3189 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_11.dat @@ -0,0 +1,23 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 2 +8 2 + +0 +7 +0 0 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 + +0 +7 +0 0 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat new file mode 100644 index 00000000000..50293f02a44 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_12.dat @@ -0,0 +1,27 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +8 2 +8 2 + +0 +9 +0 0 8 0 +8 0 12 4 +12 4 14 0 +14 0 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 + +0 +9 +0 0 8 0 +8 0 12 4 +12 4 14 5 +14 5 14 7 +14 7 7 7 +7 7 6 4 +6 4 6 2 +6 2 0 2 +0 2 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat new file mode 100644 index 00000000000..89a50356237 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_13.dat @@ -0,0 +1,26 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 2 +5 2 + +0 +11 +0 0 12 0 +12 0 12 4 +12 4 8 7 +8 7 11 9 +11 9 11 12 +11 12 6 9 +6 9 0 12 +0 12 0 10 +0 10 8 5 +8 5 0 5 +0 5 0 0 + +0 +6 +0 0 12 0 +12 0 12 4 +12 4 64/7 43/7 +64/7 43/7 8 5 +8 5 0 5 +0 5 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat new file mode 100644 index 00000000000..1f3f06be81f --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_14.dat @@ -0,0 +1,26 @@ +# Test case 10 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 3 +2 3 + +0 +10 +0 0 8 0 +8 0 10 3 +10 3 10 6 +10 6 9 4 +9 4 8 6 +8 6 8 2 +8 2 6 3 +6 3 6 7 +6 7 0 7 +0 7 0 0 + +0 +7 +0 0 8 0 +8 0 46/5 9/5 +46/5 9/5 8 2 +8 2 6 3 +6 3 6 7 +6 7 0 7 +0 7 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat new file mode 100644 index 00000000000..f5e0a064fa7 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_15.dat @@ -0,0 +1,21 @@ +# Test case 15 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 4 +5 4 + +0 +6 +0 0 8 0 +8 0 8 8 +8 8 3 8 +3 8 3 4 +3 4 0 6 +0 6 0 0 + +0 +6 +0 0 8 0 +8 0 8 8 +8 8 3 8 +3 8 3 4 +3 4 0 4 +0 4 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat new file mode 100644 index 00000000000..1a22709c2e5 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_16.dat @@ -0,0 +1,22 @@ +# Test case 16 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +3 3 +3 3 + +0 +7 +0 0 12 0 +12 0 12 3 +12 3 9 5 +9 5 6 3 +6 3 3 5 +3 5 0 3 +0 3 0 0 + +0 +6 +0 0 12 0 +12 0 12 3 +12 3 6 3 +6 3 3 5 +3 5 0 3 +0 3 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat new file mode 100644 index 00000000000..5f58092bdda --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_17.dat @@ -0,0 +1,24 @@ +# Test case 17 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 3 +2 3 + +0 +8 +0 0 12 0 +12 0 12 3 +12 3 9 5 +9 5 6 3 +6 3 4 3 +4 3 2 6 +2 6 0 3 +0 3 0 0 + +0 +7 +0 0 12 0 +12 0 12 3 +12 3 6 3 +6 3 4 3 +4 3 2 6 +2 6 0 3 +0 3 0 0 \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_18.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_18.dat new file mode 100644 index 00000000000..53977df93c6 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_18.dat @@ -0,0 +1,51 @@ +0 0 +0 0 + +0 +37 +20 0 20 20 +20 20 -40 20 +-40 20 -40 -40 +-40 -40 40 -40 +40 -40 40 40 +40 40 -60 40 +-60 40 -60 -60 +-60 -60 60 -60 +60 -60 60 60 +60 60 -80 60 +-80 60 -80 -80 +-80 -80 80 -80 +80 -80 80 80 +80 80 -100 80 +-100 80 -100 -100 +-100 -100 100 -100 +100 -100 100 100 +100 100 90 100 +90 100 90 -90 +90 -90 -90 -90 +-90 -90 -90 70 +-90 70 70 70 +70 70 70 -70 +70 -70 -70 -70 +-70 -70 -70 50 +-70 50 50 50 +50 50 50 -50 +50 -50 -50 -50 +-50 -50 -50 30 +-50 30 30 30 +30 30 30 -30 +30 -30 -30 -30 +-30 -30 -30 10 +-30 10 -10 10 +-10 10 -10 -10 +-10 -10 20 -10 +20 -10 20 0 + +0 +6 +-10 -10 20 -10 +20 -10 20 0 +20 0 20 20 +20 20 -20 20 +-20 20 -10 10 +-10 10 -10 -10 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_19.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_19.dat new file mode 100644 index 00000000000..1a30a031e63 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_19.dat @@ -0,0 +1,51 @@ +0 0 +0 0 + +0 +38 +-10 -10 10 -10 +10 -10 10 10 +10 10 20 10 +20 10 20 -20 +20 -20 -20 -20 +-20 -20 -20 30 +-20 30 40 30 +40 30 40 -40 +40 -40 -40 -40 +-40 -40 -40 50 +-40 50 60 50 +60 50 60 -60 +60 -60 -60 -60 +-60 -60 -60 70 +-60 70 80 70 +80 70 80 -80 +80 -80 -80 -80 +-80 -80 -80 90 +-80 90 100 90 +100 90 100 100 +100 100 -90 100 +-90 100 -90 -90 +-90 -90 90 -90 +90 -90 90 80 +90 80 -70 80 +-70 80 -70 -70 +-70 -70 70 -70 +70 -70 70 60 +70 60 -50 60 +-50 60 -50 -50 +-50 -50 50 -50 +50 -50 50 40 +50 40 -30 40 +-30 40 -30 -30 +-30 -30 30 -30 +30 -30 30 20 +30 20 -10 20 +-10 20 -10 -10 + +0 +5 +-10 20 -10 -10 +-10 -10 10 -10 +10 -10 10 10 +10 10 20 20 +20 20 -10 20 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_2.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_2.dat new file mode 100644 index 00000000000..c4113a8b559 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_2.dat @@ -0,0 +1,17 @@ +# Test case 2 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +1 3 +1 3 + +0 +4 +0 0 4 4 +4 4 8 4 +8 4 0 8 +0 8 0 0 + +0 +4 +0 0 4 4 +4 4 32/5 24/5 +32/5 24/5 0 8 +0 8 0 0 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_20.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_20.dat new file mode 100644 index 00000000000..6b1d08de06e --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_20.dat @@ -0,0 +1,39 @@ +0 0 +0 0 + +0 +24 +0 -40 80 -40 +80 -40 100 0 +100 0 120 -50 +120 -50 -60 -50 +-60 -50 -60 50 +-60 50 40 50 +40 50 40 -10 +40 -10 45 -10 +45 -10 45 10 +45 10 50 10 +50 10 50 -10 +50 -10 55 -10 +55 -10 55 70 +55 70 -80 70 +-80 70 -80 -80 +-80 -80 150 -80 +150 -80 150 20 +150 20 65 20 +65 20 65 -15 +65 -15 35 -15 +35 -15 35 10 +35 10 -20 10 +-20 10 -20 -30 +-20 -30 0 -40 + +0 +7 +35 10 -20 10 +-20 10 -20 -30 +-20 -30 0 -40 +0 -40 80 -40 +80 -40 1400/17 -600/17 +1400/17 -600/17 35 -15 +35 -15 35 10 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_21.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_21.dat new file mode 100644 index 00000000000..f379cb855f7 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_21.dat @@ -0,0 +1,43 @@ +80 0 +80 0 + +0 +23 +100 0 100 20 +100 20 108 23 +108 23 100 50 +100 50 80 60 +80 60 100 70 +100 70 110 70 +110 70 110 -100 +110 -100 80 -100 +80 -100 120 -130 +120 -130 120 100 +120 100 -40 100 +-40 100 -40 -20 +-40 -20 -20 -20 +-20 -20 -20 0 +-20 0 -10 -30 +-10 -30 -60 -30 +-60 -30 -60 0 +-60 0 -70 -10 +-70 -10 -70 0 +-70 0 -80 10 +-80 10 -80 -40 +-80 -40 90 -40 +90 -40 100 0 + +0 +12 +-10 -30 -40 -40 +-40 -40 90 -40 +90 -40 100 0 +100 0 100 20 +100 20 748/7 188/7 +748/7 188/7 100 50 +100 50 80 60 +80 60 80 100 +80 100 -40 100 +-40 100 -40 0 +-40 0 -20 0 +-20 0 -10 -30 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_3.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_3.dat new file mode 100644 index 00000000000..932b304cb08 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_3.dat @@ -0,0 +1,26 @@ +# Test case 3 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +2 2 +2 2 + +0 +8 +0 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 + +0 +7 +0 0 13 0 +13 0 13 2 +13 2 11 2 +11 2 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 + + diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_4.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_4.dat new file mode 100644 index 00000000000..5499e797fc4 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_4.dat @@ -0,0 +1,42 @@ +# Test case 4 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +6 4 +6 4 + +0 +18 +0 0 3 2 +3 2 5 1 +5 1 8 1 +8 1 16 2 +16 2 16 5 +16 5 14 4 +14 4 12 7 +12 7 10 4 +10 4 8 4 +8 4 10 8 +10 8 9 10 +9 10 8 8 +8 8 6 8 +6 8 7 6 +7 6 1 6 +1 6 4 8 +4 8 0 9 +0 9 0 0 + +0 +15 +0 0 3 2 +3 2 5 1 +5 1 8 1 +8 1 16 2 +16 2 16 4 +16 4 14 4 +14 4 10 4 +10 4 8 4 +8 4 10 8 +10 8 9 10 +9 10 8 8 +8 8 7 6 +7 6 1 6 +1 6 0 32/5 +0 32/5 0 0 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_5.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_5.dat new file mode 100644 index 00000000000..114390d664d --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_5.dat @@ -0,0 +1,37 @@ +# Test case 5 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 2 +5 2 + +0 +20 +0 0 12 0 +12 0 12 2 +12 2 9 2 +9 2 9 4 +9 4 16 4 +16 4 16 0 +16 0 20 0 +20 0 20 12 +20 12 0 12 +0 12 0 8 +0 8 15 8 +15 8 15 9 +15 9 1 9 +1 9 1 11 +1 11 19 11 +19 11 19 1 +19 1 17 1 +17 1 17 6 +17 6 0 6 +0 6 0 0 + +0 +7 +0 0 12 0 +12 0 12 2 +12 2 9 2 +9 2 9 4 +9 4 13 6 +13 6 0 6 +0 6 0 0 + diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_6.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_6.dat new file mode 100644 index 00000000000..4ced7944242 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_6.dat @@ -0,0 +1,25 @@ +# Test case 6 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +1 2 +1 2 + +0 +9 +0 0 0 4 +0 4 2 4 +2 4 3 2 +3 2 4 4 +4 4 5 4 +5 4 5 0 +5 0 4 2 +4 2 3 0 +3 0 0 0 + +0 +7 +0 0 0 4 +0 4 2 4 +2 4 3 2 +3 2 4 2 +4 2 5 2 +4 2 3 0 +3 0 0 0 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_7.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_7.dat new file mode 100644 index 00000000000..536d64a2cfd --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_7.dat @@ -0,0 +1,39 @@ +# Test case 6 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +1 2 +1 2 + +0 +18 +0 0 0 4 +0 4 2 4 +2 4 3 2 +3 2 4 4 +4 4 5 2 +5 2 6 2 +6 2 6 4 +6 4 11 4 +11 4 11 0 +11 0 10 2 +10 2 9 0 +9 0 9 2 +9 2 7 2 +7 2 7 0 +7 0 5 0 +5 0 4 2 +4 2 3 0 +3 0 0 0 + +0 +12 +0 0 0 4 +0 4 2 4 +2 4 3 2 +3 2 4 2 +4 2 5 2 +5 2 6 2 +6 2 7 2 +7 2 9 2 +9 2 10 2 +10 2 11 2 +4 2 3 0 +3 0 0 0 diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_8.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_8.dat new file mode 100644 index 00000000000..4f52bbb694d --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_8.dat @@ -0,0 +1,26 @@ +# Test case 8 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +5 2 +7 2 + +0 +8 +0 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 + +0 +7 +0 0 13 0 +13 0 13 2 +13 2 11 2 +11 2 7 2 +7 2 4 2 +4 2 0 2 +0 2 0 0 + + diff --git a/Visibility_2/test/Visibility_2/data/test_simple_polygon_9.dat b/Visibility_2/test/Visibility_2/data/test_simple_polygon_9.dat new file mode 100644 index 00000000000..56b7193c623 --- /dev/null +++ b/Visibility_2/test/Visibility_2/data/test_simple_polygon_9.dat @@ -0,0 +1,24 @@ +# Test case 9 for simple polygons. See https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases +9 4 +11 2 + +0 +8 +0 0 13 0 +13 0 13 4 +13 4 11 2 +11 2 9 4 +9 4 7 2 +7 2 4 2 +4 2 0 5 +0 5 0 0 + +0 +5 +13 0 11 2 +11 2 9 4 +9 4 7 2 +7 2 5 0 +5 0 13 0 + + diff --git a/Visibility_2/test/Visibility_2/include/CGAL/test_model_methods.h b/Visibility_2/test/Visibility_2/include/CGAL/test_model_methods.h new file mode 100644 index 00000000000..2bca8bd5f44 --- /dev/null +++ b/Visibility_2/test/Visibility_2/include/CGAL/test_model_methods.h @@ -0,0 +1,178 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer + +#ifndef CGAL_TEST_MODEL_METHODS_H +#define CGAL_TEST_MODEL_METHODS_H + +#include +#include +#include +#include + +namespace CGAL { + +template +void test_model_methods_for_arr( + typename Visibility_2::Arrangement_2 &arr) { + + typedef typename Visibility_2::Arrangement_2 + Arrangement_2; + typedef typename Visibility_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Point_2 + Point_2; + typedef typename Arrangement_2::Geometry_traits_2::Segment_2 + Segment_2; + + typedef typename Visibility_arrangement_2::Face_handle VFH; + + + Visibility_2 visibility; + assert(false == visibility.is_attached()); + visibility.attach(arr); + assert(true == visibility.is_attached()); + assert(true == (CGAL::test_are_equal(arr,visibility.arr()))); + + Visibility_arrangement_2 arr_out; + Visibility_arrangement_2 arr_out_check; + + typename Arrangement_2::Face_const_iterator fit; + + for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) { + if (!fit->is_unbounded()) { + break; + } + } + // First consider query point in the unbounded face + const Point_2 query_pt(1, 1); + // Check returned face_handle + VFH face_check = visibility.compute_visibility(query_pt, fit, arr_out); + VFH face; + if (arr_out.faces_begin()->is_unbounded()) { + face = ++arr_out.faces_begin(); + } + else { + face = arr_out.faces_begin(); + } + assert(face_check == face); + + assert((true == test_are_equal + (arr, arr_out))); + visibility.detach(); + assert(false == visibility.is_attached()); + visibility.attach(arr); + + visibility.compute_visibility(query_pt, fit, arr_out_check); + assert((true == test_are_equal + (arr_out_check, arr))); + assert((true == test_are_equal + (arr_out, arr_out_check))); + arr_out.clear(); + visibility.compute_visibility(query_pt, fit, arr_out); + assert((true == test_are_equal + (arr_out, arr_out_check))); + + // Now consider the query point on a halfedge + const Point_2 query_pt2 = Point_2(0, 4); + arr_out.clear(); + typename Arrangement_2::Halfedge_const_iterator hit; + VFH face_check_he; + for (hit = arr.halfedges_begin(); + hit != arr.halfedges_end(); ++hit) { + + if (hit->source()->point() == Point_2(0, 8) && hit->target()->point() == Point_2(0, 0)) { + face_check_he = visibility.compute_visibility(query_pt2, hit, arr_out); + break; + } + } + if (arr_out.faces_begin()->is_unbounded()) { + face = ++arr_out.faces_begin(); + } + else { + face = arr_out.faces_begin(); + } + assert(face_check_he == face); + assert((true == test_are_equal(arr_out, arr))); + arr_out_check.clear(); + visibility.compute_visibility(query_pt2, hit, arr_out_check); + assert((true == test_are_equal + (arr_out, arr_out_check))); + + // Now consider the query point as the target of a halfedge + typename Arrangement_2::Halfedge_const_iterator hit_snd; + for (hit_snd = arr.halfedges_begin(); hit_snd != arr.halfedges_end(); ++hit_snd) { + if(!hit_snd->face()->is_unbounded()){ + arr_out.clear(); + VFH face_check_he_snd = visibility.compute_visibility(hit_snd->target()->point(), hit_snd, arr_out); + assert(!face_check_he_snd->is_unbounded()); + if (arr_out.faces_begin()->is_unbounded()) { + face = ++arr_out.faces_begin(); + } + else { + face = arr_out.faces_begin(); + } + assert(face_check_he_snd == face); + if (! test_are_equal(arr_out, arr)) { + assert(false); + } + } + } +} + +template +void test_model_methods() { + + // Check concept obediance + typedef typename Visibility_2::Arrangement_2 + Arrangement_2; + typedef typename Arrangement_2::Point_2 Point_2; + typedef typename Arrangement_2::Face_handle Face_handle; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Visibility_2::Regularization_tag Regularization_tag; + typedef typename Visibility_2::Supports_general_polygon_tag + Supports_general_polygon_tag; + typedef typename Visibility_2::Supports_simple_polygon_tag + Supports_simple_polygon_tag; + typedef typename Arrangement_2::Geometry_traits_2::Segment_2 + Segment_2; + + Point_2 p1(0, 0), p2(8, 0), p3(8, 8), p4(0, 8); + std::vector seg_sq; + seg_sq.push_back(Segment_2(p1, p2)); + seg_sq.push_back(Segment_2(p2, p3)); + seg_sq.push_back(Segment_2(p3, p4)); + seg_sq.push_back(Segment_2(p4, p1)); + Arrangement_2 arr_square; + CGAL::insert(arr_square, seg_sq.begin(), seg_sq.end()); + + test_model_methods_for_arr(arr_square); + + std::vector seg_tri; + seg_tri.push_back(Segment_2(p1, p2)); + seg_tri.push_back(Segment_2(p2, p4)); + seg_tri.push_back(Segment_2(p4, p1)); + Arrangement_2 arr_triangle; + CGAL::insert(arr_triangle, seg_tri.begin(), seg_tri.end()); + + test_model_methods_for_arr(arr_triangle); +} + +} // end CGAL namespace +#endif diff --git a/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h b/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h new file mode 100644 index 00000000000..ab7ea367ad5 --- /dev/null +++ b/Visibility_2/test/Visibility_2/include/CGAL/test_utils.h @@ -0,0 +1,1380 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Kan Huang +// Francisc Bungiu +// Michael Hemmer + +#ifndef CGAL_TEST_UTILS_H +#define CGAL_TEST_UTILS_H + +//#define RESET "\033[0m" +//#define RED "\033[31m" +//#define GREEN "\033[32m" + +#define RESET "" +#define RED "" +#define GREEN "" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +enum Query_choice {VERTEX, EDGE, FACE}; + +template +typename Arrangement_2::Halfedge_handle get_initial_halfedge(const Arrangement_2 &arr) { + + typedef typename Arrangement_2::Vertex Vertex; + typedef typename Arrangement_2::Vertex_handle Vertex_handle; + typedef typename Arrangement_2::Vertex_const_iterator Vertex_const_iterator; + typedef typename Arrangement_2::Halfedge Halfedge; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + + // find the min vertex + Vertex v = *arr.vertices_begin(); + for(Vertex_const_iterator vit = arr.vertices_begin(); vit != arr.vertices_end(); vit++){ + if(arr.traits()->compare_xy_2_object()((*vit).point(),v.point()) == CGAL::SMALLER){ + v = *vit; + } + } + + // take the edge with the smallest source + Halfedge_handle he_final = v.incident_halfedges(); + Halfedge_handle he1 = v.incident_halfedges(); + he1=he1->next()->twin(); + + while(he1 != v.incident_halfedges()){ + if(arr.traits()->compare_xy_2_object()( + he1->source()->point(), + he_final->source()->point()) == CGAL::SMALLER){ + he_final = he1; + } + he1=he1->next()->twin(); + } + + // as this may be on a needle, continue until faces on both sides differ + while(he_final->face() == he_final->twin()->face()) + he_final = he_final->next(); + + return he_final; + +} + +/* + * Function to compare two arrangements; first determines lowest vertex + * from each arrangements, then it walks the edges and compares them + */ +template +bool test_are_equal(const ARR1 &arr1, const ARR2 &arr2) { + + typedef typename ARR1::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + + typedef typename ARR1::Halfedge_handle HE1; + typedef typename ARR2::Halfedge_handle HE2; + + + // First make sure they have the same size + if (arr1.number_of_vertices() != arr2.number_of_vertices()) { + return false; + } + if (arr1.number_of_edges() != arr2.number_of_edges()) { + return false; + } + if (arr1.number_of_isolated_vertices() != arr2.number_of_isolated_vertices()) { + return false; + } + if (arr1.number_of_faces() != arr2.number_of_faces()) { + return false; + } + + // currently checking for closed for visibility region + assert(arr1.number_of_faces() == 2); + assert(arr2.number_of_faces() == 2); + + // get unique halfedge + HE1 he_start_1 = get_initial_halfedge(arr1); + HE2 he_start_2 = get_initial_halfedge(arr2); + + // run on first loop and compare sources + assert(arr1.traits()->compare_xy_2_object()( + he_start_1->source()->point(), + he_start_2->source()->point()) == CGAL::EQUAL); + + HE1 he_run_1 = he_start_1->next(); + HE2 he_run_2 = he_start_2->next(); + + while(he_run_1 != he_start_1){ + + assert(arr1.traits()->compare_xy_2_object()( + he_run_1->source()->point(), + he_run_2->source()->point()) == CGAL::EQUAL); + + he_run_1 = he_run_1->next(); + he_run_2 = he_run_2->next(); + } + assert(he_run_2 == he_start_2); + + // run on second loop and compare sources. + he_start_1 = he_start_1->twin(); + he_start_2 = he_start_2->twin(); + he_run_1 = he_start_1->next(); + he_run_2 = he_start_2->next(); + while(he_run_1 != he_start_1){ + + assert(arr1.traits()->compare_xy_2_object()( + he_run_1->source()->point(), + he_run_2->source()->point()) == CGAL::EQUAL); + + he_run_1 = he_run_1->next(); + he_run_2 = he_run_2->next(); + } + assert(he_run_2 == he_start_2); + return true; +} + +template +Number_type string2num(const std::string& s) { + int i; + if (s.find("/") != std::string::npos) { + i = s.find("/"); + std::string p = s.substr(0, i); + std::string q = s.substr(i+1); + std::stringstream convert(p); + int n, d; + convert >> n; + std::stringstream convert2(q); + convert2 >> d; + return Number_type(n)/Number_type(d); + + } + else { + std::stringstream convert(s); + double n; + convert >> n; + return Number_type(n); + } +} + +template +std::string num2string(Number_type& n) { + std::stringstream ss; + ss< +CGAL::Object get_location( + const Arrangement_2 &arr, + const typename Arrangement_2::Geometry_traits_2::Point_2 &q) { + + typedef CGAL::Arr_naive_point_location Naive_pl; + Naive_pl naive_pl(arr); + + // Perform the point-location query. + CGAL::Object obj = naive_pl.locate(q); + return obj; +} + +template +bool is_inside_face( + const Arrangement_2 &arr, + const typename Arrangement_2::Face_const_handle face, + const typename Arrangement_2::Geometry_traits_2::Point_2 &q) { + + CGAL::Object obj = get_location(arr, q); + typename Arrangement_2::Face_const_handle f; + if (CGAL::assign (f, obj)) { + // q is located inside a face: + if (!f->is_unbounded()) { + if (f == face) { + return true; + } + } + } + return false; +} + +template +bool create_arrangement_from_dat_file(std::ifstream &input, + _Arrangement_2 &arr) { + arr.clear(); + + typedef _Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_handle Face_handle; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + + if (input) { + std::string curr_line; + std::vector isolated_vertices; + std::getline(input, curr_line); + std::stringstream convert(curr_line); + int number_of_isolated_vertices; + convert >> number_of_isolated_vertices; + Face_handle uface = arr.unbounded_face(); + for (int i = 0 ; i < number_of_isolated_vertices ; i++) { + std::getline(input, curr_line); + std::istringstream iss(curr_line); + std::string x, y; + iss >> x >> y; + arr.insert_in_face_interior(Point_2(string2num(x), + string2num(y)), + uface); + } + std::vector edges; + int number_of_edges; + std::getline(input, curr_line); + std::stringstream convert2(curr_line); + convert2 >> number_of_edges; + for (int i = 0 ; i < number_of_edges ; i++) { + std::getline(input, curr_line); + std::string x1, y1, x2, y2; + std::istringstream iss(curr_line); + iss >> x1 >> y1 >> x2 >> y2; + edges.push_back(Segment_2(Point_2(string2num(x1), + string2num(y1)), + Point_2(string2num(x2), + string2num(y2)))); + } + CGAL::insert(arr, edges.begin(), edges.end()); + return true; + } + else { + return false; + } +} + +template +void regularize(Arrangement_2& arr){ + //std::cout << "\n regularize" << std::endl; + // remove all edges with the same face on both sides + typedef typename Arrangement_2::Edge_iterator EIT; + for(EIT eit = arr.edges_begin(); eit != arr.edges_end();){ + if(eit->face() == eit->twin()->face()){ + // arr.remove_edge(eit++,false,false); did not compile + EIT eh = eit; + ++eit; + arr.remove_edge(eh,false,false); + }else{ + ++eit; + } + } + // remove all isolated vertices (also those left from prvious step) + typedef typename Arrangement_2::Vertex_iterator VIT; + for(VIT vit = arr.vertices_begin(); vit != arr.vertices_end();){ + if(vit->degree()== 0){ + VIT vh = vit; + vit++; + arr.remove_isolated_vertex(vh); + }else{ + vit++; + } + } + //std::cout << "regularize done" << std::endl; +} + +template +bool is_regular_arr(Arrangement_2& arr){ + //std::cout << "\n regularize" << std::endl; + // remove all edges with the same face on both sides + typedef typename Arrangement_2::Edge_iterator EIT; + for(EIT eit = arr.edges_begin(); eit != arr.edges_end();){ + if(eit->face() == eit->twin()->face()){ + // arr.remove_edge(eit++,false,false); did not compile + EIT eh = eit; + ++eit; + return false; + }else{ + ++eit; + } + } + // remove all isolated vertices (also those left from prvious step) + typedef typename Arrangement_2::Vertex_iterator VIT; + for(VIT vit = arr.vertices_begin(); vit != arr.vertices_end();){ + if(vit->degree()== 0){ + VIT vh = vit; + vit++; + return false; + }else{ + vit++; + } + } + return true; + //std::cout << "regularize done" << std::endl; +} + + +template +bool run_test_case_from_file(Visibility_2 visibility, std::ifstream &input) { + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef typename Arrangement_2::Halfedge_around_vertex_const_circulator + Halfedge_around_vertex_const_circulator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; + + Arrangement_2 arr_in; + Visibility_arrangement_2 arr_correct_out; + Visibility_arrangement_2 arr_out; + + std::string curr_line; + while (std::getline(input, curr_line)) { + if (curr_line[0] != '#' && curr_line[0] != '/') + break; + } + std::stringstream convert(curr_line); + std::string x, y; + convert >> x >> y; + Point_2 query_pt(string2num(x), + string2num(y)); + std::getline(input, curr_line); + std::string x1, y1; + std::istringstream iss(curr_line); + iss >> x1 >> y1; + Point_2 reference_pt(string2num(x1), + string2num(y1)); + + std::getline(input, curr_line); + if (!create_arrangement_from_dat_file(input, arr_in)) { + return false; + } + visibility.attach(arr_in); + std::getline(input, curr_line); + if (!create_arrangement_from_dat_file + (input, arr_correct_out)) { + return false; + } + + if(Visibility_2::Regularization_tag::value){ + regularize(arr_correct_out); + } + + + CGAL::Object obj = CGAL::get_location(arr_in, query_pt); + Face_const_handle f; + Halfedge_const_handle e; + Vertex_const_handle v; + + if (CGAL::assign (f, obj)) { + if (!f->is_unbounded()) { + visibility.compute_visibility(query_pt, f, arr_out); + } + } + else if (CGAL::assign(e, obj)) { + if (e->source()->point() == reference_pt) { + visibility.compute_visibility(query_pt, e, arr_out); + } + else { + visibility.compute_visibility(query_pt, e->twin(), arr_out); + } + } + else if (CGAL::assign(v, obj)) { + // Check which halfedge we want in the query + Halfedge_around_vertex_const_circulator he_circ = v->incident_halfedges(); + Halfedge_around_vertex_const_circulator he_curr = he_circ; + do { + if (he_curr->source()->point() == reference_pt) { + visibility.compute_visibility(query_pt, he_curr, arr_out); + } + } while (++he_curr != he_circ); + } + + + if (!test_are_equal(arr_out, arr_correct_out)) { + std::cout<<"the result is:\n"; + CGAL::Visibility_2::print_arrangement(arr_out); + std::cout<<"however, the expected answer is:\n"; + CGAL::Visibility_2::print_arrangement(arr_correct_out); + return false; + } + visibility.detach(); + return true; +} + +template +void run_tests(int case_number_simple, int case_number_non_simple) { + + Visibility_2 visibility; + bool one_failed = false; + if (Visibility_2::Supports_simple_polygon_tag::value + && case_number_simple >= 1) { + int cnt = 0; + int cnt_passed = 0; + std::cout << " Running simple polygon test cases...\n"; + for (int i = 1 ; i <= case_number_simple ; i++) { + std::string input_arr_file("data/test_simple_polygon_"); + input_arr_file += num2string(i); + input_arr_file += ".dat"; + std::cout << " Running test " + << GREEN << input_arr_file << RESET + << " - "; + std::ifstream input(input_arr_file.c_str()); + if (run_test_case_from_file(visibility, input)) { + cnt_passed++; + std::cout << GREEN << "Done!" << RESET << std::endl; + } + else { + one_failed = true; + std::cout << RED << "Failed!" << RESET << std::endl; + } + cnt++; + } + std::cout << " Visibility_2 object passed " << cnt_passed + << "/" << cnt << " tests" + << " ("; + double result = (double)cnt_passed/cnt*100; + if (result > 99.9) { + std::cout << GREEN << result << "%" << RESET; + } + else { + std::cout << RED << result << "%" << RESET; + } + std::cout << ")" << std::endl; + } + if (Visibility_2::Supports_general_polygon_tag::value + && case_number_non_simple >= 1) { + + int cnt = 0; + int cnt_passed = 0; + std::cout << " Running non-simple polygon test cases...\n"; + for (int i = 1 ; i <= case_number_non_simple ; i++) { + std::string input_arr_file("data/test_non_simple_polygon_"); + input_arr_file += num2string(i); + input_arr_file += ".dat"; + std::cout << " Running test " + << GREEN << input_arr_file << RESET + << " - "; + std::ifstream input(input_arr_file.c_str()); + if (run_test_case_from_file(visibility, input)) { + cnt_passed++; + std::cout << GREEN << "Done!" << RESET << std::endl; + } + else { + one_failed = true; + std::cout << RED << "Failed!" << RESET << std::endl; + } + cnt++; + } + std::cout << " Visibility_2 object passed " << cnt_passed + << "/" << cnt << " tests" + << " ("; + double result = (double)cnt_passed/cnt*100; + if (result > 99.9) { + std::cout << GREEN << result << "%" << RESET; + } + else { + std::cout << RED << result << "%" << RESET; + } + std::cout << ")" << std::endl; + } + if (one_failed) { + assert(false); + } +} + +template +void create_arrangement_from_file(_Arrangement_2 &arr, std::ifstream& input) { + typedef _Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + if (input) { + std::string line; + while (std::getline(input, line)) { + if (line[0] != '#' && line[0] != '/') + break; + } + std::vector points; + std::vector segments; + std::stringstream convert(line); + int number_of_points; + convert >> number_of_points; + + for (int i = 0; i != number_of_points; i++) { + std::getline(input, line); + std::string n1, n2; + std::istringstream iss(line); + iss>> n1 >> n2; + points.push_back(Point_2(string2num(n1), + string2num(n2))); + } + int number_of_edges; + input >> number_of_edges; + for (int i = 0; i != number_of_edges; i++) { + unsigned i1,i2; + input >> i1 >> i2; + segments.push_back(Segment_2(points[i1], points[i2])); + } + CGAL::insert(arr, segments.begin(), segments.end()); + } + else { + std::cout<<"Can't open the file. Check the file name."; + } +} + + +template +void create_arrangement_from_env_file(_Arrangement_2 &arr, std::ifstream& input) { + typedef _Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + if (input) { + std::string line; + while (std::getline(input, line)) { + if (line[0] != '#' && line[0] != '/') + break; + } + std::stringstream convert(line); + int number_of_polygons; + convert >> number_of_polygons; + for (int i = 0 ; i < number_of_polygons ; i++) { + std::vector points; + std::vector segments; + + std::getline(input, line); + std::stringstream convert(line); + int number_of_vertices; + convert >> number_of_vertices; + for (int j = 0; j < number_of_vertices; j++) { + std::getline(input, line); + std::string n1, n2; + std::istringstream iss(line); + iss >> n1 >> n2; + points.push_back(Point_2(string2num(n1), + string2num(n2))); + } + for (int j = 0; j < number_of_vertices-1 ; j++) { + segments.push_back(Segment_2(points[j], points[j+1])); + } + segments.push_back(Segment_2(points.front(), points.back())); + // std::cout << "before insertion\n"; + CGAL::insert(arr, segments.begin(), segments.end()); + // std::cout << "after\n"; + } + } + else { + std::cout<<"Can't open the file. Check the file name."; + } +} + +template +bool compare_arr_by_edges(const Arrangement_2& arr1, const Arrangement_2& arr2){ + std::set s1; + typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator; + for (Edge_const_iterator eit = arr1.edges_begin(); + eit != arr1.edges_end(); ++eit) { + s1.insert(edge2string(eit->target()->point(), eit->source()->point())); + } + std::set s2; + for (Edge_const_iterator eit = arr2.edges_begin(); + eit != arr2.edges_end(); ++eit) { + s2.insert(edge2string(eit->target()->point(), eit->source()->point())); + } + return s1==s2; +} + +template +bool is_ahead(Point_2& p1, Point_2& p2) { + if (p1.x() > p2.x()) { + return true; + } + if (p1.x() == p2.x() && p1.y() > p2.y()) { + return true; + } + return false; +} + + +template +std::string edge2string(const Point_2& p1, const Point_2& p2) { + Point_2 q1, q2; + if (is_ahead(p1, p2)) { + q1 = p1; + q2 = p2; + } + else { + q1 = p2; + q2 = p1; + } + return num2string(q1.x()) + num2string(q1.y()) + + num2string(q2.x()) + num2string(q2.y()); +} + +template +Point_2 random_linear_interpolation(const Point_2 &p, const Point_2 &q) { + +// srand(time(NULL)); + Number_type min_x, max_x; + Number_type y0, y1, x0, x1; + + if (p.x() < q.x()) { + min_x = p.x(); + max_x = q.x(); + x0 = p.x(); + x1 = q.x(); + y0 = p.y(); + y1 = q.y(); + } + else { + min_x = q.x(); + max_x = p.x(); + x0 = q.x(); + x1 = p.x(); + y0 = q.y(); + y1 = p.y(); + } + + Number_type x_normalized = rand()/static_cast(RAND_MAX); + Number_type x = min_x + static_cast(x_normalized*(max_x - min_x)); + if (x == max_x && x == min_x) { + Number_type min_y, max_y; + if (p.y() < q.y()) { + min_y = p.y(); + max_y = q.y(); + } + else { + min_y = q.y(); + max_y = p.y(); + } + Number_type y_normalized = rand()/static_cast(RAND_MAX); + Number_type y = min_y + static_cast(y_normalized*(max_y - min_y)); + return Point_2(x, y); + } + else { + Number_type y = y0 + (y1 - y0)*(x - x0)/(x1 - x0); + return Point_2(x, y); + } +} + +//make sure q is in fh or on the bound. +template +bool is_star_shape( + const typename Arrangement_2::Point_2& q, + const Arrangement_2& arr) { + + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Edge_iterator Edge_iterator; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + + // this test is written for an arr that contains on star shaped polygon + if (arr.number_of_faces()!=2){ + return false; + } + + // get the bounded face + Face_const_handle fh; + if(arr.faces_begin()->is_unbounded()){ + fh = arr.faces_begin(); + }else{ + fh = ++(arr.faces_begin()); + } + assert(fh->is_unbounded()); + + if (fh->has_outer_ccb()) { + typename Arrangement_2::Ccb_halfedge_const_circulator curr, circ; + curr = circ = fh->outer_ccb(); + do { + if (CGAL::right_turn(q, curr->source()->point(), curr->target()->point())) { + return false; + } +// Point_2 p = curr->target()->point(); +// typename Arrangement_2::Ccb_halfedge_const_circulator curr1, circ1; +// curr1 = circ1 = fh->outer_ccb(); +// do { +// Segment_2 intersect_s; +// Point_2 intersect_p; +// Point_2 source = curr1->source()->point(); +// Point_2 target = curr1->target()->point(); +// int i = intersect_seg(Segment_2(p, q), Segment_2(source, target), intersect_s, intersect_p); +// if (i == 1 && intersect_p != source && intersect_p != target && intersect_p != q) +// return false; +// } while (++curr1 != circ1); + } while (++curr != circ); + } + return true; +} + +template +int count_edges_in_face(typename Arrangement_2::Face_const_handle &fch) { + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + + Ccb_halfedge_const_circulator circ = fch->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + + int edge_cnt(0); + do { + edge_cnt++; + } while (++curr != circ); + return edge_cnt; +} + +template +typename Arrangement_2::Face_const_handle construct_biggest_arr_with_no_holes( + Arrangement_2 &arr_in, + Arrangement_2 &arr_out) { + + typedef typename Arrangement_2::Face_const_iterator Face_const_iterator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + + int curr_max(0); + Ccb_halfedge_const_circulator curr_max_circ; + Ccb_halfedge_const_circulator circ; + Ccb_halfedge_const_circulator curr; + Face_const_iterator fit; + + int cnt(0); + for (fit = arr_in.faces_begin() ; fit != arr_in.faces_end() ; fit++) { + if (fit->has_outer_ccb()) { + Ccb_halfedge_const_circulator circ = fit->outer_ccb(); + int edge_cnt = count_edges_in_face(fit); + if (edge_cnt > curr_max) { + curr_max = edge_cnt; + curr_max_circ = circ; + } + } + cnt++; + } + + std::vector segments; + curr = curr_max_circ; + Halfedge_const_handle he; + do { + he = curr; + segments.push_back(Segment_2(he->source()->point(), he->target()->point())); + } while (++curr != curr_max_circ); + + arr_out.clear(); +// std::cout << "before insertion\n"; + CGAL::insert_non_intersecting_curves(arr_out, segments.begin(), segments.end()); +// std::cout << "after\n"; + + Face_const_handle fch; + curr_max = 0; + for (fit = arr_out.faces_begin() ; fit != arr_out.faces_end() ; fit++) { + if (fit->has_outer_ccb()) { + int edge_cnt = count_edges_in_face(fit); + if (edge_cnt > curr_max) { + curr_max = edge_cnt; + fch = fit; + } + } + } + Ccb_halfedge_const_circulator circ_p = fch->outer_ccb(); + Ccb_halfedge_const_circulator curr_p = circ_p; + Halfedge_const_handle he_p;/* + std::cout << "OUT FACE\n"; + do { + he_p = curr_p; + Ccb_halfedge_const_circulator next = curr_p; + next++; + Halfedge_const_handle h_next = next; + assert(he_p->target() == h_next->source()); + std::cout << he_p->source()->point() << std::endl; + } while(++curr_p != circ_p); + std::cout << "END\n";*/ + return fch; +} + +template +void simple_benchmark_one_unit( + typename Visibility_2_fst::Arrangement_2 &arr, + const Query_choice &choice, + typename Visibility_2_fst::Arrangement_2::Face_const_handle &fit, + Visibility_2_fst visibility_fst, + Visibility_2_snd visibility_snd, + double& qtime1, + double& qtime2, + int& query_cnt) { + + typedef typename Visibility_2_fst::Arrangement_2 Arrangement_2; + typedef typename Visibility_2_fst::Arrangement_2 Visibility_arrangement_2; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + + typedef typename Visibility_arrangement_2::Face_handle Face_handle; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef Timer Benchmark_timer; + + Benchmark_timer timer; + + Ccb_halfedge_const_circulator circ = fit->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + + do { + Halfedge_const_handle he = curr; + Point_2 curr_query_pt; + bool selected_query_pt = true; + switch (choice) { + case VERTEX: + curr_query_pt = he->target()->point(); + break; + case EDGE: + curr_query_pt = random_linear_interpolation + (he->source()->point(), he->target()->point()); + break; + case FACE: + Ccb_halfedge_const_circulator curr_next = curr; + curr_next++; + Halfedge_const_handle he_next = curr_next; + Point_2 p1 = he->source()->point(); + Point_2 p2 = he->target()->point(); + Point_2 p3 = he_next->target()->point(); + Point_2 avg((p1.x() + p2.x() + p3.x())/3, (p1.y() + p2.y() + p3.y())/3); + if (is_inside_face(arr, fit, avg)) { + curr_query_pt = avg; + } + else { + selected_query_pt = false; + } + break; + } + if (!selected_query_pt) { + curr++; + if (curr == circ) { + break; + } + continue; + } + + Visibility_arrangement_2 out_arr_fst, out_arr_snd; + timer.reset(); + timer.start(); + Face_handle f_fst; + if (choice == CGAL::FACE) { + f_fst = visibility_fst.compute_visibility(curr_query_pt, fit, out_arr_fst); + query_cnt++; + } + else { + f_fst = visibility_fst.compute_visibility(curr_query_pt, he, out_arr_fst); + query_cnt++; + } + timer.stop(); + qtime1 += timer.time(); + + timer.reset(); + if ( !is_star_shape(curr_query_pt, out_arr_fst) ) { + std::cout << RED << " Warning: the first output is not star-shape." << RESET << std::endl; + } + timer.start(); + Face_handle f_snd; + if (choice == CGAL::FACE) { + f_snd = visibility_snd.compute_visibility(curr_query_pt, fit, out_arr_snd); + } + else { + f_snd = visibility_snd.compute_visibility(curr_query_pt, he, out_arr_snd); + } + timer.stop(); + if ( !is_star_shape(curr_query_pt, out_arr_snd) ) { + std::cout << RED << " Warning: the second output is not star-shape." << RESET << std::endl; + } + qtime2 += timer.time(); + + if (! CGAL::test_are_equal (out_arr_fst, out_arr_snd)) { + if (choice == CGAL::FACE) { + std::cout << "query in Face:\n"; + CGAL::Visibility_2::print_simple_face(fit); + } + std::cout << "the query point is " << curr_query_pt << std::endl; + std::cout << RED << "two outputs are different:\n" + << "first output is:\n" << RESET; + CGAL::Visibility_2::print_arrangement(out_arr_fst); + std::cout << RED << "second output is:\n"<< RESET; + CGAL::Visibility_2::print_arrangement(out_arr_snd); + assert(false); + } + } while (++curr != circ); +} + +template +void simple_benchmark(Visibility_2_fst &visibility_fst, + Visibility_2_snd &visibility_snd, + const Query_choice &choice, + std::ifstream &input) { + + typedef typename Visibility_2_fst::Arrangement_2 + Arrangement_2; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_const_iterator Face_const_iterator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Hole_const_iterator Hole_const_iterator; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + + assert(Visibility_2_fst::Regularization_tag::value + == Visibility_2_snd::Regularization_tag::value); + + Arrangement_2 arr; + create_arrangement_from_env_file(arr, input); + + int query_cnt(0); + double qtime1(0), qtime2(0), ptime1(0), ptime2(0); + if (Visibility_2_fst::Supports_general_polygon_tag::value + && Visibility_2_snd::Supports_general_polygon_tag::value) { + + Face_const_iterator fit; + Timer timer; + + timer.start(); + visibility_fst.attach(arr); + timer.stop(); + ptime1 = timer.time(); + + timer.reset(); + timer.start(); + visibility_snd.attach(arr); + timer.stop(); + ptime2 = timer.time(); + + for (fit = arr.faces_begin() ; fit != arr.faces_end() ; fit++) { + if (!fit->is_unbounded()) { + + simple_benchmark_one_unit(arr, + choice, + fit, + visibility_fst, + visibility_snd, + qtime1, + qtime2, + query_cnt); + } + } + } + else { + Arrangement_2 arr_trimmed; + Face_const_handle fch = construct_biggest_arr_with_no_holes + (arr, arr_trimmed); + Timer timer; + + timer.start(); + visibility_fst.attach(arr_trimmed); + timer.stop(); + ptime1 = timer.time(); + + timer.reset(); + timer.start(); + visibility_snd.attach(arr_trimmed); + timer.stop(); + ptime2 = timer.time(); + simple_benchmark_one_unit(arr_trimmed, + choice, + fch, + visibility_fst, + visibility_snd, + qtime1, + qtime2, + query_cnt); + } + std::cout << "Preprocessing: " << std::endl + << "Model 1 uses " << ptime1 << " sec" << std::endl + << "Model 2 uses " << ptime2 << " sec" << std::endl; + std::cout << query_cnt << " queries are done.\n" + << "Model 1 uses " << qtime1 << " sec" << std::endl + << "Model 2 uses " << qtime2 << " sec" << std::endl; + std::cout << "total times are:" << std::endl + << "Model 1 uses " << ptime1 + qtime1 << " sec" << std::endl + << "Model 2 uses " << ptime2 + qtime2 << " sec" << std::endl; +} + +template +void pure_benchmark_one_unit( + typename Visibility_2::Arrangement_2 &arr, + const Query_choice &choice, + typename Visibility_2::Arrangement_2::Face_const_handle &fit, + Visibility_2 visibility, + double& qtime, + int& query_cnt) { + + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Visibility_2::Arrangement_2 Visibility_arrangement_2; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + + typedef typename Visibility_arrangement_2::Face_handle Face_handle; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef Timer Benchmark_timer; + + Benchmark_timer timer; + + Ccb_halfedge_const_circulator circ = fit->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + + do { + Halfedge_const_handle he = curr; + Point_2 curr_query_pt; + bool selected_query_pt = true; + switch (choice) { + case VERTEX: + curr_query_pt = he->target()->point(); + break; + case EDGE: + curr_query_pt = random_linear_interpolation + (he->source()->point(), he->target()->point()); + break; + case FACE: + Ccb_halfedge_const_circulator curr_next = curr; + curr_next++; + Halfedge_const_handle he_next = curr_next; + Point_2 p1 = he->source()->point(); + Point_2 p2 = he->target()->point(); + Point_2 p3 = he_next->target()->point(); + Point_2 avg((p1.x() + p2.x() + p3.x())/3, (p1.y() + p2.y() + p3.y())/3); + if (is_inside_face(arr, fit, avg)) { + curr_query_pt = avg; + } + else { + selected_query_pt = false; + } + break; + } + if (!selected_query_pt) { + curr++; + if (curr == circ) { + break; + } + continue; + } + + Visibility_arrangement_2 out_arr; + timer.reset(); + timer.start(); + Face_handle fh; + if (choice == CGAL::FACE) { + fh = visibility.compute_visibility(curr_query_pt, fit, out_arr); + query_cnt++; + } + else { + fh = visibility.compute_visibility(curr_query_pt, he, out_arr); + query_cnt++; + } + timer.stop(); + qtime += timer.time(); + + timer.reset(); + } while (++curr != circ); +} + +template +void pure_benchmark( Visibility_2 &visibility, + const Query_choice &choice, + std::ifstream &input) { + + typedef typename Visibility_2::Arrangement_2 + Arrangement_2; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_const_iterator Face_const_iterator; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Hole_const_iterator Hole_const_iterator; + typedef typename Arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + + Arrangement_2 arr; + create_arrangement_from_env_file(arr, input); + + int query_cnt(0); + double qtime(0), ptime(0); + if (Visibility_2::Supports_general_polygon_tag::value) { + + Face_const_iterator fit; + Timer timer; + + timer.start(); + visibility.attach(arr); + timer.stop(); + ptime = timer.time(); + + for (fit = arr.faces_begin() ; fit != arr.faces_end() ; fit++) { + if (!fit->is_unbounded()) { + + pure_benchmark_one_unit( arr, + choice, + fit, + visibility, + qtime, + query_cnt); + } + } + } + else { + Arrangement_2 arr_trimmed; + Face_const_handle fch = construct_biggest_arr_with_no_holes + (arr, arr_trimmed); + Timer timer; + + timer.start(); + visibility.attach(arr_trimmed); + timer.stop(); + ptime = timer.time(); + + pure_benchmark_one_unit( arr_trimmed, + choice, + fch, + visibility, + qtime, + query_cnt); + } + + // std::cout << "NAME TAG PreProTime NQueries TimeQueries TotalTime QAVE TAVE" << std::endl; + std::cout << " " << visibility.name() + << " " << Visibility_2::Regularization_tag::value + << " " << ptime + << " " << query_cnt + << " " << qtime + << " " << ptime+qtime + << " " << qtime/query_cnt + << " " << (ptime+qtime)/query_cnt + << " " << std::endl; +// std::cout << "Preprocessing: " << std::endl +// << "cost " << ptime << " sec" << std::endl; +// std::cout << query_cnt << " queries are done.\n" +// << "cost " << qtime << " sec" << std::endl; +// std::cout << "total time is:" << ptime + qtime << " sec" << std::endl; +} + +template +int intersect_seg(const Segment_2& seg1, const Segment_2& seg2, Segment_2& seg_out, Point_2& p_out) +{ + CGAL::Object result = CGAL::intersection(seg1, seg2); + if (const Point_2 *ipoint = CGAL::object_cast(&result)) { + p_out = *ipoint; + return 1; + } else + if (const Segment_2 *iseg = CGAL::object_cast(&result)) { + seg_out = *iseg; + return 2; + } else { + return 0; + } +} + + +template +void test_star_shape_one_face( typename Visibility_2::Arrangement_2 &arr, + const Query_choice &choice, + typename Visibility_2::Arrangement_2::Face_const_handle &fit, + Visibility_2 visibility) +{ + + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Visibility_2::Arrangement_2 Visibility_arrangement_2; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + + + typedef typename Arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + + typedef typename Visibility_arrangement_2::Face_handle Face_handle; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::FT Number_type; + typedef Timer Benchmark_timer; + + visibility.attach(arr); + + Ccb_halfedge_const_circulator circ = fit->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + do { + Halfedge_const_handle he = curr; + Point_2 curr_query_pt; + bool selected_query_pt = true; + switch (choice) { + case VERTEX: + curr_query_pt = he->target()->point(); + break; + case EDGE: + curr_query_pt = random_linear_interpolation + (he->source()->point(), he->target()->point()); + break; + case FACE: + Ccb_halfedge_const_circulator curr_next = curr; + curr_next++; + Halfedge_const_handle he_next = curr_next; + Point_2 p1 = he->source()->point(); + Point_2 p2 = he->target()->point(); + Point_2 p3 = he_next->target()->point(); + Point_2 avg((p1.x() + p2.x() + p3.x())/3, (p1.y() + p2.y() + p3.y())/3); + if (is_inside_face(arr, fit, avg)) { + curr_query_pt = avg; + } + else { + selected_query_pt = false; + } + break; + } + if (!selected_query_pt) { + curr++; + continue; + } + std::cout << " Running with qpoint: " + << RED << curr_query_pt << RESET << std::endl; + Visibility_arrangement_2 out_arr; + Face_handle fh; + if (choice == FACE) { + fh = visibility.compute_visibility(curr_query_pt, fit, out_arr); + } + else { + fh = visibility.compute_visibility(curr_query_pt, he, out_arr); + } + assert(out_arr.number_of_faces()==2); + assert(fh->is_unbounded()); + if ( !is_star_shape(curr_query_pt, out_arr)) { + std::cout << RED << " The face is not a star shape to qpoint." << RESET << std::endl; + } + } while (++curr != circ); +} + +template +void test_star_shape(Visibility_2 &visibility, + const Query_choice &choice, + std::ifstream &input) { + + typedef typename Visibility_2::Arrangement_2 Arrangement_2; + typedef typename Visibility_2::Arrangement_2 Visibility_arrangement_2; + typedef typename Visibility_arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Visibility_arrangement_2::Geometry_traits_2 Geometry_traits_2; + typedef typename Visibility_arrangement_2::Face_const_iterator Face_const_iterator; + typedef typename Visibility_arrangement_2::Face_const_handle Face_const_handle; + typedef typename Visibility_arrangement_2::Hole_const_iterator Hole_const_iterator; + typedef typename Visibility_arrangement_2::Halfedge_const_handle + Halfedge_const_handle; + typedef typename Visibility_arrangement_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Geometry_traits_2::Point_2 Point_2; + typedef typename Geometry_traits_2::Segment_2 Segment_2; + + Arrangement_2 arr; + create_arrangement_from_env_file(arr, input); + std::cout << "Input arrangement has: " + << GREEN << arr.number_of_faces()-1 << RESET + << " faces." << std::endl; + if (Visibility_2::Supports_general_polygon_tag::value) { + int cnt(1); + Face_const_iterator fit; + for (fit = arr.faces_begin() ; fit != arr.faces_end() ; fit++) { + if (!fit->is_unbounded()) { + std::cout << "Test star-shape with face " + << GREEN << cnt << RESET << " ..." << std::endl; + test_star_shape_one_face( arr, + choice, + fit, + visibility); + } + } + } + else { // Only run the test_star_shape_one_face() on the outer loop of the arrangement + Face_const_iterator fit; + // See which face has holes + int cnt(1); + for (fit = arr.faces_begin() ; fit != arr.faces_end() ; fit++) { + if (!fit->is_unbounded()) { + std::cout << "Test star-shape with face " + << GREEN << cnt << RESET << " ..." << std::endl; + Hole_const_iterator hit; + bool has_holes = false; + for (hit = fit->holes_begin() ; hit != fit->holes_end() ; hit++) { + has_holes = true; + break; + } + if (has_holes && fit->has_outer_ccb()) { + Visibility_arrangement_2 arr_trimmed; + std::vector segments; + Ccb_halfedge_const_circulator circ = fit->outer_ccb(); + Ccb_halfedge_const_circulator curr = circ; + do { + Halfedge_const_handle he = curr; + segments.push_back(Segment_2(he->source()->point(), he->target()->point())); + } while (++curr != circ); + CGAL::insert(arr_trimmed, segments.begin(), segments.end()); + Face_const_handle fch; + if (arr_trimmed.faces_begin()->is_unbounded()) { + fch = ++arr_trimmed.faces_begin(); + } + else { + fch = arr_trimmed.faces_begin(); + } + test_star_shape_one_face(arr_trimmed, + choice, + fch, + visibility + ); + } + else if (!has_holes) { + test_star_shape_one_face(arr, + choice, + fit, + visibility); + } + cnt++; + } + } + } +} + +} // end namespace CGAL + +#endif diff --git a/Visibility_2/test/Visibility_2/pure_benchmark.cpp b/Visibility_2/test/Visibility_2/pure_benchmark.cpp new file mode 100644 index 00000000000..e68ca3cbc33 --- /dev/null +++ b/Visibility_2/test/Visibility_2/pure_benchmark.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer +// Kan Huang +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef CGAL::Gmpq Number_type; +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Arr_segment_traits_2 Traits_2; +typedef Traits_2::Point_2 Point_2; +typedef Traits_2::X_monotone_curve_2 Segment_2; +typedef CGAL::Arrangement_2 Arrangement_2; + +template +void deploy_pure_benchmark(const CGAL::Query_choice& qchoice, std::ifstream& input) { + Visibility v; + CGAL::pure_benchmark + (v, qchoice, input); +} + + +template +void benchmark_one_class(std::string name, const CGAL::Query_choice& qchoice, std::string input_arr_file) { + std::ifstream input(input_arr_file.c_str()); + if (name == "S") + deploy_pure_benchmark > (qchoice, input); + if (name == "T") + deploy_pure_benchmark > (qchoice, input); + if (name == "R") + deploy_pure_benchmark > (qchoice, input); +} + +void print_usage() { + std::cout << "Usage: ./pure_benchmark [filename] [Class type] [Query type] [Regularize]\n"; + std::cout << "where [Class type] could be S(simple), R(rotational sweep) and T(triangular), indicating which class you want to test.\n"; + std::cout << "[Query type] can be: {vertex, edge, face}.\n"; + std::cout << "[Regularize] can be: {true, false}.\n"; +} + +int main(int argc, char* argv[]) { + + CGAL::Query_choice qchoice = CGAL::FACE; + std::string regularization_tag("true"); + if (argc > 1) { + std::string input_arr_file(argv[1]); + + if (argc == 2) { + std::cout << "NAME TAG PreProTime NQueries TimeQueries TotalTime QAVE TAVE" << std::endl; + benchmark_one_class(std::string("T"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("T"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("T"), CGAL::FACE, input_arr_file); + benchmark_one_class(std::string("T"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("T"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("T"), CGAL::FACE, input_arr_file); + std::cout << std::endl; + benchmark_one_class(std::string("S"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("S"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("S"), CGAL::FACE, input_arr_file); + benchmark_one_class(std::string("S"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("S"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("S"), CGAL::FACE, input_arr_file); + std::cout << std::endl; + benchmark_one_class(std::string("R"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("R"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("R"), CGAL::FACE, input_arr_file); + benchmark_one_class(std::string("R"), CGAL::VERTEX, input_arr_file); + benchmark_one_class(std::string("R"), CGAL::EDGE, input_arr_file); + benchmark_one_class(std::string("R"), CGAL::FACE, input_arr_file); + } else if (argc == 5) { + qchoice = CGAL::FACE; + std::string query_type(argv[3]); + if (query_type == "vertex") + qchoice = CGAL::VERTEX; + else if (query_type == "edge") + qchoice = CGAL::EDGE; + else if (query_type == "face") + qchoice = CGAL::FACE; + else { + std::cout<<"query type is not matched.\n"; + return 0; + } + + regularization_tag = argv[4]; + std::string classname(argv[2]); + if (regularization_tag == "true") { + benchmark_one_class(classname, qchoice, input_arr_file); + } + else { + benchmark_one_class(classname, qchoice, input_arr_file); + } + + return 0; + } + else { + print_usage(); + exit(0); + } + } + else { + print_usage(); + exit(0); + } + return 0; +} diff --git a/Visibility_2/test/Visibility_2/run_tests.sh b/Visibility_2/test/Visibility_2/run_tests.sh new file mode 100644 index 00000000000..dd4d808f211 --- /dev/null +++ b/Visibility_2/test/Visibility_2/run_tests.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Author: Francisc Bungiu +# E-mail: fbungiu@gmail.com + +for file in * +do + if ! [[ -d $file ]] + then + if [[ -x $file ]] + then + echo "Executing '$file'..." + ./$file + fi + fi +done \ No newline at end of file diff --git a/Visibility_2/test/Visibility_2/simple_benchmark.cpp b/Visibility_2/test/Visibility_2/simple_benchmark.cpp new file mode 100644 index 00000000000..9323c6080db --- /dev/null +++ b/Visibility_2/test/Visibility_2/simple_benchmark.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer +// Kan Huang + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef CGAL::Gmpq Number_type; +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Arr_segment_traits_2 Traits_2; +typedef Traits_2::Point_2 Point_2; +typedef Traits_2::X_monotone_curve_2 Segment_2; +typedef CGAL::Arrangement_2 Arrangement_2; + +template +void deploy_benchmark(CGAL::Query_choice& qchoice, std::ifstream& input) { + Visibility_fst v1; + Visibility_snd v2; + CGAL::simple_benchmark + (v1, v2, qchoice, input); +} + +template +void define_snd_class(std::string name2, CGAL::Query_choice& qchoice, std::ifstream& input){ + if (name2 == "S") + deploy_benchmark > + (qchoice, input); + if (name2 == "T") + deploy_benchmark > + (qchoice, input); + if (name2 == "R") + deploy_benchmark > + (qchoice, input); +} + +template +void benchmark_two_classes(std::string name1, std::string name2, CGAL::Query_choice& qchoice, std::ifstream& input) { + if (name1 == "S") + define_snd_class, Regularization_tag> (name2, qchoice, input); + if (name1 == "T") + define_snd_class, Regularization_tag> (name2, qchoice, input); + if (name1 == "R") + define_snd_class, Regularization_tag> (name2, qchoice, input); +} + +void print_usage() { + std::cout << "Usage: ./simple_benchmark [filename] [Class type 1] [Class type 2] [Query type] [Regularize]\n"; + std::cout << "where [Class type] could be S(simple), R(rotational sweep) and T(triangular), indicating which classes you want to test.\n"; + std::cout << "[Query type] can be: {vertex, edge, face}.\n"; + std::cout << "[Regularize] can be: {true, false}.\n"; +} + +int main(int argc, char* argv[]) { + + CGAL::Query_choice qchoice = CGAL::FACE; + std::string regularization_tag("true"); + if (argc > 1) { + std::string input_arr_file(argv[1]); + std::ifstream input(input_arr_file.c_str()); + if (argc == 6) { + qchoice = CGAL::FACE; + std::string query_type(argv[4]); + if (query_type == "vertex") + qchoice = CGAL::VERTEX; + else if (query_type == "edge") + qchoice = CGAL::EDGE; + else if (query_type == "face") + qchoice = CGAL::FACE; + else { + std::cout<<"query type is not matched.\n"; + return 0; + } + + regularization_tag = argv[5]; + std::string class1(argv[2]), class2(argv[3]); + if (regularization_tag == "true") { + benchmark_two_classes(class1, class2, qchoice, input); + } + else { + benchmark_two_classes(class1, class2, qchoice, input); + } + + return 0; + } + else { + print_usage(); + exit(0); + } + } + else { + print_usage(); + exit(0); + } + return 0; +} diff --git a/Visibility_2/test/Visibility_2/test_rotational_visibility.cpp b/Visibility_2/test/Visibility_2/test_rotational_visibility.cpp new file mode 100644 index 00000000000..e085ae2afad --- /dev/null +++ b/Visibility_2/test/Visibility_2/test_rotational_visibility.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Kan Huang + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +int main() { +{ + typedef CGAL::Cartesian Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef Traits_2::Point_2 Point_2; + typedef Traits_2::X_monotone_curve_2 Segment_2; + typedef CGAL::Arrangement_2 Arrangement_2; + { + typedef CGAL::Rotational_sweep_visibility_2 + RSV; + CGAL::test_model_methods(); + std::cout << "Running test suite with " << GREEN << "Cartesian" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 2); + } + { + typedef CGAL::Rotational_sweep_visibility_2 + RSV; + CGAL::test_model_methods(); + std::cout << "Running test suite with " << GREEN << "Cartesian" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 2); + } +}{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef Traits_2::Point_2 Point_2; + typedef Traits_2::X_monotone_curve_2 Segment_2; + typedef CGAL::Arrangement_2 Arrangement_2; + { + typedef CGAL::Rotational_sweep_visibility_2 + RSV; + CGAL::test_model_methods(); + std::cout << "Running test suite with " << GREEN << "EPECK" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 2); + } + { + typedef CGAL::Rotational_sweep_visibility_2 + RSV; + CGAL::test_model_methods(); + std::cout << "Running test suite with " << GREEN << "EPECK" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 2); + } +} +{ + // test Visibility_arrangement_type with extended DCEL + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef CGAL::Arrangement_2 ARR; + typedef CGAL::Arr_extended_dcel EDCEL; + typedef CGAL::Arrangement_2 EARR; + { + typedef CGAL::Rotational_sweep_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + }{ + typedef CGAL::Rotational_sweep_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } +} +return 0; +} diff --git a/Visibility_2/test/Visibility_2/test_simple_visibility.cpp b/Visibility_2/test/Visibility_2/test_simple_visibility.cpp new file mode 100644 index 00000000000..a32c683b116 --- /dev/null +++ b/Visibility_2/test/Visibility_2/test_simple_visibility.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +int main() { +{ + typedef CGAL::Gmpq Number_type; + typedef CGAL::Cartesian Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef Traits_2::Point_2 Point_2; + typedef Traits_2::X_monotone_curve_2 Segment_2; + typedef CGAL::Arrangement_2 Arrangement_2; + typedef CGAL::Simple_polygon_visibility_2 + Simple_polygon_visibility_2; + std::cout << "Running model tests - "; + CGAL::test_model_methods(); + std::cout << GREEN << "Done!" << RESET << std::endl; + std::cout << "Running test suite with " << GREEN + << "Cartesian" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 0); +} +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef Traits_2::Point_2 Point_2; + typedef Traits_2::X_monotone_curve_2 Segment_2; + typedef CGAL::Arrangement_2 Arrangement_2; + typedef CGAL::Simple_polygon_visibility_2 + Simple_polygon_visibility_2; + std::cout << "Running model tests - "; + CGAL::test_model_methods(); + std::cout << GREEN << "Done!" << RESET << std::endl; + std::cout << "Running test suite with " << GREEN + << "EPECK" << RESET << " Kernel..." << std::endl; + CGAL::run_tests(21, 0); +} +{ + // test Visibility_arrangement_type with extended DCEL + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef CGAL::Arrangement_2 ARR; + typedef CGAL::Arr_extended_dcel EDCEL; + typedef CGAL::Arrangement_2 EARR; + { + typedef CGAL::Simple_polygon_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + }{ + typedef CGAL::Simple_polygon_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } +} + + return 0; +} diff --git a/Visibility_2/test/Visibility_2/test_star_shape.cpp b/Visibility_2/test/Visibility_2/test_star_shape.cpp new file mode 100644 index 00000000000..8678724c2d3 --- /dev/null +++ b/Visibility_2/test/Visibility_2/test_star_shape.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Kan Huang +// Francisc Bungiu +// Michael Hemmer + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +int main(int argc, char* argv[]) { +{ + typedef CGAL::Gmpq Number_type; + typedef CGAL::Cartesian Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef Traits_2::Point_2 Point_2; + typedef Traits_2::X_monotone_curve_2 Segment_2; + typedef CGAL::Arrangement_2 Arrangement_2; + typedef CGAL::Simple_polygon_visibility_2 + Simple_polygon_visibility_2; + + typedef CGAL::Triangular_expansion_visibility_2 + Triangular_expansion_visibility_2; + + if (argc == 2) { + Simple_polygon_visibility_2 simple_visibility; + const CGAL::Query_choice qchoice = CGAL::FACE; + std::string input_arr_file(argv[1]); + std::ifstream input(input_arr_file.c_str()); + CGAL::test_star_shape + (simple_visibility, qchoice, input); + return 0; + } + + if (argc == 3) { + const CGAL::Query_choice qchoice = CGAL::FACE; + std::string input_arr_file(argv[1]); + std::ifstream input(input_arr_file.c_str()); + std::string class_name(argv[2]); + if ( class_name == "simple") { + Simple_polygon_visibility_2 simple_visibility; + CGAL::test_star_shape + (simple_visibility, qchoice, input); + return 0; + } + if (class_name == "triangular") { + Triangular_expansion_visibility_2 triangular_visibility; + CGAL::test_star_shape + (triangular_visibility, qchoice, input); + return 0; + } + std::cout<<"no type is matched.\n"; + return 0; + } + + if (argc == 4) { + std::string input_arr_file(argv[1]); + std::ifstream input(input_arr_file.c_str()); + CGAL::Query_choice qchoice; + std::string query_type(argv[3]); + if (query_type == "vertex") + qchoice = CGAL::VERTEX; + else { + if (query_type == "edge") + qchoice = CGAL::EDGE; + else { + if (query_type == "face") + qchoice = CGAL::FACE; + else { + std::cout<<"query type is not matched.\n"; + return 0; + } + } + } + std::string class_name(argv[2]); + if (class_name == "simple") { + Simple_polygon_visibility_2 simple_visibility; + CGAL::test_star_shape + (simple_visibility, qchoice, input); + return 0; + } + if (class_name == "triangular") { + Triangular_expansion_visibility_2 triangular_visibility; + CGAL::test_star_shape + (triangular_visibility, qchoice, input); + return 0; + } + std::cout<<"no type is matched.\n"; + return 0; + + } + + + std::cout << "Usage: ./test_star_shape [filename] [Class type] [Query type]\n"; + std::cout << "where [Class type] could be simple, naive and triangular, indicating which class you want to test.\n"; + std::cout << "[Query type] could be vertex, edge, face.\n"; + std::cout << "The default value of [Query type] is face. The default value of [Class type] is simple.\n"; + exit(0); +} + +} diff --git a/Visibility_2/test/Visibility_2/test_triangular_expansion.cpp b/Visibility_2/test/Visibility_2/test_triangular_expansion.cpp new file mode 100644 index 00000000000..24b604e023a --- /dev/null +++ b/Visibility_2/test/Visibility_2/test_triangular_expansion.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2013 Technical University Braunschweig (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s): Francisc Bungiu +// Michael Hemmer + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int main() { + { + typedef CGAL::Gmpq Number_type; + typedef CGAL::Cartesian Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef CGAL::Arrangement_2 Arrangement_2; + { + typedef CGAL::Triangular_expansion_visibility_2 + Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } + { + typedef CGAL::Triangular_expansion_visibility_2 + Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } + } + { + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef CGAL::Arrangement_2 Arrangement_2; + { + typedef CGAL::Triangular_expansion_visibility_2 + Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + }{ + typedef CGAL::Triangular_expansion_visibility_2 + Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } + } + + { + // test Visibility_arrangement_type with extended DCEL + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef CGAL::Arr_segment_traits_2 Traits_2; + typedef CGAL::Arrangement_2 ARR; + typedef CGAL::Arr_extended_dcel EDCEL; + typedef CGAL::Arrangement_2 EARR; + { + typedef CGAL::Triangular_expansion_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + }{ + typedef CGAL::Triangular_expansion_visibility_2 Visibility_2; + CGAL::test_model_methods(); + CGAL::run_tests(21, 2); + } + } + + return 0; +}