Skip to content

Commit

Permalink
#757: Added binary set operations by CGAL
Browse files Browse the repository at this point in the history
  • Loading branch information
MaartenHilferink committed Jul 29, 2024
1 parent 0551ac1 commit b441726
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 155 deletions.
92 changes: 91 additions & 1 deletion geo/dll/src/BoostGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "BoostGeometry.h"

#include <CGAL/Boolean_set_operations_2.h>

static VersionComponent s_BoostGeometry("boost::geometry " BOOST_STRINGIZE(BOOST_GEOMETRY_VERSION));

// *****************************************************************************
Expand All @@ -26,6 +28,11 @@ static CommonOperGroup grBgUnion ("bg_union" , oper_policy::better_not_i
static CommonOperGroup grBgXOR ("bg_xor" , oper_policy::better_not_in_meta_scripting);
static CommonOperGroup grBgDifference("bg_difference", oper_policy::better_not_in_meta_scripting);

static CommonOperGroup grcgalIntersect("cgal_intersect", oper_policy::better_not_in_meta_scripting);
static CommonOperGroup grcgalUnion("cgal_union", oper_policy::better_not_in_meta_scripting);
static CommonOperGroup grcgalXOR("cgal_xor", oper_policy::better_not_in_meta_scripting);
static CommonOperGroup grcgalDifference("cgal_difference", oper_policy::better_not_in_meta_scripting);

static CommonOperGroup grBgBuffer_point ("bg_buffer_point", oper_policy::better_not_in_meta_scripting);
static CommonOperGroup grBgBuffer_multi_point ("bg_buffer_multi_point", oper_policy::better_not_in_meta_scripting);

Expand All @@ -46,7 +53,7 @@ static CommonOperGroup grBgOuter_single_polygon("bg_outer_single_polygon", oper_
static CommonOperGroup grBgOuter_multi_polygon("bg_outer_multi_polygon", oper_policy::better_not_in_meta_scripting);

// *****************************************************************************
// map algebraic operations
// map algebraic operations on boost geometry polygons
// *****************************************************************************

template <typename P> using sequence_t = std::vector<P>;
Expand Down Expand Up @@ -102,6 +109,59 @@ struct BgMultiPolygonOperator : BinaryMapAlgebraicOperator<P>
BinaryBgMpOper m_Oper;
};

// *****************************************************************************
// map algebraic operations on CGAL polygons
// *****************************************************************************

template <typename P, typename BinaryBgMpOper>
struct CGAL_MultiPolygonOperator : BinaryMapAlgebraicOperator<P>
{
using PointType = P;
using PolygonType = std::vector<PointType>;
using ArgType = DataArray<PolygonType>;

CGAL_MultiPolygonOperator(AbstrOperGroup& gr, BinaryBgMpOper&& oper = BinaryBgMpOper())
: BinaryMapAlgebraicOperator<P>(&gr, compatible_simple_values_unit_creator, ValueComposition::Polygon)
{}
using st = sequence_traits<PolygonType>;
using seq_t = typename st::seq_t;
using cseq_t = typename st::cseq_t;

void CalcTile(seq_t resData, cseq_t arg1Data, cseq_t arg2Data, ArgFlags af MG_DEBUG_ALLOCATOR_SRC_ARG) const override
{
tile_offset n1 = arg1Data.size();
tile_offset n2 = arg2Data.size();
tile_offset n = std::max(n1, n2);
assert(n1 == n || (af & AF1_ISPARAM));
assert(n2 == n || (af & AF2_ISPARAM));
assert(resData.size() == n);

CGAL_Traits::Ring helperRing;
CGAL_Traits::Polygon_with_holes helperPolygon;
CGAL_Traits::Polygon_set currMP1, currMP2, resMP;
std::vector<DPoint> helperPointArray;

bool domain1IsVoid = (af & AF1_ISPARAM);
bool domain2IsVoid = (af & AF2_ISPARAM);
if (domain1IsVoid)
assign_multi_polygon(currMP1, arg1Data[0], true, std::move(helperPolygon), std::move(helperRing));
if (domain2IsVoid)
assign_multi_polygon(currMP2, arg2Data[0], true, std::move(helperPolygon), std::move(helperRing));

for (SizeT i = 0; i != n; ++i)
{
if (!domain1IsVoid)
assign_multi_polygon(currMP1, arg1Data[i], true, std::move(helperPolygon), std::move(helperRing));
if (!domain2IsVoid)
assign_multi_polygon(currMP2, arg2Data[i], true, std::move(helperPolygon), std::move(helperRing));
resMP.clear();
m_Oper(currMP1, currMP2, resMP);
cgal_assign(resData[i], resMP);
}
}
BinaryBgMpOper m_Oper;
};

// *****************************************************************************
// simplify
// *****************************************************************************
Expand Down Expand Up @@ -889,6 +949,22 @@ namespace
void operator ()(const auto& a, const auto& b, auto& r) const { boost::geometry::sym_difference(a, b, r); }
};

