【问题标题】:How to calculate the Minimum Translation Vector in a given direction?如何计算给定方向的最小平移向量?
【发布时间】:2015-03-23 03:54:40
【问题描述】:

分离轴定理返回任意方向的最小平移向量。这个问题的一个变体是计算给定方向上的最小平移向量。我想知道如何用多边形和圆圈计算这个,但我被困在圆圈的情况下。有人知道如何解决这个问题吗?

这个函数的签名是:

Vector minimum_tranlation_vector_between(Circle a, Circle b, Vector axis);

提前致谢!

【问题讨论】:

    标签: algorithm math geometry computational-geometry


    【解决方案1】:

    假设圆a的中心坐标和半径分别由a.x、a.y和a.r.给出。

    还假设我们有一个向量 v,我们想通过将第一个圆沿 v 的方向移动 d 量来将圆推开。圆圈将在以下情况下相互接触:

    ((a.x + (v.x * d)) - b.x)2 + ((a.y + (v.y * d)) - b.y)2 = (a.r + b.r)2

    这个等式只是计算偏移圆心之间的平方距离,并将其设置为半径之和的平方。

    我们可以通过移动两个圆来简化它,方法是从两个圆中减去第二个圆的中心点,使第二个圆位于原点,从而将其从等式中删除:

    (a.x + (v.x * d))2 + (a.y + (v.y * d))2 = (a.r + b.r)2支持>

    现在我们只需要求解 d 并将其乘以 v 即可得到结果(分离向量)。我作弊并使用了online solver,有两种解决方案(格式化为代码,因为格式化程序一直试图将乘法转换为斜体):

    d = -(sqrt((v.y²+v.x²)*e-a.x²*v.y²+2*a.x*v.x*a.y*v.y-v.x²*a.y²)+a.y*v.y+a.x*v.x)/(v.y²+v.x²)
    d = (sqrt((v.y²+v.x²)*e-a.x²*v.y²+2*a.x*v.x*a.y*v.y-v.x²*a.y²)-a.y*v.y-a.x*v.x)/(v.y²+v.x²)
    

    以下是 Java 中的一些概念验证代码:

    double calculateSeparationDistance(double circle1x, double circle1y, double radius1, double circle2x, double circle2y, double radius2, double vectorx, double vectory)
    {
        double a = circle1x-circle2x;
        double b = vectorx;
        double c = circle1y-circle2y;
        double d = vectory;
        double e = (radius1 + radius2) * (radius1 + radius2);
    
        // 2 possible solutions:
        double distance = -(Math.sqrt(((d*d)+(b*b))*e-(a*a)*(d*d)+2*a*b*c*d-(b*b)*(c*c))+c*d+a*b)/((d*d)+(b*b));
        // double distance = (Math.sqrt(((d*d)+(b*b))*e-(a*a)*(d*d)+2*a*b*c*d-(b*b)*(c*c))-c*d-a*b)/((d*d)+(b*b));
    
        // add (distance * vectorx, distance * vectory) to first circle, or subtract from second circle to separate them 
        return distance;
    }
    

    这两种解决方案对应于将第一个圆圈从第二个圆圈中向任一方向推出。您可以选择绝对值最小的任一解,或选择带正号的解。

    失败案例:当圆不相交并且向量没有将它们置于碰撞路线上时,则没有解,并且方程给出了负值的平方根,因此要么事先进行相交测试,要么检查将值传递给 sqrt() 之前的符号。

    【讨论】:

      【解决方案2】:

      从 samgak 复制命名方案,但将所有内容简化为二次方程的标准情况给出了过程

      double calculateSeparationDistance(double circle1x, double circle1y, double radius1, double circle2x, double circle2y, double radius2, double vectorx, double vectory)
      {
          double dx = circle1x-circle2x;
          double vx = vectorx;
          double dy = circle1y-circle2y;
          double vy = vectory;
          double R2 = (radius1 + radius2) * (radius1 + radius2);
      
          // the equation is 
          // (dx+vx*d)²+(dy+vy*d)² = R2
          // expanding and reordering by degree
          // (vx²+vy²)*d²+2*(vx*dx+vy*dy)*d+(dx²+dy²-R2) = 0
      
          double a = vx*vx;
          double b = 2*(vx*dx+vy*dy);
          double c = dx*dx+dy*dy-R2
      
          // Note that we want the smaller (in absolute value) solution, 
          // and that the selection by the solution formula depends on
          // the sign of b. Setting (b,d):=(-b,-d) still results in an
          // equation with a solution.
      
          double sign = 1;
          if ( b<0 ) { b=-b; sign = -1; } 
      
          // Real solutions do not exist if the discriminant is negative
          // here that means that abs(dx*vx+dx*vy) is too small, 
          // geometrically that the circles never touch if moving in
          // direction v.
      
          if( b*b < 4*a*c ) return 0; // or 1e308 or throw exception
      
          // apply stable standard solution formula for the smaller solution:
          double d = -(2*c)/(b + Math.sqrt(b*b-4*a*c));
      
          return sign*d;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-02
        • 2021-08-26
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 2019-11-26
        • 2015-01-14
        • 1970-01-01
        相关资源
        最近更新 更多