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 <cmath>
29#include <cstdlib> // for abs
30#include <type_traits> // for swap
31
32#include <geometry/seg.h>
33#include <math/util.h>
34#include <math/wide_int.h>
35#include <math/vector2d.h> // for VECTOR2I
36#include <trigo.h>
37
38
39/*
40CircleCenterFrom3Points calculate the center of a circle defined by 3 points
41It is similar to CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
42but it was needed to debug CalcArcCenter, so I keep it available for other issues in CalcArcCenter
43
44The perpendicular bisector of the segment between two points is the
45set of all points equidistant from both. So if you take the
46perpendicular bisector of (x1,y1) and (x2,y2) and the perpendicular
47bisector of the segment from (x2,y2) to (x3,y3) and find the
48intersection of those lines, that point will be the center.
49
50To find the equation of the perpendicular bisector of (x1,y1) to (x2,y2),
51you know that it passes through the midpoint of the segment:
52((x1+x2)/2,(y1+y2)/2), and if the slope of the line
53connecting (x1,y1) to (x2,y2) is m, the slope of the perpendicular
54bisector is -1/m. Work out the equations for the two lines, find
55their intersection, and bingo! You've got the coordinates of the center.
56
57An error should occur if the three points lie on a line, and you'll
58need special code to check for the case where one of the slopes is zero.
59
60see https://web.archive.org/web/20171223103555/http://mathforum.org/library/drmath/view/54323.html
61*/
62
63//#define USE_ALTERNATE_CENTER_ALGO
64
65#ifdef USE_ALTERNATE_CENTER_ALGO
66bool CircleCenterFrom3Points( const VECTOR2D& p1, const VECTOR2D& p2, const VECTOR2D& p3, VECTOR2D* aCenter )
67{
68 // Move coordinate origin to p2, to simplify calculations
69 VECTOR2D b = p1 - p2;
70 VECTOR2D d = p3 - p2;
71 double bc = ( b.x*b.x + b.y*b.y ) / 2.0;
72 double cd = ( -d.x*d.x - d.y*d.y ) / 2.0;
73 double det = -b.x*d.y + d.x*b.y;
74
75 if( fabs(det) < 1.0e-6 ) // arbitrary limit to avoid divide by 0
76 return false;
77
78 det = 1/det;
79 aCenter->x = ( -bc*d.y - cd*b.y ) * det;
80 aCenter->y = ( b.x*cd + d.x*bc ) * det;
81 *aCenter += p2;
82
83 return true;
84}
85#endif
86
87bool IsPointOnSegment( const VECTOR2I& aSegStart, const VECTOR2I& aSegEnd,
88 const VECTOR2I& aTestPoint )
89{
90 VECTOR2I vectSeg = aSegEnd - aSegStart; // Vector from S1 to S2
91 VECTOR2I vectPoint = aTestPoint - aSegStart; // Vector from S1 to P
92
93 // Use long long here to avoid overflow in calculations
94 if( (long long) vectSeg.x * vectPoint.y - (long long) vectSeg.y * vectPoint.x )
95 return false; /* Cross product non-zero, vectors not parallel */
96
97 if( ( (long long) vectSeg.x * vectPoint.x + (long long) vectSeg.y * vectPoint.y ) <
98 ( (long long) vectPoint.x * vectPoint.x + (long long) vectPoint.y * vectPoint.y ) )
99 return false; /* Point not on segment */
100
101 return true;
102}
103
104
105bool SegmentIntersectsSegment( const VECTOR2I& a_p1_l1, const VECTOR2I& a_p2_l1,
106 const VECTOR2I& a_p1_l2, const VECTOR2I& a_p2_l2,
107 VECTOR2I* aIntersectionPoint )
108{
109
110 // We are forced to use 64bit ints because the internal units can overflow 32bit ints when
111 // multiplied with each other, the alternative would be to scale the units down (i.e. divide
112 // by a fixed number).
113 int64_t dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
114 int64_t num_a, num_b, den;
115
116 // Test for intersection within the bounds of both line segments using line equations of the
117 // form:
118 // x_k(u_k) = u_k * dX_k + x_k(0)
119 // y_k(u_k) = u_k * dY_k + y_k(0)
120 // with 0 <= u_k <= 1 and k = [ a, b ]
121
122 dX_a = int64_t{ a_p2_l1.x } - a_p1_l1.x;
123 dY_a = int64_t{ a_p2_l1.y } - a_p1_l1.y;
124 dX_b = int64_t{ a_p2_l2.x } - a_p1_l2.x;
125 dY_b = int64_t{ a_p2_l2.y } - a_p1_l2.y;
126 dX_ab = int64_t{ a_p1_l2.x } - a_p1_l1.x;
127 dY_ab = int64_t{ a_p1_l2.y } - a_p1_l1.y;
128
129 den = dY_a * dX_b - dY_b * dX_a ;
130
131 // Check if lines are parallel.
132 if( den == 0 )
133 return false;
134
135 num_a = dY_ab * dX_b - dY_b * dX_ab;
136 num_b = dY_ab * dX_a - dY_a * dX_ab;
137
138 // Only compute the intersection point if requested.
139 if( aIntersectionPoint )
140 {
141 *aIntersectionPoint = a_p1_l1;
142 aIntersectionPoint->x += KiROUND( dX_a * ( double )num_a / ( double )den );
143 aIntersectionPoint->y += KiROUND( dY_a * ( double )num_b / ( double )den );
144 }
145
146 if( den < 0 )
147 {
148 den = -den;
149 num_a = -num_a;
150 num_b = -num_b;
151 }
152
153 // Test sign( u_a ) and return false if negative.
154 if( num_a < 0 )
155 return false;
156
157 // Test sign( u_b ) and return false if negative.
158 if( num_b < 0 )
159 return false;
160
161 // Test to ensure (u_a <= 1).
162 if( num_a > den )
163 return false;
164
165 // Test to ensure (u_b <= 1).
166 if( num_b > den )
167 return false;
168
169 return true;
170}
171
172
173bool TestSegmentHit( const VECTOR2I& aRefPoint, const VECTOR2I& aStart, const VECTOR2I& aEnd,
174 int aDist )
175{
176 int xmin = aStart.x;
177 int xmax = aEnd.x;
178 int ymin = aStart.y;
179 int ymax = aEnd.y;
180 VECTOR2I delta = aStart - aRefPoint;
181
182 if( xmax < xmin )
183 std::swap( xmax, xmin );
184
185 if( ymax < ymin )
186 std::swap( ymax, ymin );
187
188 // Check if we are outside of the bounding box.
189 if( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) )
190 return false;
191
192 if( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) )
193 return false;
194
195 // Eliminate easy cases.
196 if( aStart.x == aEnd.x && aRefPoint.y > ymin && aRefPoint.y < ymax )
197 return std::abs( delta.x ) <= aDist;
198
199 if( aStart.y == aEnd.y && aRefPoint.x > xmin && aRefPoint.x < xmax )
200 return std::abs( delta.y ) <= aDist;
201
202 SEG segment( aStart, aEnd );
203 return segment.SquaredDistance( aRefPoint ) < SEG::Square( aDist + 1 );
204}
205
206
207const VECTOR2I CalcArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
208 bool aMinArcAngle )
209{
210 VECTOR2I startVector = aStart - aCenter;
211 VECTOR2I endVector = aEnd - aCenter;
212
213 EDA_ANGLE startAngle( startVector );
214 EDA_ANGLE endAngle( endVector );
215 EDA_ANGLE midPointRotAngle = ( startAngle - endAngle ).Normalize180() / 2;
216
217 if( !aMinArcAngle )
218 midPointRotAngle += ANGLE_180;
219
220 VECTOR2I newMid = aStart;
221 RotatePoint( newMid, aCenter, midPointRotAngle );
222
223 return newMid;
224}
225
226
227void RotatePoint( int* pX, int* pY, const EDA_ANGLE& aAngle )
228{
229 VECTOR2I pt;
230 EDA_ANGLE angle = aAngle;
231
232 angle.Normalize();
233
234 // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
235 if( angle == ANGLE_0 )
236 {
237 pt = VECTOR2I( *pX, *pY );
238 }
239 else if( angle == ANGLE_90 ) /* sin = 1, cos = 0 */
240 {
241 pt = VECTOR2I( *pY, -*pX );
242 }
243 else if( angle == ANGLE_180 ) /* sin = 0, cos = -1 */
244 {
245 pt = VECTOR2I( -*pX, -*pY );
246 }
247 else if( angle == ANGLE_270 ) /* sin = -1, cos = 0 */
248 {
249 pt = VECTOR2I( -*pY, *pX );
250 }
251 else
252 {
253 double sinus = angle.Sin();
254 double cosinus = angle.Cos();
255
256 pt.x = KiROUND( ( *pY * sinus ) + ( *pX * cosinus ) );
257 pt.y = KiROUND( ( *pY * cosinus ) - ( *pX * sinus ) );
258 }
259
260 *pX = pt.x;
261 *pY = pt.y;
262}
263
264
265void RotatePoint( int* pX, int* pY, int cx, int cy, const EDA_ANGLE& angle )
266{
267 int ox, oy;
268
269 ox = *pX - cx;
270 oy = *pY - cy;
271
272 RotatePoint( &ox, &oy, angle );
273
274 *pX = ox + cx;
275 *pY = oy + cy;
276}
277
278
279void RotatePoint( double* pX, double* pY, double cx, double cy, const EDA_ANGLE& angle )
280{
281 double ox, oy;
282
283 ox = *pX - cx;
284 oy = *pY - cy;
285
286 RotatePoint( &ox, &oy, angle );
287
288 *pX = ox + cx;
289 *pY = oy + cy;
290}
291
292
293void RotatePoint( double* pX, double* pY, const EDA_ANGLE& aAngle )
294{
295 EDA_ANGLE angle = aAngle;
296 VECTOR2D pt;
297
298 angle.Normalize();
299
300 // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
301 if( angle == ANGLE_0 )
302 {
303 pt = VECTOR2D( *pX, *pY );
304 }
305 else if( angle == ANGLE_90 ) /* sin = 1, cos = 0 */
306 {
307 pt = VECTOR2D( *pY, -*pX );
308 }
309 else if( angle == ANGLE_180 ) /* sin = 0, cos = -1 */
310 {
311 pt = VECTOR2D( -*pX, -*pY );
312 }
313 else if( angle == ANGLE_270 ) /* sin = -1, cos = 0 */
314 {
315 pt = VECTOR2D( -*pY, *pX );
316 }
317 else
318 {
319 double sinus = angle.Sin();
320 double cosinus = angle.Cos();
321
322 pt.x = ( *pY * sinus ) + ( *pX * cosinus );
323 pt.y = ( *pY * cosinus ) - ( *pX * sinus );
324 }
325
326 *pX = pt.x;
327 *pY = pt.y;
328}
329
330
331const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd,
332 const EDA_ANGLE& aAngle )
333{
334 EDA_ANGLE angle( aAngle );
335 VECTOR2D start = aStart;
336 VECTOR2D end = aEnd;
337
338 if( angle < ANGLE_0 )
339 {
340 std::swap( start, end );
341 angle = -angle;
342 }
343
344 if( angle > ANGLE_180 )
345 {
346 std::swap( start, end );
347 angle = ANGLE_360 - angle;
348 }
349
350 double chord = ( start - end ).EuclideanNorm();
351 double sinHalfAngle = ( angle / 2.0 ).Sin();
352
353 // A zero arc angle has no defined center, so fall back to the chord midpoint
354 if( sinHalfAngle == 0.0 )
355 return VECTOR2D( ( start + end ) / 2.0 );
356
357 // The center sits (chord/2) * cot(angle/2) off the chord; sqrt(r^2 - chord^2/4) cancels near 180 degrees
358 double d = ( chord / 2.0 ) * ( angle / 2.0 ).Cos() / sinHalfAngle;
359
360 if( !std::isfinite( d ) )
361 d = 0.0;
362
363 VECTOR2D vec2 = VECTOR2D(end - start).Resize( d );
364 VECTOR2D vc = VECTOR2D(end - start).Resize( chord / 2 );
365
366 RotatePoint( vec2, -ANGLE_90 );
367
368 return VECTOR2D( start + vc + vec2 );
369}
370
371
372namespace
373{
374// No unique circumcircle exists if any two of the three points coincide
375// Bbox below catches all three; pairwise checks below catch just one pair
376constexpr double kClusterExtent = 5.0;
377
378// A pair separated by more than integer rounding is a real, if small, arc. This is not the
379// cluster extent above: three points inside a 5 IU box are all noise, but two points 4 IU
380// apart with a distant third still span a healthy triangle
381constexpr double kCoincidentRadius = 2.0;
382constexpr double kCoincidentRadiusSquared = kCoincidentRadius * kCoincidentRadius;
383
384// Radius agreement required of a snapped center, in IU
385constexpr double kSnapRadiusTolerance = 1.0;
386
387// Stand-in radius for collinear points, whose true center is at infinity
388constexpr double kCollinearRadius = 1e17;
389
390// Largest magnitude at which every integer is still a double
391constexpr double kMaxExactInteger = 9007199254740992.0;
392
393// Integer arc centers are clamped to this range
394constexpr double kMinArcCenter = std::numeric_limits<int>::min() + 100.0;
395constexpr double kMaxArcCenter = std::numeric_limits<int>::max() - 100.0;
396
397
398bool degenerateArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd,
399 VECTOR2D& aCenter )
400{
401 auto [minX, maxX] = std::minmax( { aStart.x, aMid.x, aEnd.x } );
402 auto [minY, maxY] = std::minmax( { aStart.y, aMid.y, aEnd.y } );
403
404 if( maxX - minX < kClusterExtent && maxY - minY < kClusterExtent )
405 {
406 aCenter = VECTOR2D( ( aStart.x + aMid.x + aEnd.x ) / 3.0, ( aStart.y + aMid.y + aEnd.y ) / 3.0 );
407 return true;
408 }
409
410 auto coincident = []( const VECTOR2D& a, const VECTOR2D& b )
411 {
412 return ( a - b ).SquaredEuclideanNorm() < kCoincidentRadiusSquared;
413 };
414
415 // Two distinct points fall back to the chord midpoint, same as the diameter-arc paths below
416 if( coincident( aStart, aMid ) || coincident( aMid, aEnd ) )
417 {
418 aCenter = VECTOR2D( ( aStart.x + aEnd.x ) / 2.0, ( aStart.y + aEnd.y ) / 2.0 );
419 return true;
420 }
421
422 if( coincident( aStart, aEnd ) )
423 {
424 aCenter = VECTOR2D( ( aStart.x + aMid.x ) / 2.0, ( aStart.y + aMid.y ) / 2.0 );
425 return true;
426 }
427
428 return false;
429}
430
431
432VECTOR2D collinearArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd )
433{
434 VECTOR2D chord = aEnd - aStart;
435 VECTOR2D mid( ( aStart.x + aEnd.x ) / 2.0, ( aStart.y + aEnd.y ) / 2.0 );
436
437 return mid + VECTOR2D( chord.y, -chord.x ).Resize( kCollinearRadius );
438}
439
440
441// Kahan's a*d - b*c, accurate to about one ulp despite the cancellation
442double det2( double a, double b, double c, double d )
443{
444 double w = b * c;
445 double e = std::fma( -b, c, w );
446 double f = std::fma( a, d, -w );
447
448 return f + e;
449}
450
451
452// Prefer a nice 100 nm or 10 nm center when it still lies on the circle to within a nanometer
453VECTOR2D snapArcCenter( const VECTOR2D& aCenter, const VECTOR2D& aStart, const VECTOR2D& aMid,
454 const VECTOR2D& aEnd )
455{
456 if( !( std::abs( aCenter.x ) < kMaxExactInteger ) || !( std::abs( aCenter.y ) < kMaxExactInteger ) )
457 return aCenter;
458
459 auto radiiAgree = [&]( const VECTOR2D& aCandidate )
460 {
461 double rs = ( aCandidate - aStart ).EuclideanNorm();
462 double rm = ( aCandidate - aMid ).EuclideanNorm();
463 double re = ( aCandidate - aEnd ).EuclideanNorm();
464 auto [minR, maxR] = std::minmax( { rs, rm, re } );
465
466 return maxR - minR <= kSnapRadiusTolerance;
467 };
468
469 for( double grid : { 100.0, 10.0 } )
470 {
471 VECTOR2D candidate( std::floor( aCenter.x / grid + 0.5 ) * grid,
472 std::floor( aCenter.y / grid + 0.5 ) * grid );
473
474 if( radiiAgree( candidate ) )
475 return candidate;
476 }
477
478 return aCenter;
479}
480
481
482VECTOR2D unclampedArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
483{
484 VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
485 VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
486 VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
487 VECTOR2D dCenter;
488
489 if( degenerateArcCenter( dStart, dMid, dEnd, dCenter ) )
490 return dCenter;
491
492 // Deltas are exact in 64 bits and the numerators in 128, so only the final divisions round
493 VECTOR2L b( int64_t( aMid.x ) - aStart.x, int64_t( aMid.y ) - aStart.y );
494 VECTOR2L c( int64_t( aEnd.x ) - aStart.x, int64_t( aEnd.y ) - aStart.y );
495
496 KI_INT128 b2 = KI_INT128( b.x ) * KI_INT128( b.x ) + KI_INT128( b.y ) * KI_INT128( b.y );
497 KI_INT128 c2 = KI_INT128( c.x ) * KI_INT128( c.x ) + KI_INT128( c.y ) * KI_INT128( c.y );
498 KI_INT128 d = CrossWide( b, c ) * KI_INT128( 2 );
499
500 if( d == KI_INT128( 0 ) )
501 return collinearArcCenter( dStart, dEnd );
502
503 // Fold start into the numerator so the sum is rounded once
504 double dd = ToDouble( d );
505 double cx = ToDouble( KI_INT128( aStart.x ) * d + b2 * KI_INT128( c.y ) - c2 * KI_INT128( b.y ) ) / dd;
506 double cy = ToDouble( KI_INT128( aStart.y ) * d + c2 * KI_INT128( b.x ) - b2 * KI_INT128( c.x ) ) / dd;
507
508 return snapArcCenter( VECTOR2D( cx, cy ), dStart, dMid, dEnd );
509}
510} // namespace
511
512
513const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
514{
516
517 if( degenerateArcCenter( aStart, aMid, aEnd, center ) )
518 return center;
519
520 // Work relative to start so the result cannot depend on where the arc sits
521 double bx = aMid.x - aStart.x;
522 double by = aMid.y - aStart.y;
523 double cx = aEnd.x - aStart.x;
524 double cy = aEnd.y - aStart.y;
525
526 double b2 = std::fma( bx, bx, by * by );
527 double c2 = std::fma( cx, cx, cy * cy );
528 double d = 2.0 * det2( bx, by, cx, cy );
529
530 if( d == 0.0 )
531 return collinearArcCenter( aStart, aEnd );
532
533 double ux = det2( b2, c2, by, cy ) / d;
534 double uy = det2( c2, b2, cx, bx ) / d;
535
536 return snapArcCenter( VECTOR2D( aStart.x + ux, aStart.y + uy ), aStart, aMid, aEnd );
537}
538
539
540const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
541{
542 VECTOR2D dCenter = unclampedArcCenter( aStart, aMid, aEnd );
543
544 return VECTOR2I( KiROUND( std::clamp( dCenter.x, kMinArcCenter, kMaxArcCenter ) ),
545 KiROUND( std::clamp( dCenter.y, kMinArcCenter, kMaxArcCenter ) ) );
546}
547
548
549bool IsStraightArc( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
550{
551 if( aStart == aEnd )
552 return false;
553
554 if( CrossWide( VECTOR2L( aMid ) - VECTOR2L( aStart ), VECTOR2L( aEnd ) - VECTOR2L( aStart ) ) == KI_INT128( 0 ) )
555 return true;
556
557 VECTOR2D center = unclampedArcCenter( aStart, aMid, aEnd );
558
559 // Near-collinear points put the center outside the clamp
560 return !( center.x >= kMinArcCenter && center.x <= kMaxArcCenter && center.y >= kMinArcCenter
561 && center.y <= kMaxArcCenter );
562}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
EDA_ANGLE Normalize()
Definition eda_angle.h:228
double Sin() const
Definition eda_angle.h:177
double Cos() const
Definition eda_angle.h:196
Definition seg.h:38
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:35
static SEG::ecoord Square(int a)
Definition seg.h:119
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:406
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
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:207
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:173
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:227
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:105
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:87
bool IsStraightArc(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Definition trigo.cpp:549
const VECTOR2D CalcArcCenter(const VECTOR2D &aStart, const VECTOR2D &aEnd, const EDA_ANGLE &aAngle)
Definition trigo.cpp:331
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709
128-bit integers for exact products of 64-bit coordinate deltas.
double ToDouble(KI_INT128 aValue)
Definition wide_int.h:94
constexpr KI_INT128 CrossWide(const VECTOR2L &aA, const VECTOR2L &aB)
Exact aA.x * aB.y - aA.y * aB.x.
Definition wide_int.h:104
__int128 KI_INT128
Definition wide_int.h:91