implemented polygon validation as global functions in Gps_polygon_validation.h instead of using afunctor from the GpsTraits2 model

This commit is contained in:
Guy Zucker 2009-02-05 15:39:55 +00:00
parent 2ccf2ba9cc
commit fa507ef863
20 changed files with 938 additions and 230 deletions

11
.gitattributes vendored
View File

@ -1255,9 +1255,20 @@ Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes2.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes3.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes4.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes5.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test1.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test2.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test3.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test4.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test5.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test6.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test7.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test8.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/val_test9.dat -text
Boolean_set_operations_2/test/Boolean_set_operations_2/data/validation/validation_test_output.txt -text
Boolean_set_operations_2/test/Boolean_set_operations_2/test_agg_op.cmd eol=lf
Boolean_set_operations_2/test/Boolean_set_operations_2/test_bop.cmd eol=lf
Boolean_set_operations_2/test/Boolean_set_operations_2/test_connect_holes.cpp -text
Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp -text
Box_intersection_d/doc_tex/Box_intersection_d/fig/benchmark.eps -text svneol=unset#application/postscript
Box_intersection_d/doc_tex/Box_intersection_d/fig/benchmark.gif -text svneol=unset#image/gif
Box_intersection_d/doc_tex/Box_intersection_d/fig/benchmark.pdf -text svneol=unset#application/pdf

View File

