KiCad PCB EDA Suite
lib_arc.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) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
29 #include <fctsys.h>
30 #include <gr_basic.h>
31 #include <macros.h>
32 #include <class_drawpanel.h>
33 #include <plotter.h>
34 #include <trigo.h>
35 #include <base_units.h>
36 #include <msgpanel.h>
37 #include <bitmaps.h>
38 
39 #include <general.h>
40 #include <lib_arc.h>
41 #include <transform.h>
42 
43 // Helper function
44 static inline wxPoint twoPointVector( const wxPoint &startPoint, const wxPoint &endPoint )
45 {
46  return endPoint - startPoint;
47 }
48 
49 
53 static wxPoint calcCenter( const wxPoint& A, const wxPoint& B, const wxPoint& C )
54 {
55  double circumCenterX, circumCenterY;
56  double Ax = (double) A.x;
57  double Ay = (double) A.y;
58  double Bx = (double) B.x;
59  double By = (double) B.y;
60  double Cx = (double) C.x;
61  double Cy = (double) C.y;
62 
63  wxPoint circumCenter;
64 
65  double D = 2.0 * ( Ax * ( By - Cy ) + Bx * ( Cy - Ay ) + Cx * ( Ay - By ) );
66 
67  // prevent division / 0
68  if( fabs( D ) < 1e-7 )
69  D = 1e-7;
70 
71  circumCenterX = ( (Ay * Ay + Ax * Ax) * (By - Cy) +
72  (By * By + Bx * Bx) * (Cy - Ay) +
73  (Cy * Cy + Cx * Cx) * (Ay - By) ) / D;
74 
75  circumCenterY = ( (Ay * Ay + Ax * Ax) * (Cx - Bx) +
76  (By * By + Bx * Bx) * (Ax - Cx) +
77  (Cy * Cy + Cx * Cx) * (Bx - Ax) ) / D;
78 
79  circumCenter.x = (int) circumCenterX;
80  circumCenter.y = (int) circumCenterY;
81 
82  return circumCenter;
83 }
84 
85 
86 LIB_ARC::LIB_ARC( LIB_PART* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
87 {
88  m_Radius = 0;
89  m_t1 = 0;
90  m_t2 = 0;
91  m_Width = 0;
92  m_Fill = NO_FILL;
93  m_isFillable = true;
94  m_editState = 0;
95  m_lastEditState = 0;
98  m_editDirection = 0;
99 }
100 
101 
102 bool LIB_ARC::HitTest( const wxPoint& aRefPoint ) const
103 {
104  int mindist = GetPenSize() / 2;
105 
106  // Have a minimal tolerance for hit test
107  if( mindist < MINIMUM_SELECTION_DISTANCE )
108  mindist = MINIMUM_SELECTION_DISTANCE;
109 
110  return HitTest( aRefPoint, mindist, DefaultTransform );
111 }
112 
113 
114 bool LIB_ARC::HitTest( const wxPoint &aPosition, int aThreshold, const TRANSFORM& aTransform ) const
115 {
116 
117  if( aThreshold < 0 )
118  aThreshold = GetPenSize() / 2;
119 
120  // TODO: use aTransMat to calculates parameters
121  wxPoint relativePosition = aPosition;
122 
123  relativePosition.y = -relativePosition.y; // reverse Y axis
124 
125  int distance = KiROUND( GetLineLength( m_Pos, relativePosition ) );
126 
127  if( abs( distance - m_Radius ) > aThreshold )
128  return false;
129 
130  // We are on the circle, ensure we are only on the arc, i.e. between
131  // m_ArcStart and m_ArcEnd
132 
133  wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd);
134  wxPoint startRelativePositionVector = twoPointVector( m_ArcStart, relativePosition );
135 
136  wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart );
137  wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd );
138  wxPoint centerRelativePositionVector = twoPointVector( m_Pos, relativePosition );
139 
140  // Compute the cross product to check if the point is in the sector
141  double crossProductStart = CrossProduct( centerStartVector, centerRelativePositionVector );
142  double crossProductEnd = CrossProduct( centerEndVector, centerRelativePositionVector );
143 
144  // The cross products need to be exchanged, depending on which side the center point
145  // relative to the start point to end point vector lies
146  if( CrossProduct( startEndVector, startRelativePositionVector ) < 0 )
147  {
148  std::swap( crossProductStart, crossProductEnd );
149  }
150 
151  // When the cross products have a different sign, the point lies in sector
152  // also check, if the reference is near start or end point
153  return HitTestPoints( m_ArcStart, relativePosition, MINIMUM_SELECTION_DISTANCE ) ||
154  HitTestPoints( m_ArcEnd, relativePosition, MINIMUM_SELECTION_DISTANCE ) ||
155  ( crossProductStart <= 0 && crossProductEnd >= 0 );
156 }
157 
158 
160 {
161  return new LIB_ARC( *this );
162 }
163 
164 
165 int LIB_ARC::compare( const LIB_ITEM& aOther ) const
166 {
167  wxASSERT( aOther.Type() == LIB_ARC_T );
168 
169  const LIB_ARC* tmp = ( LIB_ARC* ) &aOther;
170 
171  if( m_Pos.x != tmp->m_Pos.x )
172  return m_Pos.x - tmp->m_Pos.x;
173 
174  if( m_Pos.y != tmp->m_Pos.y )
175  return m_Pos.y - tmp->m_Pos.y;
176 
177  if( m_t1 != tmp->m_t1 )
178  return m_t1 - tmp->m_t1;
179 
180  if( m_t2 != tmp->m_t2 )
181  return m_t2 - tmp->m_t2;
182 
183  return 0;
184 }
185 
186 
187 void LIB_ARC::SetOffset( const wxPoint& aOffset )
188 {
189  m_Pos += aOffset;
190  m_ArcStart += aOffset;
191  m_ArcEnd += aOffset;
192 }
193 
194 
195 bool LIB_ARC::Inside( EDA_RECT& aRect ) const
196 {
197  return aRect.Contains( m_ArcStart.x, -m_ArcStart.y )
198  || aRect.Contains( m_ArcEnd.x, -m_ArcEnd.y );
199 }
200 
201 
202 void LIB_ARC::Move( const wxPoint& aPosition )
203 {
204  wxPoint offset = aPosition - m_Pos;
205  m_Pos = aPosition;
206  m_ArcStart += offset;
207  m_ArcEnd += offset;
208 }
209 
210 
211 void LIB_ARC::MirrorHorizontal( const wxPoint& aCenter )
212 {
213  m_Pos.x -= aCenter.x;
214  m_Pos.x *= -1;
215  m_Pos.x += aCenter.x;
216  m_ArcStart.x -= aCenter.x;
217  m_ArcStart.x *= -1;
218  m_ArcStart.x += aCenter.x;
219  m_ArcEnd.x -= aCenter.x;
220  m_ArcEnd.x *= -1;
221  m_ArcEnd.x += aCenter.x;
222  std::swap( m_ArcStart, m_ArcEnd );
223  std::swap( m_t1, m_t2 );
224  m_t1 = 1800 - m_t1;
225  m_t2 = 1800 - m_t2;
226  if( m_t1 > 3600 || m_t2 > 3600 )
227  {
228  m_t1 -= 3600;
229  m_t2 -= 3600;
230  }
231  else if( m_t1 < -3600 || m_t2 < -3600 )
232  {
233  m_t1 += 3600;
234  m_t2 += 3600;
235  }
236 }
237 
238 void LIB_ARC::MirrorVertical( const wxPoint& aCenter )
239 {
240  m_Pos.y -= aCenter.y;
241  m_Pos.y *= -1;
242  m_Pos.y += aCenter.y;
243  m_ArcStart.y -= aCenter.y;
244  m_ArcStart.y *= -1;
245  m_ArcStart.y += aCenter.y;
246  m_ArcEnd.y -= aCenter.y;
247  m_ArcEnd.y *= -1;
248  m_ArcEnd.y += aCenter.y;
249  std::swap( m_ArcStart, m_ArcEnd );
250  std::swap( m_t1, m_t2 );
251  m_t1 = - m_t1;
252  m_t2 = - m_t2;
253  if( m_t1 > 3600 || m_t2 > 3600 )
254  {
255  m_t1 -= 3600;
256  m_t2 -= 3600;
257  }
258  else if( m_t1 < -3600 || m_t2 < -3600 )
259  {
260  m_t1 += 3600;
261  m_t2 += 3600;
262  }
263 }
264 
265 void LIB_ARC::Rotate( const wxPoint& aCenter, bool aRotateCCW )
266 {
267  int rot_angle = aRotateCCW ? -900 : 900;
268  RotatePoint( &m_Pos, aCenter, rot_angle );
269  RotatePoint( &m_ArcStart, aCenter, rot_angle );
270  RotatePoint( &m_ArcEnd, aCenter, rot_angle );
271  m_t1 -= rot_angle;
272  m_t2 -= rot_angle;
273  if( m_t1 > 3600 || m_t2 > 3600 )
274  {
275  m_t1 -= 3600;
276  m_t2 -= 3600;
277  }
278  else if( m_t1 < -3600 || m_t2 < -3600 )
279  {
280  m_t1 += 3600;
281  m_t2 += 3600;
282  }
283 }
284 
285 
286 
287 void LIB_ARC::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
288  const TRANSFORM& aTransform )
289 {
290  wxASSERT( aPlotter != NULL );
291 
292  int t1 = m_t1;
293  int t2 = m_t2;
294  wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset;
295 
296  aTransform.MapAngles( &t1, &t2 );
297 
298  if( aFill && m_Fill == FILLED_WITH_BG_BODYCOLOR )
299  {
301  aPlotter->Arc( pos, -t2, -t1, m_Radius, FILLED_WITH_BG_BODYCOLOR, 0 );
302  }
303 
304  bool already_filled = m_Fill == FILLED_WITH_BG_BODYCOLOR;
305  aPlotter->SetColor( GetLayerColor( LAYER_DEVICE ) );
306  aPlotter->Arc( pos, -t2, -t1, m_Radius, already_filled ? NO_FILL : m_Fill, GetPenSize() );
307 }
308 
309 
311 {
312  return ( m_Width == 0 ) ? GetDefaultLineThickness() : m_Width;
313 }
314 
315 
316 void LIB_ARC::drawEditGraphics( EDA_RECT* aClipBox, wxDC* aDC, COLOR4D aColor )
317 {
318  // The edit indicators only get drawn when a new arc is being drawn.
319  if( !IsNew() )
320  return;
321 
322  // Use the last edit state so when the drawing switches from the end mode to the center
323  // point mode, the last line between the center points gets erased.
324  if( m_lastEditState == 1 )
325  {
326  GRLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_ArcEnd.x, -m_ArcEnd.y, 0, aColor );
327  }
328  else
329  {
330  GRDashedLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_Pos.x, -m_Pos.y, 0, aColor );
331  GRDashedLine( aClipBox, aDC, m_ArcEnd.x, -m_ArcEnd.y, m_Pos.x, -m_Pos.y, 0, aColor );
332  }
333 }
334 
335 
336 void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset,
337  COLOR4D aColor, GR_DRAWMODE aDrawMode, void* aData,
338  const TRANSFORM& aTransform )
339 {
340  // Don't draw the arc until the end point is selected. Only the edit indicators
341  // get drawn at this time.
342  if( IsNew() && m_lastEditState == 1 )
343  return;
344 
345  wxPoint pos1, pos2, posc;
347 
348  if( aColor == COLOR4D::UNSPECIFIED ) // Used normal color or selected color
349  {
350  if( IsSelected() )
351  color = GetItemSelectedColor();
352  }
353  else
354  {
355  color = aColor;
356  }
357 
358  pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset;
359  pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset;
360  posc = aTransform.TransformCoordinate( m_Pos ) + aOffset;
361  int pt1 = m_t1;
362  int pt2 = m_t2;
363  bool swap = aTransform.MapAngles( &pt1, &pt2 );
364 
365  if( swap )
366  {
367  std::swap( pos1.x, pos2.x );
368  std::swap( pos1.y, pos2.y );
369  }
370 
371  GRSetDrawMode( aDC, aDrawMode );
372 
373  FILL_T fill = aData ? NO_FILL : m_Fill;
374 
375  if( aColor != COLOR4D::UNSPECIFIED )
376  fill = NO_FILL;
377 
378  EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL;
379 
380  if( fill == FILLED_WITH_BG_BODYCOLOR )
381  {
382  GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2,
383  m_Radius, GetPenSize( ),
386  }
387  else if( fill == FILLED_SHAPE && !aData )
388  {
389  GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius,
390  color, color );
391  }
392  else
393  {
394 
395 #ifdef DRAW_ARC_WITH_ANGLE
396 
397  GRArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius,
398  GetPenSize(), color );
399 #else
400 
401  GRArc1( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y,
402  posc.x, posc.y, GetPenSize(), color );
403 #endif
404  }
405 
406  /* Set to one (1) to draw bounding box around arc to validate bounding box
407  * calculation. */
408 #if 0
409  EDA_RECT bBox = GetBoundingBox();
410  bBox.RevertYAxis();
411  bBox = aTransform.TransformCoordinate( bBox );
412  bBox.Move( aOffset );
413  GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA );
414 #endif
415 }
416 
417 
419 {
420  int minX, minY, maxX, maxY, angleStart, angleEnd;
421  EDA_RECT rect;
422  wxPoint nullPoint, startPos, endPos, centerPos;
423  wxPoint normStart = m_ArcStart - m_Pos;
424  wxPoint normEnd = m_ArcEnd - m_Pos;
425 
426  if( ( normStart == nullPoint ) || ( normEnd == nullPoint ) || ( m_Radius == 0 ) )
427  {
428  wxLogDebug( wxT("Invalid arc drawing definition, center(%d, %d) \
429 start(%d, %d), end(%d, %d), radius %d" ),
430  m_Pos.x, m_Pos.y, m_ArcStart.x, m_ArcStart.y, m_ArcEnd.x,
431  m_ArcEnd.y, m_Radius );
432  return rect;
433  }
434 
437  centerPos = DefaultTransform.TransformCoordinate( m_Pos );
438  angleStart = m_t1;
439  angleEnd = m_t2;
440 
441  if( DefaultTransform.MapAngles( &angleStart, &angleEnd ) )
442  {
443  std::swap( endPos.x, startPos.x );
444  std::swap( endPos.y, startPos.y );
445  }
446 
447  /* Start with the start and end point of the arc. */
448  minX = std::min( startPos.x, endPos.x );
449  minY = std::min( startPos.y, endPos.y );
450  maxX = std::max( startPos.x, endPos.x );
451  maxY = std::max( startPos.y, endPos.y );
452 
453  /* Zero degrees is a special case. */
454  if( angleStart == 0 )
455  maxX = centerPos.x + m_Radius;
456 
457  /* Arc end angle wrapped passed 360. */
458  if( angleStart > angleEnd )
459  angleEnd += 3600;
460 
461  if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */
462  maxY = centerPos.y + m_Radius;
463 
464  if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */
465  minX = centerPos.x - m_Radius;
466 
467  if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */
468  minY = centerPos.y - m_Radius;
469 
470  if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */
471  maxX = centerPos.x + m_Radius;
472 
473  rect.SetOrigin( minX, minY );
474  rect.SetEnd( maxX, maxY );
475  rect.Inflate( ( GetPenSize()+1 ) / 2 );
476 
477  return rect;
478 }
479 
480 
481 void LIB_ARC::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
482 {
483  wxString msg;
484  EDA_RECT bBox = GetBoundingBox();
485 
486  LIB_ITEM::GetMsgPanelInfo( aList );
487 
488  msg = StringFromValue( g_UserUnit, m_Width, true );
489 
490  aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) );
491 
492  msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x,
493  bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y );
494 
495  aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) );
496 }
497 
498 
500 {
501  return wxString::Format( _( "Arc center (%s, %s), radius %s" ),
505 }
506 
507 
509 {
510  return add_arc_xpm;
511 }
512 
513 
514 void LIB_ARC::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition )
515 {
516  wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0,
517  wxT( "Invalid edit mode for LIB_ARC object." ) );
518 
519  if( aEditMode == IS_NEW )
520  {
521  m_ArcStart = m_ArcEnd = aPosition;
523  }
524  else if( aEditMode == IS_MOVED )
525  {
527  m_initialCursorPos = aPosition;
529  }
530  else
531  {
532  // The arc center point has to be rotated with while adjusting the
533  // start or end point, determine the side of this point and the distance
534  // from the start / end point
535  wxPoint middlePoint = wxPoint( (m_ArcStart.x + m_ArcEnd.x) / 2,
536  (m_ArcStart.y + m_ArcEnd.y) / 2 );
537  wxPoint centerVector = m_Pos - middlePoint;
538  wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd );
539  m_editCenterDistance = EuclideanNorm( centerVector );
540 
541  // Determine on which side is the center point
542  m_editDirection = CrossProduct( startEndVector, centerVector ) ? 1 : -1;
543 
544  // Drag either the start, end point or the outline
546  {
548  }
549  else if( HitTestPoints( m_ArcEnd, aPosition, MINIMUM_SELECTION_DISTANCE ) )
550  {
552  }
553  else
554  {
556  }
557 
558  m_editState = 0;
560  }
561 
562  m_Flags = aEditMode;
563 }
564 
565 
566 bool LIB_ARC::ContinueEdit( const wxPoint aPosition )
567 {
568  wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false,
569  wxT( "Bad call to ContinueEdit(). LIB_ARC is not being edited." ) );
570 
571  if( m_Flags == IS_NEW )
572  {
573  if( m_editState == 1 ) // Second position yields the arc segment length.
574  {
575  m_ArcEnd = aPosition;
576  m_editState = 2;
577  SetEraseLastDrawItem( false );
578  return true; // Need third position to calculate center point.
579  }
580  }
581 
582  return false;
583 }
584 
585 
586 void LIB_ARC::EndEdit( const wxPoint& aPosition, bool aAbort )
587 {
588  wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0,
589  wxT( "Bad call to EndEdit(). LIB_ARC is not being edited." ) );
590 
591  SetEraseLastDrawItem( false );
592  m_lastEditState = 0;
593  m_editState = 0;
594  m_Flags = 0;
595 }
596 
597 
598 void LIB_ARC::calcEdit( const wxPoint& aPosition )
599 {
600  if( m_Flags == IS_RESIZED )
601  {
602  wxPoint newCenterPoint, startPos, endPos;
603 
604  // Choose the point of the arc to be adjusted
606  {
607  startPos = aPosition;
608  endPos = m_ArcEnd;
609  }
610  else if( m_editSelectPoint == ARC_STATUS_END )
611  {
612  endPos = aPosition;
613  startPos = m_ArcStart;
614  }
615  else
616  {
617  // Use the cursor for adjusting the arc curvature
618  startPos = m_ArcStart;
619  endPos = m_ArcEnd;
620 
621  // If the distance is too small, use the old center point
622  // else the new center point is calculated over the three points start/end/cursor
623  if( DistanceLinePoint( startPos, endPos, aPosition ) > MINIMUM_SELECTION_DISTANCE )
624  {
625  newCenterPoint = calcCenter( startPos, aPosition, endPos );
626  }
627  else
628  {
629  newCenterPoint = m_Pos;
630  }
631 
632  // Determine if the arc angle is larger than 180 degrees -> this happens if both
633  // points (cursor position, center point) lie on the same side of the vector
634  // start-end
635  double crossA = CrossProduct( twoPointVector( startPos, endPos ),
636  twoPointVector( endPos, aPosition ) );
637  double crossB = CrossProduct( twoPointVector( startPos, endPos ),
638  twoPointVector( endPos, newCenterPoint ) );
639 
640  if( ( crossA < 0 && crossB < 0 ) || ( crossA >= 0 && crossB >= 0 ) )
641  newCenterPoint = m_Pos;
642  }
643 
645  {
646  // Compute the new center point when the start/end points are modified
647  wxPoint middlePoint = wxPoint( (startPos.x + endPos.x) / 2,
648  (startPos.y + endPos.y) / 2 );
649 
650  wxPoint startEndVector = twoPointVector( startPos, endPos );
651  wxPoint perpendicularVector = wxPoint( -startEndVector.y, startEndVector.x );
652  double lengthPerpendicularVector = EuclideanNorm( perpendicularVector );
653 
654  // prevent too large values, division / 0
655  if( lengthPerpendicularVector < 1e-1 )
656  lengthPerpendicularVector = 1e-1;
657 
658  perpendicularVector.x = (int) ( (double) perpendicularVector.x *
660  lengthPerpendicularVector ) * m_editDirection;
661  perpendicularVector.y = (int) ( (double) perpendicularVector.y *
663  lengthPerpendicularVector ) * m_editDirection;
664 
665  newCenterPoint = middlePoint + perpendicularVector;
666 
667  m_ArcStart = startPos;
668  m_ArcEnd = endPos;
669  }
670 
671  m_Pos = newCenterPoint;
673  }
674  else if( m_Flags == IS_NEW )
675  {
676  if( m_editState == 1 )
677  {
678  m_ArcEnd = aPosition;
679  }
680 
683 
684  // Keep the arc center point up to date. Otherwise, there will be edit graphic
685  // artifacts left behind from the initial draw.
686  int dx, dy;
687  int cX, cY;
688  double angle;
689 
690  cX = aPosition.x;
691  cY = aPosition.y;
692 
693  dx = m_ArcEnd.x - m_ArcStart.x;
694  dy = m_ArcEnd.y - m_ArcStart.y;
695  cX -= m_ArcStart.x;
696  cY -= m_ArcStart.y;
697  angle = ArcTangente( dy, dx );
698  RotatePoint( &dx, &dy, angle ); /* The segment dx, dy is horizontal
699  * -> Length = dx, dy = 0 */
700  RotatePoint( &cX, &cY, angle );
701  cX = dx / 2; /* cX, cY is on the median segment 0.0 a dx, 0 */
702 
703  RotatePoint( &cX, &cY, -angle );
704  cX += m_ArcStart.x;
705  cY += m_ArcStart.y;
706  m_Pos.x = cX;
707  m_Pos.y = cY;
709 
711  }
712  else if( m_Flags == IS_MOVED )
713  {
714  Move( m_initialPos + aPosition - m_initialCursorPos );
715  }
716 }
717 
718 
720 {
721  wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart );
722  wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd );
723 
724  m_Radius = KiROUND( EuclideanNorm( centerStartVector ) );
725 
726  // Angles in eeschema are still integers
727  m_t1 = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) );
728  m_t2 = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) );
729 
731  NORMALIZE_ANGLE_POS( m_t2 ); // angles = 0 .. 3600
732 
733  // Restrict angle to less than 180 to avoid PBS display mirror Trace because it is
734  // assumed that the arc is less than 180 deg to find orientation after rotate or mirror.
735  if( (m_t2 - m_t1) > 1800 )
736  m_t2 -= 3600;
737  else if( (m_t2 - m_t1) <= -1800 )
738  m_t2 += 3600;
739 
740  while( (m_t2 - m_t1) >= 1800 )
741  {
742  m_t2--;
743  m_t1++;
744  }
745 
746  while( (m_t1 - m_t2) >= 1800 )
747  {
748  m_t2++;
749  m_t1--;
750  }
751 
753 
754  if( !IsMoving() )
756 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:112
Definition: colors.h:57
int m_Radius
Definition: lib_arc.h:47
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:209
static wxPoint twoPointVector(const wxPoint &startPoint, const wxPoint &endPoint)
Definition: lib_arc.cpp:44
bool IsMoving() const
Definition: base_struct.h:229
int m_t1
Definition: lib_arc.h:48
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
void Plot(PLOTTER *aPlotter, const wxPoint &aOffset, bool aFill, const TRANSFORM &aTransform) override
Plot the draw item using the plot object.
Definition: lib_arc.cpp:287
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
PNG memory record (file in memory).
Definition: bitmap_types.h:41
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:318
double m_editCenterDistance
Definition: lib_arc.h:54
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
void SetEraseLastDrawItem(bool aErase=true)
Implementation of conversion functions that require both schematic and board internal units...
bool IsNew() const
Definition: base_struct.h:227
virtual void SetColor(COLOR4D color)=0
#define MINIMUM_SELECTION_DISTANCE
Definition: lib_draw_item.h:52
bool Contains(const wxPoint &aPoint) const
Function Contains.
int m_t2
Definition: lib_arc.h:49
int m_lastEditState
Definition: lib_arc.h:58
wxString StringFromValue(EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol)
Function StringFromValue returns the string from aValue according to units (inch, mm ...
Definition: base_units.cpp:205
int color
Definition: DXF_plotter.cpp:62
const EDA_RECT GetBoundingBox() const override
Definition: lib_arc.cpp:418
int GetDefaultLineThickness()
Default line thickness used to draw/plot items having a default thickness line value (i...
bool IsSelected() const
Definition: base_struct.h:232
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
bool HitTest(const wxPoint &aPosition) const override
Function HitTest tests if aPosition is contained within or on the bounding area of an item...
Definition: lib_arc.cpp:102
void CalcRadiusAngles()
Calculate the radius and angle of an arc using the start, end, and center points. ...
Definition: lib_arc.cpp:719
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
Definition: lib_arc.cpp:508
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
wxString GetSelectMenuText() const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
Definition: lib_arc.cpp:499
wxPoint m_ArcEnd
Definition: lib_arc.h:51
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:241
COLOR4D GetLayerColor(SCH_LAYER_ID aLayer)
Definition: eeschema.cpp:167
void SetOffset(const wxPoint &aOffset) override
Set the drawing object by aOffset from the current position.
Definition: lib_arc.cpp:187
void RevertYAxis()
Function RevertYAxis Mirror the rectangle from the X axis (negate Y pos and size) ...
Definition: eda_rect.h:144
#define abs(a)
Definition: auxiliary.h:84
The base class for drawable items used by schematic library components.
Definition: lib_draw_item.h:66
void MirrorVertical(const wxPoint &aCenter) override
Mirror the draw object along the MirrorVertical (Y) axis about aCenter point.
Definition: lib_arc.cpp:238
This file contains miscellaneous commonly used macros and functions.
void GetMsgPanelInfo(std::vector< MSG_PANEL_ITEM > &aList) override
Display basic info (type, part and convert) about the current item in message panel.
Definition: lib_arc.cpp:481
#define IS_NEW
New item, just created.
Definition: base_struct.h:109
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:41
void GRRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, COLOR4D aColor)
Definition: gr_basic.cpp:1098
Class for tranforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
bool Inside(EDA_RECT &aRect) const override
Test if any part of the draw object is inside rectangle bounds of aRect.
Definition: lib_arc.cpp:195
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:170
bool MapAngles(int *aAngle1, int *aAngle2) const
Calculate new angles according to the transform.
Definition: transform.cpp:80
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
wxPoint m_Pos
Definition: lib_arc.h:52
void SetEnd(int x, int y)
Definition: eda_rect.h:134
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: lib_arc.cpp:159
void GRArc(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, double StAngle, double EndAngle, int r, COLOR4D Color)
Definition: gr_basic.cpp:1003
void Move(const wxPoint &aPosition) override
Move a draw object to aPosition.
Definition: lib_arc.cpp:202
bool m_isFillable
Flag to indicate if draw item is fillable.
Define a library symbol object.
unsigned STATUS_FLAGS
Definition: base_struct.h:142
void EndEdit(const wxPoint &aPosition, bool aAbort=false) override
End an object editing action.
Definition: lib_arc.cpp:586
int m_editState
Definition: lib_arc.h:56
EDA_RECT * GetClipBox()
double CrossProduct(const wxPoint &vectorA, const wxPoint &vectorB)
Determine the cross product.
Definition: trigo.h:166
int compare(const LIB_ITEM &aOther) const override
Provide the draw object specific comparison called by the == and < operators.
Definition: lib_arc.cpp:165
bool ContinueEdit(const wxPoint aNextPoint) override
Continue an edit in progress at aPosition.
Definition: lib_arc.cpp:566
int GetPenSize() const override
Definition: lib_arc.cpp:310
virtual void Rotate()
Rotate the draw item.
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:380
void GRFilledArc(EDA_RECT *ClipBox, wxDC *DC, int x, int y, double StAngle, double EndAngle, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:943
const wxPoint GetEnd() const
Definition: eda_rect.h:114
void MirrorHorizontal(const wxPoint &aCenter) override
Mirror the draw object along the horizontal (X) axis about aCenter point.
Definition: lib_arc.cpp:211
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:57
void drawGraphic(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aOffset, COLOR4D aColor, GR_DRAWMODE aDrawMode, void *aData, const TRANSFORM &aTransform) override
Draws the arc.
Definition: lib_arc.cpp:336
Base plotter engine class.
Definition: plotter.h:96
#define D(x)
Definition: ptree.cpp:41
virtual void GetMsgPanelInfo(std::vector< MSG_PANEL_ITEM > &aList) override
Display basic info (type, part and convert) about the current item in message panel.
void GRDashedLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:403
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
TRANSFORM DefaultTransform
Definition: eeschema.cpp:58
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
#define max(a, b)
Definition: auxiliary.h:86
wxPoint m_initialPos
Temporary position when moving an existing item.
void drawEditGraphics(EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor) override
Draw the graphics when the arc is being edited.
Definition: lib_arc.cpp:316
FILL_T m_Fill
The body fill type.
LIB_ARC(LIB_PART *aParent)
Definition: lib_arc.cpp:86
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
bool HitTestPoints(const wxPoint &pointA, const wxPoint &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:150
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:186
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:162
#define IS_RESIZED
Item being resized.
Definition: base_struct.h:110
int m_editDirection
Definition: lib_arc.h:57
virtual void Arc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)
Generic fallback: arc rendered as a polyline.
Definition: plotter.cpp:155
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:52
COLOR4D GetItemSelectedColor()
Class EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
SELECT_T m_editSelectPoint
Definition: lib_arc.h:55
wxPoint m_ArcStart
Definition: lib_arc.h:50
static wxPoint calcCenter(const wxPoint &A, const wxPoint &B, const wxPoint &C)
Given three points A B C, compute the circumcenter of the resulting triangle reference: http://en...
Definition: lib_arc.cpp:53
Message panel definition file.
double DistanceLinePoint(const wxPoint &linePointA, const wxPoint &linePointB, const wxPoint &referencePoint)
Compute the distance between a line and a reference point Reference: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html.
Definition: trigo.h:129
void calcEdit(const wxPoint &aPosition) override
Calculates the center, radius, and angles at aPosition when the arc is being edited.
Definition: lib_arc.cpp:598
void BeginEdit(STATUS_FLAGS aEditMode, const wxPoint aStartPoint=wxPoint(0, 0)) override
Begin an editing a component library draw item in aEditMode at aPosition.
Definition: lib_arc.cpp:514
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
wxPoint m_initialCursorPos
Initial cursor position at the beginning of a move.
int m_Width
Definition: lib_arc.h:53
#define min(a, b)
Definition: auxiliary.h:85
void GRArc1(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int xc, int yc, COLOR4D Color)
Definition: gr_basic.cpp:894
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
#define IS_MOVED
Item being moved.
Definition: base_struct.h:108
Definition: colors.h:62