Boost :: Geometry - 在3d空间中查找2d多边形的区域?

时间:2014-08-16 12:23:29

标签: c++ area boost-geometry

我试图在3d空间中获得2d多边形的区域。 Boost :: Geometry有没有办法做到这一点?这是我的实现,但它一直返回0:

#include <iostream>

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

namespace bg = boost::geometry;

typedef bg::model::point<double, 3, bg::cs::cartesian> point3d;

int main()
{
    bg::model::multi_point<point3d> square;
    bg::read_wkt("MULTIPOINT((0 0 0), (0 2 0), (0 2 2), (0 0 2), (0 0 0))", square);
    double area = bg::area(square);
    std::cout << "Area: " << area << std::endl;

    return 0;
}

UPD :实际上,我对简单的2d多点广场有同样的问题:

#include <iostream>

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

namespace bg = boost::geometry;

typedef bg::model::point<double, 2, bg::cs::cartesian> point2d;

int main()
{
    bg::model::multi_point<point2d> square;
    bg::read_wkt("MULTIPOINT((0 0), (2 0), (2 2), (0 2))", square);
    double area = bg::area(square);
    std::cout << "Area: " << area << std::endl;

    return 0;
}

结果如下:

$ ./test_area
Area: 0

UPD :看起来boost::geometry中的区域计算仅适用于2维多边形。

2 个答案:

答案 0 :(得分:2)

我不希望一组积分有一个区域。您需要等效的model::polygon<poind3d>,但目前似乎不支持。

如果保证点是共面的并且线段不相互交叉,则可以将多边形分解为一系列三角形,并使用一点线性代数计算区域,基于以下公式对于三角形区域:
enter image description here

在非凸多边形的情况下,需要调整面积之和以减去多边形外的区域。实现这一目标的最简单方法是使用三角形的有符号区域,包括右手三角形的正贡献和左手三角形的负贡献:
enter image description here

请注意,似乎有一些计划在Boost中包含cross_product实现,但从版本1.56开始,它似乎不包括在内。以下替换应该适用于您的用例:

point3d cross_product(const point3d& p1, const point3d& p2)
{
  double x = bg::get<0>(p1);
  double y = bg::get<1>(p1);
  double z = bg::get<2>(p1);
  double u = bg::get<0>(p2);
  double v = bg::get<1>(p2);
  double w = bg::get<2>(p2);
  return point3d(y*w-z*v, z*u-x*w, x*v-y*u);
}
point3d cross_product(const bg::model::segment<point3d>& p1
                    , const bg::model::segment<point3d>& p2)
{
  point3d v1(p1.second);
  point3d v2(p2.second);
  bg::subtract_point(v1, p1.first);
  bg::subtract_point(v2, p2.first);

  return cross_product(v1, v2);
}

然后可以使用以下内容计算区域:

// compute the are of a collection of 3D points interpreted as a 3D polygon
// Note that there are no checks as to whether or not the points are
// indeed co-planar.
double area(bg::model::multi_point<point3d>& polygon)
{
  if (polygon.size()<3) return 0;

  bg::model::segment<point3d> v1(polygon[1], polygon[0]);
  bg::model::segment<point3d> v2(polygon[2], polygon[0]);
  // Compute the cross product for the first pair of points, to handle
  // shapes that are not convex.
  point3d n1 = cross_product(v1, v2);
  double normSquared = bg::dot_product(n1, n1);
  if (normSquared > 0)
  {
    bg::multiply_value(n1, 1.0/sqrt(normSquared));
  }
  // sum signed areas of triangles
  double result = 0.0;
  for (size_t i=1; i<polygon.size(); ++i)
  {
    bg::model::segment<point3d> v1(polygon[0], polygon[i-1]);
    bg::model::segment<point3d> v2(polygon[0], polygon[i]);

    result += bg::dot_product(cross_product(v1, v2), n1);
  }
  result *= 0.5;
  return abs(result);
}

答案 1 :(得分:1)

我不熟悉boost的几何部分,但凭借我对几何学的了解,我可以说3D在3D方面没有太大差别。虽然可能已经有了一些提升,但您可以编写自己的方法来轻松完成这项工作。

编辑:

da code monkey指出shoelace formula以这种方式会更有效率,因为它不那么复杂,而且速度更快。

以下原创意见:


为了计算这个,我首先将多边形镶嵌成三角形,因为任何多边形都可以分割成许多三角形。我将采用这些三角形中的每一个,并计算每个三角形的面积。要在3d空间中执行此操作,相同的概念适用。为了得到基数,你取△ABC并任意指定-AB作为基数,-BC作为高度,-CA作为斜边。做(-AB * -BC)/ 2。只需将每个三角形的区域相加即可。

我不知道boost是否有内置的tessellate方法,这在c ++中实现起来相当困难,但你可能想要创建某种三角形扇形。 (注意:这仅适用于凸多边形)。如果你有一个凹多边形,你应该看看这个:http://www.cs.unc.edu/~dm/CODE/GEM/chapter.html我将把它放到c ++作为练习,但过程相当简单。