繁体   English   中英

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

[英]Algorithm to detect intersection between an axis-aligned rectangle and an oriented superellipse

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

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

这是我用于检测轴对齐的矩形是否与轴对齐的超椭圆相交的内容:

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之间变化。

感谢您的协助。

看一下本资料中的第二点。 简而言之,您将需要进行以下测试:

1.椭圆中是否有矩形顶点?

2.矩形的边缘是否与椭圆相交?

3.椭圆的中心在矩形内吗?

如果可以使用yes回答上面的任何问题,则椭圆和矩形彼此相交,因此,您的函数应返回如下内容:

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

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

要检查椭圆中是否有任何顶点,可以针对椭圆的不等式计算其坐标。 要检查边缘是否与椭圆重叠,您需要检查其线是穿过椭圆还是接触椭圆。 如果是这样,则需要检查直线穿过椭圆或触摸椭圆的线段是否与边缘定义的线段相交。 要检查椭圆的中心是否在矩形内,您需要对照矩形的不等式检查中心。

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

首先,您应该使用分隔轴定理排除明显的非相交情况-超椭圆可能具有两个边界框(指数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上无法在标准执行时间内产生任何结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM