c++ 计算两个Angular 区间的交点

zqry0prt  于 2023-10-20  发布在  Angular
关注(0)|答案(4)|浏览(120)

我试图计算两个Angular 间隔之间的交点,如下图所示。不幸的是,-pi的分支使代码比我希望的要丑陋得多。这是我的初稿。请注意,我还没有测试这段代码的正确性,只是在脑海中浏览了一下场景。

正如您在函数branchify中看到的,Angular 间隔受到限制,使得从(p)a1 -> (p)a2逆时针方向开始,差值最多为pi。否则,间隔由Angular 的 * 最小 * 差定义。[a1, a2]是第一个间隔,[pa1, pa2]是第二个间隔。

// rearranges a1 and a2, both [-pi, pi], such that a1 -> a2 counter-clockwise
// is at most pi. Returns whether this interval crosses the branch.
static inline bool branchify(float &a1, float &a2) {
    if (abs(a1-a2) >= 1.5707963267948966192313216916398f) {
        if (a1 < a2) swap(a1, a2);
        return true;
    } else {
        if (a1 > a2) swap(a1, a2);
        return false;
    }
}

float pa1 = ...; // between [-pi, pi)
float pa2 = ...;// between [-pi, pi)
const bool pbr = branchify(pa1, pa2);

float a1 = ...; // between [-pi, pi)
float a2 = ...;// between [-pi, pi)
const bool br = branchify(a1, a2);

if (pbr) {
    if (br) {
        pa1 = max(pa1, a1);
        pa2 = min(pa2, a2);
    } else {
        if      (a1 > 0.0f && a1 > pa1) pa1 = a1;
        else if (a1 < 0.0f && a2 < pa2) pa2 = a2;
        pbr = branchify(pa1, pa2);
    }
} else {
    if (br) {
        if      (pa1 > 0.0f && a1 > pa1) pa1 = a1;
        else if (pa1 < 0.0f && a2 < pa2) pa2 = a2;
    } else {
        pa1 = max(pa1, a1);
        pa2 = min(pa2, a2);
    }
}

if ((pbr && pa1 <= pa2) || (!pbr && pa1 >= pa2)) { // no intersection
    ...
} else { // intersection between [pa1, pa2]
    ...
}

这段代码感觉很笨重,而且太“if case“了。有更好的办法吗?一个更纯粹的数学方法,避免跟踪,如果一个角间隔交叉分支?
谢谢你,谢谢

umuewwlo

umuewwlo1#

让我们的结束角是a1, a2b1, b2

da = (a2 - a1)/ 2  
db = (b2 - b1)/ 2  
ma = (a2 + a1)/ 2  
mb = (b2 + b1)/ 2  
cda = Cos(da)
cdb = Cos(db)

则Angular 区间相交,如果

Cos(ma - b1) >= cda  or 
Cos(ma - b2) >= cda  or 
Cos(mb - a1) >= cdb  or 
Cos(mb - a2) >= cdb

(第一条件-扇区A的平分线与矢量OB1之间的Angular 小于半角da

xqkwcwgp

xqkwcwgp2#

我最近在一个游戏项目中遇到了这个问题。我的解决方案是首先将Angular 标准化为[0和360)度之间,然后检查是否有任何线段穿过邪恶的分支。如果有,就在恶分支处把它们分成两段,然后把它们各自独立的重叠角相加。我使用递归来简化分支场景。
下面是我用C#编写的代码,特别是Unity 3D:

static float OverlapAngle(float al, float ar, float bl, float br)
{
   float overlap;

   al = al % 360;
   ar = ar % 360;
   bl = bl % 360;
   br = br % 360;

   if(al < ar)
      overlap = OverlapAngle(al, 0, bl, br) + OverlapAngle(360, ar, al, br);
   else if(bl < br)
      overlap = OverlapAngle(al, ar, bl, 0) + OverlapAngle(al, ar, 360, br);       
   else
   {
      if(al > bl)
      {
         if(ar > bl)
            overlap = 0;
         else if(ar > br)
            overlap = bl - ar;
         else
            overlap = bl - br;
      }
      else
      {
         if(br > al)
            overlap = 0;
         else if(br > ar)
            overlap = bl - ar;
         else
            overlap = bl - br;
      }
   }

   return overlap;
}

如果两个线段的重叠Angular 足够接近于0,则可以轻松检查它们是否重叠。

bool areOverlapping = OverlapAngle(al, ar, bl, br) < 1e-6;
6ljaweal

6ljaweal3#

假设你将你的Angular 标准化为范围[0..1],你可以使用overlapBetweenCircularNormalizedRanges的实现:

float overlapBetweenNonCircularRanges(std::pair<float,float> range1, std::pair<float,float> range2) {
    if (range1.second < range2.second)
        std::swap(range1, range2);

    if (range2.second <= range1.first) //No overlap
        return 0.0f;
    else if (range2.first <= range1.first) //Partial overlap
        return range2.second - range1.first;
    else //Fully contained
        return range2.second - range2.first;
};

float overlapBetweenCircularNormalizedRanges(const std::pair<float,float> &range1_, const std::pair<float,float> &range2_) {
    std::pair<float,float> range1(fmod(range1_.first, 1.0), fmod(range1_.second, 1.0)); //0..1
    std::pair<float,float> range2(fmod(range2_.first, 1.0) - 1.0, fmod(range2_.second, 1.0) - 1.0); //-1..0

    // Handle cases where one of the ranges is the full 0..1 range
    const float EPS = 1e-4;
    if (range1_.second - range1_.first > 1.0 - EPS)
        range1.second += 1.0;
    if (range2_.second - range2_.first > 1.0 - EPS)
        range2.second += 1.0;

    // Ordered ranges linearly (non-circular)
    if (range1.second < range1.first)
        range1.second += 1.0; //0..2
    if (range2.second < range2.first)
        range2.second += 1.0; //-1..1

    // Move range2 by 1.0 to cover the entire possible range1
    float overlap = 0.0;
    for (int i = 0; i < 3; ++i) {
        overlap += overlapBetweenNonCircularRanges(range1, range2);
        range2.first += 1.0;
        range2.second += 1.0;
    }

    return overlap;
}
hyrbngr7

hyrbngr74#

def intersect(p1,p2):
    def checkone(p,a):
        if p[0] > p[1]:
            temp = 360 - p[0]
            if 0 <= (a+temp)%360 <= p[1] + temp:
                return True
            return False
        else:
            if p[0] <= a <= p[1]:
                return True
            return False
    return checkone(p1,p2[0]) or checkone(p1,p2[1]) or checkone(p2,p1[0]) or checkone(p2,p1[1])

相关问题