Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 计算两个角度间隔之间的交点_C++_Math_Geometry_Intervals_Angle - Fatal编程技术网

C++ 计算两个角度间隔之间的交点

C++ 计算两个角度间隔之间的交点,c++,math,geometry,intervals,angle,C++,Math,Geometry,Intervals,Angle,我试图计算两个角度间隔之间的交点,如下图所示。不幸的是,at-pi分支使代码比我所希望的要难看得多。这是我的初稿。请注意,我没有测试这段代码的正确性,而是在脑海中经历了各种场景 正如您在函数branchify中所看到的,角度间隔受到约束,因此从(p)a1->(p)a2逆时针方向,差值最多为pi。否则,间隔由最小角度差定义[a1,a2]是第一个间隔,[pa1,pa2]是第二个间隔 // rearranges a1 and a2, both [-pi, pi], such that a1 ->

我试图计算两个角度间隔之间的交点,如下图所示。不幸的是,at-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]
    ...
}
//重新排列a1和a2,两者都[-pi,pi],使a1->a2逆时针
//最多是π。返回此间隔是否穿过分支。
静态内联布尔分支(浮点和a1、浮点和a2){
如果(abs(a1-a2)>=1.57079663267948966192313216916398F){
如果(a1a2)互换(a1,a2);
返回false;
}
}
浮动pa1=…;//介于[-pi,pi)之间
浮点pa2=…;//介于[-pi,pi)之间
const bool pbr=branchify(第1页,第2页);
浮点a1=…;//介于[-pi,pi)之间
浮点a2=…;//介于[-pi,pi)之间
常数布尔br=branchify(a1,a2);
如果(pbr){
如果(br){
pa1=最大值(pa1,a1);
pa2=最小值(pa2,a2);
}否则{
如果(a1>0.0f&&a1>pa1)pa1=a1;
如果(a1<0.0f&&a20.0f&&a1>pa1)pa1=a1;
如果(pa1<0.0f&&a2
这段代码感觉很笨拙,而且太“如果情况”了。有没有更好的方法?一种更纯粹的数学方法,可以避免跟踪角度间隔穿过分支的情况


谢谢!

让我们将端点角度设置为
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

假设将角度标准化到范围
[0..1]
,则可以使用循环标准化范围之间重叠的
实现:

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;
}
非循环排列之间的浮点重叠(标准::对范围1,标准::对范围2){ 如果(范围1.s<范围2.s) 标准::交换(范围1,范围2); 如果(范围为2.1秒1.0-每股收益) 范围2.2秒+=1.0; //线性有序范围(非圆形) 如果(范围1.2<范围1.1) 范围1.second+=1.0;//0..2 如果(范围2.2秒<范围2.1秒) 范围2.2秒+=1.0;//-1..1 //将range2移动1.0以覆盖整个可能的range1 浮动重叠=0.0; 对于(int i=0;i<3;++i){ 重叠+=非循环安排之间的重叠(范围1,范围2); 范围2.1+=1.0; 范围2.2秒+=1.0; } 返回重叠; }
最近,我在一个游戏项目中遇到了这个问题。我的解决方案是首先将两者之间的角度标准化[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;
}
静态浮动重叠角(浮动al、浮动ar、浮动bl、浮动br)
{
浮动重叠;
al=al%360;
ar=ar%360;
bl=bl%360;
br=br%360;
if(albl)
{
如果(ar>bl)
重叠=0;
否则如果(ar>br)
重叠=bl-ar;
其他的
重叠=bl-br;
}
其他的
{
如果(br>al)
重叠=0;
否则如果(br>ar)
重叠=bl-ar;
其他的
重叠=bl-br;
}
}
返回重叠;
}
如果两段的重叠角度足够接近于0,则可以轻松检查两段是否重叠

bool areOverlapping = OverlapAngle(al, ar, bl, br) < 1e-6;
bool aretlapping=重叠角度(al,ar,bl,br)<1e-6;

Hmm。你的每个角度都可以被认为是由两个角度组成的:一个开始角度和一个结束角度。因此,圆的填充部分就是开始和结束之间的角度。你不能用开始和结束角度来确定一个角度是否与另一个重叠吗?对于第一个角度,如果在
分支中HytIt/Cuffe,你可以把<代码> 2 *PI/< >添加到<代码> A1 < /C>而不是交换吗?这样,你基本上把重叠的测试转换成两个线性间隔,在代码< -PI >代码中没有跳跃。老实说,我不知道我到底想要什么,特别是你认为的“邪恶分支”。不清楚。另外,为什么最大间隔pi?为什么不能是tau(=2pi)如果它们总是以某个角度开始,然后继续朝正方向继续,那么你就可以简化一些计算。此外,为了计算,考虑偏移范围,使其中的一个总是从角度零点开始。最后,因为你有一个圆,你也错过了一种重叠的方式,即开始和结束重合而不是中间。这是一个分支:不幸的是,添加2 *PI只会取代这个问题,因为现在的检查将以负角度失败。凯特兰就是这样,只有我必须考虑分支,因为差异是如何工作的。我必须用几种不同的语言编写代码。