mirror of https://github.com/CGAL/cgal
Merge branch 'gsoc2013-Visibility_doc-hemmer-old' into gsoc2013-Visibility_doc-hemmer
This commit is contained in:
commit
f9a0c14427
|
|
@ -2336,6 +2336,25 @@ ADDRESS = "Saarbr{\"u}cken, Germany"
|
|||
series = {Texts and Monographs in Symbolic Computation}
|
||||
}
|
||||
|
||||
@article{cgal: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{cgal: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"
|
||||
}
|
||||
|
||||
% ----------------------------------------------------------------------------
|
||||
% END OF BIBFILE
|
||||
% ----------------------------------------------------------------------------
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -718,8 +718,24 @@ namespace for the XML file to be processed properly. -->
|
|||
<item>./tags/Arrangement_on_surface_2.tag=../../CGAL.CGAL.2D-Arrangements/html</item>
|
||||
</list>
|
||||
</doxygen>
|
||||
</project>
|
||||
|
||||
<project>
|
||||
<name>2D Visibility</name>
|
||||
<input>../Visibility_2/doc/Visibility_2</input>
|
||||
<doxygen>
|
||||
<string name="STRIP_FROM_INC_PATH">../Visibility_2/doc/Visibility_2/</string>
|
||||
<string name="STRIP_FROM_PATH">../Visibility_2/doc/Visibility_2/</string>
|
||||
<string name="GENERATE_TAGFILE">./tags/Visibility_2.tag</string>
|
||||
<string name="EXAMPLE_PATH">../Visibility_2/examples</string>
|
||||
<string name="IMAGE_PATH">../Visibility_2/doc/Visibility_2/fig</string>
|
||||
<list name="TAGFILES" append="true">
|
||||
<item>./tags/Arrangement_on_surface_2.tag=../../CGAL.CGAL.2D-Arrangements/html</item>
|
||||
</list>
|
||||
</doxygen>
|
||||
</project>
|
||||
|
||||
|
||||
<project>
|
||||
<name>2D Minkowski Sums</name>
|
||||
<input>../Minkowski_sum_2/doc/Minkowski_sum_2</input>
|
||||
|
|
@ -1457,6 +1473,7 @@ namespace for the XML file to be processed properly. -->
|
|||
<item>../Convex_hull_d/doc/Convex_hull_d/fig</item>
|
||||
<item>../Envelope_2/doc/Envelope_2/fig</item>
|
||||
<item>../Envelope_3/doc/Envelope_3/fig</item>
|
||||
<item>../Visibility_2/doc/Visibility_2/fig</item>
|
||||
<item>../Generator/doc/Generator/fig</item>
|
||||
<item>../Geomview/doc/Geomview/fig</item>
|
||||
<item>../GraphicsView/doc/GraphicsView/fig</item>
|
||||
|
|
@ -1538,6 +1555,7 @@ namespace for the XML file to be processed properly. -->
|
|||
<item>./tags/Convex_hull_d.tag=../../CGAL.CGAL.dD-Convex-Hulls-and-Delaunay-Triangulations/html</item>
|
||||
<item>./tags/Envelope_2.tag=../../CGAL.CGAL.2D-Envelopes/html</item>
|
||||
<item>./tags/Envelope_3.tag=../../CGAL.CGAL.3D-Envelopes/html</item>
|
||||
<item>./tags/Visibility_2.tag=../../CGAL.CGAL.2D-Visibility/html</item>
|
||||
<item>./tags/Generator.tag=../../CGAL.CGAL.Geometric-Object-Generators/html</item>
|
||||
<item>./tags/Geomview.tag=../../CGAL.CGAL.Geomview/html</item>
|
||||
<item>./tags/GraphicsView.tag=../../CGAL.CGAL.CGAL-and-the-Qt-Graphics-View-Framework/html</item>
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
\ingroup PkgVisibility_2Classes
|
||||
|
||||
This class is a model of the concept `Visibility_2` offers visibility queries within
|
||||
an Arrangement. The algorithm it applies to obtain visibility is without preprocessing.
|
||||
It relies on the algorithm of T. Asano \cite ta-aeafvpprh-85 based on angular plane sweep,
|
||||
with a time complexity of O (n log n) in the number of vertices.
|
||||
|
||||
ArrExtensionTraits_2 gives information about the input/output Arrangements and the extension between them.
|
||||
The Regularization_tag indicates whether the output Arrangement result should be regularized. It can be
|
||||
specified by one of the following: CGAL::Tag_true or CGAL::Tag_false.
|
||||
|
||||
\cgalModels `Visibility_2`
|
||||
|
||||
\sa 'CGAL::Visibility_2'
|
||||
\sa `CGAL::Simple_visibility_2<ArrExtensionTraits_2, Regularization_tag>`
|
||||
\sa `CGAL::Preprocessed_visibility_2<ArrExtensionTraits_2, Regularization_tag>`
|
||||
|
||||
*/
|
||||
template <typename ArrExtensionTraits_2, typename Regularization_tag>
|
||||
class Naive_visibility_2 {
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
/*!
|
||||
*The type of Arrangement Extension Traits.
|
||||
*/
|
||||
typedef ArrExtensionTraits_2 Arr_extension_traits_2;
|
||||
|
||||
/*!
|
||||
The type of input Arrangement.
|
||||
*/
|
||||
typedef Arr_extension_traits_2::Input_Arrangement_2 Input_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The type of output Arrangement.
|
||||
*/
|
||||
typedef Arr_extension_traits_2::Output_Arrangement_2 Output_Arrangement_2;
|
||||
|
||||
|
||||
/*!
|
||||
The Point_2 type which is used for queries.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Point_2 Point_2;
|
||||
|
||||
/*!
|
||||
Face_handle type of input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Face_handle Face_handle;
|
||||
|
||||
/*!
|
||||
Halfedge_handle type of input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
/*!
|
||||
* Face_handle type of output Arrangement.
|
||||
*/
|
||||
typedef Output_Arrangement_2::Face_handle Out_face_handle;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Constructors
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Constructs a `Visibility_2` object from a given `Input_Arrangement_2`
|
||||
*/
|
||||
Naive_visibility_2(const Input_Arrangement_2& arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// \name functions
|
||||
/// @{
|
||||
|
||||
|
||||
/*!
|
||||
Return whether the object is attached to an arrangement.
|
||||
*/
|
||||
bool is_attached ();
|
||||
|
||||
/*!
|
||||
Attaches visibility object to the given arrangement arr.
|
||||
*/
|
||||
void attach ( Input_Arrangement_2 arr);
|
||||
|
||||
|
||||
/*!
|
||||
Detaches the object from the arrangement it is currently attached to.
|
||||
*/
|
||||
void detach ();
|
||||
|
||||
/*!
|
||||
Access to the attached Arrangement.
|
||||
*/
|
||||
Input_Arrangement_2 arr();
|
||||
|
||||
/*!
|
||||
Computes the visibility region for the given query point q.
|
||||
\pre face is a face of this->arr()
|
||||
\pre p is in the interior of face
|
||||
\pre out_arr is the output arrangement
|
||||
|
||||
*/
|
||||
void visibility_region(const Point_2& q, const Face_handle& face, Output_Arrangement_2& out_arr, Out_face_handle& out_face);
|
||||
|
||||
/*!
|
||||
Computes for the given query point q the visibility region that is on the side of the given halfedge.
|
||||
\pre half_edge is a half edge of this->arr()
|
||||
\pre p is on halfedge
|
||||
\pre out_arr is the output arrangement
|
||||
|
||||
*/
|
||||
void visibility_region(const Point_2& q, const Halfedge_handle& halfedge, Output_Arrangement_2& out_arr, Out_face_handle& out_face);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
}; /* end Visibility_2 */
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
\ingroup PkgVisibility_2Classes
|
||||
|
||||
This class is a model of the concept `Visibility_2` offers visibility queries within
|
||||
an Arrangement. The algorithm it applies to obtain visibility is using preprocessing.
|
||||
|
||||
\cgalModels `Visibility_2`
|
||||
|
||||
\sa 'CGAL::Visibility_2'
|
||||
\sa `CGAL::Simple_visibility_2<ArrExtensionTraits_2, Regularization_tag>`
|
||||
\sa `CGAL::Naive_visibility_2<ArrExtensionTraits_2, Regularization_tag>`
|
||||
|
||||
*/
|
||||
template <typename ArrExtensionTraits_2, typename Regularization_tag>
|
||||
class Preprocessed_visibility_2 {
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
The type of Arrangement extension traits.
|
||||
*/
|
||||
typedef ArrExtensionTraits_2 Arr_extension_traits_2;
|
||||
|
||||
/*!
|
||||
The type of input Arrangement.
|
||||
*/
|
||||
typedef Arr_extension_traits_2::Input_Arrangement_2 Input_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The type of output Arrangement.
|
||||
*/
|
||||
typedef Arr_extension_traits_2::Output_Arrangement_2 Output_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The Point_2 type which is used for queries.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Point_2 Point_2;
|
||||
|
||||
/*!
|
||||
Face_handle type of input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Face_handle Face_handle;
|
||||
|
||||
/*!
|
||||
Halfedge_handle type of input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Constructors
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Constructs a `Visibility_2` object from a given `Input_Arrangement_2`
|
||||
*/
|
||||
Naive_visibility_2(const Input_Arrangement_2& arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// \name functions
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Return whether the object is attached to an arrangement.
|
||||
*/
|
||||
bool is_attached ();
|
||||
|
||||
/*!
|
||||
Attaches visibility object to the given arrangement arr.
|
||||
*/
|
||||
void attach ( Input_Arrangement_2 arr);
|
||||
|
||||
|
||||
/*!
|
||||
Detaches the object from the arrangement it is currently attached to.
|
||||
*/
|
||||
void detach ();
|
||||
|
||||
/*!
|
||||
Access to the attached Arrangement_2.
|
||||
*/
|
||||
Input_Arrangement_2 arr();
|
||||
|
||||
/*!
|
||||
Computes the visibility region for the given query point q.
|
||||
\pre face is a face of this->arr()
|
||||
\pre p is in the interior of face
|
||||
\pre out_arr is the output arrangement
|
||||
|
||||
*/
|
||||
void visibility_region(const Point_2& q, const Face& face, Output_Arrangement_2& out_arr);
|
||||
|
||||
/*!
|
||||
Computes for the given query point q the visibility region that is on the side of the given halfedge.
|
||||
\pre half_edge is a half edge of this->arr()
|
||||
\pre p is on halfedge
|
||||
\pre out_arr is the output arrangement
|
||||
|
||||
*/
|
||||
void visibility_region(const Point_2& q, const Halfedge& halfedge, Output_Arrangement_2& out_arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
}; /* end Visibility_2 */
|
||||
|
||||
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
\ingroup PkgVisibility_2Classes
|
||||
|
||||
This class is a model of the concept `Visibility_2` offers visibility queries within
|
||||
a simple polygon with no holes. Uses the algorithm of B.Joe and R.B.Simpson \cite bjrb-clvpa-87 to
|
||||
obtain the visibility polygon, based on a scan of the boundary of the polygon and the notion
|
||||
of angular displacement as a control variable. The algorithm is a modification and extension
|
||||
of the linear time algorithm of Lee \cite TODO. It computes the visibility polygon from a
|
||||
viewpoint that is in the interior or on the boundary of the polygon.
|
||||
|
||||
The algorithm uses a stack to manipulate the vertices, and ultimately yields the visibility
|
||||
polygon. For each scanned edge, at most 2 points are pushed on the stack. Overall, it
|
||||
will have at most 2n points pushed and popped, thus the time and space complexities of the
|
||||
algorithm are O(n), where n is the number of the vertices of the polygon. Degenerate cases
|
||||
such as needles require a post-processing step, which is linear in the number of vertices
|
||||
forming the needles. In such cases, the overall time complexity is O(n*m), where n is the
|
||||
number of vertices of the polygon, and m is the number of vertices forming the largest needle
|
||||
in the output.
|
||||
|
||||
The class also supports a regularization tag which allows the user to obtain an output
|
||||
with all the isolated vertices and edges that have the same face on both sides removed.
|
||||
|
||||
\cgalModels `Visibility_2`
|
||||
|
||||
\sa 'CGAL::Visibility_2'
|
||||
\sa `CGAL::Naive_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
\sa `CGAL::Preprocessed_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
|
||||
*/
|
||||
template <typename ArrTraits_2, typename Regularization_tag>
|
||||
class Simple_visibility_2 {
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
typedef ArrTraits_2 Arr_traits_2;
|
||||
/*!
|
||||
The Arrangement type is used for input.
|
||||
*/
|
||||
typedef Arr_traits_2::Input_Arrangement_2 Input_Arrangement_2;
|
||||
|
||||
/*!
|
||||
*The Arrangement type is used for output.
|
||||
*/
|
||||
typedef Arr_traits_2::Output_Arrangement_2 Output_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The Point_2 type which is used for queries.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Point_2 Point_2;
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Constructors
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Default constructor creates an empty `Visibility_2` object
|
||||
*/
|
||||
Simple_visibility_2();
|
||||
|
||||
/*!
|
||||
Constructs a `Visibility_2` object from a given `Input_Arrangement_2`
|
||||
*/
|
||||
Simple_visibility_2(const Input_Arrangement_2& arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// \name functions
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Returns whether an arrangement is attached to the visibility object
|
||||
*/
|
||||
bool is_attached ();
|
||||
|
||||
/*!
|
||||
Attaches the given arrangement to the visibility object
|
||||
*/
|
||||
void attach (const Input_Arrangement_2 &arr);
|
||||
|
||||
/*!
|
||||
Detaches the arrangement from the visibility object it is currently attached to
|
||||
*/
|
||||
void detach();
|
||||
|
||||
/*!
|
||||
Access to the attached arrangement
|
||||
*/
|
||||
Input_Arrangement_2 arr();
|
||||
|
||||
/*!
|
||||
Computes the visibility region for the given query point q.
|
||||
\pre face is a face of this->arr() with no holes
|
||||
\pre p is in the interior of face
|
||||
\pre out_arr is the output arrangement
|
||||
\return a face handle to the bounded face of the output
|
||||
*/
|
||||
Face_handle visibility_region(const Point_2& q, const Face& face, Output_Arrangement_2& out_arr);
|
||||
|
||||
/*!
|
||||
Computes for the given query point q the visibility region that is on the side of the given halfedge.
|
||||
\pre half_edge is a half edge of this->arr()
|
||||
\pre p is located on the halfedge
|
||||
\pre out_arr is the output arrangement
|
||||
\return a face handle to the bounded face of the output
|
||||
*/
|
||||
Face_handle visibility_region(const Point_2& q, const Halfedge& halfedge, Output_Arrangement_2& out_arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
}; /* end Visibility_2 */
|
||||
}
|
||||
|
|
@ -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<K>`
|
||||
|
||||
\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();
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
/*!
|
||||
\ingroup PkgVisibility_2Concepts
|
||||
\cgalConcept
|
||||
|
||||
A model of the concept `Visibility_2` offers visibility queries within
|
||||
an Arrangement.
|
||||
|
||||
\cgalHasModel `CGAL::Simple_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
\cgalHasModel `CGAL::Naive_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
\cgalHasModel `CGAL::Preprocessed_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
|
||||
\sa `CGAL::Simple_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
\sa `CGAL::Naive_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
\sa `CGAL::Preprocessed_visibility_2<ArrTraits_2, Regularization_tag>`
|
||||
|
||||
*/
|
||||
class Visibility_2 {
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
The supported Arrangement type of input.
|
||||
*/
|
||||
typedef Hidden_type Input_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The supported Arrangement type of output.
|
||||
*/
|
||||
typedef Hidden_type Output_Arrangement_2;
|
||||
|
||||
/*!
|
||||
The supported Point_2 type of the input type, used for queries.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Point_2 Point_2;
|
||||
|
||||
/*!
|
||||
* The supported Face handle type of the input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Face_handle Face_handle;
|
||||
|
||||
/*!
|
||||
* The supported Halfedge handle type of the input Arrangement.
|
||||
*/
|
||||
typedef Input_Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
/*!
|
||||
* The supported Face_handle type of output Arrangement.
|
||||
*/
|
||||
typedef Output_Arrangement_2::Face_handle Out_face_handle;
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
Tag identifying whether `Visibility_2` computes regularized visbility area.
|
||||
*/
|
||||
typedef Hidden_type Regularization_tag;
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Constructors
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
default constructor.
|
||||
*/
|
||||
Visibility_2();
|
||||
|
||||
/*!
|
||||
Constructs a `Visibility_2` object from a given `Arrangement_2` and a given Regularization tag.
|
||||
*/
|
||||
Visibility_2(const Input_Arrangement_2 &arr);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// \name functions
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Returns whether an arrangement is attached to the visibility object
|
||||
*/
|
||||
bool is_attached ();
|
||||
|
||||
/*!
|
||||
Attaches the given arrangement to the visibility object.
|
||||
*/
|
||||
void attach (const Input_Arrangement_2 &arr);
|
||||
|
||||
|
||||
/*!
|
||||
Detaches the arrangement from the visibility object it is currently attached to
|
||||
*/
|
||||
void detach();
|
||||
|
||||
/*!
|
||||
Access to the attached arrangement
|
||||
*/
|
||||
Input_Arrangement_2 arr();
|
||||
|
||||
/*!
|
||||
Computes the visibility region for the given query point q. Visibility polygon of q and its face will be saved to out_arr and out_face.
|
||||
\pre face is a face of this->arr()
|
||||
\pre p is in the interior of face
|
||||
\pre out_arr is the output arrangement
|
||||
\return a face handle to the bounded face of the output
|
||||
*/
|
||||
Face_handle visibility_region(const Point_2& q, const Face_handle& face, Output_Arrangement_2& out_arr);
|
||||
|
||||
/*!
|
||||
Computes for the given query point q the visibility region that is on the side of the given halfedge. Visibility polygon of q and its face will be saved to out_arr and out_face.
|
||||
\pre half_edge is a half edge of this->arr()
|
||||
\pre p is on halfedge
|
||||
\pre out_arr is the output arrangement
|
||||
\return a face handle to the bounded face of the output
|
||||
*/
|
||||
Face_handle visibility_region(const Point_2& q, const Halfedge_handle& halfedge, Output_Arrangement_2& out_arr);
|
||||
|
||||
/// @}
|
||||
|
||||
}; /* end Visibility_2 */
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/// \defgroup PkgVisibility_2 Visibility_2 Reference
|
||||
|
||||
/// \defgroup PkgVisibility_2Concepts Concepts
|
||||
/// \ingroup PkgVisibility_2
|
||||
|
||||
/*!
|
||||
\addtogroup PkgVisibility_2
|
||||
\cgalPkgDescriptionBegin{2D Visibility Computation,PkgVisibility_2Summary}
|
||||
\cgalPkgPicture{visibility_2-teaser-thumb.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Michael Hemmer, Kan Huang, Francisc Bungiu}
|
||||
\cgalPkgDesc{The 2D Visibility component offers several variants for
|
||||
viibility computation amidst liniar geometry in the plain.}
|
||||
\cgalPkgManuals{Chapter_2D_Visibility_Computation,PkgVisibility_2}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{99.99}
|
||||
\cgalPkgBib{cgal:hhb-visibility-2}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgShortInfoEnd
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
## Concepts ##
|
||||
- `Visibility_2`
|
||||
|
||||
## Classes ##
|
||||
- `CGAL::Simple_visibility_2<Arr>
|
||||
- `CGAL::Naive_visibility_2<Arr>
|
||||
- `CGAL::Preprocessed_visibility_2<Arr>
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*!
|
||||
\example Visibility_2/Visibility_2_example.cpp
|
||||
*/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
|
|
@ -0,0 +1,67 @@
|
|||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_2D_Visibility_Computation
|
||||
\cgalAutoToc
|
||||
|
||||
\authors Michael Hemmer, Kan Huang, Francisc Bungiu
|
||||
|
||||
\section visibility_2_introduction Introduction
|
||||
|
||||
\cgalFigureBegin{exaample_figure,visibility-teaser.png}
|
||||
An example figure.
|
||||
\cgalFigureEnd
|
||||
|
||||
\section visibility_2_interface Interface
|
||||
|
||||
|
||||
The following is a cut and paste from the minutes of the CGAL developer meeting in Nancy:
|
||||
|
||||
Status of Visibility computation:
|
||||
Currently there is some code within the Art Gallery project that does visibility computation without preprocessing. The output is essentially an arrangement. But it is probably better to start new code in CGAL style.
|
||||
Design of Visibility package which should be the result of GSoC 2013:
|
||||
Goals:
|
||||
|
||||
The package should be able to optionally handle degenerated outputs, i.e., one dimensional needles -- this is why I put visibility "polygon" in ""
|
||||
|
||||
the package should be able to associate the origin of an edge in the output to its counter part in the input or to the vertex that "caused" the creation of the edge.
|
||||
|
||||
there should be the option to do visibility computation with and without preprocessing
|
||||
|
||||
Principal design idea:
|
||||
|
||||
The main concept is that of a visibility object that allows visibility queries. We will have at least three different strategies in different classes:
|
||||
|
||||
simple visibility (for arrangements with no holes)
|
||||
|
||||
naive visibility -- without preprocessing
|
||||
|
||||
visibility with preprocessing (some algo)
|
||||
|
||||
The object is constructed from a full arrangement which is stored and which allows preprocessing inside if needed. Visibility queries are then to that object. This allows to have both strategies in the same interface. It is worth considering distinguishing the regularized and non-regularized in compile time (e.g., using a template Boolean parameter.)
|
||||
|
||||
The constructor takes an additional bool whether the output should be regularized or not. This is already in the constructor as this may effect potential preprocessing
|
||||
|
||||
Template parameters are the Arrangement type (allows access to traits and kernel)
|
||||
|
||||
A query is a point and:
|
||||
|
||||
a face if the point is inside the interior of the face
|
||||
|
||||
a half edge if the point is on the boundary, this avoid ambiguity on which polygon is to be computed (e.g. which side of the edge is seen.)
|
||||
|
||||
Output: The output is an "extended" Arrangement (using [1]) such that additional data members of vertex/edge/face give pointers to their counterparts in the input arrangement if they exists. -- view edges don't have counter parts, but they can link to the vertex that caused them. The data member of the face can probably be empty (but it can not hurt to point to the original face either.)
|
||||
|
||||
using the arrangement as output it easy to also report needles in case the (regularize) bool is not set. Otherwise we report the regularized version of the visibility area. Also as an extended arrangement. Though in this case it is indeed a polygon that could be reported.
|
||||
|
||||
[1] http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Arrangement_on_surface_2_ref/Class_Arr_extended_dcel.html
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,746 @@
|
|||
// 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 <huangkandiy@gmail.com>
|
||||
//
|
||||
#ifndef CGAL_NAIVE_VISIBILITY_2_H
|
||||
#define CGAL_NAIVE_VISIBILITY_2_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Direction_2.h>
|
||||
#include <CGAL/Vector_2.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Ray_2.h>
|
||||
#include <CGAL/tags.h>
|
||||
#include <CGAL/enum.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Visibility_2 {
|
||||
|
||||
//debug
|
||||
template<typename Point_handle>
|
||||
void print(std::vector<Point_handle> ps){
|
||||
for (int i=0; i<ps.size(); i++)
|
||||
{
|
||||
std::cout<<ps[i]->point().x()<<","<<ps[i]->point().y()<<std::endl;
|
||||
}
|
||||
}
|
||||
//template <typename Point_2>
|
||||
//void print_point(const Point_2& p) {
|
||||
// std::cout<<"["<<p.x()<<","<<p.y()<<"]"<<std::endl;
|
||||
//}
|
||||
|
||||
|
||||
template <typename Arrangement_2, typename Regularization_tag>
|
||||
class Naive_visibility_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::Ray_2 Ray_2;
|
||||
typedef typename Geometry_traits_2::Segment_2 Segment_2;
|
||||
typedef typename Geometry_traits_2::Vector_2 Vector_2;
|
||||
typedef typename Geometry_traits_2::Direction_2 Direction_2;
|
||||
|
||||
typedef typename Arrangement_2::Halfedge Halfedge;
|
||||
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
|
||||
|
||||
enum Intersection_type { UNBOUNDED, CORNER, INNER };
|
||||
|
||||
public:
|
||||
//members
|
||||
Arrangement_2 arr;
|
||||
|
||||
//functions
|
||||
Naive_visibility_2(const Arrangement_2 &arr):arr(arr), attach_tag(true) {}
|
||||
|
||||
Naive_visibility_2(): attach_tag(false) {}
|
||||
|
||||
|
||||
void visibility_region(const Point_2 &q, const Halfedge &edge, Arrangement_2 &out_arr) {
|
||||
|
||||
}
|
||||
|
||||
void visibility_region(const Point_2 &query, Face_const_handle fh, Arrangement_2 &out_arr) {
|
||||
visibility_region_impl(query, fh, out_arr, Regularization_tag());
|
||||
|
||||
}
|
||||
|
||||
void visibility_region_impl(const Point_2 &query, Face_const_handle fh, Arrangement_2 &out_arr, CGAL::Tag_true) {
|
||||
std::vector<Vertex_const_handle> vertices; //all vertices of the face.
|
||||
std::vector<Halfedge_const_handle> edges, active_edges; //edges stores all halfedges of the face; and active_edges stores all halfedges that is currently intersected by the view ray.
|
||||
//preprocess the face
|
||||
input_face(fh, vertices, edges, query);
|
||||
//initiation of vision ray
|
||||
Vector_2 dir;
|
||||
if (Direction_2(-1, 0) < Direction_2(Vector_2(query, (*vertices.rbegin())->point())))
|
||||
{
|
||||
dir = Vector_2(1, 0) + Vector_2(query, (*vertices.rbegin())->point());
|
||||
}
|
||||
else {
|
||||
dir = Vector_2(0, -1);
|
||||
}
|
||||
Ray_2 init_vision_ray(query, dir);
|
||||
|
||||
//initiation of active_edges
|
||||
typename std::vector<Halfedge_const_handle>::iterator iter1;
|
||||
for (iter1 = edges.begin(); iter1 != edges.end(); iter1++)
|
||||
{
|
||||
insert_halfedge(active_edges, init_vision_ray, *iter1);
|
||||
}
|
||||
|
||||
//angular sweep
|
||||
std::vector<Point_2> polygon;
|
||||
Ray_2 curr_vision_ray = init_vision_ray;
|
||||
typename std::vector<Vertex_const_handle>::iterator vit = vertices.begin(), begin_it, end_it;
|
||||
Halfedge_const_handle closest_edge;
|
||||
bool is_init_empty = active_edges.empty();
|
||||
while (vit != vertices.end())
|
||||
{
|
||||
if (active_edges.empty())
|
||||
{
|
||||
begin_it = vit;
|
||||
end_it = vit;
|
||||
curr_vision_ray= Ray_2(query, (*begin_it)->point());
|
||||
Direction_2 d1(curr_vision_ray), d2;
|
||||
do {
|
||||
d2 = Direction_2(Ray_2(query, (*end_it)->point()));
|
||||
if (d1 != d2) break;
|
||||
} while (++end_it != vertices.end());
|
||||
add_edges(begin_it, end_it, active_edges, curr_vision_ray);
|
||||
|
||||
//since active_edges is empty, that means adding new edges will bring in an unbounded edge to arrangement.
|
||||
closest_edge = active_edges[0];
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
|
||||
if (active_edges.empty()) {
|
||||
//this means in input, there is no edge that intersects curr_vision_ray
|
||||
//except those collinear ones.
|
||||
//because one unbounded ray has been inserted before,
|
||||
//we don't need to do anything here.
|
||||
}
|
||||
else {
|
||||
//add new edge;
|
||||
Point_2 p1 = intersection_point(curr_vision_ray, closest_edge);
|
||||
Point_2 p2 = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(p1, polygon, out_arr);
|
||||
update_visibility(p2, polygon, out_arr);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
closest_edge = active_edges[0];
|
||||
begin_it = vit; //all vertices between begin_it and end_it(not included) are collinear with query point.
|
||||
end_it = vit;
|
||||
curr_vision_ray = Ray_2(query, (*begin_it)->point());
|
||||
Direction_2 d1(curr_vision_ray), d2;
|
||||
do {
|
||||
d2 = Direction_2(Ray_2(query, (*end_it)->point()));
|
||||
if (d1 != d2) break;
|
||||
} while (++end_it != vertices.end());
|
||||
add_edges(begin_it, end_it, active_edges, curr_vision_ray);
|
||||
|
||||
if (closest_edge != active_edges[0])
|
||||
{
|
||||
//add new edge;
|
||||
Point_2 p1 = intersection_point(curr_vision_ray, closest_edge);
|
||||
Point_2 p2 = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(p1, polygon, out_arr);
|
||||
update_visibility(p2, polygon, out_arr);
|
||||
|
||||
}
|
||||
|
||||
closest_edge = active_edges[0];
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
|
||||
if (active_edges.empty()) {
|
||||
//add an unbounded edge
|
||||
//todo CGAL::insert_curve(out_arr, Ray_2((*begin_it)->point(), Direction_2(curr_vision_ray)));
|
||||
}
|
||||
else {
|
||||
if (closest_edge != active_edges[0]) {
|
||||
//add new edge;
|
||||
Point_2 p1 = intersection_point(curr_vision_ray, closest_edge);
|
||||
Point_2 p2 = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(p1, polygon, out_arr);
|
||||
update_visibility(p2, polygon, out_arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
vit = end_it;
|
||||
}
|
||||
if (!is_init_empty) {
|
||||
CGAL::insert(out_arr, Segment_2(polygon[0], polygon.back()));
|
||||
}
|
||||
}
|
||||
|
||||
void visibility_region_impl(const Point_2 &query, Face_const_handle fh, Arrangement_2 &out_arr, CGAL::Tag_false) {
|
||||
std::vector<Vertex_const_handle> vertices; //all vertices of the face.
|
||||
std::vector<Halfedge_const_handle> edges, active_edges; //edges stores all halfedges of the face; and active_edges stores all halfedges that is currently intersected by the view ray.
|
||||
//preprocess the face
|
||||
input_face(fh, vertices, edges, query);
|
||||
//initiation of vision ray
|
||||
Vector_2 dir;
|
||||
if (Direction_2(-1, 0) < Direction_2(Vector_2(query, (*vertices.rbegin())->point())))
|
||||
{
|
||||
dir = Vector_2(1, 0) + Vector_2(query, (*vertices.rbegin())->point());
|
||||
}
|
||||
else {
|
||||
dir = Vector_2(0, -1);
|
||||
}
|
||||
Ray_2 init_vision_ray(query, dir);
|
||||
|
||||
//initiation of active_edges
|
||||
typename std::vector<Halfedge_const_handle>::iterator iter1;
|
||||
for (iter1 = edges.begin(); iter1 != edges.end(); iter1++)
|
||||
{
|
||||
insert_halfedge(active_edges, init_vision_ray, *iter1);
|
||||
}
|
||||
|
||||
//angular sweep
|
||||
std::vector<Point_2> polygon;
|
||||
Ray_2 curr_vision_ray = init_vision_ray;
|
||||
typename std::vector<Vertex_const_handle>::iterator vit = vertices.begin(), begin_it, end_it;
|
||||
Halfedge_const_handle closest_edge;
|
||||
bool is_init_empty = active_edges.empty();
|
||||
while (vit != vertices.end())
|
||||
{
|
||||
if (active_edges.empty())
|
||||
{
|
||||
begin_it = vit;
|
||||
end_it = vit;
|
||||
curr_vision_ray= Ray_2(query, (*begin_it)->point());
|
||||
Direction_2 d1(curr_vision_ray), d2;
|
||||
do {
|
||||
d2 = Direction_2(Ray_2(query, (*end_it)->point()));
|
||||
if (d1 != d2) break;
|
||||
} while (++end_it != vertices.end());
|
||||
add_edges(begin_it, end_it, active_edges, curr_vision_ray);
|
||||
|
||||
//since active_edges is empty, that means adding new edges will bring in an unbounded edge to arrangement.
|
||||
Point_2 p1 = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
polygon.push_back(p1);
|
||||
//todo CGAL::insert_curve(out_arr, Ray_2(p1, d1));
|
||||
|
||||
closest_edge = active_edges[0];
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
|
||||
if (active_edges.empty()) {
|
||||
//this means there is no edge that intersects curr_vision_ray
|
||||
//except those collinear ones.
|
||||
//because one unbounded ray has been inserted before,
|
||||
//we don't need to do anything here.
|
||||
}
|
||||
else {
|
||||
//add new edge;
|
||||
//Point_2 p1 = intersection_point(curr_vision_ray, closest_edge);
|
||||
Point_2 p2 = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
//update_visibility(p1, polygon, out_arr);
|
||||
update_visibility(p2, polygon, out_arr);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
Point_2 right_p, left_p, mid_p;
|
||||
begin_it = vit;
|
||||
end_it = vit; //all vertices between begin_it and end_it(not included) are collinear with query point.
|
||||
curr_vision_ray= Ray_2(query, (*begin_it)->point());
|
||||
right_p = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
Direction_2 d1(curr_vision_ray), d2;
|
||||
do {
|
||||
d2 = Direction_2(Ray_2(query, (*end_it)->point()));
|
||||
if (d1 != d2) break;
|
||||
} while (++end_it != vertices.end());
|
||||
add_edges(begin_it, end_it, active_edges, curr_vision_ray);
|
||||
|
||||
mid_p = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
std::vector<Point_2> collinear_vertices;
|
||||
Intersection_type i_type = needle(active_edges, curr_vision_ray, collinear_vertices);
|
||||
switch (i_type) {
|
||||
case UNBOUNDED :
|
||||
//todo:this part is not finished.
|
||||
//remove right and collinear;
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
update_visibility(right_p, polygon, out_arr);
|
||||
update_visibility(mid_p, polygon, out_arr);
|
||||
//todo CGAL::insert_curve();
|
||||
if (!active_edges.empty()) {
|
||||
left_p = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(left_p, polygon, out_arr);
|
||||
}
|
||||
break;
|
||||
case CORNER :
|
||||
//remove right and collinear;
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
left_p = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(right_p, polygon, out_arr);
|
||||
insert_needle(collinear_vertices, polygon, out_arr);
|
||||
// update_visibility(mid_p, polygon, out_arr);
|
||||
// update_visibility(left_p, polygon, out_arr);
|
||||
polygon.push_back(left_p);
|
||||
break;
|
||||
case INNER :
|
||||
//remove right and collinear;
|
||||
remove_edges(active_edges, curr_vision_ray);
|
||||
if (collinear_vertices.size() < 2) {
|
||||
//this means mid_p = left_p = right_p = furthest_p. no new vertex is found.
|
||||
}
|
||||
else {
|
||||
left_p = intersection_point(curr_vision_ray, active_edges[0]);
|
||||
update_visibility(right_p, polygon, out_arr);
|
||||
insert_needle(collinear_vertices, polygon, out_arr);
|
||||
// update_visibility(left_p, polygon, out_arr);
|
||||
polygon.push_back(left_p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
vit = end_it;
|
||||
}
|
||||
if (!is_init_empty) {
|
||||
CGAL::insert(out_arr, Segment_2(polygon.back(),polygon.front()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool is_attached() {
|
||||
return attach_tag;
|
||||
}
|
||||
|
||||
void attach(Arrangement_2 arr) {
|
||||
this->arr = arr;
|
||||
this->attach_tag = true;
|
||||
}
|
||||
|
||||
void detach() {
|
||||
attach_tag = false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool attach_tag;
|
||||
|
||||
// return the intersection of a ray and a segment. if the intersection is a segment, return the end closer to the source of ray.
|
||||
// if there is no intersection, return the source of ray.
|
||||
Point_2 intersection_point(Ray_2 ray, Segment_2 seg )
|
||||
{
|
||||
|
||||
CGAL::Object result = CGAL::intersection(ray, seg);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
return *ipoint;
|
||||
} else
|
||||
//if result is a segment, return the end closer to the source of ray.
|
||||
if (const Segment_2 *iseg = CGAL::object_cast<Segment_2 >(&result)) {
|
||||
switch (CGAL::compare_distance_to_point(ray.source(), iseg->source(), iseg->target())) {
|
||||
case (CGAL::SMALLER):
|
||||
return iseg->source();
|
||||
break;
|
||||
case (CGAL::LARGER) :
|
||||
return iseg->target();
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// if no intersection, return the source of ray.
|
||||
return ray.source();
|
||||
}
|
||||
}
|
||||
|
||||
Point_2 intersection_point(Ray_2 ray, Halfedge_const_handle seg) {
|
||||
return intersection_point(ray, halfedge2seg(seg));
|
||||
}
|
||||
|
||||
//convertor for halfedge to segment
|
||||
Segment_2 halfedge2seg(Halfedge_const_handle e){
|
||||
return Segment_2(e->source()->point(), e->target()->point());
|
||||
}
|
||||
|
||||
//check whether two halfedges are the same segment.
|
||||
bool is_same_edge(Halfedge_const_handle e1, Halfedge_const_handle e2) {
|
||||
|
||||
}
|
||||
|
||||
//given two edges incident to a vision ray at the same point, find which one is first seen in sweeping.
|
||||
bool is_closer(const Ray_2 &ray, Halfedge_const_handle seg1, Halfedge_const_handle seg2) {
|
||||
Point_2 shared = intersection_point(ray, seg1);
|
||||
Point_2 end1, end2;
|
||||
if (shared == seg1->source()->point())
|
||||
end1 = seg1->target()->point();
|
||||
else
|
||||
end1 = seg1->source()->point();
|
||||
|
||||
if (shared == seg2->source()->point())
|
||||
end2 = seg2->target()->point();
|
||||
else
|
||||
end2 = seg2->source()->point();
|
||||
if (CGAL::right_turn(ray.source(), shared, end1) && !CGAL::right_turn(ray.source(), shared, end2))
|
||||
return true;
|
||||
if (CGAL::right_turn(ray.source(), shared, end2) && !CGAL::right_turn(ray.source(), shared, end1))
|
||||
return false;
|
||||
switch (CGAL::orientation(ray.source(), shared, end1)) {
|
||||
case CGAL::COLLINEAR:
|
||||
return (CGAL::left_turn(ray.source(), shared, end2));
|
||||
case CGAL::RIGHT_TURN:
|
||||
return (CGAL::right_turn(end1, shared, end2));
|
||||
case CGAL::LEFT_TURN:
|
||||
return (CGAL::left_turn(end1, shared, end2));
|
||||
}
|
||||
}
|
||||
|
||||
//insert newly-discovered edges into active_edges according to its intersection with the view ray.
|
||||
void insert_halfedge(std::vector<Halfedge_const_handle> &active_edges, const Ray_2 &ray, Halfedge_const_handle edge)
|
||||
{
|
||||
Point_2 cross_of_e = intersection_point(ray, edge);
|
||||
if (cross_of_e != ray.source())
|
||||
{
|
||||
typename std::vector<Halfedge_const_handle>::iterator curr = active_edges.begin();
|
||||
while (curr != active_edges.end())
|
||||
{
|
||||
|
||||
Point_2 cross_of_curr = intersection_point(ray, *curr);
|
||||
if (CGAL::compare_distance_to_point(ray.source(), cross_of_e, cross_of_curr) == CGAL::SMALLER)
|
||||
break;
|
||||
if (cross_of_curr == cross_of_e && is_closer(ray, edge, *curr))
|
||||
break;
|
||||
++curr;
|
||||
}
|
||||
active_edges.insert(curr, edge);
|
||||
}
|
||||
}
|
||||
|
||||
//insert vh into vertices by the angle between ray<p, vh> and positive x-ray.
|
||||
//if the angles are the same, compare their distances to p.
|
||||
void sort_vertex(std::vector<Vertex_const_handle>& vertices, Vertex_const_handle vh, const Point_2& p)
|
||||
{
|
||||
typename std::vector<Vertex_const_handle>::iterator first = vertices.begin();
|
||||
Vector_2 vector_of_v(p, vh->point());
|
||||
Direction_2 dir_of_v(vector_of_v);
|
||||
while (first != vertices.end())
|
||||
{
|
||||
if (vh->point() == (*first)->point()) {
|
||||
return;
|
||||
}
|
||||
Vector_2 vector1(p, (*first)->point());
|
||||
Direction_2 d1(vector1);
|
||||
if (dir_of_v < d1)
|
||||
break;
|
||||
//if same angles are the same, put the vertex which is closer to query point before.
|
||||
if (dir_of_v == d1 && CGAL::compare_distance_to_point(p, vh->point(), (*first)->point()) == CGAL::SMALLER)
|
||||
break;
|
||||
++first;
|
||||
}
|
||||
vertices.insert(first, vh);
|
||||
}
|
||||
|
||||
|
||||
//sort vertex vh by the angle between vector<p, v> and positive x-ray.
|
||||
//if the angles are the same, place them in a 'circular' way.
|
||||
//we do this because the output is not regularized, i.e. 1-d needle is reserved in output.
|
||||
// void sort_vertex(vector<Vertex_const_handle>& vertices, Vertex_const_handle vh, const Point_2& p, CGAL::Tag_false)
|
||||
// {
|
||||
// Ray_2 ray(p, vh->point());
|
||||
// typename vector<Vertex_const_handle>::iterator first = vertices.begin();
|
||||
// while (first != vertices.end())
|
||||
// {
|
||||
// Ray_2 r(p, (*first)->point());
|
||||
// Direction_2 d1(r);
|
||||
// if (ray.direction() < d1)
|
||||
// break;
|
||||
// //if angles are the same, then using Isblock() to decide the order of vertices on the view ray.
|
||||
// if (ray.direction() == d1)
|
||||
// {
|
||||
// if (Is_block(vh, ray) && (!Is_block(*first, ray)))
|
||||
// break;
|
||||
// if (Is_block(vh, ray) && Is_block(*first, ray) && CGAL::compare_distance_to_point(p, vh->point(), (*first)->point()) == CGAL::SMALLER)
|
||||
// break;
|
||||
// if (!Is_block(vh, ray) && !Is_block(*first, ray) && CGAL::compare_distance_to_point(p, vh->point(), (*first)->point()) == CGAL::LARGER)
|
||||
// break;
|
||||
// }
|
||||
// ++first;
|
||||
// }
|
||||
// vertices.insert(first, vh);
|
||||
// }
|
||||
|
||||
//traverse the face to get all edges and sort vertices in counter-clockwise order.
|
||||
void input_face (Face_const_handle fh,
|
||||
std::vector<Vertex_const_handle>& vertices,
|
||||
std::vector<Halfedge_const_handle>& edges,
|
||||
const Point_2& p)
|
||||
{
|
||||
typename Arrangement_2::Ccb_halfedge_const_circulator curr = fh->outer_ccb();
|
||||
typename Arrangement_2::Ccb_halfedge_const_circulator circ = curr;
|
||||
do {
|
||||
sort_vertex(vertices, curr->source(), p);
|
||||
edges.push_back(curr);
|
||||
} while (++curr != circ);
|
||||
typename Arrangement_2::Hole_const_iterator hi;
|
||||
for (hi = fh->holes_begin(); hi != fh->holes_end(); ++hi) {
|
||||
typename Arrangement_2::Ccb_halfedge_const_circulator c1 = *hi, c2 = *hi;
|
||||
do {
|
||||
sort_vertex(vertices, c1->source(), p);
|
||||
edges.push_back(c1);
|
||||
} while (++c1 != c2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//insert new vertice to polygon. before insertion, check if this vertice has been added before.
|
||||
void update_visibility(const Point_2 p, std::vector<Point_2>& polygon, Arrangement_2& arr){
|
||||
if (polygon.empty())
|
||||
polygon.push_back(p);
|
||||
else
|
||||
{
|
||||
if (polygon.back() != p){
|
||||
CGAL::insert(arr, Segment_2(polygon.back(), p));
|
||||
polygon.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void insert_needle(const std::vector<Point_2>& points, std::vector<Point_2>& polygon, Arrangement_2 &arr){
|
||||
if (points.size() > 1) {
|
||||
for (int i = 0; i != points.size()-1; i++) {
|
||||
CGAL::insert(arr, Segment_2(points[i], points[i+1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//add a new edge when vision ray passes a vertex
|
||||
void add_edge(Vertex_const_handle vh,
|
||||
std::vector<Halfedge_const_handle>& edges,
|
||||
const Ray_2& r) {
|
||||
typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr;
|
||||
first = curr = vh->incident_halfedges();
|
||||
do {
|
||||
if (!CGAL::right_turn(r.source(), vh->point(), curr->source()->point()))
|
||||
{
|
||||
insert_halfedge(edges, r, curr);
|
||||
}
|
||||
} while (++curr != first);
|
||||
|
||||
}
|
||||
//add new edges
|
||||
void add_edges(typename std::vector<Vertex_const_handle>::iterator begin_it,
|
||||
typename std::vector<Vertex_const_handle>::iterator end_it,
|
||||
std::vector<Halfedge_const_handle>& edges,
|
||||
const Ray_2& r)
|
||||
{
|
||||
do {
|
||||
add_edge(*begin_it, edges, r);
|
||||
} while (++begin_it != end_it);
|
||||
|
||||
}
|
||||
|
||||
//remove edges that are not active any longer
|
||||
void remove_edges(std::vector<Halfedge_const_handle>& edges, const Ray_2& r) {
|
||||
typename std::vector<Halfedge_const_handle>::iterator eit = edges.begin();
|
||||
while (eit != edges.end()) {
|
||||
Point_2 p1 = (*eit)->target()->point();
|
||||
Point_2 p2 = (*eit)->source()->point();
|
||||
bool is_incident(false);
|
||||
if (is_on_ray(r, p1)) {
|
||||
is_incident = true;
|
||||
}
|
||||
else if (is_on_ray(r, p2)) {
|
||||
Point_2 tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = p1;
|
||||
is_incident = true;
|
||||
}
|
||||
|
||||
|
||||
if ( is_incident && !CGAL::left_turn(r.source(), p1, p2))
|
||||
{
|
||||
eit = edges.erase(eit);
|
||||
}
|
||||
else {
|
||||
eit++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool is_on_ray(const Ray_2& r, const Point_2& p) {
|
||||
return Direction_2(Vector_2(r.source(), p)) == Direction_2(r);
|
||||
}
|
||||
//return the type of the needle.
|
||||
//the vertices on the needle will be saved in collinear_vertices.
|
||||
Intersection_type needle(std::vector<Halfedge_const_handle>& edges, Ray_2& r, std::vector<Point_2>& collinear_vertices) {
|
||||
typename std::vector<Halfedge_const_handle>::iterator curr = edges.begin();
|
||||
// Point_2 p = r.source(), end1, end2;
|
||||
Vertex_const_handle vertex1;
|
||||
//flag shows whether the left side or right side of needle is blocked.
|
||||
bool block_left, block_right;
|
||||
do {
|
||||
Point_2 cross = intersection_point(r, *curr);
|
||||
if (cross != (*curr)->source()->point() && cross != (*curr)->target()->point()) {
|
||||
collinear_vertices.push_back(cross);
|
||||
return INNER;
|
||||
}
|
||||
if (CGAL::orientation(r.source(), (*curr)->source()->point(), (*curr)->target()->point()) == CGAL::COLLINEAR) {
|
||||
vertex1 = (*curr)->target();
|
||||
}
|
||||
else {
|
||||
if (cross == (*curr)->source()->point()) {
|
||||
vertex1 = (*curr)->source();
|
||||
}
|
||||
else {
|
||||
vertex1 = (*curr)->target();
|
||||
}
|
||||
}
|
||||
if (collinear_vertices.empty() || vertex1->point() != collinear_vertices.back()) {
|
||||
collinear_vertices.push_back(vertex1->point());
|
||||
//flag shows whether the left side or right side of current vertex is blocked.
|
||||
//has_predecessor indicates whether this vertex is incident to an edge whose another end is between the source of ray and it,
|
||||
//because that will effect the value of block_left, block_right.
|
||||
bool left_v(false), right_v(false), has_predecessor(false);
|
||||
|
||||
typename Arrangement_2::Halfedge_around_vertex_const_circulator first_edge, curr_edge;
|
||||
first_edge = curr_edge = vertex1->incident_halfedges();
|
||||
do {
|
||||
switch (CGAL::orientation(r.source(), curr_edge->target()->point(), curr_edge->source()->point())) {
|
||||
case CGAL::RIGHT_TURN :
|
||||
right_v = true;
|
||||
break;
|
||||
case CGAL::LEFT_TURN :
|
||||
left_v = true;
|
||||
break;
|
||||
case CGAL::COLLINEAR :
|
||||
if (CGAL::compare_distance_to_point(r.source(), curr_edge->target()->point(), curr_edge->source()->point()) == CGAL::LARGER) {
|
||||
has_predecessor = true;
|
||||
}
|
||||
}
|
||||
|
||||
} while (++curr_edge != first_edge);
|
||||
if (has_predecessor) {
|
||||
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) {
|
||||
return CORNER;
|
||||
}
|
||||
}
|
||||
} while (++curr != edges.end());
|
||||
return UNBOUNDED;
|
||||
}
|
||||
//debug
|
||||
void print_edges(std::vector<Halfedge_const_handle>& edges){
|
||||
for (int i = 0; i != edges.size(); i++) {
|
||||
Point_2 p1, p2;
|
||||
p1 = edges[i]->source()->point();
|
||||
p2 = edges[i]->target()->point();
|
||||
std::cout<<p1<<"->"<<p2<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//angular sweep a vertice of face.
|
||||
void sweep_vertex(std::vector<Halfedge_const_handle> &active_edges, const Point_2 &query, Vertex_const_handle vh, std::vector<Point_2> &polygon )
|
||||
{
|
||||
//closest_edge_copy is a copy of the closest edge to query point in active_edges before sweeping.
|
||||
Halfedge_const_handle closest_edge_copy = active_edges[0];
|
||||
Ray_2 ray(query, vh->point());
|
||||
int add_count(0);
|
||||
int del_count(0);
|
||||
|
||||
//delete all edges in active_edges which is incident to v, because they has been sweeped over
|
||||
typename std::vector<Halfedge_const_handle>::iterator edge_iter = active_edges.begin();
|
||||
while (edge_iter != active_edges.end()) {
|
||||
if (((*edge_iter)->source()->point() == vh->point()) || ((*edge_iter)->target()->point() == vh->point()))
|
||||
{
|
||||
edge_iter = active_edges.erase(edge_iter);
|
||||
++del_count;
|
||||
}
|
||||
else {
|
||||
++edge_iter;
|
||||
}
|
||||
}
|
||||
|
||||
//add all edges which is incident to v but not in active_edges before to active_edges
|
||||
typename Arrangement_2::Halfedge_around_vertex_const_circulator first, curr;
|
||||
first = curr = vh->incident_halfedges();
|
||||
do {
|
||||
if (CGAL::left_turn(query, vh->point(), curr->source()->point()))
|
||||
{
|
||||
insert_halfedge(active_edges, ray, curr);
|
||||
++add_count;
|
||||
}
|
||||
else if (CGAL::collinear(query, vh->point(), curr->source()->point()) &&
|
||||
CGAL::compare_distance_to_point(query, vh->point(), curr->source()->point()) == CGAL::SMALLER)
|
||||
{
|
||||
insert_halfedge(active_edges, ray, curr);
|
||||
++add_count;
|
||||
}
|
||||
} while (++curr != first);
|
||||
|
||||
//update the visibility region
|
||||
if (closest_edge_copy != active_edges[0]) {
|
||||
//when the closest edge changed
|
||||
if (del_count > 0 && add_count > 0) {
|
||||
//some edges are added and some are deleted, which means the vertice sweeped is a vertice of visibility polygon.
|
||||
update_visibility(vh->point(), polygon);
|
||||
}
|
||||
if (del_count == 0 && add_count > 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 sweeped.
|
||||
update_visibility(intersection_point(ray, halfedge2seg(closest_edge_copy)), polygon);
|
||||
update_visibility(vh->point(), polygon);
|
||||
}
|
||||
if (del_count > 0 && add_count == 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(), polygon);
|
||||
update_visibility(intersection_point(ray, halfedge2seg(active_edges[0])), polygon);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//For debug. Print all edges of arrangements into console.
|
||||
template <typename Arrangement_2>
|
||||
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)
|
||||
std::cout << "[" << eit->curve() << "]" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Visibility_2
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// 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 <huangkandiy@gmail.com>
|
||||
//
|
||||
|
||||
#ifndef CGAL_PREPROCESSED_VISIBILITY_2_H
|
||||
#define CGAL_PREPROCESSED_VISIBILITY_2_H
|
||||
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Arr_linear_traits_2.h>
|
||||
#include <stack>
|
||||
#include <deque>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Visibility_2 {
|
||||
|
||||
template<class Arrangement_2>
|
||||
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<Kernel> 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<Linear_traits_2> Line_Arrangement_2;
|
||||
|
||||
Preprocessed_visibility_2() : p_arr(NULL) {};
|
||||
|
||||
/*! Constructor given an arrangement and the Regularization tag. */
|
||||
Preprocessed_visibility_2(const Input_Arrangement_2 &arr/*, Regularization_tag r_t*/): p_arr(&arr) {};
|
||||
|
||||
bool is_attached() {
|
||||
return (p_arr != NULL);
|
||||
}
|
||||
|
||||
void attach(const Input_Arrangement_2 &arr) {
|
||||
p_arr = &arr;
|
||||
}
|
||||
|
||||
void detach() {
|
||||
p_arr = NULL;
|
||||
}
|
||||
|
||||
Input_Arrangement_2 arr() {
|
||||
return *p_arr;
|
||||
}
|
||||
|
||||
void visibility_region(Point_2 &q,
|
||||
const Face_const_handle face,
|
||||
Output_Arrangement_2 &out_arr
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
void visibility_region(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 Visibility_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
// 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 <fbungiu@gmail.com>
|
||||
// Michael Hemmer <michael.hemmer@cgal.org>
|
||||
|
||||
#ifndef CGAL_SIMPLE_VISIBILITY_2_H
|
||||
#define CGAL_SIMPLE_VISIBILITY_2_H
|
||||
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <stack>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Visibility_2 {
|
||||
|
||||
template<class Arrangement_2, class Regularization_tag>
|
||||
class Simple_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 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;
|
||||
|
||||
Simple_visibility_2() : p_arr(NULL), geom_traits(NULL) {};
|
||||
|
||||
/*! Constructor given an arrangement and the Regularization tag. */
|
||||
Simple_visibility_2(const Input_Arrangement_2 &arr):
|
||||
p_arr(&arr) {
|
||||
geom_traits = p_arr->geometry_traits();
|
||||
};
|
||||
|
||||
bool is_attached() {
|
||||
return (p_arr != NULL);
|
||||
}
|
||||
|
||||
void attach(const Input_Arrangement_2 &arr) {
|
||||
p_arr = &arr;
|
||||
geom_traits = p_arr->geometry_traits();
|
||||
}
|
||||
|
||||
void detach() {
|
||||
p_arr = NULL;
|
||||
geom_traits = NULL;
|
||||
}
|
||||
|
||||
Input_Arrangement_2 arr() {
|
||||
return *p_arr;
|
||||
}
|
||||
|
||||
void visibility_region(Point_2 &q, const Face_const_handle face,
|
||||
Output_Arrangement_2 &out_arr) {
|
||||
|
||||
typename Input_Arrangement_2::Ccb_halfedge_const_circulator circ =
|
||||
face->outer_ccb();
|
||||
typename Input_Arrangement_2::Ccb_halfedge_const_circulator curr = circ;
|
||||
typename Input_Arrangement_2::Halfedge_const_handle he = curr;
|
||||
|
||||
std::vector<Point_2> temp_vertices;
|
||||
Point_2 min_intersect_pt;
|
||||
bool intersect_on_endpoint = false;
|
||||
|
||||
Segment_2 curr_edge(he->source()->point(), he->target()->point());
|
||||
Segment_2 curr_min_edge(he->source()->point(), he->target()->point());
|
||||
Point_2 curr_vertex = he->target()->point();
|
||||
min_intersect_pt =
|
||||
Construct_projected_point_2(curr_min_edge.supporting_line(), q);
|
||||
|
||||
temp_vertices.push_back(curr_vertex);
|
||||
Number_type min_dist = Compute_squared_distance_2(q, curr_edge);
|
||||
|
||||
int min_dist_index = 0;
|
||||
int index = 1;
|
||||
|
||||
curr++;
|
||||
// Push all vertices and determine edge minimum in terms
|
||||
// of squared distance to query point
|
||||
do {
|
||||
he = curr;
|
||||
curr_edge = Segment_2(he->source()->point(), he->target()->point());
|
||||
Number_type curr_dist = Compute_squared_distance_2(q, curr_edge);
|
||||
|
||||
if (curr_dist < min_dist) {
|
||||
min_dist = curr_dist;
|
||||
min_dist_index = index;
|
||||
curr_min_edge = curr_edge;
|
||||
}
|
||||
temp_vertices.push_back(he->target()->point());
|
||||
index++;
|
||||
} while (++curr != circ);
|
||||
|
||||
// Only now compute the intersection point
|
||||
min_intersect_pt =
|
||||
Construct_projected_point_2(curr_min_edge.supporting_line(), q);
|
||||
|
||||
if (min_intersect_pt != curr_min_edge.source() &&
|
||||
min_intersect_pt != curr_min_edge.target()) {
|
||||
vertices.push_back(min_intersect_pt);
|
||||
}
|
||||
|
||||
// Now create vector so that first vertex v0 is visible
|
||||
for (unsigned int k = min_dist_index ; k < temp_vertices.size() ; k++) {
|
||||
vertices.push_back(temp_vertices[k]);
|
||||
}
|
||||
for (unsigned int k = 0 ; k < min_dist_index ; k++) {
|
||||
vertices.push_back(temp_vertices[k]);
|
||||
}
|
||||
|
||||
// Push first vertex again to fulfill algo precondition
|
||||
if (min_intersect_pt != curr_min_edge.source() &&
|
||||
min_intersect_pt != curr_min_edge.target()) {
|
||||
vertices.push_back(min_intersect_pt);
|
||||
}
|
||||
else {
|
||||
vertices.push_back(vertices[0]);
|
||||
}
|
||||
|
||||
visibility_region_impl(q);
|
||||
|
||||
typename std::vector<Point_2> points;
|
||||
if (!s.empty()) {
|
||||
Point_2 prev_pt = s.top();
|
||||
if (prev_pt == min_intersect_pt) {
|
||||
s.pop();
|
||||
if (!s.empty()) {
|
||||
prev_pt = s.top();
|
||||
points.push_back(prev_pt);
|
||||
}
|
||||
}
|
||||
if (!s.empty()) {
|
||||
s.pop();
|
||||
}
|
||||
while(!s.empty()) {
|
||||
Point_2 curr_pt = s.top();
|
||||
if (curr_pt == min_intersect_pt) {
|
||||
s.pop();
|
||||
}
|
||||
else {
|
||||
points.push_back(curr_pt);
|
||||
prev_pt = curr_pt;
|
||||
s.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::reverse(points.begin(), points.end());
|
||||
std::vector<Segment_2> segments;
|
||||
treat_needles(q, points, segments);
|
||||
CGAL::insert_non_intersecting_curves(out_arr,
|
||||
segments.begin(),
|
||||
segments.end());
|
||||
}
|
||||
|
||||
void visibility_region(const Point_2 &q, const Halfedge_const_handle he,
|
||||
Output_Arrangement_2 &out_arr ) {
|
||||
|
||||
if (q != he->source()->point()) {
|
||||
if (q != he->target()->point()) {
|
||||
s.push(q);
|
||||
vertices.push_back(he->target()->point());
|
||||
}
|
||||
else {
|
||||
vertices.push_back(q);
|
||||
}
|
||||
}
|
||||
else {
|
||||
vertices.push_back(q);
|
||||
vertices.push_back(he->target()->point());
|
||||
}
|
||||
|
||||
typename Input_Arrangement_2::Face_const_handle face = he->face();
|
||||
typename Input_Arrangement_2::Ccb_halfedge_const_circulator circ =
|
||||
face->outer_ccb();
|
||||
typename Input_Arrangement_2::Ccb_halfedge_const_circulator curr;
|
||||
typename Input_Arrangement_2::Halfedge_const_handle he_handle = circ;
|
||||
|
||||
while (he_handle != he) {
|
||||
he_handle = circ;
|
||||
circ++;
|
||||
}
|
||||
|
||||
curr = circ;
|
||||
curr++;
|
||||
|
||||
he_handle = curr;
|
||||
vertices.push_back(Point_2(he_handle->source()->point()));
|
||||
|
||||
while (curr != circ) {
|
||||
he_handle = curr;
|
||||
Point_2 curr_vertex = he_handle->target()->point();
|
||||
vertices.push_back(curr_vertex);
|
||||
curr++;
|
||||
}
|
||||
vertices.push_back(q);
|
||||
|
||||
visibility_region_impl(q);
|
||||
|
||||
typename std::vector<Point_2> points;
|
||||
if (!s.empty()) {
|
||||
Point_2 prev_pt = s.top();
|
||||
if (prev_pt != q) {
|
||||
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);
|
||||
}
|
||||
s.pop();
|
||||
}
|
||||
}
|
||||
|
||||
std::reverse(points.begin(), points.end());
|
||||
std::vector<Segment_2> segments;
|
||||
treat_needles(q, points, segments);
|
||||
CGAL::insert_non_intersecting_curves(out_arr, segments.begin(), segments.end());
|
||||
}
|
||||
|
||||
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)
|
||||
std::cout << "[" << eit->curve() << "]" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
const Input_Arrangement_2 *p_arr;
|
||||
const Geometry_traits_2 *geom_traits;
|
||||
std::stack<Point_2> s;
|
||||
std::vector<Point_2> vertices;
|
||||
enum {LEFT, RIGHT, SCANA, SCANB, SCANC, SCAND, FINISH} upcase;
|
||||
|
||||
typedef Arr_traits_basic_adaptor_2<Geometry_traits_2> Traits_adaptor_2;
|
||||
|
||||
bool LessDistanceToPoint_2(const Point_2 &p, const Point_2 &q,
|
||||
const Point_2 &r) const {
|
||||
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);
|
||||
}
|
||||
|
||||
bool Collinear(const Point_2 &p, const Point_2 &q,
|
||||
const Point_2 &r) const {
|
||||
typename Geometry_traits_2::Collinear_2 collinear_fnct =
|
||||
geom_traits->collinear_2_object();
|
||||
return collinear_fnct(p, q, r);
|
||||
}
|
||||
|
||||
template < class _Curve_first, class _Curve_second >
|
||||
Object_2 Intersect_2(const _Curve_first &s1, const _Curve_second &s2) {
|
||||
typedef typename Geometry_traits_2::Kernel Kernel;
|
||||
const Kernel *kernel = static_cast<const Kernel*> (geom_traits);
|
||||
typename Kernel::Intersect_2 intersect_fnct =
|
||||
kernel->intersect_2_object();
|
||||
return intersect_fnct(s1, s2);
|
||||
}
|
||||
|
||||
Orientation Orientation_2(const Point_2 &p, const Point_2 &q,
|
||||
const Point_2 &r) {
|
||||
typename Geometry_traits_2::Orientation_2 orient =
|
||||
geom_traits->orientation_2_object();
|
||||
return orient(p, q, r);
|
||||
}
|
||||
|
||||
Point_2 Construct_projected_point_2(const Line_2 &l, const Point_2 &p) {
|
||||
typename Geometry_traits_2::Construct_projected_point_2 construct_proj =
|
||||
geom_traits->construct_projected_point_2_object();
|
||||
return construct_proj(l, p);
|
||||
}
|
||||
|
||||
Number_type Compute_squared_distance_2(const Point_2 &p,
|
||||
const Segment_2 &seg) {
|
||||
typename Geometry_traits_2::Compute_squared_distance_2 compute_dist =
|
||||
geom_traits->compute_squared_distance_2_object();
|
||||
return compute_dist(p, seg);
|
||||
}
|
||||
|
||||
bool do_overlap(const Point_2 &a, const Point_2 &b, const Point_2 &c) {
|
||||
if (collinear(a, b, c)) {
|
||||
Segment_2 s1(a, b);
|
||||
Segment_2 s2(a, c);
|
||||
const Segment_2 *seg_overlap;
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
if (seg_overlap = CGAL::object_cast<Segment_2>(&result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void treat_needles(const Point_2 &q, typename std::vector<Point_2> &points,
|
||||
typename std::vector<Segment_2> &segments) {
|
||||
|
||||
typename std::vector<Point_2>::size_type i = 0;
|
||||
|
||||
while (CGAL::collinear(points[i], points[points.size()-1],
|
||||
points[points.size()-2]) ||
|
||||
CGAL::collinear(points[i], points[i+1], points[points.size()-1])) {
|
||||
|
||||
points.push_back(points[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
points.push_back(points[i]);
|
||||
|
||||
std::vector<Point_2> forward_needle;
|
||||
std::vector<Point_2> backward_needle;
|
||||
|
||||
while (i+1 < points.size()) {
|
||||
if ((i+2 < points.size()) &&
|
||||
(Orientation_2(points[i],
|
||||
points[i+1],
|
||||
points[i+2]) == CGAL::COLLINEAR)) {
|
||||
|
||||
Point_2 needle_start = points[i];
|
||||
Direction_2 forward_dir(Segment_2(points[i], points[i+1]));
|
||||
forward_needle.push_back(points[i]);
|
||||
forward_needle.push_back(points[i+1]);
|
||||
|
||||
while ((i+2 < points.size()) &&
|
||||
(Orientation_2(points[i],
|
||||
points[i+1],
|
||||
points[i+2]) == CGAL::COLLINEAR)) {
|
||||
|
||||
Direction_2 check_dir(Segment_2(points[i+1], points[i+2]));
|
||||
if (forward_dir == check_dir) {
|
||||
forward_needle.push_back(points[i+2]);
|
||||
}
|
||||
else if (check_dir == -forward_dir) {
|
||||
backward_needle.push_back(points[i+2]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
std::reverse(backward_needle.begin(), backward_needle.end());
|
||||
|
||||
std::vector<Point_2> merged_needle;
|
||||
|
||||
// Now merge the two vectors
|
||||
unsigned int itr_fst = 0, itr_snd = 0;
|
||||
while (itr_fst < forward_needle.size() &&
|
||||
itr_snd < backward_needle.size()) {
|
||||
|
||||
if (LessDistanceToPoint_2(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++) {
|
||||
segments.push_back(Segment_2(merged_needle[p], merged_needle[p+1]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
segments.push_back(Segment_2(points[i], points[i+1]));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void visibility_region_impl(const Point_2 &q) {
|
||||
|
||||
int i = 0;
|
||||
Point_2 w;
|
||||
|
||||
if (Orientation_2(q, vertices[0], vertices[1]) == CGAL::LEFT_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]);
|
||||
}
|
||||
|
||||
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) {
|
||||
// Check if (s_t-1, s_t) intersects (q, vn)
|
||||
Point_2 s_t = s.top();
|
||||
s.pop();
|
||||
Point_2 s_t_prev = s.top();
|
||||
Segment_2 s1(s_t_prev, s_t);
|
||||
Segment_2 s2(q, vertices[vertices.size()-1]);
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
Segment_2 s3(s_t_prev, vertices[i]);
|
||||
Object_2 result2 = Intersect_2<Segment_2, Segment_2>(s3, s2);
|
||||
if (const Point_2 *vertex_new = CGAL::object_cast<Point_2>(&result2)){
|
||||
if ((*vertex_new) != (s_t_prev) && (*vertex_new != s_t)) {
|
||||
upcase = SCANB;
|
||||
s.push(*vertex_new);
|
||||
}
|
||||
else { // Do not alter stack if it doesn't intersect - push back s_t
|
||||
s.push(s_t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.push(s_t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.push(s_t);
|
||||
}
|
||||
}
|
||||
} while(upcase != FINISH);
|
||||
}
|
||||
|
||||
void left(int &i, Point_2 &w, const Point_2 &query_pt) {
|
||||
if (i == vertices.size() - 1) {
|
||||
upcase = FINISH;
|
||||
}
|
||||
else if (Orientation_2(query_pt,
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::LEFT_TURN) {
|
||||
upcase = LEFT;
|
||||
s.push(vertices[i+1]);
|
||||
w = vertices[i+1];
|
||||
i++;
|
||||
}
|
||||
else if (Orientation_2(query_pt,
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::RIGHT_TURN) {
|
||||
Point_2 s_t = s.top();
|
||||
s.pop();
|
||||
Point_2 s_t_prev = s.top();
|
||||
s.pop();
|
||||
if (Orientation_2(s_t_prev,
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::RIGHT_TURN) {
|
||||
upcase = SCANA;
|
||||
w = vertices[i+1];
|
||||
i++;
|
||||
} // Both conditions have to be met to move on. Thus same else branch as below
|
||||
else {
|
||||
upcase = RIGHT;
|
||||
w = vertices[i];
|
||||
i++;
|
||||
}
|
||||
s.push(s_t_prev);
|
||||
s.push(s_t);
|
||||
}
|
||||
else {
|
||||
upcase = RIGHT;
|
||||
i++;
|
||||
w = vertices[i];
|
||||
}
|
||||
}
|
||||
|
||||
void right(int &i, Point_2 &w, const Point_2 &query_pt) {
|
||||
// Scan s_t, s_t-1, ..., s_1, s_0 for the first edge (s_j, s_j-1) such that
|
||||
// (a) (z, s_j, v_i) is a right turn and (z, s_j-1, v_i) is a left turn, or
|
||||
// (b) (z, s_j-1, s_j) is a forward move and (v_i-1, v_i) intersects (s_j-1, s_j)
|
||||
bool found = false;
|
||||
while(!found && !s.empty()) {
|
||||
Point_2 s_j = s.top();
|
||||
s.pop();
|
||||
if (!s.empty()) {
|
||||
Point_2 s_j_prev = s.top();
|
||||
// Check condition (a)
|
||||
if ((Orientation_2(query_pt,
|
||||
s_j,
|
||||
vertices[i]) == CGAL::RIGHT_TURN) &&
|
||||
(Orientation_2(query_pt,
|
||||
s_j_prev,
|
||||
vertices[i]) == CGAL::LEFT_TURN)) {
|
||||
found = true;
|
||||
Segment_2 s1(s_j_prev, s_j);
|
||||
Ray_2 s2(query_pt, vertices[i]);
|
||||
Object_2 result = Intersect_2<Segment_2, Ray_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
s_j = *ipoint;
|
||||
}
|
||||
|
||||
if (Orientation_2(query_pt,
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::RIGHT_TURN) {
|
||||
upcase = RIGHT;
|
||||
s.push(s_j);
|
||||
w = vertices[i];
|
||||
i++;
|
||||
}
|
||||
else if ((Orientation_2(query_pt,
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::LEFT_TURN) &&
|
||||
(Orientation_2(vertices[i-1],
|
||||
vertices[i],
|
||||
vertices[i+1]) == CGAL::RIGHT_TURN)) {
|
||||
upcase = LEFT;
|
||||
s.push(s_j);
|
||||
s.push(vertices[i]);
|
||||
s.push(vertices[i+1]);
|
||||
w = vertices[i+1];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
upcase = SCANC;
|
||||
s.push(s_j);
|
||||
w = vertices[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (do_overlap(query_pt, s_j_prev, s_j)) { // Case (b)
|
||||
// Check if v_i-1, v_i intersects (s_j-1, s_j)
|
||||
Segment_2 s1(s_j_prev, s_j);
|
||||
Segment_2 s2(vertices[i-1], vertices[i]);
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
// Keep s_j off the stack
|
||||
found = true;
|
||||
upcase = SCAND;
|
||||
w = *ipoint;
|
||||
}
|
||||
}
|
||||
else if ((Orientation_2(query_pt,
|
||||
s_j,
|
||||
vertices[i]) == CGAL::RIGHT_TURN) &&
|
||||
(Orientation_2(query_pt,
|
||||
s_j_prev,
|
||||
vertices[i]) == CGAL::COLLINEAR)) {
|
||||
found = true;
|
||||
upcase = LEFT;
|
||||
s.push(vertices[i]);
|
||||
s.push(vertices[i+1]);
|
||||
w = vertices[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
bool found = false;
|
||||
int k = i;
|
||||
Point_2 intersection_pt;
|
||||
while (k+1 < vertices.size()) {
|
||||
Segment_2 s1(vertices[k], vertices[k+1]);
|
||||
Ray_2 s2(query_pt, s.top());
|
||||
Object_2 result = Intersect_2<Segment_2, Ray_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
found = true;
|
||||
intersection_pt = *ipoint;
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
if (found) {
|
||||
if ((Orientation_2(query_pt,
|
||||
vertices[k],
|
||||
vertices[k+1]) == CGAL::RIGHT_TURN) &&
|
||||
(!do_overlap(query_pt, s.top(), intersection_pt))) {
|
||||
|
||||
upcase = RIGHT;
|
||||
i = k+1;
|
||||
w = intersection_pt;
|
||||
}
|
||||
else if ((Orientation_2(query_pt,
|
||||
vertices[k],
|
||||
vertices[k+1]) == CGAL::RIGHT_TURN) &&
|
||||
(do_overlap(query_pt, s.top(), intersection_pt))) {
|
||||
|
||||
upcase = SCAND;
|
||||
i = k+1;
|
||||
w = intersection_pt;
|
||||
}
|
||||
else if ((Orientation_2(query_pt,
|
||||
vertices[k],
|
||||
vertices[k+1]) == CGAL::LEFT_TURN) &&
|
||||
(do_overlap(query_pt, s.top(), intersection_pt))) {
|
||||
|
||||
upcase = LEFT;
|
||||
i = k+1;
|
||||
s.push(intersection_pt);
|
||||
if (intersection_pt != vertices[k+1]) {
|
||||
s.push(vertices[k+1]);
|
||||
}
|
||||
w = vertices[k+1];
|
||||
}
|
||||
else {
|
||||
// This case never occurs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scanb(int &i, Point_2 &w, const Point_2 &query_pt) {
|
||||
// Scan v_i, v_i+1, ..., v_n-1, v_n for the first edge to intersect (s_t, v_n]
|
||||
Point_2 s_t = s.top();
|
||||
int k = i;
|
||||
bool found = false;
|
||||
Point_2 intersection_pt;
|
||||
while (k+1 < vertices.size()) {
|
||||
Segment_2 s1(vertices[k], vertices[k+1]);
|
||||
Segment_2 s2(s_t, vertices[vertices.size()-1]);
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
if (*ipoint != s_t) {
|
||||
intersection_pt = *ipoint;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
if (found) {
|
||||
if ((intersection_pt == vertices[k+1]) &&
|
||||
(intersection_pt == vertices[vertices.size()-1])) {
|
||||
|
||||
upcase = FINISH;
|
||||
w = vertices[vertices.size()-1];
|
||||
s.push(vertices[vertices.size()-1]);
|
||||
}
|
||||
else {
|
||||
upcase = RIGHT;
|
||||
i = k+1;
|
||||
w = intersection_pt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
upcase = LEFT;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void scanc(int &i,Point_2 &w, const Point_2 &query_pt) {
|
||||
// Scan v_i, v_i+1, ..., v_n-1, v_n for the first edge to intersect (s_t, w)
|
||||
Point_2 s_t = s.top();
|
||||
int k = i;
|
||||
bool found = false;
|
||||
Point_2 intersection_pt;
|
||||
while (k+1 < vertices.size()) {
|
||||
Segment_2 s1(vertices[k], vertices[k+1]);
|
||||
Segment_2 s2(s_t, w);
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
found = true;
|
||||
intersection_pt = *ipoint;
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
if (found) {
|
||||
upcase = RIGHT;
|
||||
i = k+1;
|
||||
w = intersection_pt;
|
||||
}
|
||||
}
|
||||
|
||||
void scand(int &i, Point_2 &w, const Point_2 &query_pt) {
|
||||
// Scan v_i, v_i+1, v_n-1, v_n for the fist edge to intersect (s_t, w)
|
||||
Point_2 s_t = s.top();
|
||||
int k = i;
|
||||
bool found = false;
|
||||
Point_2 intersection_pt;
|
||||
while (k+1 < vertices.size()) {
|
||||
Segment_2 s1(vertices[k], vertices[k+1]);
|
||||
Segment_2 s2(s_t, w);
|
||||
Object_2 result = Intersect_2<Segment_2, Segment_2>(s1, s2);
|
||||
if (const Point_2 *ipoint = CGAL::object_cast<Point_2>(&result)) {
|
||||
found = true;
|
||||
intersection_pt = *ipoint;
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
if (found) {
|
||||
upcase = LEFT;
|
||||
i = k+1;
|
||||
s.push(intersection_pt);
|
||||
s.push(vertices[k+1]);
|
||||
w = vertices[k+1];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Visibility_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
4
|
||||
0 0
|
||||
8 0
|
||||
8 8
|
||||
0 8
|
||||
4
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
3 0
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
4
|
||||
0 0
|
||||
4 4
|
||||
32/5 24/5
|
||||
0 8
|
||||
4
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
3 0
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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 <fbungiu@gmail.com>
|
||||
// Michael Hemmer <michael.hemmer@cgal.org>
|
||||
|
||||
#ifndef CGAL_TEST_MODEL_METHODS_H
|
||||
#define CGAL_TEST_MODEL_METHODS_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <class _Visibility_2>
|
||||
bool test_is_attached(_Visibility_2 visibility) {
|
||||
return visibility.is_attached();
|
||||
}
|
||||
|
||||
} // end CGAL namespace
|
||||
#endif
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// 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 <fbungiu@gmail.com>
|
||||
// Michael Hemmer <michael.hemmer@cgal.org>
|
||||
|
||||
#ifndef CGAL_TEST_SIMPLE_POLYGONS_H
|
||||
#define CGAL_TEST_SIMPLE_POLYGONS_H
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_face_test_case(std::ifstream &input, std::ifstream &correct_output) {
|
||||
|
||||
typedef _Visibility_2 Visibility_2;
|
||||
typedef _Arrangement_2 Arrangement_2;
|
||||
typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2;
|
||||
typedef typename Geometry_traits_2::Point_2 Point_2;
|
||||
|
||||
Visibility_2 visibility;
|
||||
|
||||
// First read arrangement
|
||||
Arrangement_2 arr, out_arr, correct_out_arr;
|
||||
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr, input);
|
||||
|
||||
// Read query point from file
|
||||
double x, y;
|
||||
input >> x >> y;
|
||||
Point_2 query_pt(x, y);
|
||||
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(correct_out_arr, correct_output);
|
||||
|
||||
typename Arrangement_2::Face_const_iterator fit;
|
||||
|
||||
for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) {
|
||||
if (!fit->is_unbounded()) {
|
||||
visibility.visibility_region(query_pt, fit, out_arr);
|
||||
}
|
||||
}
|
||||
|
||||
return CGAL::test_are_equal<Arrangement_2>(correct_out_arr, out_arr);
|
||||
}
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_halfedge_test_case(std::ifstream &input, std::ifstream &correct_output) {
|
||||
|
||||
typedef _Visibility_2 Visibility_2;
|
||||
typedef _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::Segment_2 Segment_2;
|
||||
|
||||
Visibility_2 visibility;
|
||||
|
||||
// First read arrangement
|
||||
Arrangement_2 arr, out_arr, correct_out_arr;
|
||||
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr, input);
|
||||
|
||||
// Read query point from file
|
||||
double x, y;
|
||||
input >> x >> y;
|
||||
Point_2 query_pt(x, y);
|
||||
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(correct_out_arr, correct_output);
|
||||
|
||||
typename Arrangement_2::Halfedge_const_iterator hit;
|
||||
|
||||
for (hit = arr.halfedges_begin(); hit != arr.halfedges_end(); ++hit) {
|
||||
Segment_2 curr_seg(hit->source()->point(), hit->target()->point());
|
||||
if (curr_seg.has_on(query_pt)) {
|
||||
visibility.visibility_region(query_pt, hit, out_arr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CGAL::test_are_equal<Arrangement_2>(correct_out_arr, out_arr);
|
||||
}
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_test_case_1() {
|
||||
|
||||
std::ifstream input("./data/simple_polygon_test_case_1.in");
|
||||
std::ifstream correct_output("./data/simple_polygon_test_case_1.out");
|
||||
return simple_polygon_face_test_case<_Visibility_2, _Arrangement_2>(input, correct_output);
|
||||
}
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_test_case_2() {
|
||||
|
||||
std::ifstream input("./data/simple_polygon_test_case_2.in");
|
||||
std::ifstream correct_output("./data/simple_polygon_test_case_2.out");
|
||||
return simple_polygon_face_test_case<_Visibility_2, _Arrangement_2>(input, correct_output);
|
||||
}
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_test_case_3() {
|
||||
std::ifstream input("./data/simple_polygon_test_case_3.in");
|
||||
std::ifstream correct_output("./data/simple_polygon_test_case_3.out");
|
||||
return simple_polygon_face_test_case<_Visibility_2, _Arrangement_2>(input, correct_output);
|
||||
}
|
||||
|
||||
template < class _Visibility_2, class _Arrangement_2 >
|
||||
bool simple_polygon_test_case_4() {
|
||||
std::ifstream input("./data/simple_polygon_test_case_4.in");
|
||||
std::ifstream correct_output("./data/simple_polygon_test_case_4.out");
|
||||
return simple_polygon_halfedge_test_case<_Visibility_2, _Arrangement_2>(input, correct_output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Author: Francisc Bungiu, Kan Huang
|
||||
* E-mail: fbungiu@gmail.com, huangkandiy@gmail.com
|
||||
* Description: This file contains useful functions for testing the
|
||||
* Visibility_2 package, such as comparing two Arrangements
|
||||
*/
|
||||
|
||||
#ifndef CGAL_TEST_UTILS_H
|
||||
#define CGAL_TEST_UTILS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <CGAL/Gmpq.h>
|
||||
#include <set>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <class Arrangement_2>
|
||||
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 <class _Arrangement_2>
|
||||
bool test_are_equal(const _Arrangement_2 &arr1, const _Arrangement_2 &arr2) {
|
||||
|
||||
typedef _Arrangement_2 Arrangement_2;
|
||||
typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2;
|
||||
typedef typename Arrangement_2::Vertex_const_iterator Vertex_const_iterator;
|
||||
typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator;
|
||||
typedef typename Arrangement_2::Halfedge Halfedge;
|
||||
typedef typename Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Geometry_traits_2::Segment_2 Segment_2;
|
||||
typedef typename Geometry_traits_2::Point_2 Point_2;
|
||||
|
||||
|
||||
// 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
|
||||
Halfedge_handle he_start_1 = get_initial_halfedge(arr1);
|
||||
Halfedge_handle 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);
|
||||
|
||||
Halfedge_handle he_run_1 = he_start_1->next();
|
||||
Halfedge_handle 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;
|
||||
|
||||
// Edge_const_iterator eit_fst, eit_snd;
|
||||
// std::vector<Halfedge> halfedges_fst, halfedges_snd;
|
||||
|
||||
// for (eit_fst = arr1.edges_begin(), eit_snd = arr2.edges_begin() ;
|
||||
// eit_fst != arr1.edges_end(), eit_snd != arr2.edges_end() ;
|
||||
// ++eit_fst, ++eit_snd) {
|
||||
|
||||
// halfedges_fst.push_back(*eit_fst);
|
||||
// halfedges_snd.push_back(*eit_snd);
|
||||
// }
|
||||
|
||||
// // Compare the two vectors
|
||||
// for (unsigned int i = 0 ; i < halfedges_fst.size() ; i++) {
|
||||
// Halfedge he_curr = halfedges_fst[i];
|
||||
// bool found = false;
|
||||
// for (unsigned int j = 0 ; j < halfedges_snd.size() ; j++) {
|
||||
// if (he_curr.source()->point() == halfedges_snd[j].source()->point() &&
|
||||
// he_curr.target()->point() == halfedges_snd[j].target()->point()) {
|
||||
// found = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (found == false) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (unsigned int i = 0 ; i < halfedges_snd.size() ; i++) {
|
||||
// Halfedge he_curr = halfedges_snd[i];
|
||||
// bool found = false;
|
||||
// for (unsigned int j = 0 ; j < halfedges_fst.size() ; j++) {
|
||||
// if (he_curr.source()->point() == halfedges_fst[j].source()->point() &&
|
||||
// he_curr.target()->point() == halfedges_fst[j].target()->point()) {
|
||||
// found = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (found == false) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Number_type>
|
||||
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<class Number_type>
|
||||
std::string num2string(Number_type& n) {
|
||||
std::stringstream ss;
|
||||
ss<<n;
|
||||
return ss.str();
|
||||
}
|
||||
template <class _Arrangement_2>
|
||||
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<Point_2> points;
|
||||
std::vector<Segment_2> 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<Number_type>(n1), string2num<Number_type>(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 <class _Arrangement_2>
|
||||
void create_polygons_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::stringstream convert(line);
|
||||
int number_of_polygons;
|
||||
convert >> number_of_polygons;
|
||||
for (int i = 0; i != number_of_polygons; i++) {
|
||||
std::vector<Point_2> points;
|
||||
std::vector<Segment_2> segments;
|
||||
int number_of_vertex;
|
||||
input >> number_of_vertex;
|
||||
for (int j = 0; j != number_of_vertex-1; j++) {
|
||||
std::getline(input, line);
|
||||
std::string n1, n2;
|
||||
std::istringstream iss(line);
|
||||
iss >> n1 >> n2;
|
||||
points.push_back(Point_2(string2num<Number_type>(n1), string2num<Number_type>(n2)));
|
||||
}
|
||||
for (int j = 0; j != number_of_vertex-1; j++) {
|
||||
|
||||
segments.push_back(Segment_2(points[j], points[j+1]));
|
||||
}
|
||||
segments.push_back(Segment_2(points.front(), points.back()));
|
||||
CGAL::insert(arr, segments.begin(), segments.end());
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
std::cout<<"Can't open the file. Check the file name.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Arrangement_2>
|
||||
bool compare_arr_by_edges(const Arrangement_2& arr1, const Arrangement_2& arr2) {
|
||||
std::set<std::string> 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<std::string> 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<typename Point_2>
|
||||
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<typename Point_2>
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Author: Kan Huang
|
||||
* E-mail: huangkandiy@gmail.com
|
||||
*/
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/Gmpq.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Arr_segment_traits_2.h>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Naive_visibility_2.h>
|
||||
#include <CGAL/test_model_methods.h>
|
||||
#include <CGAL/test_utils.h>
|
||||
#include <CGAL/Preprocessed_visibility_2.h>
|
||||
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
std::string number2string(T n) {
|
||||
std::stringstream ss;
|
||||
ss << n;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int main() {
|
||||
int case_number = 1;
|
||||
//test kernel Cartesian<Gmpq>
|
||||
{
|
||||
typedef CGAL::Gmpq Number_type;
|
||||
typedef CGAL::Cartesian<Number_type> Kernel;
|
||||
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
|
||||
typedef Traits_2::Point_2 Point_2;
|
||||
typedef Traits_2::X_monotone_curve_2 Segment_2;
|
||||
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
|
||||
|
||||
std::cout<<"Kernel: Cartesian<Gmpq>"<<std::endl;
|
||||
for (int i=1; i <= case_number; i++) {
|
||||
std::cout<<"Test "<<i<<" begins"<<std::endl;
|
||||
std::string input_arr_file("data/Arrangement_Test/in");
|
||||
input_arr_file += number2string(i);
|
||||
std::string ans_file("data/Arrangement_Test/non_regular_out");
|
||||
ans_file += number2string(i);
|
||||
|
||||
std::ifstream input(input_arr_file.c_str());
|
||||
// std::cout<<"read file over\n";
|
||||
std::ifstream ans_input(ans_file.c_str());
|
||||
// std::cout<<"read another file\n";
|
||||
Arrangement_2 arr_in, arr_ans, arr_vb;
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr_in, input);
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr_ans, ans_input);
|
||||
|
||||
CGAL::Visibility_2::Naive_visibility_2<Arrangement_2, CGAL::Tag_false> vb(arr_in);
|
||||
typename Arrangement_2::Face_const_handle fit = arr_in.faces_begin();
|
||||
do {
|
||||
if (!fit->is_unbounded()) break;
|
||||
} while (++fit != arr_in.faces_end());
|
||||
vb.visibility_region(Point_2(0, 0), fit, arr_vb);
|
||||
CGAL::Visibility_2::print_arrangement(arr_vb);
|
||||
CGAL::Visibility_2::print_arrangement(arr_ans);
|
||||
std::cout<<(true == (CGAL::test_are_equal<Arrangement_2>(arr_ans, arr_vb)))<<std::endl;
|
||||
std::cout<<CGAL::compare_arr_by_edges(arr_ans, arr_vb)<<std::endl;
|
||||
}
|
||||
}
|
||||
//test kernel Exact_predicates_exact_constructions_kernel
|
||||
// {
|
||||
// typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
// typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
|
||||
// typedef Traits_2::Point_2 Point_2;
|
||||
// typedef Traits_2::X_monotone_curve_2 Segment_2;
|
||||
// typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
|
||||
|
||||
// std::cout<<"Kernel: Exact_predicates_exact_constructions"<<std::endl;
|
||||
// for (int i=1; i <= case_number; i++) {
|
||||
// std::cout<<"Test "<<i<<" begins"<<std::endl;
|
||||
// std::string input_arr_file("data/Arrangement_Test/in");
|
||||
// input_arr_file += number2string(i);
|
||||
// std::string ans_file("data/Arrangement_Test/non_regular_out");
|
||||
// ans_file += number2string(i);
|
||||
|
||||
// std::ifstream input(input_arr_file.c_str());
|
||||
// std::ifstream ans_input(ans_file.c_str());
|
||||
// Arrangement_2 arr_in, arr_ans, arr_vb;
|
||||
// CGAL::create_arrangement_from_file<Arrangement_2>(arr_in, input);
|
||||
// CGAL::create_arrangement_from_file<Arrangement_2>(arr_ans, ans_input);
|
||||
|
||||
// CGAL::Visibility_2::Naive_visibility_2<Arrangement_2, CGAL::Tag_false> vb(arr_in);
|
||||
// typename Arrangement_2::Face_const_handle fit = arr_in.faces_begin();
|
||||
// do {
|
||||
// if (!fit->is_unbounded()) break;
|
||||
// } while (++fit != arr_in.faces_end());
|
||||
// vb.visibility_region(Point_2(0, 0), fit, arr_vb);
|
||||
// std::cout<<(true == (CGAL::test_are_equal<Arrangement_2>(arr_ans, arr_vb)))<<std::endl;
|
||||
// }
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// 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 <fbungiu@gmail.com>
|
||||
// Michael Hemmer <michael.hemmer@cgal.org>
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/Gmpq.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Arr_segment_traits_2.h>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Simple_visibility_2.h>
|
||||
#include <CGAL/test_model_methods.h>
|
||||
#include <CGAL/test_utils.h>
|
||||
#include <CGAL/test_simple_polygons.h>
|
||||
#include <CGAL/Simple_visibility_2.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
int main() {
|
||||
{
|
||||
typedef CGAL::Gmpq Number_type;
|
||||
typedef CGAL::Cartesian<Number_type> Kernel;
|
||||
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
|
||||
typedef Traits_2::Point_2 Point_2;
|
||||
typedef Traits_2::X_monotone_curve_2 Segment_2;
|
||||
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
|
||||
|
||||
// First read arrangement
|
||||
Arrangement_2 arr;
|
||||
std::ifstream input("./data/simple_polygon_test_case_1.in");
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr, input);
|
||||
CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> visibility;
|
||||
assert(false == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.attach(arr);
|
||||
assert(true == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.detach();
|
||||
assert(false == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.attach(arr);
|
||||
assert(true == (CGAL::test_are_equal<Arrangement_2>(arr, visibility.arr())));
|
||||
|
||||
// Run test cases from https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases
|
||||
assert(true == (CGAL::simple_polygon_test_case_1<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_2<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_3<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_4<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
}
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
|
||||
typedef Traits_2::Point_2 Point_2;
|
||||
typedef Traits_2::X_monotone_curve_2 Segment_2;
|
||||
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
|
||||
|
||||
// First read arrangement
|
||||
Arrangement_2 arr;
|
||||
std::ifstream input("./data/simple_polygon_test_case_1.in");
|
||||
CGAL::create_arrangement_from_file<Arrangement_2>(arr, input);
|
||||
CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> visibility;
|
||||
assert(false == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.attach(arr);
|
||||
assert(true == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.detach();
|
||||
assert(false == (CGAL::test_is_attached<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false> >(visibility)));
|
||||
visibility.attach(arr);
|
||||
assert(true == (CGAL::test_are_equal<Arrangement_2>(arr, visibility.arr())));
|
||||
|
||||
// Run test cases from https://cgal.geometryfactory.com/CGAL/Members/wiki/Visibility/TestCases
|
||||
assert(true == (CGAL::simple_polygon_test_case_1<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_2<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_3<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
assert(true == (CGAL::simple_polygon_test_case_4<CGAL::Visibility_2::Simple_visibility_2<Arrangement_2, CGAL::Tag_false>, Arrangement_2> ()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue