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) 2017 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-2017 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 
32 #include <fctsys.h>
33 #include <macros.h>
34 #include <gr_basic.h>
35 #include <bezier_curves.h>
36 #include <class_drawpanel.h>
37 #include <pcb_screen.h>
38 #include <trigo.h>
39 #include <msgpanel.h>
40 #include <bitmaps.h>
41 
42 #include <pcb_edit_frame.h>
43 
44 #include <pcbnew.h>
45 
46 #include <class_board.h>
47 #include <class_module.h>
48 #include <class_drawsegment.h>
49 #include <base_units.h>
50 
51 
53  BOARD_ITEM( aParent, idtype )
54 {
55  m_Type = 0;
56  m_Angle = 0;
57  m_Flags = 0;
59  // Gives a decent pen size to draw shape:
60  m_Width = m_Shape == S_POLYGON ? 0 : Millimeter2iu( 0.15 );
61 }
62 
63 
65 {
66 }
67 
68 void DRAWSEGMENT::SetPosition( const wxPoint& aPos )
69 {
70  m_Start = aPos;
71 }
72 
74 {
75  if( m_Shape == S_POLYGON )
76  return (wxPoint) m_Poly.CVertex( 0 );
77  else
78  return m_Start;
79 }
80 
81 void DRAWSEGMENT::Move( const wxPoint& aMoveVector )
82 {
83  m_Start += aMoveVector;
84  m_End += aMoveVector;
85 
86  switch ( m_Shape )
87  {
88  case S_POLYGON:
89  for( auto iter = m_Poly.Iterate(); iter; iter++ )
90  {
91  (*iter) += VECTOR2I( aMoveVector );
92  }
93  break;
94  default:
95  break;
96  }
97 }
98 
99 
100 void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
101 {
102  switch( m_Shape )
103  {
104  case S_ARC:
105  case S_SEGMENT:
106  case S_CIRCLE:
107  // these can all be done by just rotating the start and end points
108  RotatePoint( &m_Start, aRotCentre, aAngle);
109  RotatePoint( &m_End, aRotCentre, aAngle);
110  break;
111 
112  case S_POLYGON:
113  for( auto iter = m_Poly.Iterate(); iter; iter++ )
114  {
115  RotatePoint( *iter, VECTOR2I(aRotCentre), aAngle);
116  }
117  break;
118 
119  case S_CURVE:
120  RotatePoint( &m_Start, aRotCentre, aAngle);
121  RotatePoint( &m_End, aRotCentre, aAngle);
122 
123  for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
124  {
125  RotatePoint( &m_BezierPoints[ii], aRotCentre, aAngle);
126  }
127  break;
128 
129  case S_RECT:
130  default:
131  // un-handled edge transform
132  wxASSERT_MSG( false, wxT( "DRAWSEGMENT::Rotate not implemented for "
133  + ShowShape( m_Shape ) ) );
134  break;
135  }
136 }
137 
138 void DRAWSEGMENT::Flip( const wxPoint& aCentre )
139 {
140  m_Start.y = aCentre.y - (m_Start.y - aCentre.y);
141  m_End.y = aCentre.y - (m_End.y - aCentre.y);
142 
143  switch ( m_Shape )
144  {
145  case S_ARC:
146  m_Angle = -m_Angle;
147  break;
148  case S_POLYGON:
149  for( auto iter = m_Poly.Iterate(); iter; iter++ )
150  {
151  iter->y = aCentre.y - (iter->y - aCentre.y);
152  }
153  break;
154  default:
155  break;
156  }
157 
158  // DRAWSEGMENT items are not allowed on copper layers, so
159  // copper layers count is not taken in accoun in Flip transform
160  SetLayer( FlipLayer( GetLayer() ) );
161 }
162 
164 {
165  wxPoint c;
166 
167  switch( m_Shape )
168  {
169  case S_ARC:
170  case S_CIRCLE:
171  c = m_Start;
172  break;
173 
174  case S_SEGMENT:
175  // Midpoint of the line
176  c = ( GetStart() + GetEnd() ) / 2;
177  break;
178 
179  case S_POLYGON:
180  case S_RECT:
181  case S_CURVE:
182  c = GetBoundingBox().Centre();
183  break;
184 
185  default:
186  wxASSERT_MSG( false, "DRAWSEGMENT::GetCentre not implemented for shape"
187  + ShowShape( GetShape() ) );
188  break;
189  }
190 
191  return c;
192 }
193 
195 {
196  wxPoint endPoint; // start of arc
197 
198  switch( m_Shape )
199  {
200  case S_ARC:
201  // rotate the starting point of the arc, given by m_End, through the
202  // angle m_Angle to get the ending point of the arc.
203  // m_Start is the arc centre
204  endPoint = m_End; // m_End = start point of arc
205  RotatePoint( &endPoint, m_Start, -m_Angle );
206  break;
207 
208  default:
209  break;
210  }
211 
212  return endPoint; // after rotation, the end of the arc.
213 }
214 
216 {
217  // due to the Y axis orient atan2 needs - y value
218  double angleStart = ArcTangente( GetArcStart().y - GetCenter().y,
219  GetArcStart().x - GetCenter().x );
220 
221  // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
222  // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
223  // and this is not easy to handle in calculations
224  NORMALIZE_ANGLE_POS( angleStart );
225 
226  return angleStart;
227 }
228 
229 
230 void DRAWSEGMENT::SetAngle( double aAngle )
231 {
232  // m_Angle must be >= -360 and <= +360 degrees
233  m_Angle = NormalizeAngle360Max( aAngle );
234 }
235 
236 
238 {
239  if( !m_Parent || m_Parent->Type() != PCB_MODULE_T )
240  return NULL;
241 
242  return (MODULE*) m_Parent;
243 }
244 
245 
246 void DRAWSEGMENT::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
247  const wxPoint& aOffset )
248 {
249  int ux0, uy0, dx, dy;
250  int l_trace;
251  int radius;
252 
253  PCB_LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
254 
255  BOARD * brd = GetBoard( );
256 
257  if( brd->IsLayerVisible( GetLayer() ) == false )
258  return;
259 
260  auto frame = static_cast<PCB_EDIT_FRAME*> ( panel->GetParent() );
261  auto color = frame->Settings().Colors().GetLayerColor( GetLayer() );
262 
263  auto displ_opts = (PCB_DISPLAY_OPTIONS*) panel->GetDisplayOptions();
264 
265  if( ( draw_mode & GR_ALLOW_HIGHCONTRAST ) && displ_opts && displ_opts->m_ContrastModeDisplay )
266  {
267  if( !IsOnLayer( curr_layer ) && !IsOnLayer( Edge_Cuts ) )
269  }
270 
271  GRSetDrawMode( DC, draw_mode );
272  l_trace = m_Width >> 1; // half trace width
273 
274  // Line start point or Circle and Arc center
275  ux0 = m_Start.x + aOffset.x;
276  uy0 = m_Start.y + aOffset.y;
277 
278  // Line end point or circle and arc start point
279  dx = m_End.x + aOffset.x;
280  dy = m_End.y + aOffset.y;
281 
282  bool filled = displ_opts ? displ_opts->m_DisplayDrawItemsFill : FILLED;
283 
284  if( m_Flags & FORCE_SKETCH )
285  filled = SKETCH;
286 
287  switch( m_Shape )
288  {
289  case S_CIRCLE:
290  radius = KiROUND( Distance( ux0, uy0, dx, dy ) );
291 
292  if( filled )
293  {
294  GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
295  }
296  else
297  {
298  GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - l_trace, color );
299  GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + l_trace, color );
300  }
301 
302  break;
303 
304  case S_ARC:
305  double StAngle, EndAngle;
306  radius = KiROUND( Distance( ux0, uy0, dx, dy ) );
307  StAngle = ArcTangente( dy - uy0, dx - ux0 );
308  EndAngle = StAngle + m_Angle;
309 
310  if( !panel->GetPrintMirrored() )
311  {
312  if( StAngle > EndAngle )
313  std::swap( StAngle, EndAngle );
314  }
315  else // Mirrored mode: arc orientation is reversed
316  {
317 #ifdef __WXMAC__ // wxWidgets OSX print driver handles arc mirroring for us
318  if( StAngle > EndAngle )
319  std::swap( StAngle, EndAngle );
320 #else
321  if( StAngle < EndAngle )
322  std::swap( StAngle, EndAngle );
323 #endif
324  }
325 
326  if( filled )
327  {
328  GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
329  radius, m_Width, color );
330  }
331  else
332  {
333  GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
334  radius - l_trace, color );
335  GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
336  radius + l_trace, color );
337  }
338 
339  break;
340 
341  case S_CURVE:
342  {
343  std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
344  BEZIER_POLY converter( ctrlPoints );
345  converter.GetPoly( m_BezierPoints );
346  }
347 
348  for( unsigned int i=1; i < m_BezierPoints.size(); i++ )
349  {
350  if( filled )
351  {
352  GRFillCSegm( panel->GetClipBox(), DC,
353  m_BezierPoints[i].x, m_BezierPoints[i].y,
354  m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
355  m_Width, color );
356  }
357  else
358  {
359  GRCSegm( panel->GetClipBox(), DC,
360  m_BezierPoints[i].x, m_BezierPoints[i].y,
361  m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
362  m_Width, color );
363  }
364  }
365 
366  break;
367 
368  case S_POLYGON:
369  {
370  SHAPE_POLY_SET& outline = GetPolyShape();
371  // Draw the polygon: only one polygon is expected
372  // However we provide a multi polygon shape drawing
373  // ( for the future or to show a non expected shape )
374  for( int jj = 0; jj < outline.OutlineCount(); ++jj )
375  {
376  SHAPE_LINE_CHAIN& poly = outline.Outline( jj );
377 
378  GRClosedPoly( panel->GetClipBox(), DC, poly.PointCount(),
379  (wxPoint*)&poly.Point( 0 ), FILLED, GetWidth(),
380  color, color );
381  }
382  }
383  break;
384 
385  default:
386  if( filled )
387  {
388  GRFillCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
389  }
390  else
391  {
392  GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
393  }
394 
395  break;
396  }
397 }
398 
399 void DRAWSEGMENT::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
400 {
401  wxString msg;
402  wxASSERT( m_Parent );
403 
404  msg = _( "Drawing" );
405 
406  aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
407 
408  wxString shape = _( "Shape" );
409 
410  switch( m_Shape )
411  {
412  case S_CIRCLE:
413  aList.push_back( MSG_PANEL_ITEM( shape, _( "Circle" ), RED ) );
414  break;
415 
416  case S_ARC:
417  aList.push_back( MSG_PANEL_ITEM( shape, _( "Arc" ), RED ) );
418  msg.Printf( wxT( "%.1f" ), m_Angle / 10.0 );
419  aList.push_back( MSG_PANEL_ITEM( _( "Angle" ), msg, RED ) );
420  break;
421 
422  case S_CURVE:
423  aList.push_back( MSG_PANEL_ITEM( shape, _( "Curve" ), RED ) );
424  break;
425 
426  default:
427  {
428  aList.push_back( MSG_PANEL_ITEM( shape, _( "Segment" ), RED ) );
429 
431  aList.push_back( MSG_PANEL_ITEM( _( "Length" ), msg, DARKGREEN ) );
432 
433  // angle counter-clockwise from 3'o-clock
434  const double deg = RAD2DEG( atan2( (double)( m_Start.y - m_End.y ),
435  (double)( m_End.x - m_Start.x ) ) );
436  msg.Printf( wxT( "%.1f" ), deg );
437  aList.push_back( MSG_PANEL_ITEM( _( "Angle" ), msg, DARKGREEN ) );
438  }
439  }
440 
441  wxString start;
442  start << GetStart();
443 
444  wxString end;
445  end << GetEnd();
446 
447  aList.push_back( MSG_PANEL_ITEM( start, end, DARKGREEN ) );
448  aList.push_back( MSG_PANEL_ITEM( _( "Layer" ), GetLayerName(), DARKBROWN ) );
449  msg = ::CoordinateToString( m_Width );
450  aList.push_back( MSG_PANEL_ITEM( _( "Width" ), msg, DARKCYAN ) );
451 }
452 
453 
455 {
456  EDA_RECT bbox;
457 
458  bbox.SetOrigin( m_Start );
459 
460  switch( m_Shape )
461  {
462  case S_SEGMENT:
463  bbox.SetEnd( m_End );
464  break;
465 
466  case S_CIRCLE:
467  bbox.Inflate( GetRadius() );
468  break;
469 
470  case S_ARC:
471  computeArcBBox( bbox );
472  break;
473 
474  case S_POLYGON:
475  if( m_Poly.IsEmpty() )
476  break;
477  {
478  wxPoint p_end;
479  MODULE* module = GetParentModule();
480  bool first = true;
481 
482  for( auto iter = m_Poly.CIterate(); iter; iter++ )
483  {
484  wxPoint pt ( iter->x, iter->y );
485 
486  if( module ) // Transform, if we belong to a module
487  {
488  RotatePoint( &pt, module->GetOrientation() );
489  pt += module->GetPosition();
490  }
491 
492 
493  if( first )
494  {
495  p_end = pt;
496  bbox.SetX( pt.x );
497  bbox.SetY( pt.y );
498  first = false;
499  }
500  else
501  {
502 
503  bbox.SetX( std::min( bbox.GetX(), pt.x ) );
504  bbox.SetY( std::min( bbox.GetY(), pt.y ) );
505 
506  p_end.x = std::max( p_end.x, pt.x );
507  p_end.y = std::max( p_end.y, pt.y );
508  }
509  }
510 
511  bbox.SetEnd( p_end );
512  break;
513  }
514  default:
515  break;
516  }
517 
518  bbox.Inflate( ((m_Width+1) / 2) + 1 );
519  bbox.Normalize();
520 
521  return bbox;
522 }
523 
524 
525 bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
526 {
527  switch( m_Shape )
528  {
529  case S_CIRCLE:
530  case S_ARC:
531  {
532  wxPoint relPos = aPosition - GetCenter();
533  int radius = GetRadius();
534  int dist = KiROUND( EuclideanNorm( relPos ) );
535 
536  if( abs( radius - dist ) <= ( m_Width / 2 ) )
537  {
538  if( m_Shape == S_CIRCLE )
539  return true;
540 
541  // For arcs, the test point angle must be >= arc angle start
542  // and <= arc angle end
543  // However angle values > 360 deg are not easy to handle
544  // so we calculate the relative angle between arc start point and teast point
545  // this relative arc should be < arc angle if arc angle > 0 (CW arc)
546  // and > arc angle if arc angle < 0 (CCW arc)
547  double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
548 
549  double arc_hittest = ArcTangente( relPos.y, relPos.x );
550 
551  // Calculate relative angle between the starting point of the arc, and the test point
552  arc_hittest -= arc_angle_start;
553 
554  // Normalise arc_hittest between 0 ... 360 deg
555  NORMALIZE_ANGLE_POS( arc_hittest );
556 
557  // Check angle: inside the arc angle when it is > 0
558  // and outside the not drawn arc when it is < 0
559  if( GetAngle() >= 0.0 )
560  {
561  if( arc_hittest <= GetAngle() )
562  return true;
563  }
564  else
565  {
566  if( arc_hittest >= (3600.0 + GetAngle()) )
567  return true;
568  }
569  }
570  }
571  break;
572 
573  case S_CURVE:
574  for( unsigned int i= 1; i < m_BezierPoints.size(); i++)
575  {
576  if( TestSegmentHit( aPosition, m_BezierPoints[i-1], m_BezierPoints[i-1], m_Width / 2 ) )
577  return true;
578  }
579  break;
580 
581  case S_SEGMENT:
582  if( TestSegmentHit( aPosition, m_Start, m_End, m_Width / 2 ) )
583  return true;
584  break;
585 
586  case S_POLYGON: // not yet handled
587  {
588  #define MAX_DIST_IN_MM 0.25
589  int distmax = Millimeter2iu( 0.25 );
591  auto poly = m_Poly;
592 
593  if( poly.CollideVertex( VECTOR2I( aPosition ), dummy, distmax ) )
594  return true;
595 
596  if( poly.CollideEdge( VECTOR2I( aPosition ), dummy, distmax ) )
597  return true;
598  }
599  break;
600 
601  default:
602  wxASSERT_MSG( 0, wxString::Format( "unknown DRAWSEGMENT shape: %d", m_Shape ) );
603  break;
604  }
605 
606  return false;
607 }
608 
609 
610 bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
611 {
612  EDA_RECT arect = aRect;
613  arect.Normalize();
614  arect.Inflate( aAccuracy );
615 
616  EDA_RECT arcRect;
617  EDA_RECT bb = GetBoundingBox();
618 
619  switch( m_Shape )
620  {
621  case S_CIRCLE:
622  // Test if area intersects or contains the circle:
623  if( aContained )
624  return arect.Contains( bb );
625  else
626  {
627  // If the rectangle does not intersect the bounding box, this is a much quicker test
628  if( !aRect.Intersects( bb ) )
629  {
630  return false;
631  }
632  else
633  {
634  return arect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() );
635  }
636 
637  }
638  break;
639 
640  case S_ARC:
641  // Test for full containment of this arc in the rect
642  if( aContained )
643  {
644  return arect.Contains( bb );
645  }
646  // Test if the rect crosses the arc
647  else
648  {
649  arcRect = bb.Common( arect );
650 
651  /* All following tests must pass:
652  * 1. Rectangle must intersect arc BoundingBox
653  * 2. Rectangle must cross the outside of the arc
654  */
655  return arcRect.Intersects( arect ) &&
657  }
658  break;
659 
660  case S_SEGMENT:
661  if( aContained )
662  {
663  return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
664  }
665  else
666  {
667  // Account for the width of the line
668  arect.Inflate( GetWidth() / 2 );
669  return arect.Intersects( GetStart(), GetEnd() );
670  }
671 
672  break;
673 
674  case S_POLYGON:
675  if( aContained )
676  {
677  return arect.Contains( bb );
678  }
679  else
680  {
681  // Fast test: if aRect is outside the polygon bounding box,
682  // rectangles cannot intersect
683  if( !arect.Intersects( bb ) )
684  return false;
685 
686  // Account for the width of the line
687  arect.Inflate( GetWidth() / 2 );
688  int count = m_Poly.TotalVertices();
689 
690  for( int ii = 0; ii < count; ii++ )
691  {
692  auto vertex = m_Poly.CVertex( ii );
693  auto vertexNext = m_Poly.CVertex( ( ii + 1 ) % count );
694 
695  // Test if the point is within aRect
696  if( arect.Contains( ( wxPoint ) vertex ) )
697  return true;
698 
699  // Test if this edge intersects aRect
700  if( arect.Intersects( ( wxPoint ) vertex, ( wxPoint ) vertexNext ) )
701  return true;
702  }
703  }
704  break;
705 
706  case S_CURVE: // not yet handled
707  break;
708 
709 
710  default:
711  wxASSERT_MSG( 0, wxString::Format( "unknown DRAWSEGMENT shape: %d", m_Shape ) );
712  break;
713  }
714 
715  return false;
716 }
717 
718 
720 {
721  wxString text;
722  wxString temp = ::LengthDoubleToString( GetLength() );
723 
724  text.Printf( _( "Pcb Graphic: %s, length %s on %s" ),
725  GetChars( ShowShape( m_Shape ) ),
726  GetChars( temp ), GetChars( GetLayerName() ) );
727 
728  return text;
729 }
730 
731 
733 {
734  return add_dashed_line_xpm;
735 }
736 
737 
739 {
740  return new DRAWSEGMENT( *this );
741 }
742 
743 
745 {
746  // For arcs - do not include the center point in the bounding box,
747  // it is redundant for displaying an arc
748  if( m_Shape == S_ARC )
749  {
750  EDA_RECT bbox;
751  bbox.SetOrigin( m_End );
752  computeArcBBox( bbox );
753  return BOX2I( bbox.GetOrigin(), bbox.GetSize() );
754  }
755 
756  return EDA_ITEM::ViewBBox();
757 }
758 
759 
761 {
762  // Do not include the center, which is not necessarily
763  // inside the BB of a arc with a small angle
764  aBBox.SetOrigin( m_End );
765 
766  wxPoint end = m_End;
767  RotatePoint( &end, m_Start, -m_Angle );
768  aBBox.Merge( end );
769 
770  // Determine the starting quarter
771  // 0 right-bottom
772  // 1 left-bottom
773  // 2 left-top
774  // 3 right-top
775  unsigned int quarter = 0; // assume right-bottom
776 
777  if( m_End.x < m_Start.x )
778  {
779  if( m_End.y <= m_Start.y )
780  quarter = 2;
781  else // ( m_End.y > m_Start.y )
782  quarter = 1;
783  }
784  else if( m_End.x >= m_Start.x )
785  {
786  if( m_End.y < m_Start.y )
787  quarter = 3;
788  else if( m_End.x == m_Start.x )
789  quarter = 1;
790  }
791 
792  int radius = GetRadius();
793  int angle = (int) GetArcAngleStart() % 900 + m_Angle;
794  bool directionCW = ( m_Angle > 0 ); // Is the direction of arc clockwise?
795 
796  // Make the angle positive, so we go clockwise and merge points belonging to the arc
797  if( !directionCW )
798  {
799  angle = 900 - angle;
800  quarter = ( quarter + 3 ) % 4; // -1 modulo arithmetic
801  }
802 
803  while( angle > 900 )
804  {
805  switch( quarter )
806  {
807  case 0:
808  aBBox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); // down
809  break;
810 
811  case 1:
812  aBBox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); // left
813  break;
814 
815  case 2:
816  aBBox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); // up
817  break;
818 
819  case 3:
820  aBBox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); // right
821  break;
822  }
823 
824  if( directionCW )
825  ++quarter;
826  else
827  quarter += 3; // -1 modulo arithmetic
828 
829  quarter %= 4;
830  angle -= 900;
831  }
832 }
833 
834 void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
835 {
837  m_Poly.NewOutline();
838 
839  for ( auto p : aPoints )
840  {
841  m_Poly.Append( p.x, p.y );
842  }
843 }
844 
845 
846 const std::vector<wxPoint> DRAWSEGMENT::BuildPolyPointsList() const
847 {
848  std::vector<wxPoint> rv;
849 
850  if( m_Poly.OutlineCount() )
851  {
852  if( m_Poly.COutline( 0 ).PointCount() )
853  {
854  for ( auto iter = m_Poly.CIterate(); iter; iter++ )
855  {
856  rv.push_back( wxPoint( iter->x, iter->y ) );
857  }
858  }
859  }
860 
861  return rv;
862 }
863 
864 
866 {
867  // return true if the polygonal shape is valid (has more than 2 points)
868  if( GetPolyShape().OutlineCount() == 0 )
869  return false;
870 
871  const SHAPE_LINE_CHAIN& outline = ((SHAPE_POLY_SET&)GetPolyShape()).Outline( 0 );
872 
873  return outline.PointCount() > 2;
874 }
875 
876 
878 {
879  // return the number of corners of the polygonal shape
880  // this shape is expected to be only one polygon without hole
881  if( GetPolyShape().OutlineCount() )
882  return GetPolyShape().VertexCount( 0 );
883 
884  return 0;
885 }
886 
887 
889 {
890  assert( aImage->Type() == PCB_LINE_T );
891 
892  std::swap( *((DRAWSEGMENT*) this), *((DRAWSEGMENT*) aImage) );
893 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:112
wxString CoordinateToString(int aValue, bool aConvertToMils)
Function CoordinateToString is a helper to convert the integer coordinate aValue to a string in inche...
Definition: base_units.cpp:118
KICAD_T Type() const
Function Type()
Definition: base_struct.h:227
static wxString ShowShape(STROKE_T aShape)
Function ShowShape converts the enum STROKE_T integer value to a wxString.
virtual void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
BOX2< VECTOR2I > BOX2I
Definition: box2.h:468
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers. ...
EDA_ITEM * m_Parent
Linked list: Link (parent struct)
Definition: base_struct.h:197
double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Returns the index-th vertex in a given hole outline within a given outline
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Function GetLineLength returns the length of a line segment defined by aPointA and aPointB...
Definition: trigo.h:191
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect...
virtual void GetMsgPanelInfo(std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it&#39;s internal state for displ...
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...
PNG memory record (file in memory).
Definition: bitmap_types.h:41
virtual void Move(const wxPoint &aMoveVector) override
Function Move move this object.
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:318
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...
T NormalizeAngle360Max(T Angle)
Normalize angle to be >=-360.0 and <= 360.0 Angle can be equal to -360 or +360.
Definition: trigo.h:211
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Function IsOnLayer tests to see if this object is on the given layer.
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...
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
const wxPoint GetCenter() const override
Function GetCenter()
const wxSize GetSize() const
Definition: eda_rect.h:101
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int PointCount() const
Function PointCount()
bool Contains(const wxPoint &aPoint) const
Function Contains.
Class BOARD to handle a board.
SHAPE_POLY_SET m_Poly
Stores the S_POLYGON shape.
int color
Definition: DXF_plotter.cpp:62
polygon (not yet used for tracks, but could be in microwave apps)
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Function FlippedLayerNumber.
Definition: lset.cpp:472
virtual BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
virtual bool HitTest(const wxPoint &aPosition) const override
Function HitTest tests if aPosition is contained within or on the bounding area of an item...
double RAD2DEG(double rad)
Definition: trigo.h:200
void GetPoly(std::vector< wxPoint > &aOutput)
Converts Bezier curve to a polygon.
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
double GetArcAngleStart() const
function GetArcAngleStart()
EDA_RECT Common(const EDA_RECT &aRect) const
Function Common returns the area that is common with another rectangle.
static const int dist[10][10]
Definition: dist.cpp:57
int TotalVertices() const
Returns total number of vertices stored in the set.
Struct VERTEX_INDEX.
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, COLOR4D Color)
Definition: gr_basic.cpp:510
const wxPoint GetPosition() const override
usual segment : line with rounded ends
void SetPosition(const wxPoint &aPos) override
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
double m_Angle
Used only for Arcs: Arc angle in 1/10 deg.
bool IsPolyShapeValid() const
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Function Iterate returns an object to iterate through the points of the polygons between aFirst and a...
int OutlineCount() const
Returns the number of outlines in the set
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:241
VECTOR2< int > VECTOR2I
Definition: vector2d.h:589
#define abs(a)
Definition: auxiliary.h:84
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
wxString GetLayerName() const
Function GetLayerName returns the name of the PCB layer on which the item resides.
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, wxPoint Points[], bool Fill, COLOR4D Color, COLOR4D BgColor)
Function GRClosedPoly draws a closed polygon onto the drawing context aDC and optionally fills and/or...
Definition: gr_basic.cpp:806
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
This file contains miscellaneous commonly used macros and functions.
wxPoint m_BezierC1
Bezier Control Point 1.
const wxPoint & GetArcStart() const
int GetPointCount() const
segment with non rounded ends
class MODULE, a footprint
Definition: typeinfo.h:89
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings...
PCB_LAYER_ID
A quick note on layer IDs:
STROKE_T GetShape() const
wxPoint m_Start
Line start point or Circle and Arc center.
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:271
wxPoint m_End
Line end point or circle and arc start point.
double GetOrientation() const
Definition: class_module.h:186
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
Class SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:613
void SetEnd(int x, int y)
Definition: eda_rect.h:134
Arcs (with rounded ends)
void GRArc(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, double StAngle, double EndAngle, int r, COLOR4D Color)
Definition: gr_basic.cpp:1003
EDA_RECT * GetClipBox()
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
void SetX(int val)
Definition: eda_rect.h:130
wxString LengthDoubleToString(double aValue, bool aConvertToMils)
Function LengthDoubleToString is a helper to convert the double length aValue to a string in inches...
Definition: base_units.cpp:123
STROKE_T m_Shape
Shape: line, Circle, Arc.
Definition: colors.h:60
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:181
SHAPE_POLY_SET & GetPolyShape()
Bezier Curve.
wxPoint Centre() const
Definition: eda_rect.h:60
void computeArcBBox(EDA_RECT &aBBox) const
int NewOutline()
Creates a new empty polygon in the set and returns its index
void SetY(int val)
Definition: eda_rect.h:131
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
void Normalize()
Function Normalize ensures that the height ant width are positive.
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
Bezier curves to polygon converter.
Definition: bezier_curves.h:34
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double GetAngle() const
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:205
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
#define max(a, b)
Definition: auxiliary.h:86
bool GetPrintMirrored() const
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
Class SHAPE_LINE_CHAIN.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
int VertexCount(int aOutline=-1, int aHole=-1) const
Returns the number of vertices in a given outline/hole
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:850
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:204
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
const wxPoint GetArcEnd() const
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
int GetX() const
Definition: eda_rect.h:109
wxPoint m_BezierC2
Bezier Control Point 2.
BASE_SCREEN * GetScreen()
Definition: draw_panel.cpp:194
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:180
int GetWidth() const
int GetY() const
Definition: eda_rect.h:110
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
MODULE * GetParentModule() const
Function GetParentModule returns a pointer to the parent module, or NULL if DRAWSEGMENT does not belo...
VECTOR2I & Point(int aIndex)
Function Point()
int m_Width
thickness of lines ...
Module description (excepted pads)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
void * GetDisplayOptions()
Function GetDisplayOptions A way to pass info to draw functions.
Definition: draw_panel.cpp:188
DRAWSEGMENT(BOARD_ITEM *aParent=NULL, KICAD_T idtype=PCB_LINE_T)
Class EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Function TestSegmentHit test for hit on line segment i.e.
Definition: trigo.cpp:142
double Distance(double x1, double y1, double x2, double y2)
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
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. ...
Message panel definition file.
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
#define FORCE_SKETCH
Definition: pcbnew.h:68
const wxPoint GetPosition() const override
Definition: class_module.h:181
virtual wxString GetSelectMenuText() const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
#define min(a, b)
Definition: auxiliary.h:85
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:451
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
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
virtual const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...