KiCad PCB EDA Suite
pcb_shape.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <bezier_curves.h>
28 #include <pcb_screen.h>
29 #include <bitmaps.h>
30 #include <pcb_edit_frame.h>
31 #include <board.h>
32 #include <board_design_settings.h>
33 #include <footprint.h>
34 #include <pcb_shape.h>
35 #include <base_units.h>
36 #include <geometry/shape_simple.h>
37 #include <geometry/shape_segment.h>
38 #include <geometry/shape_circle.h>
40 #include <macros.h>
41 #include <origin_transforms.h>
44 #include <i18n_utility.h>
45 #include <math/util.h> // for KiROUND
46 
47 
49  BOARD_ITEM( aParent, idtype )
50 {
51  m_angle = 0;
52  m_filled = false;
53  m_flags = 0;
56 }
57 
58 
60 {
61 }
62 
63 
64 void PCB_SHAPE::SetPosition( const wxPoint& aPos )
65 {
66  m_start = aPos;
67 }
68 
69 
70 wxPoint PCB_SHAPE::GetPosition() const
71 {
72  if( m_shape == SHAPE_T::POLY )
73  return (wxPoint) m_poly.CVertex( 0 );
74  else
75  return m_start;
76 }
77 
78 
79 const wxPoint PCB_SHAPE::GetFocusPosition() const
80 {
81  // For some shapes return the visual center, but for not filled polygonal shapes,
82  // the center is usually far from the shape: a point on the outline is better
83 
84  switch( m_shape )
85  {
86  case SHAPE_T::CIRCLE:
87  if( !IsFilled() )
88  return wxPoint( GetCenter().x + GetRadius(), GetCenter().y );
89  break;
90 
91  case SHAPE_T::RECT:
92  if( !IsFilled() )
93  return GetStart();
94  break;
95 
96  case SHAPE_T::POLY:
97  if( !IsFilled() )
98  {
99  VECTOR2I pos = GetPolyShape().Outline(0).CPoint(0);
100  return wxPoint( pos.x, pos.y );
101  }
102  break;
103 
104  case SHAPE_T::ARC:
105  return GetArcMid();
106  break;
107 
108  case SHAPE_T::BEZIER:
109  return GetStart();
110  break;
111 
112  default:
113  break;
114  }
115 
116  return GetCenter();
117 }
118 
119 
120 double PCB_SHAPE::GetLength() const
121 {
122  double length = 0.0;
123 
124  switch( m_shape )
125  {
126  case SHAPE_T::BEZIER:
127  for( size_t ii = 1; ii < m_bezierPoints.size(); ++ii )
128  length += GetLineLength( m_bezierPoints[ ii - 1], m_bezierPoints[ii] );
129 
130  break;
131 
132  case SHAPE_T::SEGMENT:
133  length = GetLineLength( GetStart(), GetEnd() );
134  break;
135 
136  case SHAPE_T::POLY:
137  for( int ii = 0; ii < m_poly.COutline( 0 ).SegmentCount(); ii++ )
138  length += m_poly.COutline( 0 ).CSegment( ii ).Length();
139 
140  break;
141 
142  case SHAPE_T::ARC:
143  length = 2 * M_PI * GetRadius() * ( GetAngle() / 3600.0 );
144  break;
145 
146  default:
147  wxASSERT_MSG( false, "PCB_SHAPE::GetLength not implemented for shape"
148  + ShowShape( GetShape() ) );
149  break;
150  }
151 
152  return length;
153 }
154 
155 
156 void PCB_SHAPE::Move( const wxPoint& aMoveVector )
157 {
158  // Move vector should not affect start/end for polygon since it will
159  // be applied directly to polygon outline.
160  if( m_shape != SHAPE_T::POLY )
161  {
162  m_start += aMoveVector;
163  m_end += aMoveVector;
164  }
165 
166  switch ( m_shape )
167  {
168  case SHAPE_T::POLY:
169  m_poly.Move( VECTOR2I( aMoveVector ) );
170  break;
171 
172  case SHAPE_T::ARC:
173  m_thirdPoint += aMoveVector;
174  break;
175 
176  case SHAPE_T::BEZIER:
177  m_bezierC1 += aMoveVector;
178  m_bezierC2 += aMoveVector;
179 
180  for( wxPoint& pt : m_bezierPoints)
181  pt += aMoveVector;
182 
183  break;
184 
185  default:
186  break;
187  }
188 }
189 
190 
191 void PCB_SHAPE::Scale( double aScale )
192 {
193  auto scalePt = [&]( wxPoint& pt )
194  {
195  pt.x = KiROUND( pt.x * aScale );
196  pt.y = KiROUND( pt.y * aScale );
197  };
198 
199  int radius = GetRadius();
200 
201  scalePt( m_start );
202  scalePt( m_end );
203 
204  // specific parameters:
205  switch( m_shape )
206  {
207  case SHAPE_T::BEZIER:
208  scalePt( m_bezierC1 );
209  scalePt( m_bezierC2 );
210  break;
211 
212  case SHAPE_T::ARC:
213  scalePt( m_thirdPoint );
214  break;
215 
216  case SHAPE_T::CIRCLE: // ring or circle
217  m_end.x = m_start.x + KiROUND( radius * aScale );
218  m_end.y = m_start.y;
219  break;
220 
221  case SHAPE_T::POLY: // polygon
222  {
223  std::vector<wxPoint> pts;
224 
225  for( const VECTOR2I& pt : m_poly.Outline( 0 ).CPoints() )
226  {
227  pts.emplace_back( pt );
228  scalePt( pts.back() );
229  }
230 
231  SetPolyPoints( pts );
232  break;
233  }
234 
235  default:
236  break;
237  }
238 }
239 
240 
241 void PCB_SHAPE::Rotate( const wxPoint& aRotCentre, double aAngle )
242 {
243  switch( m_shape )
244  {
245  case SHAPE_T::ARC:
246  case SHAPE_T::SEGMENT:
247  case SHAPE_T::CIRCLE:
248  // these can all be done by just rotating the constituent points
249  RotatePoint( &m_start, aRotCentre, aAngle );
250  RotatePoint( &m_end, aRotCentre, aAngle );
251  RotatePoint( &m_thirdPoint, aRotCentre, aAngle );
252  break;
253 
254  case SHAPE_T::RECT:
255  if( KiROUND( aAngle ) % 900 == 0 )
256  {
257  RotatePoint( &m_start, aRotCentre, aAngle );
258  RotatePoint( &m_end, aRotCentre, aAngle );
259  break;
260  }
261 
262  // Convert non-cartesian-rotated rect to a diamond
265  m_poly.NewOutline();
266  m_poly.Append( m_start );
267  m_poly.Append( m_end.x, m_start.y );
268  m_poly.Append( m_end );
269  m_poly.Append( m_start.x, m_end.y );
270 
272 
273  case SHAPE_T::POLY:
274  m_poly.Rotate( -DECIDEG2RAD( aAngle ), VECTOR2I( aRotCentre ) );
275  break;
276 
277  case SHAPE_T::BEZIER:
278  RotatePoint( &m_start, aRotCentre, aAngle);
279  RotatePoint( &m_end, aRotCentre, aAngle);
280  RotatePoint( &m_bezierC1, aRotCentre, aAngle);
281  RotatePoint( &m_bezierC2, aRotCentre, aAngle);
282 
283  for( wxPoint& pt : m_bezierPoints )
284  RotatePoint( &pt, aRotCentre, aAngle);
285 
286  break;
287 
288  default:
289  wxFAIL_MSG( "PCB_SHAPE::Rotate not implemented for "
290  + SHAPE_T_asString( m_shape ) );
291  break;
292  }
293 }
294 
295 
296 void PCB_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
297 {
298  if( aFlipLeftRight )
299  {
300  m_start.x = aCentre.x - ( m_start.x - aCentre.x );
301  m_end.x = aCentre.x - ( m_end.x - aCentre.x );
302  }
303  else
304  {
305  m_start.y = aCentre.y - ( m_start.y - aCentre.y );
306  m_end.y = aCentre.y - ( m_end.y - aCentre.y );
307  }
308 
309  switch ( m_shape )
310  {
311  case SHAPE_T::ARC:
312  if( aFlipLeftRight )
313  m_thirdPoint.x = aCentre.x - ( m_thirdPoint.x - aCentre.x );
314  else
315  m_thirdPoint.y = aCentre.y - ( m_thirdPoint.y - aCentre.y );
316 
317  m_angle = -m_angle;
318  break;
319 
320  case SHAPE_T::POLY:
321  m_poly.Mirror( aFlipLeftRight, !aFlipLeftRight, VECTOR2I( aCentre ) );
322  break;
323 
324  case SHAPE_T::BEZIER:
325  {
326  if( aFlipLeftRight )
327  {
328  m_bezierC1.x = aCentre.x - ( m_bezierC1.x - aCentre.x );
329  m_bezierC2.x = aCentre.x - ( m_bezierC2.x - aCentre.x );
330  }
331  else
332  {
333  m_bezierC1.y = aCentre.y - ( m_bezierC1.y - aCentre.y );
334  m_bezierC2.y = aCentre.y - ( m_bezierC2.y - aCentre.y );
335  }
336 
337  // Rebuild the poly points shape
338  std::vector<wxPoint> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end };
339  BEZIER_POLY converter( ctrlPoints );
340  converter.GetPoly( m_bezierPoints, m_width );
341  }
342  break;
343 
344  case SHAPE_T::SEGMENT:
345  case SHAPE_T::RECT:
346  case SHAPE_T::CIRCLE:
347  break;
348 
349  default:
350  wxFAIL_MSG( "PCB_SHAPE::Flip not implemented for "
351  + SHAPE_T_asString( m_shape ) );
352  break;
353  }
354 
355  SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
356 }
357 
358 
360 {
361  // Has meaning only for S_CURVE DRAW_SEGMENT shape
362  if( m_shape != SHAPE_T::BEZIER )
363  {
364  m_bezierPoints.clear();
365  return;
366  }
367  // Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
369 }
370 
371 
372 const std::vector<wxPoint> PCB_SHAPE::buildBezierToSegmentsPointsList( int aMinSegLen ) const
373 {
374  std::vector<wxPoint> bezierPoints;
375 
376  // Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
377  std::vector<wxPoint> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end };
378  BEZIER_POLY converter( ctrlPoints );
379  converter.GetPoly( bezierPoints, aMinSegLen );
380 
381  return bezierPoints;
382 }
383 
384 
385 wxPoint PCB_SHAPE::GetCenter() const
386 {
387  wxPoint c;
388 
389  switch( m_shape )
390  {
391  case SHAPE_T::ARC:
392  case SHAPE_T::CIRCLE:
393  c = m_start;
394  break;
395 
396  case SHAPE_T::SEGMENT:
397  // Midpoint of the line
398  c = ( GetStart() + GetEnd() ) / 2;
399  break;
400 
401  case SHAPE_T::POLY:
402  case SHAPE_T::RECT:
403  case SHAPE_T::BEZIER:
404  c = GetBoundingBox().Centre();
405  break;
406 
407  default:
408  wxFAIL_MSG( "PCB_SHAPE::GetCentre not implemented for "
409  + SHAPE_T_asString( m_shape ) );
410  break;
411  }
412 
413  return c;
414 }
415 
416 
417 wxPoint PCB_SHAPE::GetArcEnd() const
418 {
419  wxPoint endPoint( m_end ); // start of arc
420 
421  switch( m_shape )
422  {
423  case SHAPE_T::ARC:
424  endPoint = m_thirdPoint;
425  break;
426 
427  default:
428  break;
429  }
430 
431  return endPoint; // after rotation, the end of the arc.
432 }
433 
434 
435 wxPoint PCB_SHAPE::GetArcMid() const
436 {
437  wxPoint endPoint( m_end );
438 
439  switch( m_shape )
440  {
441  case SHAPE_T::ARC:
442  // rotate the starting point of the arc, given by m_End, through half
443  // the angle m_Angle to get the middle of the arc.
444  // m_Start is the arc center
445  endPoint = m_end; // m_End = start point of arc
446  RotatePoint( &endPoint, m_start, -m_angle / 2.0 );
447  break;
448 
449  default:
450  break;
451  }
452 
453  return endPoint; // after rotation, the end of the arc.
454 }
455 
456 
458 {
459  // due to the Y axis orient atan2 needs - y value
460  double angleStart = ArcTangente( GetArcStart().y - GetCenter().y,
461  GetArcStart().x - GetCenter().x );
462 
463  // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
464  // because 180 deg and -180 are very near angles when mapping between -180 ... 180 deg.
465  // and this is not easy to handle in calculations
466  NORMALIZE_ANGLE_POS( angleStart );
467 
468  return angleStart;
469 }
470 
471 
473 {
474  // due to the Y axis orient atan2 needs - y value
475  double angleStart = ArcTangente( GetArcEnd().y - GetCenter().y,
476  GetArcEnd().x - GetCenter().x );
477 
478  // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
479  // because 180 deg and -180 are very near angles when mapping between -180 ... 180 deg.
480  // and this is not easy to handle in calculations
481  NORMALIZE_ANGLE_POS( angleStart );
482 
483  return angleStart;
484 }
485 
486 
488 {
489  double radius = GetLineLength( m_start, m_end );
490 
491  // don't allow degenerate arcs
492  return std::max( 1, KiROUND( radius ) );
493 }
494 
495 
496 void PCB_SHAPE::SetArcGeometry( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd )
497 {
498  SetArcStart( aStart );
499  SetArcEnd( aEnd );
500 
501  // Sadly we currently store center and angle rather than mid. So we have to calculate
502  // those.
503  wxPoint center = GetArcCenter( aStart, aMid, aEnd );
504  VECTOR2D startLine = aStart - center;
505  VECTOR2D endLine = aEnd - center;
506  bool clockwise = GetAngle() > 0;
507  double angle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
508 
509  if( clockwise && angle < 0.0 )
510  angle += 3600.0;
511  else if( !clockwise && angle > 0.0 )
512  angle -= 3600.0;
513 
514  SetAngle( angle, false );
515  SetCenter( center );
516 }
517 
518 
519 void PCB_SHAPE::SetAngle( double aAngle, bool aUpdateEnd )
520 {
521  // m_Angle must be >= -360 and <= +360 degrees
522  m_angle = NormalizeAngle360Max( aAngle );
523 
524  if( aUpdateEnd )
525  {
528  }
529 }
530 
531 
533 {
534  if( !m_parent || m_parent->Type() != PCB_FOOTPRINT_T )
535  return nullptr;
536 
537  return (FOOTPRINT*) m_parent;
538 }
539 
540 
541 void PCB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
542 {
543  EDA_UNITS units = aFrame->GetUserUnits();
544  ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
545  wxString msg;
546 
547  aList.emplace_back( _( "Type" ), _( "Drawing" ) );
548 
549  if( IsLocked() )
550  aList.emplace_back( _( "Status" ), _( "Locked" ) );
551 
552  wxString shape = _( "Shape" );
553 
554  switch( m_shape )
555  {
556  case SHAPE_T::CIRCLE:
557  aList.emplace_back( shape, _( "Circle" ) );
558 
559  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
560  aList.emplace_back( _( "Radius" ), msg );
561  break;
562 
563  case SHAPE_T::ARC:
564  aList.emplace_back( shape, _( "Arc" ) );
565 
566  msg.Printf( wxT( "%.1f" ), m_angle / 10.0 );
567  aList.emplace_back( _( "Angle" ), msg );
568 
569  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
570  aList.emplace_back( _( "Radius" ), msg );
571  break;
572 
573  case SHAPE_T::BEZIER:
574  aList.emplace_back( shape, _( "Curve" ) );
575 
576  msg = MessageTextFromValue( units, GetLength() );
577  aList.emplace_back( _( "Length" ), msg );
578  break;
579 
580  case SHAPE_T::POLY:
581  aList.emplace_back( shape, _( "Polygon" ) );
582 
583  msg.Printf( "%d", GetPolyShape().Outline(0).PointCount() );
584  aList.emplace_back( _( "Points" ), msg );
585  break;
586 
587  case SHAPE_T::RECT:
588  aList.emplace_back( shape, _( "Rectangle" ) );
589 
590  msg = MessageTextFromValue( units, std::abs( m_end.x - m_start.x ) );
591  aList.emplace_back( _( "Width" ), msg );
592 
593  msg = MessageTextFromValue( units, std::abs( m_end.y - m_start.y ) );
594  aList.emplace_back( _( "Height" ), msg );
595  break;
596 
597  case SHAPE_T::SEGMENT:
598  {
599  aList.emplace_back( shape, _( "Segment" ) );
600 
601  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
602  aList.emplace_back( _( "Length" ), msg );
603 
604  // angle counter-clockwise from 3'o-clock
605  const double deg = RAD2DEG( atan2( (double)( m_start.y - m_end.y ),
606  (double)( m_end.x - m_start.x ) ) );
607  aList.emplace_back( _( "Angle" ), wxString::Format( "%.1f", deg ) );
608  }
609  break;
610 
611  default:
612  aList.emplace_back( shape, _( "Unrecognized" ) );
613  break;
614  }
615 
616  aList.emplace_back( _( "Layer" ), GetLayerName() );
617 
618  aList.emplace_back( _( "Line width" ), MessageTextFromValue( units, m_width ) );
619 }
620 
621 
623 {
624  EDA_RECT bbox;
625 
626  bbox.SetOrigin( m_start );
627 
628  switch( m_shape )
629  {
630  case SHAPE_T::RECT:
631  {
632  std::vector<wxPoint> pts = GetRectCorners();
633 
634  bbox = EDA_RECT(); // re-init for merging
635 
636  for( wxPoint& pt : pts )
637  bbox.Merge( pt );
638 
639  break;
640  }
641 
642  case SHAPE_T::SEGMENT:
643  bbox.SetEnd( m_end );
644  break;
645 
646  case SHAPE_T::CIRCLE:
647  bbox.Inflate( GetRadius() );
648  break;
649 
650  case SHAPE_T::ARC:
651  computeArcBBox( bbox );
652  break;
653 
654  case SHAPE_T::POLY:
655  {
656  if( m_poly.IsEmpty() )
657  break;
658 
659  FOOTPRINT* parentFootprint = GetParentFootprint();
660  bbox = EDA_RECT(); // re-init for merging
661 
662  for( auto iter = m_poly.CIterate(); iter; iter++ )
663  {
664  wxPoint pt( iter->x, iter->y );
665 
666  if( parentFootprint ) // Transform, if we belong to a footprint
667  {
668  RotatePoint( &pt, parentFootprint->GetOrientation() );
669  pt += parentFootprint->GetPosition();
670  }
671 
672  bbox.Merge( pt );
673  }
674 
675  break;
676  }
677 
678  case SHAPE_T::BEZIER:
679  bbox.Merge( m_bezierC1 );
680  bbox.Merge( m_bezierC2 );
681  bbox.Merge( m_end );
682  break;
683 
684  default:
685  wxFAIL_MSG( "PCB_SHAPE::GetBoundingBox not implemented for "
686  + SHAPE_T_asString( m_shape ) );
687  break;
688  }
689 
690  bbox.Inflate( m_width / 2 );
691  bbox.Normalize();
692 
693  return bbox;
694 }
695 
696 
697 bool PCB_SHAPE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
698 {
699  int maxdist = aAccuracy + ( m_width / 2 );
700 
701  switch( m_shape )
702  {
703  case SHAPE_T::CIRCLE:
704  {
705  int radius = GetRadius();
706  int dist = KiROUND( EuclideanNorm( aPosition - GetCenter() ) );
707 
708  if( IsFilled() ) // Filled circle hit-test
709  {
710  if( dist <= radius + maxdist )
711  return true;
712  }
713  else // Ring hit-test
714  {
715  if( abs( radius - dist ) <= maxdist )
716  return true;
717  }
718 
719  break;
720  }
721 
722  case SHAPE_T::ARC:
723  {
724  wxPoint relPos = aPosition - GetCenter();
725  int radius = GetRadius();
726  int dist = KiROUND( EuclideanNorm( relPos ) );
727 
728  if( abs( radius - dist ) <= maxdist )
729  {
730  // For arcs, the test point angle must be >= arc angle start
731  // and <= arc angle end
732  // However angle values > 360 deg are not easy to handle
733  // so we calculate the relative angle between arc start point and test point
734  // this relative arc should be < arc angle if arc angle > 0 (CW arc)
735  // and > arc angle if arc angle < 0 (CCW arc)
736  double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
737 
738  double arc_hittest = ArcTangente( relPos.y, relPos.x );
739 
740  // Calculate relative angle between the starting point of the arc, and the test point
741  arc_hittest -= arc_angle_start;
742 
743  // Normalize arc_hittest between 0 ... 360 deg
744  NORMALIZE_ANGLE_POS( arc_hittest );
745 
746  // Check angle: inside the arc angle when it is > 0
747  // and outside the not drawn arc when it is < 0
748  if( GetAngle() >= 0.0 )
749  {
750  if( arc_hittest <= GetAngle() )
751  return true;
752  }
753  else
754  {
755  if( arc_hittest >= ( 3600.0 + GetAngle() ) )
756  return true;
757  }
758  }
759 
760  break;
761  }
762 
763  case SHAPE_T::BEZIER:
764  const_cast<PCB_SHAPE*>( this )->RebuildBezierToSegmentsPointsList( m_width );
765 
766  for( unsigned int i= 1; i < m_bezierPoints.size(); i++)
767  {
768  if( TestSegmentHit( aPosition, m_bezierPoints[ i - 1], m_bezierPoints[i], maxdist ) )
769  return true;
770  }
771 
772  break;
773 
774  case SHAPE_T::SEGMENT:
775  if( TestSegmentHit( aPosition, m_start, m_end, maxdist ) )
776  return true;
777 
778  break;
779 
780  case SHAPE_T::RECT:
781  {
782  std::vector<wxPoint> pts = GetRectCorners();
783 
784  if( IsFilled() ) // Filled rect hit-test
785  {
786  SHAPE_POLY_SET poly;
787  poly.NewOutline();
788 
789  for( const wxPoint& pt : pts )
790  poly.Append( pt );
791 
792  if( poly.Collide( VECTOR2I( aPosition ), maxdist ) )
793  return true;
794  }
795  else // Open rect hit-test
796  {
797  if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
798  || TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
799  || TestSegmentHit( aPosition, pts[2], pts[3], maxdist )
800  || TestSegmentHit( aPosition, pts[3], pts[0], maxdist ) )
801  {
802  return true;
803  }
804  }
805 
806  break;
807  }
808 
809  case SHAPE_T::POLY:
810  if( IsFilled() )
811  {
812  return m_poly.Collide( VECTOR2I( aPosition ), maxdist );
813  }
814  else
815  {
817  return m_poly.CollideEdge( VECTOR2I( aPosition ), dummy, maxdist );
818  }
819 
820  break;
821 
822  default:
823  wxFAIL_MSG( "PCB_SHAPE::HitTest (point) not implemented for "
824  + SHAPE_T_asString( m_shape ) );
825  break;
826  }
827 
828  return false;
829 }
830 
831 
832 bool PCB_SHAPE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
833 {
834  EDA_RECT arect = aRect;
835  arect.Normalize();
836  arect.Inflate( aAccuracy );
837 
838  EDA_RECT arcRect;
839  EDA_RECT bb = GetBoundingBox();
840 
841  switch( m_shape )
842  {
843  case SHAPE_T::CIRCLE:
844  // Test if area intersects or contains the circle:
845  if( aContained )
846  {
847  return arect.Contains( bb );
848  }
849  else
850  {
851  // If the rectangle does not intersect the bounding box, this is a much quicker test
852  if( !aRect.Intersects( bb ) )
853  {
854  return false;
855  }
856  else
857  {
858  return arect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() );
859  }
860  }
861 
862  break;
863 
864  case SHAPE_T::ARC:
865  // Test for full containment of this arc in the rect
866  if( aContained )
867  {
868  return arect.Contains( bb );
869  }
870  else
871  {
872  // Test if the rect crosses the arc
873  arcRect = bb.Common( arect );
874 
875  /* All following tests must pass:
876  * 1. Rectangle must intersect arc BoundingBox
877  * 2. Rectangle must cross the outside of the arc
878  */
879  return arcRect.Intersects( arect ) &&
881  }
882 
883  break;
884 
885  case SHAPE_T::RECT:
886  if( aContained )
887  {
888  return arect.Contains( bb );
889  }
890  else
891  {
892  std::vector<wxPoint> pts = GetRectCorners();
893 
894  // Account for the width of the lines
895  arect.Inflate( GetWidth() / 2 );
896  return ( arect.Intersects( pts[0], pts[1] )
897  || arect.Intersects( pts[1], pts[2] )
898  || arect.Intersects( pts[2], pts[3] )
899  || arect.Intersects( pts[3], pts[0] ) );
900  }
901 
902  break;
903 
904  case SHAPE_T::SEGMENT:
905  if( aContained )
906  {
907  return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
908  }
909  else
910  {
911  // Account for the width of the line
912  arect.Inflate( GetWidth() / 2 );
913  return arect.Intersects( GetStart(), GetEnd() );
914  }
915 
916  break;
917 
918  case SHAPE_T::POLY:
919  if( aContained )
920  {
921  return arect.Contains( bb );
922  }
923  else
924  {
925  // Fast test: if aRect is outside the polygon bounding box,
926  // rectangles cannot intersect
927  if( !arect.Intersects( bb ) )
928  return false;
929 
930  // Account for the width of the line
931  arect.Inflate( GetWidth() / 2 );
932 
933  // Polygons in footprints use coordinates relative to the footprint.
934  // Therefore, instead of using m_poly, we make a copy which is translated
935  // to the actual location in the board.
936 
937  FOOTPRINT* fp{ GetParentFootprint() };
938  double orientation{ fp ? -DECIDEG2RAD( fp->GetOrientation() ) : 0.0 };
939  wxPoint offset;
940 
941  if( fp )
942  offset = fp->GetPosition();
943 
944  SHAPE_POLY_SET poly{ m_poly };
945  poly.Rotate( orientation );
946  poly.Move( offset );
947 
948  int count = poly.TotalVertices();
949 
950  for( int ii = 0; ii < count; ii++ )
951  {
952  auto vertex = poly.CVertex( ii );
953  auto vertexNext = poly.CVertex(( ii + 1 ) % count );
954 
955  // Test if the point is within aRect
956  if( arect.Contains( ( wxPoint ) vertex ) )
957  return true;
958 
959  // Test if this edge intersects aRect
960  if( arect.Intersects( ( wxPoint ) vertex, ( wxPoint ) vertexNext ) )
961  return true;
962  }
963  }
964 
965  break;
966 
967  case SHAPE_T::BEZIER:
968  if( aContained )
969  {
970  return arect.Contains( bb );
971  }
972  else
973  {
974  // Fast test: if aRect is outside the polygon bounding box,
975  // rectangles cannot intersect
976  if( !arect.Intersects( bb ) )
977  return false;
978 
979  // Account for the width of the line
980  arect.Inflate( GetWidth() / 2 );
981  unsigned count = m_bezierPoints.size();
982 
983  for( unsigned ii = 1; ii < count; ii++ )
984  {
985  wxPoint vertex = m_bezierPoints[ ii - 1];
986  wxPoint vertexNext = m_bezierPoints[ii];
987 
988  // Test if the point is within aRect
989  if( arect.Contains( ( wxPoint ) vertex ) )
990  return true;
991 
992  // Test if this edge intersects aRect
993  if( arect.Intersects( vertex, vertexNext ) )
994  return true;
995  }
996  }
997 
998  break;
999 
1000  default:
1001  wxFAIL_MSG( "PCB_SHAPE::HitTest (rect) not implemented for "
1002  + SHAPE_T_asString( m_shape ) );
1003  break;
1004  }
1005 
1006  return false;
1007 }
1008 
1009 
1010 wxString PCB_SHAPE::GetSelectMenuText( EDA_UNITS aUnits ) const
1011 {
1012  return wxString::Format( _( "%s on %s" ), ShowShape( m_shape ), GetLayerName() );
1013 }
1014 
1015 
1017 {
1018  return BITMAPS::add_dashed_line;
1019 }
1020 
1021 
1023 {
1024  return new PCB_SHAPE( *this );
1025 }
1026 
1027 
1029 {
1030  // For arcs - do not include the center point in the bounding box,
1031  // it is redundant for displaying an arc
1032  if( m_shape == SHAPE_T::ARC )
1033  {
1034  EDA_RECT bbox;
1035  bbox.SetOrigin( m_end );
1036  computeArcBBox( bbox );
1037  return BOX2I( bbox.GetOrigin(), bbox.GetSize() );
1038  }
1039 
1040  BOX2I return_box = EDA_ITEM::ViewBBox();
1041  return_box.Inflate( m_width ); // Technically m_width / 2, but it never hurts to be a
1042  // bit large to account for selection shadows, etc.
1043 
1044  return return_box;
1045 }
1046 
1047 
1048 std::vector<wxPoint> PCB_SHAPE::GetRectCorners() const
1049 {
1050  std::vector<wxPoint> pts;
1051  FOOTPRINT* parentFootprint = GetParentFootprint();
1052  wxPoint topLeft = GetStart();
1053  wxPoint botRight = GetEnd();
1054 
1055  // Un-rotate rect topLeft and botRight
1056  if( parentFootprint && KiROUND( parentFootprint->GetOrientation() ) % 900 != 0 )
1057  {
1058  topLeft -= parentFootprint->GetPosition();
1059  RotatePoint( &topLeft, -parentFootprint->GetOrientation() );
1060 
1061  botRight -= parentFootprint->GetPosition();
1062  RotatePoint( &botRight, -parentFootprint->GetOrientation() );
1063  }
1064 
1065  // Set up the un-rotated 4 corners
1066  pts.emplace_back( topLeft );
1067  pts.emplace_back( botRight.x, topLeft.y );
1068  pts.emplace_back( botRight );
1069  pts.emplace_back( topLeft.x, botRight.y );
1070 
1071  // Now re-rotate the 4 corners to get a diamond
1072  if( parentFootprint && KiROUND( parentFootprint->GetOrientation() ) % 900 != 0 )
1073  {
1074  for( wxPoint& pt : pts )
1075  {
1076  RotatePoint( &pt, parentFootprint->GetOrientation() );
1077  pt += parentFootprint->GetPosition();
1078  }
1079  }
1080 
1081  return pts;
1082 }
1083 
1084 
1086 {
1087  // Do not include the center, which is not necessarily
1088  // inside the BB of a arc with a small angle
1089  aBBox.SetOrigin( m_end );
1090 
1091  wxPoint end = m_end;
1092  RotatePoint( &end, m_start, -m_angle );
1093  aBBox.Merge( end );
1094 
1095  // Determine the starting quarter
1096  // 0 right-bottom
1097  // 1 left-bottom
1098  // 2 left-top
1099  // 3 right-top
1100  unsigned int quarter = 0; // assume right-bottom
1101 
1102  if( m_end.x < m_start.x )
1103  {
1104  if( m_end.y <= m_start.y )
1105  quarter = 2;
1106  else // ( m_End.y > m_Start.y )
1107  quarter = 1;
1108  }
1109  else if( m_end.x >= m_start.x )
1110  {
1111  if( m_end.y < m_start.y )
1112  quarter = 3;
1113  else if( m_end.x == m_start.x )
1114  quarter = 1;
1115  }
1116 
1117  int radius = GetRadius();
1118  int angle = (int) GetArcAngleStart() % 900 + m_angle;
1119  bool directionCW = ( m_angle > 0 ); // Is the direction of arc clockwise?
1120 
1121  // Make the angle positive, so we go clockwise and merge points belonging to the arc
1122  if( !directionCW )
1123  {
1124  angle = 900 - angle;
1125  quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic
1126  }
1127 
1128  while( angle > 900 )
1129  {
1130  switch( quarter )
1131  {
1132  case 0: aBBox.Merge( wxPoint( m_start.x, m_start.y + radius ) ); break; // down
1133  case 1: aBBox.Merge( wxPoint( m_start.x - radius, m_start.y ) ); break; // left
1134  case 2: aBBox.Merge( wxPoint( m_start.x, m_start.y - radius ) ); break; // up
1135  case 3: aBBox.Merge( wxPoint( m_start.x + radius, m_start.y ) ); break; // right
1136  }
1137 
1138  if( directionCW )
1139  ++quarter;
1140  else
1141  quarter += 3; // -1 modulo arithmetic
1142 
1143  quarter %= 4;
1144  angle -= 900;
1145  }
1146 
1147  aBBox.Inflate( m_width ); // Technically m_width / 2, but it doesn't hurt to have the
1148  // bounding box a bit large to account for drawing clearances,
1149  // etc.
1150 }
1151 
1152 
1153 void PCB_SHAPE::SetPolyPoints( const std::vector<wxPoint>& aPoints )
1154 {
1156  m_poly.NewOutline();
1157 
1158  for ( const wxPoint& p : aPoints )
1159  m_poly.Append( p.x, p.y );
1160 }
1161 
1162 
1163 std::vector<SHAPE*> PCB_SHAPE::MakeEffectiveShapes() const
1164 {
1165  std::vector<SHAPE*> effectiveShapes;
1166 
1167  switch( m_shape )
1168  {
1169  case SHAPE_T::ARC:
1170  effectiveShapes.emplace_back( new SHAPE_ARC( GetCenter(), GetArcStart(),
1171  GetAngle() / 10.0, m_width ) );
1172  break;
1173 
1174  case SHAPE_T::SEGMENT:
1175  effectiveShapes.emplace_back( new SHAPE_SEGMENT( GetStart(), GetEnd(), m_width ) );
1176  break;
1177 
1178  case SHAPE_T::RECT:
1179  {
1180  std::vector<wxPoint> pts = GetRectCorners();
1181 
1182  if( IsFilled() )
1183  {
1184  effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
1185  }
1186 
1187  if( m_width > 0 || !IsFilled() )
1188  {
1189  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], m_width ) );
1190  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], m_width ) );
1191  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], m_width ) );
1192  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], m_width ) );
1193  }
1194 
1195  break;
1196  }
1197 
1198  case SHAPE_T::CIRCLE:
1199  {
1200  if( IsFilled() )
1201  {
1202  effectiveShapes.emplace_back( new SHAPE_CIRCLE( GetCenter(), GetRadius() ) );
1203  }
1204 
1205  if( m_width > 0 || !IsFilled() )
1206  {
1207  // SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
1208  SHAPE_ARC circle( GetCenter(), GetEnd(), 360.0 );
1209  SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
1210 
1211  for( int i = 0; i < l.SegmentCount(); i++ )
1212  {
1213  effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A,
1214  l.Segment( i ).B, m_width ) );
1215  }
1216  }
1217 
1218  break;
1219  }
1220 
1221  case SHAPE_T::BEZIER:
1222  {
1223  auto bezierPoints = buildBezierToSegmentsPointsList( GetWidth() );
1224  wxPoint start_pt = bezierPoints[0];
1225 
1226  for( unsigned int jj = 1; jj < bezierPoints.size(); jj++ )
1227  {
1228  wxPoint end_pt = bezierPoints[jj];
1229  effectiveShapes.emplace_back( new SHAPE_SEGMENT( start_pt, end_pt, m_width ) );
1230  start_pt = end_pt;
1231  }
1232 
1233  break;
1234  }
1235 
1236  case SHAPE_T::POLY:
1237  {
1239  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_parent );
1240 
1241  if( parentFootprint )
1242  {
1243  l.Rotate( -parentFootprint->GetOrientationRadians() );
1244  l.Move( parentFootprint->GetPosition() );
1245  }
1246 
1247  if( IsFilled() )
1248  {
1249  effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) );
1250  }
1251 
1252  if( m_width > 0 || !IsFilled() )
1253  {
1254  for( int i = 0; i < l.SegmentCount(); i++ )
1255  effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ), m_width ) );
1256  }
1257 
1258  break;
1259  }
1260 
1261  default:
1262  wxFAIL_MSG( "PCB_SHAPE::MakeEffectiveShapes unsupported PCB_SHAPE shape: "
1263  + SHAPE_T_asString( m_shape ) );
1264  break;
1265  }
1266 
1267  return effectiveShapes;
1268 }
1269 
1270 
1271 std::shared_ptr<SHAPE> PCB_SHAPE::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
1272 {
1273  return std::make_shared<SHAPE_COMPOUND>( MakeEffectiveShapes() );
1274 }
1275 
1276 
1277 void PCB_SHAPE::DupPolyPointsList( std::vector<wxPoint>& aBuffer ) const
1278 {
1279  if( m_poly.OutlineCount() )
1280  {
1281  int pointCount = m_poly.COutline( 0 ).PointCount();
1282 
1283  if( pointCount )
1284  {
1285  aBuffer.reserve( pointCount );
1286 
1287  for ( auto iter = m_poly.CIterate(); iter; iter++ )
1288  aBuffer.emplace_back( iter->x, iter->y );
1289  }
1290  }
1291 }
1292 
1293 
1295 {
1296  // return true if the polygonal shape is valid (has more than 2 points)
1297  if( GetPolyShape().OutlineCount() == 0 )
1298  return false;
1299 
1300  const SHAPE_LINE_CHAIN& outline = ( (SHAPE_POLY_SET&)GetPolyShape() ).Outline( 0 );
1301 
1302  return outline.PointCount() > 2;
1303 }
1304 
1305 
1307 {
1308  // return the number of corners of the polygonal shape
1309  // this shape is expected to be only one polygon without hole
1310  if( GetPolyShape().OutlineCount() )
1311  return GetPolyShape().VertexCount( 0 );
1312 
1313  return 0;
1314 }
1315 
1316 
1318 {
1319  PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
1320  assert( image );
1321 
1322  std::swap( m_width, image->m_width );
1323  std::swap( m_start, image->m_start );
1324  std::swap( m_end, image->m_end );
1325  std::swap( m_thirdPoint, image->m_thirdPoint );
1326  std::swap( m_shape, image->m_shape );
1327  std::swap( m_angle, image->m_angle );
1328  std::swap( m_bezierC1, image->m_bezierC1 );
1329  std::swap( m_bezierC2, image->m_bezierC2 );
1330  std::swap( m_bezierPoints, image->m_bezierPoints );
1331  std::swap( m_poly, image->m_poly );
1332  std::swap( m_layer, image->m_layer );
1333  std::swap( m_flags, image->m_flags );
1334  std::swap( m_status, image->m_status );
1335  std::swap( m_parent, image->m_parent );
1336  std::swap( m_forceVisible, image->m_forceVisible );
1337 }
1338 
1339 
1341  const BOARD_ITEM* aSecond ) const
1342 {
1343  if( aFirst->Type() != aSecond->Type() )
1344  return aFirst->Type() < aSecond->Type();
1345 
1346  if( aFirst->GetLayer() != aSecond->GetLayer() )
1347  return aFirst->GetLayer() < aSecond->GetLayer();
1348 
1349  if( aFirst->Type() == PCB_SHAPE_T )
1350  {
1351  const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( aFirst );
1352  const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( aSecond );
1353 
1354  if( dwgA->GetShape() != dwgB->GetShape() )
1355  return dwgA->GetShape() < dwgB->GetShape();
1356  }
1357 
1358  return aFirst->m_Uuid < aSecond->m_Uuid;
1359 }
1360 
1361 
1362 static struct DRAWSEGMENT_DESC
1363 {
1365  {
1369 
1370  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "Thickness" ),
1372  // TODO show certain properties depending on the shape
1373  //propMgr.AddProperty( new PROPERTY<PCB_SHAPE, double>( _HKI( "Angle" ),
1374  // &PCB_SHAPE::SetAngle, &PCB_SHAPE::GetAngle, PROPERTY_DISPLAY::DECIDEGREE ) );
1375  // TODO or may have different names (arcs)
1376  // TODO type?
1377  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "End X" ),
1379  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "End Y" ),
1381  }
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
wxPoint GetArcEnd() const
Definition: pcb_shape.cpp:417
bool IsPolyShapeValid() const
Definition: pcb_shape.cpp:1294
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:479
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:104
BOX2< VECTOR2I > BOX2I
Definition: box2.h:506
Arcs (with rounded ends)
bool IsFilled() const
Definition: pcb_shape.h:75
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:41
Bezier Curve.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:65
#define TYPE_HASH(x)
Definition: property.h:59
wxPoint m_end
Definition: pcb_shape.h:346
double GetOrientationRadians() const
Definition: footprint.h:192
int OutlineCount() const
Return the number of vertices in a given outline/hole.
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:222
void Merge(const EDA_RECT &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: eda_rect.cpp:432
polygon (not yet used for tracks, but could be in microwave apps)
static struct DRAWSEGMENT_DESC _DRAWSEGMENT_DESC
T NormalizeAngle360Max(T Angle)
Normalize angle to be >=-360.0 and <= 360.0 Angle can be equal to -360 or +360.
Definition: trigo.h:241
SHAPE_POLY_SET & GetPolyShape()
Definition: pcb_shape.h:240
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: pcb_shape.h:134
int GetEndY()
Definition: pcb_shape.h:135
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
Definition: pcb_shape.cpp:1317
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:192
Implementation of conversion functions that require both schematic and board internal units.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
void Scale(double aScale)
Definition: pcb_shape.cpp:191
SHAPE_T GetShape() const
Definition: pcb_shape.h:110
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Convert a Bezier curve to a polygon.
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_shape.cpp:1022
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
int GetRadius() const
Return the radius of this item.
Definition: pcb_shape.cpp:487
void Move(const VECTOR2I &aVector) override
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:521
bool IsEmpty() const
virtual BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: pcb_shape.cpp:1016
std::vector< wxPoint > GetRectCorners() const
Definition: pcb_shape.cpp:1048
int GetWidth() const
Definition: pcb_shape.h:97
double RAD2DEG(double rad)
Definition: trigo.h:230
double GetArcAngleStart() const
Definition: pcb_shape.cpp:457
int VertexCount(int aOutline=-1, int aHole=-1) const
Returns the number of holes in a given outline.
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition: pcb_shape.cpp:1340
void computeArcBBox(EDA_RECT &aBBox) const
Definition: pcb_shape.cpp:1085
usual segment : line with rounded ends
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pcb_shape.cpp:1028
double GetOrientation() const
Definition: footprint.h:190
#define DEFAULT_LINE_WIDTH
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:121
virtual ORIGIN_TRANSFORMS & GetOriginTransforms()
Return a reference to the default ORIGIN_TRANSFORMS object.
bool IntersectsCircleEdge(const wxPoint &aCenter, const int aRadius, const int aWidth) const
Test for intersection between this rect and the edge (radius) of a circle.
Definition: eda_rect.cpp:331
EDA_ITEM_FLAGS m_status
Definition: eda_item.h:478
EDA_RECT Common(const EDA_RECT &aRect) const
Return the area that is common with another rectangle.
Definition: eda_rect.cpp:489
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:481
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:290
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pcb_shape.cpp:1271
The base class for create windows for drawing purpose.
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:241
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
void DupPolyPointsList(std::vector< wxPoint > &aBuffer) const
Duplicate the list of corners in a std::vector<wxPoint>
Definition: pcb_shape.cpp:1277
virtual bool IsLocked() const
Definition: board_item.cpp:78
int PointCount() const
Return the number of points (vertices) in this line chain.
#define REGISTER_TYPE(x)
Definition: property_mgr.h:248
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
This file contains miscellaneous commonly used macros and functions.
wxPoint GetArcStart() const
Definition: pcb_shape.h:156
wxPoint m_thirdPoint
Definition: pcb_shape.h:347
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Test if aPosition is contained within or on the bounding box of an item.
Definition: pcb_shape.cpp:697
PCB_SHAPE(BOARD_ITEM *aParent=nullptr, KICAD_T idtype=PCB_SHAPE_T)
Definition: pcb_shape.cpp:48
void SetArcGeometry(const wxPoint &aStart, const wxPoint &aMid, const wxPoint &aEnd)
Set the three controlling points for an arc.
Definition: pcb_shape.cpp:496
virtual void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:156
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Display value expressed in distance units (mm/inch)
Definition: property.h:53
void SetEndY(int y)
Definition: pcb_shape.h:138
void Move(const VECTOR2I &aVector) override
const std::vector< VECTOR2I > & CPoints() const
SHAPE_POLY_SET m_poly
Definition: pcb_shape.h:355
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
const wxPoint GetOrigin() const
Definition: eda_rect.h:101
void SetEnd(int x, int y)
Definition: eda_rect.h:182
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.cpp:385
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: pcb_shape.h:124
bool TestSegmentHit(const wxPoint &aRefPoint, const wxPoint &aStart, const wxPoint &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static wxString SHAPE_T_asString(SHAPE_T a)
Definition: board_item.h:57
int GetEndX()
Definition: pcb_shape.h:136
#define _(s)
void SetPosition(const wxPoint &aPos) override
Definition: pcb_shape.cpp:64
double m_angle
Definition: pcb_shape.h:350
double GetArcAngleEnd() const
Definition: pcb_shape.cpp:472
void SetCenter(const wxPoint &aCenterPoint)
Definition: pcb_shape.h:198
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
int NewOutline()
Creates a new hole in a given outline.
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
int SegmentCount() const
Return the number of segments in this line chain.
void SetEndX(int x)
Definition: pcb_shape.h:139
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: pcb_shape.cpp:1010
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
const KIID m_Uuid
Definition: eda_item.h:475
Some functions to handle hotkeys in KiCad.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0)) override
Rotate all vertices by a given angle.
wxPoint m_start
Definition: pcb_shape.h:345
EDA_UNITS
Definition: eda_units.h:38
void Normalize()
Ensures that the height ant width are positive.
Definition: eda_rect.cpp:35
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
wxPoint GetPosition() const override
Definition: pcb_shape.cpp:70
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX &aClosestVertex, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
std::vector< SHAPE * > MakeEffectiveShapes() const
Make a set of SHAPE objects representing the PCB_SHAPE.
Definition: pcb_shape.cpp:1163
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:281
Bezier curves to polygon converter.
Definition: bezier_curves.h:36
SEG Segment(int aIndex)
Return a copy of the aIndex-th segment in the line chain.
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:498
int m_width
Definition: pcb_shape.h:343
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
FOOTPRINT * GetParentFootprint() const
Return the parent footprint or NULL if PCB_SHAPE does not belong to a footprint.
Definition: pcb_shape.cpp:532
A class to perform either relative or absolute display origin transforms for a single axis of a point...
Represent a polyline (an zero-thickness chain of connected line segments).
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:64
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void AddProperty(PROPERTY_BASE *aProperty)
Register a property.
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_shape.cpp:622
VECTOR2I A
Definition: seg.h:48
double GetAngle() const
Definition: pcb_shape.h:107
Handle the component boundary box.
Definition: eda_rect.h:42
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
const wxPoint GetFocusPosition() const override
Allows items to return their visual center rather than their anchor.
Definition: pcb_shape.cpp:79
void SetWidth(int aWidth)
Definition: pcb_shape.h:96
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
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
int GetPointCount() const
Definition: pcb_shape.cpp:1306
wxPoint GetPosition() const override
Definition: footprint.h:186
wxPoint Centre() const
Definition: eda_rect.h:55
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments.
Definition: pcb_shape.cpp:359
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
void SetArcEnd(const wxPoint &aArcEndPoint)
Initialize the end arc point.
Definition: pcb_shape.h:193
PCB_LAYER_ID m_layer
Definition: board_item.h:353
wxPoint m_bezierC1
Definition: pcb_shape.h:351
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:50
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:62
virtual void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pcb_shape.cpp:296
wxPoint GetArcMid() const
Definition: pcb_shape.cpp:435
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
bool m_filled
Definition: pcb_shape.h:344
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
segment with non rounded ends
std::vector< wxPoint > m_bezierPoints
Definition: pcb_shape.h:354
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:194
static wxString ShowShape(SHAPE_T aShape)
Convert the enum #PCB_SHAPE_TYPE_T integer value to a wxString.
Definition: board_item.cpp:35
bool m_forceVisible
Definition: eda_item.h:480
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Set the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:519
wxPoint m_bezierC2
Definition: pcb_shape.h:352
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:87
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
SHAPE_T m_shape
Definition: pcb_shape.h:349
static constexpr int Millimeter2iu(double mm)
#define _HKI(x)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition: pcb_shape.cpp:541
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:171
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
Definition: pcb_shape.cpp:1153
const std::vector< wxPoint > buildBezierToSegmentsPointsList(int aMinSegLen) const
Definition: pcb_shape.cpp:372
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
Definition: pcb_shape.h:183
const wxSize GetSize() const
Definition: eda_rect.h:91
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
double GetLength() const
Return the length of the track using the hypotenuse calculation.
Definition: pcb_shape.cpp:120
VECTOR2I B
Definition: seg.h:49