mirror of https://github.com/CGAL/cgal
Merge remote-tracking branch 'cgal/5.5.x-branch'
This commit is contained in:
commit
e18878f5a0
|
|
@ -36,6 +36,11 @@ Release date: June 2022
|
|||
|
||||
See also the [announcement page](https://www.cgal.org/2022/05/18/alpha_wrap/).
|
||||
|
||||
### [2D Straight Skeleton and Polygon Offsetting (breaking change)](https://doc.cgal.org/5.5/Manual/packages.html#PkgStraightSkeleton2)
|
||||
- Fix the output of the function [CGAL::create_exterior_skeleton_and_offset_polygons_with_holes_2()](https://doc.cgal.org/5.5/Straight_skeleton_2/group__PkgStraightSkeleton2OffsetFunctions.html#gaa159f093e5d6d7fdb62c1660a44f95fe)
|
||||
to not take into account the offset of the outer frame.
|
||||
- Fix the computation of the exterior offset of a polygon with holes that was not computing the offset of the holes
|
||||
|
||||
### [3D Convex Hulls](https://doc.cgal.org/5.5/Manual/packages.html#PkgConvexHull3)
|
||||
|
||||
- Added an [overload of the function `CGAL::convex_hull_3()`](https://doc.cgal.org/5.5/Convex_hull_3/group__PkgConvexHull3Functions.html#ga52fca4745c2ef0351063fbe66b035fd1), which writes the result in an indexed triangle set.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <CGAL/Named_function_parameters.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
|
||||
#include <CGAL/Container_helper.h>
|
||||
#include <CGAL/iterator.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
|
||||
|
|
@ -604,22 +605,31 @@ Polygon construct_canonical_polygon_with_markers(const Polygon& polygon,
|
|||
const bool reversed)
|
||||
{
|
||||
const std::size_t polygon_size = polygon.size();
|
||||
|
||||
Polygon canonical_polygon;
|
||||
CGAL::internal::resize(canonical_polygon, polygon_size);
|
||||
|
||||
if(reversed)
|
||||
{
|
||||
std::size_t rfirst = polygon_size - 1 - first;
|
||||
canonical_polygon.insert(canonical_polygon.end(), polygon.rbegin() + rfirst, polygon.rend());
|
||||
canonical_polygon.insert(canonical_polygon.end(), polygon.rbegin(), polygon.rbegin() + rfirst);
|
||||
std::size_t rfirst = first + 1;
|
||||
std::size_t pos = 0;
|
||||
for(std::size_t i=rfirst; i --> 0 ;) // first to 0
|
||||
canonical_polygon[pos++] = polygon[i];
|
||||
for(std::size_t i=polygon_size; i --> rfirst ;) // polygon_size-1 to first+1
|
||||
canonical_polygon[pos++] = polygon[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
canonical_polygon.insert(canonical_polygon.end(), polygon.begin() + first, polygon.end());
|
||||
canonical_polygon.insert(canonical_polygon.end(), polygon.begin(), polygon.begin() + first);
|
||||
std::size_t pos = 0;
|
||||
for(std::size_t i=first; i<polygon_size; ++i)
|
||||
canonical_polygon[pos++] = polygon[i];
|
||||
for(std::size_t i=0; i<first; ++i)
|
||||
canonical_polygon[pos++] = polygon[i];
|
||||
}
|
||||
|
||||
CGAL_postcondition(canonical_polygon[0] == polygon[first]);
|
||||
CGAL_postcondition(canonical_polygon.size() == polygon_size);
|
||||
|
||||
return canonical_polygon;
|
||||
}
|
||||
|
||||
|
|
@ -981,6 +991,62 @@ std::size_t merge_duplicate_polygons_in_polygon_soup(const PointRange& points,
|
|||
return removed_polygons_n;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename PointRange, typename PolygonRange,
|
||||
typename Polygon = typename Polygon_types<PointRange, PolygonRange>::Polygon_3>
|
||||
struct Polygon_soup_fixer
|
||||
{
|
||||
template <typename NamedParameters>
|
||||
void operator()(PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const NamedParameters& np) const
|
||||
{
|
||||
using parameters::get_parameter;
|
||||
using parameters::choose_parameter;
|
||||
|
||||
typedef typename GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type Traits;
|
||||
Traits traits = choose_parameter<Traits>(get_parameter(np, internal_np::geom_traits));
|
||||
|
||||
#ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE
|
||||
std::cout << "Repairing soup with " << points.size() << " points and " << polygons.size() << " polygons" << std::endl;
|
||||
#endif
|
||||
|
||||
merge_duplicate_points_in_polygon_soup(points, polygons, np);
|
||||
simplify_polygons_in_polygon_soup(points, polygons, traits);
|
||||
split_pinched_polygons_in_polygon_soup(points, polygons, traits);
|
||||
remove_invalid_polygons_in_polygon_soup(points, polygons);
|
||||
merge_duplicate_polygons_in_polygon_soup(points, polygons, np);
|
||||
remove_isolated_points_in_polygon_soup(points, polygons);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization if the polygon soup is an array
|
||||
// Disable repair functions that are meaningless for arrays
|
||||
template <typename PointRange, typename PolygonRange, typename PID, std::size_t N>
|
||||
struct Polygon_soup_fixer<PointRange, PolygonRange, std::array<PID, N> >
|
||||
{
|
||||
template <typename NamedParameters>
|
||||
void operator()(PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const NamedParameters& np) const
|
||||
{
|
||||
#ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE
|
||||
std::cout << "Repairing soup with " << points.size() << " points and " << polygons.size() << " arrays" << std::endl;
|
||||
#endif
|
||||
|
||||
merge_duplicate_points_in_polygon_soup(points, polygons, np);
|
||||
// skipped steps:
|
||||
// simplify_polygons_in_polygon_soup(points, polygons, traits);
|
||||
// split_pinched_polygons_in_polygon_soup(points, polygons, traits);
|
||||
remove_invalid_polygons_in_polygon_soup(points, polygons);
|
||||
merge_duplicate_polygons_in_polygon_soup(points, polygons, np);
|
||||
remove_isolated_points_in_polygon_soup(points, polygons);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
///
|
||||
/// \brief cleans a given polygon soup through various repairing operations.
|
||||
|
|
@ -1044,22 +1110,8 @@ void repair_polygon_soup(PointRange& points,
|
|||
PolygonRange& polygons,
|
||||
const NamedParameters& np = parameters::default_values())
|
||||
{
|
||||
using parameters::get_parameter;
|
||||
using parameters::choose_parameter;
|
||||
|
||||
typedef typename internal::GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type Traits;
|
||||
Traits traits = choose_parameter<Traits>(get_parameter(np, internal_np::geom_traits));
|
||||
|
||||
#ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE
|
||||
std::cout << "Repairing soup with " << points.size() << " points and " << polygons.size() << " polygons" << std::endl;
|
||||
#endif
|
||||
|
||||
merge_duplicate_points_in_polygon_soup(points, polygons, np);
|
||||
internal::simplify_polygons_in_polygon_soup(points, polygons, traits);
|
||||
internal::split_pinched_polygons_in_polygon_soup(points, polygons, traits);
|
||||
internal::remove_invalid_polygons_in_polygon_soup(points, polygons);
|
||||
merge_duplicate_polygons_in_polygon_soup(points, polygons, np);
|
||||
remove_isolated_points_in_polygon_soup(points, polygons);
|
||||
internal::Polygon_soup_fixer<PointRange, PolygonRange> fixer;
|
||||
fixer(points, polygons, np);
|
||||
}
|
||||
|
||||
} // end namespace Polygon_mesh_processing
|
||||
|
|
|
|||
|
|
@ -564,6 +564,21 @@ void test_slit_pinched_polygons(const bool /*verbose*/ = false)
|
|||
|
||||
int main()
|
||||
{
|
||||
// test compilation with different polygon soup types
|
||||
std::vector<Point_3> vpoints;
|
||||
std::vector<std::vector<std::size_t> > vpolygons;
|
||||
PMP::repair_polygon_soup(vpoints, vpolygons);
|
||||
|
||||
std::vector<std::deque<std::size_t> > dpolygons;
|
||||
PMP::repair_polygon_soup(vpoints, dpolygons);
|
||||
|
||||
std::deque<std::vector<std::size_t> > dvpolygons;
|
||||
PMP::repair_polygon_soup(vpoints, dvpolygons);
|
||||
|
||||
std::deque<std::array<std::size_t, 3> > apolygons;
|
||||
PMP::repair_polygon_soup(vpoints, apolygons);
|
||||
|
||||
// test functions
|
||||
test_polygon_canonicalization(true);
|
||||
test_merge_duplicate_points(false);
|
||||
test_merge_duplicate_polygons(false);
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ public:
|
|||
dim_ = static_cast<int>(std::distance(ccci(p), ccci(p,0)));
|
||||
|
||||
data.reserve(pts.size());
|
||||
for(unsigned int i = 0; i < pts.size(); i++){
|
||||
for(std::size_t i = 0; i < pts.size(); i++){
|
||||
data.push_back(&pts[i]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,13 @@ create_interior_skeleton_and_offset_polygons_with_holes_2(FT offset,
|
|||
\ingroup PkgStraightSkeleton2OffsetFunctions
|
||||
|
||||
returns a container with all the outer offset polygons <I>with holes</I>
|
||||
at distance `offset` of the 2D polygon `poly_with_holes`.
|
||||
at distance `offset` of the 2D polygon `poly_with_holes`. Note that the
|
||||
offset of the outer frame is ignored.
|
||||
|
||||
This is equivalent to `arrange_offset_polygons_2(create_exterior_skeleton_and_offset_polygons_2(offset, poly_with_holes, ofk, ssk))`.
|
||||
This is equivalent to a call to `CGAL::arrange_offset_polygons_2()` on the
|
||||
output of \link CGAL::create_exterior_skeleton_and_offset_polygons_2() `create_exterior_skeleton_and_offset_polygons_2(offset, poly_with_holes, ofk, ssk))` \endlink
|
||||
after having filtered out the polygon corresponding to the offset of the outer frame and
|
||||
having reversed the orientation of all other polygons.
|
||||
|
||||
\tparam OfK must be a model of `Kernel`. It is used to instantiate
|
||||
`Polygon_offset_builder_traits_2<OfK>` for constructing the offset polygons.
|
||||
|
|
|
|||
|
|
@ -422,11 +422,15 @@ This \cgal packages provides a helper function to compute the required separatio
|
|||
|
||||
If you use this function to place the outer frame you are guaranteed to obtain an offset contour corresponding exclusively to the frame, which you can always identify as the one with the largest area and which you can simple remove from the result (to keep just the relevant outer contours).
|
||||
|
||||
|
||||
\cgalFigureBegin{Exterior,exterior_skeleton.png,exterior_offset.png}
|
||||
Exterior skeleton obtained using a frame (left) and 2 sample exterior offset contours (right)
|
||||
\cgalFigureEnd
|
||||
|
||||
For convenience, the following functions are provided:
|
||||
|
||||
- `CGAL::create_exterior_skeleton_and_offset_polygons_2()` adds the outer frame to the input polygon (with or without holes) and provides output offset polygons (`CGAL::Polygon_2<K>`), including the offset of the outer frame.
|
||||
- `CGAL::create_exterior_skeleton_and_offset_polygons_with_holes_2()` adds the outer frame to the input polygon (with or without holes) and provides as output offset polygons with holes (`CGAL::Polygon_with_holes_2`), exclusing the offset of the outer frame.
|
||||
|
||||
\section Straight_skeleton_2Straight Straight Skeletons, Medial Axis and Voronoi Diagrams
|
||||
|
||||
The straight skeleton of a polygon is similar to the medial
|
||||
|
|
@ -441,7 +445,7 @@ On the other hand, only reflex vertices (whose internal angle \f$ > \pi\f$)
|
|||
are the source of deviations of the bisectors from its center
|
||||
location. Therefore, for convex polygons, the straight skeleton, the
|
||||
medial axis and the Voronoi diagram are exactly equivalent,
|
||||
and, if a non-convex polygon contains only vertices of lowfor f in *.txt ; do echo $f ; aspell list < $f | sort | uniq -c ; done
|
||||
and, if a non-convex polygon contains only vertices of low
|
||||
reflexivity, the straight skeleton bisectors will be placed nearly
|
||||
equidistant to their defining edges, producing a straight skeleton
|
||||
pretty much alike a proper medial axis.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ endforeach()
|
|||
|
||||
if(CGAL_Qt5_FOUND)
|
||||
target_link_libraries(draw_straight_skeleton_2 PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(exterior_offset_of_multiple_polygons_with_holes PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
else()
|
||||
message(STATUS "NOTICE: The example draw_straight_skeleton_2 requires Qt and will not be compiled.")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Polygon_with_holes_2.h>
|
||||
#include <CGAL/create_offset_polygons_from_polygon_with_holes_2.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <CGAL/draw_polygon_with_holes_2.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K ;
|
||||
|
||||
typedef K::Point_2 Point ;
|
||||
typedef CGAL::Polygon_2<K> Polygon_2 ;
|
||||
typedef CGAL::Polygon_with_holes_2<K> PolygonWithHoles ;
|
||||
|
||||
typedef boost::shared_ptr<PolygonWithHoles> PolygonWithHolesPtr ;
|
||||
typedef boost::shared_ptr<Polygon_2> PolygonPtr ;
|
||||
|
||||
typedef std::vector<PolygonWithHolesPtr> PolygonWithHolesPtrVector;
|
||||
typedef std::vector<PolygonPtr> PolygonPtrVector;
|
||||
|
||||
PolygonWithHolesPtrVector
|
||||
exterior_offset_of_disjoint_polygons_with_holes(double lOffset, const std::vector<PolygonWithHoles>& pwhs)
|
||||
{
|
||||
std::vector<Point> outer_vertices;
|
||||
for (const PolygonWithHoles& pwh : pwhs)
|
||||
outer_vertices.insert(outer_vertices.end(),
|
||||
pwh.outer_boundary().container().begin(),
|
||||
pwh.outer_boundary().container().end());
|
||||
boost::optional<double> margin = compute_outer_frame_margin(outer_vertices.begin(),
|
||||
outer_vertices.end(),
|
||||
lOffset);
|
||||
|
||||
if ( margin )
|
||||
{
|
||||
double lm = CGAL::to_double(*margin);
|
||||
CGAL::Bbox_2 bbox = bbox_2(outer_vertices.begin(), outer_vertices.end());
|
||||
|
||||
double fxmin = bbox.xmin() - lm ;
|
||||
double fxmax = bbox.xmax() + lm ;
|
||||
double fymin = bbox.ymin() - lm ;
|
||||
double fymax = bbox.ymax() + lm ;
|
||||
|
||||
Polygon_2 frame ;
|
||||
frame.push_back( Point(fxmin,fymin) );
|
||||
frame.push_back( Point(fxmax,fymin) );
|
||||
frame.push_back( Point(fxmax,fymax) );
|
||||
frame.push_back( Point(fxmin,fymax) );
|
||||
|
||||
std::vector<Polygon_2> outer_as_holes;
|
||||
outer_as_holes.reserve(pwhs.size());
|
||||
for (const PolygonWithHoles& pwh : pwhs)
|
||||
outer_as_holes.emplace_back(pwh.outer_boundary().container().rbegin(),
|
||||
pwh.outer_boundary().container().rend());
|
||||
|
||||
PolygonWithHoles pwh(frame, outer_as_holes.begin(), outer_as_holes.end());
|
||||
PolygonPtrVector off_polys = CGAL::create_interior_skeleton_and_offset_polygons_2(lOffset,pwh);
|
||||
|
||||
// filter outer frame
|
||||
Point xtrm_pt = *(off_polys[0]->begin());
|
||||
std::size_t outer_id=0;
|
||||
for(std::size_t i=0; i<off_polys.size(); ++i)
|
||||
if (off_polys[i]->orientation() == CGAL::COUNTERCLOCKWISE)
|
||||
{
|
||||
for (const Point& p : off_polys[i]->container())
|
||||
if (p < xtrm_pt)
|
||||
{
|
||||
xtrm_pt=p;
|
||||
outer_id=i;
|
||||
}
|
||||
}
|
||||
if (outer_id != (off_polys.size()-1))
|
||||
std::swap(off_polys[outer_id], off_polys.back());
|
||||
off_polys.pop_back();
|
||||
for (PolygonPtr ptr : off_polys)
|
||||
ptr->reverse_orientation();
|
||||
|
||||
// offset of holes
|
||||
for (const PolygonWithHoles& pwh : pwhs)
|
||||
{
|
||||
for (PolygonWithHoles::Hole_const_iterator hit=pwh.holes_begin();
|
||||
hit!=pwh.holes_end();
|
||||
++hit)
|
||||
{
|
||||
Polygon_2 h = *hit;
|
||||
h.reverse_orientation();
|
||||
PolygonPtrVector off_hole = CGAL::create_interior_skeleton_and_offset_polygons_2(lOffset,h);
|
||||
off_polys.insert(off_polys.end(), off_hole.begin(), off_hole.end());
|
||||
}
|
||||
}
|
||||
|
||||
return CGAL::arrange_offset_polygons_2<PolygonWithHoles>(off_polys);
|
||||
}
|
||||
|
||||
return PolygonWithHolesPtrVector();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::vector<PolygonWithHoles> pwhs;
|
||||
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
Polygon_2 outer;
|
||||
outer.push_back( Point(i+0+i*10, 0) );
|
||||
outer.push_back( Point(i+0+(i+1)*10, 0) );
|
||||
outer.push_back( Point(i+0+(i+1)*10, 10) );
|
||||
outer.push_back( Point(i+0+i*10, 10) );
|
||||
pwhs.emplace_back(outer);
|
||||
|
||||
Polygon_2 hole;
|
||||
hole.push_back( Point(i+3+i*10,3) ) ;
|
||||
hole.push_back( Point(i+6+i*10,3) ) ;
|
||||
hole.push_back( Point(i+6+i*10,6) ) ;
|
||||
hole.push_back( Point(i+3+i*10,6) ) ;
|
||||
pwhs[i].add_hole( hole ) ;
|
||||
}
|
||||
|
||||
double lOffset = 1.1 ;
|
||||
|
||||
PolygonWithHolesPtrVector offset_poly_with_holes = exterior_offset_of_disjoint_polygons_with_holes(lOffset,pwhs);
|
||||
|
||||
for (PolygonWithHolesPtr ptr : offset_poly_with_holes)
|
||||
CGAL::draw(*ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -389,7 +389,7 @@ create_exterior_skeleton_and_offset_polygons_2(const FT& aOffset,
|
|||
ofk);
|
||||
}
|
||||
|
||||
// Overloads common to both polygons with and without holes, a simple polygon is returned in any case
|
||||
// Overloads common to both polygons with and without holes, a simple polygons are returned in any case
|
||||
template<class FT, class APolygon, class OfK,
|
||||
class OutPolygon = typename CGAL_SS_i::Default_return_polygon_type<APolygon, OfK>::type>
|
||||
std::vector< boost::shared_ptr<OutPolygon> >
|
||||
|
|
|
|||
|
|
@ -97,6 +97,44 @@ create_interior_skeleton_and_offset_polygons_with_holes_2(const FT& aOffset,
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// EXTERIOR
|
||||
|
||||
/*! create_exterior_skeleton_and_offset_polygons_with_holes_2 (orders the resulting polygons) */
|
||||
|
||||
// Polygon might be a Polygon with holes or not, but it returns a Polygon with holes
|
||||
template<class FT, class Polygon, class OfK, class SsK,
|
||||
class OutPolygonWithHoles = typename CGAL_SS_i::Default_return_polygon_with_holes_type<Polygon, OfK>::type>
|
||||
std::vector<boost::shared_ptr<OutPolygonWithHoles> >
|
||||
inline
|
||||
create_exterior_skeleton_and_offset_polygons_with_holes_2(const FT& aOffset,
|
||||
const Polygon& aPoly,
|
||||
const OfK& ofk,
|
||||
const SsK& ssk)
|
||||
{
|
||||
typedef typename CGAL_SS_i::Default_return_polygon_type<Polygon, OfK>::type Polygon_;
|
||||
std::vector<boost::shared_ptr<Polygon_> > raw_output =
|
||||
create_exterior_skeleton_and_offset_polygons_2(aOffset, aPoly, ofk, ssk);
|
||||
|
||||
// filter offset of the outer frame
|
||||
typename OfK::Point_2 xtrm_pt = *(raw_output[0]->begin());
|
||||
std::size_t outer_id=0;
|
||||
for(std::size_t i=0; i<raw_output.size(); ++i)
|
||||
if (raw_output[i]->orientation() == COUNTERCLOCKWISE)
|
||||
{
|
||||
for (const typename OfK::Point_2& p : raw_output[i]->container())
|
||||
if (p < xtrm_pt)
|
||||
{
|
||||
xtrm_pt=p;
|
||||
outer_id=i;
|
||||
}
|
||||
}
|
||||
if (outer_id != (raw_output.size()-1))
|
||||
std::swap(raw_output[outer_id], raw_output.back());
|
||||
raw_output.pop_back();
|
||||
for (boost::shared_ptr<Polygon_> ptr : raw_output)
|
||||
ptr->reverse_orientation();
|
||||
|
||||
return arrange_offset_polygons_2<OutPolygonWithHoles>(raw_output);
|
||||
}
|
||||
|
||||
/*! create_interior_skeleton_and_offset_polygons_2 with a polygon with holes */
|
||||
|
||||
// overload where PolygonWithHoles actually is a type of Polygon that supports holes
|
||||
|
|
@ -111,23 +149,21 @@ create_exterior_skeleton_and_offset_polygons_2(const FT& aOffset,
|
|||
typename std::enable_if<
|
||||
CGAL_SS_i::has_Hole_const_iterator<PolygonWithHoles>::value>::type* = nullptr)
|
||||
{
|
||||
return create_exterior_skeleton_and_offset_polygons_2(aOffset, aPoly.outer_boundary(), ofk, ssk);
|
||||
}
|
||||
std::vector<boost::shared_ptr<OutPolygon> > polygons =
|
||||
create_exterior_skeleton_and_offset_polygons_2(aOffset, aPoly.outer_boundary(), ofk, ssk);
|
||||
|
||||
/*! create_exterior_skeleton_and_offset_polygons_with_holes_2 (orders the resulting polygons) */
|
||||
for (typename PolygonWithHoles::Hole_const_iterator hit=aPoly.holes_begin(); hit!=aPoly.holes_end(); ++hit)
|
||||
{
|
||||
typename PolygonWithHoles::Polygon_2 hole = *hit;
|
||||
hole.reverse_orientation();
|
||||
std::vector<boost::shared_ptr<OutPolygon> > hole_polygons =
|
||||
create_interior_skeleton_and_offset_polygons_2(aOffset,
|
||||
hole,
|
||||
ofk,ssk);
|
||||
polygons.insert(polygons.end(), hole_polygons.begin(), hole_polygons.end());
|
||||
}
|
||||
|
||||
// Polygon might be a Polygon with holes or not, but it returns a Polygon with holes
|
||||
template<class FT, class Polygon, class OfK, class SsK,
|
||||
class OutPolygonWithHoles = typename CGAL_SS_i::Default_return_polygon_with_holes_type<Polygon, OfK>::type>
|
||||
std::vector<boost::shared_ptr<OutPolygonWithHoles> >
|
||||
inline
|
||||
create_exterior_skeleton_and_offset_polygons_with_holes_2(const FT& aOffset,
|
||||
const Polygon& aPoly,
|
||||
const OfK& ofk,
|
||||
const SsK& ssk)
|
||||
{
|
||||
return arrange_offset_polygons_2<OutPolygonWithHoles>(
|
||||
create_exterior_skeleton_and_offset_polygons_2(aOffset, aPoly, ofk, ssk));
|
||||
return polygons;
|
||||
}
|
||||
|
||||
template<class FT, class Polygon, class OfK,
|
||||
|
|
|
|||
|
|
@ -760,9 +760,8 @@ void test_offset_polygon_exterior()
|
|||
// print_polygon_with_holes(*offp);
|
||||
|
||||
assert(offset_poly_with_holes.size() == 1);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() == 4);
|
||||
assert(offset_poly_with_holes[0]->number_of_holes() == 1);
|
||||
assert(offset_poly_with_holes[0]->holes_begin()->size() == 12);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() == 12);
|
||||
assert(offset_poly_with_holes[0]->number_of_holes() == 0);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Value such that it is clearly separated into two contours
|
||||
|
|
@ -770,20 +769,19 @@ void test_offset_polygon_exterior()
|
|||
offset_poly_with_holes =
|
||||
create_exterior_skeleton_and_offset_polygons_with_holes_2(FT(7), poly, K(), EPICK());
|
||||
|
||||
// for(const auto& offp : offset_poly_with_holes)
|
||||
// print_polygon_with_holes(*offp);
|
||||
// for(const auto& offp : offset_poly_with_holes)
|
||||
// print_polygon_with_holes(*offp);
|
||||
|
||||
assert(offset_poly_with_holes.size() == 2);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() == 4);
|
||||
assert(offset_poly_with_holes.size() == 1);
|
||||
assert(offset_poly_with_holes[0]->number_of_holes() == 1);
|
||||
|
||||
// Technically both polygons below should be rectangles, but the algorithm puts a 5th vertex collinear.
|
||||
// Tolerating it for now...
|
||||
|
||||
// assert(offset_poly_with_holes[0]->holes_begin()->size() == 4);
|
||||
// assert(offset_poly_with_holes[1]->outer_boundary().size() == 4);
|
||||
assert(offset_poly_with_holes[0]->holes_begin()->size() >= 4);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() >= 4);
|
||||
assert(offset_poly_with_holes[0]->holes_begin()->is_simple());
|
||||
assert(offset_poly_with_holes[1]->outer_boundary().is_simple());
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().is_simple());
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Border value between a single contour and two contours
|
||||
|
|
@ -795,17 +793,54 @@ void test_offset_polygon_exterior()
|
|||
// for(const auto& offp : offset_poly_with_holes)
|
||||
// print_polygon_with_holes(*offp);
|
||||
|
||||
assert(offset_poly_with_holes.size() == 2);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() == 4);
|
||||
assert(offset_poly_with_holes.size() >= 1);
|
||||
assert(offset_poly_with_holes[0]->number_of_holes() == 1);
|
||||
|
||||
// Technically both polygons below should be rectangles, but the algorithm puts a 5th vertex collinear.
|
||||
// Tolerating it for now...
|
||||
|
||||
// assert(offset_poly_with_holes[0]->holes_begin()->size() == 4);
|
||||
// assert(offset_poly_with_holes[1]->outer_boundary().size() == 4);
|
||||
assert(offset_poly_with_holes[0]->holes_begin()->size() >= 4);
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().size() >= 4);
|
||||
assert(offset_poly_with_holes[0]->holes_begin()->is_simple());
|
||||
assert(offset_poly_with_holes[1]->outer_boundary().is_simple());
|
||||
assert(offset_poly_with_holes[0]->outer_boundary().is_simple());
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
void test_offset_polygon_with_holes_exterior()
|
||||
{
|
||||
std::cout << " --- Test Polygon exterior, kernel: " << typeid(K).name() << std::endl;
|
||||
|
||||
typedef typename K::Point_2 Point;
|
||||
|
||||
typedef CGAL::Polygon_2<K> Polygon_2;
|
||||
typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes_2;
|
||||
typedef boost::shared_ptr<Polygon_with_holes_2> Polygon_with_holes_2_ptr;
|
||||
typedef std::vector<Polygon_with_holes_2_ptr> Polygon_with_holes_2_ptr_container;
|
||||
|
||||
Polygon_2 outer ;
|
||||
outer.push_back( Point( 10.0, 10.0) ) ;
|
||||
outer.push_back( Point(-10.0, 10.0) ) ;
|
||||
outer.push_back( Point(-10.0, -10.0) ) ;
|
||||
outer.push_back( Point(10.0, -10.0) ) ;
|
||||
|
||||
Polygon_2 hole ;
|
||||
hole.push_back( Point(5.0,5.0) ) ;
|
||||
hole.push_back( Point(5.0,-5.0) ) ;
|
||||
hole.push_back( Point(-5.0,-5.0) ) ;
|
||||
hole.push_back( Point(-5.0,5.0) ) ;
|
||||
|
||||
Polygon_with_holes_2 pwh(outer) ;
|
||||
pwh.add_hole( hole ) ;
|
||||
|
||||
Polygon_with_holes_2_ptr_container offset_poly_with_holes_1 =
|
||||
CGAL::create_exterior_skeleton_and_offset_polygons_with_holes_2(1., pwh, K(), EPICK());
|
||||
assert(offset_poly_with_holes_1.size()==1);
|
||||
assert(offset_poly_with_holes_1[0]->number_of_holes()==1);
|
||||
|
||||
Polygon_with_holes_2_ptr_container offset_poly_with_holes_2 =
|
||||
CGAL::create_exterior_skeleton_and_offset_polygons_with_holes_2(5., pwh, K(), EPICK());
|
||||
assert(offset_poly_with_holes_2.size()==1);
|
||||
assert(offset_poly_with_holes_2[0]->number_of_holes()==0);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
|
|
@ -940,6 +975,7 @@ void test_kernel()
|
|||
test_offset_non_manifold<K>();
|
||||
test_offset_non_manifold_2<K>();
|
||||
test_offset_polygon_exterior<K>();
|
||||
test_offset_polygon_with_holes_exterior<K>();
|
||||
test_offset_multiple_CCs<K>();
|
||||
|
||||
// Real data
|
||||
|
|
|
|||
Loading…
Reference in New Issue