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