计算两个角度区间的交点

问题描述 投票:0回答:4

我正在尝试计算两个角度间隔之间的交点,如下图所示。不幸的是,-pi 处的分支使代码比我希望的要丑陋得多。这是我的初稿。请注意,我尚未测试此代码的正确性,而只是在我的脑海中浏览了这些场景。

正如您在函数

branchify
中看到的,角度间隔受到限制,使得从
(p)a1 -> (p)a2
逆时针方向,差值最多为 pi。否则,间隔由“最小”角度差定义。 [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”了。有没有更好的办法?一种更纯粹的数学方法可以避免跟踪角度间隔是否穿过分支?

谢谢!

c++ math geometry intervals angle
4个回答
2
投票
a1, a2

b1, b2

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

则角度间隔相交如果

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

(第一个条件 - 扇形
A

平分线与矢量

OB1
之间的角度小于半角
da
    


1
投票

这是我用 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; }

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

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



0
投票
[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; }



0
投票
© www.soinside.com 2019 - 2024. All rights reserved.