C++ CGAL构造球面多面体
我是CGAL新手,目前需要使用CGAL计算球面多面体面积。然而,我停留在第一步,即从球体点构造球体多面体。这是我的密码C++ CGAL构造球面多面体,c++,cgal,C++,Cgal,我是CGAL新手,目前需要使用CGAL计算球面多面体面积。然而,我停留在第一步,即从球体点构造球体多面体。这是我的密码 typedef CGAL::Simple_笛卡尔K; typedef CGAL::Nef_多面体\ u S2 Nef_多面体; typedef Nef_多面体::球体点球体点; typedef Nef_多面体::球体_段球体_段; typedef Nef_多面体::SVertex_const_迭代器SVertex_const_迭代器; 球面点p1(1,0,0),p2(0,0,1
typedef CGAL::Simple_笛卡尔K;
typedef CGAL::Nef_多面体\ u S2 Nef_多面体;
typedef Nef_多面体::球体点球体点;
typedef Nef_多面体::球体_段球体_段;
typedef Nef_多面体::SVertex_const_迭代器SVertex_const_迭代器;
球面点p1(1,0,0),p2(0,0,1),p3(1,-1,0);
球面_段s1(p1,p2),s2(p2,p3),s3(p3,p1);
std::向量tri({s1,s2,s3});
Nef_多面体S(tri.begin(),tri.end());
int i=0;
for(SVertex_const_iterator it=S.svertices_begin();it!=S.svertices_end();++it)
{
Sphere_point p=it->point();
std::cout创建一个包含三段的球形多边形后,您将得到六个顶点,因为您不仅探索多边形,还探索整个多边形,将球体划分为多个面。每个面都由一个外半边圈(在最简单的情况下)限定,它可以包含孔,也可以由半边的循环限定。下面的代码显示了如何逐个探索此类分区的面:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <CGAL/Exact_rational.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Nef_polyhedron_S2.h>
using Kernel = CGAL::Simple_cartesian<CGAL::Exact_rational>;
using SPolygon = CGAL::Nef_polyhedron_S2<Kernel>;
using SPoint = SPolygon::Sphere_point;
using SSegment = SPolygon::Sphere_segment;
using std::cout;
using std::endl;
std::string pointAsString(const SPoint& P)
{
std::stringstream ss;
ss << "(" << P.x() << "," << P.y() << "," << P.z() << ")";
return ss.str();
}
std::string halfEdgeCycleAsString(const SPolygon::SHalfedge_const_iterator HEIT)
{
std::stringstream ss;
auto heit = HEIT;
while (true)
{
ss << pointAsString(heit->source()->point()) << " => " << pointAsString(heit->target()->point());
heit = heit->snext();
if (heit != HEIT)
{
ss << ", ";
}
else
{
break;
}
}
return ss.str();
}
void printFaces(const SPolygon& P)
{
unsigned i = 0;
for (auto fit = P.sfaces_begin(); fit != P.sfaces_end(); ++fit)
{
cout << "face #" << i++ << ":" << endl;
for (auto fcit = fit->sface_cycles_begin(); fcit != fit->sface_cycles_end(); ++fcit)
{
cout << " face boundary:" << endl;
if (fcit.is_svertex())
{
const SPolygon::SVertex_const_handle vit = fcit;
cout << " vertex " << pointAsString(vit->point()) << endl;
}
else if (fcit.is_shalfedge())
{
const SPolygon::SHalfedge_const_handle heit = fcit;
cout << " halfedge cycle [" << halfEdgeCycleAsString(heit) << "]" << endl;
}
else if (fcit.is_shalfloop())
{
const SPolygon::SHalfloop_const_handle hlit = fcit;
cout << " halfloop (" << hlit->circle() << ")" << endl;
}
}
}
}
int main()
{
const SPoint p1(1, 0, 0), p2(0, 0, 1), p3(1, -1, 0);
const std::vector<SSegment> v{{p1, p2}, {p2, p3}, {p3, p1}};
const SPolygon p(v.cbegin(), v.cend());
p.print_statistics();
printFaces(p);
}
代码中的另一个问题-您不应该在Simple_cartesian
内核中使用double
数字,因为此内核需要有理数,支持精确计算。此外,如果您有非整数输入数据,则需要将其转换为有理数:
SPoint p(1, 0, CGAL::Exact_rational(119, 31));
如果在此处使用119/31
,则此z坐标将四舍五入为3
更新。您只能遍历DCEL的一部分,这对您很重要-例如,您创建的多边形的所有边。一种方法如下:
int main()
{
const SPoint p1(1, 0, 0), p2(0, 0, 1), p3(1, -1, 0);
const std::vector<SSegment> v{{p1, p2}, {p2, p3}, {p3, p1}};
const SPolygon p(v.cbegin(), v.cend());
// ------ locate the starting vertex of this polygon and output its halfedge cycle
const auto h = p.locate(p1);
SPolygon::SVertex_const_handle vh = nullptr;
if (CGAL::assign(vh, h))
{
cout << halfEdgeCycleAsString(vh->out_sedge()) << endl;
}
else
{
cout << "Vertex is not found" << endl;
}
}
intmain()
{
常数点p1(1,0,0),p2(0,0,1),p3(1,-1,0);
常数std::向量v{p1,p2},{p2,p3},{p3,p1};
康斯特·斯波利贡(v.cbegin(),v.cend());
//------定位此多边形的起始顶点并输出其半边循环
常数自动h=p.locate(p1);
SPolygon::SVertex_const_handle vh=nullptr;
如果(CGAL::分配(vh,h))
{
cout out_sedge())创建一个包含三段的球形多边形后,您将得到六个顶点,因为您不仅探索多边形,还探索整个多边形,将球体划分为多个面。每个面都由一个外半边圈(在最简单的情况下)限定,它可以包含孔,也可以由半边的循环限定。下面的代码显示了如何逐个探索此类分区的面:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <CGAL/Exact_rational.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Nef_polyhedron_S2.h>
using Kernel = CGAL::Simple_cartesian<CGAL::Exact_rational>;
using SPolygon = CGAL::Nef_polyhedron_S2<Kernel>;
using SPoint = SPolygon::Sphere_point;
using SSegment = SPolygon::Sphere_segment;
using std::cout;
using std::endl;
std::string pointAsString(const SPoint& P)
{
std::stringstream ss;
ss << "(" << P.x() << "," << P.y() << "," << P.z() << ")";
return ss.str();
}
std::string halfEdgeCycleAsString(const SPolygon::SHalfedge_const_iterator HEIT)
{
std::stringstream ss;
auto heit = HEIT;
while (true)
{
ss << pointAsString(heit->source()->point()) << " => " << pointAsString(heit->target()->point());
heit = heit->snext();
if (heit != HEIT)
{
ss << ", ";
}
else
{
break;
}
}
return ss.str();
}
void printFaces(const SPolygon& P)
{
unsigned i = 0;
for (auto fit = P.sfaces_begin(); fit != P.sfaces_end(); ++fit)
{
cout << "face #" << i++ << ":" << endl;
for (auto fcit = fit->sface_cycles_begin(); fcit != fit->sface_cycles_end(); ++fcit)
{
cout << " face boundary:" << endl;
if (fcit.is_svertex())
{
const SPolygon::SVertex_const_handle vit = fcit;
cout << " vertex " << pointAsString(vit->point()) << endl;
}
else if (fcit.is_shalfedge())
{
const SPolygon::SHalfedge_const_handle heit = fcit;
cout << " halfedge cycle [" << halfEdgeCycleAsString(heit) << "]" << endl;
}
else if (fcit.is_shalfloop())
{
const SPolygon::SHalfloop_const_handle hlit = fcit;
cout << " halfloop (" << hlit->circle() << ")" << endl;
}
}
}
}
int main()
{
const SPoint p1(1, 0, 0), p2(0, 0, 1), p3(1, -1, 0);
const std::vector<SSegment> v{{p1, p2}, {p2, p3}, {p3, p1}};
const SPolygon p(v.cbegin(), v.cend());
p.print_statistics();
printFaces(p);
}
代码中的另一个问题-您不应该在Simple_cartesian
内核中使用double
数字,因为此内核需要有理数,支持精确计算。此外,如果您有非整数输入数据,则需要将其转换为有理数:
SPoint p(1, 0, CGAL::Exact_rational(119, 31));
如果在此处使用119/31
,则此z坐标将四舍五入为3
更新。您只能遍历DCEL的一部分,这对您很重要-例如,您创建的多边形的所有边。一种方法如下:
int main()
{
const SPoint p1(1, 0, 0), p2(0, 0, 1), p3(1, -1, 0);
const std::vector<SSegment> v{{p1, p2}, {p2, p3}, {p3, p1}};
const SPolygon p(v.cbegin(), v.cend());
// ------ locate the starting vertex of this polygon and output its halfedge cycle
const auto h = p.locate(p1);
SPolygon::SVertex_const_handle vh = nullptr;
if (CGAL::assign(vh, h))
{
cout << halfEdgeCycleAsString(vh->out_sedge()) << endl;
}
else
{
cout << "Vertex is not found" << endl;
}
}
intmain()
{
常数点p1(1,0,0),p2(0,0,1),p3(1,-1,0);
常数std::向量v{p1,p2},{p2,p3},{p3,p1};
康斯特·斯波利贡(v.cbegin(),v.cend());
//------定位此多边形的起始顶点并输出其半边循环
常数自动h=p.locate(p1);
SPolygon::SVertex_const_handle vh=nullptr;
如果(CGAL::分配(vh,h))
{
cout out_sedge())谢谢你的回答,内容非常丰富。我还有两个简单的问题。1)我能从球体多面体的边界(可能是定向的)构造球体多面体吗分段?因为这里我不需要整个曲面的分区。2)对于类型为Exact\u rational
的内核,我可以使用to\u rational
将双倍数转换为有理类型吗?@yang-当你创建一个球形多边形时,你会创建一个相应的DCEL,它定义了一个分区。所以像SVertex\u const\u这样的迭代器可以erator
将迭代此分区。但是,您可以忽略此分区,只迭代您刚刚创建的多边形-使用函数locate
查找包含多边形第一个点的DCEL对象,将此对象转换为顶点控制柄,并使用out\u sedge
函数查找t他是你的前半身polygon@yang-至于to_rational
函数-是的,您可以使用它。但是精确的\u rational
构造函数可以将双精度转换为有理数-看起来simpler@yang-请查看我的更新谢谢你的回复,内容非常丰富。我还有两个简短的问题。1)我可以构建仅从其边界开始的球面多面体(可能是定向的)分段?因为这里我不需要整个曲面的分区。2)对于类型为Exact\u rational
的内核,我可以使用to\u rational
将双倍数转换为有理类型吗?@yang-当你创建一个球形多边形时,你会创建一个相应的DCEL,它定义了一个分区。所以像SVertex\u const\u这样的迭代器可以erator
将迭代此分区。但是,您可以忽略此分区,只迭代您刚刚创建的多边形-使用函数locate
查找包含多边形第一个点的DCEL对象,将此对象转换为顶点控制柄,并使用out\u sedge
函数查找t他是你的前半身polygon@yang-至于to_rational
函数-是的,您可以使用它。但是精确的\u rational
构造函数可以将双精度转换为有理数-看起来simpler@yang-请查看我的更新
SPoint p(1, 0, CGAL::Exact_rational(119, 31));
int main()
{
const SPoint p1(1, 0, 0), p2(0, 0, 1), p3(1, -1, 0);
const std::vector<SSegment> v{{p1, p2}, {p2, p3}, {p3, p1}};
const SPolygon p(v.cbegin(), v.cend());
// ------ locate the starting vertex of this polygon and output its halfedge cycle
const auto h = p.locate(p1);
SPolygon::SVertex_const_handle vh = nullptr;
if (CGAL::assign(vh, h))
{
cout << halfEdgeCycleAsString(vh->out_sedge()) << endl;
}
else
{
cout << "Vertex is not found" << endl;
}
}