struct cgal_intersection {
void operator ()(const auto& a, const auto& b, auto& r) const { r.intersection(a, b); }
};

struct cgal_union {
void operator ()(const auto& a, const auto& b, auto& r) const { r.join(a, b); }
};

struct cgal_difference {
void operator ()(const auto& a, const auto& b, auto& r) const { r.difference(a, b); }
};

struct cgal_sym_difference {
void operator ()(const auto& a, const auto& b, auto& r) const { r.symmetric_difference(a, b); }
};

tl_oper::inst_tuple_templ<typelists::points, SimplifyLinestringOperator> simplifyLineStringOperators;
tl_oper::inst_tuple_templ<typelists::points, SimplifyMultiPolygonOperator> simplifyMultiPolygonOperators;
tl_oper::inst_tuple_templ<typelists::points, SimplifyPolygonOperator> simplifyPolygonOperators;
Expand Down Expand Up @@ -919,5 +995,19 @@ namespace

tl_oper::inst_tuple_templ<typelists::points, OuterSingePolygonOperator, AbstrOperGroup&> bg_outerSinglePolygonOperators(grBgOuter_single_polygon);
tl_oper::inst_tuple_templ<typelists::points, OuterMultiPolygonOperator, AbstrOperGroup&> bg_outerMultiPolygonOperators(grBgOuter_multi_polygon);

template <typename P> using CGAL_IntersectMultiPolygonOperator = CGAL_MultiPolygonOperator < P, cgal_intersection>;
tl_oper::inst_tuple_templ<typelists::points, CGAL_IntersectMultiPolygonOperator, AbstrOperGroup&> cgalIntersectMultiPolygonOperatorsNamed(grcgalIntersect);

template <typename P> using CGAL_UnionMultiPolygonOperator = CGAL_MultiPolygonOperator<P, cgal_union>;
tl_oper::inst_tuple_templ<typelists::points, CGAL_UnionMultiPolygonOperator, AbstrOperGroup&> cgalUnionMultiPolygonOperatorsNamed(grcgalUnion);

template <typename P> using CGAL_DifferenceMultiPolygonOperator = CGAL_MultiPolygonOperator<P, cgal_difference>;
tl_oper::inst_tuple_templ<typelists::points, CGAL_DifferenceMultiPolygonOperator, AbstrOperGroup&> cgalDifferenceMultiPolygonOperatorsNamed(grcgalDifference);

template <typename P> using CGAL_SymmetricDifferenceMultiPolygonOperator = CGAL_MultiPolygonOperator<P, cgal_sym_difference>;
tl_oper::inst_tuple_templ<typelists::points, CGAL_SymmetricDifferenceMultiPolygonOperator, AbstrOperGroup&> cgalSymmetricDifferenceMultiPolygonOperatorsNamed(grcgalXOR);


}

164 changes: 163 additions & 1 deletion geo/dll/src/BoostGeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,165 @@
#include "ipolygon/polygon.hpp"
#include "geo/BoostPolygon.h"

//============================ CGAL ============================

#include <CGAL/Polygon_set_2.h>
#include <CGAL/intersections.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>

//#include <CGAL/draw_polygon_set_2.h>

struct CGAL_Traits
{
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point = CGAL::Point_2< Kernel >;
using Ring = CGAL::Polygon_2<Kernel>;
using Polygon_with_holes = CGAL::Polygon_with_holes_2<Kernel>;
using Polygon_set = CGAL::Polygon_set_2<Kernel>;
};

