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