簡體   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