0

我正在制作一个几何库,但我很困惑,计算一个段与另一个段的交集的函数的返回类型应该是什么。返回的值有时是一个点,有时是一个段(重叠情况),有时是一个空集。根据我的想法,可以有 3 种方法来解决这个问题,如下所示: 1. 返回一个联合(段,空,点) 2. 当交点是一个点并且两个点都为NAN 当交集为空集 3. 返回一个向量(空集为 0 个元素,pnt 为 1 个元素,段为 2 个元素)

请让我知道是否有任何替代方案以及每种设计的优缺点。此外,哪个设计应该是一个好的设计以及为什么。我有兴趣制作一个健壮的架构,它允许单管道,因此几乎不需要重写代码以及可扩展(在添加功能和处理所有边缘情况方面)

以下是我的参考代码(其返回类型为矢量)

vector<pnt> seg::inter(seg z){
vector<pnt> ans;
if(p1==p2){if(z.doesinter(p1)){ans.pb(p1);}}
else if(z.p1==z.p2){
if(doesinter(z.p1)) ans.pb(z.p1);}
else{
pnt p1p2=(p2-p1);
pnt q1=p1p2*pnt(0,1);
long double h1,h2;
if(abs((z.p2-z.p1).dot(q1))<=eps){
pnt r1((z.p1-p1)/(p2-p1)),r2((z.p2-p1)/(p2-p1));
if(abs(r1.y)<=eps){//colinear case
h1=r1.x;
h2=r2.x;
if(h1>h2)swap(h1,h2);
if(h2>=0&&h1<=1){//add eps
h1=max(0.0L,h1);h2=min(1.0L,h2);
ans.pb(p1+p1p2*h1);
if(doublecompare(h1,h2)==-1)ans.pb(p1+p1p2*h2);}}}
else{
h1 = ((p1-z.p1).dot(q1))/((z.p2-z.p1).dot(q1));
pnt q2 = (z.p2-z.p1)*pnt(0,1);
h2 = ((z.p1-p1).dot(q2))/((p2-p1).dot(q2));
if(h1+eps>=0&&h1-eps<=1&&h2+eps>=0&&h2-eps<=1) ans.pb(z.p1+(z.p2-z.p1)*h1);}}
return ans;}
4

3 回答 3

3

我的建议是创建一个专门的 Intersection 类来处理所有情况。然后,您可以返回该类的实例。在内部,该类可以具有例如矢量表示(如果相交是一个点,则具有相同的端点,如您所建议的),并且可以具有确定它实际上是哪种情况的方法(bool isIntersecting(),isSegment()等)。

对于更复杂的设计,您可以使这个 Intersection 类抽象,并为 NoIntersection、PointIntersection 和 SegmentIntersection 提供不同的内部数据表示的专门实现。

于 2010-11-16T12:11:35.097 回答
1

这个union“想法”很好,它自然地表达了所有的情况。但是,我建议不要union直接使用 C 语言,因为它是一种低级结构,会使您面临难以发现的错误。

相反,您应该使用Boost.Variant

基本上,一个变体是 2 个元素的组合:一个标签和一个标签union,该标签用于告诉联合体的哪个成员在给定时刻被使用。作为一个 C++ 类,它是 C++ 感知的(不像联合),因此您不会面临可以放入的对象类型的限制,也不会面临未定义的行为。

typedef boost::Variant<NoneType, Point, Segment> IntersectionType;

当然,您也可以决定将其包装在一个类中,以公开更丰富的接口。

于 2010-11-16T13:33:17.500 回答
0

在现代 C++ 设计中,Alexandrescu 以您的问题为例解释了多种方法。

你应该看看。

http://loki-lib.sourceforge.net/index.php?n=Idioms.MultipleDispatcher

于 2010-11-16T16:34:13.497 回答