线段相交(使用容差)

输入点 p 1 p_1 p1, p 2 p_2 p2, p 3 p_3 p3, p 4 p_4 p4,最小容差dSmallestDisTol,距离容差dDisTol
输出vector<Point>

  1. 构造线段 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
  2. 计算 l 1 , l 2 l_1, l_2 l1,l2的距离dis (dis = Distance( l 1 l_1 l1, l 2 l_2 l2))
  3. 如果dis>dDisTOl 没有交点,返回
  4. 判断线段 l 1 , l 2 l_1,l_2 l1l2是否平行
  1. 计算线段 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) )
  2. 计算线段 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) )
  3. d0<dDisTol且d1<dDisTol则平行
  1. 平行跳到11;不平行,使用CGAL计算 l 1 , l 2 l_1,l_2 l1,l2的交点,
  2. 如果存在交点 p 0 p_0 p0,返回
  3. 不存在,计算 l 1 , l 2 l_1,l_2 l1l2的最近点对 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]);
}
  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;
}

  1. 如果满足条件8,则交点为 ( p n t N s t 0 + p n t N s t 1 ) / 2 (pntNst_0+pntNst_1)/2 (pntNst0+pntNst1)/2
  2. 否则判断为平行,跳到11
  3. 由于平行线之间距离<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>0ds1<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>0ds2<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>0de1<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>0de2<l1+dSmallestDisTol 添加 p 4 p_4 p4
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值