started refactorization of sign of ccb computations

- introduced _compute_signs_and_local_minima
- enhanced _defines_outer_ccb_of_new_face with local-minima-range
-- it also computes the global leftmost vertex of a ccb
cd >> both are based on now deprecated _find_leftmost_vertex_on_open_loop function
- introduced m_topol_traits.let_me_decide_the_outer_ccb
- rename prev1_before_prev2 -> prev1_on_outer_ccb_and_not_prev2
- added TODOs for _insert_at_vertices and (_)remove_edge
- missing: to-cv-away semantics in some functions
- TODO remove std::couts
- TODO some documentation
* all tests work
This commit is contained in:
Eric Berberich 2012-07-27 01:26:41 +00:00
parent 9374a140e2
commit a7d3ff0f22
5 changed files with 697 additions and 57 deletions

View File

@ -520,6 +520,11 @@ public:
Arr_parameter_space ps_x,
Arr_parameter_space ps_y);
bool let_me_decide_the_outer_ccb(std::pair< CGAL::Sign, CGAL::Sign> signs1,
std::pair< CGAL::Sign, CGAL::Sign> signs2,
bool& prev1_on_outer_ccb_and_not_prev2) const;
/*! Given two predecessor halfedges that belong to the same inner CCB of
* a face, determine what happens when we insert an edge connecting the
* target vertices of the two edges.

View File

@ -160,6 +160,15 @@ public:
return;
}
// TODO document
bool let_me_decide_the_outer_ccb(std::pair< CGAL::Sign, CGAL::Sign> signs1,
std::pair< CGAL::Sign, CGAL::Sign> signs2,
bool& prev1_on_outer_ccb_and_not_prev2) const {
prev1_on_outer_ccb_and_not_prev2 = false;
return false;
}
/*!
* Given two predecessor halfedges that belong to the same inner CCB of
* a face, determine what happens when we insert an edge connecting the
@ -285,7 +294,6 @@ public:
return (false);
}
#if CGAL_ARRANGEMENT_ON_SURFACE_INSERT_VERBOSE || CGAL_NEW_FACE_SPLIT_STRATEGY
/*!
* Computes the sign of two halfedges approaching and leaving the

View File

@ -482,6 +482,27 @@ notify_on_boundary_vertex_creation(Vertex* v,
m_boundary_vertices.insert(Vertex_value(key, v));
}
template <class GeomTraits, class Dcel>
bool
Arr_spherical_topology_traits_2<GeomTraits, Dcel>::
let_me_decide_the_outer_ccb(std::pair< CGAL::Sign, CGAL::Sign> signs1,
std::pair< CGAL::Sign, CGAL::Sign> signs2,
bool& prev1_on_outer_ccb_and_not_prev2) const {
CGAL_precondition(signs1.second == CGAL::ZERO); // no perimetric in top-bottom for first loop
CGAL_precondition(signs2.second == CGAL::ZERO); // no perimetric in top-bottom for second loop
// choose prev1 to define outer ccb of new face if it is a non-perimetric loop,
// otherwise choose prev2
// TODO what if both are non-zero?
prev1_on_outer_ccb_and_not_prev2 = (signs1.first == CGAL::ZERO);
// but only if the at least one of the loops is perimetric, otherwise return false
// to let leftmost-vertex decide which becomes part of the new outer ccb
return signs1.first != CGAL::ZERO || signs2.first != CGAL::ZERO;
}
/*! \brief given a curve end with boundary conditions and a face that contains
* the interior of the curve, find a place for a boundary vertex that will
* represent the curve end along the face boundary */

View File