@ -1,4 +1,4 @@
// Copyright (c) 2005 Tel-Aviv University (Israel).
// Copyright (c) 2008 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
@ -11,37 +11,87 @@
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s): Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il>
// Boris Kozorovitzky <boriskoz@post.tau.ac.il>
// Guy Zucker <guyzucke@post.tau.ac.il>
#ifndef CGAL_GPS_POLYGON_VALIDATION_VISITOR_H
#define CGAL_GPS_POLYGON_VALIDATION_VISITOR_H
#ifndef CGAL_GPS_POLYGON_VALIDATION_2_H
#define CGAL_GPS_POLYGON_VALIDATION_2_H
#include <CGAL/Sweep_line_2.h>
#include <CGAL/Sweep_line_2/Sweep_line_event.h>
#include <CGAL/Sweep_line_2/Sweep_line_subcurve.h>
#include <CGAL/Sweep_line_empty_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_traits_adaptor.h>
#include <CGAL/Boolean_set_operations_2/Gps_default_dcel.h>
#include <CGAL/General_polygon_set_2.h>
#include <list>
#include <iterator>
#include <CGAL/Arr_naive_point_location.h>
#include <iostream>
#include <CGAL/Arr_default_overlay_traits.h>
/*Arrangement is templated with extended face dcel*/
template<typename Arrangement_2>
class ValidationOverlayTraits : public CGAL::Arr_default_overlay_traits<Arrangement_2>
{
public:
typedef CGAL::Arr_default_overlay_traits<Arrangement_2> Base;
typedef typename Base::Face_handle_A Face_handle_A;
typedef typename Base::Face_handle_B Face_handle_B;
typedef typename Base::Face_handle_R Face_handle_R;
typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator;
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
typedef typename Arrangement_2::Hole_const_iterator Hole_const_iterator;
/*red faces source is the arrangement of holes. The blue faces (face) are caused by the PWH's outer boundary*/
virtual void create_face(Face_handle_A red_face, Face_handle_B blue_face, Face_handle_R r_face) {
if ((red_face->contained()==true) && (blue_face->contained()==false)) {
hole_overlap=true;
}
}
public:
ValidationOverlayTraits() : hole_overlap(false) {}
bool getHoleOverlap() {
return hole_overlap;
}
void setHoleOverlap(bool b) {
hole_overlap=b; return;
}
private:
bool hole_overlap;
};
CGAL_BEGIN_NAMESPACE
#define CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF \
typedef Gps_traits_adaptor<Traits_2> Traits_adapter_2;\
typedef typename Traits_2::Curve_const_iterator Curve_const_iterator;\
typedef std::pair<Curve_const_iterator,Curve_const_iterator> Cci_pair;\
typedef typename Traits_2::Construct_curves_2 Construct_curves_2;\
typedef typename Traits_adapter_2::Construct_vertex_2 Construct_vertex_2;
/*! \class
* A visitor used for checking whether the edges of a polygon are
* non-intersecting.
*/
template <class ArrTraits_>
class Gps_polygon_validation_visitor :
public Sweep_line_empty_visitor<ArrTraits_>
{
private:
typedef ArrTraits_ Traits_2;
typedef Gps_polygon_validation_visitor<Traits_2> Self;
typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2;
typedef typename Traits_2::Point_2 Point_2;
@ -105,118 +155,26 @@ protected:
};
/*! \class
* An uxiliary functor used for checking the validity of polygons.
*/
template <class Traits_, class TraitsAdapter_>
class Is_valid_2
//Traits_2 templates the General_polygon_set_2 Traits.
//These include types for polygon and PWH.
template <typename Traits_2>
bool is_closed_polygon(const typename Traits_2::Polygon_2& pgn, Traits_2 traits)
{
public:
typedef Traits_ Traits_2;
typedef TraitsAdapter_ Traits_adapter_2;
private:
typedef typename Traits_2::Point_2 Point_2;
typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2;
typedef typename Traits_2::Polygon_2 Polygon_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_with_holes_2::Hole_const_iterator
Hole_const_iterator;
typedef typename Traits_2::Curve_const_iterator Curve_const_iterator;
typedef std::pair<Curve_const_iterator,
Curve_const_iterator> Cci_pair;
typedef typename Traits_2::Construct_curves_2 Construct_curves_2;
typedef typename Traits_adapter_2::Construct_vertex_2
Construct_vertex_2;
typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2;
typedef Gps_polygon_validation_visitor<Traits_2> Visitor;
typedef Sweep_line_2<Traits_2, Visitor> Sweep_line ;
private:
// Data members:
Construct_curves_2 construct_curves_func;
Construct_vertex_2 construct_vertex_func;
Check_orientation_2 check_orientation_func;
public:
/*! Constructor. */
Is_valid_2 (Traits_2& traits,
const Traits_adapter_2& tr_adapter)
{
construct_curves_func = traits.construct_curves_2_object();
construct_vertex_func = tr_adapter.construct_vertex_2_object();
check_orientation_func = tr_adapter.orientation_2_object();
}
/*! Check if the given polygon is valid. */
bool operator()(const Polygon_2& pgn)
{
bool is_closed = _is_closed(pgn);
CGAL_warning_msg (is_closed,
"The polygon's boundary is not closed.");
if (! is_closed)
return (false);
bool has_valid_orientation = _has_valid_orientation(pgn);
CGAL_warning_msg (has_valid_orientation,
"The polygon has a wrong orientation.");
if (! has_valid_orientation)
return (false);
bool is_strictly_simple = _is_strictly_simple(pgn);
CGAL_warning_msg (is_strictly_simple,
"The polygon is not strictly simple.");
if (! is_strictly_simple)
return (false);
return (true);
}
/*! Check if the given polygon with holes is valid. */
bool operator()(const Polygon_with_holes_2& pgn)
{
bool is_closed = _is_closed(pgn);
CGAL_warning_msg (is_closed,
"The polygon's boundary is not closed.");
if (! is_closed)
return (false);
bool has_valid_orientation = _has_valid_orientation(pgn);
CGAL_warning_msg (has_valid_orientation,
"The polygon has a wrong orientation.");
if (! has_valid_orientation)
return (false);
bool is_simple = _is_simple(pgn);
CGAL_warning_msg (is_simple,
"The polygon is not simple.");
if (! is_simple)
return (false);
return (true);
}
protected:
bool _is_closed(const Polygon_2& pgn)
{
Cci_pair itr_pair = construct_curves_func (pgn);
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
Cci_pair itr_pair = traits.construct_curves_2_object()(pgn);
Curve_const_iterator begin = itr_pair.first;
Curve_const_iterator end = itr_pair.second;
if (begin == end)
return (true); // An empty polygon is valid.
Traits_2 tr;
typename Traits_2::Equal_2 equal_func = tr.equal_2_object();
Traits_adapter_2 traits_adapter;
typename Traits_2::Equal_2 equal_func = traits.equal_2_object();
Curve_const_iterator curr, next;
Construct_vertex_2 construct_vertex_func;
construct_vertex_func = traits_adapter.construct_vertex_2_object();
curr = next = begin;
++next;
@ -250,30 +208,16 @@ protected:
return (true);
}
template <typename Traits_2>
bool is_simple_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits)
{// Previously known as is_strictly_simple
bool _is_closed (const Polygon_with_holes_2& pgn)
{
Traits_2 traits;
if(! _is_closed (traits.construct_outer_boundary_object()(pgn)))
return (false);
Hole_const_iterator itr;
std::pair<Hole_const_iterator, Hole_const_iterator> pair = traits.construct_holes_object()(pgn);
for (itr = pair.first; itr!=pair.second; ++itr)
//for (itr = pgn.holes_begin(); itr != pgn.holes_end(); ++itr)
{
if(! _is_closed (*itr))
return (false);
}
return (true);
}
bool _is_strictly_simple (const Polygon_2& pgn)
{
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
// Sweep the boundary curves and look for intersections.
Cci_pair itr_pair = construct_curves_func (pgn);
Traits_2 traits;
typedef Gps_polygon_validation_visitor<Traits_2> Visitor;
typedef Sweep_line_2<Traits_2, Visitor> Sweep_line;
Cci_pair itr_pair = traits.construct_curves_2_object()(pgn);
Visitor visitor;
Sweep_line sweep_line (&traits, &visitor);
@ -281,53 +225,329 @@ protected:
return (visitor.is_valid());
}
bool _is_simple (const Polygon_with_holes_2& pgn)
template <typename Traits_2>
bool has_valid_orientation_polygon (const typename Traits_2::Polygon_2& pgn,Traits_2 traits)
{
// Construct a container of all boundary curves.
Traits_2 traits;
Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pgn);
Cci_pair itr_pair = construct_curves_func(pgn2);
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
std::list<X_monotone_curve_2> curves;
std::copy (itr_pair.first, itr_pair.second,
std::back_inserter(curves));
std::pair<Hole_const_iterator, Hole_const_iterator> pair = traits.construct_holes_object()(pgn);
Hole_const_iterator hoit;
for (hoit = pair.first; hoit!=pair.second; ++hoit)
//for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit)
{
itr_pair = construct_curves_func (*hoit);
std::copy (itr_pair.first, itr_pair.second,
std::back_inserter(curves));
}
// Perform the sweep and check fir intersections.
//Traits_2 traits; moved to top, needed also for boundary.
Visitor visitor(false);
Sweep_line sweep_line (&traits, &visitor);
visitor.sweep (curves.begin(), curves.end());
return (visitor.is_valid());
}
bool _has_valid_orientation (const Polygon_2& pgn)
{
Cci_pair itr_pair = construct_curves_func (pgn);
Cci_pair itr_pair = traits.construct_curves_2_object()(pgn);
Traits_adapter_2 traits_adapter;
typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2;
if(itr_pair.first == itr_pair.second)
return (true); // empty polygon
return (check_orientation_func (itr_pair.first,
return (traits_adapter.orientation_2_object()(itr_pair.first,
itr_pair.second) == COUNTERCLOCKWISE);
}
bool _has_valid_orientation (const Polygon_with_holes_2& pgn)
/* A valid polygon is :
* 1 - Closed or empty polygon
* 2 - Simple (previously known as strictly simple)
* 3 - Counterclockwise oriented
*/
template <typename Traits_2>
bool is_valid_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits)
{
bool closed = is_closed_polygon(pgn,traits);
CGAL_warning_msg (closed,
"The polygon's boundary is not closed.");
if (! closed)
return (false);
bool simple = is_simple_polygon(pgn,traits);
CGAL_warning_msg (simple,
"The polygon is not simple.");
if (!simple)
return (false);
bool valid_orientation = has_valid_orientation_polygon(pgn,traits);
CGAL_warning_msg (valid_orientation,
"The polygon has a wrong orientation.");
if (! valid_orientation)
return (false);
return (true);
}
template <typename Traits_2>
bool is_closed_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits)
{
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
if(! is_closed_polygon (pgn.outer_boundary(),traits))
return (false);
typename Polygon_with_holes_2::Hole_const_iterator itr;
for (itr = pgn.holes_begin(); itr != pgn.holes_end(); ++itr)
{
if(! is_closed_polygon (*itr,traits))
return (false);
}
return (true);
}
template<typename Traits_2>
bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits ) {
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
typedef typename Traits_2::Point_2 Point_2;
typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2;
typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2;
typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2;
typedef CGAL::Gps_default_dcel<Traits_2> dcel;
typedef CGAL::General_polygon_set_2<Traits_2, dcel> Polygon_set_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_set_2::Arrangement_2 Arrangement_2;
typedef typename Arrangement_2::Halfedge_handle Halfedge_handle;
typedef typename Arrangement_2::Vertex_handle Vertex_handle;
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
typedef typename Traits_2::Curve_const_iterator Curve_const_iterator;
typedef CGAL::Arr_naive_point_location<Arrangement_2> Naive_pl;
typename std::list<Halfedge_handle> he_path;
typename std::list<Halfedge_handle>::iterator he_itr;
//functors used throughout the function
Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object();
Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object();
Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object();
Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary());
Curve_const_iterator begin = itr_pair.first;
Curve_const_iterator end = itr_pair.second;
if (begin == end)
return (true); // An empty polygon is valid.
//handles to consecutive curves
Curve_const_iterator curr, next;
curr = next = begin;
//handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex.
//the other maintains the next curve's second vertex if it already exists in the arrangement.
Vertex_handle joint_ver, second_ver;
//closed check guarantees polygon has more than 1 curve
++next;
//halfedge handle whose target is always the joint vertex between next and curr.
Halfedge_handle last_he;
Polygon_set_2 gps(traits);
Arrangement_2 arr = gps.arrangement();
Naive_pl pl (arr);
//insert first edge lexicographically to arrangement
// compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex
last_he = CGAL::insert_non_intersecting_curve(arr, *curr);
if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction
joint_ver = last_he->target();
he_path.push_back(last_he);
} else { //polygon's boundary first curve not lexicographic
joint_ver = last_he->source();
he_path.push_back(last_he->twin());
}
/*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees
equal_func (construct_vertex_func (*curr, 1), construct_vertex_func (*next, 0))) */
while (next != end) {
CGAL::Object obj;
Vertex_const_handle cver;
Point_2 second_point;
if(cmp_endpoints(*next) == SMALLER) {
//next curve's minimum is the joint vertex. Look if it's max exists in the arrangement and insert lexicographically
second_point = max_functor(*next);
obj = pl.locate(second_point);
if (CGAL::assign (cver, obj)) {
//insert where both vertices exist
second_ver = arr.non_const_handle(cver);
last_he = arr.insert_at_vertices( *next, joint_ver, second_ver);
} else //insert from left vertex
last_he = arr.insert_from_left_vertex ( *next,joint_ver) ;
} else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices
second_point = min_functor(*next);
obj = pl.locate(second_point);
if (CGAL::assign (cver, obj)) {
//insert where both vertices exist
second_ver = arr.non_const_handle(cver);
last_he = arr.insert_at_vertices( *next, joint_ver, second_ver);
} else //insert from right vertex
last_he = arr.insert_from_right_vertex ( *next,joint_ver) ;
}
// Move to the next pair of edges.
he_path.push_back(last_he);
joint_ver=last_he->target();
curr = next;
++next;
} //end of while
/*We created a path of halfedges that circulates the polygon counterclockwise (curves . The
polygon should ly on the left of each of these half edges. If the boundary is invalid, the unbounded face should
be on the left of one of more than one of the halfedges*/
typename Arrangement_2::Face_const_handle cfh;
typename Arrangement_2::Face_handle fh;
cfh = arr.unbounded_face();
fh = arr.non_const_handle(cfh);
for (he_itr = he_path.begin();he_itr != he_path.end();he_itr++) {
Halfedge_handle cur = *he_itr;
if (cur->face() == fh)
return false;
}
return true;
}
//templated point location version
template<typename Traits_2, class PointLocation>
bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits, const PointLocation& pl ) {
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
typedef typename Traits_2::Point_2 Point_2;
typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2;
typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2;
typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2;
typedef CGAL::Gps_default_dcel<Traits_2> dcel;
typedef CGAL::General_polygon_set_2<Traits_2, dcel> Polygon_set_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_set_2::Arrangement_2 Arrangement_2;
typedef typename Arrangement_2::Halfedge_handle Halfedge_handle;
typedef typename Arrangement_2::Vertex_handle Vertex_handle;
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
typedef typename Traits_2::Curve_const_iterator Curve_const_iterator;
typedef CGAL::Arr_naive_point_location<Arrangement_2> Naive_pl;
typename std::list<Halfedge_handle> he_path;
typename std::list<Halfedge_handle>::iterator he_itr;
//functors used throughout the function
Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object();
Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object();
Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object();
Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary());
Curve_const_iterator begin = itr_pair.first;
Curve_const_iterator end = itr_pair.second;
if (begin == end)
return (true); // An empty polygon is valid.
//handles to consecutive curves
Curve_const_iterator curr, next;
curr = next = begin;
//handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex.
//the other maintains the next curve's second vertex if it already exists in the arrangement.
Vertex_handle joint_ver, second_ver;
//closed check guarantees polygon has more than 1 curve
++next;
//halfedge handle whose target is always the joint vertex between next and curr.
Halfedge_handle last_he;
Polygon_set_2 gps(traits);
Arrangement_2 arr = gps.arrangement();
//insert first edge lexicographically to arrangement
// compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex
last_he = CGAL::insert_non_intersecting_curve(arr, *curr);
if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction
joint_ver = last_he->target();
he_path.push_back(last_he);
} else { //polygon's boundary first curve not lexicographic
joint_ver = last_he->source();
he_path.push_back(last_he->twin());
}
/*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees
equal_func (construct_vertex_func (*curr, 1), construct_vertex_func (*next, 0))) */
while (next != end) {
CGAL::Object obj;
Vertex_const_handle cver;
Point_2 second_point;
if(cmp_endpoints(*next) == SMALLER) {
//next curve's minimum is the joint vertex. Look if it's max exists in the arrangement and insert lexicographically
second_point = max_functor(*next);
obj = pl.locate(second_point);
if (CGAL::assign (cver, obj)) {
//insert where both vertices exist
second_ver = arr.non_const_handle(cver);
last_he = arr.insert_at_vertices( *next, joint_ver, second_ver);
} else //insert from left vertex
last_he = arr.insert_from_left_vertex ( *next,joint_ver) ;
} else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices
second_point = min_functor(*next);
obj = pl.locate(second_point);
if (CGAL::assign (cver, obj)) {
//insert where both vertices exist
second_ver = arr.non_const_handle(cver);
last_he = arr.insert_at_vertices( *next, joint_ver, second_ver);
} else //insert from right vertex
last_he = arr.insert_from_right_vertex ( *next,joint_ver) ;
}
// Move to the next pair of edges.
he_path.push_back(last_he);
joint_ver=last_he->target();
curr = next;
++next;
} //end of while
/*We created a path of halfedges that circulates the polygon counterclockwise (curves . The
polygon should ly on the left of each of these half edges. If the boundary is invalid, the unbounded face should
be on the left of one of more than one of the halfedges*/
typename Arrangement_2::Face_const_handle cfh;
typename Arrangement_2::Face_handle fh;
cfh = arr.unbounded_face();
fh = arr.non_const_handle(cfh);
for (he_itr = he_path.begin();he_itr != he_path.end();he_itr++) {
Halfedge_handle cur = *he_itr;
if (cur->face() == fh)
return false;
}
return true;
}
template <typename Traits_2>
bool is_relatively_simple_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits)
{// previously known as Simple
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2;
typedef Gps_polygon_validation_visitor<Traits_2> Visitor;
typedef Sweep_line_2<Traits_2, Visitor> Sweep_line;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
Construct_curves_2 construct_curves_func = traits.construct_curves_2_object();
// Construct a container of all outer boundary curves.
Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary());
std::list<X_monotone_curve_2> outer_curves;
std::copy (itr_pair.first, itr_pair.second,
std::back_inserter(outer_curves));
//create visitor and sweep to verify outer boundary is relatively simple
Visitor relative_visitor(false);
Sweep_line sweep_line (&traits, &relative_visitor);
relative_visitor.sweep (outer_curves.begin(), outer_curves.end());
if (!relative_visitor.is_valid())
return false;
//verify every hole is simple
typename Polygon_with_holes_2::Hole_const_iterator hoit;
std::list<X_monotone_curve_2> hole_curves;
for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit)
{
bool simple_hole = is_simple_polygon(*hoit,traits);
if (!simple_hole)
return false;
}
return true;
}
template <typename Traits_2>
bool has_valid_orientation_polygon_with_holes (const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits)
{
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2;
typedef Gps_polygon_validation_visitor<Traits_2> Visitor;
typedef Sweep_line_2<Traits_2, Visitor> Sweep_line;
typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
Traits_adapter_2 traits_adapter;
Construct_curves_2 construct_curves_func = traits.construct_curves_2_object();
Check_orientation_2 check_orientation_func = traits_adapter.orientation_2_object();;
// Check the orientation of the outer boundary.
Traits_2 traits;
Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pgn);
Cci_pair itr_pair = construct_curves_func (pgn2);
Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary());
if ((itr_pair.first != itr_pair.second) &&
check_orientation_func (itr_pair.first,
@ -337,11 +557,9 @@ protected:
}
// Check the orientation of each of the holes.
// typename Polygon_with_holes_2::
Hole_const_iterator hoit;
std::pair<Hole_const_iterator, Hole_const_iterator> pair = traits.construct_holes_object()(pgn);
for (hoit = pair.first; hoit!=pair.second;++hoit)
//for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit)
typename Polygon_with_holes_2::Hole_const_iterator hoit;
for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit)
{
itr_pair = construct_curves_func (*hoit);
@ -352,11 +570,206 @@ protected:
return (false);
}
}
return (true);
}
/*Verify holes do not intersect between themselves as well with the outer boundary
(except intersection on a vertex which is allowed).
This efficient implementation utilizes the general poygon set for aggregated join
operations for N holes which should result in a GPS that contains N independent PWH.
Executing a difference(gps, outer boundary) should result in an empty set if
no holes intersect the boundary.
An iterative use of the difference free function while iterating over the holes
may have an advantage in case there are numerous holes that intersect the boundary
and the iterative loop will be stopped after a small number of iterations.
*/
template <class Traits_2>
bool are_holes_and_boundary_pairwise_disjoint(const typename Traits_2::Polygon_with_holes_2& pwh, Traits_2 traits)
{
CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF
typedef CGAL::Gps_default_dcel<Traits_2> dcel;
typedef CGAL::General_polygon_set_2<Traits_2, dcel> Polygon_set_2;
typedef typename Polygon_set_2::Size Size;
typedef typename Traits_2::Polygon_2 Polygon_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_with_holes_2::Hole_const_iterator Hole_const_iterator;
typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2;
typedef std::pair<Curve_const_iterator,
Curve_const_iterator> Cci_pair;
typedef typename Traits_2::Construct_curves_2 Construct_curves_2;
typedef typename Traits_adapter_2::Construct_vertex_2
Construct_vertex_2;
typedef Gps_polygon_validation_visitor<Traits_2> Visitor;
typedef Sweep_line_2<Traits_2, Visitor> Sweep_line ;
typedef typename Polygon_set_2::Arrangement_2 Arrangement_2;
/* Should be perfored more efficeintly than using sweep and than difference().*/
/*Use sweep to find intersections on the interior of curves (not on vertices) and overlapping edges which are not allowed
(note that 0/1 dimension intersections are not detectes by do_intersect() which only returns the 2D intersection polygon if exists)
Note that using this sweep alone allows for a hole and an edge to share a vertex and intersect
(like illegal input pgn_w_overlap_hole.dat in validation_example)*/
Hole_const_iterator hoit;
// Construct a container of all boundary curves.
Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pwh);
Construct_curves_2 construct_curves_func;
Cci_pair itr_pair = construct_curves_func(pgn2);
std::list<X_monotone_curve_2> curves;
std::copy (itr_pair.first, itr_pair.second,
std::back_inserter(curves));
std::pair<Hole_const_iterator, Hole_const_iterator> pair = traits.construct_holes_object()(pwh);
for (hoit = pair.first; hoit!=pair.second; ++hoit)
//for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit)
{
itr_pair = construct_curves_func (*hoit);
std::copy (itr_pair.first, itr_pair.second,
std::back_inserter(curves));
}
// Perform the sweep and check for curve intersections on the interior.
//Traits_2 traits; moved to top, needed also for boundary.
Visitor visitor(false);
Sweep_line sweep_line (&traits, &visitor);
visitor.sweep (curves.begin(), curves.end());
if (!visitor.is_valid())
return false;
Polygon_set_2 gps(traits);
//check for 2D intersections of holes (holes must be disjoint except for vertices)
Size num_of_holes=0;
for (hoit = pwh.holes_begin(); hoit != pwh.holes_end(); ++hoit) {
Polygon_2 hole(*hoit);
hole.reverse_orientation();
/*gps.join() and gps.insert()requires that the polyon insrted is valid, and therfore hole
orientation must be reversed*/
bool intersect = gps.do_intersect(hole);
if (intersect)
return false;
else {
/*to use gps.insert(hole) it is required that the set coponents and the new holes do not intersect.
because the sweep detects shared edges and the do_intersect query detects 2D intersections we can safely use
the insert(pwh) function whose performance is better than the join(pgn)*/
Polygon_with_holes_2 empty_pwh(hole);
gps.insert(empty_pwh);
num_of_holes++;
}
}
/*not good - doesn't work if intersection at vertices is legal.
Size arr_num_of_holes = gps.number_of_polygons_with_holes();
if (num_of_holes != arr_num_of_holes)
return false;
*/
//check for intersection of holes with the outer boundary
Hole_const_iterator fit;
/*outer boundary can be relatively simple. Execution of
do_intersect(hole, boundary) or difference(hole,boundary) relies on
implementation of General polygon set which has a precondition that requires
valid polygon or PWH to be inserted (not just a simple polygon).
This helper function is utilized after checking for the PWH closure,
relative simplicity and orientation. Therefore it is safe to assume the
outer boundary is valid PWH with no holes. We can't assume it is a valid
(simple) polygon. */
Polygon_with_holes_2 boundary(pwh.outer_boundary(), fit, fit);
//unbounded outer boundaries contain all the holes and are OK
if (boundary.is_unbounded())
return true;
/*do_intersect predicate will not suffice as hole can be completely outside
the outer boundary in an (extremely strange) case
The gps now contains all the holes. the difference between the boundary and a union of all
the holes should be the empty set. For performance reasons, we use a customized overlay traits and
perform an arrangement overlay instead of difference */
ValidationOverlayTraits<Arrangement_2> valOverlayTraits;
valOverlayTraits.setHoleOverlap(false);
Polygon_set_2 gps2(traits);
Arrangement_2 boundary_arr = gps2.arrangement();
gps2._insert(boundary,boundary_arr);
Arrangement_2 holes_arr = gps.arrangement();
Arrangement_2 output_arr;
overlay(holes_arr, boundary_arr, output_arr, valOverlayTraits);
if (valOverlayTraits.getHoleOverlap())
return false;
/*old code that works less efficiently than the new overly traits
gps.validation_difference(boundary);
//if gps is not empty at least one hole intersected the boundary
if (!gps.is_empty())
return (false);
*/
return (true);
}
/*A valid polygon with holes is :
* 1 - Has empty or closed boundary and all the holes are closed
* 2 - The PWH is relatively simple polygon (holes are simple...)
* 3 - Has it's boundary oriented counterclockwise and the holes oriented clockwise
* 4 - All the segments (boundry and holes) do not cross or intersect in their relative interior
* 5 - The holes are on the interior of the boundary polygon if the boundary is not empty
*/
template <typename Traits_2>
bool is_valid_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits)
{
bool closed = is_closed_polygon_with_holes(pgn,traits);
CGAL_warning_msg (closed,
"The polygon's boundary or one of it's holes is not closed.");
if (! closed)
return (false);
bool relatively_simple = is_relatively_simple_polygon_with_holes(pgn,traits);
CGAL_warning_msg (relatively_simple,
"The polygon is not relatively simple.");
if (! relatively_simple)
return (false);
bool no_cross = is_crossover_outer_boundary(pgn, traits);
CGAL_warning_msg (no_cross,
"The polygon has a crossover.");
if (!no_cross)
return (false);
bool valid_orientation = has_valid_orientation_polygon_with_holes(pgn,traits);
CGAL_warning_msg (valid_orientation,
"The polygon has a wrong orientation.");
if (! valid_orientation)
return (false);
bool holes_disjoint = are_holes_and_boundary_pairwise_disjoint(pgn,traits);
CGAL_warning_msg (holes_disjoint,
"Holes of the PWH intersect amongst themselves or with outer boundary");
if (! holes_disjoint)
return false;
return (true);
}
};
template <typename Traits_2>
bool is_valid_unknown_polygon(const typename Traits_2::Polygon_with_holes_2& pgn,
Traits_2 traits)
{
return is_valid_polygon_with_holes(pgn, traits);
}
template <typename Traits_2>
bool is_valid_unknown_polygon(const typename Traits_2::Polygon_2& pgn,
Traits_2 traits)
{
return is_valid_polygon(pgn, traits);
}
CGAL_END_NAMESPACE
#endif