template <typename DmsPointType>
void assign_multi_polygon(CGAL_Traits::Polygon_set& resMP, SA_ConstReference<DmsPointType> polyRef, bool mustInsertInnerRings
, CGAL_Traits::Polygon_with_holes&& helperPolygon = CGAL_Traits::Polygon_with_holes()
, CGAL_Traits::Ring&& helperRing = CGAL_Traits::Ring()
)
{
resMP.clear();

boost::polygon::SA_ConstRingIterator<DmsPointType>
rb(polyRef, 0),
re(polyRef, -1);
auto ri = rb;
// dbg_assert(ri != re);
if (ri == re)
return;
CGAL::Orientation outerOrientation = CGAL::Orientation::COUNTERCLOCKWISE;
for (; ri != re; ++ri)
{
assert((*ri).begin() != (*ri).end());
assert((*ri).begin()[0] == (*ri).end()[-1]); // closed ?

helperRing.clear();
for (auto p = (*ri).begin(); p != (*ri).end(); ++p)
helperRing.push_back(CGAL_Traits::Point(p->X(), p->Y()));
// helperRing.insert(helperRing.end(), (*ri).begin(), (*ri).end());
if (helperRing.is_empty())
continue;

assert(helperRing.begin() != helperRing.end());
assert(helperRing.begin()[0] == helperRing.end()[-1]); // closed ?

CGAL::Orientation currOrientation = helperRing.orientation();
if (ri == rb || currOrientation == outerOrientation)
{
if (ri != rb && !helperPolygon.outer_boundary().is_empty())
resMP.insert(std::move(helperPolygon));
helperPolygon.clear(); assert(helperPolygon.outer_boundary().is_empty() && helperPolygon.holes().empty());

helperPolygon.outer_boundary() = std::move(helperRing); // swap is faster than assign
assert(helperRing.is_empty());
outerOrientation = currOrientation;

// skip outer rings that intersect with a previous outer ring if innerRings are skipped
MG_CHECK(mustInsertInnerRings);
/* TODO
if (!mustInsertInnerRings)
{
SizeT polygonIndex = 0;
while (polygonIndex < resMP.size())
{
auto currPolygon = resMP.begin() + polygonIndex;
if (CGAL::do_intersect(currPolygon->outer_boundary(), helperPolygon.outer_boundary()))
{
if (CGAL::within(currPolygon->outer_boundary(), helperPolygon.outer_boundary()))
{
resMP.erase(currPolygon);
continue;
}
if (CGAL::within(helperPolygon.outer_boundary(), currPolygon->outer_boundary()))
{
helperPolygon.clear();
assert(helperPolygon.outer_boundary().is_empty() && helperPolygon.holes().is_empty());
break;
}
if (CGAL::overlaps(currPolygon->outer_boundary(), helperPolygon.outer_boundary()))
throwDmsErrF("OuterPolygon: unexpected overlap of two outer rings in %s", AsString(polyRef).c_str());
// a combination of touching outer rings such as in an 8 shape is
}
polygonIndex++;
}
}
*/
}
else if (mustInsertInnerRings)
{
helperPolygon.holes().emplace_back(helperRing);
}
}
if (!helperPolygon.outer_boundary().is_empty())
resMP.insert(helperPolygon);
}


template <dms_sequence E>
void cgal_assign_ring(E&& ref, const CGAL_Traits::Ring& polyData)
{
using coordinate_type = scalar_of_t<std::remove_reference_t<E>>;
for (const auto& p : polyData)
ref.push_back(shp2dms_order<coordinate_type>(p.x(), p.y()));
}

template <dms_sequence E>
void cgal_assign(E&& ref, std::vector<CGAL_Traits::Polygon_with_holes>&& polyVec)
{
using coordinate_type = scalar_of_t<std::remove_reference_t<E>>;

std::vector<CGAL_Traits::Point> closurePoints;

for (const auto& poly : polyVec)
{
// E::value_type polyVec;
cgal_assign_ring(std::forward<E>(ref), poly.outer_boundary());
closurePoints.emplace_back(poly.outer_boundary().end()[-1]);
for (const auto& hole : poly.holes())
{
cgal_assign_ring(std::forward<E>(ref), hole);
closurePoints.emplace_back(hole.end()[-1]);
}
}
if (closurePoints.size() > 1)
{
closurePoints.pop_back();
while (closurePoints.size())
{
// ref.push_back(shp2dms_order<coordinate_type>(closurePoints.back().x(), closurePoints.back().y()));
coordinate_type x = closurePoints.back().x();
coordinate_type y = closurePoints.back().y();

Point<coordinate_type> p = shp2dms_order<coordinate_type>(x, y);
ref.push_back(p);
closurePoints.pop_back();
}
}
}

template <dms_sequence E>
void cgal_assign(E&& ref, const CGAL_Traits::Polygon_set& polyData)
{
std::vector<CGAL_Traits::Polygon_with_holes> polyVec;

polyData.polygons_with_holes(std::back_inserter(polyVec));
cgal_assign(std::forward<E>(ref), std::move(polyVec));
}

//============================ boost geometry ============================



using bg_multi_point_t = boost::geometry::model::multi_point<DPoint>;
using bg_linestring_t = boost::geometry::model::linestring<DPoint>;
using bg_multi_linestring_t = boost::geometry::model::multi_linestring<bg_linestring_t>;
Expand Down Expand Up @@ -251,7 +410,10 @@ void assign_polygon(bg_polygon_t& resPoly, SA_ConstReference<DmsPointType> polyR
}

template <typename DmsPointType>
void assign_multi_polygon(bg_multi_polygon_t& resMP, SA_ConstReference<DmsPointType> polyRef, bool mustInsertInnerRings, bg_polygon_t& helperPolygon, bg_ring_t& helperRing)
void assign_multi_polygon(bg_multi_polygon_t& resMP, SA_ConstReference<DmsPointType> polyRef, bool mustInsertInnerRings
, bg_polygon_t& helperPolygon
, bg_ring_t& helperRing
)
{
resMP.clear();

Expand Down
Loading

0 comments on commit b441726

Please sign in to comment.