mirror of https://github.com/CGAL/cgal
Added support for the computation of Minkowski sum of polygons with holes
This commit is contained in:
parent
9ee92d42d8
commit
5e7e4ee8dd
|
|
@ -0,0 +1,6 @@
|
|||
4 0 0 3 0 3 3 0 3
|
||||
1
|
||||
4 1 1 1 2 2 2 2 1
|
||||
4 0 0 3 0 3 3 0 3
|
||||
1
|
||||
4 1 1 1 2 2 2 2 1
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//! \file examples/Minkowski_sum_2/sum_by_decomposition.cpp
|
||||
// Computing the Minkowski sum of two non-convex polygons read from a file
|
||||
// using the small-side angle-bisector decomposition strategy.
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/minkowski_sum_2.h>
|
||||
#include <CGAL/Polygon_vertical_decomposition_2.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "print_utils.h"
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef CGAL::Polygon_with_holes_2<Kernel> Polygon_with_holes_2;
|
||||
|
||||
int main()
|
||||
{
|
||||
// Open the input file.
|
||||
std::ifstream in_file("holes.dat");
|
||||
|
||||
if (! in_file.is_open()) {
|
||||
std::cerr << "Failed to open the input file." << std::endl;
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Read the two polygons from the file and compute their Minkowski sum.
|
||||
Polygon_with_holes_2 P, Q;
|
||||
|
||||
in_file >> P >> Q;
|
||||
in_file.close();
|
||||
|
||||
// Compute the Minkowski sum using the decomposition approach.
|
||||
CGAL::Polygon_vertical_decomposition_2<Kernel> vertical_decomp;
|
||||
Polygon_with_holes_2 sum = minkowski_sum_2(P, Q, vertical_decomp);
|
||||
std::cout << "P (+) Q = ";
|
||||
print_polygon_with_holes(sum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ template <class DecompStrategy_, class Container_>
|
|||
class Minkowski_sum_by_decomposition_2
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
typedef DecompStrategy_ Decomposition_strategy;
|
||||
typedef Container_ Container;
|
||||
typedef typename Decomposition_strategy::Polygon_2 Polygon_2;
|
||||
|
|
@ -52,7 +52,7 @@ private:
|
|||
typedef typename Kernel::Point_2 Point_2;
|
||||
typedef typename Kernel::Vector_2 Vector_2;
|
||||
typedef typename Kernel::Direction_2 Direction_2;
|
||||
|
||||
|
||||
// Kernel functors:
|
||||
typedef typename Kernel::Equal_2 Equal_2;
|
||||
typedef typename Kernel::Compare_angle_with_x_axis_2 Compare_angle_2;
|
||||
|
|
@ -96,7 +96,7 @@ public:
|
|||
|
||||
f_equal = ker.equal_2_object();
|
||||
f_compare_angle = ker.compare_angle_with_x_axis_2_object();
|
||||
f_add = ker.construct_translated_point_2_object();
|
||||
f_add = ker.construct_translated_point_2_object();
|
||||
f_vector = ker.construct_vector_2_object();
|
||||
f_direction = ker.construct_direction_2_object();
|
||||
f_orientation = ker.orientation_2_object();
|
||||
|
|
@ -142,18 +142,60 @@ public:
|
|||
_compute_sum_of_convex (*curr1, *curr2, sub_sum);
|
||||
|
||||
sub_sum_polygons.push_back(sub_sum);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
General_polygon_set_2 gps;
|
||||
|
||||
|
||||
gps.join(sub_sum_polygons.begin(),sub_sum_polygons.end());
|
||||
|
||||
|
||||
Polygon_with_holes_list sum;
|
||||
|
||||
gps.polygons_with_holes(std::back_inserter(sum));
|
||||
|
||||
|
||||
return (*(sum.begin()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Compute the Minkowski sum of two polygon-with-holes.
|
||||
* \param pgn1 The first polygon.
|
||||
* \param pgn2 The second polygon.
|
||||
* \pre Both input polygons are simple.
|
||||
* \return The resulting polygon with holes, representing the sum.
|
||||
*/
|
||||
Polygon_with_holes_2
|
||||
operator()(const Polygon_with_holes_2& pgn1,
|
||||
const Polygon_with_holes_2& pgn2) const
|
||||
{
|
||||
// Decompose both input polygons to convex sub-polygons.
|
||||
Decomposition_strategy decomp_strat;
|
||||
Polygons_list sub_pgns1;
|
||||
Polygons_list sub_pgns2;
|
||||
Polygons_list sub_sum_polygons;
|
||||
|
||||
decomp_strat(pgn1, std::back_inserter(sub_pgns1));
|
||||
decomp_strat(pgn2, std::back_inserter(sub_pgns2));
|
||||
|
||||
// Compute the sub-sums of all pairs of sub-polygons.
|
||||
Polygons_iterator end1 = sub_pgns1.end();
|
||||
Polygons_iterator end2 = sub_pgns2.end();
|
||||
Polygons_iterator curr1, curr2;
|
||||
|
||||
for (curr1 = sub_pgns1.begin(); curr1 != end1; ++curr1) {
|
||||
for (curr2 = sub_pgns2.begin(); curr2 != end2; ++curr2) {
|
||||
// Compute the sum of the current pair of convex sub-polygons.
|
||||
Polygon_2 sub_sum;
|
||||
_compute_sum_of_convex(*curr1, *curr2, sub_sum);
|
||||
sub_sum_polygons.push_back(sub_sum);
|
||||
}
|
||||
}
|
||||
|
||||
General_polygon_set_2 gps;
|
||||
gps.join(sub_sum_polygons.begin(), sub_sum_polygons.end());
|
||||
Polygon_with_holes_list sum;
|
||||
gps.polygons_with_holes(std::back_inserter(sum));
|
||||
CGAL_assertion(sum.size() == 1);
|
||||
return (*(sum.begin()));
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +231,7 @@ private:
|
|||
// Find the bottom-left vertex in both polygons.
|
||||
Vertex_circulator first2, curr2, next2;
|
||||
Vertex_circulator bottom_left2;
|
||||
|
||||
|
||||
bottom_left2 = curr2 = first2 = pgn2.vertices_circulator();
|
||||
++curr2;
|
||||
while (curr2 != first2)
|
||||
|
|
@ -208,7 +250,7 @@ private:
|
|||
++next1;
|
||||
next2 = curr2 = bottom_left2;
|
||||
++next2;
|
||||
|
||||
|
||||
// Compute the Minkowski sum.
|
||||
Point_2 first_pt;
|
||||
Point_2 curr_pt;
|
||||
|
|
@ -241,7 +283,7 @@ private:
|
|||
}
|
||||
|
||||
// Compare the angles the current edges form with the x-axis.
|
||||
res = f_compare_angle (f_direction (f_vector (*curr1, *next1)),
|
||||
res = f_compare_angle (f_direction (f_vector (*curr1, *next1)),
|
||||
f_direction (f_vector (*curr2, *next2)));
|
||||
|
||||
// Proceed to the next vertex according to the result.
|
||||
|
|
@ -265,8 +307,8 @@ private:
|
|||
curr1 = next1;
|
||||
++next1;
|
||||
moved_on1 = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (inc2)
|
||||
{
|
||||
curr2 = next2;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,245 @@
|
|||
// Copyright (c) 2006 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Ron Wein <wein@post.tau.ac.il>
|
||||
// (based on an old version by Eyal Flato)
|
||||
|
||||
#ifndef CGAL_SMALL_SIDE_ANGLE_BISECTOR_DECOMPOSITION_2_H
|
||||
#define CGAL_SMALL_SIDE_ANGLE_BISECTOR_DECOMPOSITION_2_H
|
||||
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/General_polygon_set_2.h>
|
||||
#include <CGAL/Arr_vertical_decomposition_2.h>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
* \class
|
||||
* Vertical decomposition strategy.
|
||||
*/
|
||||
template <class Kernel_,
|
||||
class Container_ = std::vector<typename Kernel_::Point_2> >
|
||||
class Polygon_vertical_decomposition_2 {
|
||||
public:
|
||||
typedef Kernel_ Kernel;
|
||||
typedef Container_ Container;
|
||||
|
||||
typedef CGAL::Polygon_2<Kernel, Container> Polygon_2;
|
||||
typedef CGAL::Polygon_with_holes_2<Kernel, Container> Polygon_with_holes_2;
|
||||
|
||||
typedef CGAL::Arr_segment_traits_2<Kernel> Arr_segment_traits;
|
||||
typedef CGAL::Gps_segment_traits_2<Kernel, Container, Arr_segment_traits>
|
||||
Traits_2;
|
||||
typedef CGAL::General_polygon_set_2<Traits_2> General_polygon_set_2;
|
||||
typedef typename General_polygon_set_2::Arrangement_2 Arrangement_2;
|
||||
|
||||
typedef typename Arrangement_2::Halfedge_const_iterator
|
||||
Halfedge_const_iterator;
|
||||
typedef typename Arrangement_2::Face_const_iterator Face_const_iterator;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_handle Vertex_handle;
|
||||
typedef typename Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Arrangement_2::Face_handle Face_handle;
|
||||
|
||||
typedef std::pair<Vertex_const_handle, std::pair<CGAL::Object, CGAL::Object> >
|
||||
Vert_decomp_entry;
|
||||
typedef std::list<Vert_decomp_entry> Vert_decomp_list;
|
||||
|
||||
typedef typename Kernel::Point_2 Point_2;
|
||||
|
||||
typedef typename Arrangement_2::Outer_ccb_const_iterator
|
||||
Outer_ccb_const_iterator;
|
||||
|
||||
private:
|
||||
|
||||
typedef typename Arrangement_2::X_monotone_curve_2 Segment_2;
|
||||
typedef typename Kernel::Line_2 Line_2;
|
||||
|
||||
typedef typename Polygon_2::Vertex_circulator Vertex_circulator;
|
||||
|
||||
// An arrangement observer, used to receive notifications of face splits and
|
||||
// face mergers.
|
||||
class My_observer : public CGAL::Arr_observer<Arrangement_2> {
|
||||
public:
|
||||
My_observer (Arrangement_2& arr) :
|
||||
CGAL::Arr_observer<Arrangement_2>(arr)
|
||||
{}
|
||||
|
||||
virtual void after_split_face(Face_handle f, Face_handle new_f,
|
||||
bool /* is_hole */)
|
||||
{ if (f->contained()) new_f->set_contained(true); }
|
||||
};
|
||||
|
||||
// Kernel functors:
|
||||
typedef typename Kernel::Compare_x_2 Compare_x_2;
|
||||
typedef typename Kernel::Intersect_2 Intersect_2;
|
||||
typedef typename Kernel::Equal_2 Equal_2;
|
||||
|
||||
// Data members:
|
||||
Kernel* m_kernel;
|
||||
bool m_own_kernel; // inidicates whether the kernel should be freed up.
|
||||
|
||||
Compare_x_2 f_cmp_x;
|
||||
Intersect_2 f_intersect;
|
||||
Equal_2 f_equal;
|
||||
|
||||
public:
|
||||
|
||||
/*! Default constructor. */
|
||||
Polygon_vertical_decomposition_2() :
|
||||
m_kernel(new Kernel),
|
||||
m_own_kernel(true)
|
||||
{
|
||||
// Obtain kernel functors.
|
||||
f_cmp_x = m_kernel->compare_x_2_object();
|
||||
f_intersect = m_kernel->intersect_2_object();
|
||||
f_equal = m_kernel->equal_2_object();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~Polygon_vertical_decomposition_2()
|
||||
{
|
||||
if (m_own_kernel && m_kernel) {
|
||||
delete m_kernel;
|
||||
m_kernel = NULL;
|
||||
m_own_kernel = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Decompose a polygon-with-holes into convex sub-polygons.
|
||||
* \param pgn The input polygon.
|
||||
* \param oi An output iterator of convex polygons.
|
||||
* \return A past-the-end iterator for the sub-polygons.
|
||||
*/
|
||||
template <class OutputIterator>
|
||||
OutputIterator operator()(const Polygon_with_holes_2& pgn,
|
||||
OutputIterator oi) const
|
||||
{
|
||||
General_polygon_set_2 gps;
|
||||
gps.insert(pgn);
|
||||
Arrangement_2& arr = gps.arrangement();
|
||||
My_observer obs(arr);
|
||||
vertical_decomposition(arr);
|
||||
Face_const_iterator fi;
|
||||
for (fi = arr.faces_begin(); fi != arr.faces_end(); ++fi) {
|
||||
if (! fi->contained()) continue;
|
||||
CGAL_assertion(fi->number_of_outer_ccbs() == 1);
|
||||
Outer_ccb_const_iterator oci = fi->outer_ccbs_begin();
|
||||
Halfedge_const_iterator first = *oci;
|
||||
Halfedge_const_iterator curr = first;
|
||||
Polygon_2 pgn;
|
||||
do {
|
||||
pgn.push_back(curr->target()->point());
|
||||
curr = curr->next();
|
||||
} while (curr != first);
|
||||
*oi++ = pgn;
|
||||
}
|
||||
return oi;
|
||||
}
|
||||
|
||||
private:
|
||||
// Add a vertical segment from the given vertex to some other arrangement
|
||||
// feature.
|
||||
Halfedge_const_handle
|
||||
add_vertical_segment(Arrangement_2& arr, Vertex_handle v, CGAL::Object obj)
|
||||
const
|
||||
{
|
||||
Segment_2 seg;
|
||||
Vertex_const_handle vh;
|
||||
Halfedge_const_handle hh;
|
||||
Face_const_handle fh;
|
||||
Vertex_handle v2;
|
||||
|
||||
if (CGAL::assign(vh, obj)) {
|
||||
// The given feature is a vertex.
|
||||
seg = Segment_2(v->point(), vh->point());
|
||||
v2 = arr.non_const_handle(vh);
|
||||
}
|
||||
else if (CGAL::assign(hh, obj)) {
|
||||
// The given feature is a halfedge. We ignore fictitious halfedges.
|
||||
if (hh->is_fictitious())
|
||||
return Halfedge_const_handle();
|
||||
|
||||
// Check whether v lies in the interior of the x-range of the edge (in
|
||||
// which case this edge should be split).
|
||||
if (f_cmp_x(v->point(), hh->target()->point()) == CGAL::EQUAL) {
|
||||
// In case the target of the edge already has the same x-coordinate as
|
||||
// the vertex v, just connect these two vertices.
|
||||
seg = Segment_2(v->point(), hh->target()->point());
|
||||
v2 = arr.non_const_handle(hh->target());
|
||||
}
|
||||
else {
|
||||
// Compute the vertical projection of v onto the segment associated
|
||||
// with the halfedge. Split the edge and connect v with the split point.
|
||||
Line_2 supp_line(hh->source()->point(), hh->target()->point());
|
||||
Line_2 vert_line(v->point(),
|
||||
Point_2(v->point().x(), v->point().y() + 1));
|
||||
Point_2 point;
|
||||
CGAL::assign(point, f_intersect(supp_line, vert_line));
|
||||
seg = Segment_2(v->point(), point);
|
||||
arr.split_edge(arr.non_const_handle(hh),
|
||||
Segment_2(hh->source()->point(), point),
|
||||
Segment_2(point, hh->target()->point()));
|
||||
v2 = arr.non_const_handle(hh->target());
|
||||
}
|
||||
}
|
||||
// Ignore faces and empty objects.
|
||||
else return Halfedge_const_handle();
|
||||
|
||||
// Add the vertical segment to the arrangement using its two end vertices.
|
||||
return arr.insert_at_vertices(seg, v, v2);
|
||||
}
|
||||
|
||||
// Construct the vertical decomposition of the given arrangement.
|
||||
void vertical_decomposition(Arrangement_2& arr) const
|
||||
{
|
||||
// For each vertex in the arrangment, locate the feature that lies
|
||||
// directly below it and the feature that lies directly above it.
|
||||
Vert_decomp_list vd_list;
|
||||
CGAL::decompose(arr, std::back_inserter(vd_list));
|
||||
|
||||
// Go over the vertices (given in ascending lexicographical xy-order),
|
||||
// and add segements to the feautres below and above it.
|
||||
typename Vert_decomp_list::iterator it, prev = vd_list.end();
|
||||
for (it = vd_list.begin(); it != vd_list.end(); ++it) {
|
||||
// If the feature above the previous vertex is not the current vertex,
|
||||
// add a vertical segment to the feature below the vertex.
|
||||
Vertex_const_handle v;
|
||||
if ((prev == vd_list.end()) ||
|
||||
!CGAL::assign(v, prev->second.second) ||
|
||||
!f_equal(v->point(), it->first->point()))
|
||||
add_vertical_segment(arr, arr.non_const_handle(it->first),
|
||||
it->second.first);
|
||||
// Add a vertical segment to the feature above the vertex.
|
||||
add_vertical_segment(arr, arr.non_const_handle(it->first),
|
||||
it->second.second);
|
||||
prev = it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -80,14 +80,36 @@ minkowski_sum_2 (const Polygon_2<Kernel,Container>& pgn1,
|
|||
Minkowski_sum_by_decomposition_2<DecompositionStrategy,Container> mink_sum;
|
||||
|
||||
typedef Polygon_with_holes_2<Kernel,Container> Polygon_with_holes_2;
|
||||
|
||||
|
||||
Polygon_with_holes_2 sum;
|
||||
|
||||
sum = mink_sum (pgn1, pgn2);
|
||||
|
||||
|
||||
return (sum);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Compute the Minkowski sum of two polygon-with-holes by decomposing each
|
||||
* polygon to convex sub-polygons and computing the union of the pairwise
|
||||
* Minkowski sums of the sub-polygons.
|
||||
* The result is also represented as a polygon with holes.
|
||||
* \param pgn1 The first polygon.
|
||||
* \param pgn2 The second polygon.
|
||||
* \param decomp A functor for decomposing polygons.
|
||||
* \param sum Output: The resulting polygon with holes, representing the sum.
|
||||
*/
|
||||
template <class Kernel, class Container, class DecompositionStrategy>
|
||||
Polygon_with_holes_2<Kernel, Container>
|
||||
minkowski_sum_2(const Polygon_with_holes_2<Kernel, Container>& pgn1,
|
||||
const Polygon_with_holes_2<Kernel, Container>& pgn2,
|
||||
const DecompositionStrategy&)
|
||||
{
|
||||
Minkowski_sum_by_decomposition_2<DecompositionStrategy, Container> mink_sum;
|
||||
typedef Polygon_with_holes_2<Kernel, Container> Polygon_with_holes_2;
|
||||
Polygon_with_holes_2 sum = mink_sum(pgn1, pgn2);
|
||||
return sum;
|
||||
}
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue