| by YoungTimes | No comments

多边形求并集(Union)

CGAL计算多边形并集

CGAL提供一系列的join函数用于计算两个Polygon的并集(Union)。

bool join(const Type1 & p1, const Type2 & p2, General_polygon_with_holes_2 & res)

Type1和Type2支持的类型如下,简单的说就是,它支持计算任意简单多边形和带洞(hole)多边形求并集。

Type1Type2
Polygon_2Polygon_2
Polygon_2polygon_with_holes_2
Polygon_with_holes_2Polygon_2
Polygon_with_holes_2Polygon_with_holes_2
General_polygon_2General_polygon_2
General_polygon_2General_polygon_with_holes_2
General_polygon_with_holes_2General_polygon_2
General_polygon_with_holes_2General_polygon_with_holes_2

完整的代码如下:

#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Gps_circle_segment_traits_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/Lazy_exact_nt.h>
#include <list>
#include <cstdlib>
#include <cmath>

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_2                                   Point_2;
typedef Kernel::Circle_2                                  Circle_2;
typedef CGAL::Gps_circle_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 Traits_2::Curve_2                                 Curve_2;
typedef Traits_2::X_monotone_curve_2                      X_monotone_curve_2;

// Construct a polygon from a circle.
Polygon_2 construct_polygon (const Circle_2& circle) {
  // Subdivide the circle into two x-monotone arcs.
  Traits_2 traits;
  Curve_2 curve (circle);
  std::list<CGAL::Object> objects;
  traits.make_x_monotone_2_object() (curve, std::back_inserter(objects));
  CGAL_assertion (objects.size() == 2);

  // Construct the polygon.
  Polygon_2 pgn;
  X_monotone_curve_2 arc;
  std::list<CGAL::Object>::iterator iter;
  for (iter = objects.begin(); iter != objects.end(); ++iter) {
    CGAL::assign(arc, *iter);
    pgn.push_back (arc);
  }
  return pgn;
}

// The main program:
int main (int argc, char* argv[]) {
  // Read the number of circles from the command line.
  unsigned int n_circles = 8;

  // Create the circles, equally spaced of the circle x^2 + y^2 = 1.
  const double pi = std::atan(1.0) * 4;
  const double n_circles_reciep = 1.0 / n_circles;
  const double radius = 1;
  const double frac = 2 * pi * n_circles_reciep;
  std::list<Polygon_2> circles;
  unsigned int k;
  for (k = 0; k < n_circles; k++) {
    const double angle = frac * k;
    const double x = radius * std::sin(angle);
    const double y = radius * std::cos(angle);
    Point_2 center = Point_2(x, y);
    Circle_2 circle(center, radius);
    circles.push_back (construct_polygon (circle));
  }

  // Compute the union aggregately.
  std::list<Polygon_with_holes_2> res;
  CGAL::join (circles.begin(), circles.end(), std::back_inserter (res));
  // Print the result.
  std::copy (res.begin(), res.end(),
             std::ostream_iterator<Polygon_with_holes_2>(std::cout, "\n"));
  std::cout << std::endl;

  return 0;
}

Boost计算多边形并集(Union)

Boost库中也提供了求解多边形并集的方法。

template<typename Geometry1, typename Geometry2, typename Collection>
void union_(Geometry1 const & geometry1, Geometry2 const & geometry2, Collection & output_collection)

完整的代码如下:

#include <iostream>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

#include <boost/foreach.hpp>

int main() {
    typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;

    polygon green, blue;

    boost::geometry::read_wkt(
        "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3)"
            "(4.0 2.0, 4.2 1.4, 4.8 1.9, 4.4 2.2, 4.0 2.0))", green);

    boost::geometry::read_wkt(
        "POLYGON((4.0 -0.5 , 3.5 1.0 , 2.0 1.5 , 3.5 2.0 , 4.0 3.5 , 4.5 2.0 , 6.0 1.5 , 4.5 1.0 , 4.0 -0.5))", blue);

    std::vector<polygon> output;
    boost::geometry::union_(green, blue, output);

    int i = 0;
    std::cout << "green || blue:" << std::endl;
    BOOST_FOREACH(polygon const& p, output) {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;
    }


    return 0;
}

输出的效果如下:

在线效果体验网站

https://www.bing.com/api/maps/sdk/mapcontrol/isdk#binaryOperations+JS

https://milevski.co/martinez/demo/#geo

参考材料

https://doc.cgal.org/latest/Boolean_set_operations_2/Boolean_set_operations_2_2set_union_8cpp-example.html

https://www.boost.org/doc/libs/1_56_0/libs/geometry/doc/html/geometry/reference/algorithms/union_.html

发表评论