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