线条几乎平行时的远距离交点

3
我正在画一张画布上的大量相连边,它们都以某种方式排列,以便这些边的特定扩展总是与另一个扩展边相交。这个点在进一步计算中是必需的 - 它在画布上不相关。我的代码对于一般情况运行良好,但是如果边的相应扩展超出范围,则交点并不总是存在(但是,线不平行)- 至少不在此程序的范围内。有人有什么想法来提高此代码的精度吗?我实际上稍后会使用BigDecimals,但是对于绘图步骤,我最初认为使用double就足够了。
这个将边延伸到两侧:
public Line2D.Double ExteLine(Point2D p, Point2D q){
   double slope, y3, y4;
   slope = (q.getY() - p.getY())/(q.getX() - p.getX());
   y3 = (slope * (100000 - p.getX())) + p.getY();
   y4 = (slope * (-100000 - p.getX())) + p.getY();
   Point2D out1 = new Point2D.Double(100000, y3);
   Point2D out2 = new Point2D.Double(-100000, y4);
   Line2D.Double line = new Line2D.Double(out1, out2);
   return line; }

这个函数找到两个集合的交集:
public Point2D.Double getIntersectionPoint(Line2D.Double line1, Line2D.Double line2) {
if (! line1.intersectsLine(line2)) { 
  System.out.println("No intersection"); 
  return null;} 
  double s1 = line1.getX1(),
        sp2 = line1.getY1(),
        rx = line1.getX2()-s1,
        ry = line1.getY2()-sp2;
  double qx = line2.getX1(),
        qy = line2.getY1(),
        sx = line2.getX2()-qx,
        sy = line2.getY2()-qy;
  double det = sx*ry - sy*rx;
  if (det == 0) { System.out.println("Det = 0");
    return null;} 
  else {
    double z = (sx*(qy-sp2)+sy*(s1-qx))/det;
    if (z==0 ||  z==1) return null;  
    return new Point2D.Double(
      (double)(s1+z*rx), (double)(sp2+z*ry));
  }
}

边缘是“真实”的线条吗?它们在两个方向上延伸到无限远,并且只是通过由Line2D.Doubles表示的线段,还是它们是具有明确起点和终点的线段,由Line2D.Doubles表示? - undefined
1
一个绝对不能依赖于两个通过不同方法计算得出的浮点数值相等(使用==判断)的情况。如果你必须使用浮点数,你必须在某个小的误差范围内进行比较。例如,使用if (abs(a-b) < 1.0E-6)而不是if(a==b) - undefined
@JimGarrison 这是一个很好的观点,也是我在后期使用的一种方法 - 但我不太清楚如何在这里加入它(或者是否可以使用除浮点数之外的其他东西)。 - undefined
@paulk23 它们并不无限延伸 - 实际上,我不知道它们可以这样。我想我可能需要使用不同类别的对象。 - undefined
1个回答

3
使用齐次坐标的投影几何是处理几乎平行或完全平行的线条的好方法。以下是一个快速入门:
  • 平面上的点(x,y)将被同质化为(x,y,1)。
  • 该点的倍数表示相同的点,因此您可以将其写为(2x,2y,2)。
  • ax + by + c = 0的直线表示为(a,b,c)。
  • 具有齐次坐标p =(x,y,z)的点仅当它们的点积p·g = ax + by + cz为零时才位于线g =(a,b,c)上。(您可能不需要这个,因为使用双精度数进行相等比较始终很棘手,但它解释了为什么其他步骤按照它们的方式工作。)
  • 连接两个点的线可以计算为它们的齐次坐标的叉积。
  • 两条线之间的交点也可以计算为这些线的坐标的叉积。
  • 由于上述步骤总是相乘,如果您组合其中几个,则您的双重数字可能会溢出。因此,定期重新缩放您的向量,例如将它们乘以某个标量,使其具有最大绝对值的条目变为1或其他。
  • 如果要在画布上绘制点(x,y,z),则计算(x / z,y / z)并绘制该点。
  • 如果z = 0,则无法完成上一步骤。这代表了一个“无限远”的点。
  • 如果x = y = z = 0或a = b = c = 0,则该向量不表示点或线,而是退化情况。例如,您尝试计算连接自身的点的线。
正如您所看到的,这很容易实现,而更好的是:您不需要任何情况区分!对于实际的绘图内容,您可能希望将线与画布边界相交,然后使用连接这些交点的线作为图形基元的定义。

我通过与不同的类一起工作,成功提高了精度,但我真的很喜欢这个想法,它实际上非常适合我正在做的事情,希望能够尽快实现它。 - undefined
我知道这可能是一个晚期的跟进,但在这种情况下,如何计算给定齐次坐标中四个共线点的交叉比?我首先需要用实射影线来识别它们吗? - undefined
@Denor: 通常情况下,你选择一个点 P,而不是位于四个点 A、B、C、D 所在直线上的点,然后计算 CR(A,B;C,D)=([ACP][BDP])/([ADP][BCP]),其中 [XYZ] 是平面中齐次坐标的行列式,即一个 3×3 行列式。但实际上,这更像是一个新的问题,最好在 http://math.stackexchange.com/ 上提问。毕竟,我的答案并没有使用交比。 - undefined
好的,对不起我超出了原来问题的范围。我找到了解决办法,并且我做了类似于你建议的事情。谢谢! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接