如何计算给定方向的最小平移向量?

时间:2015-03-23 03:54:41

标签: algorithm math geometry computational-geometry

分离轴定理返回任意方向的最小平移向量。该问题的变化是计算给定方向上的最小平移向量。我想知道如何用多边形和圆圈计算这个,但我陷入了圆圈的情况。有没有人知道如何处理这个问题?

此功能的签名是:

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

提前致谢!

2 个答案:

答案 0 :(得分:3)

假设中心坐标和圆半径a由a.x,a.y和a.r给出。

另外假设我们有一个向量v,我们想通过在v方向上移动第一个圆d来推动圆圈分开。在下列情况下,圈子会触及:

((ax +(vx * d)) - bx) 2 +((ay +(vy * d)) - by) 2 =(ar + BR) 2

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

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

(ax +(vx * d)) 2 +(ay +(vy * d)) 2 =(ar + br) 2

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

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()之前的值的符号。

答案 1 :(得分:3)

从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;
}