检测轴对齐矩形与定向超椭圆之间交点的算法

时间:2017-08-26 09:20:31

标签: c algorithm geometry rectangles ellipse

我正在编写一个函数来测试矩形与超椭圆的交集。 矩形将始终是轴对齐的,而超椭圆可以以旋转角α定向。

在轴对齐的矩形与轴对齐的超椭圆相交的情况下,我已经编写了这两个可以很好地工作的短函数。 代码简洁,清晰,高效。如果可能的话,我想为新的更通用的功能保留类似的结构。

以下是我检测轴对齐矩形是否与轴对齐的超椭圆相交的原因:

double fclamp(double x, double min, double max)
{
    if (x <= min) return min;
    if (x >= max) return max;
    return x;
}

bool rect_intersects_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent)
{
    t_pt closest;
    closest.x = fclamp(cx, rect->x, rect->x + rect->width);
    closest.y = fclamp(cy, rect->y, rect->y + rect->height);
    return point_inside_superellipse(&closest, cx, cy, rx, ry, exponent);
}

bool point_inside_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent)
{
    double dx = fabs(pt->x - cx);
    double dy = fabs(pt->y - cy);

    double dxp = pow(dx, exponent);
    double dyp = pow(dy, exponent);

    double rxp = pow(rx, exponent);
    double ryp = pow(ry, exponent);

    return (dxp * ryp + dyp * rxp) <= (rxp * ryp);
}

这是正常的,但正如我所说的那样 - 仅适用于轴对齐的超椭圆。

现在我想将它推广到一个定向的超椭圆,使算法结构尽可能接近上面。 之前两个函数的明显扩展将变成类似:

bool rect_intersects_oriented_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent, double radians)
{
    t_pt closest;
    closest.x = fclamp(cx, rect->x, rect->x + rect->width);
    closest.y = fclamp(cy, rect->y, rect->y + rect->height);
    return point_inside_oriented_superellipse(&closest, cx, cy, rx, ry, exponent, radians);
}

bool point_inside_oriented_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent, double radians)
{
    double dx = pt->x - cx;
    double dy = pt->y - cy;

    if (radians) {

        double c = cos(radians);
        double s = sin(radians);

        double new_x = dx * c - dy * s;
        double new_y = dx * s + dy * c;

        dx = new_x;
        dy = new_y;
    }
    double dxp = pow(fabs(dx), exponent);
    double dyp = pow(fabs(dy), exponent);

    double rxp = pow(rx, exponent);
    double ryp = pow(ry, exponent);

    return (dxp * ryp + dyp * rxp) < (rxp * ryp);
}

对于定向超椭圆,即使point_inside_oriented_superellipse()本身按预期工作,上述操作也无法正常工作。我无法使用上述函数来测试具有轴对齐矩形的交点。我已经在网上进行了大约一周的研究,我发现了一些需要逆矩阵变换来均衡超椭圆轴并使其原点为(0,0)的解决方案。权衡是现在我的矩形不再是一个矩形,当然也不是轴对齐的。我想避免走那条路。 我的问题是展示如何使上述算法保持其结构或多或少不变。如果不可能保持相同的算法结构,请显示最简单,最有效的算法来测试轴对齐矩形和定向超椭圆之间的交集。我只需要知道交叉是否发生(布尔结果)。 指数参数的范围可以在0.25到100.0之间变化。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

看看source中的第2点。简单来说,您需要进行以下测试:

<强> 1。椭圆中是否有任何矩形顶点?

<强> 2。矩形边是否与椭圆相交?

第3。椭圆的中心是否在矩形内?

如果上面的任何问题都可以用来回答,那么椭圆和矩形会相互交叉,所以,你的函数应该返回如下内容:

return areVertexesInsideEllipse(/*params*/) || areRectangleEdgesIntersectingEllipse(/*params*/) || isEllipseCenterInsideRectangle(/*params*/);

该文档甚至还有一个实现示例,它与您的实现相当接近。

要检查任何顶点是否在椭圆内,您可以根据椭圆的不等式计算它们的坐标。要检查边缘是否与椭圆重叠,您需要检查其线是否穿过椭圆或触摸它。如果是这样,您将需要检查线穿过椭圆或触摸它的线是否与边缘定义的线相交。要检查椭圆的中心是否在矩形内,您需要根据矩形的不等式检查中心。

请注意,这些是非常通用的术语,它们甚至不假设您的矩形是面向轴的,而是单独的椭圆。

答案 1 :(得分:0)

首先,你应该使用分离轴定理排除明显的非交叉情况 - 超椭圆可能有两个边界框(指数n> 1的情况)和n <= 1的情况。

在SAT中,将边界框ABCD中的所有顶点与超椭圆的BB(abcd)中的所有(定向)边进行比较;然后反之亦然。如果到分离轴的有符号距离都是正的(即外部),则物体不会发生碰撞。

          b
       a  
   A------B
   |      |     d
   |      |  c
   C------D

指数n == 1进一步划分情况 - n <= 1使得超椭圆体凹陷,在这种情况下,如果一个或多个点在超椭圆体内,则ABCD仅与abcd相交。 当n> 1时,必须求解AABB中的线段与超椭球的交点,其可能必须由样条近似或必须找到另一个代理。毕竟,实际交叉点并不重要,但将方程式设置为wolfram alpha无法在标准执行时间内产生任何结果。