KiCad PCB EDA Suite
Loading...
Searching...
No Matches
trigo.cpp
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) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
25
26#include <algorithm> // for std::clamp
27#include <limits> // for numeric_limits
28#include <cstdlib> // for abs
29#include <type_traits> // for swap
30
31#include <geometry/seg.h>
32#include <math/util.h>
33#include <math/vector2d.h> // for VECTOR2I
34#include <trigo.h>
35
36
37/*
38CircleCenterFrom3Points calculate the center of a circle defined by 3 points
39It is similar to CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
40but it was needed to debug CalcArcCenter, so I keep it available for other issues in CalcArcCenter
41
42The perpendicular bisector of the segment between two points is the
43set of all points equidistant from both. So if you take the
44perpendicular bisector of (x1,y1) and (x2,y2) and the perpendicular
45bisector of the segment from (x2,y2) to (x3,y3) and find the
46intersection of those lines, that point will be the center.
47
48To find the equation of the perpendicular bisector of (x1,y1) to (x2,y2),
49you know that it passes through the midpoint of the segment:
50((x1+x2)/2,(y1+y2)/2), and if the slope of the line
51connecting (x1,y1) to (x2,y2) is m, the slope of the perpendicular
52bisector is -1/m. Work out the equations for the two lines, find
53their intersection, and bingo! You've got the coordinates of the center.
54
55An error should occur if the three points lie on a line, and you'll
56need special code to check for the case where one of the slopes is zero.
57
58see https://web.archive.org/web/20171223103555/http://mathforum.org/library/drmath/view/54323.html
59*/
60
61//#define USE_ALTERNATE_CENTER_ALGO
62
63#ifdef USE_ALTERNATE_CENTER_ALGO
64bool CircleCenterFrom3Points( const VECTOR2D& p1, const VECTOR2D& p2, const VECTOR2D& p3, VECTOR2D* aCenter )
65{
66 // Move coordinate origin to p2, to simplify calculations
67 VECTOR2D b = p1 - p2;
68 VECTOR2D d = p3 - p2;
69 double bc = ( b.x*b.x + b.y*b.y ) / 2.0;
70 double cd = ( -d.x*d.x - d.y*d.y ) / 2.0;
71 double det = -b.x*d.y + d.x*b.y;
72
73 if( fabs(det) < 1.0e-6 ) // arbitrary limit to avoid divide by 0
74 return false;
75
76 det = 1/det;
77 aCenter->x = ( -bc*d.y - cd*b.y ) * det;
78 aCenter->y = ( b.x*cd + d.x*bc ) * det;
79 *aCenter += p2;
80
81 return true;
82}
83#endif
84
85bool IsPointOnSegment( const VECTOR2I& aSegStart, const VECTOR2I& aSegEnd,
86 const VECTOR2I& aTestPoint )
87{
88 VECTOR2I vectSeg = aSegEnd - aSegStart; // Vector from S1 to S2
89 VECTOR2I vectPoint = aTestPoint - aSegStart; // Vector from S1 to P
90
91 // Use long long here to avoid overflow in calculations
92 if( (long long) vectSeg.x * vectPoint.y - (long long) vectSeg.y * vectPoint.x )
93 return false; /* Cross product non-zero, vectors not parallel */
94
95 if( ( (long long) vectSeg.x * vectPoint.x + (long long) vectSeg.y * vectPoint.y ) <
96 ( (long long) vectPoint.x * vectPoint.x + (long long) vectPoint.y * vectPoint.y ) )
97 return false; /* Point not on segment */
98
99 return true;
100}
101
102
103bool SegmentIntersectsSegment( const VECTOR2I& a_p1_l1, const VECTOR2I& a_p2_l1,
104 const VECTOR2I& a_p1_l2, const VECTOR2I& a_p2_l2,
105 VECTOR2I* aIntersectionPoint )
106{
107
108 // We are forced to use 64bit ints because the internal units can overflow 32bit ints when
109 // multiplied with each other, the alternative would be to scale the units down (i.e. divide
110 // by a fixed number).
111 int64_t dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
112 int64_t num_a, num_b, den;
113
114 // Test for intersection within the bounds of both line segments using line equations of the
115 // form:
116 // x_k(u_k) = u_k * dX_k + x_k(0)
117 // y_k(u_k) = u_k * dY_k + y_k(0)
118 // with 0 <= u_k <= 1 and k = [ a, b ]
119
120 dX_a = int64_t{ a_p2_l1.x } - a_p1_l1.x;
121 dY_a = int64_t{ a_p2_l1.y } - a_p1_l1.y;
122 dX_b = int64_t{ a_p2_l2.x } - a_p1_l2.x;
123 dY_b = int64_t{ a_p2_l2.y } - a_p1_l2.y;
124 dX_ab = int64_t{ a_p1_l2.x } - a_p1_l1.x;
125 dY_ab = int64_t{ a_p1_l2.y } - a_p1_l1.y;
126
127 den = dY_a * dX_b - dY_b * dX_a ;
128
129 // Check if lines are parallel.
130 if( den == 0 )
131 return false;
132
133 num_a = dY_ab * dX_b - dY_b * dX_ab;
134 num_b = dY_ab * dX_a - dY_a * dX_ab;
135
136 // Only compute the intersection point if requested.
137 if( aIntersectionPoint )
138 {
139 *aIntersectionPoint = a_p1_l1;
140 aIntersectionPoint->x += KiROUND( dX_a * ( double )num_a / ( double )den );
141 aIntersectionPoint->y += KiROUND( dY_a * ( double )num_b / ( double )den );
142 }
143
144 if( den < 0 )
145 {
146 den = -den;
147 num_a = -num_a;
148 num_b = -num_b;
149 }
150
151 // Test sign( u_a ) and return false if negative.
152 if( num_a < 0 )
153 return false;
154
155 // Test sign( u_b ) and return false if negative.
156 if( num_b < 0 )
157 return false;
158
159 // Test to ensure (u_a <= 1).
160 if( num_a > den )
161 return false;
162
163 // Test to ensure (u_b <= 1).
164 if( num_b > den )
165 return false;
166
167 return true;
168}
169
170
171bool TestSegmentHit( const VECTOR2I& aRefPoint, const VECTOR2I& aStart, const VECTOR2I& aEnd,
172 int aDist )
173{
174 int xmin = aStart.x;
175 int xmax = aEnd.x;
176 int ymin = aStart.y;
177 int ymax = aEnd.y;
178 VECTOR2I delta = aStart - aRefPoint;
179
180 if( xmax < xmin )
181 std::swap( xmax, xmin );
182
183 if( ymax < ymin )
184 std::swap( ymax, ymin );
185
186 // Check if we are outside of the bounding box.
187 if( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) )
188 return false;
189
190 if( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) )
191 return false;
192
193 // Eliminate easy cases.
194 if( aStart.x == aEnd.x && aRefPoint.y > ymin && aRefPoint.y < ymax )
195 return std::abs( delta.x ) <= aDist;
196
197 if( aStart.y == aEnd.y && aRefPoint.x > xmin && aRefPoint.x < xmax )
198 return std::abs( delta.y ) <= aDist;
199
200 SEG segment( aStart, aEnd );
201 return segment.SquaredDistance( aRefPoint ) < SEG::Square( aDist + 1 );
202}
203
204
205const VECTOR2I CalcArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
206 bool aMinArcAngle )
207{
208 VECTOR2I startVector = aStart - aCenter;
209 VECTOR2I endVector = aEnd - aCenter;
210
211 EDA_ANGLE startAngle( startVector );
212 EDA_ANGLE endAngle( endVector );
213 EDA_ANGLE midPointRotAngle = ( startAngle - endAngle ).Normalize180() / 2;
214
215 if( !aMinArcAngle )
216 midPointRotAngle += ANGLE_180;
217
218 VECTOR2I newMid = aStart;
219 RotatePoint( newMid, aCenter, midPointRotAngle );
220
221 return newMid;
222}
223
224
225void RotatePoint( int* pX, int* pY, const EDA_ANGLE& aAngle )
226{
227 VECTOR2I pt;
228 EDA_ANGLE angle = aAngle;
229
230 angle.Normalize();
231
232 // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
233 if( angle == ANGLE_0 )
234 {
235 pt = VECTOR2I( *pX, *pY );
236 }
237 else if( angle == ANGLE_90 ) /* sin = 1, cos = 0 */
238 {
239 pt = VECTOR2I( *pY, -*pX );
240 }
241 else if( angle == ANGLE_180 ) /* sin = 0, cos = -1 */
242 {
243 pt = VECTOR2I( -*pX, -*pY );
244 }
245 else if( angle == ANGLE_270 ) /* sin = -1, cos = 0 */
246 {
247 pt = VECTOR2I( -*pY, *pX );
248 }
249 else
250 {
251 double sinus = angle.Sin();
252 double cosinus = angle.Cos();
253
254 pt.x = KiROUND( ( *pY * sinus ) + ( *pX * cosinus ) );
255 pt.y = KiROUND( ( *pY * cosinus ) - ( *pX * sinus ) );
256 }
257
258 *pX = pt.x;
259 *pY = pt.y;
260}
261
262
263void RotatePoint( int* pX, int* pY, int cx, int cy, const EDA_ANGLE& angle )
264{
265 int ox, oy;
266
267 ox = *pX - cx;
268 oy = *pY - cy;
269
270 RotatePoint( &ox, &oy, angle );
271
272 *pX = ox + cx;
273 *pY = oy + cy;
274}
275
276
277void RotatePoint( double* pX, double* pY, double cx, double cy, const EDA_ANGLE& angle )
278{
279 double ox, oy;
280
281 ox = *pX - cx;
282 oy = *pY - cy;
283
284 RotatePoint( &ox, &oy, angle );
285
286 *pX = ox + cx;
287 *pY = oy + cy;
288}
289
290
291void RotatePoint( double* pX, double* pY, const EDA_ANGLE& aAngle )
292{
293 EDA_ANGLE angle = aAngle;
294 VECTOR2D pt;
295
296 angle.Normalize();
297
298 // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
299 if( angle == ANGLE_0 )
300 {
301 pt = VECTOR2D( *pX, *pY );
302 }
303 else if( angle == ANGLE_90 ) /* sin = 1, cos = 0 */
304 {
305 pt = VECTOR2D( *pY, -*pX );
306 }
307 else if( angle == ANGLE_180 ) /* sin = 0, cos = -1 */
308 {
309 pt = VECTOR2D( -*pX, -*pY );
310 }
311 else if( angle == ANGLE_270 ) /* sin = -1, cos = 0 */
312 {
313 pt = VECTOR2D( -*pY, *pX );
314 }
315 else
316 {
317 double sinus = angle.Sin();
318 double cosinus = angle.Cos();
319
320 pt.x = ( *pY * sinus ) + ( *pX * cosinus );
321 pt.y = ( *pY * cosinus ) - ( *pX * sinus );
322 }
323
324 *pX = pt.x;
325 *pY = pt.y;
326}
327
328
329const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd,
330 const EDA_ANGLE& aAngle )
331{
332 EDA_ANGLE angle( aAngle );
333 VECTOR2D start = aStart;
334 VECTOR2D end = aEnd;
335
336 if( angle < ANGLE_0 )
337 {
338 std::swap( start, end );
339 angle = -angle;
340 }
341
342 if( angle > ANGLE_180 )
343 {
344 std::swap( start, end );
345 angle = ANGLE_360 - angle;
346 }
347
348 double chord = ( start - end ).EuclideanNorm();
349 double sinHalfAngle = ( angle / 2.0 ).Sin();
350
351 // A zero arc angle has no defined center, so fall back to the chord midpoint
352 if( sinHalfAngle == 0.0 )
353 return VECTOR2D( ( start + end ) / 2.0 );
354
355 double r = ( chord / 2.0 ) / sinHalfAngle;
356 double d_squared = r * r - chord* chord / 4.0;
357 double d = 0.0;
358
359 if( d_squared > 0.0 )
360 d = sqrt( d_squared );
361
362 VECTOR2D vec2 = VECTOR2D(end - start).Resize( d );
363 VECTOR2D vc = VECTOR2D(end - start).Resize( chord / 2 );
364
365 RotatePoint( vec2, -ANGLE_90 );
366
367 return VECTOR2D( start + vc + vec2 );
368}
369
370
371const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
372{
373 // If the three input points are clustered within a 10 IU bounding box, no
374 // meaningful circumcircle exists so return the centroid
375 constexpr double kCoincidentRadius = 5.0;
376
377 auto [minX, maxX] = std::minmax( { aStart.x, aMid.x, aEnd.x } );
378 auto [minY, maxY] = std::minmax( { aStart.y, aMid.y, aEnd.y } );
379
380 if( maxX - minX < kCoincidentRadius && maxY - minY < kCoincidentRadius )
381 {
382 return VECTOR2D( ( aStart.x + aMid.x + aEnd.x ) / 3.0,
383 ( aStart.y + aMid.y + aEnd.y ) / 3.0 );
384 }
385
387
388 double yDelta_21 = aMid.y - aStart.y;
389 double xDelta_21 = aMid.x - aStart.x;
390 double yDelta_32 = aEnd.y - aMid.y;
391 double xDelta_32 = aEnd.x - aMid.x;
392
393 // This is a special case for aMid as the half-way point when aSlope = 0 and bSlope = inf
394 // or the other way around. In that case, the center lies in a straight line between
395 // aStart and aEnd
396 if( ( ( xDelta_21 == 0.0 ) && ( yDelta_32 == 0.0 ) ) ||
397 ( ( yDelta_21 == 0.0 ) && ( xDelta_32 == 0.0 ) ) )
398 {
399 center.x = ( aStart.x + aEnd.x ) / 2.0;
400 center.y = ( aStart.y + aEnd.y ) / 2.0 ;
401 return center;
402 }
403
404 // Prevent div-by-0 errors
405 if( xDelta_21 == 0.0 )
406 xDelta_21 = std::numeric_limits<double>::epsilon();
407
408 if( xDelta_32 == 0.0 )
409 xDelta_32 = -std::numeric_limits<double>::epsilon();
410
411 double aSlope = yDelta_21 / xDelta_21;
412 double bSlope = yDelta_32 / xDelta_32;
413
414 // Guard the y-deltas after the slopes are taken so a horizontal chord keeps its exact zero
415 // slope while the 0.5/yDelta uncertainty terms below stay finite instead of a NaN-yielding inf
416 if( yDelta_21 == 0.0 )
417 yDelta_21 = std::numeric_limits<double>::epsilon();
418
419 if( yDelta_32 == 0.0 )
420 yDelta_32 = std::numeric_limits<double>::epsilon();
421
422 double daSlope = aSlope * VECTOR2D( 0.5 / yDelta_21, 0.5 / xDelta_21 ).EuclideanNorm();
423 double dbSlope = bSlope * VECTOR2D( 0.5 / yDelta_32, 0.5 / xDelta_32 ).EuclideanNorm();
424
425 if( aSlope == bSlope )
426 {
427 if( aStart == aEnd )
428 {
429 // This is a special case for a 360 degrees arc. In this case, the center is
430 // halfway between the midpoint and either end point.
431 center.x = ( aStart.x + aMid.x ) / 2.0;
432 center.y = ( aStart.y + aMid.y ) / 2.0 ;
433 return center;
434 }
435 else
436 {
437 // If the points are colinear, the center is at infinity, so offset
438 // the slope by a minimal amount
439 // Warning: This will induce a small error in the center location
440 aSlope += std::numeric_limits<double>::epsilon();
441 bSlope -= std::numeric_limits<double>::epsilon();
442 }
443 }
444#ifdef USE_ALTERNATE_CENTER_ALGO
445 // We can call ArcCenterFrom3Points from here because special cases are filtered.
446 CircleCenterFrom3Points( aStart, aMid, aEnd, &center );
447 return center;
448#endif
449
450 // Prevent divide by zero error
451 // a small value is used. std::numeric_limits<double>::epsilon() is too small and
452 // generate false results
453 if( aSlope == 0.0 )
454 aSlope = 1e-10;
455 if( bSlope == 0.0 )
456 bSlope = 1e-10;
457
458 // What follows is the calculation of the center using the slope of the two lines as well as
459 // the propagated error that occurs when rounding to the nearest nanometer. The error can be
460 // ±0.5 units but can add up to multiple nanometers after the full calculation is performed.
461 // All variables starting with `d` are the delta of that variable. This is approximately equal
462 // to the standard deviation.
463 // We ignore the possible covariance between variables. We also truncate our series expansion
464 // at the first term. These are reasonable assumptions as the worst-case scenario is that we
465 // underestimate the potential uncertainty, which would potentially put us back at the status
466 // quo.
467 double abSlopeStartEndY = aSlope * bSlope * ( aStart.y - aEnd.y );
468 double dabSlopeStartEndY = abSlopeStartEndY *
469 std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
470 + ( dbSlope / bSlope * dbSlope / bSlope )
471 + ( M_SQRT1_2 / ( aStart.y - aEnd.y )
472 * M_SQRT1_2 / ( aStart.y - aEnd.y ) ) );
473
474 double bSlopeStartMidX = bSlope * ( aStart.x + aMid.x );
475 double dbSlopeStartMidX = bSlopeStartMidX * std::sqrt( ( dbSlope / bSlope * dbSlope / bSlope )
476 + ( M_SQRT1_2 / ( aStart.x + aMid.x )
477 * M_SQRT1_2 / ( aStart.x + aMid.x ) ) );
478
479 double aSlopeMidEndX = aSlope * ( aMid.x + aEnd.x );
480 double daSlopeMidEndX = aSlopeMidEndX * std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
481 + ( M_SQRT1_2 / ( aMid.x + aEnd.x )
482 * M_SQRT1_2 / ( aMid.x + aEnd.x ) ) );
483
484 double twiceBASlopeDiff = 2 * ( bSlope - aSlope );
485 double dtwiceBASlopeDiff = 2 * std::sqrt( dbSlope * dbSlope + daSlope * daSlope );
486
487 double centerNumeratorX = abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX;
488 double dCenterNumeratorX = std::sqrt( dabSlopeStartEndY * dabSlopeStartEndY
489 + dbSlopeStartMidX * dbSlopeStartMidX
490 + daSlopeMidEndX * daSlopeMidEndX );
491
492 double centerX = ( abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX ) / twiceBASlopeDiff;
493 double dCenterX = centerX * std::sqrt( ( dCenterNumeratorX / centerNumeratorX *
494 dCenterNumeratorX / centerNumeratorX )
495 + ( dtwiceBASlopeDiff / twiceBASlopeDiff *
496 dtwiceBASlopeDiff / twiceBASlopeDiff ) );
497
498
499 double centerNumeratorY = ( ( aStart.x + aMid.x ) / 2.0 - centerX );
500 double dCenterNumeratorY = std::sqrt( 1.0 / 8.0 + dCenterX * dCenterX );
501
502 double centerFirstTerm = centerNumeratorY / aSlope;
503 double dcenterFirstTermY = centerFirstTerm * std::sqrt(
504 ( dCenterNumeratorY/ centerNumeratorY *
505 dCenterNumeratorY / centerNumeratorY )
506 + ( daSlope / aSlope * daSlope / aSlope ) );
507
508 double centerY = centerFirstTerm + ( aStart.y + aMid.y ) / 2.0;
509 double dCenterY = std::sqrt( dcenterFirstTermY * dcenterFirstTermY + 1.0 / 8.0 );
510
511 double rounded100CenterX = std::floor( ( centerX + 50.0 ) / 100.0 ) * 100.0;
512 double rounded100CenterY = std::floor( ( centerY + 50.0 ) / 100.0 ) * 100.0;
513 double rounded10CenterX = std::floor( ( centerX + 5.0 ) / 10.0 ) * 10.0;
514 double rounded10CenterY = std::floor( ( centerY + 5.0 ) / 10.0 ) * 10.0;
515
516 // The last step is to find the nice, round numbers near our baseline estimate and see if
517 // they are within our uncertainty range. If they are, then we use this round value as the
518 // true value. This is justified because ALL values within the uncertainty range are equally
519 // true. Using a round number will make sure that we are on a multiple of 1mil or 100nm
520 // when calculating centers.
521 if( std::abs( rounded100CenterX - centerX ) < dCenterX &&
522 std::abs( rounded100CenterY - centerY ) < dCenterY )
523 {
524 center.x = rounded100CenterX;
525 center.y = rounded100CenterY;
526 }
527 else if( std::abs( rounded10CenterX - centerX ) < dCenterX &&
528 std::abs( rounded10CenterY - centerY ) < dCenterY )
529 {
530 center.x = rounded10CenterX;
531 center.y = rounded10CenterY;
532 }
533 else
534 {
535 center.x = centerX;
536 center.y = centerY;
537 }
538
539
540 return center;
541}
542
543
544const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
545{
546 VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
547 VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
548 VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
549 VECTOR2D dCenter = CalcArcCenter( dStart, dMid, dEnd );
550
551 VECTOR2I iCenter;
552
553 iCenter.x = KiROUND( std::clamp( dCenter.x,
554 double( std::numeric_limits<int>::min() + 100 ),
555 double( std::numeric_limits<int>::max() - 100 ) ) );
556
557 iCenter.y = KiROUND( std::clamp( dCenter.y,
558 double( std::numeric_limits<int>::min() + 100 ),
559 double( std::numeric_limits<int>::max() - 100 ) ) );
560
561 return iCenter;
562}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double Sin() const
Definition eda_angle.h:178
double Cos() const
Definition eda_angle.h:197
Definition seg.h:38
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:76
static SEG::ecoord Square(int a)
Definition seg.h:119
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:381
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
VECTOR2I center
VECTOR2I end
int delta
const VECTOR2I CalcArcMid(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aMinArcAngle)
Return the middle point of an arc, half-way between aStart and aEnd.
Definition trigo.cpp:205
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition trigo.cpp:171
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
bool SegmentIntersectsSegment(const VECTOR2I &a_p1_l1, const VECTOR2I &a_p2_l1, const VECTOR2I &a_p1_l2, const VECTOR2I &a_p2_l2, VECTOR2I *aIntersectionPoint)
Test if two lines intersect.
Definition trigo.cpp:103
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition trigo.cpp:85
const VECTOR2D CalcArcCenter(const VECTOR2D &aStart, const VECTOR2D &aEnd, const EDA_ANGLE &aAngle)
Definition trigo.cpp:329
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682