测试角度是否在范围内(高效且优雅)

时间:2014-09-22 08:31:08

标签: c++ math angle

我有一个角度phi,我会在定期a空间内测试其内部(比如已关闭,但无关紧要)间隔b0..2pi。对phiab的值没有任何限制,特别是:

  • a>b是可能的(例如a =(3/2。)pi,b = pi /; 2对应于间隔-pi / 2 ... pi / 2)
  • 如果a==b,则间隔为零宽度且内部只有phi==a
  • a-b>=2*piphi将始终在

我想出了以下内容:

bool angleInside(const double& phi, double a, const double& b){
   if(std::abs(a-b)>=2*M_PI) return true; // interval covers everything
   if(a>b) a-=2*M_PI;
   if(a==b) return (fmod(a,2*M_PI)==fmod(phi,2*M_PI)); // corner case
   assert(b-a>0 && b-a<2*M_PI); // unless I overlooked something?
   // wrap phi so that a+pphi is in a..a+2*M_PI, i.e. pphi in 0..2*M_PI
   double n=(phi-a)/(2*M_PI); // n in <0..2pi)
   double pphi=(n-floor(n))*(2*M_PI);
   return pphi<(b-a);
}

但我不确定它是否有效,也许如果没有lib实现这样的事情。

2 个答案:

答案 0 :(得分:0)

你的条件是矛盾的,特别是条件:

  

a-b> = 2 * pi,phi将始终位于

之内

有点奇怪。之一:

  1. 您的范围是模数空间中的[a,b],a-b永远不会超过2pi
  2. 您的范围为[a,b] if(a b)和然后您应用模数。
  3. 在任何情况下,无论何时遇到这样的问题,都可以考虑左边界和范围大小,而不是左右限制。

    也就是说,如果您可以使用a==0解决问题,那么您可以将此解决方案与phi' = phi - ab' = b - a一起使用。

    还要记住std::remainder(只有C ++ 11)是你这样的问题的朋友,因为与fmod不同,它总会产生(-pi, pi)范围内的结果。

    我建议的解决方案是:

    bool angleInside(const double phi, const double a, const double b)
    {
        //Case 1 above
        const double d = phi - a;
        const double s = std::remainder(b-a - M_PI, 2 * M_PI) + M_PI;
    
        // Or (Case 2)
        const double d = phi - std::min(a,b);
        const double s = std::fabs(b-a);
    
    
        return std::remainder( d - M_PI, 2 * M_PI ) + M_PI <= s;
    }
    

    请注意,在这两种情况下都难以获得边界案例的一致结果,尤其是当phi 并且以范围边界为模2pi时。

答案 1 :(得分:0)

如果你有可能改变双重发帖。到类/结构角度,它存储角度的cos值和sin值而不是角度值本身。然后,您可以轻松区分,角度alpha是否在“正确”位置。或者&#39;离开&#39;另一角β的一面。 样品:

struct Angle {
    Angle() : m_cos(1.), m_sin(0.) {} // 0 degree
    // some other methods
    friend double sin( const Angle& a ) { return a.m_sin; }
    friend double cos( const Angle& a ) { return a.m_cos; }
    bool operator<( const Angle& beta ) const {
        return (m_cos * beta.m_sin - m_sin * beta.m_cos) > 0.;
    }
private:
    double m_cos, m_sin;
};

不知道这在您的应用程序中是否有意义。 如果是,您可以编程间隔

struct Interval {
    Interval( const Angle& from, const Angle& to )
        : m_from( from ), m_to( to ), m_inner( from < to )
    {}
    friend bool in( const Angle& a, const Interval& i ) { // true, if 'a' is in ]from, to[
        if( i.m_inner )
            return i.m_from < a && a < i.m_to;
        return i.m_from < a || a < i.m_to;
    }
private:
    Angle m_from, m_to;
    bool m_inner;
};

..功能&#39; in&#39;检查一个角度是否是一个角度&#39;在区间&#39; i&#39;。

请注意,未定义from == to的空(或整体!)间隔!在这种情况下,您需要特殊处理。