KiCad PCB EDA Suite
shape_arc.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) 2017 CERN
5  * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
27 #include <geometry/seg.h> // for SEG
28 #include <geometry/shape_arc.h>
30 #include <trigo.h>
31 
32 
33 std::ostream& operator<<( std::ostream& aStream, const SHAPE_ARC& aArc )
34 {
35  aStream << "Arc( P0=" << aArc.GetP0() << " P1=" << aArc.GetP1() << " Mid=" << aArc.GetArcMid()
36  << " Width=" << aArc.GetWidth() << " )";
37  return aStream;
38 }
39 
40 
41 SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint,
42  double aCenterAngle, int aWidth ) :
43  SHAPE( SH_ARC ), m_width( aWidth )
44 {
45  m_start = aArcStartPoint;
46  m_mid = aArcStartPoint;
47  m_end = aArcStartPoint;
48 
49  RotatePoint( m_mid, aArcCenter, -aCenterAngle * 10.0 / 2.0 );
50  RotatePoint( m_end, aArcCenter, -aCenterAngle * 10.0 );
51 
52  update_bbox();
53 }
54 
55 
56 SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid,
57  const VECTOR2I& aArcEnd, int aWidth ) :
58  SHAPE( SH_ARC ), m_start( aArcStart ), m_mid( aArcMid ), m_end( aArcEnd ),
59  m_width( aWidth )
60 {
61  update_bbox();
62 }
63 
64 
65 SHAPE_ARC::SHAPE_ARC( const SEG& aSegmentA, const SEG& aSegmentB, int aRadius, int aWidth )
66  : SHAPE( SH_ARC )
67 {
68  m_width = aWidth;
69 
70  /*
71  * Construct an arc that is tangent to two segments with a given radius.
72  *
73  * p
74  * A
75  * A \
76  * / \
77  * / . . \ segB
78  * /. .\
79  * segA / c \
80  * / B
81  * /
82  * /
83  * B
84  *
85  *
86  * segA is the fist segment (with its points A and B)
87  * segB is the second segment (with its points A and B)
88  * p is the point at which segA and segB would intersect if they were projected
89  * c is the centre of the arc to be constructed
90  * rad is the radius of the arc to be constructed
91  *
92  * We can create two vectors, between point p and segA /segB
93  * pToA = p - segA.B //< note that segA.A would also be valid as it is colinear
94  * pToB = p - segB.B //< note that segB.A would also be valid as it is colinear
95  *
96  * Let the angle formed by segA and segB be called 'alpha':
97  * alpha = angle( pToA ) - angle( pToB )
98  *
99  * The distance PC can be computed as
100  * distPC = rad / abs( sin( alpha / 2 ) )
101  *
102  * The polar angle of the vector PC can be computed as:
103  * anglePC = angle( pToA ) + alpha / 2
104  *
105  * Therefore:
106  * C.x = P.x + distPC*cos( anglePC )
107  * C.y = P.y + distPC*sin( anglePC )
108  */
109 
110  OPT_VECTOR2I p = aSegmentA.Intersect( aSegmentB, true, true );
111 
112  if( !p || aSegmentA.Length() == 0 || aSegmentB.Length() == 0 )
113  {
114  // Catch bugs in debug
115  wxASSERT_MSG( false, "The input segments do not intersect or one is zero length." );
116 
117  // Make a 180 degree arc around aSegmentA in case we end up here in release
118  m_start = aSegmentA.A;
119  m_end = aSegmentA.B;
120  m_mid = m_start;
121 
122  VECTOR2I arcCenter = aSegmentA.Center();
123  RotatePoint( m_mid, arcCenter, 900.0 ); // mid point at 90 degrees
124  }
125  else
126  {
127  VECTOR2I pToA = aSegmentA.B - p.get();
128  VECTOR2I pToB = aSegmentB.B - p.get();
129 
130  if( pToA.EuclideanNorm() == 0 )
131  pToA = aSegmentA.A - p.get();
132 
133  if( pToB.EuclideanNorm() == 0 )
134  pToB = aSegmentB.A - p.get();
135 
136  double pToAangle = ArcTangente( pToA.y, pToA.x );
137  double pToBangle = ArcTangente( pToB.y, pToB.x );
138 
139  double alpha = NormalizeAngle180( pToAangle - pToBangle );
140 
141  double distPC = (double) aRadius / abs( sin( DECIDEG2RAD( alpha / 2 ) ) );
142  double angPC = pToAangle - alpha / 2;
143 
144  VECTOR2I arcCenter;
145 
146  arcCenter.x = p.get().x + KiROUND( distPC * cos( DECIDEG2RAD( angPC ) ) );
147  arcCenter.y = p.get().y + KiROUND( distPC * sin( DECIDEG2RAD( angPC ) ) );
148 
149  // The end points of the arc are the orthogonal projected lines from the line segments
150  // to the center of the arc
151  m_start = aSegmentA.LineProject( arcCenter );
152  m_end = aSegmentB.LineProject( arcCenter );
153 
154  //The mid point is rotated start point around center, half the angle of the arc.
155  VECTOR2I startVector = m_start - arcCenter;
156  VECTOR2I endVector = m_end - arcCenter;
157 
158  double startAngle = ArcTangente( startVector.y, startVector.x );
159  double endAngle = ArcTangente( endVector.y, endVector.x );
160 
161  double midPointRotAngle = NormalizeAngle180( startAngle - endAngle ) / 2;
162  m_mid = m_start;
163  RotatePoint( m_mid, arcCenter, midPointRotAngle );
164  }
165 
166  update_bbox();
167 }
168 
169 
171  : SHAPE( SH_ARC )
172 {
173  m_start = aOther.m_start;
174  m_end = aOther.m_end;
175  m_mid = aOther.m_mid;
176  m_width = aOther.m_width;
177  m_bbox = aOther.m_bbox;
178 }
179 
180 
182  double aAngle, double aWidth )
183 {
184  m_start = aStart;
185  m_mid = aStart;
186  m_end = aEnd;
187  m_width = aWidth;
188 
189  VECTOR2I center( GetArcCenter( aStart, aEnd, aAngle ) );
190 
191  RotatePoint( m_mid, center, -aAngle * 10.0 / 2.0 );
192 
193  update_bbox();
194 
195  return *this;
196 }
197 
198 
200  const VECTOR2I& aCenter, bool aClockwise,
201  double aWidth )
202 {
203  VECTOR2I startLine = aStart - aCenter;
204  VECTOR2I endLine = aEnd - aCenter;
205 
206  double startangle = NormalizeAnglePos(RAD2DECIDEG( startLine.Angle() ));
207  double endangle = NormalizeAnglePos(RAD2DECIDEG( endLine.Angle() ));
208  double angle = endangle - startangle;
209 
210  if( aClockwise )
212  else
214 
215  m_start = aStart;
216  m_end = aEnd;
217  m_mid = aStart;
218 
219  RotatePoint( m_mid, aCenter, -angle / 2.0 );
220 
221  update_bbox();
222 
223  return *this;
224 }
225 
226 
227 bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
228 {
229  if( aSeg.A == aSeg.B )
230  return Collide( aSeg.A, aClearance, aActual, aLocation );
231 
232  int minDist = aClearance + m_width / 2;
233  VECTOR2I center = GetCenter();
234  ecoord dist_sq;
235  ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
236  VECTOR2I nearest;
237 
238  VECTOR2I ab = ( aSeg.B - aSeg.A );
239  VECTOR2I ac = ( center - aSeg.A );
240 
241  ecoord lenAbSq = ab.SquaredEuclideanNorm();
242  double lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
243 
244  if( lambda >= 0.0 && lambda <= 1.0 )
245  {
246  VECTOR2I p;
247 
248  p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
249  p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
250 
251  dist_sq = ( m_start - p ).SquaredEuclideanNorm();
252 
253  if( dist_sq < closest_dist_sq )
254  {
255  closest_dist_sq = dist_sq;
256  nearest = p;
257  }
258 
259  dist_sq = ( m_end - p ).SquaredEuclideanNorm();
260 
261  if( dist_sq < closest_dist_sq )
262  {
263  closest_dist_sq = dist_sq;
264  nearest = p;
265  }
266  }
267 
268  dist_sq = aSeg.SquaredDistance( m_start );
269 
270  if( dist_sq < closest_dist_sq )
271  {
272  closest_dist_sq = dist_sq;
273  nearest = m_start;
274  }
275 
276  dist_sq = aSeg.SquaredDistance( m_end );
277 
278  if( dist_sq < closest_dist_sq )
279  {
280  closest_dist_sq = dist_sq;
281  nearest = m_end;
282  }
283 
284  if( closest_dist_sq == 0 || closest_dist_sq < SEG::Square( minDist ) )
285  {
286  if( aLocation )
287  *aLocation = nearest;
288 
289  if( aActual )
290  *aActual = std::max( 0, (int) sqrt( closest_dist_sq ) - m_width / 2 );
291 
292  return true;
293  }
294 
295  return false;
296 }
297 
298 
300 {
301  std::vector<VECTOR2I> points;
302  // Put start and end points in the point list
303  points.push_back( m_start );
304  points.push_back( m_end );
305 
306  double start_angle = GetStartAngle();
307  double end_angle = start_angle + GetCentralAngle();
308 
309  // we always count quadrants clockwise (increasing angle)
310  if( start_angle > end_angle )
311  std::swap( start_angle, end_angle );
312 
313  int quad_angle_start = std::ceil( start_angle / 90.0 );
314  int quad_angle_end = std::floor( end_angle / 90.0 );
315 
316  // count through quadrants included in arc
317  for( int quad_angle = quad_angle_start; quad_angle <= quad_angle_end; ++quad_angle )
318  {
319  const int radius = KiROUND( GetRadius() );
320  VECTOR2I quad_pt = GetCenter();
321 
322  switch( quad_angle % 4 )
323  {
324  case 0: quad_pt += { radius, 0 }; break;
325  case 1:
326  case -3: quad_pt += { 0, radius }; break;
327  case 2:
328  case -2: quad_pt += { -radius, 0 }; break;
329  case 3:
330  case -1: quad_pt += { 0, -radius }; break;
331  default: assert( false );
332  }
333 
334  points.push_back( quad_pt );
335  }
336 
337  m_bbox.Compute( points );
338 }
339 
340 
341 const BOX2I SHAPE_ARC::BBox( int aClearance ) const
342 {
343  BOX2I bbox( m_bbox );
344 
345  if( aClearance != 0 )
346  bbox.Inflate( aClearance );
347 
348  return bbox;
349 }
350 
351 
353 {
354  return GetCentralAngle() < 0;
355 }
356 
357 
358 bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
359  VECTOR2I* aLocation ) const
360 {
361  int minDist = aClearance + m_width / 2;
362  auto bbox = BBox( minDist );
363 
364  // Fast check using bounding box:
365  if( !bbox.Contains( aP ) )
366  return false;
367 
368  VECTOR2I center = GetCenter();
369  VECTOR2I vec = aP - center;
370 
371  int dist = abs( vec.EuclideanNorm() - GetRadius() );
372 
373  // If not a 360 degree arc, need to use arc angles to decide if point collides
374  if( m_start != m_end )
375  {
376  bool ccw = GetCentralAngle() > 0.0;
377  double rotatedVecAngle = NormalizeAngleDegreesPos( NormalizeAngleDegreesPos( RAD2DEG( vec.Angle() ) )
378  - GetStartAngle() );
379  double rotatedEndAngle = NormalizeAngleDegreesPos( GetEndAngle() - GetStartAngle() );
380 
381  if( ( ccw && rotatedVecAngle > rotatedEndAngle )
382  || ( !ccw && rotatedVecAngle < rotatedEndAngle ) )
383  {
384  int distStartpt = ( aP - m_start ).EuclideanNorm();
385  int distEndpt = ( aP - m_end ).EuclideanNorm();
386  dist = std::min( distStartpt, distEndpt );
387  }
388  }
389 
390  if( dist <= minDist )
391  {
392  if( aLocation )
393  *aLocation = ( aP + GetCenter() ) / 2;
394 
395  if( aActual )
396  *aActual = std::max( 0, dist - m_width / 2 );
397 
398  return true;
399  }
400 
401  return false;
402 }
403 
404 
406 {
407  VECTOR2D d( m_start - GetCenter() );
408 
409  auto ang = 180.0 / M_PI * atan2( d.y, d.x );
410 
411  return NormalizeAngleDegrees( ang, 0.0, 360.0 );
412 }
413 
414 
416 {
417  VECTOR2D d( m_end - GetCenter() );
418 
419  auto ang = 180.0 / M_PI * atan2( d.y, d.x );
420 
421  return NormalizeAngleDegrees( ang, 0.0, 360.0 );
422 }
423 
424 
426 {
427  return GetArcCenter( m_start, m_mid, m_end );
428 }
429 
430 
431 double SHAPE_ARC::GetLength() const
432 {
433  double radius = GetRadius();
434  double includedAngle = std::abs( GetCentralAngle() );
435 
436  return radius * M_PI * includedAngle / 180.0;
437 }
438 
439 
441 {
442  VECTOR2I center = GetCenter();
443  VECTOR2I p0 = m_start - center;
444  VECTOR2I p1 = m_mid - center;
445  VECTOR2I p2 = m_end - center;
446  double angle1 = ArcTangente( p1.y, p1.x ) - ArcTangente( p0.y, p0.x );
447  double angle2 = ArcTangente( p2.y, p2.x ) - ArcTangente( p1.y, p1.x );
448 
449  return ( NormalizeAngle180( angle1 ) + NormalizeAngle180( angle2 ) ) / 10.0;
450 }
451 
452 
453 double SHAPE_ARC::GetRadius() const
454 {
455  return ( m_start - GetCenter() ).EuclideanNorm();
456 }
457 
458 
460  double* aEffectiveAccuracy ) const
461 {
462  SHAPE_LINE_CHAIN rv;
463  double r = GetRadius();
464  double sa = GetStartAngle();
465  VECTOR2I c = GetCenter();
466  double ca = GetCentralAngle();
467 
468  int n;
469 
470  // To calculate the arc to segment count, use the external radius instead of the radius.
471  // for a arc with small radius and large width, the difference can be significant
472  double external_radius = r+(m_width/2);
473  double effectiveAccuracy;
474 
475  if( external_radius < aAccuracy/2 ) // Should be a very rare case
476  {
477  // In this case, the arc is approximated by one segment, with a effective error
478  // between -aAccuracy/2 and +aAccuracy/2, as expected.
479  n = 0;
480  effectiveAccuracy = external_radius;
481  }
482  else
483  {
484  double arc_angle = std::abs( ca );
485  n = GetArcToSegmentCount( external_radius, aAccuracy, arc_angle );
486 
487  // Recalculate the effective error of approximation, that can be < aAccuracy
488  int seg360 = n * 360.0 / arc_angle;
489  effectiveAccuracy = CircleToEndSegmentDeltaRadius( external_radius, seg360 );
490  }
491 
492  // Split the error on either side of the arc. Since we want the start and end points
493  // to be exactly on the arc, the first and last segments need to be shorter to stay within
494  // the error band (since segments normally start 1/2 the error band outside the arc).
495  r += effectiveAccuracy / 2;
496  n = n * 2;
497 
498  rv.Append( m_start );
499 
500  for( int i = 1; i < n ; i += 2 )
501  {
502  double a = sa;
503 
504  if( n != 0 )
505  a += ( ca * i ) / n;
506 
507  double x = c.x + r * cos( a * M_PI / 180.0 );
508  double y = c.y + r * sin( a * M_PI / 180.0 );
509 
510  rv.Append( KiROUND( x ), KiROUND( y ) );
511  }
512 
513  rv.Append( m_end );
514 
515  if( aEffectiveAccuracy )
516  *aEffectiveAccuracy = effectiveAccuracy;
517 
518  return rv;
519 }
520 
521 
522 void SHAPE_ARC::Move( const VECTOR2I& aVector )
523 {
524  m_start += aVector;
525  m_end += aVector;
526  m_mid += aVector;
527  update_bbox();
528 }
529 
530 
531 void SHAPE_ARC::Rotate( double aAngle, const VECTOR2I& aCenter )
532 {
533  m_start -= aCenter;
534  m_end -= aCenter;
535  m_mid -= aCenter;
536 
537  m_start = m_start.Rotate( aAngle );
538  m_end = m_end.Rotate( aAngle );
539  m_mid = m_mid.Rotate( aAngle );
540 
541  m_start += aCenter;
542  m_end += aCenter;
543  m_mid += aCenter;
544 
545  update_bbox();
546 }
547 
548 
549 void SHAPE_ARC::Mirror( bool aX, bool aY, const VECTOR2I& aVector )
550 {
551  if( aX )
552  {
553  m_start.x = -m_start.x + 2 * aVector.x;
554  m_end.x = -m_end.x + 2 * aVector.x;
555  m_mid.x = -m_mid.x + 2 * aVector.x;
556  }
557 
558  if( aY )
559  {
560  m_start.y = -m_start.y + 2 * aVector.y;
561  m_end.y = -m_end.y + 2 * aVector.y;
562  m_mid.y = -m_mid.y + 2 * aVector.y;
563  }
564 
565  update_bbox();
566 }
567 
568 
569 void SHAPE_ARC::Mirror( const SEG& axis )
570 {
571  m_start = axis.ReflectPoint( m_start );
572  m_end = axis.ReflectPoint( m_end );
573  m_mid = axis.ReflectPoint( m_mid );
574 
575  update_bbox();
576 }
577 
578 
580 {
581  std::swap( m_start, m_end );
582 }
583 
584 
586 {
587  return SHAPE_ARC( m_end, m_mid, m_start, m_width );
588 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
int Length() const
Return the length (this).
Definition: seg.h:350
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aVector={ 0, 0 })
Definition: shape_arc.cpp:549
T NormalizeAngleNeg(T Angle)
Normalize angle to be in the 0.0 .. -360.0 range: angle is in 1/10 degrees.
Definition: trigo.h:268
int CircleToEndSegmentDeltaRadius(int aInnerCircleRadius, int aSegCount)
void Rotate(double aAngle, const VECTOR2I &aCenter) override
Rotate the arc by a given angle about a point.
Definition: shape_arc.cpp:531
bool IsClockwise() const
Definition: shape_arc.cpp:352
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
Definition: shape_arc.cpp:227
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:154
double GetRadius() const
Definition: shape_arc.cpp:453
VECTOR2I m_end
Definition: shape_arc.h:232
double RAD2DEG(double rad)
Definition: trigo.h:230
const VECTOR2I ReflectPoint(const VECTOR2I &aP) const
Reflect a point using this segment as axis.
Definition: seg.cpp:249
SHAPE_ARC & ConstructFromStartEndAngle(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle, double aWidth=0)
Construct this arc from the given start, end and angle.
Definition: shape_arc.cpp:181
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
void Compute(const Container &aPointList)
Compute the bounding box from a given list of points.
Definition: box2.h:75
extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition: vector2d.h:300
ecoord SquaredDistance(const SEG &aSeg) const
Definition: seg.cpp:39
bool ccw(const VECTOR2I &aA, const VECTOR2I &aB, const VECTOR2I &aC) const
Definition: shape_arc.h:221
double GetStartAngle() const
Definition: shape_arc.cpp:405
VECTOR2I Center() const
Definition: seg.h:386
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
static SEG::ecoord Square(int a)
Definition: seg.h:122
std::ostream & operator<<(std::ostream &aStream, const SHAPE_ARC &aArc)
Definition: shape_arc.cpp:33
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
T NormalizeAngle180(T Angle)
Normalize angle to be in the -180.0 .. 180.0 range.
Definition: trigo.h:387
VECTOR2I m_mid
Definition: shape_arc.h:231
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:79
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition: seg.cpp:268
double NormalizeAngleDegreesPos(double Angle)
Normalize angle to be in the 0.0 .. 360.0 range: angle is in degrees.
Definition: trigo.h:297
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:38
const VECTOR2I & GetP0() const
Definition: shape_arc.h:111
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:113
circular arc
Definition: shape.h:50
a few functions useful in geometry calculations.
An abstract shape on 2D plane.
Definition: shape.h:116
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
double GetEndAngle() const
Definition: shape_arc.cpp:415
void update_bbox()
Definition: shape_arc.cpp:299
void Reverse()
Definition: shape_arc.cpp:579
Definition: seg.h:40
void Move(const VECTOR2I &aVector) override
Definition: shape_arc.cpp:522
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:281
int GetWidth() const
Definition: shape_arc.h:130
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
const SHAPE_LINE_CHAIN ConvertToPolyline(double aAccuracy=DefaultAccuracyForPCB(), double *aEffectiveAccuracy=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
Definition: shape_arc.cpp:459
extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
Definition: vector2d.h:521
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Definition: shape_arc.cpp:199
VECTOR2I::extended_type ecoord
Definition: shape.h:236
Represent a polyline (an zero-thickness chain of connected line segments).
VECTOR2I m_start
Definition: shape_arc.h:230
T NormalizeAnglePos(T Angle)
Normalize angle to be in the 0.0 .. 360.0 range: angle is in 1/10 degrees.
Definition: trigo.h:281
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
VECTOR2I A
Definition: seg.h:48
double GetCentralAngle() const
Definition: shape_arc.cpp:440
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
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:73
SHAPE_ARC()
Definition: shape_arc.h:39
double NormalizeAngleDegrees(double Angle, double aMin, double aMax)
Normalize angle to be aMin < angle <= aMax angle is in degrees.
Definition: trigo.h:327
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Definition: shape_arc.cpp:341
SHAPE_ARC Reversed() const
Definition: shape_arc.cpp:585
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
const VECTOR2I GetArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:454
double GetLength() const
Definition: shape_arc.cpp:431
int m_width
Definition: shape_arc.h:234
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
BOX2I m_bbox
Definition: shape_arc.h:235
const VECTOR2I & GetP1() const
Definition: shape_arc.h:112
VECTOR2I GetCenter() const
Definition: shape_arc.cpp:425
VECTOR2I B
Definition: seg.h:49