mirror of https://github.com/CGAL/cgal
272 lines
10 KiB
C++
272 lines
10 KiB
C++
// Copyright (c) 2000 Max-Planck-Institute Saarbruecken (Germany).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $Source$
|
|
// $Revision$ $Date$
|
|
// $Name$
|
|
//
|
|
// Author(s) : Susan Hert <hert@mpi-sb.mpg.de>
|
|
|
|
#ifndef CGAL_PARTITION_APPROX_CONVEX_H
|
|
#define CGAL_PARTITION_APPROX_CONVEX_H
|
|
|
|
#include <CGAL/Constrained_triangulation_2.h>
|
|
#include <CGAL/Triangulation_indirect_traits_2.h>
|
|
#include <CGAL/Turn_reverser.h>
|
|
#include <CGAL/Partitioned_polygon_2.h>
|
|
#include <CGAL/IO/Tee_for_output_iterator.h>
|
|
#include <CGAL/Partition_traits_2.h>
|
|
#include <CGAL/partition_is_valid_2.h>
|
|
#include <CGAL/partition_assertions.h>
|
|
#include <utility>
|
|
#include <iterator>
|
|
|
|
namespace CGAL {
|
|
|
|
template< class Point_2, class Traits >
|
|
bool partition_appx_cvx_is_edge_through_interior(const Point_2& before_s,
|
|
const Point_2& source,
|
|
const Point_2& after_s,
|
|
const Point_2& target,
|
|
const Traits& traits )
|
|
{
|
|
// determine if the edge goes through the interior of the polygon or not
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
if (right_turn(before_s, source, after_s)) // concave angle
|
|
{
|
|
if (right_turn(before_s, source, target) &&
|
|
right_turn(target, source, after_s))
|
|
return false;
|
|
}
|
|
else // left turn or straight
|
|
if (right_turn(before_s, source, target) ||
|
|
right_turn(target, source, after_s))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
// e_circ is a circulator for the edges incident to the point referred to by
|
|
// v_ref, which is a circualtor around the vertices of the original polygon
|
|
template <class Edge_circulator, class Circulator, class Triangulation,
|
|
class Traits>
|
|
bool partition_appx_cvx_cuts_nonconvex_angle( Edge_circulator e_circ,
|
|
Circulator v_ref,
|
|
const Triangulation& triangles,
|
|
const Traits& traits)
|
|
{
|
|
typedef typename Triangulation::Segment Segment_2;
|
|
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
Segment_2 edge = triangles.segment((*e_circ).first, (*e_circ).second);
|
|
std::cout << "edge: " << *edge.source() << " " << *edge.target()
|
|
<< std::endl;
|
|
#endif
|
|
|
|
typename Triangulation::Point next_ccw_pt_ref, prev_ccw_pt_ref;
|
|
|
|
// the next and previous edges in the ccw ordering of edges around v_ref
|
|
Edge_circulator next_e = e_circ; next_e++;
|
|
Edge_circulator prev_e = e_circ; prev_e--;
|
|
|
|
// find the first edge before this one that has been included in the
|
|
// partition polygon (and is thus marked as constrained in triangulation)
|
|
while (prev_e != e_circ && (triangles.is_infinite(*prev_e) ||
|
|
!(*prev_e).first->is_constrained((*prev_e).second)))
|
|
prev_e--;
|
|
|
|
Segment_2 next_edge = triangles.segment((*next_e).first,(*next_e).second);
|
|
Segment_2 prev_edge = triangles.segment((*prev_e).first,(*prev_e).second);
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "next_edge: " << *next_edge.source() << " "
|
|
<< *next_edge.target() <<std::endl;
|
|
std::cout << "prev_edge: " << *prev_edge.source() << " "
|
|
<< *prev_edge.target() <<std::endl;
|
|
#endif
|
|
// find which endpoint is shared by the two edges
|
|
if (next_edge.source() == v_ref)
|
|
next_ccw_pt_ref = next_edge.target();
|
|
else
|
|
next_ccw_pt_ref = next_edge.source();
|
|
if (prev_edge.source() == v_ref)
|
|
prev_ccw_pt_ref = prev_edge.target();
|
|
else
|
|
prev_ccw_pt_ref = prev_edge.source();
|
|
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "partition_appx_cvx_cuts_nonconvex_angle: next_ccw_pt "
|
|
<< *next_ccw_pt_ref << " v_ref " << *v_ref << " prev_ccw_pt_ref "
|
|
<< *prev_ccw_pt_ref << std::endl;
|
|
#endif
|
|
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
typedef typename Traits::Point_2 Point_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
return right_turn(*next_ccw_pt_ref, *v_ref, *prev_ccw_pt_ref);
|
|
}
|
|
|
|
|
|
template<class InputIterator, class Traits, class OutputIterator>
|
|
OutputIterator partition_approx_convex_2(InputIterator first,
|
|
InputIterator beyond,
|
|
OutputIterator result,
|
|
const Traits& traits)
|
|
{
|
|
if (first == beyond) return result;
|
|
|
|
typedef Partitioned_polygon_2< Traits > P_Polygon_2;
|
|
typedef typename P_Polygon_2::iterator I;
|
|
typedef Circulator_from_iterator<I> Circulator;
|
|
typedef Triangulation_indirect_traits_2<Circulator, Traits> Gt;
|
|
|
|
typedef Constrained_triangulation_2<Gt> Constrained_tri_2;
|
|
typedef typename Constrained_tri_2::Edge_iterator Edge_iterator;
|
|
typedef typename Constrained_tri_2::Edge_circulator Edge_circulator;
|
|
typedef typename Constrained_tri_2::Vertex_iterator Tri_vertex_iterator;
|
|
typedef typename Constrained_tri_2::Vertex_handle Vertex_handle;
|
|
typedef typename Gt::Segment_2 Segment_2;
|
|
|
|
P_Polygon_2 polygon(first, beyond);
|
|
|
|
CGAL_partition_precondition(
|
|
orientation_2(polygon.begin(), polygon.end(), traits) == COUNTERCLOCKWISE);
|
|
|
|
Circulator first_c(polygon.begin(), polygon.end(), polygon.begin());
|
|
Circulator c(polygon.begin(), polygon.end());
|
|
Circulator next(polygon.begin(), polygon.end());
|
|
|
|
Constrained_tri_2 triangles;
|
|
|
|
do
|
|
{
|
|
next = c; next++;
|
|
triangles.insert(c, next);
|
|
} while (++c != first_c);
|
|
|
|
Segment_2 edge;
|
|
Circulator source, target, before_s, after_s;
|
|
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "Inserting diagonals: " << std::endl;
|
|
#endif
|
|
|
|
Edge_circulator e_circ, first_e;
|
|
Tri_vertex_iterator v_it;
|
|
|
|
|
|
for (v_it = triangles.vertices_begin(); v_it != triangles.vertices_end();
|
|
v_it++)
|
|
{
|
|
first_e = triangles.incident_edges(Vertex_handle(v_it));
|
|
// find the constrained edge attached to this vertex that is first
|
|
// when going CW from the first edge returned above.
|
|
while (triangles.is_infinite(*first_e) ||
|
|
!(*first_e).first->is_constrained((*first_e).second))
|
|
{
|
|
first_e--;
|
|
}
|
|
e_circ = first_e;
|
|
do
|
|
{
|
|
if ((*e_circ).first->is_constrained((*e_circ).second))
|
|
{
|
|
edge = triangles.segment((*e_circ).first, (*e_circ).second);
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "edge " << *edge.source() << " " << *edge.target()
|
|
<< " is constrained " << std::endl;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (!triangles.is_infinite(*e_circ))
|
|
{
|
|
edge = triangles.segment((*e_circ).first, (*e_circ).second);
|
|
source = edge.source();
|
|
target = edge.target();
|
|
before_s = source; before_s--;
|
|
after_s = source; after_s++;
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "considering " << *source << " " << *target
|
|
<< "...";
|
|
#endif
|
|
if (partition_appx_cvx_is_edge_through_interior(*before_s,
|
|
*source, *after_s, *target, traits))
|
|
{
|
|
if (partition_appx_cvx_cuts_nonconvex_angle(e_circ,
|
|
(*v_it).point(), triangles, traits))
|
|
{
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "inserting" << std::endl;
|
|
#endif
|
|
polygon.insert_diagonal(source, target);
|
|
triangles.insert(source, target);
|
|
}
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
else
|
|
std::cout << "doesn't cut reflex angle" << std::endl;
|
|
#endif
|
|
}
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
else
|
|
std::cout << "not an edge through the interior"
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
#ifdef CGAL_PARTITION_APPROX_CONVEX_DEBUG
|
|
std::cout << "edge is infinite " << std::endl;
|
|
#endif
|
|
}
|
|
} while (++e_circ != first_e);
|
|
}
|
|
|
|
#if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \
|
|
defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG)
|
|
OutputIterator res(result);
|
|
#else
|
|
typedef typename Traits::Polygon_2 Polygon_2;
|
|
Tee_for_output_iterator<OutputIterator, Polygon_2> res(result);
|
|
#endif // no postconditions
|
|
|
|
polygon.partition(res, 0);
|
|
CGAL_partition_postcondition(
|
|
convex_partition_is_valid_2(polygon.begin(), polygon.end(),
|
|
res.output_so_far_begin(),
|
|
res.output_so_far_end(), traits));
|
|
|
|
#if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \
|
|
defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG)
|
|
return res;
|
|
#else
|
|
return res.to_output_iterator();
|
|
#endif // no postconditions
|
|
}
|
|
|
|
template <class InputIterator, class OutputIterator>
|
|
inline
|
|
OutputIterator partition_approx_convex_2(InputIterator first,
|
|
InputIterator beyond,
|
|
OutputIterator result)
|
|
{
|
|
typedef typename std::iterator_traits<InputIterator>::value_type Point_2;
|
|
typedef typename Kernel_traits<Point_2>::Kernel K;
|
|
return partition_approx_convex_2(first, beyond, result,
|
|
Partition_traits_2<K>());
|
|
}
|
|
|
|
}
|
|
|
|
#endif // CGAL_PARTITION_APPROX_CONVEX_H
|