У меня есть угол phi
который я хотел бы проверить, чтобы быть внутри (скажем, закрыт, но не имеет значения) интервал a
, b
в периодическом 0..2pi
пространство. Нет ограничений на значения phi
, a
а также b
, особенно:
a>b
возможно (например, a = (3/2.) pi, b = pi /; 2 соответствует интервалу -pi / 2 … pi / 2)a==b
интервал равен нулю и только phi==a
будет внутриa-b>=2*pi
, phi
всегда будет внутриЯ придумал следующее:
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);
}
но я не уверен, что это эффективно, и, возможно, если нет библиотек, реализующих подобные вещи.
Ваши условия противоречивы, в частности условие:
с a-b> = 2 * пи, фи всегда будет внутри
Это немного странно. Или:
a-b
никогда не будет больше, чем 2pi
,В любом случае, когда у вас возникает такая проблема, удобно думать с точки зрения левой границы и размера диапазона, а не левой и правой границ.
То есть, если вы можете решить проблему с a==0
, то вы можете просто использовать это решение с phi' = phi - a
, а также b' = 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
,
Если у вас есть возможность изменить ‘double phi’ на класс / структуру Angle, в которой вместо значения угла хранится значение cos и sin угла. Затем Вы можете легко определить, находится ли угол альфа на «правой» или «левой» стороне другого угла бета.
Образец:
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;
};
.. с помощью функции «in», чтобы проверить, находится ли угол «a» в интервале «i».
Обратите внимание, что пустой (или полностью полный!) Интервал с == до не определен! Вам нужна особая обработка в этом случае.