|
|
1
14
贝塞尔曲线的交集是由(非常酷)
Asymptote
矢量图形语言:查找
虽然他们没有解释他们在那里实际使用的算法,除了说它来自“元字体书”的第137页外,似乎它的关键是贝塞尔曲线的两个重要属性(在该网站的其他地方解释,尽管我现在找不到页面):
有了这两个属性和相交多边形的算法,您可以递归到任意精度: 贝辛特(B 一 ,B 二 ):
如果曲线不相交,这会很快——这是常见的情况吗? [编辑] 看起来把贝塞尔曲线一分为二的算法叫做 de Casteljau's algorithm . |
|
2
7
如果您是为生产代码做这个的,我建议使用贝塞尔裁剪算法。解释得很清楚 section 7.7 of this free online CAGD text (pdf),适用于任何程度的贝塞尔曲线,并且速度快且健壮。 虽然从数学的角度来看,使用标准的rootfinder或矩阵可能更简单,但是贝塞尔剪辑相对容易实现和调试,并且实际上具有更少的浮点误差。这是因为每当它创建新的数字时,它都会进行加权平均(凸组合),因此没有机会根据噪声输入进行外推。 |
|
|
3
3
你是根据附在第4条评论中的决定因素来解释的吗? this answer ?如果是这样,我相信这就是错误所在。在此处复制评论:
我看不出这部分有什么问题,但作者接着说:
我认为那不正确。两条曲线完全有可能在t值不同的位置相交,在这种情况下,即使矩阵具有非零行列式,也会有一个交点。我相信这就是你的案子。 |
|
|
4
2
我不知道有多快,但是如果你有两条曲线c1(t)和c2(k),它们相交,如果c1(t)==c2(k)。对于两个变量(t,k),有两个方程(每x和每y)。你可以用足够精确的数值方法来解这个系统。找到t,k参数后,应检查[0,1]上是否有参数。如果是,它们在[0,1]上相交。 |
|
|
5
2
我决不是这类事情的专家,但我喜欢 blog 那是关于曲线的。他有两篇关于你的问题的好文章的链接(第二个链接有一个交互式演示和一些源代码)。其他人可能对这个问题有更好的了解,但我希望这有帮助! |
|
6
2
这是个难题。我将把两条贝塞尔曲线中的每一条分割成5-10个离散的线段,然后做直线交叉。
|
|
|
7
0
我会说,最简单也可能最快的答案是将它们细分为非常小的线,并找到曲线相交的点(如果它们确实如此)。
很明显,蛮力的答案是不好的,看bo 4的答案,有很多线性几何和碰撞检测实际上会有很大帮助。 选择曲线所需的切片数。像100这样的应该很好。 我们取所有的段,并根据它们所拥有的y的最大值对它们进行排序。然后,在列表中为该段的最小值y添加第二个标志。 我们保留一个活动边的列表。 我们迭代Y排序的段列表,当我们遇到一个前导段时,我们将它添加到活动列表中。当我们点击小的Y标记值时,我们从活动列表中删除该段。 然后我们可以简单地用相当于一条扫描线的数据迭代整个段集,在简单地迭代列表时单调地增加y。我们迭代排序列表中的值,这通常会删除一个段并添加一个新段(或者对于拆分和合并节点,添加两个段或删除两个段)。从而保持相关段的活动列表。 当我们将一个新的活动段添加到活动段列表中时,只针对该段和当前活动段运行快速失败交叉检查。 因此,当我们在曲线的采样段中迭代时,我们始终确切地知道哪些线段是相关的。我们知道这些段在y坐标中共享重叠。我们可以快速失败任何新的部分不重叠的X坐标。在极少数情况下,它们在X坐标中重叠,然后我们检查这些段是否相交。 这可能会将线路交叉口检查的数量减少到基本上的交叉口数量。
checkAgInstactive()只需检查此段和活动列表中的任何段是否与它们的X坐标重叠,如果重叠,则运行行交叉检查,并采取适当的操作。 还要注意,这对于任何数量的曲线、任何类型的曲线、任何顺序的曲线、任何混合曲线都有效。如果我们遍历整个段列表,它会找到每个交叉点。它会发现一个贝塞尔曲线上的每一个点都与一个圆相交,或是一打二次贝塞尔曲线上的每一个相交点(或它们本身),并且都在同一个时间间隔内。 经常引用的 Chapter 7 document 注:对于细分算法: “一旦对一对曲线进行了足够的细分,每一条曲线都可以通过一个线段近似到公差范围内。” 我们可以跳过中间人。我们可以以足够快的速度来比较直线段和曲线的误差。最后,这就是典型的答案。 其次,请注意,在这里碰撞检测的速度增加的大部分,即根据要添加到活动列表中的最高Y和要从活动列表中删除的最低Y排序的分段列表,同样可以直接对贝塞尔曲线的外壳多边形进行。我们的直线段只是一个2级的多边形,但是我们可以做任何数量的点,就像琐碎一样,并检查所有控制点的边界框,不管我们处理的是什么样的曲线顺序。因此,我们将有一个活动的船体多边形点列表,而不是一个活动段列表。我们可以简单地使用de Casteljau的算法来分割曲线,从而作为细分曲线而不是直线段进行采样。因此,我们不需要2分,而是4分或7分或其他什么分数,并且运行相同的程序,很容易快速失败。 在最大Y处添加相关的点组,在最小Y处删除它,并仅比较活动列表。从而可以快速、更好地实现贝塞尔细分算法。通过简单地查找边界框重叠,然后细分那些重叠的曲线,并删除那些不重叠的曲线。同样,我们可以做任意数量的曲线,甚至是在前一次迭代中从曲线细分出来的曲线。像我们的分段近似法一样,快速求解数百条不同曲线(甚至不同阶数)之间的每个交叉点位置。只需检查所有曲线,看看边界框是否重叠,如果重叠,我们就细分这些曲线,直到我们的曲线足够小或用完它们为止。 |
|
|
8
0
是的,我知道,这个线程被接受并关闭了很长一段时间,但是… 首先,我要感谢你, 泽纳克 为了灵感。你的努力可以找到正确的方法。 第二,我对被接受的解决方案不太满意。这种是在我最喜欢的免费软件IPE中使用的,它的Bugzilla对交叉点问题的准确性和可靠性都很低,这其中就包括。 缺失的技巧,允许以提出的方式解决问题 泽纳克 :只需将其中一条曲线缩短一个系数即可。 K >0,那么西尔维斯特矩阵的行列式等于零。很明显,如果缩短的曲线会相交,那么原始曲线也会相交。现在,任务变为搜索合适的值 K 因素。这就导致了求解9度单变量多项式的问题。此多项式的实根和正根负责 潜在的 交叉点。(这并不奇怪,两条三次贝塞尔曲线最多可以相交9次。)最后的选择是只找到那些 K 系数,提供0<。= T &两条曲线lt;=1。 现在是maxima代码,其中起始点是由 泽纳克 :
此时,马克西玛回答说:
让马克西玛解这个方程:
答案是:
现在选择正确值的代码 K :
马克西玛的回答:
不过,这里不仅有蜂蜜。如果出现以下情况,则所述方法不可用:
人们可以问,为什么缩短只执行一次。这就足够了,因为反逆定律被发现了 在过去 但这是另一个故事。 |