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  // PCB_SHAPE items are not allowed on copper layers, so
312  // copper layers count is not taken in account in Flip transform
313  SetLayer( FlipLayer( GetLayer() ) );
314 }
315 
316 
318 {
319  // Has meaning only for S_CURVE DRAW_SEGMENT shape
320  if( m_shape != S_CURVE )
321  {
322  m_bezierPoints.clear();
323  return;
324  }
325  // Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
327 }
328 
329 
330 const std::vector<wxPoint> PCB_SHAPE::buildBezierToSegmentsPointsList( int aMinSegLen ) const
331 {
332  std::vector<wxPoint> bezierPoints;
333 
334  // Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
335  std::vector<wxPoint> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end };
336  BEZIER_POLY converter( ctrlPoints );
337  converter.GetPoly( bezierPoints, aMinSegLen );
338 
339  return bezierPoints;
340 }
341 
342 
343 wxPoint PCB_SHAPE::GetCenter() const
344 {
345  wxPoint c;
346 
347  switch( m_shape )
348  {
349  case S_ARC:
350  case S_CIRCLE:
351  c = m_start;
352  break;
353 
354  case S_SEGMENT:
355  // Midpoint of the line
356  c = ( GetStart() + GetEnd() ) / 2;
357  break;
358 
359  case S_POLYGON:
360  case S_RECT:
361  case S_CURVE:
362  c = GetBoundingBox().Centre();
363  break;
364 
365  default:
366  wxFAIL_MSG( "PCB_SHAPE::GetCentre not implemented for "
368  break;
369  }
370 
371  return c;
372 }
373 
374 
375 wxPoint PCB_SHAPE::GetArcEnd() const
376 {
377  wxPoint endPoint( m_end ); // start of arc
378 
379  switch( m_shape )
380  {
381  case S_ARC:
382  endPoint = m_thirdPoint;
383  break;
384 
385  default:
386  break;
387  }
388 
389  return endPoint; // after rotation, the end of the arc.
390 }
391 
392 
393 wxPoint PCB_SHAPE::GetArcMid() const
394 {
395  wxPoint endPoint( m_end );
396 
397  switch( m_shape )
398  {
399  case S_ARC:
400  // rotate the starting point of the arc, given by m_End, through half
401  // the angle m_Angle to get the middle of the arc.
402  // m_Start is the arc centre
403  endPoint = m_end; // m_End = start point of arc
404  RotatePoint( &endPoint, m_start, -m_angle / 2.0 );
405  break;
406 
407  default:
408  break;
409  }
410 
411  return endPoint; // after rotation, the end of the arc.
412 }
413 
414 
416 {
417  // due to the Y axis orient atan2 needs - y value
418  double angleStart = ArcTangente( GetArcStart().y - GetCenter().y,
419  GetArcStart().x - GetCenter().x );
420 
421  // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
422  // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
423  // and this is not easy to handle in calculations
424  NORMALIZE_ANGLE_POS( angleStart );
425 
426  return angleStart;
427 }
428 
430 {
431  // due to the Y axis orient atan2 needs - y value
432  double angleStart = ArcTangente( GetArcEnd().y - GetCenter().y,
433  GetArcEnd().x - GetCenter().x );
434 
435  // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
436  // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
437  // and this is not easy to handle in calculations
438  NORMALIZE_ANGLE_POS( angleStart );
439 
440  return angleStart;
441 }
442 
443 
444 void PCB_SHAPE::SetAngle( double aAngle, bool aUpdateEnd )
445 {
446  // m_Angle must be >= -360 and <= +360 degrees
447  m_angle = NormalizeAngle360Max( aAngle );
448 
449  if( aUpdateEnd )
450  {
453  }
454 }
455 
456 
458 {
459  if( !m_parent || m_parent->Type() != PCB_FOOTPRINT_T )
460  return NULL;
461 
462  return (FOOTPRINT*) m_parent;
463 }
464 
465 
466 void PCB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
467 {
468  EDA_UNITS units = aFrame->GetUserUnits();
469  ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
470  wxString msg;
471 
472  aList.emplace_back( _( "Type" ), _( "Drawing" ) );
473 
474  wxString shape = _( "Shape" );
475 
476  switch( m_shape )
477  {
478  case S_CIRCLE:
479  aList.emplace_back( shape, _( "Circle" ) );
480 
481  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
482  aList.emplace_back( _( "Radius" ), msg );
483  break;
484 
485  case S_ARC:
486  aList.emplace_back( shape, _( "Arc" ) );
487 
488  msg.Printf( wxT( "%.1f" ), m_angle / 10.0 );
489  aList.emplace_back( _( "Angle" ), msg );
490 
491  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
492  aList.emplace_back( _( "Radius" ), msg );
493  break;
494 
495  case S_CURVE:
496  aList.emplace_back( shape, _( "Curve" ) );
497 
498  msg = MessageTextFromValue( units, GetLength() );
499  aList.emplace_back( _( "Length" ), msg );
500  break;
501 
502  case S_POLYGON:
503  aList.emplace_back( shape, _( "Polygon" ) );
504 
505  msg.Printf( "%d", GetPolyShape().Outline(0).PointCount() );
506  aList.emplace_back( _( "Points" ), msg );
507  break;
508 
509  case S_RECT:
510  aList.emplace_back( shape, _( "Rectangle" ) );
511 
512  msg = MessageTextFromValue( units, std::abs( m_end.x - m_start.x ) );
513  aList.emplace_back( _( "Width" ), msg );
514 
515  msg = MessageTextFromValue( units, std::abs( m_end.y - m_start.y ) );
516  aList.emplace_back( _( "Height" ), msg );
517  break;
518 
519  case S_SEGMENT:
520  {
521  aList.emplace_back( shape, _( "Segment" ) );
522 
523  msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) );
524  aList.emplace_back( _( "Length" ), msg );
525 
526  // angle counter-clockwise from 3'o-clock
527  const double deg = RAD2DEG( atan2( (double)( m_start.y - m_end.y ),
528  (double)( m_end.x - m_start.x ) ) );
529  aList.emplace_back( _( "Angle" ), wxString::Format( "%.1f", deg ) );
530  }
531  break;
532 
533  default:
534  aList.emplace_back( shape, _( "Unrecognized" ) );
535  break;
536  }
537 
538  aList.emplace_back( _( "Layer" ), GetLayerName() );
539 
540  aList.emplace_back( _( "Width" ), MessageTextFromValue( units, m_width ) );
541 }
542 
543 
545 {
546  EDA_RECT bbox;
547 
548  bbox.SetOrigin( m_start );
549 
550  switch( m_shape )
551  {
552  case S_RECT:
553  {
554  std::vector<wxPoint> pts = GetRectCorners();
555 
556  bbox = EDA_RECT(); // re-init for merging
557 
558  for( wxPoint& pt : pts )
559  bbox.Merge( pt );
560  }
561  break;
562 
563  case S_SEGMENT:
564  bbox.SetEnd( m_end );
565  break;
566 
567  case S_CIRCLE:
568  bbox.Inflate( GetRadius() );
569  break;
570 
571  case S_ARC:
572  computeArcBBox( bbox );
573  break;
574 
575  case S_POLYGON:
576  {
577  if( m_poly.IsEmpty() )
578  break;
579 
580  FOOTPRINT* parentFootprint = GetParentFootprint();
581  bbox = EDA_RECT(); // re-init for merging
582 
583  for( auto iter = m_poly.CIterate(); iter; iter++ )
584  {
585  wxPoint pt( iter->x, iter->y );
586 
587  if( parentFootprint ) // Transform, if we belong to a footprint
588  {
589  RotatePoint( &pt, parentFootprint->GetOrientation() );
590  pt += parentFootprint->GetPosition();
591  }
592 
593  bbox.Merge( pt );
594  }
595  }
596  break;
597 
598  case S_CURVE:
599  bbox.Merge( m_bezierC1 );
600  bbox.Merge( m_bezierC2 );
601  bbox.Merge( m_end );
602  break;
603 
604  default:
605  wxFAIL_MSG( "PCB_SHAPE::GetBoundingBox not implemented for "
607  break;
608  }
609 
610  bbox.Inflate( m_width / 2 );
611  bbox.Normalize();
612 
613  return bbox;
614 }
615 
616 
617 bool PCB_SHAPE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
618 {
619  int maxdist = aAccuracy + ( m_width / 2 );
620 
621  switch( m_shape )
622  {
623  case S_CIRCLE:
624  {
625  int radius = GetRadius();
626  int dist = KiROUND( EuclideanNorm( aPosition - GetCenter() ) );
627 
628  if( IsFilled() ) // Filled circle hit-test
629  {
630  if( dist <= radius + maxdist )
631  return true;
632  }
633  else // Ring hit-test
634  {
635  if( abs( radius - dist ) <= maxdist )
636  return true;
637  }
638  }
639  break;
640 
641  case S_ARC:
642  {
643  wxPoint relPos = aPosition - GetCenter();
644  int radius = GetRadius();
645  int dist = KiROUND( EuclideanNorm( relPos ) );
646 
647  if( abs( radius - dist ) <= maxdist )
648  {
649  // For arcs, the test point angle must be >= arc angle start
650  // and <= arc angle end
651  // However angle values > 360 deg are not easy to handle
652  // so we calculate the relative angle between arc start point and teast point
653  // this relative arc should be < arc angle if arc angle > 0 (CW arc)
654  // and > arc angle if arc angle < 0 (CCW arc)
655  double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
656 
657  double arc_hittest = ArcTangente( relPos.y, relPos.x );
658 
659  // Calculate relative angle between the starting point of the arc, and the test point
660  arc_hittest -= arc_angle_start;
661 
662  // Normalise arc_hittest between 0 ... 360 deg
663  NORMALIZE_ANGLE_POS( arc_hittest );
664 
665  // Check angle: inside the arc angle when it is > 0
666  // and outside the not drawn arc when it is < 0
667  if( GetAngle() >= 0.0 )
668  {
669  if( arc_hittest <= GetAngle() )
670  return true;
671  }
672  else
673  {
674  if( arc_hittest >= ( 3600.0 + GetAngle() ) )
675  return true;
676  }
677  }
678  }
679  break;
680 
681  case S_CURVE:
682  const_cast<PCB_SHAPE*>( this )->RebuildBezierToSegmentsPointsList( m_width );
683 
684  for( unsigned int i= 1; i < m_bezierPoints.size(); i++)
685  {
686  if( TestSegmentHit( aPosition, m_bezierPoints[ i - 1], m_bezierPoints[i], maxdist ) )
687  return true;
688  }
689 
690  break;
691 
692  case S_SEGMENT:
693  if( TestSegmentHit( aPosition, m_start, m_end, maxdist ) )
694  return true;
695 
696  break;
697 
698  case S_RECT:
699  {
700  std::vector<wxPoint> pts = GetRectCorners();
701 
702  if( IsFilled() ) // Filled rect hit-test
703  {
704  SHAPE_POLY_SET poly;
705  poly.NewOutline();
706 
707  for( const wxPoint& pt : pts )
708  poly.Append( pt );
709 
710  if( poly.Collide( VECTOR2I( aPosition ), maxdist ) )
711  return true;
712  }
713  else // Open rect hit-test
714  {
715  if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
716  || TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
717  || TestSegmentHit( aPosition, pts[2], pts[3], maxdist )
718  || TestSegmentHit( aPosition, pts[3], pts[0], maxdist ) )
719  {
720  return true;
721  }
722  }
723  }
724  break;
725 
726  case S_POLYGON:
727  if( IsFilled() )
728  {
729  return m_poly.Collide( VECTOR2I( aPosition ), maxdist );
730  }
731  else
732  {
734  return m_poly.CollideEdge( VECTOR2I( aPosition ), dummy, maxdist );
735  }
736 
737  break;
738 
739  default:
740  wxFAIL_MSG( "PCB_SHAPE::HitTest (point) not implemented for "
742  break;
743  }
744 
745  return false;
746 }
747 
748 
749 bool PCB_SHAPE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
750 {
751  EDA_RECT arect = aRect;
752  arect.Normalize();
753  arect.Inflate( aAccuracy );
754 
755  EDA_RECT arcRect;
756  EDA_RECT bb = GetBoundingBox();
757 
758  switch( m_shape )
759  {
760  case S_CIRCLE:
761  // Test if area intersects or contains the circle:
762  if( aContained )
763  return arect.Contains( bb );
764  else
765  {
766  // If the rectangle does not intersect the bounding box, this is a much quicker test
767  if( !aRect.Intersects( bb ) )
768  {
769  return false;
770  }
771  else
772  {
773  return arect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() );
774  }
775  }
776  break;
777 
778  case S_ARC:
779  // Test for full containment of this arc in the rect
780  if( aContained )
781  {
782  return arect.Contains( bb );
783  }
784  // Test if the rect crosses the arc
785  else
786  {
787  arcRect = bb.Common( arect );
788 
789  /* All following tests must pass:
790  * 1. Rectangle must intersect arc BoundingBox
791  * 2. Rectangle must cross the outside of the arc
792  */
793  return arcRect.Intersects( arect ) &&
795  }
796  break;
797 
798  case S_RECT:
799  if( aContained )
800  {
801  return arect.Contains( bb );
802  }
803  else
804  {
805  std::vector<wxPoint> pts = GetRectCorners();
806 
807  // Account for the width of the lines
808  arect.Inflate( GetWidth() / 2 );
809  return ( arect.Intersects( pts[0], pts[1] )
810  || arect.Intersects( pts[1], pts[2] )
811  || arect.Intersects( pts[2], pts[3] )
812  || arect.Intersects( pts[3], pts[0] ) );
813  }
814 
815  break;
816 
817  case S_SEGMENT:
818  if( aContained )
819  {
820  return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
821  }
822  else
823  {
824  // Account for the width of the line
825  arect.Inflate( GetWidth() / 2 );
826  return arect.Intersects( GetStart(), GetEnd() );
827  }
828 
829  break;
830 
831  case S_POLYGON:
832  if( aContained )
833  {
834  return arect.Contains( bb );
835  }
836  else
837  {
838  // Fast test: if aRect is outside the polygon bounding box,
839  // rectangles cannot intersect
840  if( !arect.Intersects( bb ) )
841  return false;
842 
843  // Account for the width of the line
844  arect.Inflate( GetWidth() / 2 );
845  int count = m_poly.TotalVertices();
846 
847  for( int ii = 0; ii < count; ii++ )
848  {
849  auto vertex = m_poly.CVertex( ii );
850  auto vertexNext = m_poly.CVertex(( ii + 1 ) % count );
851 
852  // Test if the point is within aRect
853  if( arect.Contains( ( wxPoint ) vertex ) )
854  return true;
855 
856  // Test if this edge intersects aRect
857  if( arect.Intersects( ( wxPoint ) vertex, ( wxPoint ) vertexNext ) )
858  return true;
859  }
860  }
861  break;
862 
863  case S_CURVE:
864  if( aContained )
865  {
866  return arect.Contains( bb );
867  }
868  else
869  {
870  // Fast test: if aRect is outside the polygon bounding box,
871  // rectangles cannot intersect
872  if( !arect.Intersects( bb ) )
873  return false;
874 
875  // Account for the width of the line
876  arect.Inflate( GetWidth() / 2 );
877  unsigned count = m_bezierPoints.size();
878 
879  for( unsigned ii = 1; ii < count; ii++ )
880  {
881  wxPoint vertex = m_bezierPoints[ ii - 1];
882  wxPoint vertexNext = m_bezierPoints[ii];
883 
884  // Test if the point is within aRect
885  if( arect.Contains( ( wxPoint ) vertex ) )
886  return true;
887 
888  // Test if this edge intersects aRect
889  if( arect.Intersects( vertex, vertexNext ) )
890  return true;
891  }
892  }
893  break;
894 
895 
896  default:
897  wxFAIL_MSG( "PCB_SHAPE::HitTest (rect) not implemented for "
899  break;
900  }
901 
902  return false;
903 }
904 
905 
906 wxString PCB_SHAPE::GetSelectMenuText( EDA_UNITS aUnits ) const
907 {
908  return wxString::Format( _( "%s on %s" ),
909  ShowShape( m_shape ),
910  GetLayerName() );
911 }
912 
913 
915 {
916  return add_dashed_line_xpm;
917 }
918 
919 
921 {
922  return new PCB_SHAPE( *this );
923 }
924 
925 
927 {
928  // For arcs - do not include the center point in the bounding box,
929  // it is redundant for displaying an arc
930  if( m_shape == S_ARC )
931  {
932  EDA_RECT bbox;
933  bbox.SetOrigin( m_end );
934  computeArcBBox( bbox );
935  return BOX2I( bbox.GetOrigin(), bbox.GetSize() );
936  }
937 
938  return EDA_ITEM::ViewBBox();
939 }
940 
941 
942 std::vector<wxPoint> PCB_SHAPE::GetRectCorners() const
943 {
944  std::vector<wxPoint> pts;
945  FOOTPRINT* parentFootprint = GetParentFootprint();
946  wxPoint topLeft = GetStart();
947  wxPoint botRight = GetEnd();
948 
949  // Un-rotate rect topLeft and botRight
950  if( parentFootprint && KiROUND( parentFootprint->GetOrientation() ) % 900 != 0 )
951  {
952  topLeft -= parentFootprint->GetPosition();
953  RotatePoint( &topLeft, -parentFootprint->GetOrientation() );
954 
955  botRight -= parentFootprint->GetPosition();
956  RotatePoint( &botRight, -parentFootprint->GetOrientation() );
957  }
958 
959  // Set up the un-rotated 4 corners
960  pts.emplace_back( topLeft );
961  pts.emplace_back( botRight.x, topLeft.y );
962  pts.emplace_back( botRight );
963  pts.emplace_back( topLeft.x, botRight.y );
964 
965  // Now re-rotate the 4 corners to get a diamond
966  if( parentFootprint && KiROUND( parentFootprint->GetOrientation() ) % 900 != 0 )
967  {
968  for( wxPoint& pt : pts )
969  {
970  RotatePoint( &pt, parentFootprint->GetOrientation() );
971  pt += parentFootprint->GetPosition();
972  }
973  }
974 
975  return pts;
976 }
977 
978 
980 {
981  // Do not include the center, which is not necessarily
982  // inside the BB of a arc with a small angle
983  aBBox.SetOrigin( m_end );
984 
985  wxPoint end = m_end;
986  RotatePoint( &end, m_start, -m_angle );
987  aBBox.Merge( end );
988 
989  // Determine the starting quarter
990  // 0 right-bottom
991  // 1 left-bottom
992  // 2 left-top
993  // 3 right-top
994  unsigned int quarter = 0; // assume right-bottom
995 
996  if( m_end.x < m_start.x )
997  {
998  if( m_end.y <= m_start.y )
999  quarter = 2;
1000  else // ( m_End.y > m_Start.y )
1001  quarter = 1;
1002  }
1003  else if( m_end.x >= m_start.x )
1004  {
1005  if( m_end.y < m_start.y )
1006  quarter = 3;
1007  else if( m_end.x == m_start.x )
1008  quarter = 1;
1009  }
1010 
1011  int radius = GetRadius();
1012  int angle = (int) GetArcAngleStart() % 900 + m_angle;
1013  bool directionCW = ( m_angle > 0 ); // Is the direction of arc clockwise?
1014 
1015  // Make the angle positive, so we go clockwise and merge points belonging to the arc
1016  if( !directionCW )
1017  {
1018  angle = 900 - angle;
1019  quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic
1020  }
1021 
1022  while( angle > 900 )
1023  {
1024  switch( quarter )
1025  {
1026  case 0: aBBox.Merge( wxPoint( m_start.x, m_start.y + radius ) ); break; // down
1027  case 1: aBBox.Merge( wxPoint( m_start.x - radius, m_start.y ) ); break; // left
1028  case 2: aBBox.Merge( wxPoint( m_start.x, m_start.y - radius ) ); break; // up
1029  case 3: aBBox.Merge( wxPoint( m_start.x + radius, m_start.y ) ); break; // right
1030  }
1031 
1032  if( directionCW )
1033  ++quarter;
1034  else
1035  quarter += 3; // -1 modulo arithmetic
1036 
1037  quarter %= 4;
1038  angle -= 900;
1039  }
1040 }
1041 
1042 
1043 void PCB_SHAPE::SetPolyPoints( const std::vector<wxPoint>& aPoints )
1044 {
1046  m_poly.NewOutline();
1047 
1048  for ( const wxPoint& p : aPoints )
1049  m_poly.Append( p.x, p.y );
1050 }
1051 
1052 
1053 std::vector<SHAPE*> PCB_SHAPE::MakeEffectiveShapes() const
1054 {
1055  std::vector<SHAPE*> effectiveShapes;
1056 
1057  switch( m_shape )
1058  {
1059  case S_ARC:
1060  {
1061  SHAPE_ARC arc( GetCenter(), GetArcStart(), (double) GetAngle() / 10.0 );
1063 
1064  for( int i = 0; i < l.SegmentCount(); i++ )
1065  {
1066  effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A,
1067  l.Segment( i ).B, m_width ) );
1068  }
1069 
1070  break;
1071  }
1072 
1073  case S_SEGMENT:
1074  effectiveShapes.emplace_back( new SHAPE_SEGMENT( GetStart(), GetEnd(), m_width ) );
1075  break;
1076 
1077  case S_RECT:
1078  {
1079  std::vector<wxPoint> pts = GetRectCorners();
1080 
1081  if( IsFilled() )
1082  {
1083  effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
1084  }
1085 
1086  if( m_width > 0 || !IsFilled() )
1087  {
1088  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], m_width ) );
1089  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], m_width ) );
1090  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], m_width ) );
1091  effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], m_width ) );
1092  }
1093  }
1094  break;
1095 
1096  case S_CIRCLE:
1097  {
1098  if( IsFilled() )
1099  {
1100  effectiveShapes.emplace_back( new SHAPE_CIRCLE( GetCenter(), GetRadius() ) );
1101  }
1102 
1103  if( m_width > 0 || !IsFilled() )
1104  {
1105  // SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
1106  SHAPE_ARC circle( GetCenter(), GetEnd(), 360.0 );
1107  SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
1108 
1109  for( int i = 0; i < l.SegmentCount(); i++ )
1110  {
1111  effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A,
1112  l.Segment( i ).B, m_width ) );
1113  }
1114  }
1115 
1116  break;
1117  }
1118 
1119  case S_CURVE:
1120  {
1121  auto bezierPoints = buildBezierToSegmentsPointsList( GetWidth() );
1122  wxPoint start_pt = bezierPoints[0];
1123 
1124  for( unsigned int jj = 1; jj < bezierPoints.size(); jj++ )
1125  {
1126  wxPoint end_pt = bezierPoints[jj];
1127  effectiveShapes.emplace_back( new SHAPE_SEGMENT( start_pt, end_pt, m_width ) );
1128  start_pt = end_pt;
1129  }
1130 
1131  break;
1132  }
1133 
1134  case S_POLYGON:
1135  {
1137  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_parent );
1138 
1139  if( parentFootprint )
1140  {
1141  l.Rotate( -parentFootprint->GetOrientationRadians() );
1142  l.Move( parentFootprint->GetPosition() );
1143  }
1144 
1145  if( IsFilled() )
1146  {
1147  effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) );
1148  }
1149 
1150  if( m_width > 0 || !IsFilled() )
1151  {
1152  for( int i = 0; i < l.SegmentCount(); i++ )
1153  effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ), m_width ) );
1154  }
1155  }
1156  break;
1157 
1158  default:
1159  wxFAIL_MSG( "PCB_SHAPE::MakeEffectiveShapes unsupported PCB_SHAPE shape: "
1161  break;
1162  }
1163 
1164  return effectiveShapes;
1165 }
1166 
1167 
1168 std::shared_ptr<SHAPE> PCB_SHAPE::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
1169 {
1170  return std::make_shared<SHAPE_COMPOUND>( MakeEffectiveShapes() );
1171 }
1172 
1173 
1174 const std::vector<wxPoint> PCB_SHAPE::BuildPolyPointsList() const
1175 {
1176  std::vector<wxPoint> rv;
1177 
1178  if( m_poly.OutlineCount() )
1179  {
1180  if( m_poly.COutline( 0 ).PointCount() )
1181  {
1182  for ( auto iter = m_poly.CIterate(); iter; iter++ )
1183  rv.emplace_back( iter->x, iter->y );
1184  }
1185  }
1186 
1187  return rv;
1188 }
1189 
1190 
1192 {
1193  // return true if the polygonal shape is valid (has more than 2 points)
1194  if( GetPolyShape().OutlineCount() == 0 )
1195  return false;
1196 
1197  const SHAPE_LINE_CHAIN& outline = ( (SHAPE_POLY_SET&)GetPolyShape() ).Outline( 0 );
1198 
1199  return outline.PointCount() > 2;
1200 }
1201 
1202 
1204 {
1205  // return the number of corners of the polygonal shape
1206  // this shape is expected to be only one polygon without hole
1207  if( GetPolyShape().OutlineCount() )
1208  return GetPolyShape().VertexCount( 0 );
1209 
1210  return 0;
1211 }
1212 
1213 
1215 {
1216  PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
1217  assert( image );
1218 
1219  std::swap( m_width, image->m_width );
1220  std::swap( m_start, image->m_start );
1221  std::swap( m_end, image->m_end );
1222  std::swap( m_thirdPoint, image->m_thirdPoint );
1223  std::swap( m_shape, image->m_shape );
1224  std::swap( m_angle, image->m_angle );
1225  std::swap( m_bezierC1, image->m_bezierC1 );
1226  std::swap( m_bezierC2, image->m_bezierC2 );
1227  std::swap( m_bezierPoints, image->m_bezierPoints );
1228  std::swap( m_poly, image->m_poly );
1229  std::swap( m_layer, image->m_layer );
1230  std::swap( m_flags, image->m_flags );
1231  std::swap( m_status, image->m_status );
1232  std::swap( m_parent, image->m_parent );
1233  std::swap( m_forceVisible, image->m_forceVisible );
1234 }
1235 
1236 
1237 bool PCB_SHAPE::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const
1238 {
1239  if( aFirst->Type() != aSecond->Type() )
1240  return aFirst->Type() < aSecond->Type();
1241 
1242  if( aFirst->GetLayer() != aSecond->GetLayer() )
1243  return aFirst->GetLayer() < aSecond->GetLayer();
1244 
1245  if( aFirst->Type() == PCB_SHAPE_T )
1246  {
1247  const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( aFirst );
1248  const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( aSecond );
1249 
1250  if( dwgA->GetShape() != dwgB->GetShape() )
1251  return dwgA->GetShape() < dwgB->GetShape();
1252  }
1253 
1254  return aFirst->m_Uuid < aSecond->m_Uuid;
1255 }
1256 
1257 
1258 static struct DRAWSEGMENT_DESC
1259 {
1261  {
1265 
1266  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "Thickness" ),
1268  // TODO show certain properties depending on the shape
1269  //propMgr.AddProperty( new PROPERTY<PCB_SHAPE, double>( _HKI( "Angle" ),
1270  // &PCB_SHAPE::SetAngle, &PCB_SHAPE::GetAngle, PROPERTY_DISPLAY::DECIDEGREE ) );
1271  // TODO or may have different names (arcs)
1272  // TODO type?
1273  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "End X" ),
1275  propMgr.AddProperty( new PROPERTY<PCB_SHAPE, int>( _HKI( "End Y" ),
1277  }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
int Length() const
Function Length()
Definition: seg.h:319
int TotalVertices() const
Returns total number of vertices stored in the set.
wxPoint GetArcEnd() const
Definition: pcb_shape.cpp:375
bool IsPolyShapeValid() const
Definition: pcb_shape.cpp:1191
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:162
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Definition: base_units.cpp:123
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:64
#define TYPE_HASH(x)
Macro to generate unique identifier for a type
Definition: property.h:55
wxPoint m_end
Definition: pcb_shape.h:49
double GetOrientationRadians() const
Definition: footprint.h:206
int OutlineCount() const
Returns the number of outlines in the set
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:209
void Merge(const EDA_RECT &aRect)
Function Merge modifies 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:229
SHAPE_POLY_SET & GetPolyShape()
Definition: pcb_shape.h:259
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Definition: pcb_shape.h:155
int GetEndY()
Definition: pcb_shape.h:156
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
Definition: pcb_shape.cpp:1214
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Definition: board_item.h:206
Implementation of conversion functions that require both schematic and board internal units.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
Definition: board_item.h:86
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)
Converts Bezier curve to a polygon.
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: pcb_shape.cpp:920
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Returns the index-th vertex in a given hole outline within a given outline
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Definition: pcb_shape.h:200
void Move(const VECTOR2I &aVector) override
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:521
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
std::vector< wxPoint > GetRectCorners() const
Definition: pcb_shape.cpp:942
int GetWidth() const
Definition: pcb_shape.h:118
double RAD2DEG(double rad)
Definition: trigo.h:218
double GetArcAngleStart() const
function GetArcAngleStart()
Definition: pcb_shape.cpp:415
int VertexCount(int aOutline=-1, int aHole=-1) const
Returns the number of vertices in a given outline/hole
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
Definition: pcb_shape.cpp:1237
void computeArcBBox(EDA_RECT &aBBox) const
Definition: pcb_shape.cpp:979
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:56
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
Definition: pcb_shape.cpp:926
double GetOrientation() const
Definition: footprint.h:204
#define DEFAULT_LINE_WIDTH
Struct VERTEX_INDEX.
static wxString ShowShape(PCB_SHAPE_TYPE_T aShape)
Function ShowShape converts 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:131
usual segment : line with rounded ends
Definition: board_item.h:52
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
IntersectsCircleEdge Tests 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
Function Common returns the area that is common with another rectangle.
Definition: eda_rect.cpp:487
Arcs (with rounded ends)
Definition: board_item.h:54
#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
Function Rotate rotates all vertices by a given angle.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:274
segment with non rounded ends
Definition: board_item.h:53
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Function GetEffectiveShape Some pad shapes can be complex (rounded/chamfered rectangle),...
Definition: pcb_shape.cpp:1168
The base class for create windows for drawing purpose.
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
Definition: pcb_shape.cpp:197
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
int PointCount() const
Function PointCount()
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names
Definition: property_mgr.h:247
bool Contains(const wxPoint &aPoint) const
Function Contains.
Definition: eda_rect.cpp:57
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirrors the line points about y or x (or both)
STATUS_FLAGS m_status
Definition: eda_item.h:161
wxPoint GetArcStart() const
Definition: pcb_shape.h:178
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
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: pcb_shape.cpp:617
virtual void Move(const wxPoint &aMoveVector) override
Function Move 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:1174
PCB_LAYER_ID
A quick note on layer IDs:
Display value expressed in distance units (mm/inch)
Definition: property.h:49
void SetEndY(int y)
Definition: pcb_shape.h:159
#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:370
void Move(const VECTOR2I &aVector) override
const std::vector< VECTOR2I > & CPoints() const
SHAPE_POLY_SET m_poly
Definition: pcb_shape.h:58
SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
void SetEnd(int x, int y)
Definition: eda_rect.h:192
static wxString PCB_SHAPE_TYPE_T_asString(PCB_SHAPE_TYPE_T a)
Definition: board_item.h:61
wxPoint GetCenter() const override
Function GetCenter()
Definition: pcb_shape.cpp:343
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Definition: pcb_shape.h:144
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declares an inheritance relationship between types.
int GetEndX()
Definition: pcb_shape.h:157
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:429
int NewOutline()
Creates a new empty polygon in the set and returns its index
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
int SegmentCount() const
Function SegmentCount()
void SetEndX(int x)
Definition: pcb_shape.h:160
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
Definition: pcb_shape.cpp:906
class FOOTPRINT, a footprint
Definition: typeinfo.h:89
const KIID m_Uuid
Definition: eda_item.h:151
Some functions to handle hotkeys in KiCad.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs 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()
Function 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
Function Collide()
wxPoint GetPosition() const override
Definition: pcb_shape.cpp:67
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX &aClosestVertex, int aClearance=0) const
Function CollideEdge Checks whether aPoint collides with any edge of any of the contours of the polyg...
std::vector< SHAPE * > MakeEffectiveShapes() const
Makes a set of SHAPE objects representing the PCB_SHAPE.
Definition: pcb_shape.cpp:1053
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
SEG Segment(int aIndex)
Function Segment()
virtual BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
Definition: pcb_shape.cpp:914
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:457
A class to perform either relative or absolute display origin transforms for a single axis of a point...
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
#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)
Registers a property.
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: pcb_shape.cpp:544
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
VECTOR2I A
Definition: seg.h:47
double GetAngle() const
Definition: pcb_shape.h:126
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
double DECIDEG2RAD(double deg)
Definition: trigo.h:221
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
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
int GetPointCount() const
Definition: pcb_shape.cpp:1203
wxPoint GetPosition() const override
Definition: footprint.h:200
wxPoint Centre() const
Definition: eda_rect.h:62
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:317
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
Definition: eda_rect.cpp:150
PCB_LAYER_ID m_layer
Definition: board_item.h:89
ring
Definition: board_item.h:55
wxPoint m_bezierC1
Definition: pcb_shape.h:54
Provides class metadata.
Definition: property_mgr.h:61
virtual void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
Definition: pcb_shape.cpp:252
wxPoint GetArcMid() const
Definition: pcb_shape.cpp:393
PCB_SHAPE_TYPE_T GetShape() const
Definition: pcb_shape.h:129
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:162
bool m_filled
Definition: pcb_shape.h:47
std::vector< wxPoint > m_bezierPoints
Definition: pcb_shape.h:57
STATUS_FLAGS m_flags
Definition: eda_item.h:164
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
Definition: eda_item.cpp:206
bool m_forceVisible
Definition: eda_item.h:163
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:444
wxPoint m_bezierC2
Definition: pcb_shape.h:55
wxString GetLayerName() const
Function GetLayerName returns 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:91
Bezier Curve.
Definition: board_item.h:57
static constexpr int Millimeter2iu(double mm)
#define _HKI(x)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
Definition: pcb_shape.cpp:466
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Definition: board_item.h:185
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:1043
const std::vector< wxPoint > buildBezierToSegmentsPointsList(int aMinSegLen) const
Definition: pcb_shape.cpp:330
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:363
const wxSize GetSize() const
Definition: eda_rect.h:103
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
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:48