我正在编写一个函数来测试矩形与超椭圆的交集。 矩形将始终是轴对齐的,而超椭圆可以以旋转角α定向。
在轴对齐的矩形与轴对齐的超椭圆相交的情况下,我已经编写了这两个可以很好地工作的短函数。 代码简洁,清晰,高效。如果可能的话,我想为新的更通用的功能保留类似的结构。
以下是我检测轴对齐矩形是否与轴对齐的超椭圆相交的原因:
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之间变化。
感谢您的帮助。
答案 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无法在标准执行时间内产生任何结果。