KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eda_angle.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef EDA_ANGLE_H
21#define EDA_ANGLE_H
22
23#include <cassert>
24#include <cmath>
25#include <math/vector2d.h> // for VECTOR2I
26
27
34
35
37{
38public:
46 EDA_ANGLE( double aValue, EDA_ANGLE_T aAngleType )
47 {
48 switch( aAngleType )
49 {
50 case RADIANS_T:
51 m_value = aValue / DEGREES_TO_RADIANS;
52 break;
53
55 m_value = aValue / 10.0;
56 break;
57
58 default:
59 m_value = aValue;
60 }
61 }
62
68 constexpr explicit EDA_ANGLE( double aAngleInDegrees ) :
69 m_value( aAngleInDegrees )
70 {}
71
72 explicit EDA_ANGLE( const VECTOR2D& aVector )
73 {
74 if( aVector.x == 0.0 && aVector.y == 0.0 )
75 {
76 m_value = 0.0;
77 }
78 else if( aVector.y == 0.0 )
79 {
80 if( aVector.x >= 0 )
81 m_value = 0.0;
82 else
83 m_value = -180.0;
84 }
85 else if( aVector.x == 0.0 )
86 {
87 if( aVector.y >= 0.0 )
88 m_value = 90.0;
89 else
90 m_value = -90.0;
91 }
92 else if( aVector.x == aVector.y )
93 {
94 if( aVector.x >= 0.0 )
95 m_value = 45.0;
96 else
97 m_value = -180.0 + 45.0;
98 }
99 else if( aVector.x == -aVector.y )
100 {
101 if( aVector.x >= 0.0 )
102 m_value = -45.0;
103 else
104 m_value = 180.0 - 45.0;
105 }
106 else
107 {
108 *this = EDA_ANGLE( atan2( aVector.y, aVector.x ), RADIANS_T );
109 }
110 }
111
113 m_value( 0.0 )
114 {}
115
116 inline double AsDegrees() const { return m_value; }
117
118 inline int AsTenthsOfADegree() const { return KiROUND( m_value * 10.0 ); }
119
120 inline double AsRadians() const { return m_value * DEGREES_TO_RADIANS; }
121
122 static constexpr double DEGREES_TO_RADIANS = M_PI / 180.0;
123
128 bool IsCardinal() const;
129
134 bool IsCardinal90() const;
135
136 bool IsZero() const
137 {
138 return m_value == 0.0;
139 // return equals( m_value, 0.0 );
140 }
141
142 bool IsHorizontal() const
143 {
144 return m_value == 0.0 || m_value == 180.0;
145 // return equals( m_value, 0.0 ) || equals( m_value, 180.0 );
146 }
147
148 bool IsVertical() const
149 {
150 return m_value == 90.0 || m_value == 270.0;
151 //return equals( m_value, 90.0 ) || equals( m_value, 270.0 );
152 }
153
154 bool IsParallelTo( EDA_ANGLE aAngle ) const
155 {
156 EDA_ANGLE thisNormalized = *this;
157
158 // Normalize90 is inclusive on both ends [-90, +90]
159 // but we need it to be (-90, +90] for this test to work
160 thisNormalized.Normalize90();
161
162 if( equals( thisNormalized.AsDegrees(), -90.0 ) )
163 thisNormalized = EDA_ANGLE( 90.0, DEGREES_T );
164
165 aAngle.Normalize90();
166
167 if( equals( aAngle.AsDegrees(), -90.0 ) )
168 aAngle = EDA_ANGLE( 90.0, DEGREES_T );
169
170 return ( equals( thisNormalized.AsDegrees(), aAngle.AsDegrees() ) );
171 }
172
174 {
175 return EDA_ANGLE( -AsDegrees(), DEGREES_T );
176 }
177
178 double Sin() const
179 {
180 EDA_ANGLE test = *this;
181 test.Normalize();
182
183 if( test.m_value == 0.0 || test.m_value == 180.0 )
184 return 0.0;
185 else if( test.m_value == 45.0 || test.m_value == 135.0 )
186 return M_SQRT1_2; // sqrt(2)/2
187 else if( test.m_value == 225.0 || test.m_value == 315.0 )
188 return -M_SQRT1_2;
189 else if( test.m_value == 90.0 )
190 return 1.0;
191 else if( test.m_value == 270.0 )
192 return -1.0;
193 else
194 return sin( AsRadians() );
195 }
196
197 double Cos() const
198 {
199 EDA_ANGLE test = *this;
200 test.Normalize();
201
202 if( test.m_value == 0.0 )
203 return 1.0;
204 else if( test.m_value == 180.0 )
205 return -1.0;
206 else if( test.m_value == 90.0 || test.m_value == 270.0 )
207 return 0.0;
208 else if( test.m_value == 45.0 || test.m_value == 315.0 )
209 return M_SQRT1_2; // sqrt(2)/2
210 else if( test.m_value == 135.0 || test.m_value == 225.0 )
211 return -M_SQRT1_2;
212 else
213 return cos( AsRadians() );
214 }
215
216 double Tan() const { return tan( AsRadians() ); }
217
218 static EDA_ANGLE Arccos( double x ) { return EDA_ANGLE( acos( x ), RADIANS_T ); }
219
220 static EDA_ANGLE Arcsin( double x ) { return EDA_ANGLE( asin( x ), RADIANS_T ); }
221
222 static EDA_ANGLE Arctan( double x ) { return EDA_ANGLE( atan( x ), RADIANS_T ); }
223
224 static EDA_ANGLE Arctan2( double y, double x )
225 {
226 return EDA_ANGLE( atan2( y, x ), RADIANS_T );
227 }
228
230 {
231 while( m_value < -0.0 )
232 m_value += 360.0;
233
234 while( m_value >= 360.0 )
235 m_value -= 360.0;
236
237 return *this;
238 }
239
241 {
242 EDA_ANGLE ret( *this );
243 return ret.Normalize();
244 }
245
247 {
248 while( m_value <= -360.0 )
249 m_value += 360.0;
250
251 while( m_value > 0.0 )
252 m_value -= 360.0;
253
254 return *this;
255 }
256
258 {
259 while( m_value < -90.0 )
260 m_value += 180.0;
261
262 while( m_value > 90.0 )
263 m_value -= 180.0;
264
265 return *this;
266 }
267
269 {
270 while( m_value <= -180.0 )
271 m_value += 360.0;
272
273 while( m_value > 180.0 )
274 m_value -= 360.0;
275
276 return *this;
277 }
278
280 {
281 while( m_value < -360.0 )
282 m_value += 360.0;
283
284 while( m_value >= 360.0 )
285 m_value -= 360.0;
286
287 return *this;
288 }
289
291 EDA_ANGLE Snapped( const EDA_ANGLE& aStep ) const
292 {
293 double step = aStep.AsDegrees();
294
295 if( step <= 0.0 )
296 return *this;
297
298 return EDA_ANGLE( step * KiROUND( AsDegrees() / step ), DEGREES_T );
299 }
300
301 EDA_ANGLE KeepUpright() const;
302
303 [[nodiscard]] EDA_ANGLE Round( int digits ) const
304 {
305 EDA_ANGLE angle( *this );
306 double rounded = KiROUND( angle.AsDegrees() * pow( 10.0, digits ) ) / pow( 10.0, digits );
307 angle = EDA_ANGLE( rounded, DEGREES_T );
308 return angle;
309 }
310
312 {
313 *this = EDA_ANGLE( AsDegrees() + aAngle.AsDegrees(), DEGREES_T );
314 return *this;
315 }
316
318 {
319 *this = EDA_ANGLE( AsDegrees() - aAngle.AsDegrees(), DEGREES_T );
320 return *this;
321 }
322
323private:
324 double m_value;
325
326};
327
328
329inline EDA_ANGLE operator-( const EDA_ANGLE& aAngle )
330{
331 return aAngle.Invert();
332}
333
334
335inline EDA_ANGLE operator-( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
336{
337 return EDA_ANGLE( aAngleA.AsDegrees() - aAngleB.AsDegrees(), DEGREES_T );
338}
339
340
341inline EDA_ANGLE operator+( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
342{
343 return EDA_ANGLE( aAngleA.AsDegrees() + aAngleB.AsDegrees(), DEGREES_T );
344}
345
346
347inline EDA_ANGLE operator*( const EDA_ANGLE& aAngleA, double aOperator )
348{
349 return EDA_ANGLE( aAngleA.AsDegrees() * aOperator, DEGREES_T );
350}
351
352
353inline EDA_ANGLE operator/( const EDA_ANGLE& aAngleA, double aOperator )
354{
355 return EDA_ANGLE( aAngleA.AsDegrees() / aOperator, DEGREES_T );
356}
357
358
359inline double operator/( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aOperator )
360{
361 return aAngleA.AsDegrees() / aOperator.AsDegrees();
362}
363
364
365inline bool operator==( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
366{
367 return aAngleA.AsDegrees() == aAngleB.AsDegrees();
368 //return equals( aAngleA.AsDegrees(), aAngleB.AsDegrees() );
369}
370
371
372inline bool operator!=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
373{
374 return aAngleA.AsDegrees() != aAngleB.AsDegrees();
375 // return !equals( aAngleA.AsDegrees(), aAngleB.AsDegrees() );
376}
377
378
379inline bool operator>( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
380{
381 return aAngleA.AsDegrees() > aAngleB.AsDegrees();
382}
383
384
385inline bool operator<( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
386{
387 return aAngleA.AsDegrees() < aAngleB.AsDegrees();
388}
389
390
391inline bool operator<=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
392{
393 return aAngleA.AsDegrees() <= aAngleB.AsDegrees();
394}
395
396
397inline bool operator>=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
398{
399 return aAngleA.AsDegrees() >= aAngleB.AsDegrees();
400}
401
402
403inline std::ostream& operator<<( std::ostream& aStream, const EDA_ANGLE& aAngle )
404{
405 return aStream << aAngle.AsDegrees();
406}
407
408
409namespace std
410{
411inline EDA_ANGLE abs( const EDA_ANGLE& aAngle )
412{
413 return EDA_ANGLE( std::abs( aAngle.AsDegrees() ), DEGREES_T );
414}
415}
416
417
418static constexpr EDA_ANGLE ANGLE_HORIZONTAL{ 0 };
419static constexpr EDA_ANGLE ANGLE_VERTICAL{ 90 };
420static constexpr EDA_ANGLE FULL_CIRCLE{ 360 };
421
422static constexpr EDA_ANGLE ANGLE_0{ 0 };
423static constexpr EDA_ANGLE ANGLE_45{ 45 };
424static constexpr EDA_ANGLE ANGLE_90{ 90 };
425static constexpr EDA_ANGLE ANGLE_135{ 135 };
426static constexpr EDA_ANGLE ANGLE_180{ 180 };
427static constexpr EDA_ANGLE ANGLE_270{ 270 };
428static constexpr EDA_ANGLE ANGLE_360{ 360 };
429
430
431#endif // EDA_ANGLE_H
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
EDA_ANGLE Normalize()
Definition eda_angle.h:229
EDA_ANGLE NormalizeNegative()
Definition eda_angle.h:246
double Sin() const
Definition eda_angle.h:178
EDA_ANGLE Normalize90()
Definition eda_angle.h:257
double Tan() const
Definition eda_angle.h:216
constexpr EDA_ANGLE(double aAngleInDegrees)
Construct an EDA_ANGLE in degrees.
Definition eda_angle.h:68
int AsTenthsOfADegree() const
Definition eda_angle.h:118
bool IsParallelTo(EDA_ANGLE aAngle) const
Definition eda_angle.h:154
double AsDegrees() const
Definition eda_angle.h:116
EDA_ANGLE Snapped(const EDA_ANGLE &aStep) const
Snap to the nearest integer multiple of aStep (returns *this if aStep <= 0).
Definition eda_angle.h:291
EDA_ANGLE Invert() const
Definition eda_angle.h:173
bool IsZero() const
Definition eda_angle.h:136
bool IsHorizontal() const
Definition eda_angle.h:142
bool IsCardinal() const
Definition eda_angle.cpp:40
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
static EDA_ANGLE Arctan2(double y, double x)
Definition eda_angle.h:224
EDA_ANGLE KeepUpright() const
Definition eda_angle.cpp:23
EDA_ANGLE Normalize720()
Definition eda_angle.h:279
double AsRadians() const
Definition eda_angle.h:120
bool IsVertical() const
Definition eda_angle.h:148
EDA_ANGLE & operator-=(const EDA_ANGLE &aAngle)
Definition eda_angle.h:317
EDA_ANGLE Round(int digits) const
Definition eda_angle.h:303
EDA_ANGLE & operator+=(const EDA_ANGLE &aAngle)
Definition eda_angle.h:311
EDA_ANGLE(const VECTOR2D &aVector)
Definition eda_angle.h:72
EDA_ANGLE(double aValue, EDA_ANGLE_T aAngleType)
Angles can be created in degrees, 1/10ths of a degree, or radians, and read as any of the angle types...
Definition eda_angle.h:46
static constexpr double DEGREES_TO_RADIANS
Definition eda_angle.h:122
bool IsCardinal90() const
Definition eda_angle.cpp:54
double Cos() const
Definition eda_angle.h:197
double m_value
value in degrees
Definition eda_angle.h:324
static EDA_ANGLE Arctan(double x)
Definition eda_angle.h:222
static EDA_ANGLE Arcsin(double x)
Definition eda_angle.h:220
EDA_ANGLE Normalized() const
Definition eda_angle.h:240
static EDA_ANGLE Arccos(double x)
Definition eda_angle.h:218
EDA_ANGLE operator/(const EDA_ANGLE &aAngleA, double aOperator)
Definition eda_angle.h:353
bool operator>(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:379
bool operator>=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:397
EDA_ANGLE operator*(const EDA_ANGLE &aAngleA, double aOperator)
Definition eda_angle.h:347
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:424
bool operator<=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:391
std::ostream & operator<<(std::ostream &aStream, const EDA_ANGLE &aAngle)
Definition eda_angle.h:403
EDA_ANGLE_T
Definition eda_angle.h:29
@ TENTHS_OF_A_DEGREE_T
Definition eda_angle.h:30
@ RADIANS_T
Definition eda_angle.h:32
@ DEGREES_T
Definition eda_angle.h:31
EDA_ANGLE operator-(const EDA_ANGLE &aAngle)
Definition eda_angle.h:329
bool operator<(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:385
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:419
bool operator==(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:365
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:418
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:423
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:427
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:420
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:428
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:426
EDA_ANGLE operator+(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:341
static constexpr EDA_ANGLE ANGLE_135
Definition eda_angle.h:425
bool operator!=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition eda_angle.h:372
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
bool equals(glm::mat< L, C, T, Q > const &aFirst, glm::mat< L, C, T, Q > const &aSecond, T aEpsilon=static_cast< T >(FLT_EPSILON *10))
Template to compare two glm::mat<T> values for equality within a required epsilon.
#define M_PI
VECTOR2< double > VECTOR2D
Definition vector2d.h:682