View File

@ -269,7 +269,6 @@ template <class Traits_, class Dcel_>
void General_polygon_set_2<Traits_, Dcel_>::
_insert(const Polygon_2& pgn, Arrangement_2 & arr)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
typedef Arr_accessor<Arrangement_2> Arr_accessor;
Arr_accessor accessor(arr);
@ -379,6 +378,11 @@ void General_polygon_set_2<Traits_, Dcel_>::
insert(PolygonIter p_begin, PolygonIter p_end)
{
typename std::iterator_traits<PolygonIter>::value_type pgn;
//check validity of all polygons
for( ; p_begin != p_end; ++p_begin)
{
CGAL_precondition(is_valid_unkown_polygon(*p_begin, *m_traits));
}
_insert(p_begin, p_end, pgn);
}
@ -396,14 +400,14 @@ insert(PolygonIter p_begin, PolygonIter p_end,
for( ; p_begin != p_end; ++p_begin)
{
CGAL_precondition(m_traits->is_valid_2_object()(*p_begin));
CGAL_precondition(is_valid_polygon(*p_begin, *m_traits));
_construct_curves(*p_begin, std::back_inserter(xcurve_list));
}
bool is_unbounded = false;
for( ; pwh_begin != pwh_end; ++pwh_begin)
{
CGAL_precondition(m_traits->is_valid_2_object()(*pwh_begin));
CGAL_precondition(is_valid_polygon_with_holes(*pwh_begin, *m_traits));
is_unbounded = (is_unbounded || m_traits->construct_is_unbounded_object()(*pwh_begin));
// is_unbounded = (is_unbounded || pwh_begin->is_unbounded());
_construct_curves(*pwh_begin, std::back_inserter(xcurve_list));
@ -427,7 +431,6 @@ _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2 & /*pgn*/)
{
for(PolygonIter pitr = p_begin; pitr != p_end; ++pitr)
{
CGAL_precondition(m_traits->is_valid_2_object()(*pitr));
this->_insert(*pitr, *m_arr);
}
}
@ -445,7 +448,6 @@ _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_with_holes_2 & /*pgn*/)
bool is_unbounded = false;
for( ; p_begin != p_end; ++p_begin)
{
CGAL_precondition(m_traits->is_valid_2_object()(*p_begin));
// is_unbounded = (is_unbounded || p_begin->is_unbounded());
is_unbounded = (is_unbounded || m_traits->construct_is_unbounded_object()(*p_begin));
_construct_curves(*p_begin, std::back_inserter(xcurve_list));
@ -469,7 +471,8 @@ template <class Traits_, class Dcel_>
void General_polygon_set_2<Traits_, Dcel_>::
_insert(const Polygon_with_holes_2 & pgn, Arrangement_2 & arr)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
//not needed gps.insert(PWH) has the precondition
// CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
typedef std::list<X_monotone_curve_2> XCurveList;
typedef Init_faces_visitor<Arrangement_2> My_visitor;
typedef Gps_bfs_scanner<Arrangement_2, My_visitor> Arr_bfs_scanner;
@ -502,8 +505,7 @@ _construct_curves(const Polygon_2 & pgn, OutputIterator oi)
template <class Traits_, class Dcel_>
template <class OutputIterator>
void
General_polygon_set_2<Traits_, Dcel_>::
void General_polygon_set_2<Traits_, Dcel_>::
_construct_curves(const Polygon_with_holes_2 & pgn, OutputIterator oi)
{
//if (!pgn.is_unbounded())

View File

@ -148,7 +148,7 @@ public:
m_traits_owner(true),
m_arr(new Arrangement_2(m_traits))
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_insert(pgn, *m_arr);
}
@ -157,7 +157,7 @@ public:
m_traits_owner(true),
m_arr(new Arrangement_2(m_traits))
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn_with_holes));
CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes,*m_traits));
_insert(pgn_with_holes, *m_arr);
}
@ -197,18 +197,17 @@ public:
// insert a simple polygon
void insert(const Polygon_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_insert(pgn, *m_arr);
}
// insert a polygon with holes
void insert(const Polygon_with_holes_2& pgn_with_holes)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn_with_holes));
CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits));
_insert(pgn_with_holes, *m_arr);
}
// insert a range of polygons that can be either simple polygons
// or polygons with holes
// precondition: the polygons are disjoint and simple
@ -228,7 +227,7 @@ public:
// test for intersection with a simple polygon
bool do_intersect(const Polygon_2 &pgn) const
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn,*m_traits));
Self other(pgn);
return (do_intersect(other));
}
@ -236,7 +235,7 @@ public:
// test for intersection with a polygon with holes
bool do_intersect(const Polygon_with_holes_2& pgn_with_holes) const
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn_with_holes));
CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits));
Self other(pgn_with_holes);
return (do_intersect(other));
}
@ -278,14 +277,14 @@ public:
// intersection with a simple polygon
void intersection(const Polygon_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_intersection(pgn);
}
// intersection with a polygon with holes
void intersection(const Polygon_with_holes_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
_intersection(pgn);
}
@ -305,14 +304,14 @@ public:
// join with a simple polygon
void join(const Polygon_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_join(pgn);
}
// join with a polygon with holes
void join(const Polygon_with_holes_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
_join(pgn);
}
@ -328,18 +327,17 @@ public:
_join(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr));
}
// difference with a simple polygon
void difference (const Polygon_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_difference(pgn);
}
// difference with a polygon with holes
void difference (const Polygon_with_holes_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
_difference(pgn);
}
@ -359,14 +357,14 @@ public:
// symmetric_difference with a simple polygon
void symmetric_difference(const Polygon_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
_symmetric_difference(pgn);
}
// symmetric_difference with a polygon with holes
void symmetric_difference(const Polygon_with_holes_2& pgn)
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
_symmetric_difference(pgn);
}
@ -490,14 +488,14 @@ public:
Oriented_side oriented_side(const Polygon_2& pgn) const
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon(pgn, *m_traits));
Self other(pgn);
return (oriented_side(other));
}
Oriented_side oriented_side(const Polygon_with_holes_2& pgn) const
{
CGAL_precondition(m_traits->is_valid_2_object()(pgn));
CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits));
Self other(pgn);
return (oriented_side(other));
}
@ -701,7 +699,7 @@ public:
for (InputIterator itr = begin; itr!=end; ++itr, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr));
CGAL_precondition(is_valid_polygon((*itr), *m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr, *(arr_vec[i].first));
}
@ -726,7 +724,7 @@ public:
for (InputIterator itr = begin; itr!=end; ++itr, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr));
CGAL_precondition(is_valid_polygon_with_holes((*itr), *m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr, *(arr_vec[i].first));
}
@ -753,14 +751,14 @@ public:
for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr1));
CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr1, *(arr_vec[i].first));
}
for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr2));
CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr2, *(arr_vec[i].first));
}
@ -801,7 +799,7 @@ public:
for (InputIterator itr = begin; itr!=end; ++itr, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr));
CGAL_precondition(is_valid_polygon(*itr,*m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr, *(arr_vec[i].first));
}
@ -826,7 +824,7 @@ public:
for (InputIterator itr = begin; itr!=end; ++itr, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr));
CGAL_precondition(is_valid_polygon_with_holes(*itr,*m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr, *(arr_vec[i].first));
}
@ -853,14 +851,14 @@ public:
for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr1));
CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr1, *(arr_vec[i].first));
}
for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i)
{
CGAL_precondition(m_traits->is_valid_2_object()(*itr2));
CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits));
arr_vec[i].first = new Arrangement_2(m_traits);
_insert(*itr2, *(arr_vec[i].first));
}

