mirror of https://github.com/CGAL/cgal
Aos 2 fixes efif (#8666)
## Fixed the Landmark point-location strategy of the Aos_2 package, so that it can be applied to arrangements on a sphere. The title says it all. I slightly changed one paragraph in the user manual. Here is the new version: The arrangement attached to the landmark strategy must be either (i) an instance of the `Arrangement_2]<Geom,Dcel>` class template, where the `Traits` parameter is substituted by a geometry-traits class that models the `ArrangementLandmarkTraits_2` concept, or (ii) an instance of the `Arrangement_on_surface_2<GeomTraits,TopolTraits>` class template, where the `GeometryTraits` is similarly substituted; see Section The Landmark Concept for details about this concept. ## Release Management * Affected package(s): Arrangement_on_surface_2 * Issue(s) solved (if any): NA * Feature/Small Feature (if any): NA * Link to compiled documentation: Changed one paragraph; see above. * License and copyright ownership: TAU
This commit is contained in:
commit
76321c4be1
|
|
@ -1438,14 +1438,15 @@ vary according to the user choice.} for answering queries:
|
|||
points or choosing points on a grid, are also available; see the
|
||||
Reference Manual for more details.
|
||||
|
||||
The landmark strategy requires that the type of the attached
|
||||
arrangement be an instance of the `Arrangement_2<Traits,Dcel>` class
|
||||
template, where the `Traits` parameter is substituted by a
|
||||
geometry-traits class that models the `ArrangementLandmarkTraits_2`
|
||||
concept, which refines the basic `ArrangementBasicTraits_2` concept;
|
||||
see Section \ref aos_sssec-tr_landmarks_concept for details. Most
|
||||
traits classes included in the \ref PkgArrangementOnSurface2 package
|
||||
are models of this refined concept.
|
||||
The arrangement attached to the landmark strategy must be either (i)
|
||||
an instance of the `Arrangement_2<Geom,Dcel>` class template, where
|
||||
the `Traits` parameter is substituted by a geometry-traits class
|
||||
that models the `ArrangementLandmarkTraits_2` concept, or (ii) an
|
||||
instance of the `Arrangement_on_surface_2<GeomTraits,TopolTraits>`
|
||||
class template, where the `GeomTraits` is similarly substituted;
|
||||
see Section \ref aos_sssec-tr_landmarks_concept for details about
|
||||
this concept. Most traits classes included in the \ref
|
||||
PkgArrangementOnSurface2 package are models of this refined concept.
|
||||
|
||||
<LI>`Arr_trapezoid_ric_point_location<Arrangement>` implements an
|
||||
improved variant of Mulmuley's point-location algorithm
|
||||
|
|
|
|||
|
|
@ -36,13 +36,6 @@ using Trap_pl = CGAL::Arr_trapezoid_ric_point_location<Gm>;
|
|||
using Geom_traits = Gm::Geometry_traits_2;
|
||||
using Point_2 = Geom_traits::Point_2;
|
||||
|
||||
using Point_location_result = CGAL::Arr_point_location_result<Gm>;
|
||||
using Query_result = std::pair<Point_2, Point_location_result::Type>;
|
||||
|
||||
using Vertex_const_handle = Gm::Vertex_const_handle;
|
||||
using Halfedge_const_handle = Gm::Halfedge_const_handle;
|
||||
using Face_const_handle = Gm::Face_const_handle;
|
||||
|
||||
int main() {
|
||||
Gm_polyhedron p;
|
||||
p.make_tetrahedron(Point_3(1.0, 0.0, 0.0), Point_3(0.0, 1.0, 0.0),
|
||||
|
|
@ -50,7 +43,7 @@ int main() {
|
|||
Gm gm;
|
||||
|
||||
Naive_pl naive_pl(gm);
|
||||
// Landmarks_pl landmarks_pl(gm);
|
||||
Landmarks_pl landmarks_pl(gm);
|
||||
Walk_pl walk_pl(gm);
|
||||
// Trap_pl trap_pl(gm);
|
||||
|
||||
|
|
@ -70,30 +63,17 @@ int main() {
|
|||
locate_point(naive_pl, points[1]);
|
||||
locate_point(naive_pl, points[2]);
|
||||
|
||||
// locate_point(walk_pl, points[0]);
|
||||
// locate_point(walk_pl, points[1]);
|
||||
// locate_point(walk_pl, points[2]);
|
||||
|
||||
locate_point(landmarks_pl, points[0]);
|
||||
locate_point(landmarks_pl, points[1]);
|
||||
locate_point(landmarks_pl, points[2]);
|
||||
|
||||
// locate_point(trap_pl, points[0]);
|
||||
|
||||
////////
|
||||
std::list<Query_result> results;
|
||||
// The following cause an assertion failure.
|
||||
// CGAL::locate(gm, &points[0], &points[3], std::back_inserter(results));
|
||||
|
||||
// Print the results.
|
||||
for (auto it = results.begin(); it != results.end(); ++it) {
|
||||
std::cout << "The point (" << it->first << ") is located ";
|
||||
if (const Face_const_handle* f =
|
||||
std::get_if<Face_const_handle>(&(it->second))) // inside a face
|
||||
std::cout << "inside "
|
||||
<< (((*f)->is_unbounded()) ? "the unbounded" : "a bounded")
|
||||
<< " face.\n";
|
||||
else if (const Halfedge_const_handle* e =
|
||||
std::get_if<Halfedge_const_handle>(&(it->second))) // on an edge
|
||||
std::cout << "on an edge: " << (*e)->curve() << std::endl;
|
||||
else if (const Vertex_const_handle* v =
|
||||
std::get_if<Vertex_const_handle>(&(it->second))) // on a vertex
|
||||
std::cout << "on "
|
||||
<< (((*v)->is_isolated()) ? "an isolated" : "a")
|
||||
<< " vertex: " << (*v)->point() << std::endl;
|
||||
}
|
||||
// locate_point(trap_pl, points[1]);
|
||||
// locate_point(trap_pl, points[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Idit Haran <haranidi@post.tau.ac.il>
|
||||
// Ron Wein <wein@post.tau.ac.il>
|
||||
// Author(s) : Idit Haran <haranidi@post.tau.ac.il>
|
||||
// Ron Wein <wein@post.tau.ac.il>
|
||||
|
||||
#ifndef CGAL_ARR_LANDMARKS_POINT_LOCATION_H
|
||||
#define CGAL_ARR_LANDMARKS_POINT_LOCATION_H
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include <CGAL/Arr_point_location_result.h>
|
||||
#include <CGAL/Arrangement_2/Arr_traits_adaptor_2.h>
|
||||
#include <CGAL/Arr_point_location/Arr_lm_vertices_generator.h>
|
||||
#include <CGAL/Arr_tags.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
|
@ -42,44 +43,54 @@ namespace CGAL {
|
|||
* Generator is a class that generates the set of landmarks.
|
||||
*/
|
||||
|
||||
template <class Arrangement_,
|
||||
class Generator_ = Arr_landmarks_vertices_generator<Arrangement_> >
|
||||
class Arr_landmarks_point_location
|
||||
{
|
||||
template <typename Arrangement_,
|
||||
typename Generator_ = Arr_landmarks_vertices_generator<Arrangement_>>
|
||||
class Arr_landmarks_point_location {
|
||||
public:
|
||||
typedef Arrangement_ Arrangement_2;
|
||||
typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2;
|
||||
typedef Generator_ Generator;
|
||||
using Arrangement_2 = Arrangement_;
|
||||
using Generator = Generator_;
|
||||
using Geometry_traits_2 = typename Arrangement_2::Geometry_traits_2;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
|
||||
using Vertex_const_handle = typename Arrangement_2::Vertex_const_handle;
|
||||
using Halfedge_const_handle = typename Arrangement_2::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Arrangement_2::Face_const_handle;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_const_iterator Vertex_const_iterator;
|
||||
typedef typename Arrangement_2::Halfedge_const_iterator
|
||||
Halfedge_const_iterator;
|
||||
typedef typename Arrangement_2::Halfedge_around_vertex_const_circulator
|
||||
Halfedge_around_vertex_const_circulator;
|
||||
typedef typename Arrangement_2::Ccb_halfedge_const_circulator
|
||||
Ccb_halfedge_const_circulator;
|
||||
typedef typename Arrangement_2::Outer_ccb_const_iterator
|
||||
Outer_ccb_const_iterator;
|
||||
typedef typename Arrangement_2::Inner_ccb_const_iterator
|
||||
Inner_ccb_const_iterator;
|
||||
typedef typename Arrangement_2::Isolated_vertex_const_iterator
|
||||
Isolated_vertex_const_iterator;
|
||||
using Vertex_const_iterator = typename Arrangement_2::Vertex_const_iterator;
|
||||
using Halfedge_const_iterator =
|
||||
typename Arrangement_2::Halfedge_const_iterator;
|
||||
|
||||
typedef typename Arrangement_2::Point_2 Point_2;
|
||||
typedef typename Arrangement_2::X_monotone_curve_2 X_monotone_curve_2;
|
||||
using Halfedge_around_vertex_const_circulator =
|
||||
typename Arrangement_2::Halfedge_around_vertex_const_circulator;
|
||||
using Ccb_halfedge_const_circulator =
|
||||
typename Arrangement_2::Ccb_halfedge_const_circulator;
|
||||
using Outer_ccb_const_iterator =
|
||||
typename Arrangement_2::Outer_ccb_const_iterator;
|
||||
using Inner_ccb_const_iterator =
|
||||
typename Arrangement_2::Inner_ccb_const_iterator;
|
||||
using Isolated_vertex_const_iterator =
|
||||
typename Arrangement_2::Isolated_vertex_const_iterator;
|
||||
|
||||
typedef Arr_point_location_result<Arrangement_2> Result;
|
||||
typedef typename Result::Type Result_type;
|
||||
using Point_2 = typename Arrangement_2::Point_2;
|
||||
using X_monotone_curve_2 = typename Arrangement_2::X_monotone_curve_2;
|
||||
|
||||
using Result = Arr_point_location_result<Arrangement_2>;
|
||||
using Result_type = typename Result::Type;
|
||||
|
||||
// Support cpp11::result_of
|
||||
typedef Result_type result_type;
|
||||
using result_type = Result_type;
|
||||
|
||||
private:
|
||||
using Gt2 = Geometry_traits_2;
|
||||
using Left_side_category =
|
||||
typename internal::Arr_complete_left_side_category<Gt2>::Category;
|
||||
using Right_side_category =
|
||||
typename internal::Arr_complete_right_side_category<Gt2>::Category;
|
||||
using Left_or_right_sides_category =
|
||||
typename Arr_two_sides_category<Left_side_category,
|
||||
Right_side_category>::result;
|
||||
|
||||
protected:
|
||||
typedef Arr_traits_basic_adaptor_2<Geometry_traits_2> Traits_adaptor_2;
|
||||
using Traits_adaptor_2 = Arr_traits_basic_adaptor_2<Geometry_traits_2>;
|
||||
|
||||
/*! \struct Less_halfedge_handle
|
||||
* Used to sort handles.
|
||||
|
|
@ -92,10 +103,10 @@ protected:
|
|||
typedef std::set<Halfedge_const_handle, Less_halfedge_handle> Halfedge_set;
|
||||
|
||||
// Data members:
|
||||
const Arrangement_2* p_arr; // The associated arrangement.
|
||||
const Arrangement_2* p_arr; // The associated arrangement.
|
||||
const Traits_adaptor_2* m_traits; // Its associated traits object.
|
||||
Generator* lm_gen; // The associated landmark generator.
|
||||
bool own_gen; // Indicates whether the generator
|
||||
Generator* lm_gen; // The associated landmark generator.
|
||||
bool own_gen; // Indicates whether the generator
|
||||
// has been locally allocated.
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -103,7 +114,7 @@ protected:
|
|||
inline Result_type default_result() const { return Result::default_result(); }
|
||||
|
||||
public:
|
||||
/*! Default constructor. */
|
||||
/*! constructs default. */
|
||||
Arr_landmarks_point_location() :
|
||||
p_arr(nullptr),
|
||||
m_traits(nullptr),
|
||||
|
|
@ -111,34 +122,32 @@ public:
|
|||
own_gen(false)
|
||||
{}
|
||||
|
||||
/*! Constructor given an arrangement only. */
|
||||
/*! constructs given an arrangement only. */
|
||||
Arr_landmarks_point_location(const Arrangement_2& arr) :
|
||||
p_arr(&arr),
|
||||
m_traits(static_cast<const Traits_adaptor_2*>(p_arr->geometry_traits())),
|
||||
lm_gen(new Generator(arr)), // allocate the landmarks generator.
|
||||
own_gen(true)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/*! Constructor given an arrangement, and landmarks generator. */
|
||||
/*! constructs given an arrangement, and landmarks generator. */
|
||||
Arr_landmarks_point_location(const Arrangement_2& arr, Generator* gen) :
|
||||
p_arr(&arr),
|
||||
m_traits(static_cast<const Traits_adaptor_2*>(p_arr->geometry_traits())),
|
||||
lm_gen(gen),
|
||||
own_gen(false)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/*! Destructor. */
|
||||
~Arr_landmarks_point_location()
|
||||
{
|
||||
/*! destructs. */
|
||||
~Arr_landmarks_point_location() {
|
||||
if (own_gen) {
|
||||
delete lm_gen;
|
||||
lm_gen = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Attach an arrangement object (and a generator, if supplied). */
|
||||
void attach(const Arrangement_2& arr, Generator* gen = nullptr)
|
||||
{
|
||||
/*! attaches an arrangement object (and a generator, if supplied). */
|
||||
void attach(const Arrangement_2& arr, Generator* gen = nullptr) {
|
||||
// Keep a pointer to the associated arrangement.
|
||||
p_arr = &arr;
|
||||
m_traits = static_cast<const Traits_adaptor_2*>(p_arr->geometry_traits());
|
||||
|
|
@ -163,9 +172,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/*! Detach the instance from the arrangement object. */
|
||||
void detach()
|
||||
{
|
||||
/*! detaches the instance from the arrangement object. */
|
||||
void detach() {
|
||||
p_arr = nullptr;
|
||||
m_traits = nullptr;
|
||||
|
||||
|
|
@ -174,8 +182,7 @@ public:
|
|||
lm_gen->detach();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Locate the arrangement feature containing the given point.
|
||||
/*! locates the arrangement feature containing the given point.
|
||||
* \param p The query point.
|
||||
* \return An object representing the arrangement feature containing the
|
||||
* query point. This object is either a Face_const_handle or a
|
||||
|
|
@ -184,7 +191,7 @@ public:
|
|||
result_type locate(const Point_2& p) const;
|
||||
|
||||
protected:
|
||||
/*! Walk from the given vertex to the query point.
|
||||
/*! walks from the given vertex to the query point.
|
||||
* \param vh The given vertex handle.
|
||||
* \param p The query point.
|
||||
* \param crossed_edges In/Out: The set of edges crossed so far.
|
||||
|
|
@ -196,7 +203,7 @@ protected:
|
|||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const;
|
||||
|
||||
/*! Locate an edge around a given vertex that is the predecessor of the
|
||||
/*! locates an edge around a given vertex that is the predecessor of the
|
||||
* curve connecting the vertex to the query point in a clockwise order.
|
||||
* \param vh The vertex.
|
||||
* \param p The query point.
|
||||
|
|
@ -207,7 +214,7 @@ protected:
|
|||
const Point_2& p,
|
||||
bool& new_vertex) const;
|
||||
|
||||
/*! Walk from a point on a given halfedge to the query point.
|
||||
/*! walks from a point on a given halfedge to the query point.
|
||||
* \param eh The given halfedge handle.
|
||||
* \param np The point that the walk starts from.
|
||||
* \param p The query point.
|
||||
|
|
@ -220,7 +227,7 @@ protected:
|
|||
const Point_2& np,
|
||||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const;
|
||||
/*! In case the arrangement's curve contained in the segment
|
||||
/*! handles the arrangement curve contained in the segment
|
||||
* from the nearest landmark to the query point
|
||||
* \param he The given halfedge handle.
|
||||
* \param p_is_left Is the query point the left endpoint of seg.
|
||||
|
|
@ -236,7 +243,7 @@ protected:
|
|||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const;
|
||||
|
||||
/*! Walk from a point in a face to the query point.
|
||||
/*! walks from a point in a face to the query point.
|
||||
* \param fh A halfedge handle that points to the face.
|
||||
* \param np The point that the walk starts from.
|
||||
* \param p The query point.
|
||||
|
|
@ -250,7 +257,7 @@ protected:
|
|||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const;
|
||||
|
||||
/*! Find a halfedge on the given CCB that intersects the given x-monotone
|
||||
/*! finds a halfedge on the given CCB that intersects the given x-monotone
|
||||
* curve, connecting the current landmark to the query point.
|
||||
* \param circ The CCB circulator.
|
||||
* \param seg The segment connecting the landmark and the query point.
|
||||
|
|
@ -275,7 +282,7 @@ protected:
|
|||
bool& cv_is_contained_in_seg,
|
||||
Vertex_const_handle& new_vertex) const;
|
||||
|
||||
/*! Return the halfedge that contains the query point.
|
||||
/*! returns the halfedge that contains the query point.
|
||||
* \param he The halfedge handle.
|
||||
* \param crossed_edges In/Out: The set of edges crossed so far.
|
||||
* \param p The query point.
|
||||
|
|
@ -287,7 +294,7 @@ protected:
|
|||
const Point_2& p,
|
||||
bool& is_target) const;
|
||||
|
||||
/*! Check whether the given curve intersects a simple segment, which connects
|
||||
/*! checks whether the given curve intersects a simple segment, which connects
|
||||
* the current landmark to the query point, an odd number of times.
|
||||
* \param cv The curve.
|
||||
* \param seg The segment connecting the landmark and the query point.
|
||||
|
|
@ -303,9 +310,62 @@ protected:
|
|||
bool& p_on_curve,
|
||||
bool& cv_and_seg_overlap,
|
||||
bool& cv_is_contained_in_seg) const;
|
||||
|
||||
//!
|
||||
template <typename T>
|
||||
std::pair<X_monotone_curve_2, Comparison_result>
|
||||
construct_segment(const Point_2& p, const Point_2& q, T const& traits,
|
||||
...) const {
|
||||
X_monotone_curve_2 seg = traits.construct_x_monotone_curve_2_object()(p, q);
|
||||
Comparison_result res = traits.compare_xy_2_object()(p, q);
|
||||
return std::make_pair(seg, res);
|
||||
}
|
||||
|
||||
//*!
|
||||
template <typename T, typename = typename T::Compare_endpoints_xy_2>
|
||||
std::pair<X_monotone_curve_2, Comparison_result>
|
||||
construct_segment(const Point_2& p, const Point_2& q, T const& traits,
|
||||
int) const {
|
||||
X_monotone_curve_2 seg = traits.construct_x_monotone_curve_2_object()(p, q);
|
||||
Comparison_result res = traits.compare_endpoints_xy_2_object()(seg);
|
||||
return std::make_pair(seg, res);
|
||||
}
|
||||
|
||||
/*! Determines whether the $x$-coordinates of two points are equal.
|
||||
*/
|
||||
bool equal_x_2(const Point_2& p, const Point_2& q,
|
||||
Arr_all_sides_oblivious_tag) const
|
||||
{ return (m_traits->compare_x_2_object()(p, q) == EQUAL); }
|
||||
|
||||
/*! Determines whether the $x$-coordinates of two points are equal.
|
||||
*/
|
||||
bool equal_x_2(const Point_2& p, const Point_2& q,
|
||||
Arr_has_identified_side_tag) const {
|
||||
auto is_on_y_identification = m_traits->is_on_y_identification_2_object();
|
||||
if (is_on_y_identification(p)) {
|
||||
return is_on_y_identification(q);
|
||||
}
|
||||
if (is_on_y_identification(q)) return false;
|
||||
return (m_traits->compare_x_2_object()(p, q) == EQUAL);
|
||||
}
|
||||
|
||||
/*! Determines whether the $x$-coordinates of two points are equal.
|
||||
*/
|
||||
bool equal_x_2(const Point_2& p, const Point_2& q,
|
||||
Arr_boundary_cond_tag) const {
|
||||
auto param_space_in_x = m_traits->parameter_space_in_x_2_object();
|
||||
switch (param_space_in_x(p)) {
|
||||
case ARR_LEFT_BOUNDARY: return (param_space_in_x(q) == ARR_LEFT_BOUNDARY);
|
||||
case ARR_RIGHT_BOUNDARY: return (param_space_in_x(q) == ARR_LEFT_BOUNDARY);
|
||||
case ARR_INTERIOR: return (m_traits->compare_x_2_object()(p, q) == EQUAL);
|
||||
default: CGAL_error();
|
||||
}
|
||||
CGAL_error();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace CGAL
|
||||
} // namespace CGAL
|
||||
|
||||
// The member-function definitions can be found under:
|
||||
#include <CGAL/Arr_point_location/Arr_landmarks_pl_impl.h>
|
||||
|
|
|
|||
|
|
@ -7,16 +7,15 @@
|
|||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Idit Haran <haranidi@post.tau.ac.il>
|
||||
// Ron Wein <wein@post.tau.ac.il>
|
||||
// Efi Fogel <efif@post.tau.ac.il>
|
||||
// Author(s) : Idit Haran <haranidi@post.tau.ac.il>
|
||||
// Ron Wein <wein@post.tau.ac.il>
|
||||
// Efi Fogel <efif@post.tau.ac.il>
|
||||
|
||||
#ifndef CGAL_ARR_LANDMARKS_PL_IMPL_H
|
||||
#define CGAL_ARR_LANDMARKS_PL_IMPL_H
|
||||
|
||||
#include <CGAL/license/Arrangement_on_surface_2.h>
|
||||
|
||||
|
||||
/*! \file
|
||||
* Member-function definitions for the
|
||||
* Arr_landmarks_point_location<Arrangement, Generator> class.
|
||||
|
|
@ -24,60 +23,53 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Locate the arrangement feature containing the given point.
|
||||
//
|
||||
/*! locates the arrangement feature containing the given point.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::locate(const Point_2& p) const
|
||||
{
|
||||
Arr_landmarks_point_location<Arr, Gen>::locate(const Point_2& p) const {
|
||||
// If the arrangement is empty, return its initial (empty and
|
||||
// non-fictitious) face.
|
||||
if (p_arr->number_of_vertices() == 0) {
|
||||
CGAL_assertion(p_arr->number_of_faces() == 1);
|
||||
Face_const_handle fh = p_arr->faces_begin();
|
||||
Face_const_handle fh = p_arr->faces_begin();
|
||||
return make_result(fh);
|
||||
}
|
||||
|
||||
// Use the generator and to find the closest landmark to the query point.
|
||||
result_type lm_location_obj;
|
||||
result_type lm_location_obj;
|
||||
const Point_2& landmark_point = lm_gen->closest_landmark(p, lm_location_obj);
|
||||
|
||||
// If the query point and the landmark point are equal, return the landmark.
|
||||
if (m_traits->equal_2_object()(landmark_point, p))
|
||||
return lm_location_obj;
|
||||
if (m_traits->equal_2_object()(landmark_point, p)) return lm_location_obj;
|
||||
|
||||
// Walk from the nearest_vertex to the point p, using walk algorithm,
|
||||
// and find the location of the query point p. Note that the set of edges
|
||||
// we have crossed so far is initially empty.
|
||||
Halfedge_set crossed_edges;
|
||||
result_type out_obj;
|
||||
Halfedge_set crossed_edges;
|
||||
result_type out_obj;
|
||||
|
||||
// Locate the arrangement feature that contains the landmark.
|
||||
const Vertex_const_handle* vh;
|
||||
const Halfedge_const_handle* hh;
|
||||
const Face_const_handle* fh;
|
||||
if ( ( vh = Result().template assign<Vertex_const_handle>(&lm_location_obj) ) )
|
||||
out_obj = _walk_from_vertex(*vh, p, crossed_edges);
|
||||
else if ( ( hh = Result().template assign<Halfedge_const_handle>(&lm_location_obj) ) )
|
||||
out_obj = _walk_from_edge(*hh, landmark_point, p, crossed_edges);
|
||||
else if ( ( fh = Result().template assign<Face_const_handle>(&lm_location_obj) ) )
|
||||
out_obj = _walk_from_face(*fh, landmark_point, p, crossed_edges);
|
||||
if (const auto* v = std::get_if<Vertex_const_handle>(&lm_location_obj))
|
||||
out_obj = _walk_from_vertex(*v, p, crossed_edges);
|
||||
else if (const auto* e = std::get_if<Halfedge_const_handle>(&lm_location_obj))
|
||||
out_obj = _walk_from_edge(*e, landmark_point, p, crossed_edges);
|
||||
else if (const auto* f = std::get_if<Face_const_handle>(&lm_location_obj))
|
||||
out_obj = _walk_from_face(*f, landmark_point, p, crossed_edges);
|
||||
else CGAL_error_msg("lm_location_obj of an unknown type.");
|
||||
|
||||
if ( ( fh = Result().template assign<Face_const_handle>(&out_obj) ) ) {
|
||||
if (const auto* fp = std::get_if<Face_const_handle>(&out_obj)) {
|
||||
const auto& f = *fp;
|
||||
// If we reached here, we did not locate the query point in any of the
|
||||
// holes inside the current face, so we conclude it is contained in this
|
||||
// face.
|
||||
// However, we first have to check whether the query point coincides with
|
||||
// any of the isolated vertices contained inside this face.
|
||||
Isolated_vertex_const_iterator iso_verts_it;
|
||||
typename Traits_adaptor_2::Equal_2 equal = m_traits->equal_2_object();
|
||||
|
||||
for (iso_verts_it = (*fh)->isolated_vertices_begin();
|
||||
iso_verts_it != (*fh)->isolated_vertices_end(); ++iso_verts_it)
|
||||
{
|
||||
// face. However, we first have to check whether the query point coincides
|
||||
// with any of the isolated vertices contained inside this face.
|
||||
auto equal = m_traits->equal_2_object();
|
||||
// Do not use 'auto' to define the iterator, as MSVC2017 complains.
|
||||
for (Isolated_vertex_const_iterator iso_verts_it = f->isolated_vertices_begin();
|
||||
iso_verts_it != f->isolated_vertices_end(); ++iso_verts_it) {
|
||||
if (equal(p, iso_verts_it->point())) {
|
||||
Vertex_const_handle ivh = iso_verts_it;
|
||||
Vertex_const_handle ivh = iso_verts_it;
|
||||
return make_result(ivh);
|
||||
}
|
||||
}
|
||||
|
|
@ -86,28 +78,24 @@ Arr_landmarks_point_location<Arr, Gen>::locate(const Point_2& p) const
|
|||
return out_obj;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Walk from a given vertex to the query point.
|
||||
//
|
||||
/*! walks from a given vertex to the query point.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
_walk_from_vertex(Vertex_const_handle nearest_vertex,
|
||||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const
|
||||
{
|
||||
_walk_from_vertex(Vertex_const_handle nearest_vertex, const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const {
|
||||
Vertex_const_handle vh = nearest_vertex;
|
||||
CGAL_assertion_msg(! vh->is_at_open_boundary(),
|
||||
"_walk_from_vertex() from a vertex at infinity.");
|
||||
|
||||
// Check if the query point p coincides with the vertex.
|
||||
if (m_traits->equal_2_object()(vh->point(), p))
|
||||
return make_result(vh);
|
||||
if (m_traits->equal_2_object()(vh->point(), p)) return make_result(vh);
|
||||
|
||||
// In case of an isolated vertex, walk to from the face that contains
|
||||
// it toward the query point.
|
||||
if (vh->is_isolated()) {
|
||||
Face_const_handle fh = vh->face();
|
||||
Face_const_handle fh = vh->face();
|
||||
return (_walk_from_face(fh, vh->point(), p, crossed_edges));
|
||||
}
|
||||
|
||||
|
|
@ -116,16 +104,15 @@ _walk_from_vertex(Vertex_const_handle nearest_vertex,
|
|||
Halfedge_around_vertex_const_circulator first = vh->incident_halfedges();
|
||||
// Create an x-monotone curve connecting the point associated with the
|
||||
// vertex vp and the query point p.
|
||||
const Point_2& vp = vh->point();
|
||||
X_monotone_curve_2 seg =
|
||||
m_traits->construct_x_monotone_curve_2_object()(vp, p);
|
||||
const bool seg_dir_right =
|
||||
(m_traits->compare_xy_2_object()(vp, p) == SMALLER);
|
||||
const Point_2& vp = vh->point();
|
||||
X_monotone_curve_2 seg;
|
||||
Comparison_result res;
|
||||
std::tie(seg, res) = construct_segment(vp, p, *m_traits, 0);
|
||||
bool seg_dir_right = (res == SMALLER);
|
||||
Halfedge_around_vertex_const_circulator curr_iter = first;
|
||||
Halfedge_around_vertex_const_circulator next_iter = curr_iter;
|
||||
++next_iter;
|
||||
typename Traits_adaptor_2::Is_between_cw_2 is_between_cw =
|
||||
m_traits->is_between_cw_2_object();
|
||||
auto is_between_cw = m_traits->is_between_cw_2_object();
|
||||
// Traverse the halfedges around vp until we find the pair of adjacent
|
||||
// halfedges such as seg is located clockwise in between them.
|
||||
do {
|
||||
|
|
@ -134,12 +121,11 @@ _walk_from_vertex(Vertex_const_handle nearest_vertex,
|
|||
(curr_iter->direction() == ARR_RIGHT_TO_LEFT),
|
||||
next_iter->curve(),
|
||||
(next_iter->direction() == ARR_RIGHT_TO_LEFT),
|
||||
vp, eq_curr_iter, eq_next_iter))
|
||||
{
|
||||
vp, eq_curr_iter, eq_next_iter)) {
|
||||
// the assumption is that each edge is crossed at most twice
|
||||
CGAL_assertion_msg(crossed_edges.count (curr_iter) < 2,
|
||||
CGAL_assertion_msg(crossed_edges.count(curr_iter) < 2,
|
||||
"crossed_edges should contain each halfedge at most twice.");
|
||||
CGAL_assertion_msg(crossed_edges.count (next_iter) < 2,
|
||||
CGAL_assertion_msg(crossed_edges.count(next_iter) < 2,
|
||||
"crossed_edges should contain each halfedge at most twice.");
|
||||
crossed_edges.insert(curr_iter);
|
||||
crossed_edges.insert(curr_iter->twin());
|
||||
|
|
@ -158,8 +144,7 @@ _walk_from_vertex(Vertex_const_handle nearest_vertex,
|
|||
result_type obj = _find_face_around_vertex(vh, p, new_vertex);
|
||||
if (new_vertex) {
|
||||
// We found a vertex closer to p; Continue using this vertex.
|
||||
const Vertex_const_handle* p_vh =
|
||||
Result().template assign<Vertex_const_handle>(&obj);
|
||||
const auto* p_vh = std::get_if<Vertex_const_handle>(&obj);
|
||||
CGAL_assertion(p_vh != nullptr);
|
||||
vh = *p_vh;
|
||||
continue;
|
||||
|
|
@ -167,15 +152,13 @@ _walk_from_vertex(Vertex_const_handle nearest_vertex,
|
|||
|
||||
// If p is located on an edge or on a vertex, return the object
|
||||
// that wraps this arrangement feature.
|
||||
if (Result().template assign<Halfedge_const_handle>(&obj) ||
|
||||
Result().template assign<Vertex_const_handle>(&obj))
|
||||
if (std::get_if<Halfedge_const_handle>(&obj) ||
|
||||
std::get_if<Vertex_const_handle>(&obj))
|
||||
return obj;
|
||||
|
||||
const Face_const_handle* p_fh =
|
||||
Result().template assign<Face_const_handle>(&obj);
|
||||
if (p_fh)
|
||||
// Walk to p from the face we have located:
|
||||
return _walk_from_face(*p_fh, vh->point(), p, crossed_edges);
|
||||
const auto* p_fh = std::get_if<Face_const_handle>(&obj);
|
||||
// Walk to p from the face we have located:
|
||||
if (p_fh) return _walk_from_face(*p_fh, vh->point(), p, crossed_edges);
|
||||
|
||||
CGAL_error_msg("_find_face_around_vertex() returned an unknown object.");
|
||||
}
|
||||
|
|
@ -185,31 +168,27 @@ _walk_from_vertex(Vertex_const_handle nearest_vertex,
|
|||
return default_result();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Locate an edge around a given vertex that is the predecessor of the curve
|
||||
// connecting the vertex to the query point in a clockwise order.
|
||||
//
|
||||
/*! locates an edge around a given vertex that is the predecessor of the curve
|
||||
* connecting the vertex to the query point in a clockwise order.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
_find_face_around_vertex(Vertex_const_handle vh,
|
||||
const Point_2& p,
|
||||
bool& new_vertex) const
|
||||
{
|
||||
_find_face_around_vertex(Vertex_const_handle vh, const Point_2& p,
|
||||
bool& new_vertex) const {
|
||||
new_vertex = false;
|
||||
|
||||
// Create an x-monotone curve connecting the point associated with the
|
||||
// vertex vp and the query point p.
|
||||
const Point_2& vp = vh->point();
|
||||
X_monotone_curve_2 seg =
|
||||
m_traits->construct_x_monotone_curve_2_object()(vp, p);
|
||||
const bool seg_dir_right =
|
||||
(m_traits->compare_xy_2_object()(vp, p) == SMALLER);
|
||||
|
||||
const Point_2& vp = vh->point();
|
||||
X_monotone_curve_2 seg;
|
||||
Comparison_result res;
|
||||
std::tie(seg, res) = construct_segment(vp, p, *m_traits, 0);
|
||||
bool seg_dir_right = (res == SMALLER);
|
||||
// Get the first incident halfedge around v and the next halfedge.
|
||||
Halfedge_around_vertex_const_circulator first = vh->incident_halfedges();
|
||||
Halfedge_around_vertex_const_circulator curr, next;
|
||||
bool equal_curr = false;
|
||||
Halfedge_around_vertex_const_circulator first = vh->incident_halfedges();
|
||||
Halfedge_around_vertex_const_circulator curr, next;
|
||||
bool equal_curr = false;
|
||||
|
||||
next = curr = first;
|
||||
++next;
|
||||
|
|
@ -241,16 +220,14 @@ _find_face_around_vertex(Vertex_const_handle vh,
|
|||
else {
|
||||
// Traverse the halfedges around v until we find the pair of adjacent
|
||||
// halfedges such as seg is located clockwise in between them.
|
||||
typename Traits_adaptor_2::Is_between_cw_2 is_between_cw =
|
||||
m_traits->is_between_cw_2_object();
|
||||
bool eq_curr, eq_next;
|
||||
auto is_between_cw = m_traits->is_between_cw_2_object();
|
||||
bool eq_curr, eq_next;
|
||||
|
||||
while (! is_between_cw(seg, seg_dir_right, curr->curve(),
|
||||
(curr->direction() == ARR_RIGHT_TO_LEFT),
|
||||
next->curve(),
|
||||
(next->direction() == ARR_RIGHT_TO_LEFT),
|
||||
vp, eq_curr, eq_next))
|
||||
{
|
||||
vp, eq_curr, eq_next)) {
|
||||
// Break the loop if seg equals one of the halfedges next to v.
|
||||
if (eq_curr) {
|
||||
equal_curr = true;
|
||||
|
|
@ -291,10 +268,9 @@ _find_face_around_vertex(Vertex_const_handle vh,
|
|||
|
||||
// Check whether p lies on the curve associated with the edge.
|
||||
if (m_traits->is_in_x_range_2_object()(curr->curve(), p) &&
|
||||
m_traits->compare_y_at_x_2_object()(p, curr->curve()) == EQUAL)
|
||||
{
|
||||
m_traits->compare_y_at_x_2_object()(p, curr->curve()) == EQUAL) {
|
||||
// p is located on the interior of the edge.
|
||||
Halfedge_const_handle he = curr;
|
||||
Halfedge_const_handle he = curr;
|
||||
return make_result(he);
|
||||
}
|
||||
|
||||
|
|
@ -304,22 +280,18 @@ _find_face_around_vertex(Vertex_const_handle vh,
|
|||
return make_result(curr->source());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Walk from the edge to the query point.
|
||||
//
|
||||
/*! walks from the edge to the query point.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
_walk_from_edge(Halfedge_const_handle eh,
|
||||
const Point_2& np,
|
||||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const
|
||||
{
|
||||
_walk_from_edge(Halfedge_const_handle eh, const Point_2& np, const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const {
|
||||
CGAL_assertion_msg(! eh->is_fictitious(),
|
||||
"_walk_from_edge() from a fictitious edge.");
|
||||
|
||||
const X_monotone_curve_2& cv = eh->curve() ;
|
||||
Comparison_result res;
|
||||
Comparison_result res;
|
||||
|
||||
X_monotone_curve_2 seg =
|
||||
m_traits->construct_x_monotone_curve_2_object()(np, p);
|
||||
|
|
@ -345,8 +317,7 @@ _walk_from_edge(Halfedge_const_handle eh,
|
|||
if (m_traits->is_in_x_range_2_object()(seg, temp_p)) {
|
||||
//we must make sure that eh is not a tip on an "antena"
|
||||
if (m_traits->compare_y_at_x_2_object()(temp_p, seg) == EQUAL &&
|
||||
eh->prev() != eh->twin())
|
||||
{
|
||||
eh->prev() != eh->twin()) {
|
||||
// the assumption is that each edge is crossed at most twice
|
||||
CGAL_assertion_msg(crossed_edges.count(eh->prev()) < 2,
|
||||
"crossed_edges should contain each halfedge at most twice.");
|
||||
|
|
@ -367,8 +338,7 @@ _walk_from_edge(Halfedge_const_handle eh,
|
|||
if (m_traits->is_in_x_range_2_object()(seg, temp_p)) {
|
||||
//we must make sure that eh is not a tip on an "antena"
|
||||
if (m_traits->compare_y_at_x_2_object()(temp_p, seg) == EQUAL &&
|
||||
eh->next() != eh->twin())
|
||||
{
|
||||
eh->next() != eh->twin()) {
|
||||
// the assumption is that each edge is crossed at most twice
|
||||
CGAL_assertion_msg(crossed_edges.count(eh->next()) < 2,
|
||||
"crossed_edges should contain each halfedge at most twice.");
|
||||
|
|
@ -428,89 +398,71 @@ _walk_from_edge(Halfedge_const_handle eh,
|
|||
return (_walk_from_vertex(vh, p, crossed_edges));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// In case the arrangement's curve contained in the segment
|
||||
// from the nearest landmark to the query point
|
||||
//
|
||||
/*! deals with an arrangement curve contained in the segment from the nearest
|
||||
* landmark to the query point
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
_deal_with_curve_contained_in_segment(Halfedge_const_handle he,
|
||||
bool p_is_left,
|
||||
_deal_with_curve_contained_in_segment(Halfedge_const_handle he, bool p_is_left,
|
||||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const
|
||||
{
|
||||
Halfedge_set& crossed_edges) const {
|
||||
// in this case we want to walk from to the query point from the nearest
|
||||
// vertex either the halfedge's source or target
|
||||
Vertex_const_handle vh;
|
||||
bool target_is_left;
|
||||
if (m_traits->compare_xy_2_object()
|
||||
(he->source()->point(),he->target()->point()) == LARGER)
|
||||
target_is_left = true;
|
||||
else
|
||||
target_is_left = false;
|
||||
auto cmp_xy = m_traits->compare_xy_2_object();
|
||||
bool target_is_left =
|
||||
(cmp_xy(he->source()->point(), he->target()->point()) == LARGER);
|
||||
|
||||
Vertex_const_handle vh;
|
||||
if (p_is_left) {
|
||||
if (target_is_left)
|
||||
vh = he->target();
|
||||
else
|
||||
vh = he->source();
|
||||
if (target_is_left) vh = he->target();
|
||||
else vh = he->source();
|
||||
}
|
||||
else {
|
||||
if (target_is_left)
|
||||
vh = he->source();
|
||||
else
|
||||
vh = he->target();
|
||||
if (target_is_left) vh = he->source();
|
||||
else vh = he->target();
|
||||
}
|
||||
// vh is the closest vertex among the halfedge's end points
|
||||
return (_walk_from_vertex(vh, p, crossed_edges));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Walk from the given face to the query point.
|
||||
//
|
||||
/*! walks from the given face to the query point.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::result_type
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
_walk_from_face(Face_const_handle face,
|
||||
const Point_2& np,
|
||||
const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const
|
||||
{
|
||||
_walk_from_face(Face_const_handle face, const Point_2& np, const Point_2& p,
|
||||
Halfedge_set& crossed_edges) const {
|
||||
// Construct an x-monotone curve connecting the nearest landmark point np
|
||||
// to the query point p and check which CCB intersects this segment.
|
||||
X_monotone_curve_2 seg =
|
||||
m_traits->construct_x_monotone_curve_2_object()(np, p);
|
||||
const bool p_is_left =
|
||||
(m_traits->compare_xy_2_object()(np, p) == LARGER);
|
||||
X_monotone_curve_2 seg;
|
||||
Comparison_result res;
|
||||
std::tie(seg, res) = construct_segment(np, p, *m_traits, 0);
|
||||
const bool p_is_left = (res == LARGER);
|
||||
|
||||
Inner_ccb_const_iterator inner_ccb_iter;
|
||||
Outer_ccb_const_iterator outer_ccb_iter;
|
||||
const Halfedge_const_handle invalid_he;
|
||||
Halfedge_const_handle he;
|
||||
Face_const_handle new_face;
|
||||
bool is_on_edge;
|
||||
bool is_target;
|
||||
bool cv_is_contained_in_seg;
|
||||
Vertex_const_handle new_vertex;
|
||||
const Vertex_const_handle invalid_vertex;
|
||||
const Halfedge_const_handle invalid_he;
|
||||
const Vertex_const_handle invalid_vertex;
|
||||
bool cv_is_contained_in_seg;
|
||||
|
||||
do {
|
||||
// Check whether p lies inside the current face (including its holes):
|
||||
if (p_arr->topology_traits()->is_in_face(&(*face), p, nullptr))
|
||||
{
|
||||
if (p_arr->topology_traits()->is_in_face(&(*face), p, nullptr)) {
|
||||
// We know that p is located inside the current face, and we check
|
||||
// whether it lies inside one of its holes (or on the boundary of
|
||||
// its holes).
|
||||
cv_is_contained_in_seg = false;
|
||||
new_face = face;
|
||||
for (inner_ccb_iter = face->inner_ccbs_begin();
|
||||
inner_ccb_iter != face->inner_ccbs_end(); ++inner_ccb_iter)
|
||||
{
|
||||
he = _intersection_with_ccb(*inner_ccb_iter,seg, p, p_is_left,
|
||||
crossed_edges,is_on_edge, is_target,
|
||||
cv_is_contained_in_seg,new_vertex);
|
||||
if (he == invalid_he && cv_is_contained_in_seg)
|
||||
{
|
||||
auto new_face = face;
|
||||
// Do not use 'auto' to define the iterator, as MSVC2017 complains.
|
||||
for (Inner_ccb_const_iterator inner_ccb_iter = face->inner_ccbs_begin();
|
||||
inner_ccb_iter != face->inner_ccbs_end(); ++inner_ccb_iter) {
|
||||
bool is_on_edge;
|
||||
bool is_target;
|
||||
Vertex_const_handle new_vertex;
|
||||
Halfedge_const_handle he =
|
||||
_intersection_with_ccb(*inner_ccb_iter,seg, p, p_is_left,
|
||||
crossed_edges, is_on_edge, is_target,
|
||||
cv_is_contained_in_seg, new_vertex);
|
||||
if (he == invalid_he && cv_is_contained_in_seg) {
|
||||
return _deal_with_curve_contained_in_segment(*inner_ccb_iter,
|
||||
p_is_left,p,
|
||||
crossed_edges);
|
||||
|
|
@ -535,8 +487,7 @@ _walk_from_face(Face_const_handle face,
|
|||
|
||||
// Check if we found a new face (hole) containing p. If not, the current
|
||||
// face contains p.
|
||||
if (new_face == face)
|
||||
return make_result(face);
|
||||
if (new_face == face) return make_result(face);
|
||||
|
||||
// Continue from the new face (hole).
|
||||
face = new_face;
|
||||
|
|
@ -544,13 +495,17 @@ _walk_from_face(Face_const_handle face,
|
|||
else {
|
||||
// We know that p is not located inside the current face. We therefore
|
||||
// look for an edge on its outer boundary that intersects seg.
|
||||
new_face = face;
|
||||
for (outer_ccb_iter = face->outer_ccbs_begin();
|
||||
outer_ccb_iter != face->outer_ccbs_end(); ++outer_ccb_iter)
|
||||
{
|
||||
he = _intersection_with_ccb(*outer_ccb_iter,seg, p, p_is_left,
|
||||
crossed_edges,is_on_edge, is_target,
|
||||
cv_is_contained_in_seg,new_vertex);
|
||||
auto new_face = face;
|
||||
// Do not use 'auto' to define the iterator, as MSVC2017 complains.
|
||||
for (Inner_ccb_const_iterator outer_ccb_iter = face->outer_ccbs_begin();
|
||||
outer_ccb_iter != face->outer_ccbs_end(); ++outer_ccb_iter) {
|
||||
bool is_on_edge;
|
||||
bool is_target;
|
||||
Vertex_const_handle new_vertex;
|
||||
Halfedge_const_handle he =
|
||||
_intersection_with_ccb(*outer_ccb_iter,seg, p, p_is_left,
|
||||
crossed_edges, is_on_edge, is_target,
|
||||
cv_is_contained_in_seg, new_vertex);
|
||||
if (he == invalid_he && cv_is_contained_in_seg) {
|
||||
return _deal_with_curve_contained_in_segment(*outer_ccb_iter,
|
||||
p_is_left,p,
|
||||
|
|
@ -585,10 +540,9 @@ _walk_from_face(Face_const_handle face,
|
|||
return default_result();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Find a halfedge on the given CCB that intersects the given x-monotone
|
||||
// curve, connecting the current landmark to the query point.
|
||||
//
|
||||
/*! finds a halfedge on the given CCB that intersects the given x-monotone
|
||||
* curve, connecting the current landmark to the query point.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
typename Arr_landmarks_point_location<Arr, Gen>::Halfedge_const_handle
|
||||
Arr_landmarks_point_location<Arr, Gen>::
|
||||
|
|
@ -598,17 +552,15 @@ _intersection_with_ccb(Ccb_halfedge_const_circulator circ,
|
|||
Halfedge_set& crossed_edges,
|
||||
bool& is_on_edge, bool& is_target,
|
||||
bool& cv_is_contained_in_seg,
|
||||
Vertex_const_handle & new_vertex) const
|
||||
{
|
||||
Vertex_const_handle& new_vertex) const {
|
||||
is_on_edge = false;
|
||||
is_target = false;
|
||||
|
||||
// Go over the CCB.
|
||||
typename Traits_adaptor_2::Is_in_x_range_2 is_in_x_range =
|
||||
m_traits->is_in_x_range_2_object();
|
||||
Ccb_halfedge_const_circulator curr = circ , temp_circ;
|
||||
const Halfedge_const_handle invalid_he;
|
||||
Halfedge_const_handle he;
|
||||
auto is_in_x_range = m_traits->is_in_x_range_2_object();
|
||||
Ccb_halfedge_const_circulator curr = circ , temp_circ;
|
||||
const Halfedge_const_handle invalid_he;
|
||||
Halfedge_const_handle he;
|
||||
bool cv_and_seg_overlap;
|
||||
do {
|
||||
he = curr;
|
||||
|
|
@ -646,33 +598,28 @@ _intersection_with_ccb(Ccb_halfedge_const_circulator circ,
|
|||
// Check whether the current curve intersects seg an odd number of times.
|
||||
if (_have_odd_intersections(he->curve(), seg, p_is_left,
|
||||
is_on_edge,cv_and_seg_overlap,
|
||||
cv_is_contained_in_seg)
|
||||
&& !(cv_and_seg_overlap || cv_is_contained_in_seg))
|
||||
{
|
||||
cv_is_contained_in_seg) &&
|
||||
! (cv_and_seg_overlap || cv_is_contained_in_seg)) {
|
||||
// Check if the query point lies on the current edge, or whether
|
||||
// it lies in its interior.
|
||||
if (is_on_edge)
|
||||
return _in_case_p_is_on_edge(he,crossed_edges,p,is_target);
|
||||
|
||||
if ((!curr->target()->is_at_open_boundary()) &&
|
||||
is_in_x_range(seg, curr->target()->point()))
|
||||
{
|
||||
is_in_x_range(seg, curr->target()->point())) {
|
||||
// if the target point of curr is located on seg
|
||||
// we should walk from it to the query point
|
||||
if (m_traits->compare_y_at_x_2_object()
|
||||
(curr->target()->point(), seg) == EQUAL)
|
||||
{
|
||||
(curr->target()->point(), seg) == EQUAL) {
|
||||
new_vertex = curr->target();
|
||||
}
|
||||
}
|
||||
else if ((!curr->source()->is_at_open_boundary()) &&
|
||||
is_in_x_range(seg , curr->source()->point() ))
|
||||
{
|
||||
is_in_x_range(seg , curr->source()->point())) {
|
||||
// if the source point of curr is located on seg
|
||||
// we should walk from it to the query point
|
||||
if (m_traits->compare_y_at_x_2_object()
|
||||
(curr->source()->point() , seg) == EQUAL)
|
||||
{
|
||||
(curr->source()->point(), seg) == EQUAL) {
|
||||
new_vertex = curr->source();
|
||||
}
|
||||
}
|
||||
|
|
@ -718,8 +665,7 @@ Arr_landmarks_point_location<Arr, Gen>::
|
|||
_in_case_p_is_on_edge(Halfedge_const_handle he,
|
||||
Halfedge_set& crossed_edges,
|
||||
const Point_2 & p,
|
||||
bool & is_target) const
|
||||
{
|
||||
bool & is_target) const {
|
||||
// cv and seg overlap, obviously we crossed it
|
||||
// the assumption is that each edge is crossed at most twice
|
||||
CGAL_assertion_msg(crossed_edges.count(he) < 2,
|
||||
|
|
@ -728,14 +674,12 @@ _in_case_p_is_on_edge(Halfedge_const_handle he,
|
|||
crossed_edges.insert(he->twin());
|
||||
// Check if p equals one of the edge end-vertices.
|
||||
if (! he->target()->is_at_open_boundary() &&
|
||||
m_traits->compare_xy_2_object()(he->target()->point(), p) == EQUAL)
|
||||
{
|
||||
m_traits->equal_2_object()(he->target()->point(), p)) {
|
||||
// p is the target of the current halfedge.
|
||||
is_target = true;
|
||||
}
|
||||
else if (! he->source()->is_at_open_boundary() &&
|
||||
m_traits->compare_xy_2_object()(he->source()->point(), p) == EQUAL)
|
||||
{
|
||||
m_traits->equal_2_object()(he->source()->point(), p)) {
|
||||
// Take the twin halfedge, so p equals its target.
|
||||
he = he->twin();
|
||||
is_target = true;
|
||||
|
|
@ -744,21 +688,17 @@ _in_case_p_is_on_edge(Halfedge_const_handle he,
|
|||
return he;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Check whether the given curve intersects a simple segment, which connects
|
||||
// the current landmark to the query point, an odd number of times.
|
||||
//
|
||||
/*! checks whether the given curve intersects a simple segment, which connects
|
||||
* the current landmark to the query point, an odd number of times.
|
||||
*/
|
||||
template <typename Arr, typename Gen>
|
||||
bool Arr_landmarks_point_location<Arr, Gen>::
|
||||
_have_odd_intersections(const X_monotone_curve_2& cv,
|
||||
const X_monotone_curve_2& seg,
|
||||
bool p_is_left,
|
||||
bool& p_on_curve,
|
||||
bool p_is_left, bool& p_on_curve,
|
||||
bool& cv_and_seg_overlap,
|
||||
bool& cv_is_contained_in_seg) const
|
||||
{
|
||||
typename Traits_adaptor_2::Is_in_x_range_2 is_in_x_range =
|
||||
m_traits->is_in_x_range_2_object();
|
||||
bool& cv_is_contained_in_seg) const {
|
||||
auto is_in_x_range = m_traits->is_in_x_range_2_object();
|
||||
p_on_curve = false;
|
||||
cv_and_seg_overlap = false;
|
||||
cv_is_contained_in_seg = false;
|
||||
|
|
@ -776,9 +716,9 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
cv_right = m_traits->construct_max_vertex_2_object()(cv);
|
||||
if (cv_left_is_closed && cv_right_is_closed) {
|
||||
if (is_in_x_range(seg,cv_left) && is_in_x_range(seg,cv_right)) {
|
||||
if ((m_traits->compare_y_at_x_2_object()(cv_left, seg) == EQUAL) &&
|
||||
(m_traits->compare_y_at_x_2_object()(cv_right, seg) == EQUAL))
|
||||
{
|
||||
auto cmp_y_at_x = m_traits->compare_y_at_x_2_object();
|
||||
if ((cmp_y_at_x(cv_left, seg) == EQUAL) &&
|
||||
(cmp_y_at_x(cv_right, seg) == EQUAL)) {
|
||||
// cv is contained in seg non of the answer true or false is correct
|
||||
// we must set a special flag to distinguish this case
|
||||
cv_is_contained_in_seg = true;
|
||||
|
|
@ -791,22 +731,17 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
if (cv_left_is_closed) {
|
||||
// Check if the left endpoint of cv has the same x-coordinate as the
|
||||
// right endpoint of seg.
|
||||
if (m_traits->compare_x_2_object()
|
||||
(m_traits->construct_min_vertex_2_object()(cv), seg_right) == EQUAL)
|
||||
{
|
||||
if (! p_is_left &&
|
||||
m_traits->compare_xy_2_object()
|
||||
(m_traits->construct_min_vertex_2_object()(cv), seg_right) == EQUAL)
|
||||
{
|
||||
auto min_p = m_traits->construct_min_vertex_2_object()(cv);
|
||||
if (equal_x_2(min_p, seg_right, Left_or_right_sides_category())) {
|
||||
if (! p_is_left && m_traits->equal_2_object()(min_p, seg_right)) {
|
||||
p_on_curve = true;
|
||||
return true;
|
||||
}
|
||||
else if (m_traits->is_vertical_2_object()(seg)) {
|
||||
auto cmp_y_at_x = m_traits->compare_y_at_x_2_object();
|
||||
// Special treatment for vertical segments.
|
||||
Comparison_result res_l =
|
||||
m_traits->compare_y_at_x_2_object()(seg_left, cv);
|
||||
Comparison_result res_r =
|
||||
m_traits->compare_y_at_x_2_object()(seg_right, cv);
|
||||
Comparison_result res_l = cmp_y_at_x(seg_left, cv);
|
||||
Comparison_result res_r = cmp_y_at_x(seg_right, cv);
|
||||
if ((p_is_left && res_l == EQUAL) || (! p_is_left && res_r == EQUAL)) {
|
||||
p_on_curve = true;
|
||||
return true;
|
||||
|
|
@ -819,23 +754,17 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
if (cv_right_is_closed) {
|
||||
// Check if the right endpoint of cv has the same x-coordinate as the
|
||||
// left endpoint of seg.
|
||||
if (m_traits->compare_x_2_object()
|
||||
(m_traits->construct_max_vertex_2_object()(cv), seg_left) == EQUAL)
|
||||
{
|
||||
if (p_is_left &&
|
||||
m_traits->compare_xy_2_object()
|
||||
(m_traits->construct_max_vertex_2_object()(cv), seg_left) == EQUAL)
|
||||
{
|
||||
auto max_p = m_traits->construct_max_vertex_2_object()(cv);
|
||||
if (equal_x_2(max_p, seg_left, Left_or_right_sides_category())) {
|
||||
if (p_is_left && m_traits->equal_2_object()(max_p, seg_left)) {
|
||||
p_on_curve = true;
|
||||
return true;
|
||||
}
|
||||
else if (m_traits->is_vertical_2_object()(seg)) {
|
||||
// Special treatment for vertical segments.
|
||||
Comparison_result res_l =
|
||||
m_traits->compare_y_at_x_2_object()(seg_left, cv);
|
||||
Comparison_result res_r =
|
||||
m_traits->compare_y_at_x_2_object()(seg_right, cv);
|
||||
|
||||
auto cmp_y_at_x = m_traits->compare_y_at_x_2_object();
|
||||
Comparison_result res_l = cmp_y_at_x(seg_left, cv);
|
||||
Comparison_result res_r = cmp_y_at_x(seg_right, cv);
|
||||
if ((p_is_left && res_l == EQUAL) || (! p_is_left && res_r == EQUAL)) {
|
||||
p_on_curve = true;
|
||||
return true;
|
||||
|
|
@ -846,8 +775,8 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
}
|
||||
}
|
||||
// Compare the two left ends of cv and seg.
|
||||
Comparison_result left_res;
|
||||
const Arr_parameter_space bx_l =
|
||||
Comparison_result left_res;
|
||||
const Arr_parameter_space bx_l =
|
||||
m_traits->parameter_space_in_x_2_object()(cv, ARR_MIN_END);
|
||||
if (bx_l == ARR_LEFT_BOUNDARY) {
|
||||
// The left end of cv lies to the left of seg_left:
|
||||
|
|
@ -858,11 +787,11 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
// The left end of cv lies to the right of seg_left.
|
||||
// Compare the left endpoint of cv to seg.
|
||||
left_res = m_traits->compare_y_at_x_2_object()
|
||||
(m_traits->construct_min_vertex_2_object()(cv), seg);
|
||||
(m_traits->construct_min_vertex_2_object()(cv), seg);
|
||||
left_res = CGAL::opposite(left_res);
|
||||
}
|
||||
else {
|
||||
const Arr_parameter_space by_l =
|
||||
const Arr_parameter_space by_l =
|
||||
m_traits->parameter_space_in_y_2_object()(cv, ARR_MIN_END);
|
||||
if (by_l == ARR_BOTTOM_BOUNDARY)
|
||||
// The left end of cv is at y = -oo, so cv obviously lies above it.
|
||||
|
|
@ -876,8 +805,7 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
Comparison_result res = m_traits->compare_xy_2_object()(cv_left, seg_left);
|
||||
if (res != LARGER) {
|
||||
left_res = m_traits->compare_y_at_x_2_object()(seg_left, cv);
|
||||
if (p_is_left && left_res == EQUAL)
|
||||
{
|
||||
if (p_is_left && left_res == EQUAL) {
|
||||
// In this case the query point p, which is the left endpoint of seg,
|
||||
// lies on cv.
|
||||
p_on_curve = true;
|
||||
|
|
@ -904,8 +832,7 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
// we must set a special flag to distinguish this case
|
||||
if (is_in_x_range(cv,( p_is_left ? seg_left : seg_right)))
|
||||
if (m_traits->compare_y_at_x_2_object()
|
||||
((p_is_left ? seg_left : seg_right), cv) == EQUAL)
|
||||
{
|
||||
((p_is_left ? seg_left : seg_right), cv) == EQUAL) {
|
||||
p_on_curve = true;
|
||||
}
|
||||
cv_and_seg_overlap = true;
|
||||
|
|
@ -913,8 +840,8 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
}
|
||||
}
|
||||
// Compare the two right ends of cv and seg.
|
||||
Comparison_result right_res;
|
||||
const Arr_parameter_space bx_r =
|
||||
Comparison_result right_res;
|
||||
const Arr_parameter_space bx_r =
|
||||
m_traits->parameter_space_in_x_2_object()(cv, ARR_MAX_END);
|
||||
if (bx_r == ARR_RIGHT_BOUNDARY) {
|
||||
// The right end of cv lies to the right of seg_right:
|
||||
|
|
@ -925,11 +852,11 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
// The right end of cv lies to the left of seg_right.
|
||||
// Compare the right endpoint of cv to seg.
|
||||
right_res = m_traits->compare_y_at_x_2_object()
|
||||
(m_traits->construct_max_vertex_2_object()(cv), seg);
|
||||
(m_traits->construct_max_vertex_2_object()(cv), seg);
|
||||
right_res = CGAL::opposite(right_res);
|
||||
}
|
||||
else {
|
||||
const Arr_parameter_space by_r =
|
||||
const Arr_parameter_space by_r =
|
||||
m_traits->parameter_space_in_y_2_object()(cv, ARR_MAX_END);
|
||||
if (by_r == ARR_BOTTOM_BOUNDARY)
|
||||
// The right end of cv is at y = -oo, so cv obviously lies above it.
|
||||
|
|
@ -972,8 +899,7 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
// we must set a special flag to distinguish this case
|
||||
if (is_in_x_range(cv, (p_is_left ? seg_left : seg_right)))
|
||||
if (m_traits->compare_y_at_x_2_object()
|
||||
((p_is_left ? seg_left : seg_right), cv) == EQUAL)
|
||||
{
|
||||
((p_is_left ? seg_left : seg_right), cv) == EQUAL) {
|
||||
p_on_curve = true;
|
||||
}
|
||||
cv_and_seg_overlap = true;
|
||||
|
|
@ -986,6 +912,6 @@ _have_odd_intersections(const X_monotone_curve_2& cv,
|
|||
return (left_res != right_res);
|
||||
}
|
||||
|
||||
} //namespace CGAL
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ public:
|
|||
NUMBER_OF_OPERATIONS
|
||||
};
|
||||
|
||||
private:
|
||||
using Base = BaseTraits;
|
||||
|
||||
private:
|
||||
//! A set of bits that indicate whether operations should be traced.
|
||||
unsigned long long m_flags;
|
||||
|
||||
|
|
@ -833,9 +833,16 @@ public:
|
|||
std::cout << "approximate_2" << std::endl
|
||||
<< " xcv: " << xcv << ", error: " << error
|
||||
<< ", l2r: " << l2r << std::endl;
|
||||
auto res = m_object(xcv, error, oi, l2r);
|
||||
std::cout << " result: " << res << std::endl;
|
||||
return res;
|
||||
std::list<Approximate_point_2> container;
|
||||
m_object(xcv, error, std::back_inserter(container), l2r);
|
||||
if (container.empty()) return oi;
|
||||
|
||||
std::size_t i = 0;
|
||||
for (const auto& point : container) {
|
||||
std::cout << " result[" << i++ << "]: " << point << std::endl;
|
||||
*oi++ = point;
|
||||
}
|
||||
return oi;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
### [2D Arrangements](https://doc.cgal.org/6.1/Manual/packages.html#PkgArrangementOnSurface2)
|
||||
|
||||
- Introduces two traits decorators, namely `Arr_tracing_traits_2` and `Arr_counting_traits_2`, which can be used to extract debugging and informative metadata about the traits in use while a program is being executed.
|
||||
- Fixed the Landmark point-location strategy so that it can be applied to arrangements on a sphere.
|
||||
|
||||
## [Release 6.0.1](https://github.com/CGAL/cgal/releases/tag/v6.0.1)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue