Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 封闭Bezier曲线中的自相交检测_Java_Algorithm_Geometry_Bezier_Java 2d - Fatal编程技术网

Java 封闭Bezier曲线中的自相交检测

Java 封闭Bezier曲线中的自相交检测,java,algorithm,geometry,bezier,java-2d,Java,Algorithm,Geometry,Bezier,Java 2d,我通过将三次贝塞尔曲线拼接在一起创建了一个“水滴”形状(下面的屏幕截图)。我希望能够检测到一条曲线越过它自己或另一条曲线的情况,并且想知道是否有推荐的方法或已知的算法可以做到这一点 我的一个想法是使用展平路径迭代器将形状分解为直线段,然后检测给定段是否与另一段相交,但我感兴趣的是是否有更好的方法(因为这将具有二次性能)。如果我采用这种方法,Java中是否有库函数来检测两条线段是否重叠 谢谢 无交叉 交叉 您可以做的是将向量函数用于: 并将构成曲线的不同bezier曲线成对相等,以查看[0,1

我通过将三次贝塞尔曲线拼接在一起创建了一个“水滴”形状(下面的屏幕截图)。我希望能够检测到一条曲线越过它自己或另一条曲线的情况,并且想知道是否有推荐的方法或已知的算法可以做到这一点

我的一个想法是使用
展平路径迭代器
将形状分解为直线段,然后检测给定段是否与另一段相交,但我感兴趣的是是否有更好的方法(因为这将具有二次性能)。如果我采用这种方法,Java中是否有库函数来检测两条线段是否重叠

谢谢

无交叉

交叉


您可以做的是将向量函数用于:

并将构成曲线的不同bezier曲线成对相等,以查看[0,1]中是否有解决方案。当然,如果重叠的部分是不同曲线的一部分,这将有所帮助。在一条曲线与自身相交的情况下,它不会有帮助

编辑:

我引用了二次曲线函数,所以这是三次曲线:

这个方程确实很难求解。作为替代方案,我建议使用更宽松的方法。您可以将每条曲线“分割”为n个点,并使用上述函数计算其位置。然后,对于这些点中的每一个,你将考虑任意半径的圆盘(取决于曲线的大小),并搜索这些圆盘的交点。您将需要忽略顺序磁盘的交点,因为它们相交只是因为它们在单个曲线段上彼此太近


这种方法应该非常快,但如果选择了“错误”的参数(n大小和半径),则可能会失去准确性,但您可以进行实验。

我不确定这是否有帮助,但它类似于多边形渲染中的问题,在多边形渲染中,对于每个扫描线Y,都有一个(X,flag)值对数组,其中线与该扫描线相交

沿着形状中的每条曲线,并在其与每条扫描线Y相交的位置,记录(X,标志),其中,标志=1(如果向北),标志=1(如果向南)

如果在每一条扫描线上考虑X对的顺序,并且保持一个游标值的运行总和,那么如果曲线是顺时针的,两个X值的跨度之间的和将是正的,如果曲线是逆时针的,则是负的。 如果所有跨距均为+1或-1,则曲线不会与自身相交


编辑:这需要一段时间,扫描线的数量与图形交叉。然后,生成的数据结构可用于渲染图形。

我认为您可以通过

  • 使用
    flattingPathIterator
    获取近似水滴的多边形
  • 将多边形周围的路径划分为非减缩y的子路径(即,向下路径想象仅使用铅笔向下的笔划绘制多边形)
  • 协调向下走路径,仅将每个线段与y维度上至少重叠的线段进行比较
这非常简单,避免了您担心的O(n2)性能。对于您的平均基本斑点,如图中所示,只有两条向下的路径

通过在运行过程中保持向下路径的水平排序,您可以进一步减少比较的数量(可能是
树集


另一种只比较y维度上重叠的线段的方法是使用一个。

我实际上找到了一个工作解决方案,它使用内置的Java2D函数,速度非常快

只需用曲线创建一个Path2D,然后用Path2D创建一个区域并调用方法area.Isingular()

它是有效的。。。看看这个小例子

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D;

import javax.swing.JFrame;
import javax.swing.JPanel;



public class Test {
@SuppressWarnings("serial")
public static void main(String[] args) {
    JFrame f = new JFrame("Test");
    JPanel c = new JPanel() {
        Area a;
        Path2D p;
        {
            p = new Path2D.Double();
            p.append(new CubicCurve2D.Double(0, 0, 100, 0, 150, 50, 200, 100), true);
            p.append(new CubicCurve2D.Double(200, 100, 200, 150, 150,0, 50, 100), true);
            p.append(new CubicCurve2D.Double(100, 100, 100, 50, 50, 50, 0, 0), true);
            a = new Area(p);
            setPreferredSize(new Dimension(300, 300));
        }
        @Override
        protected void paintComponent(Graphics g) {
            g.setColor(Color.black);
            ((Graphics2D)g).fill(p);
            System.out.println(a.isSingular());
        }
    };
    f.setContentPane(c);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.pack();
    f.setVisible(true);
}
}

这里有一些递归算法,来自于


其中,
delta^2(b_i)
被定义为
b_{i+2}-2*b_{i+1}+b_i

这假设只有一个控制点。但问题中的每条曲线都有两个控制点,它们是三次Bézier曲线。找到十字路口显然被认为是困难的。解释了其中的一些困难,最后还包括一些可能有用的测试用例。谢谢Jason-这听起来是个不错的方法。我需要在每个动画帧上执行此测试,因此它需要快速(但可以是近似值)。我想知道,在决定是否运行更全面的测试之前,是否还有一个额外的“快速”测试可以运行(在运行完整的测试之前,与边界框碰撞测试类似)。
INTERSECT(b_0,...,b_m;c_0,...,c_n, EPSILON)
  if [min b_i, max b_i] AND [min c_i, max c_i] != EMPTY { // check bounding boxes
    if m*(m-1)*max||delta^2(b_i)|| > EPSILON) { // check flatness
      Calculate b'_0, ..., b'_2m over [0, 0.5, 1] with the deCasteljau algorithm;
      INTERSECT(b'_0,...,b'_m;c_0,...,c_n;EPSILON);
      INTERSECT(b'_m,...,b'_2m;c_0,...,c_n;EPSILON);
    }
  }
  else {
    if (n*n-1)*max||delta^2(c_i)|| > EPSILON then {
      Calculate c'_0, ..., c'_2m over [0, 0.5, 1] with the deCasteljau algorithm;
      INTERSECT(b_0,...,b_m;c'_0,...,c'_n;EPSILON);
      INTERSECT(b_0,...,b_m;c'_n,...,c'_2n;EPSILON);
    }
    else {
      Intersect line segments b_0b_m and c_0c_n;
    }
  }