mirror of https://github.com/CGAL/cgal
3313 lines
92 KiB
C++
3313 lines
92 KiB
C++
// ======================================================================
|
|
//
|
|
// Copyright (c) 1997 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------
|
|
//
|
|
// release : $CGAL_Revision: CGAL-2.4-I-40 $
|
|
// release_date : $CGAL_Date: 2001/12/28 $
|
|
//
|
|
// file : include/CGAL/Trapezoidal_decomposition_2.h
|
|
// package : Trapezoidal_decomposition (1.17)
|
|
// maintainer : Eugene Lipovetsky <eug@post.tau.ac.il>
|
|
// source :
|
|
// revision :
|
|
// revision_date :
|
|
// author(s) : Oren Nechushtan <theoren@math.tau.ac.il>
|
|
// Iddo Hanniel <hanniel@math.tau.ac.il>
|
|
//
|
|
// maintainer(s) : Oren Nechushtan <theoren@math.tau.ac.il>
|
|
//
|
|
//
|
|
// coordinator : Tel-Aviv University (Dan Halperin <halperin@math.tau.ac.il>)
|
|
//
|
|
// Chapter :
|
|
// ======================================================================
|
|
|
|
#ifndef CGAL_TRAPEZOIDAL_DECOMPOSITION_2_H
|
|
#define CGAL_TRAPEZOIDAL_DECOMPOSITION_2_H
|
|
|
|
#ifndef CGAL_BASIC_H
|
|
#include <CGAL/basic.h>
|
|
#endif
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <cmath>
|
|
#include <ctime>
|
|
#include <list>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
#include <CGAL/Trapezoidal_decomposition_2/Trapezoidal_decomposition_2_misc.h>
|
|
#include <CGAL/Trapezoidal_decomposition_2/Td_predicates.h>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
/* //////////////////////////////////////////////////////////////////////////
|
|
|
|
class Trapezoidal_decomposition_2
|
|
parameters Traits,X_curve
|
|
Description Implementation for a planar trapezoidal map also known as
|
|
trapezoidal decomposition and vertical decomposition.
|
|
|
|
For requirements on Traits and X_curve classes see
|
|
Trapezoidal_decomposition_2 documentation.
|
|
|
|
////////////////////////////////////////////////////////////////////////// */
|
|
|
|
template < class Td_traits>
|
|
class Trapezoidal_decomposition_2
|
|
{
|
|
public:
|
|
enum Locate_type {POINT=0,CURVE,TRAPEZOID,UNBOUNDED_TRAPEZOID=8} ;
|
|
class Base_trapezoid_iterator;
|
|
class In_face_iterator;
|
|
friend class In_face_iterator;
|
|
class Around_point_circulator;
|
|
struct Unbounded {};
|
|
typedef Td_traits Traits;
|
|
typedef Trapezoidal_decomposition_2<Traits> Self;
|
|
typedef typename Traits::Point Point;
|
|
typedef typename Traits::X_curve X_curve;
|
|
typedef typename Traits::X_curve_ptr curve_pointer;
|
|
typedef typename Traits::X_curve_ref curve_ref;
|
|
typedef typename Traits::X_curve_const_ref curve_const_ref;
|
|
typedef typename Traits::X_trapezoid X_trapezoid;
|
|
typedef typename Traits::X_trapezoid_ptr pointer;
|
|
typedef typename Traits::X_trapezoid_ref reference;
|
|
typedef typename Traits::X_trapezoid_const_ref const_ref;
|
|
typedef std::list<X_trapezoid> list_container;
|
|
typedef std::vector<X_trapezoid> vector_container;
|
|
typedef std::vector<X_curve> X_curve_container;
|
|
typedef In_face_iterator Iterator;
|
|
typedef class Base_trapezoid_iterator Base_trapezoid_circulator;
|
|
// friend class Td_traits::X_trapezoid;
|
|
|
|
typedef Td_active_trapezoid<X_trapezoid> Active_trapezoid;
|
|
typedef Td_active_non_degenerate_trapezoid<X_trapezoid,Traits>
|
|
Active_non_degenerate_trapezoid;
|
|
typedef Td_active_right_degenerate_curve_trapezoid<X_trapezoid,Traits>
|
|
Active_right_degenerate_curve_trapezoid;
|
|
typedef Td_dag< X_trapezoid> Data_structure;
|
|
typedef std::map<int,Data_structure> map_nodes;
|
|
|
|
/* ///////////////////////////////////////////////////////////////////////
|
|
|
|
class Base_trapezoid_iterator
|
|
member of Trapezoidal_decomposition_2<Traits>
|
|
Description Implements a basic Trapezoid iterator
|
|
|
|
/////////////////////////////////////////////////////////////////////// */
|
|
|
|
class Base_trapezoid_iterator
|
|
{
|
|
public:
|
|
Base_trapezoid_iterator() : traits(0),curr(0) {};
|
|
Base_trapezoid_iterator(Traits* traits_,pointer currt=0):
|
|
traits(traits_),curr(currt) {}
|
|
Base_trapezoid_iterator(const Base_trapezoid_iterator &it):
|
|
traits(it.traits),curr(it.curr){;}
|
|
Base_trapezoid_iterator & operator=(const Base_trapezoid_iterator &it)
|
|
{
|
|
traits=it.traits;
|
|
curr=it.curr;
|
|
return *this;
|
|
}
|
|
bool operator==(const Base_trapezoid_iterator &it) const
|
|
{
|
|
return (curr==it.curr );
|
|
}
|
|
bool operator!=(const Base_trapezoid_iterator &it) const
|
|
{
|
|
return !operator==(it);
|
|
}
|
|
reference operator*() const
|
|
{
|
|
CGAL_precondition(curr);
|
|
|
|
return *curr;
|
|
}
|
|
pointer operator->() const
|
|
{
|
|
return curr;
|
|
}
|
|
bool operator!() const
|
|
{
|
|
return curr==0;
|
|
}
|
|
|
|
protected:
|
|
Traits* traits;
|
|
pointer curr;
|
|
};
|
|
|
|
/* *********************************************************************
|
|
|
|
class In_face_iterator
|
|
member of Trapezoidal_decomposition_2<Traits>
|
|
Description Implements a Trapezoid iterator along a X_curve
|
|
|
|
********************************************************************* */
|
|
|
|
class In_face_iterator : public Base_trapezoid_iterator
|
|
{
|
|
protected:
|
|
const X_curve& sep;
|
|
public:
|
|
|
|
In_face_iterator(Traits* traits_,const X_curve& sepc,pointer currt=0) :
|
|
Base_trapezoid_iterator(traits_,currt),sep(sepc){}
|
|
In_face_iterator(const In_face_iterator &it) :
|
|
Base_trapezoid_iterator((Base_trapezoid_iterator&)it),sep(it.sep){}
|
|
bool operator==(const In_face_iterator &it) const
|
|
{
|
|
return ( Base_trapezoid_iterator::operator==(it) &&
|
|
traits->curve_is_same(sep,it.sep) );
|
|
}
|
|
|
|
/*
|
|
destription:
|
|
advances curr to one of the right neighbours according to the relation
|
|
between the seperating X_curve and the right() trapezoid point.
|
|
precoditions:
|
|
sep doesn't intersect no existing edges except possibly on common end
|
|
points.
|
|
postconditions:
|
|
if the rightest trapezoid was traversed curr is set to NULL.
|
|
remark:
|
|
if the seperator is vertical, using the precondition assumptions it
|
|
follows that
|
|
there is exactly one trapezoid to travel.
|
|
*/
|
|
In_face_iterator& operator++()
|
|
{
|
|
if (!curr) return *this;// end reached, do nothing!
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
|
|
#endif
|
|
|
|
Point right(curr->right());
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(curr->is_active());
|
|
CGAL_assertion(!traits->is_degenerate_point(*curr));
|
|
|
|
#endif
|
|
if (!traits->is_degenerate(*curr))
|
|
{
|
|
#ifndef NDEBUG
|
|
Data_structure* tt=curr->get_node();
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!tt->is_inner_node());
|
|
|
|
#else
|
|
|
|
CGAL_assertion(tt);
|
|
CGAL_assertion(!tt->is_inner_node());
|
|
#endif
|
|
#endif
|
|
|
|
// handle degeneracies
|
|
if (!traits->point_is_left_low(curr->left(),
|
|
traits->curve_righttop_most(sep)))
|
|
curr=0;
|
|
else
|
|
{
|
|
switch(traits->curve_get_point_status(sep,right))
|
|
{
|
|
case LARGER:
|
|
curr=curr->right_top_neighbour();
|
|
break;
|
|
case SMALLER:
|
|
curr=curr->right_bottom_neighbour();
|
|
break;
|
|
case EQUAL:
|
|
// end reached
|
|
curr=0;
|
|
break;
|
|
default:
|
|
curr=0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else // pass along degenerate X_curve.
|
|
{
|
|
#ifndef NDEBUG
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
Data_structure* tt=curr->get_node();
|
|
CGAL_warning(tt);
|
|
CGAL_warning(tt->is_inner_node());
|
|
|
|
#else
|
|
|
|
Data_structure* tt=curr->get_node();
|
|
CGAL_assertion(tt);
|
|
CGAL_assertion(tt->is_inner_node());
|
|
#endif
|
|
#endif
|
|
|
|
curr=curr->right_bottom_neighbour();
|
|
if (curr)
|
|
{
|
|
while(traits->is_degenerate_point(*curr))
|
|
curr=curr->get_node()->left().operator->();
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits->is_degenerate_curve(*curr));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(traits->is_degenerate_curve(*curr));
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
In_face_iterator operator++(int)
|
|
{
|
|
In_face_iterator tmp = *this;
|
|
++*this;
|
|
return tmp;
|
|
}
|
|
const X_curve& seperator()
|
|
{
|
|
return sep;
|
|
}
|
|
};
|
|
|
|
/* //////////////////////////////////////////////////////////////////////////
|
|
|
|
class Around_point_circulator
|
|
member of Trapezoidal_decomposition_2<Traits>
|
|
Description Implements a Trapezoid circulator around a point
|
|
|
|
/////////////////////////////////////////////////////////////////////// */
|
|
|
|
class Around_point_circulator : public Base_trapezoid_circulator
|
|
{
|
|
protected:
|
|
const Point& fixed;
|
|
public:
|
|
|
|
Around_point_circulator(Traits * traits_, const Point & fixedp,
|
|
pointer currt) :
|
|
Base_trapezoid_iterator(traits_,currt),fixed(fixedp) {};
|
|
|
|
Around_point_circulator(const Around_point_circulator &it) :
|
|
Base_trapezoid_iterator(it),fixed(it.fixed){};
|
|
|
|
Around_point_circulator &operator++()
|
|
{
|
|
if (operator!()) return *this;
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(fixed,curr->left()) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(fixed,curr->right()));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(fixed,curr->left()) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(fixed,curr->right()));
|
|
|
|
#endif
|
|
|
|
curr=operator->();
|
|
return *this;
|
|
}
|
|
Around_point_circulator operator++(int)
|
|
{
|
|
Around_point_circulator tmp = *this;
|
|
++*this;
|
|
return tmp;
|
|
}
|
|
pointer operator[](int i) const
|
|
{
|
|
Around_point_circulator c=*this;
|
|
while(i-->0) c++;
|
|
return c.curr;
|
|
}
|
|
/* returns reference to the next trapezoid
|
|
on a clockwise orientation rotation with centre
|
|
taken as the fixed point
|
|
preconditions:
|
|
ciruclator is not empty*/
|
|
reference operator*() const
|
|
{
|
|
|
|
CGAL_precondition(!operator!());
|
|
return *operator->();
|
|
}
|
|
/* returns pointer to the next trapezoid
|
|
on a clockwise orientation rotation with centre
|
|
taken as the fixed point */
|
|
pointer operator->() const
|
|
{
|
|
pointer cand;
|
|
if (operator!()) return curr;
|
|
cand=is_right_rotation() ?
|
|
curr->right_top_neighbour() : curr->left_bottom_neighbour();
|
|
if (traits->is_degenerate_curve(*cand)) return cand;
|
|
// cand was splited by a point
|
|
while(traits->is_degenerate_point(*cand))
|
|
cand=traits->point_is_left_low(cand->left(),fixed)?
|
|
// move right using data structure
|
|
cand->get_node()->right().operator->():
|
|
// move left using data structure
|
|
cand->get_node()->left().operator->();
|
|
return cand;
|
|
}
|
|
bool is_valid() const
|
|
{
|
|
return
|
|
(!curr)||(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(fixed,curr->left())) ||
|
|
(!curr->is_right_unbounded() &&
|
|
traits->point_is_same(fixed,curr->right()));
|
|
}
|
|
|
|
/* description:
|
|
inserts the input trapezoid between the
|
|
current trapezoid and the next trapezoid
|
|
on a clockwise orientation rotation with
|
|
centre taken as the fixed point.
|
|
preconditions:
|
|
current trapezoid exist
|
|
input trapezoid is adjacent to fixed point
|
|
*/
|
|
void insert(reference tr)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_warning(!tr.is_left_unbounded() && traits->point_is_same(tr.left(),
|
|
fixed) ||
|
|
!tr.is_right_unbounded()&& traits->point_is_same(tr.right(),
|
|
fixed));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_precondition(!tr.is_left_unbounded() &&
|
|
traits->point_is_same(tr.left(),fixed) ||
|
|
!tr.is_right_unbounded() &&
|
|
traits->point_is_same(tr.right(),fixed));
|
|
|
|
#endif
|
|
|
|
if (!tr.is_left_unbounded()&&traits->point_is_same(tr.left(),fixed))
|
|
tr.set_lb(operator->());
|
|
else
|
|
tr.set_rt(operator->());
|
|
if (is_right_rotation())
|
|
curr->set_rt(&tr);
|
|
else
|
|
curr->set_lb(&tr);
|
|
}
|
|
/* precondition:
|
|
curr!=NULL
|
|
*/
|
|
void remove()
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_warning(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(curr->left(), fixed) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(curr->right(), fixed));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_warning(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(curr->left(),fixed) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(curr->right(),fixed));
|
|
|
|
#endif
|
|
|
|
Around_point_circulator old=*this;
|
|
old++;
|
|
pointer next=old.operator->();
|
|
// handle 1-cycle and 2-cycles seperately
|
|
if (curr!=next)
|
|
{
|
|
}
|
|
// 2-cycle
|
|
else if (*this!=old)
|
|
{
|
|
next=curr;
|
|
}
|
|
// 1-cycle
|
|
else
|
|
{
|
|
if (is_right_rotation())
|
|
curr->set_rt(0);
|
|
else
|
|
curr->set_lb(0);
|
|
curr=0;
|
|
return;
|
|
}
|
|
if (is_right_rotation())
|
|
curr->set_rt(next);
|
|
else
|
|
curr->set_lb(next);
|
|
if (old.is_right_rotation())
|
|
old[0]->set_rt(0);
|
|
else
|
|
old[0]->set_lb(0);
|
|
}
|
|
void replace(reference tr)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_warning(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(curr->left(),fixed) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(curr->right(),fixed));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(curr);
|
|
CGAL_precondition(!curr->is_left_unbounded() &&
|
|
traits->point_is_same(curr->left(),fixed) ||
|
|
!curr->is_right_unbounded() &&
|
|
traits->point_is_same(curr->right(),fixed));
|
|
|
|
#endif
|
|
|
|
Around_point_circulator old=*this;
|
|
old++;
|
|
pointer next=old.operator->();
|
|
// handle 1-cycle and 2-cycles seperately
|
|
if (curr!=next)
|
|
{
|
|
}
|
|
// 2-cycle
|
|
else if (*this!=old)
|
|
{
|
|
next=curr;
|
|
}
|
|
// 1-cycle
|
|
else
|
|
{
|
|
curr=&tr;
|
|
if (is_right_rotation())
|
|
curr->set_rt(curr);
|
|
else
|
|
curr->set_lb(curr);
|
|
return;
|
|
}
|
|
if (!tr.is_right_unbounded()&&traits->point_is_same(tr.right(),fixed))
|
|
tr.set_rt(next);
|
|
else
|
|
tr.set_lb(next);
|
|
if (is_right_rotation())
|
|
curr->set_rt(&tr);
|
|
else
|
|
curr->set_lb(&tr);
|
|
}
|
|
bool is_right_rotation() const
|
|
{
|
|
return !curr->is_right_unbounded() &&
|
|
traits->point_is_same(curr->right(),fixed);
|
|
}
|
|
const Point& fixed_point() const
|
|
{
|
|
return fixed;
|
|
}
|
|
};
|
|
//////////////////////////////////////////////
|
|
//Trapezoidal_decomposition_2 member functions:
|
|
//////////////////////////////////////////////
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
protected:
|
|
|
|
#else
|
|
|
|
public:
|
|
|
|
#endif
|
|
|
|
/* input: X_curve,
|
|
two Trapezoidal maps that corespond the the
|
|
X_curve's source degenerate trapezoid and the
|
|
X_curve's target degenerate trapezoid
|
|
output: trapezoid iterator
|
|
|
|
Description:
|
|
the output (trapezoid iterator) is initialized with
|
|
the leftmost and rightmost
|
|
(non degenerate) trapezoids in the trapezoid interval that corresponds
|
|
to the input from either the top side or the bottom side,
|
|
depending on the up flag.
|
|
preconditions:
|
|
There exist non degenerate trapezoids between the roots of the input DS's
|
|
*/
|
|
In_face_iterator follow_curve(const Data_structure& left_end_point,
|
|
const X_curve& cv,
|
|
Comparison_result up) const
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
CGAL_warning(traits->is_degenerate_point(*left_end_point));
|
|
if (!(traits->point_is_same(traits->curve_leftlow_most(cv),
|
|
left_end_point->left())))
|
|
{
|
|
CGAL_warning(traits->point_is_same(traits->curve_leftlow_most(cv),
|
|
left_end_point->left()));
|
|
}
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
CGAL_precondition(traits->is_degenerate_point(*left_end_point));
|
|
CGAL_precondition(traits->point_is_same(traits->curve_leftlow_most(cv),
|
|
left_end_point->left()));
|
|
|
|
#endif
|
|
|
|
const Point& p1=left_end_point->left();
|
|
Data_structure left=left_end_point.right();
|
|
search_using_data_structure(left,traits,p1,&cv,up);
|
|
return In_face_iterator(traits,cv,left.operator->());
|
|
}
|
|
|
|
/*
|
|
input:
|
|
X_trapezoid reference
|
|
X_trapezoid pointer
|
|
output:
|
|
bool
|
|
preconditions:
|
|
the referenced trapezoid is to the right of the pointered trapezoid
|
|
description:
|
|
if the two input Trapezoids can be merged they are ,
|
|
with one copy destroyed(the right one).
|
|
postconfition:
|
|
The reference points to the right trapezoid
|
|
The returned value is true iff merging took place.
|
|
*/
|
|
bool merge_if_possible(pointer left,pointer right)
|
|
{
|
|
if (left && right &&
|
|
traits->trapezoid_top_curve_is_same(*left,*right) &&
|
|
traits->trapezoid_bottom_curve_is_same(*left,*right) &&
|
|
traits->point_is_same(left->right(),right->left()))
|
|
{
|
|
left->merge_trapezoid(*right);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(left->is_right_unbounded()==right->is_right_unbounded());
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Description:
|
|
splits the trapezoid with vertical line through p */
|
|
/* Precondition:
|
|
The trapezoid is active and contains p in its closure */
|
|
|
|
Data_structure& split_trapezoid_by_point(
|
|
Data_structure& tt,
|
|
const Point& p,
|
|
const X_curve& cv_bottom_ray_shoot,
|
|
const X_curve& cv_top_ray_shoot
|
|
)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!!tt);
|
|
if (!tt) return tt;
|
|
|
|
#else
|
|
|
|
CGAL_precondition(!!tt);
|
|
|
|
#endif
|
|
|
|
reference curr=*tt;
|
|
pointer
|
|
lb=curr.left_bottom_neighbour(),
|
|
lt=curr.left_top_neighbour(),
|
|
rb=curr.right_bottom_neighbour(),
|
|
rt=curr.right_top_neighbour();
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(curr.is_active());
|
|
CGAL_warning(traits->is_in_closure(curr,p));
|
|
#else
|
|
CGAL_precondition(curr.is_active());
|
|
if (!traits->is_in_closure(curr,p))
|
|
{
|
|
std::cout << "\ncurr=";
|
|
write(std::cout,curr,*traits) << "\tp=" << p;
|
|
}
|
|
CGAL_precondition(traits->is_in_closure(curr,p));
|
|
#endif
|
|
|
|
// left and right are set to the point itself,
|
|
// bottom and top are set to the ray shooting resulting curves at this
|
|
// stage.
|
|
X_trapezoid sep(p,p,cv_bottom_ray_shoot,cv_top_ray_shoot);
|
|
Data_structure leftDS = Data_structure(X_trapezoid(curr.left(), p,
|
|
curr.bottom(),
|
|
curr.top(),
|
|
curr.boundedness() & (CGAL_TRAPEZOIDAL_DECOMPOSITION_2_LEFT_UNBOUNDED |
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_BOTTOM_UNBOUNDED |
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_TOP_UNBOUNDED)
|
|
));
|
|
Data_structure rightDS=Data_structure(X_trapezoid(p, curr.right(),
|
|
curr.bottom(),curr.top(),
|
|
curr.boundedness()&(CGAL_TRAPEZOIDAL_DECOMPOSITION_2_RIGHT_UNBOUNDED |
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_BOTTOM_UNBOUNDED |
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_TOP_UNBOUNDED)
|
|
));
|
|
|
|
reference left = *leftDS;
|
|
reference right = *rightDS;
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->trapezoid_top_curve_is_same(left,right));
|
|
CGAL_warning(traits->trapezoid_bottom_curve_is_same(left,right));
|
|
CGAL_warning(left.is_left_unbounded()==curr.is_left_unbounded());
|
|
CGAL_warning(right.is_right_unbounded()==curr.is_right_unbounded());
|
|
#else
|
|
CGAL_warning(traits->trapezoid_top_curve_is_same(left,right));
|
|
CGAL_warning(traits->trapezoid_bottom_curve_is_same(left,right));
|
|
CGAL_assertion(left.is_left_unbounded()==curr.is_left_unbounded());
|
|
CGAL_assertion(right.is_right_unbounded()==curr.is_right_unbounded());
|
|
#endif
|
|
|
|
if (!traits->is_degenerate_curve(curr))
|
|
{
|
|
left.init_neighbours(lb,lt,&right,&right);
|
|
right.init_neighbours(&left,&left,rb,rt);
|
|
if (lb) lb->set_rb(&left);
|
|
if (lt) lt->set_rt(&left);
|
|
if (rb) rb->set_lb(&right);
|
|
if (rt) rt->set_lt(&right);
|
|
}
|
|
else
|
|
{
|
|
left.set_bottom(cv_bottom_ray_shoot);
|
|
left.set_top(cv_bottom_ray_shoot);
|
|
right.set_bottom(cv_top_ray_shoot);
|
|
right.set_top(cv_top_ray_shoot);
|
|
left.set_rt(&right);
|
|
left.set_lb(lb);
|
|
left.set_rb(0);
|
|
right.set_lb(&left);
|
|
right.set_rt(rt);
|
|
right.set_rb(rb);
|
|
}
|
|
tt.replace(sep,leftDS,rightDS);
|
|
const Data_structure
|
|
*leftPtr=&tt.left(),
|
|
*rightPtr=&tt.right();
|
|
(*leftPtr)->set_node((Data_structure*)leftPtr);
|
|
(*rightPtr)->set_node((Data_structure*)rightPtr);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(&left==leftDS.operator->());
|
|
CGAL_assertion(&right==rightDS.operator->());
|
|
CGAL_assertion(left==*leftDS);
|
|
CGAL_assertion(right==*rightDS);
|
|
CGAL_assertion(left==*tt.left());
|
|
CGAL_assertion(right==*tt.right());
|
|
/*
|
|
CGAL_assertion(left.get_node()==&tt.left());
|
|
CGAL_assertion(right.get_node()==&tt.right());
|
|
*/
|
|
CGAL_assertion(**left.get_node()==left);
|
|
CGAL_assertion(**right.get_node()==right);
|
|
#endif
|
|
|
|
return tt;
|
|
}
|
|
|
|
/* Description:
|
|
the opposite operation for spliting the trapezoid with
|
|
vertical line through p */
|
|
/* Precondition:
|
|
The root trapezoid is degenerate point (p) and is active */
|
|
|
|
void remove_split_trapezoid_by_point(
|
|
Data_structure& tt,
|
|
const Point& p)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
if (!tt||
|
|
!tt->is_active()||
|
|
!traits->is_degenerate_point(*tt)||
|
|
!traits->point_is_same(tt->left(),p)
|
|
)
|
|
{
|
|
CGAL_warning(!!tt);
|
|
CGAL_warning(tt->is_active());
|
|
CGAL_warning(traits->is_degenerate_point(*tt));
|
|
CGAL_warning(traits->point_is_same(tt->left(),p));
|
|
return;
|
|
}
|
|
|
|
#else
|
|
|
|
CGAL_precondition(!!tt);
|
|
CGAL_precondition(tt->is_active());
|
|
CGAL_precondition(traits->is_degenerate_point(*tt));
|
|
CGAL_precondition(traits->point_is_same(tt->left(),p));
|
|
|
|
#endif
|
|
|
|
Data_structure
|
|
tt_left=tt.left(),
|
|
tt_right=tt.right();
|
|
|
|
search_using_data_structure(tt_left,traits,p,0);
|
|
search_using_data_structure(tt_right,traits,p,0);
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
merge_if_possible(&*tt_left,&*tt_right);
|
|
|
|
CGAL_warning(!tt_left.is_inner_node());
|
|
CGAL_warning(!tt_right.is_inner_node());
|
|
CGAL_warning(tt_left->is_right_unbounded() ==
|
|
tt_right->is_right_unbounded());
|
|
|
|
#else
|
|
std::cout << "\nremove_split_trapezoid_by_point(){";
|
|
std::cout << "\ntt_left=";
|
|
write(std::cout,*tt_left,*traits);
|
|
std::cout << "\ntt_right=";
|
|
write(std::cout,*tt_right,*traits) << "}" << std::endl;
|
|
|
|
bool merge_if_poss_left_right = merge_if_possible(&*tt_left,&*tt_right);
|
|
|
|
std::cout << "\n->";
|
|
write(std::cout,*tt_left,*traits) << std::endl;
|
|
|
|
CGAL_postcondition(merge_if_poss_left_right);
|
|
CGAL_assertion(!tt_left.is_inner_node());
|
|
CGAL_assertion(!tt_right.is_inner_node());
|
|
CGAL_assertion(tt_left->is_right_unbounded() ==
|
|
tt_right->is_right_unbounded());
|
|
CGAL_assertion(**tt_left->get_node()==*tt_left);
|
|
#endif
|
|
|
|
tt_right->remove(&tt_left);
|
|
// mark root as deleted
|
|
tt->remove();
|
|
}
|
|
|
|
/* Description:
|
|
splits the trapezoid that corresponds to the root of the
|
|
trapezoidal tree with an input edge cv*/
|
|
/* Precondition:
|
|
The root trapezoid is active
|
|
cv is non degenerate
|
|
The root trapezoid is devided by cv or
|
|
is equal to it and is vertical.
|
|
*/
|
|
Data_structure&
|
|
split_trapezoid_by_curve(
|
|
Data_structure& tt,
|
|
pointer& prev,
|
|
pointer& prev_bottom,
|
|
pointer& prev_top,
|
|
const X_curve& cv)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
|
|
#endif
|
|
|
|
reference currt=*tt;
|
|
Point p[2];
|
|
int i= traits->point_is_left_low(
|
|
p[0]=traits->curve_source(cv),
|
|
p[1]=traits->curve_target(cv)
|
|
) ? 0 : 1;
|
|
|
|
// sets left and right accoring to curves source's and target's positions
|
|
// sets bottom and top to X_curve itself
|
|
X_trapezoid sep(p[i],p[1-i],cv,cv);
|
|
/*
|
|
creates a one-way path for all the X_curve-degenerate
|
|
trapezoids that represent the X_curve.
|
|
right_bottom_neighbour() is used to retrieve the
|
|
next on path information
|
|
*/
|
|
Data_structure
|
|
topBT = Data_structure(X_trapezoid(currt.left(), currt.right(), cv,
|
|
currt.top(),
|
|
currt.boundedness() &
|
|
(CGAL_TRAPEZOIDAL_DECOMPOSITION_2_LEFT_UNBOUNDED |
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_RIGHT_UNBOUNDED|
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_TOP_UNBOUNDED))),
|
|
bottomBT = Data_structure(X_trapezoid(currt.left(),currt.right(),
|
|
currt.bottom(), cv,
|
|
currt.boundedness() &
|
|
(CGAL_TRAPEZOIDAL_DECOMPOSITION_2_LEFT_UNBOUNDED|
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_RIGHT_UNBOUNDED|
|
|
CGAL_TRAPEZOIDAL_DECOMPOSITION_2_BOTTOM_UNBOUNDED)));
|
|
reference bottom=*bottomBT;
|
|
reference top=*topBT;
|
|
top.init_neighbours(prev_top, currt.left_top_neighbour(), 0,
|
|
currt.right_top_neighbour());
|
|
bottom.init_neighbours(currt.left_bottom_neighbour(),
|
|
prev_bottom,currt.right_bottom_neighbour(),0);
|
|
if (prev_bottom) prev_bottom->set_rt(&bottom);
|
|
if (prev_top) prev_top->set_rb(&top);
|
|
if (currt.left_bottom_neighbour())
|
|
currt.left_bottom_neighbour()->set_rb(&bottom);
|
|
if (currt.left_top_neighbour())
|
|
currt.left_top_neighbour()->set_rt(&top);
|
|
if (currt.right_bottom_neighbour())
|
|
currt.right_bottom_neighbour()->set_lb(&bottom);
|
|
if (currt.right_top_neighbour()) currt.right_top_neighbour()->set_lt(&top);
|
|
tt.replace(sep,bottomBT,topBT);
|
|
const Data_structure
|
|
*bottomPtr=&tt.left(),
|
|
*topPtr=&tt.right();
|
|
(*bottomPtr)->set_node((Data_structure*)bottomPtr);
|
|
(*topPtr)->set_node((Data_structure*)topPtr);
|
|
if (prev) prev->set_rb(tt.operator->());
|
|
prev_bottom=(*bottomPtr).operator->();
|
|
prev_top=(*topPtr).operator->();
|
|
prev=tt.operator->();
|
|
return tt;
|
|
}
|
|
|
|
/* replace X_curve-point adjacency in the data structure with
|
|
a new one
|
|
precondition:
|
|
the X_curve represented by t is top-right
|
|
relative to the point represented by sep
|
|
if and only if top=true
|
|
*/
|
|
void replace_curve_at_point_using_geometry(reference t, reference sep,
|
|
bool cv_top_right=true)
|
|
{
|
|
Point p(sep.left());
|
|
X_curve cv(t.top());
|
|
Around_point_circulator circ(traits,p,cv_top_right ?
|
|
sep.right_top_neighbour() :
|
|
sep.left_bottom_neighbour());
|
|
if (circ.operator->())
|
|
{
|
|
if (cv_top_right)
|
|
while(traits->curve_compare_at_x_from_top(circ->top(),cv,p)!=EQUAL)
|
|
circ++;
|
|
else
|
|
while(traits->curve_compare_at_x_from_bottom(circ->bottom(), cv, p)
|
|
!= EQUAL)
|
|
circ++;
|
|
circ.replace(t);
|
|
}
|
|
}
|
|
void insert_curve_at_point_using_geometry(reference sep, reference end_point)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
CGAL_warning(traits->is_degenerate_point(end_point));
|
|
CGAL_warning(traits->is_degenerate_curve(sep));
|
|
CGAL_warning(traits->point_is_same(end_point.left(),sep.right()) ||
|
|
traits->point_is_same(end_point.left(),sep.left()));
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
CGAL_precondition(traits->is_degenerate_point(end_point));
|
|
CGAL_precondition(traits->is_degenerate_curve(sep));
|
|
CGAL_precondition(traits->point_is_same(end_point.left(),sep.right()) ||
|
|
traits->point_is_same(end_point.left(),sep.left()));
|
|
|
|
#endif
|
|
|
|
/* update (in this order)
|
|
end_point.left_bottom_neighbour()
|
|
if no curves adjacent to the point eminating toward up
|
|
or right exist returns null, otherwise return
|
|
the first X_curve sweeped using a counter clockwise sweep
|
|
starting from up direction not including.
|
|
end_point.right_top_neighbour()
|
|
if no curves adjacent to the point eminating toward bottom
|
|
or left exist returns null, otherwise return
|
|
the first X_curve sweeped using a counter clockwise sweep
|
|
starting from bottom direction not including.
|
|
sep.right_top_neighbour()
|
|
next clockwise degenerate_curve around rightmost end_point (possibly
|
|
himself)
|
|
sep.left_bottom_neighbour()
|
|
next clockwise degenerate_curve around leftmost end_point (possibly
|
|
himself)
|
|
*/
|
|
const X_curve& cv=sep.top();
|
|
const Point& p=end_point.left();
|
|
pointer rt = end_point.right_top_neighbour(),
|
|
lb = end_point.left_bottom_neighbour();
|
|
if(!traits->point_is_same(end_point.left(),sep.right()))
|
|
{
|
|
if (!rt && !lb)
|
|
// empty circulator
|
|
{
|
|
end_point.set_rt(&sep);
|
|
sep.set_lb(&sep);
|
|
}
|
|
else
|
|
{
|
|
/* set circ[0] to first X_curve on a counter clockwise
|
|
sweep starting at cv */
|
|
Around_point_circulator circ(traits,p,rt ? rt : lb),stopper=circ;
|
|
// if !rt set circ to lb
|
|
// otherwise advance as required
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
Around_point_circulator first_circ(circ);
|
|
|
|
#endif
|
|
|
|
while(traits->curve_compare_at_x_from_top(circ->top(),cv,p)
|
|
==SMALLER)
|
|
{
|
|
circ++;
|
|
if (circ==stopper)
|
|
break;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(first_circ!=circ);
|
|
CGAL_assertion(circ->is_active());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_compare_at_x_from_top(circ->top(), cv, p)
|
|
!= EQUAL);
|
|
|
|
#endif
|
|
|
|
circ.insert(sep);
|
|
// set end_point.left_bottom_neighbour()
|
|
// set end_point.right_top_neighbour();
|
|
if (lb)
|
|
{
|
|
Around_point_circulator lb_circ(traits,p,lb);
|
|
if (!rt) end_point.set_rt(lb);
|
|
if (lb_circ.operator->()==&sep) end_point.set_lb(&sep);
|
|
}
|
|
else
|
|
{
|
|
if (traits->curve_compare_at_x_from_bottom(rt->top(), cv, p) ==
|
|
SMALLER)
|
|
end_point.set_rt(&sep);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!rt && !lb)
|
|
// empty circulator
|
|
{
|
|
end_point.set_lb(&sep);
|
|
sep.set_rt(&sep);
|
|
}
|
|
else
|
|
{
|
|
/* set circ[0] to first X_curve on a counter clockwise
|
|
sweep starting at cv */
|
|
Around_point_circulator circ(traits,p,lb ? lb : rt),stopper=circ;
|
|
// if !lb set circ to rt
|
|
// otherwise advance as required
|
|
while (traits->curve_compare_at_x_from_bottom(circ->top(),cv,p) ==
|
|
SMALLER)
|
|
{
|
|
circ++;
|
|
if (circ==stopper)
|
|
break;
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_compare_at_x_from_bottom(circ->top(), cv,
|
|
p) != EQUAL);
|
|
|
|
#endif
|
|
|
|
circ.insert(sep);
|
|
if (rt)
|
|
// set end_point.left_bottom_neighbour()
|
|
{
|
|
Around_point_circulator rt_circ(traits,p,rt);
|
|
if (!lb) end_point.set_lb(rt);
|
|
if (rt_circ.operator->()==&sep) end_point.set_rt(&sep);
|
|
}
|
|
else
|
|
{
|
|
// set end_point.right_top_neighbour();
|
|
if(traits->curve_compare_at_x_from_top(lb->top(),cv,p)
|
|
==SMALLER)
|
|
end_point.set_lb(&sep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
description:
|
|
Update top(),bottom() for trapezoid
|
|
Update rt,lb
|
|
remarks:
|
|
The point degenerate trapezoid representing a point p holds as its top and
|
|
bottom curves
|
|
the output for a vertical ray shoot quiries immidiately below the point
|
|
toward up and
|
|
immediately above the point toward down respectively.
|
|
optimization:
|
|
Each degenerate X_curve trapezoid eminating from the point p holds a pointer
|
|
to the next
|
|
trapezoid in a clockwise sweep around p(possibly to itself).
|
|
This pointer is stored in rt or lb depending on the trapezoid is top right or
|
|
bottom left of p.
|
|
For the trapezoid representing p rt and lb hold the previous X_curve
|
|
degenerate trapezoid
|
|
in a clockwise sweep to the first top right and bottom left respectively.
|
|
*/
|
|
|
|
void remove_curve_at_point_using_geometry(const_ref sep,reference end_point)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
CGAL_warning(traits->is_degenerate_point(end_point));
|
|
CGAL_warning(traits->is_degenerate_curve(sep));
|
|
CGAL_warning(traits->point_is_same(end_point.left(),sep.right()) ||
|
|
traits->point_is_same(end_point.left(),sep.left()));
|
|
CGAL_warning(end_point.is_active());
|
|
CGAL_warning(sep.is_active());
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
CGAL_precondition(traits->is_degenerate_point(end_point));
|
|
CGAL_precondition(traits->is_degenerate_curve(sep));
|
|
CGAL_precondition(traits->point_is_same(end_point.left(),sep.right()) ||
|
|
traits->point_is_same(end_point.left(),sep.left()));
|
|
CGAL_precondition(end_point.is_active());
|
|
CGAL_precondition(sep.is_active());
|
|
|
|
#endif
|
|
|
|
/* update (in this order)
|
|
end_point.left_bottom_neighbour()
|
|
if no curves adjacent to the point eminating toward up
|
|
or right exist returns null, otherwise return
|
|
the first X_curve sweeped using a counter clockwise sweep
|
|
starting from up direction not including.
|
|
end_point.right_top_neighbour()
|
|
if no curves adjacent to the point eminating toward bottom
|
|
or left exist returns null, otherwise return
|
|
the first X_curve sweeped using a counter clockwise sweep
|
|
starting from bottom direction not including.
|
|
sep.right_top_neighbour()
|
|
next clockwise degenerate_curve around rightmost end_point (possibly
|
|
himself)
|
|
sep.left_bottom_neighbour()
|
|
next clockwise degenerate_curve around leftmost end_point (possibly
|
|
himself)
|
|
*/
|
|
const X_curve& cv=sep.top();
|
|
const Point& p=end_point.left();
|
|
Around_point_circulator
|
|
prev_top(traits,p,end_point.right_top_neighbour()),
|
|
prev_bottom(traits,p,end_point.left_bottom_neighbour());
|
|
|
|
// update bottom
|
|
if(traits->curve_is_same(cv,end_point.bottom()))
|
|
{
|
|
Around_point_circulator bottom=(!!prev_bottom) ? prev_bottom : prev_top;
|
|
bottom++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(!!bottom);
|
|
|
|
#endif
|
|
|
|
if (!bottom->is_bottom_unbounded())
|
|
end_point.set_bottom(bottom->bottom());
|
|
else
|
|
end_point.set_bottom_unbounded();
|
|
}
|
|
// update top
|
|
if(traits->curve_is_same(cv,end_point.top()))
|
|
{
|
|
Around_point_circulator top=(!!prev_top) ? prev_top : prev_bottom;
|
|
top++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(!!top);
|
|
|
|
#endif
|
|
|
|
if (!top->is_top_unbounded())
|
|
end_point.set_top(top->top());
|
|
else
|
|
end_point.set_top_unbounded();
|
|
}
|
|
|
|
//update right top neighbour and left bottom neighbour
|
|
bool b=traits->point_is_left_low(p,sep.right());
|
|
Around_point_circulator circ(traits,p,b ? end_point.right_top_neighbour() :
|
|
end_point.left_bottom_neighbour());
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(!!circ);
|
|
|
|
#endif
|
|
|
|
while(*circ!=sep)circ++;
|
|
pointer removed=circ.operator->();
|
|
circ.remove();
|
|
if(!!circ)
|
|
{
|
|
pointer effective_curr=circ[0];
|
|
if (end_point.right_top_neighbour()==removed)
|
|
end_point.set_rt(effective_curr);
|
|
if (end_point.left_bottom_neighbour()==removed)
|
|
end_point.set_lb(effective_curr);
|
|
Around_point_circulator rt_circ(traits, p,
|
|
end_point.right_top_neighbour());
|
|
if (!!rt_circ)
|
|
{
|
|
rt_circ++;
|
|
if (rt_circ.is_right_rotation())
|
|
end_point.set_rt(0);
|
|
}
|
|
Around_point_circulator lb_circ(traits, p,
|
|
end_point.left_bottom_neighbour());
|
|
if (!!lb_circ)
|
|
{
|
|
lb_circ++;
|
|
if (!lb_circ.is_right_rotation())
|
|
end_point.set_lb(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
end_point.set_rt(0);
|
|
end_point.set_lb(0);
|
|
}
|
|
}
|
|
|
|
/*update
|
|
tr.bottom()
|
|
vertical_ray_shoot downward from tr
|
|
tr.top()
|
|
vertical_ray_shoot upward from tr
|
|
*/
|
|
reference insert_curve_at_point_using_geometry(const X_curve & cv,
|
|
const Point& p,
|
|
pointer & tr,
|
|
const Locate_type & lt)
|
|
{
|
|
CGAL_assertion(traits);
|
|
CGAL_precondition(lt==POINT);
|
|
|
|
if (traits->curve_compare_at_x_from_top(cv,tr->top(),p)==SMALLER)
|
|
tr->set_top(cv);
|
|
if (traits->curve_compare_at_x_from_bottom(cv,tr->bottom(),p)==SMALLER)
|
|
tr->set_bottom(cv);
|
|
return *tr;
|
|
}
|
|
|
|
reference insert_curve_at_point_using_data_structure(const X_curve & cv,
|
|
const Point & p,
|
|
pointer & tr,
|
|
const Locate_type & lt)
|
|
{
|
|
CGAL_precondition(lt==TRAPEZOID || lt==UNBOUNDED_TRAPEZOID);
|
|
|
|
Data_structure *tt=tr->get_node();
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(tr->get_node());
|
|
|
|
#endif
|
|
|
|
return *split_trapezoid_by_point(*tt,p,cv,cv);
|
|
//return *tr;
|
|
}
|
|
|
|
void replace_curve_at_point_using_geometry(const X_curve& old_cv,
|
|
const X_curve& new_cv,reference sep)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(traits->is_degenerate_point(sep));
|
|
|
|
#endif
|
|
|
|
if (!sep.is_top_unbounded() && traits->curve_is_same(sep.top(), old_cv))
|
|
sep.set_top(new_cv);
|
|
if (!sep.is_bottom_unbounded() &&
|
|
traits->curve_is_same(sep.bottom(), old_cv)) sep.set_bottom(new_cv);
|
|
}
|
|
|
|
/* update geometric boundary(top and bottom) for trapezoids
|
|
traveled along an iterator till end reached
|
|
precondition:
|
|
end==0 or end is on the path of the iterator
|
|
postcondition:
|
|
end is pointer to the last trapezoid encountered,if any
|
|
*/
|
|
void replace_curve_using_geometry(In_face_iterator & it,
|
|
const X_curve & old_cv,
|
|
const X_curve & new_cv,pointer & end)
|
|
{
|
|
pointer last=0;
|
|
while (it.operator->()!=end)
|
|
{
|
|
if (!it->is_top_unbounded() && traits->curve_is_same(it->top(),old_cv))
|
|
it->set_top(new_cv);
|
|
if (!it->is_bottom_unbounded() &&
|
|
traits->curve_is_same(it->bottom(),old_cv)) it->set_bottom(new_cv);
|
|
last=it.operator->();
|
|
++it;
|
|
}
|
|
end=last;
|
|
}
|
|
|
|
/*
|
|
description:
|
|
advances input Data structure using data structure,input point p and
|
|
possibly X_curve cv till
|
|
p is found(if cv hadn't been given)
|
|
cv is found(if cv was given)
|
|
or
|
|
leaf node reached
|
|
postcondition:
|
|
output is the closest active trapezoid to p/cv
|
|
remark:
|
|
use this function with care!
|
|
*/
|
|
/*static */
|
|
Locate_type search_using_data_structure(Data_structure& curr,Traits* traits,
|
|
const Point& p,const X_curve* cv,
|
|
Comparison_result up = EQUAL) const
|
|
{
|
|
const Point* pp;
|
|
const X_curve* pc;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
pointer old = NULL;
|
|
#endif
|
|
|
|
while(true)
|
|
{
|
|
#ifdef CGAL_TD_DEBUG
|
|
// unbounded loop
|
|
CGAL_assertion(curr.operator->() != old);
|
|
old = curr.operator->();
|
|
#endif
|
|
|
|
if (traits->is_degenerate_point(*curr))
|
|
// point node conditional (separation)
|
|
{
|
|
// extract point from trapezoid
|
|
pp = &curr->left();
|
|
if (traits->point_is_left_low(p, *pp))
|
|
{
|
|
curr = curr.left();
|
|
continue;
|
|
}
|
|
else if (traits->point_is_left_low(*pp, p))
|
|
{
|
|
curr = curr.right();
|
|
continue;
|
|
}
|
|
else if (traits->point_is_same(*pp, p))
|
|
{
|
|
if (!cv)
|
|
{
|
|
if ( up == EQUAL ) { // point found!
|
|
if (curr->is_active()) return POINT;
|
|
curr = curr.left();
|
|
}
|
|
else if ( up == LARGER ) { // vertical ray shut up
|
|
curr = curr.right();
|
|
}
|
|
else /*if ( up == SMALLER ) */ {
|
|
curr = curr.left(); // vertical ray shut down
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(
|
|
traits->point_is_same(traits->curve_leftlow_most(*cv), p) ||
|
|
traits->point_is_same(traits->curve_righttop_most(*cv), p));
|
|
#else
|
|
CGAL_assertion(
|
|
traits->point_is_same(traits->curve_leftlow_most(*cv), p) ||
|
|
traits->point_is_same(traits->curve_righttop_most(*cv), p));
|
|
#endif
|
|
curr = traits->point_is_same(traits->curve_leftlow_most(*cv), p) ?
|
|
curr.right() : curr.left();
|
|
// (Oren 14/4/02) ??
|
|
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->point_is_left_low(p,*pp) ||
|
|
traits->point_is_left_low(*pp,p) ||
|
|
traits->point_is_same(*pp,p));
|
|
#else
|
|
CGAL_assertion(traits->point_is_left_low(p,*pp) ||
|
|
traits->point_is_left_low(*pp,p) ||
|
|
traits->point_is_same(*pp,p));
|
|
#endif
|
|
|
|
return Locate_type();
|
|
}
|
|
}
|
|
if (traits->is_degenerate_curve(*curr))
|
|
{
|
|
// CURVE SEPRATION
|
|
pc = &curr->top();
|
|
Comparison_result cres = traits->curve_get_point_status(*pc,p);
|
|
if (cres == LARGER)
|
|
{
|
|
curr = curr.left();
|
|
continue;
|
|
}
|
|
else if (cres == SMALLER)
|
|
{
|
|
curr = curr.right();
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// p on CURVE
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(cres == EQUAL &&
|
|
!traits->point_is_right(p,traits->curve_rightmost(*pc))&&
|
|
!traits->point_is_left(p,traits->curve_leftmost(*pc)));
|
|
#else
|
|
|
|
CGAL_postcondition(cres == EQUAL &&
|
|
!traits->point_is_right(p,traits->curve_rightmost(*pc))&&
|
|
!traits->point_is_left(p,traits->curve_leftmost(*pc)));
|
|
#endif
|
|
if (!cv)
|
|
{
|
|
// For a vertical curve, we always visit it after visiting
|
|
// one of its endpoints.
|
|
if ((up == EQUAL) || traits->is_vertical(*curr)) {
|
|
//std::cout << "EQUAL or VERTICAL" << std::endl;
|
|
if (curr->is_active()) return CURVE;
|
|
curr = curr.left();
|
|
}
|
|
else if (up == LARGER) {
|
|
curr = curr.right();
|
|
}
|
|
else /* if (up==SMALLER) */ {
|
|
curr = curr.left();
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->point_is_same
|
|
(traits->curve_leftlow_most(*cv),
|
|
traits->curve_leftlow_most(*pc)) ||
|
|
traits->point_is_same
|
|
(traits->curve_righttop_most(*cv),
|
|
traits->curve_righttop_most(*pc)));
|
|
#else
|
|
if (!(traits->point_is_same
|
|
(traits->curve_leftlow_most(*cv),
|
|
traits->curve_leftlow_most(*pc))||
|
|
traits->point_is_same
|
|
(traits->curve_righttop_most(*cv),
|
|
traits->curve_righttop_most(*pc))))
|
|
{
|
|
std::cerr << "\npc " << *pc;
|
|
std::cerr << "\ncv " << *cv << std::endl;
|
|
CGAL_assertion(traits->point_is_same
|
|
(traits->curve_leftlow_most(*cv),
|
|
traits->curve_leftlow_most(*pc)) ||
|
|
traits->point_is_same
|
|
(traits->curve_righttop_most(*cv),
|
|
traits->curve_righttop_most(*pc)));
|
|
}
|
|
#endif
|
|
|
|
Comparison_result res =
|
|
traits->point_is_same(traits->curve_leftlow_most(*cv),
|
|
traits->curve_leftlow_most(*pc)) ?
|
|
traits->curve_compare_at_x_from_top(*pc,*cv,p) :
|
|
traits->curve_compare_at_x_from_bottom(*cv,*pc,p);
|
|
|
|
switch(res)
|
|
{
|
|
case LARGER:
|
|
curr = curr.right();
|
|
break;
|
|
case SMALLER:
|
|
curr = curr.left();
|
|
break;
|
|
case EQUAL:
|
|
switch(up)
|
|
{
|
|
case LARGER:
|
|
curr = curr.right();
|
|
break;
|
|
case SMALLER:
|
|
curr = curr.left();
|
|
break;
|
|
case EQUAL:
|
|
if (curr->is_active()) return CURVE;
|
|
curr = curr.left();
|
|
break;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
default:
|
|
CGAL_assertion(up==LARGER||up==SMALLER||up==EQUAL);
|
|
return Locate_type();
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
default:
|
|
CGAL_assertion(res == LARGER || res == SMALLER || res == EQUAL);
|
|
return Locate_type();
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// !is_degenerate()
|
|
if (curr->is_active())
|
|
return curr->is_unbounded() ? UNBOUNDED_TRAPEZOID : TRAPEZOID;
|
|
curr = curr.left();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
Data_structure container2data_structure(map_nodes& ar, int left,
|
|
int right) const
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits);
|
|
|
|
#else
|
|
|
|
CGAL_assertion(traits);
|
|
|
|
#endif
|
|
|
|
if (right>left)
|
|
{
|
|
int d=(int)CGAL_CLIB_STD::floor((double(right+left))/2);
|
|
// Replacing operator [] of map with find to please MSVC 7
|
|
Point p = (ar.find(d)->second)->right();
|
|
//Point p=ar[d]->right();
|
|
Data_structure curr=
|
|
Data_structure(
|
|
X_trapezoid(&p,&p,0,0),
|
|
container2data_structure(ar,left,d),
|
|
container2data_structure(ar,d+1,right)
|
|
);
|
|
curr.left()->set_node((Data_structure*)&curr.left());
|
|
curr.right()->set_node((Data_structure*)&curr.right());
|
|
curr->set_node(&curr);// fake temporary node
|
|
curr->remove(); // mark as deleted
|
|
curr->set_node(0);
|
|
|
|
return curr;
|
|
}
|
|
else
|
|
// Replacing operator [] of map with find to please MSVC 7
|
|
return ar.find(left)->second;
|
|
//return ar[left];
|
|
}
|
|
/*==============================================
|
|
Trapezoidal_decomposition_2 public member functions
|
|
==============================================*/
|
|
public:
|
|
|
|
Trapezoidal_decomposition_2(bool rebuild=true) :
|
|
depth_threshold(CGAL_TD_DEFAULT_DEPTH_THRESHOLD),
|
|
size_threshold(CGAL_TD_DEFAULT_SIZE_THRESHOLD)
|
|
{init();set_needs_update(rebuild);}
|
|
Trapezoidal_decomposition_2(const double& depth_th,const double& size_th) :
|
|
depth_threshold(depth_th),size_threshold(size_th)
|
|
{init();set_needs_update(rebuild);}
|
|
|
|
virtual ~Trapezoidal_decomposition_2()
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(DS);
|
|
if (!DS) return;
|
|
|
|
#else
|
|
|
|
CGAL_assertion(DS);
|
|
|
|
#endif
|
|
|
|
delete DS;
|
|
}
|
|
|
|
/* Input:
|
|
X_curve
|
|
Output:
|
|
if X_curve or twin already inserted the latter is returned.
|
|
otherwise the left-low most edge-degenerate trapezoid that represents
|
|
the input X_curve is returned
|
|
Remark:
|
|
Given an edge-degenerate trapezoid representing a X_curve,
|
|
all the other trapezoids representing the X_curve can be extracted
|
|
via moving continously to the left and right neighbours.
|
|
*/
|
|
X_trapezoid insert(curve_const_ref cv)
|
|
{
|
|
#ifdef CGAL_TD_DEBUG
|
|
*cv.get_parent();
|
|
#endif
|
|
/*
|
|
Point tmp;
|
|
// maintaining some bounding box for future use.
|
|
|
|
if (!number_of_curves_)
|
|
// give initiale values to bounding points when empty
|
|
{
|
|
POINT_AT_LEFT_TOP_INFINITY=POINT_AT_RIGHT_BOTTOM_INFINITY=
|
|
traits->curve_source(cv);
|
|
}
|
|
|
|
if (!traits->point_is_left_low(POINT_AT_LEFT_TOP_INFINITY,tmp=
|
|
traits->curve_leftlow_most(cv)))
|
|
POINT_AT_LEFT_TOP_INFINITY=traits->point_to_left(tmp);
|
|
if (!traits->point_is_right_top(POINT_AT_RIGHT_BOTTOM_INFINITY,tmp=
|
|
traits->curve_righttop_most(cv)))
|
|
POINT_AT_RIGHT_BOTTOM_INFINITY=traits->point_to_right(tmp);
|
|
*/
|
|
return insert_in_face_interior(cv);
|
|
}
|
|
|
|
/* Input:
|
|
X_curve
|
|
Output:
|
|
if X_curve or twin already inserted the latter is returned.
|
|
otherwise the left-low most edge-degenerate trapezoid that represents the
|
|
input X_curve is returned
|
|
Remark:
|
|
Given an edge-degenerate trapezoid representing a X_curve,
|
|
all the other trapezoids representing the X_curve can be extracted
|
|
via moving continously to the left and right neighbours.
|
|
*/
|
|
const X_trapezoid insert_in_face_interior(curve_const_ref cv)
|
|
{
|
|
#ifdef CGAL_TD_DEBUG
|
|
*cv.get_parent();
|
|
#endif
|
|
#ifdef CGAL_TDBB_DEBUG
|
|
std::cout << "\ninsert_in_face_interior(" << cv << ")"
|
|
<< "\nBbox " << traits->get_bounding_box();
|
|
#endif
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::insert_in_face_interior(" << cv << ") called with "
|
|
<< (is_valid(*DS) ? "valid" : "invalid") << " data structure"
|
|
<< std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
if (needs_update_) update();
|
|
// locate the input X_curve end points in the X_trapezoid Dag
|
|
|
|
CGAL_assertion(traits);
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!traits->point_is_same(traits->curve_source(cv),
|
|
traits->curve_target(cv)));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(!traits->point_is_same(traits->curve_source(cv),
|
|
traits->curve_target(cv)));
|
|
|
|
#endif
|
|
|
|
Point p[2];
|
|
int i= traits->point_is_left_low(
|
|
p[0]=traits->curve_source(cv),
|
|
p[1]=traits->curve_target(cv)
|
|
) ? 0 : 1;
|
|
Locate_type lt1,lt2;
|
|
pointer tr1,tr2;
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_optimization(p[i],tr1,lt1);
|
|
|
|
#else
|
|
|
|
tr1=&locate(p[i],lt1);
|
|
|
|
#endif
|
|
|
|
if (lt1==CURVE)
|
|
{
|
|
CGAL_precondition_msg(lt1!=CURVE,"Input is not planar as\
|
|
one of the input point inside previously inserted X_curve.");
|
|
return X_trapezoid();
|
|
}
|
|
|
|
reference t_p1=
|
|
(lt1==POINT) ?
|
|
insert_curve_at_point_using_geometry(cv,p[i],tr1,lt1) :
|
|
insert_curve_at_point_using_data_structure(cv,p[i],tr1,lt1);
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_optimization(p[1-i],tr2,lt2);
|
|
locate_opt_empty();
|
|
|
|
#else
|
|
|
|
tr2=&locate(p[1-i],lt2);
|
|
|
|
#endif
|
|
|
|
if (lt2==CURVE)
|
|
{
|
|
CGAL_precondition_msg(lt2!=CURVE,"Input is not planar as\
|
|
one of the input point inside previously inserted X_curve.");
|
|
return X_trapezoid();
|
|
}
|
|
|
|
reference t_p2= (lt2==POINT) ?
|
|
insert_curve_at_point_using_geometry(cv,p[1-i],tr2,lt2) :
|
|
insert_curve_at_point_using_data_structure(cv,p[1-i],tr2,lt2);
|
|
|
|
// locate and insert end points of the input X_curve to the X_trapezoid Dag
|
|
// if needed
|
|
Data_structure tt_p1(*t_p1.get_node());
|
|
Data_structure tt_p2(*t_p2.get_node());
|
|
|
|
// create the X_trapezoid iterator for traveling along the Trapezoids that
|
|
// intersect the input X_curve, using left-low to right-high order
|
|
In_face_iterator it=follow_curve(tt_p1,cv,LARGER);
|
|
pointer curr,prev=&t_p1,prev_bottom,prev_top;
|
|
pointer old_output = it.operator->(), old_top = 0, old_bottom = 0;
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!traits->is_degenerate(*old_output));
|
|
|
|
#else
|
|
|
|
CGAL_assertion(!traits->is_degenerate(*old_output));
|
|
|
|
#endif
|
|
|
|
old_output=0;
|
|
Data_structure *tt;
|
|
bool first_time=true;
|
|
while(!!it)
|
|
{
|
|
curr=it.operator->();
|
|
prev_bottom=curr->left_bottom_neighbour();
|
|
prev_top=curr->left_top_neighbour();
|
|
// pass using it along cv
|
|
it++;
|
|
tt = curr->get_node();
|
|
if(first_time)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
if(!curr->is_top_unbounded()&&traits->curve_is_same(curr->top(),cv))
|
|
{
|
|
CGAL_warning(!traits->curve_is_same(curr->top(),cv));
|
|
return X_trapezoid();
|
|
}
|
|
|
|
#else
|
|
|
|
CGAL_precondition(curr->is_top_unbounded()||
|
|
!traits->curve_is_same(curr->top(),cv));
|
|
|
|
#endif
|
|
|
|
}
|
|
split_trapezoid_by_curve(*tt,old_output, old_bottom, old_top, cv);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_is_same((**tt).top(),cv));
|
|
|
|
#endif
|
|
|
|
if(first_time)
|
|
{
|
|
insert_curve_at_point_using_geometry(*old_output,t_p1);
|
|
first_time=false;
|
|
}
|
|
if (tt->is_inner_node())
|
|
{
|
|
// merge adjacent trapezoids on input X_curve's bottom side if possible
|
|
if(merge_if_possible(
|
|
prev_bottom,
|
|
tt->left().operator->()
|
|
))
|
|
{
|
|
tt->set_left(*(prev_bottom->get_node()));
|
|
old_bottom = prev_bottom;
|
|
}
|
|
// merge adjacent trapezoids on input X_curve's top side if possible
|
|
if(merge_if_possible(
|
|
prev_top,
|
|
tt->right().operator->()
|
|
))
|
|
{
|
|
tt->set_right(*(prev_top->get_node()));
|
|
old_top=prev_top;
|
|
}
|
|
|
|
// update trapezoid's left/right neighbouring relations
|
|
if(!traits->is_degenerate(*prev) &&
|
|
!traits->is_degenerate(*curr))
|
|
{
|
|
curr->set_lb(prev);
|
|
curr->set_lt(prev);
|
|
prev->set_rb(curr);
|
|
prev->set_rt(curr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(curr->is_valid(traits));
|
|
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(curr->is_valid(traits));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_postcondition(traits->is_degenerate_curve(*old_output));
|
|
CGAL_postcondition(traits->curve_is_same((const X_curve)old_output->top(),
|
|
cv));
|
|
|
|
#endif
|
|
|
|
insert_curve_at_point_using_geometry(*old_output,t_p2);
|
|
number_of_curves_++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::insert_in_face_interior() exited with data structure"
|
|
<< is_valid(*DS) << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
return *old_output;
|
|
}
|
|
|
|
// removal functions
|
|
|
|
void remove(curve_const_ref cv)
|
|
// We assume here that the input curves are in planar position.
|
|
{
|
|
remove_in_face_interior(cv);
|
|
}
|
|
template <class curve_iterator>
|
|
void remove(curve_iterator begin, curve_iterator end)
|
|
{
|
|
std::random_shuffle(begin,end);
|
|
curve_iterator it=begin,next=it;
|
|
while(it!=end) {++next;remove(*it);it=next;}
|
|
}
|
|
void clear()
|
|
{
|
|
delete DS;
|
|
init();
|
|
}
|
|
|
|
void remove_in_face_interior(curve_const_ref cv)
|
|
// Assumes the map to be planar.
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::remove_in_face_interior(" << cv << ") called with "
|
|
<< (is_valid(*DS) ? "valid" : "invalid") << " data structure"
|
|
<< std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
if (needs_update_) update();
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
locate_opt_empty();
|
|
#endif
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(traits);
|
|
#else
|
|
CGAL_assertion(traits);
|
|
#endif
|
|
|
|
// calculating leftmost and rightmost points of X_curve cv
|
|
Point
|
|
leftmost=traits->curve_leftlow_most(cv),
|
|
rightmost=traits->curve_righttop_most(cv);
|
|
Locate_type lt1,lt2;
|
|
reference
|
|
t1=locate(leftmost,lt1),
|
|
t2=locate(rightmost,lt2);
|
|
|
|
CGAL_warning(lt1==POINT && lt2==POINT);
|
|
if (!(lt1==POINT && lt2==POINT)) return;
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(t1.get_node());
|
|
CGAL_warning(t2.get_node());
|
|
|
|
#endif
|
|
|
|
Data_structure
|
|
&tt1=*t1.get_node(),
|
|
&tt2=*t2.get_node();
|
|
|
|
/* calculate the immediate lower central and upper neighbourhood of the curve
|
|
in the data structure */
|
|
In_face_iterator
|
|
bottom_it(follow_curve(tt1,cv,SMALLER)),
|
|
mid_it(follow_curve(tt1,cv,EQUAL)),
|
|
top_it(follow_curve(tt1,cv,LARGER));
|
|
|
|
bool bottom, old_bottom = false, end_reached;
|
|
map_nodes new_array;
|
|
int last_index[]={0,0};
|
|
int sz=0;
|
|
Point left=bottom_it->left(),right;
|
|
pointer last_bottom,last_top,last=0,old;
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->point_is_same(top_it->left(),left));
|
|
#else
|
|
CGAL_precondition(traits->point_is_same(top_it->left(),left));
|
|
#endif
|
|
|
|
// remove adjacency at left end point
|
|
const_ref first=*mid_it;
|
|
//X_curve const * old_cv=&first.top();
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(traits->curve_is_same(first.top(),cv));
|
|
CGAL_assertion(traits->point_is_same(t1.left(),leftmost));
|
|
#endif
|
|
|
|
remove_curve_at_point_using_geometry(first,t1);
|
|
|
|
do
|
|
{
|
|
// which of bottom_it,top_it to advance.
|
|
bottom=traits->point_is_left_low(bottom_it->right(),top_it->right());
|
|
Iterator& it = bottom ? bottom_it : top_it;
|
|
pointer& last_it = bottom ? last_bottom : last_top;
|
|
right=it->right();
|
|
|
|
// copy trapezoid's content and node pointer.
|
|
typename map_nodes::value_type pair(sz,
|
|
Data_structure(
|
|
X_trapezoid(&left,&right,
|
|
!bottom_it->is_bottom_unbounded() ? &bottom_it->bottom() : 0,
|
|
!top_it->is_top_unbounded() ? &top_it->top() : 0)));
|
|
new_array.insert(pair);
|
|
Data_structure & curr = (new_array.find(sz))->second;
|
|
++sz;
|
|
curr->set_node(&curr);
|
|
curr->set_lb(bottom_it->left_bottom_neighbour());
|
|
curr->set_lt(top_it->left_top_neighbour());
|
|
if (last)
|
|
{
|
|
if (traits->trapezoid_top_curve_is_same(*last,*curr))
|
|
{
|
|
curr->set_lt(last);
|
|
}
|
|
|
|
if (traits->trapezoid_bottom_curve_is_same(*last,*curr))
|
|
{
|
|
curr->set_lb(last);
|
|
}
|
|
}
|
|
if (curr->left_bottom_neighbour())
|
|
curr->left_bottom_neighbour()->set_rb(curr.operator->());
|
|
if (curr->left_top_neighbour())
|
|
curr->left_top_neighbour()->set_rt(curr.operator->());
|
|
last=curr.operator->();
|
|
left=right;
|
|
last_bottom=bottom_it.operator->();
|
|
last_top=top_it.operator->();
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_warning(last_bottom);
|
|
CGAL_warning(last_top);
|
|
#endif
|
|
|
|
old=it.operator->();
|
|
it++;
|
|
end_reached=!bottom_it||!top_it;
|
|
if (!bottom_it ||
|
|
bottom && !traits->trapezoid_bottom_curve_is_same(*old,*it))
|
|
{
|
|
pointer rb=old->right_bottom_neighbour();
|
|
if (rb) {rb->set_lb(last);last->set_rb(rb);}
|
|
}
|
|
if (!top_it || !bottom && !traits->trapezoid_top_curve_is_same(*old,*it))
|
|
{
|
|
pointer rt=old->right_top_neighbour();
|
|
if (rt) {rt->set_lt(last);last->set_rt(rt);}
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(last->get_node());
|
|
#endif
|
|
|
|
if (old_bottom != bottom)
|
|
{
|
|
Data_structure tmp=container2data_structure(
|
|
new_array,last_index[bottom ? 0 : 1],sz-1);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nremove_in_face_interior allocated ";
|
|
write(std::cout,tmp,*traits) << "\ninto ";
|
|
write(std::cout,*last_it,*traits,false) << std::endl;
|
|
#endif
|
|
|
|
last_it->remove(&tmp);
|
|
last_index[bottom ? 0 : 1] = sz;
|
|
old_bottom = bottom;
|
|
}
|
|
else
|
|
{
|
|
Data_structure tmp=container2data_structure(new_array,sz-1,sz-1);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nremove_in_face_interior allocated ";
|
|
write(std::cout,tmp,*traits) << "\ninto ";
|
|
write(std::cout,*last_it,*traits,false) << std::endl;
|
|
#endif
|
|
|
|
last_it->remove(&tmp);
|
|
last_index[bottom ? 0 : 1] = sz;
|
|
}
|
|
const Data_structure *real=&last_it->get_node()->left();
|
|
(*real)->set_node((Data_structure*)real);
|
|
}
|
|
while(!end_reached);
|
|
Iterator & it = !old_bottom ? bottom_it : top_it;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->point_is_same(it->right(),rightmost));
|
|
#endif
|
|
|
|
pointer rb=it->right_bottom_neighbour(),rt=it->right_top_neighbour();
|
|
|
|
Data_structure tmp=container2data_structure(new_array,
|
|
last_index[!bottom ? 0 : 1],new_array.size()-1);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nremove_in_face_interior allocated ";
|
|
write(std::cout,tmp,*traits) << "\ninto ";
|
|
write(std::cout,*it,*traits,false) << std::endl;
|
|
#endif
|
|
|
|
it->remove(&tmp);
|
|
const Data_structure *real=&it->get_node()->left();
|
|
|
|
(*real)->set_node((Data_structure*)real);
|
|
if (rb) {last->set_rb(rb);rb->set_lb(last);}
|
|
if (rt) {last->set_rt(rt);rt->set_lt(last);}
|
|
|
|
Base_trapezoid_iterator last_mid=mid_it;
|
|
while(!!++mid_it)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_warning(traits->is_degenerate_curve(*last_mid));
|
|
#endif
|
|
|
|
last_mid->remove();
|
|
last_mid=mid_it;
|
|
}
|
|
|
|
// remove adjacency at right end point
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(traits->curve_is_same(cv,last_mid->top()));
|
|
CGAL_assertion(traits->point_is_same(rightmost,t2.left()));
|
|
#endif
|
|
|
|
remove_curve_at_point_using_geometry(*last_mid,t2);
|
|
last_mid->remove();
|
|
|
|
if (is_isolated_point(t1)) remove_split_trapezoid_by_point(tt1,leftmost);
|
|
if (is_isolated_point(t2)) remove_split_trapezoid_by_point(tt2,rightmost);
|
|
//freeing memory that was allocated for X_curve
|
|
//delete old_cv;
|
|
// reevaluating number of curves
|
|
number_of_curves_--;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::remove_in_face_interior() exited with data structure"
|
|
<< is_valid(*DS) << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
}
|
|
/*
|
|
output:
|
|
The active trapezoid representing the input point.
|
|
preconditions:
|
|
The trapezoidal tree is not empty
|
|
postcondition:
|
|
the input locate type is set to the type of the output trapezoid.
|
|
remarks:
|
|
locate call may change the class
|
|
*/
|
|
|
|
reference locate(const Point& p,Locate_type &t) const
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits);
|
|
CGAL_assertion(DS);
|
|
|
|
#endif
|
|
|
|
Data_structure curr=*DS;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(!!curr);
|
|
|
|
#endif
|
|
|
|
t=search_using_data_structure(curr,traits,p,0);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_postcondition(t == POINT || t == CURVE || t == TRAPEZOID ||
|
|
t == UNBOUNDED_TRAPEZOID);
|
|
|
|
#endif
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_opt_push(curr.operator->());
|
|
|
|
#endif
|
|
|
|
return *curr;
|
|
}
|
|
|
|
/* preconditions:
|
|
p is not on an edge or a vertex.
|
|
*/
|
|
|
|
curve_const_ref vertical_ray_shoot(const Point & p,Locate_type & t,
|
|
const bool up_direction = true) const
|
|
{
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_assertion(traits);
|
|
#endif
|
|
|
|
// We replace the following locate with a direct call to
|
|
// search_using_data_structure because we need to deal
|
|
// with cases where the source of shoot is a point/curve.
|
|
// reference t_p = locate(p,t);
|
|
|
|
Data_structure curr=*DS;
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_precondition(!!curr);
|
|
#endif
|
|
|
|
t = search_using_data_structure(curr, traits, p, NULL,
|
|
up_direction ?
|
|
CGAL::LARGER : CGAL::SMALLER);
|
|
reference t_p = *curr;
|
|
|
|
//std::cout << "t" << t << "\n";
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
CGAL_warning(t_p.get_node());
|
|
#endif
|
|
reference tr = **t_p.get_node();
|
|
|
|
// std::cout << "tr" << tr << "\n";
|
|
|
|
// tr should be non degenerate trapezoid
|
|
/* using exact traits, it may happen that p is on the
|
|
right side of the trapezoid directly under its
|
|
right point(analogouly directly above its left point).
|
|
with the trapezoid extending to the left.
|
|
In this case vertical ray shoot upwards(downwards)
|
|
doesn't returns c as output.
|
|
|
|
Example.
|
|
x---x
|
|
p
|
|
x------x
|
|
*/
|
|
|
|
if (up_direction && !tr.is_right_unbounded() &&
|
|
traits->point_is_same_x(p,tr.right()) &&
|
|
(tr.is_left_unbounded() ||
|
|
!traits->point_is_same(tr.left(),tr.right())) ||
|
|
!up_direction && !tr.is_left_unbounded() &&
|
|
traits->point_is_same_x(p,tr.left()) &&
|
|
(tr.is_right_unbounded() ||
|
|
!traits->point_is_same(tr.left(),tr.right())))
|
|
{
|
|
// recalculate vertical ray shoot using locate on point
|
|
return up_direction ?
|
|
locate(tr.right(),t).top() : locate(tr.left(),t).bottom();
|
|
}
|
|
|
|
curve_const_ref c = up_direction ? tr.top() : tr.bottom();
|
|
if (up_direction ? tr.is_top_unbounded() : tr.is_bottom_unbounded())
|
|
{
|
|
t=UNBOUNDED_TRAPEZOID;
|
|
}
|
|
else
|
|
{
|
|
// Now we know that the trapezoid is bounded on in the
|
|
// direction of the shoot.
|
|
t = (traits->point_is_same(p,traits->curve_source(c)) ||
|
|
traits->point_is_same(p,traits->curve_target(c))) ?
|
|
POINT : CURVE;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
/* Input:
|
|
1 whole curves
|
|
2 partial curves
|
|
Output:
|
|
X_curve
|
|
precondition:
|
|
c
|
|
The first input X_curve is the union of the other two.
|
|
The intersection of the latter is a point inside the
|
|
interior of the former.
|
|
The latter are ordered from left-down to right-up
|
|
postcondition:
|
|
The first input X_curve is broken into two curves
|
|
corresponding to the input.
|
|
The output is the degenerate point trapezoid that
|
|
corresponds to the splitting point.*/
|
|
|
|
void split_edge(curve_const_ref cv,curve_const_ref cv1, curve_const_ref cv2)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::split_edge(" << cv << "," << cv1 << "," << cv2
|
|
<< ") called with " << (is_valid(*DS) ? "valid" : "invalid")
|
|
<< " data structure" << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
if (needs_update_) update();
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_opt_empty();
|
|
|
|
#endif
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
if (!traits)
|
|
{
|
|
CGAL_warning(traits);
|
|
return;
|
|
}
|
|
if (!traits->curve_merge_condition(cv,cv1,cv2))
|
|
{
|
|
CGAL_warning(traits->curve_merge_condition(cv,cv1,cv2));
|
|
return;
|
|
}
|
|
|
|
#else
|
|
|
|
if (!traits->curve_merge_condition(cv,cv1,cv2))
|
|
{
|
|
std::cerr << "\ncv " << cv;
|
|
std::cerr << "\ncv1 " << cv1;
|
|
std::cerr << "\ncv2 " << cv2 << std::endl;
|
|
}
|
|
CGAL_precondition(traits);
|
|
CGAL_precondition(traits->curve_merge_condition(cv,cv1,cv2));
|
|
|
|
#endif
|
|
|
|
// spliting point
|
|
Point p = traits->point_is_same(traits->curve_target(cv1),
|
|
traits->curve_source(cv2)) ?
|
|
traits->curve_target(cv1) : traits->curve_target(cv2);
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(
|
|
traits->point_is_left_low(
|
|
traits->curve_leftlow_most(cv),p));
|
|
|
|
CGAL_warning(
|
|
traits->point_is_right_top(
|
|
traits->curve_righttop_most(cv),p));
|
|
|
|
#else
|
|
|
|
CGAL_precondition(
|
|
traits->point_is_left_low(
|
|
traits->curve_leftlow_most(cv),p));
|
|
|
|
CGAL_precondition(
|
|
traits->point_is_right_top(
|
|
traits->curve_righttop_most(cv),p));
|
|
|
|
#endif
|
|
|
|
// extremal points
|
|
Point
|
|
leftmost=traits->curve_leftlow_most(cv),
|
|
rightmost=traits->curve_righttop_most(cv);
|
|
Locate_type lt1,lt2;
|
|
// representing trapezoids for extremal points
|
|
reference
|
|
t1=locate(leftmost,lt1),
|
|
t2=locate(rightmost,lt2);
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(lt1==POINT && lt2==POINT);
|
|
CGAL_warning(t1.is_active() && t2.is_active());
|
|
|
|
#else
|
|
|
|
CGAL_precondition(lt1==POINT && lt2==POINT);
|
|
CGAL_precondition(t1.is_active() && t2.is_active());
|
|
CGAL_warning(t1.get_node());
|
|
CGAL_warning(t2.get_node());
|
|
|
|
#endif
|
|
|
|
Data_structure
|
|
&tt1=*t1.get_node();
|
|
In_face_iterator
|
|
bottom_it(follow_curve(tt1,cv,SMALLER)),
|
|
mid_it(follow_curve(tt1,cv,EQUAL)),
|
|
top_it(follow_curve(tt1,cv,LARGER));
|
|
Locate_type lt;
|
|
reference old_t=locate(p,lt);
|
|
//X_curve const * old_cv=&old_t.top();
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(lt==CURVE);
|
|
CGAL_precondition(old_t.is_active());
|
|
CGAL_warning(old_t.get_node());
|
|
|
|
#endif
|
|
|
|
Data_structure
|
|
&old_tt=*old_t.get_node();
|
|
|
|
// previous left and right sons of old_tt
|
|
const Data_structure
|
|
&old_left=old_tt.left(),
|
|
&old_right=old_tt.right();
|
|
|
|
X_curve left_cv,right_cv;
|
|
if (traits->point_is_same(traits->curve_leftlow_most(cv2),p))
|
|
{
|
|
left_cv=cv1;
|
|
right_cv=cv2;
|
|
}
|
|
else
|
|
{
|
|
left_cv=cv2;
|
|
right_cv=cv1;
|
|
}
|
|
const Data_structure
|
|
&new_left_tt=Data_structure(X_trapezoid(old_t.left(), p, left_cv,
|
|
left_cv), old_left, old_right),
|
|
&new_right_tt=Data_structure(X_trapezoid(p, old_t.right(), right_cv,
|
|
right_cv), old_left, old_right),
|
|
&new_tt=Data_structure(X_trapezoid(p, p, left_cv, right_cv), new_left_tt,
|
|
new_right_tt);
|
|
reference
|
|
new_left_t=*new_left_tt,
|
|
new_right_t=*new_right_tt,
|
|
new_t=*new_tt;
|
|
|
|
/* locate trapezoid trees that correspond to the closest
|
|
trapezoids above and below p */
|
|
pointer
|
|
left_top_t=top_it.operator->(),
|
|
left_bottom_t=bottom_it.operator->();
|
|
while(traits->point_is_left_low(left_top_t->right(),p))
|
|
left_top_t=left_top_t->right_bottom_neighbour();
|
|
while(traits->point_is_left_low(left_bottom_t->right(),p))
|
|
left_bottom_t=left_bottom_t->right_top_neighbour();
|
|
Data_structure
|
|
left_top=*left_top_t->get_node(),
|
|
left_bottom=*left_bottom_t->get_node();
|
|
|
|
replace_curve_at_point_using_geometry(cv,left_cv,t1);
|
|
replace_curve_at_point_using_geometry(cv,right_cv,t2);
|
|
// the point p belongs to cv interior
|
|
new_t.set_rt(&new_left_t);
|
|
new_t.set_lb(&new_right_t);
|
|
new_left_t.set_lb(old_t.left_bottom_neighbour() != &old_t ?
|
|
old_t.left_bottom_neighbour() : &new_left_t);
|
|
new_left_t.set_rt(&new_right_t);
|
|
new_right_t.set_lb(&new_left_t);
|
|
new_right_t.set_rt(old_t.right_top_neighbour() != &old_t ?
|
|
old_t.right_top_neighbour() : &new_right_t);
|
|
|
|
// update geometric boundary for trapezoids representing cv
|
|
pointer prev=0;
|
|
while(*mid_it != old_t) {
|
|
mid_it->set_top(left_cv);
|
|
mid_it->set_bottom(left_cv);
|
|
mid_it->set_right(p);
|
|
prev=mid_it.operator->();mid_it++;
|
|
}
|
|
if (prev)
|
|
{
|
|
prev->set_rb(&new_left_t);
|
|
}
|
|
// new_left_t is leftmost representative for cv
|
|
else
|
|
{
|
|
replace_curve_at_point_using_geometry(new_left_t,t1);
|
|
}
|
|
if (t1.right_top_neighbour()==&old_t) t1.set_rt(&new_left_t);
|
|
if (t1.left_bottom_neighbour()==&old_t) t1.set_lb(&new_left_t);
|
|
mid_it++;
|
|
new_right_t.set_rb(mid_it.operator->());
|
|
prev=0;
|
|
while(!!mid_it) {
|
|
mid_it->set_top(right_cv);
|
|
mid_it->set_bottom(right_cv);
|
|
mid_it->set_left(p);
|
|
prev=mid_it.operator->();
|
|
mid_it++;
|
|
}
|
|
if (prev)
|
|
{
|
|
new_right_t.set_rb(old_t.right_bottom_neighbour());
|
|
}
|
|
else
|
|
// new_right_t is rightmost representative for cv
|
|
{
|
|
replace_curve_at_point_using_geometry(new_right_t,t2,false);
|
|
}
|
|
if (t2.right_top_neighbour()==&old_t) t2.set_rt(&new_right_t);
|
|
if (t2.left_bottom_neighbour()==&old_t) t2.set_lb(&new_right_t);
|
|
|
|
/* update geometric boundary for trapezoids below cv*/
|
|
while (*bottom_it!=*left_bottom)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_is_same(bottom_it->top()
|
|
,cv));
|
|
|
|
#endif
|
|
|
|
bottom_it->set_top(left_cv);
|
|
bottom_it++;
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(*bottom_it==*left_bottom);
|
|
|
|
#endif
|
|
|
|
Data_structure &bottom_tt=*bottom_it->get_node();
|
|
bottom_it++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->is_in_closure(*bottom_tt,p));
|
|
|
|
#endif
|
|
|
|
split_trapezoid_by_point(bottom_tt,p,left_cv,right_cv);
|
|
// set the splitting trapezoid to be the same one that splits the
|
|
// X_curve'like trapezoid
|
|
*bottom_tt=new_t;
|
|
// update top curves
|
|
bottom_tt.left()->set_top(left_cv);
|
|
bottom_tt.right()->set_top(right_cv);
|
|
// left and right are not neighbours.
|
|
bottom_tt.left()->set_rt(0);
|
|
bottom_tt.right()->set_lt(0);
|
|
while(!!bottom_it)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_is_same(bottom_it->top(),cv));
|
|
|
|
#endif
|
|
|
|
bottom_it->set_top(right_cv);
|
|
bottom_it++;
|
|
}
|
|
/* update geometric boundary for trapezoids above cv*/
|
|
while (*top_it!=*left_top)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->curve_is_same(top_it->bottom(),cv));
|
|
|
|
#endif
|
|
|
|
top_it->set_bottom(left_cv);
|
|
top_it++;
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(*top_it==*left_top);
|
|
|
|
#endif
|
|
|
|
Data_structure &top_tt=*top_it->get_node();
|
|
top_it++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->is_in_closure(*bottom_tt,p));
|
|
|
|
#endif
|
|
|
|
split_trapezoid_by_point(top_tt,p,left_cv,right_cv);
|
|
// set the splitting trapezoid to be the same one that splits the
|
|
// X_curve'like trapezoid
|
|
*top_tt=new_t;
|
|
// update bottom side
|
|
top_tt.left()->set_bottom(left_cv);
|
|
top_tt.right()->set_bottom(right_cv);
|
|
// left and right aren't neighbours
|
|
top_tt.left()->set_rb(0);
|
|
top_tt.right()->set_lb(0);
|
|
while(!!top_it)
|
|
{
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(traits->curve_is_same(top_it->bottom(),cv));
|
|
|
|
#else
|
|
|
|
if (!traits->curve_is_same(top_it->bottom(),cv))
|
|
std::cout << "\ntop_it->bottom() "<< top_it->bottom() << "\t cv= "
|
|
<< cv;
|
|
CGAL_assertion(traits->curve_is_same(top_it->bottom(),cv));
|
|
|
|
#endif
|
|
|
|
top_it->set_bottom(right_cv);
|
|
top_it++;
|
|
}
|
|
// mark inactive trapezoids
|
|
old_t.remove((Data_structure*)&new_tt);
|
|
const Data_structure
|
|
*newPtr=&old_t.get_node()->left(),
|
|
*newleftPtr=&newPtr->left(),
|
|
*newrightPtr=&newPtr->right(),
|
|
*oldleftPtr=&newleftPtr->left(),
|
|
*oldrightPtr=&newleftPtr->right();
|
|
(*newPtr)->set_node((Data_structure*)newPtr);
|
|
(*newleftPtr)->set_node((Data_structure*)newleftPtr);
|
|
(*newrightPtr)->set_node((Data_structure*)newrightPtr);
|
|
(*oldleftPtr)->set_node((Data_structure*)oldleftPtr);
|
|
(*oldrightPtr)->set_node((Data_structure*)oldrightPtr);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(old_tt->is_valid(traits));
|
|
CGAL_assertion(new_tt->is_valid(traits));
|
|
CGAL_assertion((*newPtr)->is_valid(traits));
|
|
CGAL_assertion((*newleftPtr)->is_valid(traits));
|
|
CGAL_assertion((*newrightPtr)->is_valid(traits));
|
|
CGAL_assertion((*oldleftPtr)->is_valid(traits));
|
|
CGAL_assertion((*oldrightPtr)->is_valid(traits));
|
|
CGAL_assertion(top_tt->is_valid(traits));
|
|
CGAL_assertion(bottom_tt->is_valid(traits));
|
|
CGAL_assertion(old_left->is_valid(traits));
|
|
CGAL_assertion(old_right->is_valid(traits));
|
|
CGAL_assertion(traits->is_degenerate_point(**newPtr));
|
|
CGAL_assertion(traits->is_degenerate_curve(**newleftPtr));
|
|
CGAL_assertion(traits->is_degenerate_curve(**newrightPtr));
|
|
CGAL_assertion(
|
|
traits->point_is_same(
|
|
traits->curve_leftlow_most((*newrightPtr)->bottom()),
|
|
(*newPtr)->right()
|
|
)
|
|
);
|
|
CGAL_assertion(
|
|
traits->point_is_same(
|
|
traits->curve_righttop_most((*newleftPtr)->top()),
|
|
(*newPtr)->left()
|
|
)
|
|
);
|
|
#endif
|
|
|
|
// reevaluating number of curves
|
|
number_of_curves_++;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::split_edge() exited with data structure"
|
|
<< is_valid(*DS) << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
void merge_edge(
|
|
curve_const_ref cv1 ,
|
|
curve_const_ref cv2,
|
|
curve_const_ref cv)
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::merge_edge(" << cv1 << "," << cv2 << "," << cv
|
|
<< ") called with " << (is_valid(*DS) ? "valid" : "invalid")
|
|
<< " data structure" << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
if (needs_update_) update();
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_opt_empty();
|
|
|
|
#endif
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
if (!traits)
|
|
{
|
|
CGAL_warning(traits);
|
|
return;
|
|
}
|
|
if (!traits->curve_merge_condition(cv,cv1,cv2))
|
|
{
|
|
CGAL_warning(traits->curve_merge_condition(cv,cv1,cv2));
|
|
return;
|
|
}
|
|
|
|
#else
|
|
if (!traits->curve_merge_condition(cv,cv1,cv2))
|
|
{
|
|
std::cerr << "\ncv " << cv;
|
|
std::cerr << "\ncv1 " << cv1;
|
|
std::cerr << "\ncv2 " << cv2 << std::endl;
|
|
}
|
|
CGAL_assertion(traits);
|
|
CGAL_precondition(traits->curve_merge_condition(cv,cv1,cv2));
|
|
|
|
#endif
|
|
Point p=
|
|
// Calculate the common point of cv1 and cv2.
|
|
// There should be one!
|
|
traits->point_is_same(traits->curve_target(cv1),
|
|
traits->curve_source(cv2)) ?
|
|
traits->curve_target(cv1) :
|
|
// [-- cv1 -->] p [-- cv2 -->] or [<-- cv2 --] p [<-- cv1 --]
|
|
traits->point_is_same(traits->curve_source(cv1),
|
|
traits->curve_target(cv2)) ?
|
|
// [<-- cv1 --] p [<-- cv2 --] or [-- cv2 -->] p [-- cv1 -->]
|
|
traits->curve_source(cv1) : //
|
|
traits->point_is_same(traits->curve_source(cv1),
|
|
traits->curve_source(cv2)) ?
|
|
// [<-- cv1 --] p [-- cv2 -->]
|
|
traits->curve_source(cv1) :
|
|
// [-- cv1 -->] p [<-- cv2 --]
|
|
traits->curve_target(cv1);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
// p is interior to the union curve
|
|
CGAL_precondition(
|
|
traits->point_is_left_low(
|
|
traits->curve_leftlow_most(cv),p
|
|
));
|
|
CGAL_precondition(
|
|
traits->point_is_right_top(
|
|
traits->curve_righttop_most(cv),p
|
|
));
|
|
#endif
|
|
|
|
Point
|
|
leftmost=traits->curve_leftlow_most(cv),
|
|
rightmost=traits->curve_righttop_most(cv);
|
|
Locate_type lt1,lt2,lt;
|
|
reference
|
|
t1=locate(leftmost,lt1),
|
|
t2=locate(rightmost,lt2),
|
|
t=locate(p,lt);
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(t1.get_node());
|
|
CGAL_warning(t2.get_node());
|
|
CGAL_warning(t.get_node());
|
|
|
|
#else
|
|
|
|
CGAL_precondition(lt1==POINT && lt2==POINT && lt==POINT);
|
|
CGAL_precondition(t1.is_active() && t2.is_active() && t.is_active());
|
|
CGAL_assertion(t1.get_node());
|
|
CGAL_assertion(t2.get_node());
|
|
CGAL_assertion(t.get_node());
|
|
|
|
#endif
|
|
|
|
X_curve left_cv,right_cv;
|
|
if (traits->point_is_same(traits->curve_leftlow_most(cv2),p))
|
|
{
|
|
left_cv=cv1;
|
|
right_cv=cv2;
|
|
}
|
|
else
|
|
{
|
|
left_cv=cv2;
|
|
right_cv=cv1;
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(traits->point_is_same(
|
|
t1.left(),leftmost
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
t2.right(),rightmost
|
|
));
|
|
CGAL_assertion(traits->point_is_left_low(
|
|
leftmost,p
|
|
));
|
|
CGAL_assertion(traits->point_is_left_low(
|
|
p,rightmost
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_leftlow_most(left_cv),leftmost
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_righttop_most(left_cv),p
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_leftlow_most(right_cv),p
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_righttop_most(right_cv),rightmost
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_leftlow_most(cv),leftmost
|
|
));
|
|
CGAL_assertion(traits->point_is_same(
|
|
traits->curve_righttop_most(cv),rightmost
|
|
));
|
|
|
|
#endif
|
|
|
|
Data_structure
|
|
&tt1=*t1.get_node(),
|
|
&tt=*t.get_node();
|
|
In_face_iterator
|
|
bottom_left_it(follow_curve(tt1,left_cv,SMALLER)),
|
|
mid_left_it(follow_curve(tt1,left_cv,EQUAL)),
|
|
top_left_it(follow_curve(tt1,left_cv,LARGER)),
|
|
bottom_right_it(follow_curve(tt,right_cv,SMALLER)),
|
|
mid_right_it(follow_curve(tt,right_cv,EQUAL)),
|
|
top_right_it(follow_curve(tt,right_cv,LARGER));
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(bottom_left_it.operator->());
|
|
CGAL_assertion(mid_left_it.operator->());
|
|
CGAL_assertion(top_left_it.operator->());
|
|
CGAL_assertion(bottom_right_it.operator->());
|
|
CGAL_assertion(mid_right_it.operator->());
|
|
CGAL_assertion(top_right_it.operator->());
|
|
CGAL_assertion(bottom_left_it->is_active());
|
|
CGAL_assertion(mid_left_it->is_active());
|
|
CGAL_assertion(top_left_it->is_active());
|
|
CGAL_assertion(bottom_right_it->is_active());
|
|
CGAL_assertion(mid_right_it->is_active());
|
|
CGAL_assertion(top_right_it->is_active());
|
|
|
|
#endif
|
|
|
|
pointer
|
|
left=mid_left_it.operator->(),
|
|
mid_left=0,
|
|
mid_right=mid_right_it.operator->(),
|
|
top_left=0,
|
|
top_right=top_right_it.operator->(),
|
|
bottom_left=0,
|
|
bottom_right=bottom_right_it.operator->(),
|
|
right=0,
|
|
dummy=0,
|
|
dummy2=0;
|
|
replace_curve_using_geometry(mid_left_it,left_cv,cv,mid_left);
|
|
replace_curve_using_geometry(mid_right_it,right_cv,cv,right);
|
|
replace_curve_using_geometry(top_left_it,left_cv,cv,top_left);
|
|
replace_curve_using_geometry(top_right_it,right_cv,cv,dummy);
|
|
replace_curve_using_geometry(bottom_left_it,left_cv,cv,bottom_left);
|
|
replace_curve_using_geometry(bottom_right_it,right_cv,cv,dummy2);
|
|
// merge trapezoids splited by the upward and downward
|
|
// vertical extensions from p
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
merge_if_possible(top_left,top_right);
|
|
merge_if_possible(bottom_left,bottom_right);
|
|
|
|
#else
|
|
|
|
CGAL_warning(top_left);
|
|
CGAL_warning(top_right);
|
|
CGAL_warning(merge_if_possible(top_left,top_right));
|
|
CGAL_warning(bottom_left);
|
|
CGAL_warning(bottom_right);
|
|
CGAL_warning(merge_if_possible(bottom_left,bottom_right));
|
|
|
|
#endif
|
|
|
|
// mark older trapezoids as inactive
|
|
top_right->remove(top_left->get_node());
|
|
bottom_right->remove(bottom_left->get_node());
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(mid_left);
|
|
CGAL_warning(mid_right);
|
|
CGAL_warning(tt->is_active());
|
|
|
|
#endif
|
|
|
|
// make p's representative inactive
|
|
tt->remove();
|
|
mid_left->set_rb(mid_right);
|
|
mid_left->set_right(mid_right->right());
|
|
mid_right->set_left(mid_left->left());
|
|
mid_left->set_rt(0);
|
|
mid_right->set_lb(0);
|
|
replace_curve_at_point_using_geometry(left_cv,cv,t1);
|
|
replace_curve_at_point_using_geometry(right_cv,cv,t2);
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(left);
|
|
CGAL_warning(right);
|
|
|
|
#endif
|
|
|
|
replace_curve_at_point_using_geometry(*left,t1,true);
|
|
replace_curve_at_point_using_geometry(*right,t2,false);
|
|
// reevaluating number of curves
|
|
number_of_curves_--;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nTD::merge_edge() exited with data structure"
|
|
<< is_valid(*DS) << std::endl;
|
|
write(std::cout,*DS,*traits) << std::endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
unsigned long size()
|
|
{
|
|
return DS->size();
|
|
}
|
|
unsigned long depth()
|
|
{
|
|
return DS->depth();
|
|
}
|
|
unsigned long number_of_curves()
|
|
{
|
|
return number_of_curves_;
|
|
}
|
|
void init_traits(Traits* t)
|
|
{
|
|
traits = t;
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(!!*DS);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* update geometric boundary(top and bottom) for trapezoids
|
|
traveled along an iterator till end reached
|
|
precondition:
|
|
end==0 or end is on the path of the iterator
|
|
postcondition:
|
|
end is pointer to the last trapezoid encountered,if any
|
|
*/
|
|
/*------------------------------------------------------------------
|
|
description:
|
|
returns whether the Trapezoidal Dag is valid
|
|
*/
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
bool is_valid(const Data_structure& ds) const
|
|
{
|
|
return !ds || ds->is_valid(traits) && ds->get_node() &&
|
|
is_valid(ds.left()) && is_valid(ds.right());
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
description:
|
|
returns whether the member Trapezoidal data structure is valid
|
|
*/
|
|
bool is_valid() const
|
|
{
|
|
return is_valid(*DS);
|
|
}
|
|
|
|
void debug()
|
|
{
|
|
std::cout << "\nTrapezoidal_decomposition_2<Traits>::debug()\n" << *this
|
|
<< std::endl;
|
|
X_trapezoid x;
|
|
x.debug();
|
|
}
|
|
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------
|
|
description:
|
|
Rebuilds the trapezoid data structure by reinserting the curves
|
|
in a random order in an empty data structure.
|
|
|
|
postcondition:
|
|
The old and new data structures agree on their member curves.
|
|
------------------------------------------------------------------*/
|
|
Self& rebuild()
|
|
{
|
|
#ifdef CGAL_TD_DEBUG
|
|
std::cout << "\nrebuild()" << std::flush;
|
|
#endif
|
|
|
|
X_curve_container content;
|
|
unsigned long rep = container(content);
|
|
clear();
|
|
|
|
// initialize content to point to curves in X_trapezoid Tree
|
|
if (rep>0)
|
|
{
|
|
bool o=set_needs_update(false);
|
|
typename std::vector<X_curve>::iterator it = content.begin(),
|
|
it_end = content.end();
|
|
while(it!=it_end)
|
|
{
|
|
insert(*it);
|
|
++it;
|
|
}
|
|
set_needs_update(o);
|
|
}
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_assertion(is_valid());
|
|
unsigned long sz=number_of_curves();
|
|
if(sz!=rep)
|
|
{
|
|
std::cerr << "\nnumber_of_curves()=" << sz;
|
|
std::cerr << "\nrepresentatives.size()=" << rep;
|
|
CGAL_assertion(number_of_curves()==rep);
|
|
}
|
|
|
|
#endif
|
|
|
|
content.clear();
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
Input:
|
|
a list of pointers to X_trapezoids and a X_trapezoid boolean predicate.
|
|
Output:
|
|
void
|
|
Postcondition:
|
|
the list pointers correspond to all the X_trapezoids in the data
|
|
structure for which the predicate value is true.
|
|
*/
|
|
|
|
template <class Container,class Predicate>
|
|
void container(Container& c, const Predicate& pr) const
|
|
{
|
|
DS->filter(c,pr);
|
|
}
|
|
unsigned long container(X_curve_container& content)
|
|
{
|
|
unsigned long sz=number_of_curves();
|
|
list_container representatives;
|
|
container(representatives,
|
|
Active_right_degenerate_curve_trapezoid(*traits));
|
|
|
|
#ifndef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(sz==representatives.size());
|
|
|
|
#else
|
|
|
|
unsigned long rep=representatives.size();
|
|
if (sz!=rep)
|
|
{
|
|
std::cerr << "\nnumber_of_curves()=" << sz;
|
|
std::cerr << "\nrepresentatives.size()=" << rep;
|
|
CGAL_assertion(number_of_curves()==representatives.size());
|
|
}
|
|
|
|
#endif
|
|
|
|
if (sz>0)
|
|
{
|
|
typename list_container::iterator it = representatives.begin(),
|
|
it_end = representatives.end();
|
|
while(it!=it_end)
|
|
{
|
|
content.push_back(it->top());
|
|
++it;
|
|
}
|
|
}
|
|
std::random_shuffle(content.begin(),content.end());
|
|
return sz;
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
Input:
|
|
None
|
|
Output:
|
|
bool
|
|
Description:
|
|
determines according to pre defined conditions whether the
|
|
current Trapezoidal_decomposition_2<Traits> needs update
|
|
Postconditions:
|
|
The output is true iff the depth of the Trapezoidal Tree is more then
|
|
DepthThreshold times log of the X_curve count or the Trapezoidal Tree's
|
|
size
|
|
is more then SizeThreshold times the log of the last count.
|
|
*/
|
|
bool set_needs_update(bool u)
|
|
{
|
|
bool old=needs_update_;
|
|
needs_update_=u;
|
|
return old;
|
|
}
|
|
bool needs_update()
|
|
{
|
|
unsigned long sz = number_of_curves();
|
|
//to avoid signed / unsigned conversion warnings
|
|
// rand() returns an int but a non negative one.
|
|
if (static_cast<unsigned long>(rand()) >
|
|
RAND_MAX / (sz+1))
|
|
return false;
|
|
/* INTERNAL COMPILER ERROR overide
|
|
#ifndef __GNUC__
|
|
*/
|
|
#ifdef CGAL_TD_REBUILD_DEBUG
|
|
std::cout << "\n|heavy!" << std::flush;
|
|
#endif
|
|
return
|
|
depth()>(get_depth_threshold()*(CGAL_CLIB_STD::log(double(sz+1))))
|
|
|| size()>(get_size_threshold()*(sz+1));
|
|
/*
|
|
#else
|
|
// to avoid comparison between signed and unsigned
|
|
return ((depth()/10)>log(sz+1))||((size()/10)>(sz+1));
|
|
//return ((((signed)depth())/10)>log(sz+1))||
|
|
((((signed)size())/10)>(sz+1));
|
|
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
input:
|
|
None
|
|
output:
|
|
bool
|
|
Description:
|
|
uses needs_update to determine whether the
|
|
Trapezoidal_decomposition_2<Traits> needs update
|
|
and calls rebuild accordingly
|
|
Postcondition:
|
|
the return value is true iff rebuilding took place.
|
|
*/
|
|
bool update()
|
|
{
|
|
#ifdef CGAL_TD_REBUILD_DEBUG
|
|
std::cout << "\n|" << needs_update() << std::flush;
|
|
#endif
|
|
if (needs_update()) {rebuild();return true;}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* returns a reference to the internal data structure */
|
|
const Data_structure& get_data_structure() const {return *DS;}
|
|
|
|
/* returns a reference to the internal data structure */
|
|
const Traits& get_traits() const {return *traits;}
|
|
|
|
/* returns a reference to the internal depth threshold constant */
|
|
const double& get_depth_threshold() const
|
|
{
|
|
return depth_threshold;
|
|
}
|
|
/* returns a reference to the internal size threshold constant */
|
|
const double& get_size_threshold() const
|
|
{
|
|
return size_threshold;
|
|
}
|
|
/* sets the internal depth threshold constant to the parameter and
|
|
returns its reference */
|
|
const double& set_depth_threshold(const double& depth_th)
|
|
{
|
|
return depth_threshold=depth_th;
|
|
}
|
|
|
|
/* sets the internal size threshold constant to the parameter and
|
|
returns its reference */
|
|
const double& set_size_threshold(const double& size_th)
|
|
{
|
|
return size_threshold=size_th;
|
|
}
|
|
protected:
|
|
Data_structure* DS;
|
|
bool needs_update_;
|
|
unsigned long number_of_curves_;
|
|
Traits* traits;
|
|
|
|
private:
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
mutable pointer last_cv,prev_cv;
|
|
|
|
#endif
|
|
|
|
void init()
|
|
{
|
|
// traits may be initialized later
|
|
DS = new Data_structure(X_trapezoid());
|
|
(*DS)->set_node(DS);
|
|
|
|
|
|
|
|
/* Point tmp;
|
|
if (!traits->point_is_left_low(TD_X_trapezoid<Traits,
|
|
X_curve>::POINT_AT_LEFT_TOP_INFINITY,tmp=TD_X_trapezoid<Traits,
|
|
X_curve>::POINT_AT_RIGHT_BOTTOM_INFINITY))
|
|
TD_X_trapezoid<Traits,
|
|
X_curve>::POINT_AT_LEFT_TOP_INFINITY=traits->point_to_left(tmp);
|
|
*/
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_warning(!!*DS);
|
|
|
|
#endif
|
|
|
|
number_of_curves_=0;
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
locate_opt_empty();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef CGAL_NO_TRAPEZOIDAL_DECOMPOSITION_2_OPTIMIZATION
|
|
|
|
void locate_opt_push(pointer cv) const
|
|
{
|
|
prev_cv=last_cv;
|
|
last_cv=cv;
|
|
}
|
|
void locate_opt_empty() const
|
|
{
|
|
last_cv=prev_cv=0;
|
|
}
|
|
bool locate_opt_swap(pointer& cv) const
|
|
{
|
|
cv=last_cv;
|
|
last_cv=prev_cv;
|
|
prev_cv=cv;
|
|
return (cv!=0);
|
|
}
|
|
void locate_optimization(const Point& p,pointer& tr,Locate_type& lt) const
|
|
{
|
|
// optimization
|
|
if (locate_opt_swap(tr)&&tr->is_active()&&
|
|
(traits->is_degenerate_point(*tr)&&
|
|
traits->point_is_same(tr->left(),p)||
|
|
!traits->is_degenerate(*tr)&&
|
|
traits->is_inside(*tr,p)
|
|
)||
|
|
locate_opt_swap(tr)&&tr->is_active()&&
|
|
(traits->is_degenerate_point(*tr)&&
|
|
traits->point_is_same(tr->left(),p)||
|
|
!traits->is_degenerate(*tr)&&
|
|
traits->is_inside(*tr,p)
|
|
)
|
|
)
|
|
if(traits->is_degenerate_point(*tr)) lt=POINT;
|
|
else lt=tr->is_unbounded()?UNBOUNDED_TRAPEZOID:TRAPEZOID;
|
|
else
|
|
tr=&locate(p,lt);
|
|
}
|
|
|
|
#endif
|
|
|
|
protected:
|
|
bool is_isolated_point(const_ref tr) const
|
|
{
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
|
|
CGAL_precondition(traits->is_degenerate_point(tr));
|
|
|
|
#endif
|
|
|
|
return !tr.right_top_neighbour()&&!tr.left_bottom_neighbour();
|
|
}
|
|
|
|
protected:
|
|
double depth_threshold,size_threshold;
|
|
};
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#ifndef CGAL_TD_X_TRAPEZOID_H
|
|
#include <CGAL/Td_X_trapezoid.h>
|
|
#endif
|
|
|
|
#ifdef CGAL_TD_DEBUG
|
|
#ifndef CGAL_TRAPEZOIDAL_DECOMPOSITION_2_IOSTREAM_H
|
|
#include <CGAL/IO/Trapezoidal_decomposition_2_iostream.h>
|
|
#endif
|
|
#endif
|
|
|
|
#endif// CGAL_TRAPEZOIDAL_DECOMPOSITION_2_H
|