@ -1,4 +1,4 @@
// Copyright (c) 2005,2006,2007,2008,2009,2010,2011 Tel-Aviv University (Israel).
// Copyright (c) 2005,2006,2007,2008,2009,2010,2011,2012 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
@ -18,7 +18,7 @@
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// Efi Fogel <efif@post.tau.ac.il>
// Eric Berberich <ericb@post.tau.ac.il>
// Eric Berberich <eric.berberich@cgal.org>
// (based on old version by: Iddo Hanniel,
// Eyal Flato,
// Oren Nechushtan,
@ -1356,8 +1356,7 @@ insert_at_vertices(const X_monotone_curve_2& cv,
DInner_ccb* hole2 =
(p_prev2->is_on_inner_ccb()) ? p_prev2->inner_ccb() : NULL;
// TODO think of a better name
bool prev1_before_prev2 = true;
bool prev1_on_outer_ccb_and_not_prev2 = true;
if ((hole1 == hole2) && (hole1 != NULL)) {
// If prev1 and prev2 are on different components, the insertion of the
@ -1374,54 +1373,86 @@ insert_at_vertices(const X_monotone_curve_2& cv,
// inside the new face we are about to create (or alternatively, whether
// prev2 does not lie inside this new face).
// TODO EBEB 2012-07-26 activate this code
#if 0
// TODO combine length, signs and local_mins into one struct
std::list< std::pair< DHalfedge*, unsigned int > > local_mins1;
std::pair< CGAL::Sign, CGAL::Sign > signs1 = _compute_signs_and_local_minima(p_prev1, p_prev2, cv, (res == CGAL::SMALLER ? CGAL::ARR_MIN_END : CGAL::ARR_MAX_END), std::inserter(local_mins1));
#if 1
// TODO EBEB 2012-07-26 the following code enables optimizations:
// - avoid length-test
// - search only local minima to find leftmost vertex
// - re-use of signs of ccbs
Arr_halfedge_direction cv_dir1 =
(res == CGAL::SMALLER ? CGAL::ARR_LEFT_TO_RIGHT : CGAL::ARR_RIGHT_TO_LEFT);
std::list< std::pair< const DHalfedge*, int > > local_mins1;
std::pair< CGAL::Sign, CGAL::Sign > signs1 =
_compute_signs_and_local_minima(p_prev1,
cv, cv_dir1,
p_prev2->next(),
std::front_inserter(local_mins1));
// TODO replace ARR_MIN/MAX_ENX with ARR_LEFT_TO_RIGHT/RIGHT_TO_LEFT
std::list< std::pair< DHalfedge*, unsigned int > > local_mins2;
std::pair< CGAL::Sign, CGAL::Sign > signs2 = _compute_signs_and_local_minima(p_prev2, p_prev1, cv, (res == CGAL::GREATER ? CGAL::ARR_MIN_END : CGAL::ARR_MAX_END), std::inserter(local_mins2));
Arr_halfedge_direction cv_dir2 =
(res == CGAL::SMALLER ? CGAL::ARR_RIGHT_TO_LEFT : CGAL::ARR_LEFT_TO_RIGHT);
std::list< std::pair< const DHalfedge*, int > > local_mins2;
std::pair< CGAL::Sign, CGAL::Sign > signs2 =
_compute_signs_and_local_minima(p_prev2,
cv, cv_dir2,
p_prev1->next(),
std::front_inserter(local_mins2));
if (!m_topol_traits.is_perimetric(signs1, signs2,
prev1_before_prev2 /* will be set if perimetric */)) {
std::cout << "signs1.x: " << signs1.first << std::endl;
std::cout << "signs1.y: " << signs1.second << std::endl;
std::cout << "signs2.x: " << signs2.first << std::endl;
std::cout << "signs2.y: " << signs2.second << std::endl;
std::cout << "#local_mins1: " << local_mins1.size() << std::endl;
std::cout << "#local_mins2: " << local_mins2.size() << std::endl;
if (!m_topol_traits.let_me_decide_the_outer_ccb(signs1, signs2,
/* prev1_on .. will be set if true is returned */
prev1_on_outer_ccb_and_not_prev2)) {
// COMMENT: The previous solution needed O(min(length1, length2)) steps to determine
// which path is shorter and the search for the leftmost vertex on a path
// needs O(#local_mins) geometric comparison.
// This solution saves the initial loop to determine the shorter path and will only
// need O(min(#local_mins1, #local_mins2)) geometric comparisons to determine
// the leftmost vertex on a path.
prev1_before_prev2 = (local_mins1.size() < local_mins2.size()) ?
( _defines_outer_ccb_of_new_face(p_prev1, p_prev2, cv,
local_mins1.begin(), local_mins1.end())) :
(! _defines_outer_ccb_of_new_face(p_prev2, p_prev1, cv,
local_mins2.begin(), local_mins2.end()));
// which path is shorter and the search for the leftmost vertex on a path
// needs O(#local_mins) geometric comparison.
// This solution saves the initial loop to determine the shorter path and
// will only need O(min(#local_mins1, #local_mins2)) geometric comparisons
// to determine the leftmost vertex on a path.
bool cond = (local_mins1.size() > 0 && (local_mins1.size() < local_mins2.size()));
prev1_on_outer_ccb_and_not_prev2 =
(cond ?
( _defines_outer_ccb_of_new_face(p_prev1, p_prev2, cv, cv_dir1,
// local_mins2 looks wrong,
// but the first part of the signature
// and the second part of the function-body
// do not (yet) have to-cv-away semantics!
local_mins2.begin(), local_mins2.end()
))
:
(! _defines_outer_ccb_of_new_face(p_prev2, p_prev1, cv, cv_dir2,
// local_mins1 looks wrong,
// but the first part of the signature
// and the second part of the function-body
// do not (yet) have to-cv-away semantics!
local_mins1.begin(), local_mins1.end()
))
);
}
// TODO
// - enhance _defines_outer_ccb_of_new_face with local_mins parameter
// - implement find_leftmost_vertex by using cv + local_mins parameter
// - implement toptraits.is_perimetric
#else
Comparison_result path_res = _compare_induced_path_length(p_prev1, p_prev2);
prev1_before_prev2 = (path_res == LARGER) ?
(_defines_outer_ccb_of_new_face(p_prev1, p_prev2, cv)) :
(! _defines_outer_ccb_of_new_face(p_prev2, p_prev1, cv));
prev1_on_outer_ccb_and_not_prev2 =
((path_res == LARGER) ?
( _defines_outer_ccb_of_new_face(p_prev1, p_prev2, cv)) :
(! _defines_outer_ccb_of_new_face(p_prev2, p_prev1, cv))
);
#endif
}
// We already have the comparsion result of the target vertices of prev1
// and prev2. If however we swap the order of the halfedges, we take the
// opposite comparison result.
if (! prev1_before_prev2)
if (! prev1_on_outer_ccb_and_not_prev2)
res = CGAL::opposite(res);
// Perform the insertion.
bool new_face_created = false;
DHalfedge* new_he = (prev1_before_prev2) ?
DHalfedge* new_he = (prev1_on_outer_ccb_and_not_prev2) ?
// TODO EBEB 2012-07-27 forward signs1/2 of ccbs to _insert_at_vertices to simplify
// the implementation of face_split_after_edge_insertion and boundaries_of_same_face
_insert_at_vertices(cv, p_prev1, p_prev2, res, new_face_created) :
_insert_at_vertices(cv, p_prev2, p_prev1, res, new_face_created);
@ -1435,7 +1466,7 @@ insert_at_vertices(const X_monotone_curve_2& cv,
// Return a handle to the new halfedge directed from prev1's target to
// prev2's target. Note that this may be the twin halfedge of the one
// returned by _insert_at_vertices();
if (! prev1_before_prev2)
if (! prev1_on_outer_ccb_and_not_prev2)
new_he = new_he->opposite();
return (Halfedge_handle(new_he));
@ -1799,6 +1830,9 @@ remove_edge(Halfedge_handle e, bool remove_source, bool remove_target)
return Face_handle(f);
}
// TODO EBEB 2012 use _compute_signs_and_local_minima ...
// ... then extract code to compute global minimum from _defines_outer_ccb_of_new_face and finally ...
// In this case one of the following can happen: (a) a new hole will be
// created by the removal of the edge (case 3.2.1 of the removal
// procedure), or (b) an outer CCB will be split into two (case 3.2.2).
@ -1872,12 +1906,15 @@ remove_edge(Halfedge_handle e, bool remove_source, bool remove_target)
// boundary side of the parameter space), then the other path becomes
// a hole in a face bounded by the parameter-space boundary.
// EBEB 2012-07-25 the following "line" is very hard to pare by a human-being
// TODO EBEB 2012-07-25 the following "line" is very hard to pare by a human-being
// simplify to just have a call for
// _remove_edge(he1, remove_source, remove_target)
// and a call for
// _remove_edge(he2, remove_target, remove_target)
// TODO EBEB 2012-07-27 ... forward signs of ccbs to _remove_edge to simplify
// the implementation of hole_creation_after_edge_removal
DFace* f = (ind_min1 > ind_min2) ?
_remove_edge(he1, remove_source, remove_target) :
((ind_min1 < ind_min2) ?
@ -3354,6 +3391,283 @@ _is_diff(Arr_parameter_space ps_x_min, Arr_parameter_space ps_y_min,
return ((ps_x_ver != ps_x_min) || (ps_y_ver != ps_y_min));
}
//
// The function assumes that the two ccb created from single inner
// ccb when inserting cv have already been close. The tuple
// (he_to, cv, ind, he_away) is a subsequence of one of the resulting
// ones. The function is also called for a tuple indicating the other
// ccb.
template <typename GeomTraits, typename TopTraits>
template <typename OutputIterator>
std::pair< CGAL::Sign, CGAL::Sign >
Arrangement_on_surface_2<GeomTraits, TopTraits>::
_compute_signs_and_local_minima(const DHalfedge* he_to,
const X_monotone_curve_2& cv,
Arr_halfedge_direction cv_dir,
const DHalfedge* he_away,
OutputIterator local_mins_it) const
{
// std::cout << "he_to: " << he_to->opposite()->vertex()->point()
// << " => " << he_to->vertex()->point() << std::endl;
// std::cout << "he_away: " << he_away->opposite()->vertex()->point()
// << " => " << he_away->vertex()->point() << std::endl;
// We go over the sequence of vertices, starting from he_before's target
// vertex, until reaching he_after's source vertex, and find the leftmost
// one. Note that we do this carefully, keeping track of the number of
// times we crossed the identification curve in x or in y (if they exist).
// Note that the path must not be incident to any vertex on open boundary.
typename Traits_adaptor_2::Parameter_space_in_x_2 parameter_space_in_x =
m_geom_traits->parameter_space_in_x_2_object();
typename Traits_adaptor_2::Parameter_space_in_y_2 parameter_space_in_y =
m_geom_traits->parameter_space_in_y_2_object();
typename Traits_adaptor_2::Compare_y_at_x_right_2 compare_y_at_x_right_2 =
m_geom_traits->compare_y_at_x_right_2_object();
unsigned int x_cross_count = 0;
int x_index = 0;
unsigned int y_cross_count = 0;
int y_index = 0;
const DHalfedge* he = he_to;
// We need to determine which one of the 2 ends of cv matches the target
// of he.
// First obtain the parameter space pair of the target of he.
Arr_parameter_space ps_x_ver, ps_y_ver;
if (he->direction() == ARR_LEFT_TO_RIGHT) {
ps_x_ver = parameter_space_in_x(he->curve(), ARR_MAX_END);
ps_y_ver = parameter_space_in_y(he->curve(), ARR_MAX_END);
}
else {
ps_x_ver = parameter_space_in_x(he->curve(), ARR_MIN_END);
ps_y_ver = parameter_space_in_y(he->curve(), ARR_MIN_END);
}
// Obtain the parameter space pair of cv.
Arr_parameter_space ps_x_cv_min = parameter_space_in_x(cv, ARR_MIN_END);
Arr_parameter_space ps_y_cv_min = parameter_space_in_y(cv, ARR_MIN_END);
Arr_parameter_space ps_x_cv_max = parameter_space_in_x(cv, ARR_MAX_END);
Arr_parameter_space ps_y_cv_max = parameter_space_in_y(cv, ARR_MAX_END);
Arr_parameter_space ps_x, ps_y;
Arr_parameter_space ps_x_end;
// Determine the match and set the parameter space pairs accordingly.
if (_is_diff(ps_x_cv_min, ps_y_cv_min,
m_geom_traits->construct_max_vertex_2_object()(cv),
ps_x_cv_max, ps_y_cv_max,
he->vertex()->point(), ps_x_ver, ps_y_ver))
{
ps_x = ps_x_cv_max;
ps_y = ps_y_cv_max;
ps_x_end = ps_x_cv_min;
}
else {
ps_x = ps_x_cv_min;
ps_y = ps_y_cv_min;
ps_x_end = ps_x_cv_max;
}
// Handle the first halfedge.
CGAL_assertion(!is_open(ps_x, ps_y));
Arr_parameter_space ps_x_next, ps_y_next;
Arr_parameter_space ps_x_save, ps_y_save;
// In case this he->next() is the "after" halfegde, use the boundary
// conditions of the proper curve-end of cv. Otherwise, use the boundary
// conditions of the curve associated with he->next().
if (he->next()->direction() == ARR_LEFT_TO_RIGHT) {
ps_x_next = parameter_space_in_x(he->next()->curve(), ARR_MIN_END);
ps_y_next = parameter_space_in_y(he->next()->curve(), ARR_MIN_END);
ps_x_save = parameter_space_in_x(he->next()->curve(), ARR_MAX_END);
ps_y_save = parameter_space_in_y(he->next()->curve(), ARR_MAX_END);
}
else {
ps_x_next = parameter_space_in_x(he->next()->curve(), ARR_MAX_END);
ps_y_next = parameter_space_in_y(he->next()->curve(), ARR_MAX_END);
ps_x_save = parameter_space_in_x(he->next()->curve(), ARR_MIN_END);
ps_y_save = parameter_space_in_y(he->next()->curve(), ARR_MIN_END);
}
if ((ps_x == ARR_LEFT_BOUNDARY) && (ps_x_next == ARR_RIGHT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
--x_index;
}
else if ((ps_x == ARR_RIGHT_BOUNDARY) && (ps_x_next == ARR_LEFT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
++x_index;
}
// Check if we cross the identification curve in y.
if ((ps_y == ARR_BOTTOM_BOUNDARY) && (ps_y_next == ARR_TOP_BOUNDARY)) {
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
--y_index;
}
else if ((ps_y == ARR_TOP_BOUNDARY) && (ps_y_next == ARR_BOTTOM_BOUNDARY)) {
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
++y_index;
}
// Move to the halfedge.
he = he->next();
do {
// Get the boundary conditions of the current vertex.
ps_x = ps_x_save;
ps_y = ps_y_save;
CGAL_assertion(!is_open(ps_x, ps_y));
Arr_parameter_space ps_x_next, ps_y_next;
// In case this he->next() is the "after" halfegde, use the boundary
// conditions of the proper curve-end of cv. Otherwise, use the boundary
// conditions of the curve associated with he->next().
if (he->next()->direction() == ARR_LEFT_TO_RIGHT) {
ps_x_next = parameter_space_in_x(he->next()->curve(), ARR_MIN_END);
ps_y_next = parameter_space_in_y(he->next()->curve(), ARR_MIN_END);
ps_x_save = parameter_space_in_x(he->next()->curve(), ARR_MAX_END);
ps_y_save = parameter_space_in_y(he->next()->curve(), ARR_MAX_END);
}
else {
ps_x_next = parameter_space_in_x(he->next()->curve(), ARR_MAX_END);
ps_y_next = parameter_space_in_y(he->next()->curve(), ARR_MAX_END);
ps_x_save = parameter_space_in_x(he->next()->curve(), ARR_MIN_END);
ps_y_save = parameter_space_in_y(he->next()->curve(), ARR_MIN_END);
}
// If the halfedge is directed from right to left and its successor is
// directed from left to right, the target vertex might be the smallest.
// If the following condition is met, the vertex is indeed the smallest:
// The current x_index is smaller than the x_index of the smallest recorded, or
// The current x_index is equivalent to the recorded x_index, and
// - No smallest has bin recorded so far, or
// - The current target vertex and the recorded vertex are the same and
// * The current curve is smaller than the recorded curve, or
// - The current curve end is smaller then the recorded curve end.
// smaller than its source, so we should check whether it is also smaller
// Note that we compare the vertices lexicographically: first by the
// indices, then by x, then by y.
// std::cout << "he: " << he->opposite()->vertex()->point()
// << " => " << he->vertex()->point() << std::endl;
// std::cout << "he->direction(): " << he->direction() << std::endl;
// std::cout << "x_index: " << x_index << std::endl;
if ((he->direction() == ARR_RIGHT_TO_LEFT) &&
(he->next()->direction() == ARR_LEFT_TO_RIGHT))
{
// Update the left lowest halfedge incident to the leftmost vertex.
// Note that we may visit the leftmost vertex several times.
// store he (and implicitly he->next) as halfedge pointing to a local minimum
*local_mins_it++ = std::make_pair(he, x_index);
}
// If we cross the identification curve in x, then we must update the
// x_index. Note that a crossing takes place in the following cases:
// . .
// . .
// . .
// . v he he . v
// <-------(.)<--------- -------->(.)------->
// . .
// (BEFORE) . (AFTER) (BEFORE) . (AFTER)
// x_index-1. x_index x_index . x_index+1
//
if ((ps_x == ARR_LEFT_BOUNDARY) && (ps_x_next == ARR_RIGHT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
--x_index;
}
else if ((ps_x == ARR_RIGHT_BOUNDARY) && (ps_x_next == ARR_LEFT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
++x_index;
}
// Check if we cross the identification curve in y.
if ((ps_y == ARR_BOTTOM_BOUNDARY) && (ps_y_next == ARR_TOP_BOUNDARY)) {
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
--y_index;
}
else if ((ps_y == ARR_TOP_BOUNDARY) && (ps_y_next == ARR_BOTTOM_BOUNDARY)) {
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
++y_index;
}
// Move to the halfedge.
he = he->next();
} while (he->next() != he_away);
// Get the boundary conditions of the current vertex.
ps_x = ps_x_save;
ps_y = ps_y_save;
CGAL_assertion(!is_open(ps_x, ps_y));
// If we cross the identification curve in x, then we must update the
// x_index. Note that a crossing takes place in the following cases:
// . .
// . .
// . .
// . v he he . v
// <-------(.)<--------- -------->(.)------->
// . .
// (BEFORE) . (AFTER) (BEFORE) . (AFTER)
// x_index-1. x_index x_index . x_index+1
//
if ((ps_x == ARR_LEFT_BOUNDARY) && (ps_x_end == ARR_RIGHT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
--x_index;
}
else if ((ps_x == ARR_RIGHT_BOUNDARY) && (ps_x_end == ARR_LEFT_BOUNDARY)) {
CGAL_assertion(is_identified(Left_side_category()) &&
is_identified(Right_side_category()));
++x_cross_count;
++x_index;
}
// Check if we cross the identification curve in y.
if ((ps_y == ARR_BOTTOM_BOUNDARY) && (ps_y_next == ARR_TOP_BOUNDARY))
{
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
--y_index;
}
else if ((ps_y == ARR_TOP_BOUNDARY) && (ps_y_next == ARR_BOTTOM_BOUNDARY)) {
CGAL_assertion(is_identified(Bottom_side_category()) &&
is_identified(Top_side_category()));
++y_cross_count;
++y_index;
}
// Return the leftmost vertex and its x_index (with respect to he_before).
return (std::make_pair(CGAL::sign(x_index), CGAL::sign(y_index)));
}
//-----------------------------------------------------------------------------
// Locate the leftmost vertex on the a given sequence defined by two
// halfedges. This sequence is still an open loop, but it will soon be closed
@ -3368,6 +3682,7 @@ _is_diff(Arr_parameter_space ps_x_min, Arr_parameter_space ps_y_min,
// be done in the case he_before is he_min (cv cannot be used instead of
// he_min->curve() in that case as cv may not be defined to the right of
// the left lowest point).
// TODO EBEB 2012-07-27 to be deleted
template <typename GeomTraits, typename TopTraits>
std::pair<const typename Arrangement_on_surface_2<GeomTraits,
TopTraits>::DVertex*,
@ -3460,7 +3775,7 @@ _find_leftmost_vertex_on_open_loop(const DHalfedge* he_before,
}
is_perimetric = false;
// Handle the first halfedge.
CGAL_assertion(!is_open(ps_x, ps_y));
@ -4033,23 +4348,12 @@ _find_leftmost_vertex_on_closed_loop(const DHalfedge* he_anchor,
// face we are about to create, by connecting it with another halfedge
// using a given x-monotone curve.
//
// TODO EBEB 2012-07-27 to be deleted
template <typename GeomTraits, typename TopTraits>
bool Arrangement_on_surface_2<GeomTraits, TopTraits>::
_defines_outer_ccb_of_new_face(const DHalfedge* prev1,
const DHalfedge* prev2,
const X_monotone_curve_2& cv) const
// TODO EBEB 2012-09-26 change signature to (to, cv, away)
// ----to---> ---away--->
// o ===cv=== 0
// <-tonext-- <-awaynext-
// this way, to and away lie
// BEFORE insertion on the same inner ccb and
// AFTER insertion on the same outer ccb
//
// currently it is
// ----prev1---> ( --he2--> ) ---p2next--->
// o ===cv=== 0
// <---p1next--- ( <--he1-- ) <---prev2----
{
// std::cout << "cv: " << cv << std::endl;
@ -4063,9 +4367,6 @@ _defines_outer_ccb_of_new_face(const DHalfedge* prev1,
// our traversal).
const DHalfedge* he_last = prev1->next();
// TODO 2012-07-25 this part will be handled BEFORE calling this function
// but to simplify the search for leftmost vertex, the function gets
// passed a list of halfedges possibly pointing to the leftmost vertex >> EOC
bool is_perimetric;
std::pair<const DVertex*, const DHalfedge*> find_res =
_find_leftmost_vertex_on_open_loop(prev2, he_last, cv, is_perimetric);
@ -4078,8 +4379,6 @@ _defines_outer_ccb_of_new_face(const DHalfedge* prev1,
// lies inside the hole (in case a hole is indeed created).
return m_topol_traits.is_on_new_perimetric_face_boundary(prev1, prev2, cv);
// << EOC
const DVertex* v_min = find_res.first;
// std::cout << "v_min: ";
// if (v_min)
@ -4232,6 +4531,278 @@ _defines_outer_ccb_of_new_face(const DHalfedge* prev1,
(*p_cv_curr, *p_cv_next, v_min->point()) == LARGER);
}
//-----------------------------------------------------------------------------
// Determine whether a given query halfedge lies in the interior of a new
// face we are about to create, by connecting it with another halfedge
// using a given x-monotone curve.
//
template <typename GeomTraits, typename TopTraits>
template <typename InputIterator>
bool Arrangement_on_surface_2<GeomTraits, TopTraits>::
_defines_outer_ccb_of_new_face(const DHalfedge* prev1,
const DHalfedge* prev2,
const X_monotone_curve_2& cv,
Arr_halfedge_direction cv_dir,
InputIterator lm_begin, InputIterator lm_end) const
// TODO EBEB 2012-07-27 change signature to (to, cv, away)
// ----to---> ---away--->
// o ===cv=== 0
// <-tonext-- <-awaynext-
// this way, to and away lie
// BEFORE insertion on the same inner ccb and
// AFTER insertion on the same outer ccb
//
// currently it is
// ----prev1---> ( --he2--> ) ---p2next--->
// o ===cv=== 0
// <---p1next--- ( <--he1-- ) <---prev2----
//
// BUT BE CAREFULL!!!!!! for the search of the leftmost vertex, this is used,
// for the second part here, you have to reset prev1/prev2 properly!
{
// std::cout << "cv: " << cv << std::endl;
// Go over all halfedges of along boundary of the face which will eventually
// contain prev1: As the new face is not constructed yet, this traversal
// is simulated by going from prev2's target vertex to prev1's target vertex
// (the source of prev1's successor) and then returning over the new curve.
// During the traversal we locate the leftmost halfedge along the boundary
// (i.e, the one with the lexicographically smallest target vertex, which is
// also the lowest halfedge incident to this vertex we encountered during
// our traversal).
const DHalfedge* he_last = prev1->next();
// this implements search for leftmost vertex using local minima (plus cv's ends)
typename Traits_adaptor_2::Parameter_space_in_x_2 parameter_space_in_x =
m_geom_traits->parameter_space_in_x_2_object();
typename Traits_adaptor_2::Parameter_space_in_y_2 parameter_space_in_y =
m_geom_traits->parameter_space_in_y_2_object();
typename Traits_adaptor_2::Compare_y_at_x_right_2 compare_y_at_x_right_2 =
m_geom_traits->compare_y_at_x_right_2_object();
const DHalfedge* he_to = prev1;
const DHalfedge* he_away = prev2->next();
int index_min = 0;
const X_monotone_curve_2* cv_min = NULL;
Arr_parameter_space ps_x_min = ARR_INTERIOR, ps_y_min = ARR_INTERIOR;
const DHalfedge* he_min = NULL;
const DVertex* v_min = NULL;
if (cv_dir == ARR_RIGHT_TO_LEFT) {
if (he_away->next()->direction() == ARR_LEFT_TO_RIGHT) {
// initialize with minimal endpoint of curve (he_min = null)
Arr_parameter_space ps_x_cv_min = parameter_space_in_x(cv, ARR_MIN_END);
Arr_parameter_space ps_y_cv_min = parameter_space_in_y(cv, ARR_MIN_END);
cv_min = &cv;
ps_x_min = ps_x_cv_min;
ps_y_min = ps_y_cv_min;
v_min = he_away->opposite()->vertex();
std::cout << "set global min to cv (min)" << std::endl;
}
} else {
CGAL_assertion(cv_dir == ARR_LEFT_TO_RIGHT);
if (he_to->direction() == ARR_RIGHT_TO_LEFT) {
// initialize with target of to-edge (and to-edge)
Arr_parameter_space ps_x_he_to_min = parameter_space_in_x(he_to->curve(), ARR_MIN_END);
Arr_parameter_space ps_y_he_to_min = parameter_space_in_y(he_to->curve(), ARR_MIN_END);
cv_min = &(he_to->curve());
ps_x_min = ps_x_he_to_min;
ps_y_min = ps_y_he_to_min;
he_min = he_to;
v_min = he_to->vertex();
std::cout << "set global min to he_to" << std::endl;
}
}
// check all reported local minima
for (InputIterator lm_it = lm_begin; lm_it != lm_end; lm_it++) {
const DHalfedge* he = lm_it->first;
int index = lm_it->second;
Arr_parameter_space ps_x_he_min = parameter_space_in_x(he->curve(), ARR_MIN_END);
Arr_parameter_space ps_y_he_min = parameter_space_in_y(he->curve(), ARR_MIN_END);
// Efi:
// compare_y_at_x_right_2() could happen at the boundary. In this case
// we need to compare_y_near_boundary()
if ((index < index_min) ||
((index == index_min) &&
((cv_min == NULL) ||
((v_min == he->vertex()) &&
(compare_y_at_x_right_2(he->curve(), *cv_min, v_min->point()) ==
SMALLER)) ||
_is_smaller(he->curve(), ps_x_he_min, ps_y_he_min, *cv_min, ps_x_min, ps_y_min)))) {
index_min = index;
cv_min = &(he->curve());
ps_x_min = ps_x_he_min;
ps_y_min = ps_y_he_min;
he_min = he;
v_min = he->vertex();
std::cout << "set global min to he" << std::endl;
}
}
// some output:
#if 1
std::cout << "v_min: ";
if (v_min)
std::cout << v_min->point();
else std::cout << "NULL";
std::cout << std::endl;
std::cout << "he_min: ";
if (he_min)
std::cout << he_min->opposite()->vertex()->point()
<< " => " << he_min->vertex()->point();
else std::cout << "NULL";
std::cout << std::endl;
#endif
CGAL_assertion(! v_min->has_null_point());
// Now note that the curves of leftmost edge and its successor are defined
// to the right of the smallest vertex. We compare them to the right of this
// point to determine whether prev1 is inside the hole to be created or not.
const X_monotone_curve_2* p_cv_curr;
const X_monotone_curve_2* p_cv_next;
if (he_min != NULL) {
p_cv_curr = &(he_min->curve());
// Take special care if the next curve should really be the new curve.
p_cv_next = (he_min->next() != he_last) ? &(he_min->next()->curve()) : &cv;
}
else {
// In this case, the leftmost edge should be the one associated with the
// new curve (which has not been created yet).
p_cv_curr = &cv;
p_cv_next = &(prev2->next()->curve());
}
// Check if the vertex lies on the identification curve in y, in which case
// special care must be taken.
if (((v_min->parameter_space_in_y() == ARR_BOTTOM_BOUNDARY) &&
is_identified(Bottom_side_category())) ||
((v_min->parameter_space_in_y() == ARR_TOP_BOUNDARY) &&
is_identified(Top_side_category())))
{
// Both current and next curves are incident to the identification curve.
// As v_min is the leftmost vertex, we now that their left ends must have
// a boundary condition of type identification in y.
Arr_parameter_space ps_y_curr =
m_geom_traits->parameter_space_in_y_2_object()(*p_cv_curr, ARR_MIN_END);
Arr_parameter_space ps_y_next =
m_geom_traits->parameter_space_in_y_2_object()(*p_cv_next, ARR_MIN_END);
// Check if the curves lie on opposite sides of the identification curve.
if ((ps_y_curr == ARR_BOTTOM_BOUNDARY) && (ps_y_next == ARR_TOP_BOUNDARY))
// In this case the current curve is "above" the next one to the right
// of v_min, in a cyclic order around the identification curve.
return true;
else if ((ps_y_curr == ARR_TOP_BOUNDARY) &&
(ps_y_next == ARR_BOTTOM_BOUNDARY))
// In this case the current curve is "below" the next one to the right
// of v_min, in a cyclic order around the identification curve.
return false;
// If both curves are on the same side of the identification curve, we
// continue to compare them to the right of v_min.
CGAL_assertion(((ps_y_curr == ARR_BOTTOM_BOUNDARY) &&
(ps_y_next == ARR_BOTTOM_BOUNDARY)) ||
((ps_y_curr == ARR_TOP_BOUNDARY) &&
(ps_y_next == ARR_TOP_BOUNDARY)));
}
// Check if the leftmost vertex is a contraction point in y, in which case
// special care must be taken.
if (((v_min->parameter_space_in_y() == ARR_BOTTOM_BOUNDARY) &&
is_contracted(Bottom_side_category())) ||
((v_min->parameter_space_in_y() == ARR_TOP_BOUNDARY) &&
is_contracted(Top_side_category())))
{
// Get the curve-ends for cv_curr and cv_next that conincide with the
// contraction point.
Arr_curve_end ind_curr;
Arr_curve_end ind_next;
if (he_min != NULL) {
// The contraction point is he_min's target and cv_curr is its
// associated curve.
ind_curr = (he_min->direction() == ARR_LEFT_TO_RIGHT) ?
ARR_MAX_END : ARR_MIN_END;
if (he_min->next() != he_last)
// The contraction point is he_min->next()'s source and cv_next
// is its associated curve.
ind_next = (he_min->next()->direction() == ARR_LEFT_TO_RIGHT) ?
ARR_MIN_END : ARR_MAX_END;
else {
// In this case cv_next equals cv.
ind_next =
(m_topol_traits.are_equal
(v_min, cv, ARR_MIN_END,
m_geom_traits->parameter_space_in_x_2_object()(cv, ARR_MIN_END),
m_geom_traits->parameter_space_in_y_2_object()(cv, ARR_MIN_END))) ?
ARR_MIN_END : ARR_MAX_END;
}
}
else {
// In this case cv_curr equals cv.
ind_curr =
(m_topol_traits.are_equal
(v_min, cv, ARR_MIN_END,
m_geom_traits->parameter_space_in_x_2_object()(cv, ARR_MIN_END),
m_geom_traits->parameter_space_in_y_2_object()(cv, ARR_MIN_END))) ?
ARR_MIN_END : ARR_MAX_END;
// The contraction point is prev2->next()'s source and cv_next
// is its associated curve.
ind_next = (prev2->next()->direction() == ARR_LEFT_TO_RIGHT) ?
ARR_MIN_END : ARR_MAX_END;
}
// Compare the horizontal position of the two curve-ends at the point
// of contraction.
Comparison_result x_res = (ind_curr != ind_next) ?
((ind_curr == ARR_MAX_END) ? SMALLER : LARGER) :
m_geom_traits->compare_x_curve_ends_2_object()(*p_cv_curr, ind_curr,
*p_cv_next, ind_next);
CGAL_assertion(x_res != EQUAL);
// bool rc1 = (((v_min->parameter_space_in_y() == ARR_BOTTOM_BOUNDARY) &&
// (x_res == SMALLER)) ||
// ((v_min->parameter_space_in_y() == ARR_TOP_BOUNDARY) &&
// (x_res == LARGER)));
// std::cout << "rc1: " << rc1 << std::endl;
return (((v_min->parameter_space_in_y() == ARR_BOTTOM_BOUNDARY) &&
(x_res == SMALLER)) ||
((v_min->parameter_space_in_y() == ARR_TOP_BOUNDARY) &&
(x_res == LARGER)));
}
// TODO EBEB minimal point can also be on left boundary where we have
// to call boundary-functors
// bool rc2 = (m_geom_traits->compare_y_at_x_right_2_object()
// (*p_cv_curr, *p_cv_next, v_min->point()) == LARGER);
// std::cout << *p_cv_curr << std::endl;
// std::cout << *p_cv_next << std::endl;
// std::cout << "rc2: " << rc2 << std::endl;
return (m_geom_traits->compare_y_at_x_right_2_object()
(*p_cv_curr, *p_cv_next, v_min->point()) == LARGER);
}
//-----------------------------------------------------------------------------
// Remove a pair of twin halfedges from the arrangement.
// In case the removal causes the creation of a new hole, the given halfedge

View File

@ -1628,6 +1628,16 @@ protected:
Comparison_result _compare_induced_path_length(const DHalfedge* e1,
const DHalfedge* e2) const;
// TODO document
template <typename OutputIterator>
std::pair< CGAL::Sign, CGAL::Sign >
_compute_signs_and_local_minima(const DHalfedge* he_to,
const X_monotone_curve_2& cv,
Arr_halfedge_direction cv_dir,
const DHalfedge* he_away,
OutputIterator local_mins_it) const;
/*!
* The function accepts 3 pairs of parameter spaces in x and y. The
* first 2 indicate the parameter spaces of the minimum and maximum ends,
@ -1713,6 +1723,31 @@ protected:
bool _defines_outer_ccb_of_new_face(const DHalfedge* prev1, const DHalfedge* prev2,
const X_monotone_curve_2& cv) const;
// TODO document
/*!
* Given two predecessor halfedges that will be used for inserting a
* new halfedge pair (prev1 will be the predecessor of the halfedge he1,
* and prev2 will be the predecessor of its twin he2), such that the
* insertion will create a new face that forms a hole inside an existing
* face, determine whether he1 will be part of the new outer ccb
* of the new face.
* \param prev1 The first predecessor halfedge.
* \param prev2 The second predecessor halfedge.
* \param cv The x-monotone curve we use to connect prev1's target and
* prev2's target vertex.
* \pre prev1 and prev2 belong to the same inner CCB.
* \return true if he1 (and prev2) lies in the interior of the face we
* are about to create (i.e.~are part of the new outer ccb),
* false otherwise - in which case he2
* (and prev1) must be incident to this new face (i.e.~are part
* of the new outer ccb).
*/
template <typename InputIterator>
bool _defines_outer_ccb_of_new_face(const DHalfedge* prev1, const DHalfedge* prev2,
const X_monotone_curve_2& cv,
Arr_halfedge_direction cv_dir,
InputIterator lm_begin, InputIterator lm_end) const;
/*!
* Move a given outer CCB from one face to another.
* \param from_face The face currently containing the component.