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 <sch_draw_panel.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  if( m_Width > 0 )
313  return m_Width;
314 
315  if( m_Width == 0 )
316  return GetDefaultLineThickness();
317 
318  return -1; // a value to use a minimal pen size
319 }
320 
321 
322 void LIB_ARC::drawEditGraphics( EDA_RECT* aClipBox, wxDC* aDC, COLOR4D aColor )
323 {
324  // The edit indicators only get drawn when a new arc is being drawn.
325  if( !IsNew() )
326  return;
327 
328  // Use the last edit state so when the drawing switches from the end mode to the center
329  // point mode, the last line between the center points gets erased.
330  if( m_lastEditState == 1 )
331  {
332  GRLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_ArcEnd.x, -m_ArcEnd.y, 0, aColor );
333  }
334  else
335  {
336  GRDashedLine( aClipBox, aDC, m_ArcStart.x, -m_ArcStart.y, m_Pos.x, -m_Pos.y, 0, aColor );
337  GRDashedLine( aClipBox, aDC, m_ArcEnd.x, -m_ArcEnd.y, m_Pos.x, -m_Pos.y, 0, aColor );
338  }
339 }
340 
341 
342 void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset,
343  COLOR4D aColor, GR_DRAWMODE aDrawMode, void* aData,
344  const TRANSFORM& aTransform )
345 {
346  // Don't draw the arc until the end point is selected. Only the edit indicators
347  // get drawn at this time.
348  if( IsNew() && m_lastEditState == 1 )
349  return;
350 
351  wxPoint pos1, pos2, posc;
353 
354  if( aColor == COLOR4D::UNSPECIFIED ) // Used normal color or selected color
355  {
356  if( IsSelected() )
357  color = GetItemSelectedColor();
358  }
359  else
360  {
361  color = aColor;
362  }
363 
364  pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset;
365  pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset;
366  posc = aTransform.TransformCoordinate( m_Pos ) + aOffset;
367  int pt1 = m_t1;
368  int pt2 = m_t2;
369  bool swap = aTransform.MapAngles( &pt1, &pt2 );
370 
371  if( swap )
372  {
373  std::swap( pos1.x, pos2.x );
374  std::swap( pos1.y, pos2.y );
375  }
376 
377  GRSetDrawMode( aDC, aDrawMode );
378 
379  FILL_T fill = aData ? NO_FILL : m_Fill;
380 
381  if( aColor != COLOR4D::UNSPECIFIED )
382  fill = NO_FILL;
383 
384  EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL;
385 
386  if( fill == FILLED_WITH_BG_BODYCOLOR )
387  {
388  GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2,
389  m_Radius, GetPenSize( ),
392  }
393  else if( fill == FILLED_SHAPE && !aData )
394  {
395  GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius,
396  color, color );
397  }
398  else
399  {
400 
401 #ifdef DRAW_ARC_WITH_ANGLE
402 
403  GRArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius,
404  GetPenSize(), color );
405 #else
406 
407  GRArc1( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y,
408  posc.x, posc.y, GetPenSize(), color );
409 #endif
410  }
411 
412  /* Set to one (1) to draw bounding box around arc to validate bounding box
413  * calculation. */
414 #if 0
415  EDA_RECT bBox = GetBoundingBox();
416  bBox.RevertYAxis();
417  bBox = aTransform.TransformCoordinate( bBox );
418  bBox.Move( aOffset );
419  GRRect( clipbox, aDC, bBox, 0, LIGHTMAGENTA );
420 #endif
421 }
422 
423 
425 {
426  int minX, minY, maxX, maxY, angleStart, angleEnd;
427  EDA_RECT rect;
428  wxPoint nullPoint, startPos, endPos, centerPos;
429  wxPoint normStart = m_ArcStart - m_Pos;
430  wxPoint normEnd = m_ArcEnd - m_Pos;
431 
432  if( ( normStart == nullPoint ) || ( normEnd == nullPoint ) || ( m_Radius == 0 ) )
433  {
434  wxLogDebug( wxT("Invalid arc drawing definition, center(%d, %d) \
435 start(%d, %d), end(%d, %d), radius %d" ),
436  m_Pos.x, m_Pos.y, m_ArcStart.x, m_ArcStart.y, m_ArcEnd.x,
437  m_ArcEnd.y, m_Radius );
438  return rect;
439  }
440 
443  centerPos = DefaultTransform.TransformCoordinate( m_Pos );
444  angleStart = m_t1;
445  angleEnd = m_t2;
446 
447  if( DefaultTransform.MapAngles( &angleStart, &angleEnd ) )
448  {
449  std::swap( endPos.x, startPos.x );
450  std::swap( endPos.y, startPos.y );
451  }
452 
453  /* Start with the start and end point of the arc. */
454  minX = std::min( startPos.x, endPos.x );
455  minY = std::min( startPos.y, endPos.y );
456  maxX = std::max( startPos.x, endPos.x );
457  maxY = std::max( startPos.y, endPos.y );
458 
459  /* Zero degrees is a special case. */
460  if( angleStart == 0 )
461  maxX = centerPos.x + m_Radius;
462 
463  /* Arc end angle wrapped passed 360. */
464  if( angleStart > angleEnd )
465  angleEnd += 3600;
466 
467  if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */
468  maxY = centerPos.y + m_Radius;
469 
470  if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */
471  minX = centerPos.x - m_Radius;
472 
473  if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */
474  minY = centerPos.y - m_Radius;
475 
476  if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */
477  maxX = centerPos.x + m_Radius;
478 
479  rect.SetOrigin( minX, minY );
480  rect.SetEnd( maxX, maxY );
481  rect.Inflate( ( GetPenSize()+1 ) / 2 );
482 
483  return rect;
484 }
485 
486 
487 void LIB_ARC::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
488 {
489  wxString msg;
490  EDA_RECT bBox = GetBoundingBox();
491 
492  LIB_ITEM::GetMsgPanelInfo( aUnits, aList );
493 
494  msg = MessageTextFromValue( aUnits, m_Width, true );
495 
496  aList.push_back( MSG_PANEL_ITEM( _( "Line Width" ), msg, BLUE ) );
497 
498  msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x,
499  bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y );
500 
501  aList.push_back( MSG_PANEL_ITEM( _( "Bounding Box" ), msg, BROWN ) );
502 }
503 
504 
505 wxString LIB_ARC::GetSelectMenuText( EDA_UNITS_T aUnits ) const
506 {
507  return wxString::Format( _( "Arc center (%s, %s), radius %s" ),
508  MessageTextFromValue( aUnits, m_Pos.x ),
509  MessageTextFromValue( aUnits, m_Pos.y ),
510  MessageTextFromValue( aUnits, m_Radius ) );
511 }
512 
513 
515 {
516  return add_arc_xpm;
517 }
518 
519 
520 void LIB_ARC::BeginEdit( STATUS_FLAGS aEditMode, const wxPoint aPosition )
521 {
522  wxCHECK_RET( ( aEditMode & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0,
523  wxT( "Invalid edit mode for LIB_ARC object." ) );
524 
525  if( aEditMode == IS_NEW )
526  {
527  m_ArcStart = m_ArcEnd = aPosition;
529  }
530  else if( aEditMode == IS_MOVED )
531  {
533  m_initialCursorPos = aPosition;
534  }
535  else
536  {
537  // The arc center point has to be rotated with while adjusting the
538  // start or end point, determine the side of this point and the distance
539  // from the start / end point
540  wxPoint middlePoint = wxPoint( (m_ArcStart.x + m_ArcEnd.x) / 2,
541  (m_ArcStart.y + m_ArcEnd.y) / 2 );
542  wxPoint centerVector = m_Pos - middlePoint;
543  wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd );
544  m_editCenterDistance = EuclideanNorm( centerVector );
545 
546  // Determine on which side is the center point
547  m_editDirection = CrossProduct( startEndVector, centerVector ) ? 1 : -1;
548 
549  // Drag either the start, end point or the outline
551  {
553  }
554  else if( HitTestPoints( m_ArcEnd, aPosition, MINIMUM_SELECTION_DISTANCE ) )
555  {
557  }
558  else
559  {
561  }
562 
563  m_editState = 0;
564  }
565 
566  m_Flags = aEditMode;
567 }
568 
569 
570 bool LIB_ARC::ContinueEdit( const wxPoint aPosition )
571 {
572  wxCHECK_MSG( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0, false,
573  wxT( "Bad call to ContinueEdit(). LIB_ARC is not being edited." ) );
574 
575  if( m_Flags == IS_NEW )
576  {
577  if( m_editState == 1 ) // Second position yields the arc segment length.
578  {
579  m_ArcEnd = aPosition;
580  m_editState = 2;
581  return true; // Need third position to calculate center point.
582  }
583  }
584 
585  return false;
586 }
587 
588 
589 void LIB_ARC::EndEdit( const wxPoint& aPosition, bool aAbort )
590 {
591  wxCHECK_RET( ( m_Flags & ( IS_NEW | IS_MOVED | IS_RESIZED ) ) != 0,
592  wxT( "Bad call to EndEdit(). LIB_ARC is not being edited." ) );
593 
594  m_lastEditState = 0;
595  m_editState = 0;
596  m_Flags = 0;
597 }
598 
599 
600 void LIB_ARC::CalcEdit( const wxPoint& aPosition )
601 {
602  if( m_Flags == IS_RESIZED )
603  {
604  wxPoint newCenterPoint, startPos, endPos;
605 
606  // Choose the point of the arc to be adjusted
608  {
609  startPos = aPosition;
610  endPos = m_ArcEnd;
611  }
612  else if( m_editSelectPoint == ARC_STATUS_END )
613  {
614  endPos = aPosition;
615  startPos = m_ArcStart;
616  }
617  else
618  {
619  // Use the cursor for adjusting the arc curvature
620  startPos = m_ArcStart;
621  endPos = m_ArcEnd;
622 
623  // If the distance is too small, use the old center point
624  // else the new center point is calculated over the three points start/end/cursor
625  if( DistanceLinePoint( startPos, endPos, aPosition ) > MINIMUM_SELECTION_DISTANCE )
626  {
627  newCenterPoint = calcCenter( startPos, aPosition, endPos );
628  }
629  else
630  {
631  newCenterPoint = m_Pos;
632  }
633 
634  // Determine if the arc angle is larger than 180 degrees -> this happens if both
635  // points (cursor position, center point) lie on the same side of the vector
636  // start-end
637  double crossA = CrossProduct( twoPointVector( startPos, endPos ),
638  twoPointVector( endPos, aPosition ) );
639  double crossB = CrossProduct( twoPointVector( startPos, endPos ),
640  twoPointVector( endPos, newCenterPoint ) );
641 
642  if( ( crossA < 0 && crossB < 0 ) || ( crossA >= 0 && crossB >= 0 ) )
643  newCenterPoint = m_Pos;
644  }
645 
647  {
648  // Compute the new center point when the start/end points are modified
649  wxPoint middlePoint = wxPoint( (startPos.x + endPos.x) / 2,
650  (startPos.y + endPos.y) / 2 );
651 
652  wxPoint startEndVector = twoPointVector( startPos, endPos );
653  wxPoint perpendicularVector = wxPoint( -startEndVector.y, startEndVector.x );
654  double lengthPerpendicularVector = EuclideanNorm( perpendicularVector );
655 
656  // prevent too large values, division / 0
657  if( lengthPerpendicularVector < 1e-1 )
658  lengthPerpendicularVector = 1e-1;
659 
660  perpendicularVector.x = (int) ( (double) perpendicularVector.x *
662  lengthPerpendicularVector ) * m_editDirection;
663  perpendicularVector.y = (int) ( (double) perpendicularVector.y *
665  lengthPerpendicularVector ) * m_editDirection;
666 
667  newCenterPoint = middlePoint + perpendicularVector;
668 
669  m_ArcStart = startPos;
670  m_ArcEnd = endPos;
671  }
672 
673  m_Pos = newCenterPoint;
675  }
676  else if( m_Flags == IS_NEW )
677  {
678  if( m_editState == 1 )
679  {
680  m_ArcEnd = aPosition;
681  }
682 
685 
686  // Keep the arc center point up to date. Otherwise, there will be edit graphic
687  // artifacts left behind from the initial draw.
688  int dx, dy;
689  int cX, cY;
690  double angle;
691 
692  cX = aPosition.x;
693  cY = aPosition.y;
694 
695  dx = m_ArcEnd.x - m_ArcStart.x;
696  dy = m_ArcEnd.y - m_ArcStart.y;
697  cX -= m_ArcStart.x;
698  cY -= m_ArcStart.y;
699  angle = ArcTangente( dy, dx );
700  RotatePoint( &dx, &dy, angle ); /* The segment dx, dy is horizontal
701  * -> Length = dx, dy = 0 */
702  RotatePoint( &cX, &cY, angle );
703  cX = dx / 2; /* cX, cY is on the median segment 0.0 a dx, 0 */
704 
705  RotatePoint( &cX, &cY, -angle );
706  cX += m_ArcStart.x;
707  cY += m_ArcStart.y;
708  m_Pos.x = cX;
709  m_Pos.y = cY;
711 
712  }
713  else if( m_Flags == IS_MOVED )
714  {
715  Move( m_initialPos + aPosition - m_initialCursorPos );
716  }
717 }
718 
719 
721 {
722  wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart );
723  wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd );
724 
725  m_Radius = KiROUND( EuclideanNorm( centerStartVector ) );
726 
727  // Angles in eeschema are still integers
728  m_t1 = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) );
729  m_t2 = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) );
730 
732  NORMALIZE_ANGLE_POS( m_t2 ); // angles = 0 .. 3600
733 
734  // Restrict angle to less than 180 to avoid PBS display mirror Trace because it is
735  // assumed that the arc is less than 180 deg to find orientation after rotate or mirror.
736  if( (m_t2 - m_t1) > 1800 )
737  m_t2 -= 3600;
738  else if( (m_t2 - m_t1) <= -1800 )
739  m_t2 += 3600;
740 
741  while( (m_t2 - m_t1) >= 1800 )
742  {
743  m_t2--;
744  m_t1++;
745  }
746 
747  while( (m_t1 - m_t2) >= 1800 )
748  {
749  m_t2++;
750  m_t1--;
751  }
752 
754 
755  if( !IsMoving() )
757 }
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
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
virtual void GetMsgPanelInfo(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Display basic info (type, part and convert) about the current item in message panel.
static wxPoint twoPointVector(const wxPoint &startPoint, const wxPoint &endPoint)
Definition: lib_arc.cpp:44
bool IsMoving() const
Definition: base_struct.h:221
void GetMsgPanelInfo(EDA_UNITS_T aUnits, 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:487
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:43
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:223
double m_editCenterDistance
Definition: lib_arc.h:54
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
Implementation of conversion functions that require both schematic and board internal units...
bool IsNew() const
Definition: base_struct.h:219
virtual void SetColor(COLOR4D color)=0
#define MINIMUM_SELECTION_DISTANCE
Definition: lib_draw_item.h:53
bool Contains(const wxPoint &aPoint) const
Function Contains.
int m_t2
Definition: lib_arc.h:49
int m_lastEditState
Definition: lib_arc.h:58
int color
Definition: DXF_plotter.cpp:62
const EDA_RECT GetBoundingBox() const override
Definition: lib_arc.cpp:424
int GetDefaultLineThickness()
Default line thickness used to draw/plot items having a default thickness line value (i...
bool IsSelected() const
Definition: base_struct.h:224
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:720
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
Definition: lib_arc.cpp:514
virtual EDA_RECT * GetClipBox()
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
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:174
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:67
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.
wxString MessageTextFromValue(EDA_UNITS_T aUnits, int aValue, bool aUseMils)
Definition: base_units.cpp:125
#define IS_NEW
New item, just created.
Definition: base_struct.h:114
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:1003
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:908
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:147
void EndEdit(const wxPoint &aPosition, bool aAbort=false) override
End an object editing action.
Definition: lib_arc.cpp:589
int m_editState
Definition: lib_arc.h:56
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:570
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:285
void CalcEdit(const wxPoint &aPosition) override
Calculates the center, radius, and angles at aPosition when the arc is being edited.
Definition: lib_arc.cpp:600
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:848
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
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:342
Base plotter engine class.
Definition: plotter.h:97
#define D(x)
Definition: ptree.cpp:41
wxString GetSelectMenuText(EDA_UNITS_T aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
Definition: lib_arc.cpp:505
void GRDashedLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:308
TRANSFORM DefaultTransform
Definition: eeschema.cpp:59
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:322
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:178
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:154
#define IS_RESIZED
Item being resized.
Definition: base_struct.h:115
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:154
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:54
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.
EDA_UNITS_T
Definition: common.h:159
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 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:520
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:799
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:113
Definition: colors.h:62