View File

@ -126,14 +126,14 @@ public:
* An auxiliary functor used for validity checks.
*/
typedef Gps_traits_adaptor<Base> Traits_adaptor;
typedef CGAL::Is_valid_2<Self, Traits_adaptor> Is_valid_2;
/* typedef CGAL::Is_valid_2<Self, Traits_adaptor> Is_valid_2;
Is_valid_2 is_valid_2_object()
{
Traits_adaptor tr_adp;
return (Is_valid_2 (*this, tr_adp));
}
}*/
//Added Functionality from GeneralPolygonWithHoles Concept to the traits.

View File

@ -104,14 +104,15 @@ public:
* An auxiliary functor used for validity checks.
*/
typedef Gps_traits_adaptor<Base> Traits_adaptor;
typedef CGAL::Is_valid_2<Self, Traits_adaptor> Is_valid_2;
/*typedef CGAL::Is_valid_2<Self, Traits_adaptor> Is_valid_2;
Is_valid_2 is_valid_2_object()
{
Traits_adaptor tr_adp;
return (Is_valid_2 (*this, tr_adp));
}
}*/
//Added Functionality from GeneralPolygonWithHoles Concept to the traits.
/*A functor for constructing the outer boundary of a polygon with holes*/

View File

@ -15,6 +15,7 @@
// $Id$
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// Guy Zucker <guyzucke@post.tau.ac.il>
#ifndef CGAL_CONNECT_HOLES_H
#define CGAL_CONNECT_HOLES_H

