输入点
p
1
p_1
p1,
p
2
p_2
p2,
p
3
p_3
p3,
p
4
p_4
p4,最小容差dSmallestDisTol,距离容差dDisTol
输出vector<Point>
- 构造线段 l 1 = ( p 1 , p 2 ) l_1 =(p_1,p_2) l1=(p1,p2), l 2 = ( p 3 , p 4 ) l_2 =(p_3,p_4) l2=(p3,p4), l 1 l_1 l1所在直线 L 1 L1 L1, l 2 l_2 l2所在直线 L 2 L2 L2
- 计算 l 1 , l 2 l_1, l_2 l1,l2的距离dis (dis = Distance( l 1 l_1 l1, l 2 l_2 l2))
- 如果dis>dDisTOl 没有交点,返回
- 判断线段 l 1 , l 2 l_1,l_2 l1,l2是否平行
- 计算线段 l 1 l_1 l1上的两点到直线 L 2 L_2 L2的距离差d0 = fabs(Distance( p 0 p_0 p0, L 2 L_2 L2) - Distance( p 1 p_1 p1, L 2 L_2 L2) )
- 计算线段 l 2 l_2 l2上的两点到直线 L 1 L_1 L1的距离差d1 = fabs(Distance( p 2 p_2 p2, L 1 L_1 L1) - Distance( p 3 p_3 p3, L 1 L_1 L1) )
- d0<dDisTol且d1<dDisTol则平行
- 平行跳到11;不平行,使用CGAL计算 l 1 , l 2 l_1,l_2 l1,l2的交点,
- 如果存在交点 p 0 p_0 p0,返回
- 不存在,计算 l 1 , l 2 l_1,l_2 l1,l2的最近点对 p n t N s t 0 , p n t N s t 1 pntNst_0,pntNst_1 pntNst0,pntNst1
pair<Point_3, Point_3> GetNearstPnt(Segment_3 segA, Segment_3 segB)
{
Vector_3 u = segA.to_vector();
Vector_3 v = segB.to_vector();
Vector_3 w = segA.source() - segB.source();
double a = CGAL::to_double(u * u), b = CGAL::to_double(u * v), c = CGAL::to_double(v * v), d = CGAL::to_double(u * w), e = CGAL::to_double(v * w);
double dt = a * c - b * b;
double sd = dt, td = dt, sn = 0.0, tn = 0.0;
Point_3 pntClose[2];
if (fabs(dt) < 1e-6)
{
//两直线平行
sn = 0.0; //在s上指定取s0
sd = 1.00; //防止计算时除0错误
tn = e; //按(公式3)求tc
td = c;
}
else
{
sn = (b * e - c * d);
tn = (a * e - b * d);
if (sn < 0.0)
{
//最近点在s起点以外,同平行条件
sn = 0.0;
tn = e;
td = c;
}
else if (sn > sd)
{
//最近点在s终点以外(即sc>1,则取sc=1)
sn = sd;
tn = e + b; //按(公式3)计算
td = c;
}
}
if (tn < 0.0)
{
//最近点在t起点以外
tn = 0.0;
if (-d < 0.0) //按(公式2)计算,如果等号右边小于0,则sc也小于零,取sc=0
sn = 0.0;
else if (-d > a) //按(公式2)计算,如果sc大于1,取sc=1
sn = sd;
else
{
sn = -d;
sd = a;
}
}
else if (tn > td)
{
tn = td;
if ((-d + b) < 0.0)
sn = 0.0;
else if ((-d + b) > a)
sn = sd;
else
{
sn = (-d + b);
sd = a;
}
}
double sc = 0.0;
double tc = 0.0;
if (fabs(sn) < 1e-6)
sc = 0.0;
else
sc = sn / sd;
if (fabs(tn) < 1e-6)
tc = 0.0;
else
tc = tn / td;
pntClose[0] = segA.source() + sc * u;
pntClose[1] = segB.source() + tc * v;
return make_pair(pntClose[0], pntClose[1]);
}
- 判断点 p n t N s t 0 pntNst_0 pntNst0是否在 l 1 l_1 l1, p n t N s t 1 pntNst_1 pntNst1是否在 l 2 l_2 l2,判断函数如下
double GetPntScaleInSeg(const Segment_3& seg, Point_3 pnt)
{
Vector_3 dir = seg.target() - seg.source();
int inxMax = fabs(dir[0]) > fabs(dir[1]) ? 0 : 1; inxMax = fabs(dir[inxMax]) > fabs(dir[2]) ? inxMax : 2;
return CGAL::to_double((pnt - seg.source())[inxMax]) / CGAL::to_double(dir[inxMax]);
}
bool IsPntInSeg(const Segment_3& seg, Point_3 pnt, double dTol)
{
bool ret = true;
if (VeLength(pnt - seg.source()) < dTol) return true;
if (VeLength(pnt - seg.target()) < dTol) return true;
double dDot = VeNormalTo(pnt - seg.source()) * VeNormalTo(pnt - seg.target());
if (fabs(fabs(dDot) - 1) < dTol)
{
double dScale = GetPntScaleInSeg(seg, pnt);
//判断交点是不是比较远,如果远,计算最近点对
if (!(dScale <= 1 + dTol && dScale > -dTol))
{
ret = false;
}
}
return ret;
}
- 如果满足条件8,则交点为 ( p n t N s t 0 + p n t N s t 1 ) / 2 (pntNst_0+pntNst_1)/2 (pntNst0+pntNst1)/2
- 否则判断为平行,跳到11
- 由于平行线之间距离<dDisTol所以肯定存在交点,对于
l
1
l_1
l1上的2个点
p
1
,
p
2
p_1,p_2
p1,p2
在 l 2 l_2 l2的投影点 p 12 , p 22 是 否 在 线 段 l 2 上 p_{12},p_{22}是否在线段l_2上 p12,p22是否在线段l2上,如果在加入点 p i p_i pi,同理 l 2 l_2 l2
d 1 ⃗ = l 1 l 2 → / ∣ l 1 l 2 ∣ \vec{d_1} = \overrightarrow{l_1l_2}/|l_1l_2| d1=l1l2/∣l1l2∣,
d 2 ⃗ = l 1 l 2 → / ∣ l 1 l 2 ∣ \vec{d_2} = \overrightarrow{l_1l_2}/|l_1l_2| d2=l1l2/∣l1l2∣
d s 1 = ( l 1 . s o u r c e ( ) − l 2 . s o u r c e ( ) ) ∗ d 2 ⃗ ds1=(l_1.source() - l_2.source())*\vec{d_2} ds1=(l1.source()−l2.source())∗d2
d s 2 = ( l 2 . s o u r c e ( ) − l 1 . s o u r c e ( ) ) ∗ d 1 ⃗ ds2=(l_2.source() - l_1.source())*\vec{d_1} ds2=(l2.source()−l1.source())∗d1
d e 1 = ( l 1 . e n d ( ) − l 2 . e n d ( ) ) ∗ d 2 ⃗ de1=(l_1.end() - l_2.end())*\vec{d_2} de1=(l1.end()−l2.end())∗d2
d e 2 = ( l 2 . e n d ( ) − l 1 . e n d ( ) ) ∗ d 1 ⃗ de2=(l_2.end() - l_1.end())*\vec{d_1} de2=(l2.end()−l1.end())∗d1
if d s 1 > 0 且 d s 1 < ∣ l 2 ∣ + d S m a l l e s t D i s T o l ds1>0 且ds1<|l_2|+ dSmallestDisTol ds1>0且ds1<∣l2∣+dSmallestDisTol 添加 p 1 p_1 p1
if d s 2 > 0 且 d s 2 < ∣ l 1 ∣ + d S m a l l e s t D i s T o l ds2>0 且ds2<|l_1|+ dSmallestDisTol ds2>0且ds2<∣l1∣+dSmallestDisTol 添加 p 3 p_3 p3
if d e 1 > 0 且 d e 1 < ∣ l 2 ∣ + d S m a l l e s t D i s T o l de1>0 且de1<|l_2|+ dSmallestDisTol de1>0且de1<∣l2∣+dSmallestDisTol 添加 p 2 p_2 p2
if d e 2 > 0 且 d e 2 < ∣ l 1 ∣ + d S m a l l e s t D i s T o l de2>0 且de2<|l_1|+ dSmallestDisTol de2>0且de2<∣l1∣+dSmallestDisTol 添加 p 4 p_4 p4