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