View File

@ -18,6 +18,7 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/Boolean_set_operations_2/Gps_polygon_validation.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/iterator.h>
#include <vector>
@ -48,7 +49,7 @@ bool are_polygons_valid(Vec& vec)
unsigned int i=0;
for(; i < vec.size(); ++i)
{
if(!tr.is_valid_2_object()(vec[i]))
if(!is_valid_unknown_polygon(vec[i], tr))
return false;
}
return true;

View File

@ -19,6 +19,7 @@
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/Boolean_set_operations_2/Gps_polygon_validation.h>
#include <CGAL/iterator.h>
#include <vector>
#include <iterator>
@ -42,7 +43,7 @@ bool are_polygons_valid(const std::vector<Polygon_with_holes_2>& vec)
unsigned int i=0;
for(; i < vec.size(); ++i)
{
if(!tr.is_valid_2_object()(vec[i]))
if(!is_valid_polygon_with_holes(vec[i],tr))
return false;
}
return true;
@ -61,7 +62,7 @@ std::ostream& write_result_to_file(std::ostream& out, const T_P1& p1, const T_P2
{
out << 1 << std::endl;
out << res_pgn <<std::endl;
if(!tr.is_valid_2_object()(res_pgn))
if(!is_valid_polygon_with_holes(res_pgn,tr))
std::cout<<"warning: invalid polygon was generated\n";
}
else
@ -121,7 +122,7 @@ std::ostream& write_complement_to_file(std::ostream& out, const Polygon_2& pgn)
out << res_pgn << std::endl;
Traits_2 tr;
if(!tr.is_valid_2_object()(res_pgn))
if(!is_valid_polygon_with_holes(res_pgn,tr))
std::cout<<"warning: invalid polygon was generated\n";
return out;
@ -188,7 +189,7 @@ int main(int argc, char **argv)
{
inp1 >> p1;
out << p1;
if(! tr.is_valid_2_object()(p1))
if(! is_valid_polygon(p1,tr))
{
std::cout<<"warning: first input polygon is invalid!!!\n";
}
@ -197,7 +198,7 @@ int main(int argc, char **argv)
{
inp1 >> pwh1;
out << pwh1;
if(! tr.is_valid_2_object()(pwh1))
if(! is_valid_polygon_with_holes(pwh1,tr))
{
std::cout<<"warning: first input polygon is invalid!!!\n";
}
@ -213,7 +214,7 @@ int main(int argc, char **argv)
{
inp2 >> p2;
out << p2;
if(! tr.is_valid_2_object()(p2))
if(!is_valid_polygon(p2,tr))
{
std::cout<<"warning: second input polygon is invalid!!!\n";
}
@ -222,7 +223,7 @@ int main(int argc, char **argv)
{
inp2 >> pwh2;
out << pwh2;
if(! tr.is_valid_2_object()(pwh2))
if(! is_valid_polygon_with_holes(pwh2,tr))
{
std::cout<<"warning: second input polygon is invalid!!!\n";
}

View File

@ -0,0 +1,16 @@
4
0 0
8 0
8 8
0 8
1
6
1 1
2 2
3 1
4 2
5 1
3 1

View File

@ -0,0 +1,18 @@
6
0 0
8 0
8 8
6 8
2 8
0 8
1
5
1 6
2 8
4 12
6 8
7 6

View File

@ -0,0 +1,19 @@
4
0 0
8 0
8 8
0 8
2
4
2 2
2 6
6 6
6 2
4
5 4
5 5
7 5
7 4

View File

@ -0,0 +1,18 @@
4
0 0
8 0
8 8
0 8
2
4
1 1
1 7
7 7
7 1
4
2 2
2 6
6 6
6 2

View File

@ -0,0 +1,18 @@
4
0 0
8 0
8 8
0 8
2
4
1 2
1 6
2 6
2 2
4
2 2
2 6
6 6
6 2

View File

@ -0,0 +1,15 @@
6
0 0
2 0
4 0
8 0
8 8
0 8
1
4
2 0
2 6
4 6
4 0

View File

@ -0,0 +1,12 @@
6
0 2
4 2
6 4
6 0
4 2
2 4
0

View File

@ -0,0 +1,12 @@
6
0 2
4 2
6 0
6 4
4 2
2 4
0

View File

@ -0,0 +1,19 @@
5
0 0
4 0
8 0
8 8
0 8
2
4
4 0
2 2
4 4
4 2
3
4 4
2 6
6 6

View File

@ -0,0 +1,133 @@
/*test file for polygon validation. Intended for testing the global functions defined at Gps_polygon_validation.h*/
#ifndef CGAL_BSO_RATIONAL_NT_H
#define CGAL_BSO_RATIONAL_NT_H
#include <CGAL/basic.h>
#ifdef CGAL_USE_GMP
// GMP is installed. Use the GMP rational number-type.
#include <CGAL/Gmpq.h>
typedef CGAL::Gmpq Number_type;
#else
// GMP is not installed. Use CGAL's exact rational number-type.
#include <CGAL/MP_Float.h>
#include <CGAL/Quotient.h>
typedef CGAL::Quotient<CGAL::MP_Float> Number_type;
#endif
#endif
#include <CGAL/Cartesian.h>
#include <CGAL/Gps_segment_traits_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <list>
#include <CGAL/Boolean_set_operations_2/Gps_polygon_validation.h>
#include <CGAL/General_polygon_set_2.h>
#include <iterator>
#include <string>
#include <sstream>
#include <iostream>
typedef CGAL::Cartesian<Number_type> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Circle_2 Circle_2;
typedef CGAL::Gps_segment_traits_2<Kernel> Traits_2;
typedef CGAL::General_polygon_set_2<Traits_2> Polygon_set_2;
typedef Traits_2::Polygon_2 Polygon_2;
typedef Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef CGAL::Arr_segment_traits_2<Kernel> Base;
typedef CGAL::Gps_traits_adaptor<Base> Traits_adaptor;
typedef std::list<Polygon_with_holes_2> Pwh_list_2;
/*test files:
1. val_test1.dat - invalid polygon with holes. The hole is relatively simple instead of strictly simple.
2. val_test2.dat - invalid polygon with holes. The hole overlaps the outer boundary (the intersection results in a polygon).
3. val_test3.dat - invalid polygon with holes. Two holes intersect (the intersection results in a polygon).
4. val_test4.dat - invalid polygon with holes. Two holes intersect (one contains the other).
5. val_test5.dat - invalid polygon with holes. Two holes share an edge. (non regularized intersection
results in an edge).
6. val_test6.dat - invalid polygon with holes. A hole and the outer boundary share an edge. (non regularized intersection
results in an edge).
7. val_test7.dat - invalid polygon with holes. The outer boundary is not relatively simple because a "crossover" occurs
at an intersection
8. val_test8.dat - valid polygon with holes. Outer boundary is relatively simple.
9. val_test9.dat - valid polygon with holes. Outer Boundary and holes are pairwise disjoint except on vertices
*/
/*test an input file. isValid indicates the input polygon is valid. ErrorMsg is displayed if the validation result does't equal isValid */
bool testValidationForFile(const char* infilename, std::ofstream& outfile , bool isValid) {
std::ifstream input_file (infilename);
if (! input_file.is_open()) {
std::cerr << "Failed to open the " << infilename <<std::endl;
return (false);
}
// Read a polygon with holes from a file.
Polygon_2 outerP;
unsigned int num_holes;
input_file >> outerP;
input_file >> num_holes;
std::vector<Polygon_2> holes (num_holes);
unsigned int k;
for (k = 0; k < num_holes; k++)
input_file >> holes[k];
Polygon_with_holes_2 P (outerP, holes.begin(), holes.end());
Traits_2 tr;
bool testValid = CGAL::is_valid_polygon_with_holes(P,tr);
bool res = true;
if (testValid != isValid) {
res=false;
outfile<< "Error validating " << infilename <<std::endl;
//outfile << "P = " ;
//print_polygon_with_holes (P);
outfile<<std::endl;
}
input_file.close();
return res;
}
int main (int argc, char **argv) {
std::string testfilePrefix = "data/validation/val_test";
std::string testfileSuffix = ".dat";
const char* outputfilename = "data/validation/validation_test_output.txt";
std::ofstream output_file (outputfilename);
if (! output_file.is_open()) {
std::cerr << "Failed to open the " << outputfilename <<std::endl;
return (1);
}
int result = 0;
for (int i=1;i<10;i++) {
std::stringstream strs;
std::string si;
strs << i;
strs >> si;
std::string filename = testfilePrefix + si + testfileSuffix;
const char *cfilename = filename.c_str();
bool isValidPgn=false;
if (i>7)
isValidPgn=true;
bool res = testValidationForFile(cfilename, output_file, isValidPgn);
if (!res) {
std::cout << "test " << i << " failed" << std::endl;
result=1;
}
else {
std::cout <<"test " << i << " succeeded" << std::endl;
}
}
if (result == 0)
std::cout <<"ALL TESTS SUCCEEDED!" << std::endl;
else
std::cout <<"SOME TESTS FAILED" << std::endl;
return (0);
}