C++ 几何-在三维空间中找到二维多边形的区域?

C++ 几何-在三维空间中找到二维多边形的区域?,c++,area,boost-geometry,C++,Area,Boost Geometry,我试图得到三维空间中二维多边形的面积。有没有办法通过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做到这一点?这是我的实现,但它始终返回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:看起来像是在
boost::geometry
中的面积计算,仅适用于二维多边形。

我不熟悉boost的geometry部分,但根据我的几何知识,我可以说3D与2D没有太大区别。尽管boost中可能已经有了一些东西,但是您可以编写自己的方法来相当轻松地实现这一点

编辑:

da code monkey指出,通过这种方式,系统将更加高效,因为它不那么复杂,而且速度更快

原意如下:


为了计算这一点,我首先将多边形细分为三角形,因为任何多边形都可以拆分为多个三角形。我会取每个三角形,计算每个三角形的面积。要在3d空间中实现这一点,同样的概念也适用。要得到基地,你需要△ABC和任意指定-AB为基数,-BC为高度,-CA为斜边。只要做(-AB*-BC)/2。把每个三角形的面积加起来


我不知道Boost是否有内置的Testelalt方法,这将在C++中实现相当困难,但您可能希望创建某种类型的三角形扇形。(注意:这仅适用于凸多边形)。如果你有一个凹多边形,你应该看看这个:我会把这个放进C++中作为一个练习,但是这个过程相当简单。

< p>我不希望一个点的集合有一个区域。您将需要与
model::polygon
等效的模型,但目前似乎不支持该模型

如果点保证共面且线段不相交,则可以将多边形分解为一系列三角形,并根据三角形面积的以下公式,使用少量线性代数计算面积:

对于非凸多边形,需要调整面积之和以减去多边形外部的面积。实现这一点的最简单方法是使用三角形的有符号区域,包括右侧三角形的正贡献和左侧三角形的负贡献:

请注意,似乎有一些计划在Boost中包含一个
cross_产品
实现,但它似乎从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);
}
point3d交叉乘积(const point3d&p1、const point3d&p2)
{
双x=bg::get(p1);
双y=bg::get(p1);
双z=bg::get(p1);
双u=bg::get(p2);
双v=bg::get(p2);
双w=bg::get(p2);
返回点3D(y*w-z*v,z*u-x*w,x*v-y*u);
}
point3d交叉产品(常量背景::模型::段和p1
,const bg::model::段和p2)
{
点3D v1(p1.秒);
点3D v2(p2.秒);
bg::减去_点(v1,p1.第一);
bg::减去_点(v2,p2.第一);
返回叉积(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);
}
//计算被解释为三维多边形的三维点集合
//请注意,没有检查这些点是否正确
//确实是共面的。
双区域(背景::模型::多点和多边形)
{
if(polygon.size()0)
{
bg::乘以_值(n1,1.0/sqrt(normSquared));
}
//三角形的和符号面积
双结果=0.0;

对于(size_t i=1;i任何合理简单的三角剖分算法都需要n logN时间。我建议使用更简单的鞋带公式,它是线性的。我相信OP要求的是3D空间中的解决方案,而鞋带公式是2D空间中的多边形。有关3D空间的推广,请参阅(当点位于xy平面时,简化为鞋带公式)。我猜鞋带公式更适用于2d空间(尽管可能有3d变体),但我最初的想法仍然有效。你错过了交叉积和的最后一个术语,它需要从它开始的地方结束。@Mrigank我运行的测试给了我预期的结果。你有没有具体的测试用例不能产生正确的结果?
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);
}