Algorithm 平面上非相交圆盘运动的路径生成 我在找什么

Algorithm 平面上非相交圆盘运动的路径生成 我在找什么,algorithm,language-agnostic,game-physics,computational-geometry,motion-planning,Algorithm,Language Agnostic,Game Physics,Computational Geometry,Motion Planning,在一个平面上有300个或更少的等半径圆盘。在时间0时,每个制动盘处于一个位置。在时间1时,每个光盘处于可能不同的位置。我希望在0到1之间的时间内为每个光盘生成一个2D路径,这样光盘就不会相交,并且如果可能的话,路径相对有效(短)且曲率较低。(例如,直线比曲线更好) 较低的计算时间通常比解的精确性更重要。(例如,一个小交叉点是可以的,我不一定需要一个最佳结果) 然而,光盘不应该互相传送、突然停止或减速、或突然改变方向——越“平滑”越好。唯一的例外是时间0和1 路径可以表示为采样形式或分段线性性质

在一个平面上有300个或更少的等半径圆盘。在时间0时,每个制动盘处于一个位置。在时间1时,每个光盘处于可能不同的位置。我希望在0到1之间的时间内为每个光盘生成一个2D路径,这样光盘就不会相交,并且如果可能的话,路径相对有效(短)且曲率较低。(例如,直线比曲线更好)

  • 较低的计算时间通常比解的精确性更重要。(例如,一个小交叉点是可以的,我不一定需要一个最佳结果)
  • 然而,光盘不应该互相传送、突然停止或减速、或突然改变方向——越“平滑”越好。唯一的例外是时间0和1
  • 路径可以表示为采样形式或分段线性性质(或更好)——我不担心通过样条曲线得到真正平滑的路径。(如果我需要的话,我可以估计一下。)
我试过的 我的最佳尝试(通过Javascript+WebGL)。请注意,由于涉及到计算,它将在旧计算机上缓慢加载。它似乎在Windows下的Firefox/Chrome/IE11中工作

在这个演示中,我将每个光盘表示为3D中的“弹性带”(也就是说,每个光盘在每个时间都有一个位置),并运行一个简单的游戏式物理引擎,该引擎解决了约束,并将每个时间点视为上一次/下一次带有弹簧的质量。(“时间”在本例中只是第三维度。)

这实际上对于小的N(10000)次迭代非常有效,对于我的应用程序来说,这是非常缓慢的。它也不能合理地解决许多N>40的情况,但这可能仅仅是因为我不能切实地运行足够的迭代

我还试过什么 我最初的尝试是爬山,从直线路径开始,逐渐变异。比当前最佳解决方案更好的解决方案取代了当前最佳解决方案。更好的测量结果来自于交叉点的数量(即,完全重叠的测量结果比仅仅放牧更差)和路径的长度(路径越短越好)

这产生了一些令人惊讶的好结果,但不可靠,很可能经常陷入局部极小值。在N>20时,速度非常慢。我尝试应用一些技术(模拟退火、遗传算法等),试图绕过局部极小值问题,但从未取得多大成功

我在尝试什么 我正在优化“弹性带”模型,以便张力和约束在时间维度上传播得更快。在许多情况下,这将节省大量所需的迭代,但是在高度受限的情况下(例如,许多光盘试图穿过同一位置),仍然需要大量的迭代。我不是如何更快地解决约束或传播弹簧的专家(我试着阅读了一些关于不可拉伸布料模拟的论文,但我还没有弄清楚它们是否适用),所以我想知道是否有一种好的方法来实现这一点

摆在桌面上的想法
  • Spektre已经实现了一个非常快速的RTS风格的单位移动算法,该算法运行良好。它的快速和优雅,但它也有RTS运动风格的问题:方向突然改变,单位可以突然停止以解决碰撞。此外,机组并非全部同时到达目的地,这本质上是一种突然停止。这可能是一个很好的启发式方法,可以创建可行的非平滑路径,之后可以及时对路径重新采样,并运行“平滑”算法(与我的演示中使用的算法非常相似)
  • Ashkan Kzme认为问题可能与网络流量有关。看来,只要空间和时间能够以合理的方式被描述,并且运行时间能够被缩短,那么该方法是可行的。这里的优点是,这是一组经过充分研究的问题,但速度的突然变化仍然是一个问题,一些“平滑”的后期步骤可能是可取的。我目前遇到的一个障碍是决定一种时空的网络表示形式,它不会导致光盘通过彼此传送
  • Jay Kominek发布了一个答案,使用非线性优化器优化二次Bezier曲线,获得了一些有希望的结果

    • 为了好玩,我们玩了一下,结果如下:

      算法:

    • 处理每个光盘
    • 将速度设置为
      恒定*目的地\u矢量
      • 乘法常数
        a
      • 然后将速度限制为恒定
        v
    • 测试新的迭代位置是否与任何其他光盘冲突
    • 如果它确实在一个方向上旋转某个角度步进
      ang
    • 循环,直到找到自由方向或覆盖整圈
    • 如果未找到自由方向,则将光盘标记为卡住

      这是圆到反向圆路径的外观:

      以下是随机到随机路径的情况:

      卡住的光盘呈黄色(在这种情况下为无),且未移动的光盘已到达目的地如果没有路径,这也可能会卡住,就像光盘已经在目标圆中,而另一个目标圆中一样。为了避免这种情况,您还需要更换碰撞盘。。。您可以使用
      ang,a,v
      常量制作不同的外观,还可以尝试随机角度旋转方向,以避免旋转/扭曲运动

    • 这里是我使用的源代码(C++):

      //---------------------------------------------------------------------------
      常数int discs=23;//光盘数量
      常数双盘_r=5;//圆盘半径
      常数双圆盘直径=4.0*di
      
      double errorf(unsigned n, const double *pts, double *grad,
                    void *data)
      {
        problem_t *setup = (problem_t *)data;
        double error = 0.0;
      
        for(int step=0; step<setup->steps; step++) {
          double t = (1.0+step) / (1.0+setup->steps);
          for(int i=0; i<setup->N; i++)
            quadbezier(&setup->starts[2*i],
                       &pts[2*i],
                       &setup->stops[2*i],
                       t,
                       &setup->scratch[2*i]);
      
          for(int i=0; i<setup->N; i++)
            for(int j=i+1; j<setup->N; j++) {
              double d = distance(&setup->scratch[2*i],
                                  &setup->scratch[2*j]);
              d /= RADIUS;
              error += (1.0/d) * (1.0/d);
            }
        }
      
        return error / setup->steps;
      }