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 (C) 2021-2022 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 along
17 * with this program. If not, see <http://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
29{
33};
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
67 constexpr EDA_ANGLE( double aAngleInDegrees ) : m_value(aAngleInDegrees) {}
68
69 explicit EDA_ANGLE( const VECTOR2D& aVector )
70 {
71 if( aVector.x == 0.0 && aVector.y == 0.0 )
72 {
73 m_value = 0.0;
74 }
75 else if( aVector.y == 0.0 )
76 {
77 if( aVector.x >= 0 )
78 m_value = 0.0;
79 else
80 m_value = -180.0;
81 }
82 else if( aVector.x == 0.0 )
83 {
84 if( aVector.y >= 0.0 )
85 m_value = 90.0;
86 else
87 m_value = -90.0;
88 }
89 else if( aVector.x == aVector.y )
90 {
91 if( aVector.x >= 0.0 )
92 m_value = 45.0;
93 else
94 m_value = -180.0 + 45.0;
95 }
96 else if( aVector.x == -aVector.y )
97 {
98 if( aVector.x >= 0.0 )
99 m_value = -45.0;
100 else
101 m_value = 180.0 - 45.0;
102 }
103 else
104 {
105 *this = EDA_ANGLE( atan2( aVector.y, aVector.x ), RADIANS_T );
106 }
107 }
108
109 explicit EDA_ANGLE( const VECTOR2I& aVector )
110 {
111 /* gcc is surprisingly smart in optimizing these conditions in a tree! */
112
113 if( aVector.x == 0 && aVector.y == 0 )
114 {
115 m_value = 0;
116 }
117 else if( aVector.y == 0 )
118 {
119 if( aVector.x >= 0 )
120 m_value = 0.0;
121 else
122 m_value = -180.0;
123 }
124 else if( aVector.x == 0 )
125 {
126 if( aVector.y >= 0 )
127 m_value = 90.0;
128 else
129 m_value = -90.0;
130 }
131 else if( aVector.x == aVector.y )
132 {
133 if( aVector.x >= 0 )
134 m_value = 45.0;
135 else
136 m_value = -180.0 + 45.0;
137 }
138 else if( aVector.x == -aVector.y )
139 {
140 if( aVector.x >= 0 )
141 m_value = -45.0;
142 else
143 m_value = 180.0 - 45.0;
144 }
145 else
146 {
147 *this = EDA_ANGLE( atan2( (double) aVector.y, (double) aVector.x ), RADIANS_T );
148 }
149 }
150
152 m_value( 0.0 )
153 {}
154
155 inline double AsDegrees() const { return m_value; }
156
157 inline int AsTenthsOfADegree() const { return KiROUND( m_value * 10.0 ); }
158
159 inline double AsRadians() const { return m_value * DEGREES_TO_RADIANS; }
160
161 static constexpr double DEGREES_TO_RADIANS = M_PI / 180.0;
162
167 bool IsCardinal() const;
168
173 bool IsCardinal90() const;
174
175 bool IsZero() const
176 {
177 return m_value == 0.0;
178 }
179
180 bool IsHorizontal() const
181 {
182 return m_value == 0.0 || m_value == 180.0;
183 }
184
185 bool IsVertical() const
186 {
187 return m_value == 90.0 || m_value == 270.0;
188 }
189
190 bool IsParallelTo( EDA_ANGLE aAngle ) const
191 {
192 EDA_ANGLE thisNormalized = *this;
193
194 // Normalize90 is inclusive on both ends [-90, +90]
195 // but we need it to be (-90, +90] for this test to work
196 thisNormalized.Normalize90();
197 if( thisNormalized.AsDegrees() == -90.0 )
198 thisNormalized = EDA_ANGLE( 90.0, DEGREES_T );
199
200 aAngle.Normalize90();
201 if( aAngle.AsDegrees() == -90.0 )
202 aAngle = EDA_ANGLE( 90.0, DEGREES_T );
203
204 return ( thisNormalized.AsDegrees() == aAngle.AsDegrees() );
205 }
206
208 {
209 return EDA_ANGLE( -AsDegrees(), DEGREES_T );
210 }
211
212 double Sin() const
213 {
214 EDA_ANGLE test = *this;
215 test.Normalize();
216
217 if( test.m_value == 0.0 || test.m_value == 180.0 )
218 return 0.0;
219 else if( test.m_value == 90.0 )
220 return 1.0;
221 else if( test.m_value == 270.0 )
222 return -1.0;
223 else
224 return sin( AsRadians() );
225 }
226
227 double Cos() const
228 {
229 EDA_ANGLE test = *this;
230 test.Normalize();
231
232 if( test.m_value == 0.0 )
233 return 1.0;
234 else if( test.m_value == 180.0 )
235 return -1.0;
236 else if( test.m_value == 90.0 || test.m_value == 270.0 )
237 return 0.0;
238 else
239 return cos( AsRadians() );
240 }
241
242 double Tan() const { return tan( AsRadians() ); }
243
244 static EDA_ANGLE Arccos( double x ) { return EDA_ANGLE( acos( x ), RADIANS_T ); }
245
246 static EDA_ANGLE Arcsin( double x ) { return EDA_ANGLE( asin( x ), RADIANS_T ); }
247
248 static EDA_ANGLE Arctan( double x ) { return EDA_ANGLE( atan( x ), RADIANS_T ); }
249
250 static EDA_ANGLE Arctan2( double y, double x )
251 {
252 return EDA_ANGLE( atan2( y, x ), RADIANS_T );
253 }
254
256 {
257 while( m_value < -0.0 )
258 m_value += 360.0;
259
260 while( m_value >= 360.0 )
261 m_value -= 360.0;
262
263 return *this;
264 }
265
267 {
268 EDA_ANGLE ret( *this );
269 return ret.Normalize();
270 }
271
273 {
274 while( m_value <= -360.0 )
275 m_value += 360.0;
276
277 while( m_value > 0.0 )
278 m_value -= 360.0;
279
280 return *this;
281 }
282
284 {
285 while( m_value < -90.0 )
286 m_value += 180.0;
287
288 while( m_value > 90.0 )
289 m_value -= 180.0;
290
291 return *this;
292 }
293
295 {
296 while( m_value <= -180.0 )
297 m_value += 360.0;
298
299 while( m_value > 180.0 )
300 m_value -= 360.0;
301
302 return *this;
303 }
304
306 {
307 while( m_value < -360.0 )
308 m_value += 360.0;
309
310 while( m_value >= 360.0 )
311 m_value -= 360.0;
312
313 return *this;
314 }
315
316 EDA_ANGLE KeepUpright() const;
317
318 EDA_ANGLE Round( int digits ) const
319 {
320 EDA_ANGLE angle( *this );
321 double rounded = KiROUND( angle.AsDegrees() * pow( 10.0, digits ) ) / pow( 10.0, digits );
322 angle = EDA_ANGLE( rounded, DEGREES_T );
323 return angle;
324 }
325
327 {
328 *this = EDA_ANGLE( AsDegrees() + aAngle.AsDegrees(), DEGREES_T );
329 return *this;
330 }
331
333 {
334 *this = EDA_ANGLE( AsDegrees() - aAngle.AsDegrees(), DEGREES_T );
335 return *this;
336 }
337
338private:
339 double m_value;
340
341};
342
343
344inline EDA_ANGLE operator-( const EDA_ANGLE& aAngle )
345{
346 return aAngle.Invert();
347}
348
349
350inline EDA_ANGLE operator-( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
351{
352 return EDA_ANGLE( aAngleA.AsDegrees() - aAngleB.AsDegrees(), DEGREES_T );
353}
354
355
356inline EDA_ANGLE operator+( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
357{
358 return EDA_ANGLE( aAngleA.AsDegrees() + aAngleB.AsDegrees(), DEGREES_T );
359}
360
361
362inline EDA_ANGLE operator*( const EDA_ANGLE& aAngleA, double aOperator )
363{
364 return EDA_ANGLE( aAngleA.AsDegrees() * aOperator, DEGREES_T );
365}
366
367
368inline EDA_ANGLE operator/( const EDA_ANGLE& aAngleA, double aOperator )
369{
370 return EDA_ANGLE( aAngleA.AsDegrees() / aOperator, DEGREES_T );
371}
372
373
374inline double operator/( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aOperator )
375{
376 return aAngleA.AsDegrees() / aOperator.AsDegrees();
377}
378
379
380inline bool operator==( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
381{
382 return aAngleA.AsDegrees() == aAngleB.AsDegrees();
383}
384
385
386inline bool operator!=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
387{
388 return aAngleA.AsDegrees() != aAngleB.AsDegrees();
389}
390
391
392inline bool operator>( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
393{
394 return aAngleA.AsDegrees() > aAngleB.AsDegrees();
395}
396
397
398inline bool operator<( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
399{
400 return aAngleA.AsDegrees() < aAngleB.AsDegrees();
401}
402
403
404inline bool operator<=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
405{
406 return aAngleA.AsDegrees() <= aAngleB.AsDegrees();
407}
408
409
410inline bool operator>=( const EDA_ANGLE& aAngleA, const EDA_ANGLE& aAngleB )
411{
412 return aAngleA.AsDegrees() >= aAngleB.AsDegrees();
413}
414
415
416inline std::ostream& operator<<( std::ostream& aStream, const EDA_ANGLE& aAngle )
417{
418 return aStream << aAngle.AsDegrees();
419}
420
421
422namespace std
423{
424inline EDA_ANGLE abs( const EDA_ANGLE& aAngle )
425{
426 return EDA_ANGLE( std::abs( aAngle.AsDegrees() ), DEGREES_T );
427}
428}
429
430
431static constexpr EDA_ANGLE ANGLE_HORIZONTAL{ 0 };
432static constexpr EDA_ANGLE ANGLE_VERTICAL{ 90 };
433static constexpr EDA_ANGLE FULL_CIRCLE{ 360 };
434
435static constexpr EDA_ANGLE ANGLE_0{ 0 };
436static constexpr EDA_ANGLE ANGLE_45{ 45 };
437static constexpr EDA_ANGLE ANGLE_90{ 90 };
438static constexpr EDA_ANGLE ANGLE_135{ 135 };
439static constexpr EDA_ANGLE ANGLE_180{ 180 };
440static constexpr EDA_ANGLE ANGLE_270{ 270 };
441static constexpr EDA_ANGLE ANGLE_360{ 360 };
442
443
444#endif // EDA_ANGLE_H
EDA_ANGLE Normalize()
Definition: eda_angle.h:255
EDA_ANGLE NormalizeNegative()
Definition: eda_angle.h:272
double Sin() const
Definition: eda_angle.h:212
EDA_ANGLE Normalize90()
Definition: eda_angle.h:283
double Tan() const
Definition: eda_angle.h:242
constexpr EDA_ANGLE(double aAngleInDegrees)
Construct an EDA_ANGLE in degrees.
Definition: eda_angle.h:67
int AsTenthsOfADegree() const
Definition: eda_angle.h:157
bool IsParallelTo(EDA_ANGLE aAngle) const
Definition: eda_angle.h:190
double AsDegrees() const
Definition: eda_angle.h:155
EDA_ANGLE Invert() const
Definition: eda_angle.h:207
EDA_ANGLE(const VECTOR2I &aVector)
Definition: eda_angle.h:109
bool IsZero() const
Definition: eda_angle.h:175
bool IsHorizontal() const
Definition: eda_angle.h:180
bool IsCardinal() const
Definition: eda_angle.cpp:40
EDA_ANGLE Normalize180()
Definition: eda_angle.h:294
static EDA_ANGLE Arctan2(double y, double x)
Definition: eda_angle.h:250
EDA_ANGLE KeepUpright() const
Definition: eda_angle.cpp:23
EDA_ANGLE Normalize720()
Definition: eda_angle.h:305
double AsRadians() const
Definition: eda_angle.h:159
bool IsVertical() const
Definition: eda_angle.h:185
EDA_ANGLE & operator-=(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:332
EDA_ANGLE Round(int digits) const
Definition: eda_angle.h:318
EDA_ANGLE & operator+=(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:326
EDA_ANGLE(const VECTOR2D &aVector)
Definition: eda_angle.h:69
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:161
bool IsCardinal90() const
Definition: eda_angle.cpp:54
double Cos() const
Definition: eda_angle.h:227
double m_value
value in degrees
Definition: eda_angle.h:339
static EDA_ANGLE Arctan(double x)
Definition: eda_angle.h:248
static EDA_ANGLE Arcsin(double x)
Definition: eda_angle.h:246
EDA_ANGLE Normalized() const
Definition: eda_angle.h:266
static EDA_ANGLE Arccos(double x)
Definition: eda_angle.h:244
EDA_ANGLE operator/(const EDA_ANGLE &aAngleA, double aOperator)
Definition: eda_angle.h:368
bool operator>(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:392
bool operator>=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:410
EDA_ANGLE operator*(const EDA_ANGLE &aAngleA, double aOperator)
Definition: eda_angle.h:362
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
bool operator<=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:404
std::ostream & operator<<(std::ostream &aStream, const EDA_ANGLE &aAngle)
Definition: eda_angle.h:416
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:344
bool operator<(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:398
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:432
bool operator==(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:380
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:436
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:440
static constexpr EDA_ANGLE FULL_CIRCLE
Definition: eda_angle.h:433
static constexpr EDA_ANGLE ANGLE_360
Definition: eda_angle.h:441
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:439
EDA_ANGLE operator+(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:356
static constexpr EDA_ANGLE ANGLE_135
Definition: eda_angle.h:438
bool operator!=(const EDA_ANGLE &aAngleA, const EDA_ANGLE &aAngleB)
Definition: eda_angle.h:386
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118