• 【几何图形学算法学习笔记一】三维空间线段相交,求交点


    原创文章,转载请注明出处!

    第一步:计算三维空间内两条弧段的距离d,

    We first consider two infinite lines L1: P(s) = P0 + s (P1-P0) = P0 + su and L2: Q(t) = Q0 + t (Q1-Q0) = Q0 + tv.  Let w(s,t) = P(s)-Q(t) be a vector between points on the two lines.  We want to find the w(s,t) that has a minimum length for all s and t.  This can be computed using calculus [Eberly, 2001].  Here, we use a more geometric approach, and end up with the same result as he does.  A similar geometric approach was used by [Teller, 2000], but he uses a cross product which restricts his method to 3D space whereas the method we use works in any dimension.  Also, the solution given here and by Eberly are faster than Teller's which computes intermediate planes and gets their intersections with the two lines.

    In any n-dimensional space, the two lines L1 and L2 are closest at unique points P(sc) and Q(tc) for which w(sc,tc) attains its minimum length.  Also, if L1 and L2 are not parallel, then the line segment P(sc)Q(tc) joining the closest points is uniquely perpendicular to both lines at the same time.  No other segment between L1 and L2 has this property.  That is, the vector wc = w(sc,tc) is uniquely perpendicular to the line direction vectors u and v, and this is equivalent to it satisfying the two equations: u · wc = 0 and v · wc = 0.

    We can solve these two equations by substituting wc = P(sc)-Q(tc) = w0 + scu- tcv, where w0 = P0-Q0, into each one to get two simultaneous linear equations:

    Then, letting a = u · u, b = u · v, c = v · v, d = u · w0, and e = v · w0, we solve for sc and tc as:

    whenever the denominator ac-b2  is nonzero.  Note that ac-b2 = |u|2|v|2-(|u||v|cos q)2 = (|u||v|sin q)2 >=0 is always nonnegative.  When ac-b2 = 0, the two equations are dependant, the two lines are parallel, and the distance between the lines is constant.  We can solve for this parallel distance of separation by fixing the value of one parameter and using either equation to solve for the other.  Selecting sc= 0, we get tc = d / b = e / c.

    Having solved for sc and tc, we have the points P(sc) and Q(tc) where the two lines L1 and L2 are closest.  Then the distance between them is given by:

     

    第二步:如果d<0.000000001,相交

    第三步:在XOY平面计算相交点。

    在XOY平面内投影线的交点为0时不考虑(考虑在XOZ平面或者YOZ平面相交);

    交点为1时计算交点,根据交点的位置将x,y坐标代入框架坐标向量,求的Z值作为相交点的Z值;

    返回值为2时情况暂不考虑。

    View Code
     1 // dist3D_Segment_to_Segment():
    2 // Input: two 3D line segments S1 and S2
    3 // Return: the shortest distance between S1 and S2
    4 float

    5 dist3D_Segment_to_Segment( Segment S1, Segment S2)
    6 {
    7 Vector u = S1.P1 - S1.P0;
    8 Vector v = S2.P1 - S2.P0;
    9 Vector w = S1.P0 - S2.P0;
    10 float a = dot(u,u); // always >= 0
    11 float b = dot(u,v);

    12 float c = dot(v,v); // always >= 0
    13 float d = dot(u,w);

    14 float e = dot(v,w);
    15 float D = a*c - b*b; // always >= 0
    16 float sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
    17 float tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
    18
    19 // compute the line parameters of the two closest points
    20 if (D < SMALL_NUM) { // the lines are almost parallel
    21 sN = 0.0; // force using point P0 on segment S1
    22 sD = 1.0; // to prevent possible division by 0.0 later
    23 tN = e;

    24 tD = c;
    25 }
    26 else { // get the closest points on the infinite lines
    27 sN = (b*e - c*d);

    28 tN = (a*e - b*d);
    29 if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
    30 sN = 0.0;

    31 tN = e;
    32 tD = c;
    33 }
    34 else if (sN > sD) { // sc > 1 => the s=1 edge is visible
    35 sN = sD;

    36 tN = e + b;
    37 tD = c;
    38 }
    39 }
    40
    41 if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
    42 tN = 0.0;

    43 // recompute sc for this edge
    44 if (-d < 0.0)

    45 sN = 0.0;
    46 else if (-d > a)
    47 sN = sD;
    48 else {
    49 sN = -d;
    50 sD = a;
    51 }
    52 }
    53 else if (tN > tD) { // tc > 1 => the t=1 edge is visible
    54 tN = tD;

    55 // recompute sc for this edge
    56 if ((-d + b) < 0.0)

    57 sN = 0;
    58 else if ((-d + b) > a)
    59 sN = sD;
    60 else {
    61 sN = (-d + b);
    62 sD = a;
    63 }
    64 }
    65 // finally do the division to get sc and tc
    66 sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD);

    67 tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD);
    68
    69 // get the difference of the two closest points
    70 Vector dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
    71

    72 return norm(dP); // return the closest distance
    73 }
    View Code
     1 #define SMALL_NUM  0.00000001 // anything that avoids division overflow
    
    2 // dot product (3D) which allows vector operations in arguments
    3 #define dot(u,v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)

    4 #define perp(u,v) ((u).x * (v).y - (u).y * (v).x) // perp product (2D)
    5
    6
    7 // intersect2D_2Segments(): the intersection of 2 finite 2D segments
    8 // Input: two finite segments S1 and S2
    9 // Output: *I0 = intersect point (when it exists)
    10 // *I1 = endpoint of intersect segment [I0,I1] (when it exists)
    11 // Return: 0=disjoint (no intersect)
    12 // 1=intersect in unique point I0
    13 // 2=overlap in segment from I0 to I1
    14 int

    15 intersect2D_Segments( Segment S1, Segment S2, Point* I0, Point* I1 )
    16 {
    17 Vector u = S1.P1 - S1.P0;
    18 Vector v = S2.P1 - S2.P0;
    19 Vector w = S1.P0 - S2.P0;
    20 float D = perp(u,v);
    21
    22 // test if they are parallel (includes either being a point)
    23 if (fabs(D) < SMALL_NUM) { // S1 and S2 are parallel
    24 if (perp(u,w) != 0 || perp(v,w) != 0) {

    25 return 0; // they are NOT collinear
    26 }

    27 // they are collinear or degenerate
    28 // check if they are degenerate points
    29 float du = dot(u,u);

    30 float dv = dot(v,v);
    31 if (du==0 && dv==0) { // both segments are points
    32 if (S1.P0 != S2.P0) // they are distinct points
    33 return 0;

    34 *I0 = S1.P0; // they are the same point
    35 return 1;

    36 }
    37 if (du==0) { // S1 is a single point
    38 if (inSegment(S1.P0, S2) == 0) // but is not in S2
    39 return 0;

    40 *I0 = S1.P0;
    41 return 1;
    42 }
    43 if (dv==0) { // S2 a single point
    44 if (inSegment(S2.P0, S1) == 0) // but is not in S1
    45 return 0;

    46 *I0 = S2.P0;
    47 return 1;
    48 }
    49 // they are collinear segments - get overlap (or not)
    50 float t0, t1; // endpoints of S1 in eqn for S2
    51 Vector w2 = S1.P1 - S2.P0;

    52 if (v.x != 0) {
    53 t0 = w.x / v.x;
    54 t1 = w2.x / v.x;
    55 }
    56 else {
    57 t0 = w.y / v.y;
    58 t1 = w2.y / v.y;
    59 }
    60 if (t0 > t1) { // must have t0 smaller than t1
    61 float t=t0; t0=t1; t1=t; // swap if not
    62 }

    63 if (t0 > 1 || t1 < 0) {
    64 return 0; // NO overlap
    65 }

    66 t0 = t0<0? 0 : t0; // clip to min 0
    67 t1 = t1>1? 1 : t1; // clip to max 1
    68 if (t0 == t1) { // intersect is a point
    69 *I0 = S2.P0 + t0 * v;

    70 return 1;
    71 }
    72
    73 // they overlap in a valid subsegment
    74 *I0 = S2.P0 + t0 * v;

    75 *I1 = S2.P0 + t1 * v;
    76 return 2;
    77 }
    78
    79 // the segments are skew and may intersect in a point
    80 // get the intersect parameter for S1
    81 float sI = perp(v,w) / D;

    82 if (sI < 0 || sI > 1) // no intersect with S1
    83 return 0;

    84
    85 // get the intersect parameter for S2
    86 float tI = perp(u,w) / D;

    87 if (tI < 0 || tI > 1) // no intersect with S2
    88 return 0;

    89
    90 *I0 = S1.P0 + sI * u; // compute S1 intersect point
    91 return 1;

    92 }

     

    参考文献:http://softsurfer.com/algorithms.htm

    http://geomalgorithms.com/a07-_distance.html

     

    文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。 欢迎大家留言交流,转载请注明出处。
  • 相关阅读:
    Java 面向对象(二)封装
    Java 面向对象(一)面向对象思想
    Java 字符串(二)字符串常用操作
    Java 字符串(一)字符串初始化
    JavaScript 流程控制(二)循环结构
    【剑指Offer-知识迁移能力】面试题58:翻转单词顺序
    【剑指Offer-知识迁移能力】面试题57.2:和为s的连续整数序列
    【剑指Offer-知识迁移能力】面试题57:合为s的两个数字
    【剑指Offer-知识迁移能力】面试题56:数组中只出现一次的两个数字
    【剑指Offer-知识迁移能力】面试题55.2:平衡二叉树
  • 原文地址:https://www.cnblogs.com/yhlx125/p/2299532.html
Copyright © 2020-2023  润新知