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 // No unique circumcircle exists if any two of the three points coincide
374 // Bbox below catches all three; pairwise checks below catch just one pair
375 constexpr double kClusterExtent = 5.0;
376
377 // A pair separated by more than integer rounding is a real, if small, arc. This is not the
378 // cluster extent above: three points inside a 5 IU box are all noise, but two points 4 IU
379 // apart with a distant third still span a healthy triangle
380 constexpr double kCoincidentRadius = 2.0;
381 constexpr double kCoincidentRadiusSquared = kCoincidentRadius * kCoincidentRadius;
382
383 auto [minX, maxX] = std::minmax( { aStart.x, aMid.x, aEnd.x } );
384 auto [minY, maxY] = std::minmax( { aStart.y, aMid.y, aEnd.y } );
385
386 if( maxX - minX < kClusterExtent && maxY - minY < kClusterExtent )
387 {
388 return VECTOR2D( ( aStart.x + aMid.x + aEnd.x ) / 3.0,
389 ( aStart.y + aMid.y + aEnd.y ) / 3.0 );
390 }
391
392 auto coincident = []( const VECTOR2D& a, const VECTOR2D& b )
393 {
394 return ( a - b ).SquaredEuclideanNorm() < kCoincidentRadiusSquared;
395 };
396
397 // Two distinct points fall back to the chord midpoint, same as the diameter-arc paths below
398 if( coincident( aStart, aMid ) || coincident( aMid, aEnd ) )
399 return VECTOR2D( ( aStart.x + aEnd.x ) / 2.0, ( aStart.y + aEnd.y ) / 2.0 );
400
401 if( coincident( aStart, aEnd ) )
402 return VECTOR2D( ( aStart.x + aMid.x ) / 2.0, ( aStart.y + aMid.y ) / 2.0 );
403
405
406 double yDelta_21 = aMid.y - aStart.y;
407 double xDelta_21 = aMid.x - aStart.x;
408 double yDelta_32 = aEnd.y - aMid.y;
409 double xDelta_32 = aEnd.x - aMid.x;
410
411 // This is a special case for aMid as the half-way point when aSlope = 0 and bSlope = inf
412 // or the other way around. In that case, the center lies in a straight line between
413 // aStart and aEnd
414 if( ( ( xDelta_21 == 0.0 ) && ( yDelta_32 == 0.0 ) ) ||
415 ( ( yDelta_21 == 0.0 ) && ( xDelta_32 == 0.0 ) ) )
416 {
417 center.x = ( aStart.x + aEnd.x ) / 2.0;
418 center.y = ( aStart.y + aEnd.y ) / 2.0 ;
419 return center;
420 }
421
422 // Prevent div-by-0 errors
423 if( xDelta_21 == 0.0 )
424 xDelta_21 = std::numeric_limits<double>::epsilon();
425
426 if( xDelta_32 == 0.0 )
427 xDelta_32 = -std::numeric_limits<double>::epsilon();
428
429 double aSlope = yDelta_21 / xDelta_21;
430 double bSlope = yDelta_32 / xDelta_32;
431
432 // Guard the y-deltas after the slopes are taken so a horizontal chord keeps its exact zero
433 // slope while the 0.5/yDelta uncertainty terms below stay finite instead of a NaN-yielding inf
434 if( yDelta_21 == 0.0 )
435 yDelta_21 = std::numeric_limits<double>::epsilon();
436
437 if( yDelta_32 == 0.0 )
438 yDelta_32 = std::numeric_limits<double>::epsilon();
439
440 double daSlope = aSlope * VECTOR2D( 0.5 / yDelta_21, 0.5 / xDelta_21 ).EuclideanNorm();
441 double dbSlope = bSlope * VECTOR2D( 0.5 / yDelta_32, 0.5 / xDelta_32 ).EuclideanNorm();
442
443 if( aSlope == bSlope )
444 {
445 if( aStart == aEnd )
446 {
447 // This is a special case for a 360 degrees arc. In this case, the center is
448 // halfway between the midpoint and either end point.
449 center.x = ( aStart.x + aMid.x ) / 2.0;
450 center.y = ( aStart.y + aMid.y ) / 2.0 ;
451 return center;
452 }
453 else
454 {
455 // If the points are colinear, the center is at infinity, so offset
456 // the slope by a minimal amount
457 // Warning: This will induce a small error in the center location
458 aSlope += std::numeric_limits<double>::epsilon();
459 bSlope -= std::numeric_limits<double>::epsilon();
460 }
461 }
462#ifdef USE_ALTERNATE_CENTER_ALGO
463 // We can call ArcCenterFrom3Points from here because special cases are filtered.
464 CircleCenterFrom3Points( aStart, aMid, aEnd, &center );
465 return center;
466#endif
467
468 // Prevent divide by zero error
469 // a small value is used. std::numeric_limits<double>::epsilon() is too small and
470 // generate false results
471 if( aSlope == 0.0 )
472 aSlope = 1e-10;
473 if( bSlope == 0.0 )
474 bSlope = 1e-10;
475
476 // What follows is the calculation of the center using the slope of the two lines as well as
477 // the propagated error that occurs when rounding to the nearest nanometer. The error can be
478 // ±0.5 units but can add up to multiple nanometers after the full calculation is performed.
479 // All variables starting with `d` are the delta of that variable. This is approximately equal
480 // to the standard deviation.
481 // We ignore the possible covariance between variables. We also truncate our series expansion
482 // at the first term. These are reasonable assumptions as the worst-case scenario is that we
483 // underestimate the potential uncertainty, which would potentially put us back at the status
484 // quo.
485 double abSlopeStartEndY = aSlope * bSlope * ( aStart.y - aEnd.y );
486 double dabSlopeStartEndY = abSlopeStartEndY *
487 std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
488 + ( dbSlope / bSlope * dbSlope / bSlope )
489 + ( M_SQRT1_2 / ( aStart.y - aEnd.y )
490 * M_SQRT1_2 / ( aStart.y - aEnd.y ) ) );
491
492 double bSlopeStartMidX = bSlope * ( aStart.x + aMid.x );
493 double dbSlopeStartMidX = bSlopeStartMidX * std::sqrt( ( dbSlope / bSlope * dbSlope / bSlope )
494 + ( M_SQRT1_2 / ( aStart.x + aMid.x )
495 * M_SQRT1_2 / ( aStart.x + aMid.x ) ) );
496
497 double aSlopeMidEndX = aSlope * ( aMid.x + aEnd.x );
498 double daSlopeMidEndX = aSlopeMidEndX * std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
499 + ( M_SQRT1_2 / ( aMid.x + aEnd.x )
500 * M_SQRT1_2 / ( aMid.x + aEnd.x ) ) );
501
502 double twiceBASlopeDiff = 2 * ( bSlope - aSlope );
503 double dtwiceBASlopeDiff = 2 * std::sqrt( dbSlope * dbSlope + daSlope * daSlope );
504
505 double centerNumeratorX = abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX;
506 double dCenterNumeratorX = std::sqrt( dabSlopeStartEndY * dabSlopeStartEndY
507 + dbSlopeStartMidX * dbSlopeStartMidX
508 + daSlopeMidEndX * daSlopeMidEndX );
509
510 double centerX = ( abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX ) / twiceBASlopeDiff;
511 double dCenterX = centerX * std::sqrt( ( dCenterNumeratorX / centerNumeratorX *
512 dCenterNumeratorX / centerNumeratorX )
513 + ( dtwiceBASlopeDiff / twiceBASlopeDiff *
514 dtwiceBASlopeDiff / twiceBASlopeDiff ) );
515
516
517 double centerNumeratorY = ( ( aStart.x + aMid.x ) / 2.0 - centerX );
518 double dCenterNumeratorY = std::sqrt( 1.0 / 8.0 + dCenterX * dCenterX );
519
520 double centerFirstTerm = centerNumeratorY / aSlope;
521 double dcenterFirstTermY = centerFirstTerm * std::sqrt(
522 ( dCenterNumeratorY/ centerNumeratorY *
523 dCenterNumeratorY / centerNumeratorY )
524 + ( daSlope / aSlope * daSlope / aSlope ) );
525
526 double centerY = centerFirstTerm + ( aStart.y + aMid.y ) / 2.0;
527 double dCenterY = std::sqrt( dcenterFirstTermY * dcenterFirstTermY + 1.0 / 8.0 );
528
529 double rounded100CenterX = std::floor( ( centerX + 50.0 ) / 100.0 ) * 100.0;
530 double rounded100CenterY = std::floor( ( centerY + 50.0 ) / 100.0 ) * 100.0;
531 double rounded10CenterX = std::floor( ( centerX + 5.0 ) / 10.0 ) * 10.0;
532 double rounded10CenterY = std::floor( ( centerY + 5.0 ) / 10.0 ) * 10.0;
533
534 // The last step is to find the nice, round numbers near our baseline estimate and see if
535 // they are within our uncertainty range. If they are, then we use this round value as the
536 // true value. This is justified because ALL values within the uncertainty range are equally
537 // true. Using a round number will make sure that we are on a multiple of 1mil or 100nm
538 // when calculating centers.
539 if( std::abs( rounded100CenterX - centerX ) < dCenterX &&
540 std::abs( rounded100CenterY - centerY ) < dCenterY )
541 {
542 center.x = rounded100CenterX;
543 center.y = rounded100CenterY;
544 }
545 else if( std::abs( rounded10CenterX - centerX ) < dCenterX &&
546 std::abs( rounded10CenterY - centerY ) < dCenterY )
547 {
548 center.x = rounded10CenterX;
549 center.y = rounded10CenterY;
550 }
551 else
552 {
553 center.x = centerX;
554 center.y = centerY;
555 }
556
557
558 return center;
559}
560
561
562const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
563{
564 VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
565 VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
566 VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
567 VECTOR2D dCenter = CalcArcCenter( dStart, dMid, dEnd );
568
569 VECTOR2I iCenter;
570
571 iCenter.x = KiROUND( std::clamp( dCenter.x,
572 double( std::numeric_limits<int>::min() + 100 ),
573 double( std::numeric_limits<int>::max() - 100 ) ) );
574
575 iCenter.y = KiROUND( std::clamp( dCenter.y,
576 double( std::numeric_limits<int>::min() + 100 ),
577 double( std::numeric_limits<int>::max() - 100 ) ) );
578
579 return iCenter;
580}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
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:422
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:424
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:427
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:428
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:426
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
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