我正在画布上绘制大量连接的边,所有这些边的排列方式都使这些边的某些特定扩展始终提供与另一个扩展边的交点。这一点需要进行进一步的计算-与画布上显示的内容无关。我的代码在一般情况下都很好用,但是如果边的相应扩展名太远,则交点并不总是存在(但是,线不平行)-至少不在此程序的范围内。有没有人有任何想法可以提高此代码的精度?稍后我实际上正在使用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));
  }
}

最佳答案

使用齐次坐标的投影几何是一种处理几乎平行甚至完全平行的线的好方法。这是速成课程:


平面中的点(x,y)将被均化为(x,y,1)。
的倍数表示同一点,因此您最好将其写为(2x,2y,2)。
线ax + by + c = 0表示为(a,b,c)。
当且仅当它们的点积p·g = ax + by + cz为零时,同构坐标p =(x,y,z)的点才位于g =(a,b,c)线上。 (您可能不需要这样做,因为比较带有双精度的相等性总是很棘手,但是它解释了其他步骤为何如此工作的原因。)
可以将连接两个点的线计算为其齐次坐标的叉积。
两条线之间的交点也可以计算为这些线的坐标的交叉曲线。
由于上述步骤总是相乘,因此如果您将其中几个结合使用,则双精度数可能会溢出。因此,不时调整向量的大小,例如将它们与某个标量相乘,以使它们具有最大绝对值的项变为1或任何其他值。
如果要在画布上绘制一个点(x,y,z),请计算(x / z,y / z)并绘制该点。
如果z = 0,则前一步是不可能的。这表示“无穷大”。
如果x = y = z = 0或a = b = c = 0,则矢量不代表点响应。一条线,而是退化的情况。例如。您试图计算与自身连接的线。


如您所见,这非常容易实现,而且更好:您在任何地方都不需要区分大小写!对于实际的绘图工作,您可能希望将线条与画布的边界相交,然后将连接这些相交处的线条用作图形基元的定义。

10-06 05:28
查看更多