KiCad PCB EDA Suite
pcb_point_editor.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) 2013-2021 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
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 
25 #include <functional>
26 #include <memory>
27 
28 using namespace std::placeholders;
29 #include <advanced_config.h>
30 #include <tool/tool_manager.h>
31 #include <view/view_controls.h>
32 #include <geometry/seg.h>
33 #include <confirm.h>
34 #include "pcb_actions.h"
35 #include "pcb_selection_tool.h"
36 #include "pcb_point_editor.h"
37 #include "pcb_grid_helper.h"
38 #include <board_commit.h>
39 #include <bitmaps.h>
40 #include <status_popup.h>
41 #include <pcb_edit_frame.h>
42 #include <fp_shape.h>
43 #include <dimension.h>
44 #include <zone.h>
47 
48 // Few constants to avoid using bare numbers for point indices
50 {
52 };
53 
55 {
57 };
58 
60 {
62 };
63 
65 {
67 };
68 
70 {
72 };
73 
75 {
80 };
81 
83 {
89 };
90 
92  PCB_TOOL_BASE( "pcbnew.PointEditor" ),
93  m_selectionTool( nullptr ),
94  m_editedPoint( nullptr ),
95  m_hoveredPoint( nullptr ),
96  m_original( VECTOR2I( 0, 0 ) ),
97  m_refill( false ),
98  m_altEditMethod( false ),
99  m_altConstrainer( VECTOR2I( 0, 0 ) )
100 {
101 }
102 
103 
105 {
106  m_refill = false;
107  m_editPoints.reset();
108  m_altConstraint.reset();
109  getViewControls()->SetAutoPan( false );
110 
111  m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( getEditFrame<PCB_BASE_EDIT_FRAME>() );
112  m_statusPopup->SetTextColor( wxColour( 255, 0, 0 ) );
113  m_statusPopup->SetText( _( "Self-intersecting polygons are not allowed." ) );
114 }
115 
116 
118 {
119  // Find the selection tool, so they can cooperate
121 
122  wxASSERT_MSG( m_selectionTool, "pcbnew.InteractiveSelection tool is not available" );
123 
124  auto& menu = m_selectionTool->GetToolMenu().GetMenu();
127  std::bind( &PCB_POINT_EDITOR::removeCornerCondition, this, _1 ) );
128 
129  return true;
130 }
131 
132 
133 void PCB_POINT_EDITOR::buildForPolyOutline( std::shared_ptr<EDIT_POINTS> points,
134  const SHAPE_POLY_SET* aOutline )
135 {
136  int cornersCount = aOutline->TotalVertices();
137 
138  for( auto iterator = aOutline->CIterateWithHoles(); iterator; iterator++ )
139  {
140  points->AddPoint( *iterator );
141 
142  if( iterator.IsEndContour() )
143  points->AddBreak();
144  }
145 
146  // Lines have to be added after creating edit points,
147  // as they use EDIT_POINT references
148  for( int i = 0; i < cornersCount - 1; ++i )
149  {
150  if( points->IsContourEnd( i ) )
151  points->AddLine( points->Point( i ), points->Point( points->GetContourStartIdx( i ) ) );
152  else
153  points->AddLine( points->Point( i ), points->Point( i + 1 ) );
154 
155  points->Line( i ).SetConstraint( new EC_PERPLINE( points->Line( i ) ) );
156  }
157 
158  // The last missing line, connecting the last and the first polygon point
159  points->AddLine( points->Point( cornersCount - 1 ),
160  points->Point( points->GetContourStartIdx( cornersCount - 1 ) ) );
161 
162  points->Line( points->LinesSize() - 1 )
163  .SetConstraint( new EC_PERPLINE( points->Line( points->LinesSize() - 1 ) ) );
164 }
165 
166 
167 std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
168 {
169  std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
170 
171  if( !aItem )
172  return points;
173 
174  // Generate list of edit points basing on the item type
175  switch( aItem->Type() )
176  {
177  case PCB_SHAPE_T:
178  case PCB_FP_SHAPE_T:
179  {
180  const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
181 
182  switch( shape->GetShape() )
183  {
184  case S_SEGMENT:
185  points->AddPoint( shape->GetStart() );
186  points->AddPoint( shape->GetEnd() );
187  break;
188 
189  case S_RECT:
190  points->AddPoint( shape->GetStart() );
191  points->AddPoint( wxPoint( shape->GetEnd().x, shape->GetStart().y ) );
192  points->AddPoint( shape->GetEnd() );
193  points->AddPoint( wxPoint( shape->GetStart().x, shape->GetEnd().y ) );
194 
195  points->AddLine( points->Point( RECT_TOP_LEFT ), points->Point( RECT_TOP_RIGHT ) );
196  points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
197  points->AddLine( points->Point( RECT_TOP_RIGHT ), points->Point( RECT_BOT_RIGHT ) );
198  points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
199  points->AddLine( points->Point( RECT_BOT_RIGHT ), points->Point( RECT_BOT_LEFT ) );
200  points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
201  points->AddLine( points->Point( RECT_BOT_LEFT ), points->Point( RECT_TOP_LEFT ) );
202  points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
203 
204  break;
205 
206  case S_ARC:
207  points->AddPoint( shape->GetCenter() );
208  points->AddPoint( shape->GetArcStart() );
209  points->AddPoint( shape->GetArcMid() );
210  points->AddPoint( shape->GetArcEnd() );
211 
212  points->Point( ARC_MID ).SetGridConstraint( IGNORE_GRID );
213  points->Point( ARC_START ).SetGridConstraint( SNAP_TO_GRID );
214  points->Point( ARC_CENTER ).SetGridConstraint( SNAP_BY_GRID );
215  points->Point( ARC_END ).SetGridConstraint( SNAP_TO_GRID );
216  break;
217 
218  case S_CIRCLE:
219  points->AddPoint( shape->GetCenter() );
220  points->AddPoint( shape->GetEnd() );
221  break;
222 
223  case S_POLYGON:
224  buildForPolyOutline( points, &shape->GetPolyShape() );
225  break;
226 
227  case S_CURVE:
228  points->AddPoint( shape->GetStart() );
229  points->AddPoint( shape->GetBezControl1() );
230  points->AddPoint( shape->GetBezControl2() );
231  points->AddPoint( shape->GetEnd() );
232  break;
233 
234  default: // suppress warnings
235  break;
236  }
237 
238  break;
239  }
240 
241  case PCB_PAD_T:
242  {
243  const PAD* pad = static_cast<const PAD*>( aItem );
244  wxPoint shapePos = pad->ShapePos();
245  wxPoint halfSize( pad->GetSize().x / 2, pad->GetSize().y / 2 );
246 
247  if( !m_isFootprintEditor || pad->IsLocked() )
248  break;
249 
250  switch( pad->GetShape() )
251  {
252  case PAD_SHAPE_CIRCLE:
253  points->AddPoint( shapePos );
254  points->AddPoint( wxPoint( shapePos.x + halfSize.x, shapePos.y ) );
255  break;
256 
257  case PAD_SHAPE_OVAL:
258  case PAD_SHAPE_TRAPEZOID:
259  case PAD_SHAPE_RECT:
260  case PAD_SHAPE_ROUNDRECT:
262  {
263  if( (int) pad->GetOrientation() % 900 != 0 )
264  break;
265 
266  if( pad->GetOrientation() == 900 || pad->GetOrientation() == 2700 )
267  std::swap( halfSize.x, halfSize.y );
268 
269  points->AddPoint( shapePos - halfSize );
270  points->AddPoint( wxPoint( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
271  points->AddPoint( shapePos + halfSize );
272  points->AddPoint( wxPoint( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
273  }
274  break;
275 
276  default: // suppress warnings
277  break;
278  }
279  }
280  break;
281 
282  case PCB_FP_ZONE_T:
283  case PCB_ZONE_T:
284  {
285  const ZONE* zone = static_cast<const ZONE*>( aItem );
286  buildForPolyOutline( points, zone->Outline() );
287  }
288  break;
289 
290  case PCB_DIM_ALIGNED_T:
292  {
293  const ALIGNED_DIMENSION* dimension = static_cast<const ALIGNED_DIMENSION*>( aItem );
294 
295  points->AddPoint( dimension->GetStart() );
296  points->AddPoint( dimension->GetEnd() );
297  points->AddPoint( dimension->Text().GetPosition() );
298  points->AddPoint( dimension->GetCrossbarStart() );
299  points->AddPoint( dimension->GetCrossbarEnd() );
300 
301  if( aItem->Type() == PCB_DIM_ALIGNED_T )
302  {
303  // Dimension height setting - edit points should move only along the feature lines
304  points->Point( DIM_CROSSBARSTART )
305  .SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARSTART ),
306  points->Point( DIM_START ) ) );
307  points->Point( DIM_CROSSBAREND )
308  .SetConstraint( new EC_LINE( points->Point( DIM_CROSSBAREND ),
309  points->Point( DIM_END ) ) );
310  }
311 
312  break;
313  }
314 
315  case PCB_DIM_CENTER_T:
316  {
317  const CENTER_DIMENSION* dimension = static_cast<const CENTER_DIMENSION*>( aItem );
318 
319  points->AddPoint( dimension->GetStart() );
320  points->AddPoint( dimension->GetEnd() );
321 
322  points->Point( DIM_END ).SetConstraint( new EC_45DEGREE( points->Point( DIM_END ),
323  points->Point( DIM_START ) ) );
324 
325  break;
326  }
327 
328  case PCB_DIM_LEADER_T:
329  {
330  const LEADER* dimension = static_cast<const LEADER*>( aItem );
331 
332  points->AddPoint( dimension->GetStart() );
333  points->AddPoint( dimension->GetEnd() );
334  points->AddPoint( dimension->Text().GetPosition() );
335 
336  break;
337  }
338 
339  default:
340  points.reset();
341  break;
342  }
343 
344  return points;
345 }
346 
347 
349 {
350  EDIT_POINT* point;
351  EDIT_POINT* hovered = nullptr;
352 
353  if( aEvent.IsMotion() )
354  {
355  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
356  hovered = point;
357  }
358  else if( aEvent.IsDrag( BUT_LEFT ) )
359  {
360  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
361  }
362  else
363  {
364  point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
365  }
366 
367  if( hovered )
368  {
369  if( m_hoveredPoint != hovered )
370  {
371  if( m_hoveredPoint )
372  m_hoveredPoint->SetHover( false );
373 
374  m_hoveredPoint = hovered;
376  }
377  }
378  else if( m_hoveredPoint )
379  {
380  m_hoveredPoint->SetHover( false );
381  m_hoveredPoint = nullptr;
382  }
383 
384  if( m_editedPoint != point )
385  setEditedPoint( point );
386 }
387 
388 
390 {
392  return 0;
393 
395 
396  if( selection.Size() != 1 || selection.Front()->GetEditFlags() )
397  return 0;
398 
399  Activate();
400 
402  KIGFX::VIEW* view = getView();
403  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
404 
405  controls->ShowCursor( true );
406 
407  PCB_GRID_HELPER grid( m_toolMgr, editFrame->GetMagneticItemsSettings() );
408  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
409 
410  if( !item )
411  return 0;
412 
413  m_editPoints = makePoints( item );
414 
415  if( !m_editPoints )
416  return 0;
417 
418  view->Add( m_editPoints.get() );
419  setEditedPoint( nullptr );
420  updateEditedPoint( aEvent );
421  m_refill = false;
422  bool inDrag = false;
423 
424  BOARD_COMMIT commit( editFrame );
425  LSET snapLayers = item->GetLayerSet();
426 
427  if( BaseType( item->Type() ) == PCB_DIMENSION_T )
428  snapLayers = LSET::AllLayersMask();
429 
430  // Main loop: keep receiving events
431  while( TOOL_EVENT* evt = Wait() )
432  {
433  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
434  grid.SetUseGrid( view->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) );
435 
436  if( !m_editPoints || evt->IsSelectionEvent() ||
437  evt->Matches( EVENTS::InhibitSelectionEditing ) )
438  {
439  break;
440  }
441 
442  EDIT_POINT* prevHover = m_hoveredPoint;
443 
444  if( !inDrag )
445  updateEditedPoint( *evt );
446 
447  if( prevHover != m_hoveredPoint )
448  getView()->Update( m_editPoints.get() );
449 
450  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
451  {
452  if( !inDrag )
453  {
454  frame()->UndoRedoBlock( true );
455 
456  commit.StageItems( selection, CHT_MODIFY );
457 
458  controls->ForceCursorPosition( false );
459  m_original = *m_editedPoint; // Save the original position
460  controls->SetAutoPan( true );
461  inDrag = true;
462 
464  grid.SetAuxAxes( true, m_original.GetPosition() );
465 
466  setAltConstraint( true );
468  }
469 
470  VECTOR2I pos = evt->Position();
471 
472  //TODO: unify the constraints to solve simultaneously instead of sequentially
473  switch( m_editedPoint->GetGridConstraint() )
474  {
475  case IGNORE_GRID:
476  m_editedPoint->SetPosition( pos );
477  break;
478 
479  case SNAP_TO_GRID:
480  m_editedPoint->SetPosition( grid.BestSnapAnchor( pos, snapLayers, { item } ) );
481  break;
482 
483  case SNAP_BY_GRID:
484  {
485  if( grid.GetUseGrid() )
486  {
487  VECTOR2I gridPt = grid.BestSnapAnchor( pos, {}, { item } );
488 
490  VECTOR2I delta = pos - last;
491  VECTOR2I deltaGrid = gridPt - grid.BestSnapAnchor( last, {}, { item } );
492 
493  if( abs( delta.x ) > grid.GetGrid().x / 2 )
494  pos.x = last.x + deltaGrid.x;
495  else
496  pos.x = last.x;
497 
498  if( abs( delta.y ) > grid.GetGrid().y / 2 )
499  pos.y = last.y + deltaGrid.y;
500  else
501  pos.y = last.y;
502  }
503 
504  m_editedPoint->SetPosition( pos );
505  }
506  break;
507  }
508 
509  // The alternative constraint limits to 45 degrees
510  bool enableAltConstraint = !!evt->Modifier( MD_CTRL );
511 
512  if( enableAltConstraint )
513  m_altConstraint->Apply();
514  else
516 
518  m_editedPoint->SetPosition( grid.BestSnapAnchor( pos, snapLayers, { item } ) );
519 
520  updateItem();
522  updatePoints();
523  }
524  else if( m_editedPoint && evt->Action() == TA_MOUSE_DOWN && evt->Buttons() == BUT_LEFT )
525  {
527  getView()->Update( m_editPoints.get() );
528  }
529  else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
530  {
531  if( m_editedPoint )
532  {
533  m_editedPoint->SetActive( false );
534  getView()->Update( m_editPoints.get() );
535  }
536 
537  controls->SetAutoPan( false );
538  setAltConstraint( false );
539 
540  commit.Push( _( "Drag a corner" ) );
541  inDrag = false;
542  frame()->UndoRedoBlock( false );
543 
544  m_refill = true;
545  }
546 
547  else if( evt->IsCancelInteractive() || evt->IsActivate() )
548  {
549  if( inDrag ) // Restore the last change
550  {
551  commit.Revert();
552  inDrag = false;
553  frame()->UndoRedoBlock( false );
554  }
555  else if( evt->IsCancelInteractive() )
556  {
557  break;
558  }
559 
560  if( evt->IsActivate() && !evt->IsMoveTool() )
561  break;
562  }
563 
564  else if( evt->Action() == TA_UNDO_REDO_POST )
565  {
566  break;
567  }
568 
569  else
570  {
571  evt->SetPassEvent();
572  }
573  }
574 
575  if( m_editPoints )
576  {
577  view->Remove( m_editPoints.get() );
578 
579  finishItem();
580  m_editPoints.reset();
581  }
582 
583  frame()->UpdateMsgPanel();
584 
585  return 0;
586 }
587 
589  VECTOR2I aStart, VECTOR2I aMid, VECTOR2I aEnd,
590  const VECTOR2I aCursor ) const
591 {
592  VECTOR2D startLine = aStart - aCenter;
593  VECTOR2D endLine = aEnd - aCenter;
594  double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
595 
596  bool clockwise;
597  bool movingStart;
598  bool arcValid = true;
599 
600  VECTOR2I *p1, *p2, *p3;
601  // p1 does not move, p2 does.
602 
603  if( aStart != aArc->GetArcStart() )
604  {
605  aStart = aCursor;
606  p1 = &aEnd;
607  p2 = &aStart;
608  p3 = &aMid;
609  movingStart = true;
610  }
611  else if( aEnd != aArc->GetArcEnd() )
612  {
613  aEnd = aCursor;
614  p1 = &aStart;
615  p2 = &aEnd;
616  p3 = &aMid;
617  movingStart = false;
618  }
619  else
620  {
621  return;
622  }
623 
624  VECTOR2D v1, v2, v3, v4;
625 
626  // Move the coordinate system
627  v1 = *p1 - aCenter;
628  v2 = *p2 - aCenter;
629  v3 = *p3 - aCenter;
630 
631  VECTOR2D u1, u2, u3;
632 
633  // A point cannot be both the center and on the arc.
634  if( ( v1.EuclideanNorm() == 0 ) || ( v2.EuclideanNorm() == 0 ) )
635  return;
636 
637  u1 = v1 / v1.EuclideanNorm();
638  u2 = v3 - ( u1.x * v3.x + u1.y * v3.y ) * u1;
639  u2 = u2 / u2.EuclideanNorm();
640 
641  // [ u1, u3 ] is a base centered on the circle with:
642  // u1 : unit vector toward the point that does not move
643  // u2 : unit vector toward the mid point.
644 
645  // Get vectors v1, and v2 in that coordinate system.
646 
647  double det = u1.x * u2.y - u2.x * u1.y;
648 
649  // u1 and u2 are unit vectors, and perpendicular.
650  // det should not be 0. In case it is, do not change the arc.
651  if( det == 0 )
652  return;
653 
654  double tmpx = v1.x * u2.y - v1.y * u2.x;
655  double tmpy = -v1.x * u1.y + v1.y * u1.x;
656  v1.x = tmpx;
657  v1.y = tmpy;
658  v1 = v1 / det;
659 
660  tmpx = v2.x * u2.y - v2.y * u2.x;
661  tmpy = -v2.x * u1.y + v2.y * u1.x;
662  v2.x = tmpx;
663  v2.y = tmpy;
664  v2 = v2 / det;
665 
666  double R = v1.EuclideanNorm();
667  bool transformCircle = false;
668 
669  /* p2
670  * X***
671  * ** <---- This is the arc
672  * y ^ **
673  * | R *
674  * | <-----------> *
675  * x------x------>--------x p1
676  * C' <----> C x
677  * delta
678  *
679  * p1 does not move, and the tangent at p1 remains the same.
680  * => The new center, C', will be on the C-p1 axis.
681  * p2 moves
682  *
683  * The radius of the new circle is delta + R
684  *
685  * || C' p2 || = || C' P1 ||
686  * is the same as :
687  * ( delta + p2.x ) ^ 2 + p2.y ^ 2 = ( R + delta ) ^ 2
688  *
689  * delta = ( R^2 - p2.x ^ 2 - p2.y ^2 ) / ( 2 * p2.x - 2 * R )
690  *
691  * We can use this equation for any point p2 with p2.x < R
692  */
693 
694  if( v2.x == R )
695  {
696  // Straight line, do nothing
697  }
698  else
699  {
700  if( v2.x > R )
701  {
702  // If we need to invert the curvature.
703  // We modify the input so we can use the same equation
704  transformCircle = true;
705  v2.x = 2 * R - v2.x;
706  }
707  // We can keep the tangent constraint.
708  double delta = ( R * R - v2.x * v2.x - v2.y * v2.y ) / ( 2 * v2.x - 2 * R );
709 
710  // This is just to limit the radius, so nothing overflows later when drawing.
711  if( abs( v2.y / ( R - v2.x ) ) > ADVANCED_CFG::GetCfg().m_DrawArcCenterMaxAngle )
712  {
713  arcValid = false;
714  }
715  // Never recorded a problem, but still checking.
716  if( !std::isfinite( delta ) )
717  {
718  arcValid = false;
719  }
720  // v4 is the new center
721  v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) : VECTOR2D( 2 * R + delta, 0 );
722 
723  clockwise = aArc->GetAngle() > 0;
724 
725  if( transformCircle )
726  clockwise = !clockwise;
727 
728  tmpx = v4.x * u1.x + v4.y * u2.x;
729  tmpy = v4.x * u1.y + v4.y * u2.y;
730  v4.x = tmpx;
731  v4.y = tmpy;
732 
733  aCenter = v4 + aCenter;
734 
735  startLine = aStart - aCenter;
736  endLine = aEnd - aCenter;
737  newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
738 
739  if( clockwise && newAngle < 0.0 )
740  newAngle += 3600.0;
741  else if( !clockwise && newAngle > 0.0 )
742  newAngle -= 3600.0;
743 
744  if( arcValid )
745  {
746  aArc->SetAngle( newAngle, false );
747  aArc->SetCenter( wxPoint( aCenter.x, aCenter.y ) );
748 
749  if( movingStart )
750  aArc->SetArcStart( wxPoint( aStart.x, aStart.y ) );
751  else
752  aArc->SetArcEnd( wxPoint( aEnd.x, aEnd.y ) );
753  }
754  }
755 }
756 
757 
771 static void pinEditedCorner( int aEditedPointIndex, int aMinWidth, int aMinHeight,
772  VECTOR2I& aTopLeft, VECTOR2I& aTopRight, VECTOR2I& aBotLeft,
773  VECTOR2I& aBotRight, VECTOR2I aHole, VECTOR2I aHoleSize )
774 {
775  switch( aEditedPointIndex )
776  {
777  case RECT_TOP_LEFT:
778  if( aHoleSize.x )
779  {
780  // pin edited point to the top/left of the hole
781  aTopLeft.x = std::min( aTopLeft.x, aHole.x - aHoleSize.x / 2 - aMinWidth );
782  aTopLeft.y = std::min( aTopLeft.y, aHole.y - aHoleSize.y / 2 - aMinHeight );
783  }
784  else
785  {
786  // pin edited point within opposite corner
787  aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - aMinWidth );
788  aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - aMinHeight );
789  }
790 
791  // push edited point edges to adjacent corners
792  aTopRight.y = aTopLeft.y;
793  aBotLeft.x = aTopLeft.x;
794 
795  break;
796 
797  case RECT_TOP_RIGHT:
798  if( aHoleSize.x )
799  {
800  // pin edited point to the top/right of the hole
801  aTopRight.x = std::max( aTopRight.x, aHole.x + aHoleSize.x / 2 + aMinWidth );
802  aTopRight.y = std::min( aTopRight.y, aHole.y - aHoleSize.y / 2 - aMinHeight );
803  }
804  else
805  {
806  // pin edited point within opposite corner
807  aTopRight.x = std::max( aTopRight.x, aBotLeft.x + aMinWidth );
808  aTopRight.y = std::min( aTopRight.y, aBotLeft.y - aMinHeight );
809  }
810 
811  // push edited point edges to adjacent corners
812  aTopLeft.y = aTopRight.y;
813  aBotRight.x = aTopRight.x;
814 
815  break;
816 
817  case RECT_BOT_LEFT:
818  if( aHoleSize.x )
819  {
820  // pin edited point to the bottom/left of the hole
821  aBotLeft.x = std::min( aBotLeft.x, aHole.x - aHoleSize.x / 2 - aMinWidth );
822  aBotLeft.y = std::max( aBotLeft.y, aHole.y + aHoleSize.y / 2 + aMinHeight );
823  }
824  else
825  {
826  // pin edited point within opposite corner
827  aBotLeft.x = std::min( aBotLeft.x, aTopRight.x - aMinWidth );
828  aBotLeft.y = std::max( aBotLeft.y, aTopRight.y + aMinHeight );
829  }
830 
831  // push edited point edges to adjacent corners
832  aBotRight.y = aBotLeft.y;
833  aTopLeft.x = aBotLeft.x;
834 
835  break;
836 
837  case RECT_BOT_RIGHT:
838  if( aHoleSize.x )
839  {
840  // pin edited point to the bottom/right of the hole
841  aBotRight.x = std::max( aBotRight.x, aHole.x + aHoleSize.x / 2 + aMinWidth );
842  aBotRight.y = std::max( aBotRight.y, aHole.y + aHoleSize.y / 2 + aMinHeight );
843  }
844  else
845  {
846  // pin edited point within opposite corner
847  aBotRight.x = std::max( aBotRight.x, aTopLeft.x + aMinWidth );
848  aBotRight.y = std::max( aBotRight.y, aTopLeft.y + aMinHeight );
849  }
850 
851  // push edited point edges to adjacent corners
852  aBotLeft.y = aBotRight.y;
853  aTopRight.x = aBotRight.x;
854 
855  break;
856  }
857 }
858 
859 
861  VECTOR2I aStart, VECTOR2I aMid, VECTOR2I aEnd,
862  const VECTOR2I aCursor ) const
863 {
864  bool clockwise;
865  bool movingStart;
866 
867  VECTOR2I *p1, *p2;
868  VECTOR2I target;
869 
870  // p1 does not move, p2 does.
871 
872  if( aStart != aArc->GetArcStart() )
873  {
874  p1 = &aEnd;
875  p2 = &aStart;
876  movingStart = true;
877  }
878  else
879  {
880  p1 = &aStart;
881  p2 = &aEnd;
882  movingStart = false;
883  }
884 
885  target = *p2 - aCenter;
886 
887  double sqRadius = ( *p1 - aCenter ).SquaredEuclideanNorm();
888 
889  *p1 = *p1 - aCenter;
890  *p2 = *p2 - aCenter;
891 
892  // Circle : x^2 + y^2 = R ^ 2
893  // In this coordinate system, the angular position of the cursor is (r, theta)
894  // The line coming from the center of the circle is y = start.y / start.x * x
895  // The intersection fulfills : x^2 = R^2 / ( 1 + ( start.y / start.x ) ^ 2 )
896 
897  if( target.x == 0 )
898  {
899  p2->x = 0;
900  p2->y = ( target.y > 0 ) ? sqrt( sqRadius ) : -sqrt( sqRadius );
901  }
902  else
903  {
904  double tan = target.y / static_cast<double>( target.x );
905  // The divider is always greater than 1 ( cannot be 0 )
906  double tmp = sqrt( sqRadius / ( 1.0 + tan * tan ) );
907  // Move to the correct quadrant
908  tmp = target.x > 0 ? tmp : -tmp;
909  p2->y = target.y / static_cast<double>( target.x ) * tmp;
910  p2->x = tmp;
911  }
912 
913  *p1 = *p1 + aCenter;
914  *p2 = *p2 + aCenter;
915 
916  clockwise = aArc->GetAngle() > 0;
917 
918  VECTOR2D startLine = aStart - aCenter;
919  VECTOR2D endLine = aEnd - aCenter;
920  double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
921 
922  if( clockwise && newAngle < 0.0 )
923  newAngle += 3600.0;
924  else if( !clockwise && newAngle > 0.0 )
925  newAngle -= 3600.0;
926 
927  aArc->SetAngle( newAngle, false );
928  aArc->SetCenter( (wxPoint) aCenter );
929 
930  if( movingStart )
931  aArc->SetArcStart( (wxPoint) aStart );
932  else
933  aArc->SetArcEnd( (wxPoint) aEnd );
934 }
935 
936 
938  VECTOR2I aMid, VECTOR2I aEnd,
939  const VECTOR2I aCursor ) const
940 {
941  // Now, update the edit point position
942  // Express the point in a cercle-centered coordinate system.
943  aStart = aStart - aCenter;
944  aEnd = aEnd - aCenter;
945 
946  double sqRadius = ( aCursor - aCenter ).SquaredEuclideanNorm();
947 
948  // Special case, because the tangent would lead to +/- infinity
949  if( aStart.x == 0 )
950  {
951  aStart.y = aCursor.y > 0 ? sqrt( sqRadius ) : -sqrt( sqRadius );
952  }
953  else
954  {
955  // Circle : x^2 + y^2 = R ^ 2
956  // In this coordinate system, the angular position of the cursor is (r, theta)
957  // The line coming from the center of the circle is y = start.y / start.x * x
958  // The intersection fulfills : x^2 = R^2 / ( 1 + ( start.y / start.x ) ^ 2 )
959 
960  double tan = aStart.y / static_cast<double>( aStart.x );
961  double tmp = sqrt( sqRadius / ( 1.0 + tan * tan ) );
962  // Move to the correct quadrant
963  tmp = aStart.x > 0 ? tmp : -tmp;
964  aStart.y = aStart.y / static_cast<double>( aStart.x ) * tmp;
965  aStart.x = tmp;
966  }
967 
968  // Special case, because the tangent would lead to +/- infinity
969  if( aEnd.x == 0 )
970  {
971  aEnd.y = aMid.y > 0 ? sqrt( sqRadius ) : -sqrt( sqRadius );
972  }
973  else
974  {
975  // Circle : x^2 + y^2 = R ^ 2
976  // In this coordinate system, the angular position of the cursor is (r, theta)
977  // The line coming from the center of the circle is y = start.y / start.x * x
978  // The intersection fulfills : x^2 = R^2 / ( 1 + ( start.y / start.x ) ^ 2 )
979 
980  double tan = aEnd.y / static_cast<double>( aEnd.x );
981  double tmp = sqrt( sqRadius / ( 1.0 + tan * tan ) );
982  // Move to the correct quadrant
983  tmp = aEnd.x > 0 ? tmp : -tmp;
984  aEnd.y = aEnd.y / static_cast<double>( aEnd.x ) * tmp;
985  aEnd.x = tmp;
986  }
987 
988  aStart = aStart + aCenter;
989  aEnd = aEnd + aCenter;
990 
991  aArc->SetArcStart( (wxPoint) aStart );
992  aArc->SetArcEnd( (wxPoint) aEnd );
993 }
994 
995 
997  const VECTOR2I aCursor ) const
998 {
999  // Let 'm' be the middle point of the chord between the start and end points
1000  VECTOR2I m = ( aStart + aEnd ) / 2;
1001 
1002  // Legal midpoints lie on a vector starting just off the chord midpoint and extending out
1003  // past the existing midpoint. We do not allow arc inflection while point editing.
1004  const int JUST_OFF = ( aStart - aEnd ).EuclideanNorm() / 100;
1005  VECTOR2I v = (VECTOR2I) aArc->GetArcMid() - m;
1006  SEG legal( m + v.Resize( JUST_OFF ), m + v.Resize( INT_MAX / 2 ) );
1007  VECTOR2I mid = legal.NearestPoint( aCursor );
1008 
1009  aArc->SetArcGeometry( (wxPoint) aStart, (wxPoint) mid, (wxPoint) aEnd );
1010 }
1011 
1012 
1014 {
1015  EDA_ITEM* item = m_editPoints->GetParent();
1016 
1017  if( !item )
1018  return;
1019 
1020  switch( item->Type() )
1021  {
1022  case PCB_SHAPE_T:
1023  case PCB_FP_SHAPE_T:
1024  {
1025  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
1026 
1027  switch( shape->GetShape() )
1028  {
1029  case S_SEGMENT:
1030  if( isModified( m_editPoints->Point( SEG_START ) ) )
1031  {
1032  shape->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x,
1033  m_editPoints->Point( SEG_START ).GetPosition().y ) );
1034  }
1035  else if( isModified( m_editPoints->Point( SEG_END ) ) )
1036  {
1037  shape->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x,
1038  m_editPoints->Point( SEG_END ).GetPosition().y ) );
1039  }
1040 
1041  break;
1042 
1043  case S_RECT:
1044  {
1045  if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) ) )
1046  {
1047  shape->SetStart((wxPoint) m_editPoints->Point( RECT_TOP_LEFT ).GetPosition() );
1048  }
1049  else if( isModified( m_editPoints->Point( RECT_TOP_RIGHT ) ) )
1050  {
1051  shape->SetStartY( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().y );
1052  shape->SetEndX( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().x );
1053  }
1054  else if( isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
1055  {
1056  shape->SetEnd((wxPoint) m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition() );
1057  }
1058  else if( isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
1059  {
1060  shape->SetStartX( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().x );
1061  shape->SetEndY( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().y );
1062  }
1063  else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
1064  {
1065  shape->SetStartY( m_editPoints->Point( RECT_TOP_LEFT ).GetPosition().y );
1066  }
1067  else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
1068  {
1069  shape->SetStartX( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().x );
1070  }
1071  else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
1072  {
1073  shape->SetEndY( m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition().y );
1074  }
1075  else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
1076  {
1077  shape->SetEndX( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().x );
1078  }
1079 
1080  for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1081  {
1082  if( !isModified( m_editPoints->Line( i ) ) )
1083  m_editPoints->Line( i ).SetConstraint( new EC_PERPLINE( m_editPoints->Line( i ) ) );
1084  }
1085  }
1086  break;
1087 
1088  case S_ARC:
1089  {
1090  VECTOR2I center = m_editPoints->Point( ARC_CENTER ).GetPosition();
1091  VECTOR2I mid = m_editPoints->Point( ARC_MID ).GetPosition();
1092  VECTOR2I start = m_editPoints->Point( ARC_START ).GetPosition();
1093  VECTOR2I end = m_editPoints->Point( ARC_END ).GetPosition();
1094 
1095  if( isModified( m_editPoints->Point( ARC_CENTER ) ) )
1096  {
1097  wxPoint moveVector = wxPoint( center.x, center.y ) - shape->GetCenter();
1098  shape->Move( moveVector );
1099  }
1100  else if( isModified( m_editPoints->Point( ARC_MID ) ) )
1101  {
1102  const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition( false );
1103 
1104  if( m_altEditMethod )
1105  editArcMidKeepCenter( shape, center, start, mid, end, cursorPos );
1106  else
1107  editArcMidKeepEndpoints( shape, start, end, cursorPos );
1108  }
1109  else if( isModified( m_editPoints->Point( ARC_START ) )
1110  || isModified( m_editPoints->Point( ARC_END ) ) )
1111  {
1112  const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
1113 
1114  if( m_altEditMethod )
1115  editArcEndpointKeepCenter( shape, center, start, mid, end, cursorPos );
1116  else
1117  editArcEndpointKeepTangent( shape, center, start, mid, end, cursorPos );
1118  }
1119  }
1120  break;
1121 
1122  case S_CIRCLE:
1123  {
1124  const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition();
1125  const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition();
1126 
1127  if( isModified( m_editPoints->Point( CIRC_CENTER ) ) )
1128  {
1129  wxPoint moveVector = wxPoint( center.x, center.y ) - shape->GetCenter();
1130  shape->Move( moveVector );
1131  }
1132  else
1133  {
1134  shape->SetEnd( wxPoint( end.x, end.y ) );
1135  }
1136  }
1137  break;
1138 
1139  case S_POLYGON:
1140  {
1141  SHAPE_POLY_SET& outline = shape->GetPolyShape();
1142 
1143  for( int i = 0; i < outline.TotalVertices(); ++i )
1144  outline.SetVertex( i, m_editPoints->Point( i ).GetPosition() );
1145 
1146  for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
1147  {
1148  if( !isModified( m_editPoints->Line( i ) ) )
1149  m_editPoints->Line( i ).SetConstraint( new EC_PERPLINE( m_editPoints->Line( i ) ) );
1150  }
1151 
1152  validatePolygon( outline );
1153  }
1154  break;
1155 
1156  case S_CURVE:
1157  if( isModified( m_editPoints->Point( BEZIER_CURVE_START ) ) )
1158  shape->SetStart( (wxPoint) m_editPoints->Point( BEZIER_CURVE_START ).GetPosition() );
1159  else if( isModified( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ) ) )
1160  shape->SetBezControl1( (wxPoint) m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).GetPosition() );
1161  else if( isModified( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ) ) )
1162  shape->SetBezControl2( (wxPoint) m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).GetPosition() );
1163  else if( isModified( m_editPoints->Point( BEZIER_CURVE_END ) ) )
1164  shape->SetEnd( (wxPoint) m_editPoints->Point( BEZIER_CURVE_END ).GetPosition() );
1165 
1166  shape->RebuildBezierToSegmentsPointsList( shape->GetWidth() );
1167  break;
1168 
1169  default: // suppress warnings
1170  break;
1171  }
1172 
1173  // Update relative coordinates for footprint shapes
1174  if( FP_SHAPE* fpShape = dyn_cast<FP_SHAPE*>( item ) )
1175  fpShape->SetLocalCoord();
1176 
1177  break;
1178  }
1179 
1180  case PCB_PAD_T:
1181  {
1182  PAD* pad = static_cast<PAD*>( item );
1183 
1184  switch( pad->GetShape() )
1185  {
1186  case PAD_SHAPE_CIRCLE:
1187  {
1188  wxPoint center = (wxPoint) m_editPoints->Point( CIRC_CENTER ).GetPosition();
1189  wxPoint end = (wxPoint) m_editPoints->Point( CIRC_END ).GetPosition();
1190 
1191  if( isModified( m_editPoints->Point( CIRC_CENTER ) ) )
1192  {
1193  wxPoint moveVector = center - pad->ShapePos();
1194  pad->SetOffset( pad->GetOffset() + moveVector );
1195  }
1196  else
1197  {
1198  int diameter = (int) EuclideanNorm( end - center ) * 2;
1199  pad->SetSize( wxSize( diameter, diameter ) );
1200  }
1201  }
1202  break;
1203 
1204  case PAD_SHAPE_OVAL:
1205  case PAD_SHAPE_TRAPEZOID:
1206  case PAD_SHAPE_RECT:
1207  case PAD_SHAPE_ROUNDRECT:
1209  {
1210  VECTOR2I topLeft = m_editPoints->Point( RECT_TOP_LEFT ).GetPosition();
1211  VECTOR2I topRight = m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition();
1212  VECTOR2I botLeft = m_editPoints->Point( RECT_BOT_LEFT ).GetPosition();
1213  VECTOR2I botRight = m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition();
1214 
1215  pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight,
1216  botLeft, botRight,pad->GetPosition(), pad->GetDrillSize() );
1217 
1218  if( ( pad->GetOffset().x || pad->GetOffset().y )
1219  || ( pad->GetDrillSize().x && pad->GetDrillSize().y ) )
1220  {
1221  // Keep hole pinned at the current location; adjust the pad around the hole
1222 
1223  wxPoint center = pad->GetPosition();
1224  int dist[4];
1225 
1226  if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) )
1227  || isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
1228  {
1229  dist[0] = center.x - topLeft.x;
1230  dist[1] = center.y - topLeft.y;
1231  dist[2] = botRight.x - center.x;
1232  dist[3] = botRight.y - center.y;
1233  }
1234  else
1235  {
1236  dist[0] = center.x - botLeft.x;
1237  dist[1] = center.y - topRight.y;
1238  dist[2] = topRight.x - center.x;
1239  dist[3] = botLeft.y - center.y;
1240  }
1241 
1242  wxSize padSize( dist[0] + dist[2], dist[1] + dist[3] );
1243  wxPoint deltaOffset( padSize.x / 2 - dist[2], padSize.y / 2 - dist[3] );
1244 
1245  if( pad->GetOrientation() == 900 || pad->GetOrientation() == 2700 )
1246  std::swap( padSize.x, padSize.y );
1247 
1248  RotatePoint( &deltaOffset, -pad->GetOrientation() );
1249 
1250  pad->SetSize( padSize );
1251  pad->SetOffset( -deltaOffset );
1252  }
1253  else
1254  {
1255  // Keep pad position at the center of the pad shape
1256 
1257  int left, top, right, bottom;
1258 
1259  if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) )
1260  || isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
1261  {
1262  left = topLeft.x;
1263  top = topLeft.y;
1264  right = botRight.x;
1265  bottom = botRight.y;
1266  }
1267  else
1268  {
1269  left = botLeft.x;
1270  top = topRight.y;
1271  right = topRight.x;
1272  bottom = botLeft.y;
1273  }
1274 
1275  wxSize padSize( abs( right - left ), abs( bottom - top ) );
1276 
1277  if( pad->GetOrientation() == 900 || pad->GetOrientation() == 2700 )
1278  std::swap( padSize.x, padSize.y );
1279 
1280  pad->SetSize( padSize );
1281  pad->SetPosition( wxPoint( ( left + right ) / 2, ( top + bottom ) / 2 ) );
1282  }
1283  }
1284  break;
1285 
1286  default: // suppress warnings
1287  break;
1288  }
1289  }
1290  break;
1291 
1292  case PCB_FP_ZONE_T:
1293  case PCB_ZONE_T:
1294  {
1295  ZONE* zone = static_cast<ZONE*>( item );
1296  zone->ClearFilledPolysList();
1297  SHAPE_POLY_SET& outline = *zone->Outline();
1298 
1299  for( int i = 0; i < outline.TotalVertices(); ++i )
1300  {
1301  if( outline.CVertex( i ) != m_editPoints->Point( i ).GetPosition() )
1302  zone->SetNeedRefill( true );
1303 
1304  outline.SetVertex( i, m_editPoints->Point( i ).GetPosition() );
1305  }
1306 
1307  validatePolygon( outline );
1308  zone->HatchBorder();
1309  break;
1310  }
1311 
1312  case PCB_DIM_ALIGNED_T:
1313  {
1314  ALIGNED_DIMENSION* dimension = static_cast<ALIGNED_DIMENSION*>( item );
1315 
1316  // Check which point is currently modified and updated dimension's points respectively
1317  if( isModified( m_editPoints->Point( DIM_CROSSBARSTART ) ) )
1318  {
1319  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetStart() );
1320  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetStart() );
1321 
1322  if( featureLine.Cross( crossBar ) > 0 )
1323  dimension->SetHeight( -featureLine.EuclideanNorm() );
1324  else
1325  dimension->SetHeight( featureLine.EuclideanNorm() );
1326 
1327  dimension->Update();
1328  }
1329  else if( isModified( m_editPoints->Point( DIM_CROSSBAREND ) ) )
1330  {
1331  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() );
1332  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetStart() );
1333 
1334  if( featureLine.Cross( crossBar ) > 0 )
1335  dimension->SetHeight( -featureLine.EuclideanNorm() );
1336  else
1337  dimension->SetHeight( featureLine.EuclideanNorm() );
1338 
1339  dimension->Update();
1340  }
1341  else if( isModified( m_editPoints->Point( DIM_START ) ) )
1342  {
1343  dimension->SetStart( wxPoint( m_editedPoint->GetPosition().x,
1344  m_editedPoint->GetPosition().y ) );
1345  dimension->Update();
1346 
1347  m_editPoints->Point( DIM_CROSSBARSTART ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARSTART ),
1348  m_editPoints->Point( DIM_START ) ) );
1349  m_editPoints->Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBAREND ),
1350  m_editPoints->Point( DIM_END ) ) );
1351  }
1352  else if( isModified( m_editPoints->Point( DIM_END ) ) )
1353  {
1354  dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x,
1355  m_editedPoint->GetPosition().y ) );
1356  dimension->Update();
1357 
1358  m_editPoints->Point( DIM_CROSSBARSTART ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARSTART ),
1359  m_editPoints->Point( DIM_START ) ) );
1360  m_editPoints->Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBAREND ),
1361  m_editPoints->Point( DIM_END ) ) );
1362  }
1363  else if( isModified( m_editPoints->Point(DIM_TEXT ) ) )
1364  {
1365  // Force manual mode if we weren't already in it
1367  dimension->Text().SetPosition( wxPoint( m_editedPoint->GetPosition() ) );
1368  dimension->Update();
1369  }
1370 
1371  break;
1372  }
1373 
1374  case PCB_DIM_ORTHOGONAL_T:
1375  {
1376  ORTHOGONAL_DIMENSION* dimension = static_cast<ORTHOGONAL_DIMENSION*>( item );
1377 
1378  if( isModified( m_editPoints->Point( DIM_CROSSBARSTART ) ) ||
1379  isModified( m_editPoints->Point( DIM_CROSSBAREND ) ) )
1380  {
1381  BOX2I bounds( dimension->GetStart(), dimension->GetEnd() - dimension->GetStart() );
1382 
1383  const VECTOR2I& cursorPos = m_editedPoint->GetPosition();
1384 
1385  // Find vector from nearest dimension point to edit position
1386  VECTOR2I directionA( cursorPos - dimension->GetStart() );
1387  VECTOR2I directionB( cursorPos - dimension->GetEnd() );
1388  VECTOR2I direction = ( directionA < directionB ) ? directionA : directionB;
1389 
1390  bool vert;
1391  VECTOR2D featureLine( cursorPos - dimension->GetStart() );
1392 
1393  // Only change the orientation when we move outside the bounds
1394  if( !bounds.Contains( cursorPos ) )
1395  {
1396  // If the dimension is horizontal or vertical, set correct orientation
1397  // otherwise, test if we're left/right of the bounding box or above/below it
1398  if( bounds.GetWidth() == 0 )
1399  {
1400  vert = true;
1401  }
1402  else if( bounds.GetHeight() == 0 )
1403  {
1404  vert = false;
1405  }
1406  else if( cursorPos.x > bounds.GetLeft() && cursorPos.x < bounds.GetRight() )
1407  {
1408  vert = false;
1409  }
1410  else if( cursorPos.y > bounds.GetTop() && cursorPos.y < bounds.GetBottom() )
1411  {
1412  vert = true;
1413  }
1414  else
1415  {
1416  vert = std::abs( direction.y ) < std::abs( direction.x );
1417  }
1420  }
1421  else
1422  {
1423  vert = dimension->GetOrientation() == ORTHOGONAL_DIMENSION::DIR::VERTICAL;
1424  }
1425 
1426  dimension->SetHeight( vert ? featureLine.x : featureLine.y );
1427  }
1428  else if( isModified( m_editPoints->Point( DIM_START ) ) )
1429  {
1430  dimension->SetStart( wxPoint( m_editedPoint->GetPosition().x,
1431  m_editedPoint->GetPosition().y ) );
1432  }
1433  else if( isModified( m_editPoints->Point( DIM_END ) ) )
1434  {
1435  dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x,
1436  m_editedPoint->GetPosition().y ) );
1437  }
1438  else if( isModified( m_editPoints->Point(DIM_TEXT ) ) )
1439  {
1440  // Force manual mode if we weren't already in it
1442  dimension->Text().SetPosition( wxPoint( m_editedPoint->GetPosition() ) );
1443  }
1444 
1445  dimension->Update();
1446 
1447  break;
1448  }
1449 
1450  case PCB_DIM_CENTER_T:
1451  {
1452  CENTER_DIMENSION* dimension = static_cast<CENTER_DIMENSION*>( item );
1453 
1454  if( isModified( m_editPoints->Point( DIM_START ) ) )
1455  {
1456  dimension->SetStart( wxPoint( m_editedPoint->GetPosition().x,
1457  m_editedPoint->GetPosition().y ) );
1458  }
1459  else if( isModified( m_editPoints->Point( DIM_END ) ) )
1460  {
1461  dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x,
1462  m_editedPoint->GetPosition().y ) );
1463  }
1464 
1465  dimension->Update();
1466 
1467  break;
1468  }
1469 
1470  case PCB_DIM_LEADER_T:
1471  {
1472  LEADER* dimension = static_cast<LEADER*>( item );
1473 
1474  if( isModified( m_editPoints->Point( DIM_START ) ) )
1475  {
1476  dimension->SetStart( wxPoint( m_editedPoint->GetPosition().x,
1477  m_editedPoint->GetPosition().y ) );
1478  }
1479  else if( isModified( m_editPoints->Point( DIM_END ) ) )
1480  {
1481  wxPoint newPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y );
1482  wxPoint delta = newPoint - dimension->GetEnd();
1483 
1484  dimension->SetEnd( newPoint );
1485  dimension->Text().SetPosition( dimension->Text().GetPosition() + delta );
1486  }
1487  else if( isModified( m_editPoints->Point( DIM_TEXT ) ) )
1488  {
1489  dimension->Text().SetPosition( wxPoint( m_editedPoint->GetPosition() ) );
1490  }
1491 
1492  dimension->Update();
1493 
1494  break;
1495  }
1496 
1497  default:
1498  break;
1499  }
1500 
1501  getView()->Update( item );
1502 }
1503 
1504 
1506 {
1507  auto item = m_editPoints->GetParent();
1508 
1509  if( !item )
1510  return;
1511 
1512  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
1513  {
1514  ZONE* zone = static_cast<ZONE*>( item );
1515 
1516  if( zone->IsFilled() && m_refill && zone->NeedRefill() )
1517  m_toolMgr->RunAction( PCB_ACTIONS::zoneFill, true, zone );
1518  }
1519 }
1520 
1521 
1523 {
1524  bool valid = !aPoly.IsSelfIntersecting();
1525 
1526  if( m_statusPopup )
1527  {
1528  if( valid )
1529  {
1530  m_statusPopup->Hide();
1531  }
1532  else
1533  {
1534  wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 );
1535  m_statusPopup->Move( p );
1536  m_statusPopup->PopupFor( 1500 );
1537  }
1538  }
1539 
1540  return valid;
1541 }
1542 
1543 
1545 {
1546  if( !m_editPoints )
1547  return;
1548 
1549  EDA_ITEM* item = m_editPoints->GetParent();
1550 
1551  if( !item )
1552  return;
1553 
1554  switch( item->Type() )
1555  {
1556  case PCB_SHAPE_T:
1557  case PCB_FP_SHAPE_T:
1558  {
1559  const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( item );
1560 
1561  switch( shape->GetShape() )
1562  {
1563  case S_SEGMENT:
1564  m_editPoints->Point( SEG_START ).SetPosition( shape->GetStart() );
1565  m_editPoints->Point( SEG_END ).SetPosition( shape->GetEnd() );
1566  break;
1567 
1568  case S_RECT:
1569  m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( shape->GetStart() );
1570  m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( shape->GetEnd().x,
1571  shape->GetStart().y );
1572  m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( shape->GetEnd() );
1573  m_editPoints->Point( RECT_BOT_LEFT ).SetPosition( shape->GetStart().x,
1574  shape->GetEnd().y );
1575  break;
1576 
1577  case S_ARC:
1578  m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetCenter() );
1579  m_editPoints->Point( ARC_START ).SetPosition( shape->GetArcStart() );
1580  m_editPoints->Point( ARC_MID ).SetPosition( shape->GetArcMid() );
1581  m_editPoints->Point( ARC_END ).SetPosition( shape->GetArcEnd() );
1582  break;
1583 
1584  case S_CIRCLE:
1585  m_editPoints->Point( CIRC_CENTER ).SetPosition( shape->GetCenter() );
1586  m_editPoints->Point( CIRC_END ).SetPosition( shape->GetEnd() );
1587  break;
1588 
1589  case S_POLYGON:
1590  {
1591  const auto& points = shape->BuildPolyPointsList();
1592 
1593  if( m_editPoints->PointsSize() != (unsigned) points.size() )
1594  {
1595  getView()->Remove( m_editPoints.get() );
1596  m_editedPoint = nullptr;
1597 
1598  m_editPoints = makePoints( item );
1599 
1600  if( m_editPoints )
1601  getView()->Add( m_editPoints.get() );
1602  }
1603  else
1604  {
1605  for( unsigned i = 0; i < points.size(); i++ )
1606  m_editPoints->Point( i ).SetPosition( points[i] );
1607  }
1608  break;
1609  }
1610 
1611  case S_CURVE:
1612  m_editPoints->Point( BEZIER_CURVE_START ).SetPosition( shape->GetStart() );
1613  m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).SetPosition( shape->GetBezControl1() );
1614  m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).SetPosition( shape->GetBezControl2() );
1615  m_editPoints->Point( BEZIER_CURVE_END ).SetPosition( shape->GetEnd() );
1616  break;
1617 
1618  default: // suppress warnings
1619  break;
1620  }
1621 
1622  break;
1623  }
1624 
1625  case PCB_PAD_T:
1626  {
1627  const PAD* pad = static_cast<const PAD*>( item );
1628  bool locked = pad->GetParent() && pad->IsLocked();
1629  wxPoint shapePos = pad->ShapePos();
1630  wxPoint halfSize( pad->GetSize().x / 2, pad->GetSize().y / 2 );
1631 
1632  switch( pad->GetShape() )
1633  {
1634  case PAD_SHAPE_CIRCLE:
1635  {
1636  int target = locked ? 0 : 2;
1637 
1638  // Careful; pad shape is mutable...
1639  if( int( m_editPoints->PointsSize() ) != target )
1640  {
1641  getView()->Remove( m_editPoints.get() );
1642  m_editedPoint = nullptr;
1643 
1644  m_editPoints = makePoints( item );
1645 
1646  if( m_editPoints )
1647  getView()->Add( m_editPoints.get() );
1648  }
1649  else if( target == 2 )
1650  {
1651  VECTOR2I vec = m_editPoints->Point( CIRC_END ).GetPosition()
1652  - m_editPoints->Point( CIRC_CENTER ).GetPosition();
1653  vec.Resize( halfSize.x );
1654 
1655  m_editPoints->Point( CIRC_CENTER ).SetPosition( shapePos );
1656  m_editPoints->Point( CIRC_END ).SetPosition( vec + shapePos );
1657  }
1658  }
1659  break;
1660 
1661  case PAD_SHAPE_OVAL:
1662  case PAD_SHAPE_TRAPEZOID:
1663  case PAD_SHAPE_RECT:
1664  case PAD_SHAPE_ROUNDRECT:
1666  {
1667  // Careful; pad shape and orientation are mutable...
1668  int target = locked || (int) pad->GetOrientation() % 900 > 0 ? 0 : 4;
1669 
1670  if( int( m_editPoints->PointsSize() ) != target )
1671  {
1672  getView()->Remove( m_editPoints.get() );
1673  m_editedPoint = nullptr;
1674 
1675  m_editPoints = makePoints( item );
1676 
1677  if( m_editPoints )
1678  getView()->Add( m_editPoints.get() );
1679  }
1680  else if( target == 4 )
1681  {
1682  if( pad->GetOrientation() == 900 || pad->GetOrientation() == 2700 )
1683  std::swap( halfSize.x, halfSize.y );
1684 
1685  m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( shapePos - halfSize );
1686  m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( wxPoint( shapePos.x + halfSize.x,
1687  shapePos.y - halfSize.y ) );
1688  m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( shapePos + halfSize );
1689  m_editPoints->Point( RECT_BOT_LEFT ).SetPosition( wxPoint( shapePos.x - halfSize.x,
1690  shapePos.y + halfSize.y ) );
1691  }
1692  }
1693  break;
1694 
1695  default: // suppress warnings
1696  break;
1697  }
1698  }
1699  break;
1700 
1701  case PCB_FP_ZONE_T:
1702  case PCB_ZONE_T:
1703  {
1704  ZONE* zone = static_cast<ZONE*>( item );
1705  const SHAPE_POLY_SET* outline = zone->Outline();
1706 
1707  if( m_editPoints->PointsSize() != (unsigned) outline->TotalVertices() )
1708  {
1709  getView()->Remove( m_editPoints.get() );
1710  m_editedPoint = nullptr;
1711 
1712  m_editPoints = makePoints( item );
1713 
1714  if( m_editPoints )
1715  getView()->Add( m_editPoints.get() );
1716  }
1717  else
1718  {
1719  for( int i = 0; i < outline->TotalVertices(); ++i )
1720  m_editPoints->Point( i ).SetPosition( outline->CVertex( i ) );
1721  }
1722 
1723  break;
1724  }
1725 
1726  case PCB_DIM_ALIGNED_T:
1727  case PCB_DIM_ORTHOGONAL_T:
1728  {
1729  const ALIGNED_DIMENSION* dimension = static_cast<const ALIGNED_DIMENSION*>( item );
1730 
1731  m_editPoints->Point( DIM_START ).SetPosition( dimension->GetStart() );
1732  m_editPoints->Point( DIM_END ).SetPosition( dimension->GetEnd() );
1733  m_editPoints->Point( DIM_TEXT ).SetPosition( dimension->Text().GetPosition() );
1734  m_editPoints->Point( DIM_CROSSBARSTART ).SetPosition( dimension->GetCrossbarStart() );
1735  m_editPoints->Point( DIM_CROSSBAREND ).SetPosition( dimension->GetCrossbarEnd() );
1736  break;
1737  }
1738 
1739  case PCB_DIM_CENTER_T:
1740  {
1741  const CENTER_DIMENSION* dimension = static_cast<const CENTER_DIMENSION*>( item );
1742 
1743  m_editPoints->Point( DIM_START ).SetPosition( dimension->GetStart() );
1744  m_editPoints->Point( DIM_END ).SetPosition( dimension->GetEnd() );
1745  break;
1746  }
1747 
1748  case PCB_DIM_LEADER_T:
1749  {
1750  const LEADER* dimension = static_cast<const LEADER*>( item );
1751 
1752  m_editPoints->Point( DIM_START ).SetPosition( dimension->GetStart() );
1753  m_editPoints->Point( DIM_END ).SetPosition( dimension->GetEnd() );
1754  m_editPoints->Point( DIM_TEXT ).SetPosition( dimension->Text().GetPosition() );
1755  break;
1756  }
1757 
1758  default:
1759  break;
1760  }
1761 
1762  getView()->Update( m_editPoints.get() );
1763 }
1764 
1765 
1767 {
1769 
1770  if( aPoint )
1771  {
1773  controls->ForceCursorPosition( true, aPoint->GetPosition() );
1774  controls->ShowCursor( true );
1775  }
1776  else
1777  {
1778  if( frame()->ToolStackIsEmpty() )
1779  controls->ShowCursor( false );
1780 
1781  controls->ForceCursorPosition( false );
1782  }
1783 
1784  m_editedPoint = aPoint;
1785 }
1786 
1787 
1789 {
1790  if( aEnabled )
1791  {
1792  EDIT_LINE* line = dynamic_cast<EDIT_LINE*>( m_editedPoint );
1793  bool isPoly = false;
1794 
1795  if( m_editPoints->GetParent()->Type() == PCB_ZONE_T
1796  || m_editPoints->GetParent()->Type() == PCB_FP_ZONE_T )
1797  {
1798  isPoly = true;
1799  }
1800 
1801  else if( m_editPoints->GetParent()->Type() == PCB_SHAPE_T
1802  || m_editPoints->GetParent()->Type() == PCB_FP_SHAPE_T )
1803  {
1804  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( m_editPoints->GetParent() );
1805  isPoly = shape->GetShape() == S_POLYGON;
1806  }
1807 
1808  if( line && isPoly )
1809  {
1810  EC_CONVERGING* altConstraint = new EC_CONVERGING( *line, *m_editPoints );
1811  m_altConstraint.reset( (EDIT_CONSTRAINT<EDIT_POINT>*) altConstraint );
1812  }
1813  else
1814  {
1815  // Find a proper constraining point for 45 degrees mode
1818  }
1819  }
1820  else
1821  {
1822  m_altConstraint.reset();
1823  }
1824 }
1825 
1826 
1828 {
1829  EDA_ITEM* item = m_editPoints->GetParent();
1830 
1831  switch( item->Type() )
1832  {
1833  case PCB_SHAPE_T:
1834  case PCB_FP_SHAPE_T:
1835  switch( static_cast<const PCB_SHAPE*>( item )->GetShape() )
1836  {
1837  case S_SEGMENT:
1838  return *( m_editPoints->Next( *m_editedPoint ) ); // select the other end of line
1839 
1840  case S_ARC:
1841  case S_CIRCLE:
1842  return m_editPoints->Point( CIRC_CENTER );
1843 
1844  default: // suppress warnings
1845  break;
1846  }
1847 
1848  break;
1849 
1850  case PCB_DIM_ALIGNED_T:
1851  {
1852  // Constraint for crossbar
1853  if( isModified( m_editPoints->Point( DIM_START ) ) )
1854  return m_editPoints->Point( DIM_END );
1855 
1856  else if( isModified( m_editPoints->Point( DIM_END ) ) )
1857  return m_editPoints->Point( DIM_START );
1858 
1859  else
1860  return EDIT_POINT( m_editedPoint->GetPosition() ); // no constraint
1861 
1862  break;
1863  }
1864 
1865  case PCB_DIM_CENTER_T:
1866  {
1867  if( isModified( m_editPoints->Point( DIM_END ) ) )
1868  return m_editPoints->Point( DIM_START );
1869 
1870  break;
1871  }
1872 
1873  default:
1874  break;
1875  }
1876 
1877  // In any other case we may align item to its original position
1878  return m_original;
1879 }
1880 
1881 
1883 {
1884  const auto type = aItem.Type();
1885 
1886  // Works only for zones and line segments
1887  if( type == PCB_ZONE_T || type == PCB_FP_ZONE_T )
1888  return true;
1889 
1890  if( type == PCB_SHAPE_T || type == PCB_FP_SHAPE_T )
1891  {
1892  const PCB_SHAPE& shape = static_cast<const PCB_SHAPE&>( aItem );
1893  return shape.GetShape() == S_SEGMENT || shape.GetShape() == S_POLYGON;
1894  }
1895 
1896  return false;
1897 }
1898 
1899 
1901 {
1902  if( aSelection.Size() != 1 )
1903  return false;
1904 
1905  const EDA_ITEM* item = aSelection.Front();
1906 
1907  return ( item != nullptr ) && canAddCorner( *item );
1908 }
1909 
1910 
1911 // Finds a corresponding vertex in a polygon set
1912 static std::pair<bool, SHAPE_POLY_SET::VERTEX_INDEX>
1913 findVertex( SHAPE_POLY_SET& aPolySet, const EDIT_POINT& aPoint )
1914 {
1915  for( auto it = aPolySet.IterateWithHoles(); it; ++it )
1916  {
1917  auto vertexIdx = it.GetIndex();
1918 
1919  if( aPolySet.CVertex( vertexIdx ) == aPoint.GetPosition() )
1920  return std::make_pair( true, vertexIdx );
1921  }
1922 
1923  return std::make_pair( false, SHAPE_POLY_SET::VERTEX_INDEX() );
1924 }
1925 
1926 
1928 {
1929  if( !m_editPoints || !m_editedPoint )
1930  return false;
1931 
1932  EDA_ITEM* item = m_editPoints->GetParent();
1933 
1934  if( !item )
1935  return false;
1936 
1937  if( !( item->Type() == PCB_ZONE_T
1938  || item->Type() == PCB_FP_ZONE_T
1939  || ( ( item->Type() == PCB_FP_SHAPE_T || item->Type() == PCB_SHAPE_T )
1940  && static_cast<PCB_SHAPE*>( item )->GetShape() == S_POLYGON ) ) )
1941  {
1942  return false;
1943  }
1944 
1945  SHAPE_POLY_SET *polyset;
1946 
1947  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
1948  polyset = static_cast<ZONE*>( item )->Outline();
1949  else
1950  polyset = &static_cast<PCB_SHAPE*>( item )->GetPolyShape();
1951 
1952  auto vertex = findVertex( *polyset, *m_editedPoint );
1953 
1954  if( !vertex.first )
1955  return false;
1956 
1957  const auto& vertexIdx = vertex.second;
1958 
1959  // Check if there are enough vertices so one can be removed without
1960  // degenerating the polygon.
1961  // The first condition allows one to remove all corners from holes (when
1962  // there are only 2 vertices left, a hole is removed).
1963  if( vertexIdx.m_contour == 0 && polyset->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour].PointCount() <= 3 )
1964  return false;
1965 
1966  // Remove corner does not work with lines
1967  if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
1968  return false;
1969 
1970  return m_editedPoint != NULL;
1971 }
1972 
1973 
1975 {
1976  if( !m_editPoints )
1977  return 0;
1978 
1979  EDA_ITEM* item = m_editPoints->GetParent();
1980  PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1981  const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
1982 
1983  // called without an active edited polygon
1984  if( !item || !canAddCorner( *item ) )
1985  return 0;
1986 
1987  PCB_SHAPE* graphicItem = dynamic_cast<PCB_SHAPE*>( item );
1988  BOARD_COMMIT commit( frame );
1989 
1990  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T
1991  || ( graphicItem && graphicItem->GetShape() == S_POLYGON ) )
1992  {
1993  unsigned int nearestIdx = 0;
1994  unsigned int nextNearestIdx = 0;
1995  unsigned int nearestDist = INT_MAX;
1996  unsigned int firstPointInContour = 0;
1997  SHAPE_POLY_SET* zoneOutline;
1998 
1999  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2000  {
2001  ZONE* zone = static_cast<ZONE*>( item );
2002  zoneOutline = zone->Outline();
2003  zone->SetNeedRefill( true );
2004  }
2005  else
2006  zoneOutline = &( graphicItem->GetPolyShape() );
2007 
2008  commit.Modify( item );
2009 
2010  // Search the best outline segment to add a new corner
2011  // and therefore break this segment into two segments
2012 
2013  // Object to iterate through the corners of the outlines (main contour and its holes)
2014  SHAPE_POLY_SET::ITERATOR iterator = zoneOutline->Iterate( 0, zoneOutline->OutlineCount()-1,
2015  /* IterateHoles */ true );
2016  int curr_idx = 0;
2017 
2018  // Iterate through all the corners of the outlines and search the best segment
2019  for( ; iterator; iterator++, curr_idx++ )
2020  {
2021  int jj = curr_idx+1;
2022 
2023  if( iterator.IsEndContour() )
2024  { // We reach the last point of the current contour (main or hole)
2025  jj = firstPointInContour;
2026  firstPointInContour = curr_idx+1; // Prepare next contour analysis
2027  }
2028 
2029  SEG curr_segment( zoneOutline->CVertex( curr_idx ), zoneOutline->CVertex( jj ) );
2030 
2031  unsigned int distance = curr_segment.Distance( cursorPos );
2032 
2033  if( distance < nearestDist )
2034  {
2035  nearestDist = distance;
2036  nearestIdx = curr_idx;
2037  nextNearestIdx = jj;
2038  }
2039  }
2040 
2041  // Find the point on the closest segment
2042  auto& sideOrigin = zoneOutline->CVertex( nearestIdx );
2043  auto& sideEnd = zoneOutline->CVertex( nextNearestIdx );
2044  SEG nearestSide( sideOrigin, sideEnd );
2045  VECTOR2I nearestPoint = nearestSide.NearestPoint( cursorPos );
2046 
2047  // Do not add points that have the same coordinates as ones that already belong to polygon
2048  // instead, add a point in the middle of the side
2049  if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
2050  nearestPoint = ( sideOrigin + sideEnd ) / 2;
2051 
2052  zoneOutline->InsertVertex( nextNearestIdx, nearestPoint );
2053 
2054  // We re-hatch the filled zones but not polygons
2055  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2056  static_cast<ZONE*>( item )->HatchBorder();
2057 
2058 
2059  commit.Push( _( "Add a zone corner" ) );
2060  }
2061 
2062  else if( graphicItem && graphicItem->GetShape() == S_SEGMENT )
2063  {
2064  commit.Modify( graphicItem );
2065 
2066  SEG seg( graphicItem->GetStart(), graphicItem->GetEnd() );
2067  VECTOR2I nearestPoint = seg.NearestPoint( cursorPos );
2068 
2069  // Move the end of the line to the break point..
2070  graphicItem->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) );
2071 
2072  if( graphicItem->Type() == PCB_FP_SHAPE_T )
2073  static_cast<FP_SHAPE*>( graphicItem )->SetLocalCoord();
2074 
2075  // and add another one starting from the break point
2076  PCB_SHAPE* newSegment;
2077 
2078  if( item->Type() == PCB_FP_SHAPE_T )
2079  {
2080  FP_SHAPE* edge = static_cast<FP_SHAPE*>( graphicItem );
2081  assert( edge->GetParent()->Type() == PCB_FOOTPRINT_T );
2082  newSegment = new FP_SHAPE( *edge );
2083  }
2084  else
2085  {
2086  newSegment = new PCB_SHAPE( *graphicItem );
2087  }
2088 
2089  newSegment->ClearSelected();
2090  newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) );
2091  newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) );
2092 
2093  if( newSegment->Type() == PCB_FP_SHAPE_T )
2094  static_cast<FP_SHAPE*>( newSegment )->SetLocalCoord();
2095 
2096  commit.Add( newSegment );
2097  commit.Push( _( "Split segment" ) );
2098  }
2099 
2100  updatePoints();
2101  return 0;
2102 }
2103 
2104 
2106 {
2107  if( !m_editPoints || !m_editedPoint )
2108  return 0;
2109 
2110  EDA_ITEM* item = m_editPoints->GetParent();
2111 
2112  if( !item )
2113  return 0;
2114 
2115  SHAPE_POLY_SET* polygon = nullptr;
2116 
2117  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2118  {
2119  ZONE* zone = static_cast<ZONE*>( item );
2120  polygon = zone->Outline();
2121  zone->SetNeedRefill( true );
2122  }
2123  else if( item->Type() == PCB_FP_SHAPE_T || item->Type() == PCB_SHAPE_T )
2124  {
2125  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2126 
2127  if( shape->GetShape() == S_POLYGON )
2128  polygon = &shape->GetPolyShape();
2129  }
2130 
2131  if( !polygon )
2132  return 0;
2133 
2134  PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
2135  BOARD_COMMIT commit( frame );
2136  auto vertex = findVertex( *polygon, *m_editedPoint );
2137 
2138  if( vertex.first )
2139  {
2140  const auto& vertexIdx = vertex.second;
2141  auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
2142 
2143  if( outline.PointCount() > 3 )
2144  {
2145  // the usual case: remove just the corner when there are >3 vertices
2146  commit.Modify( item );
2147  polygon->RemoveVertex( vertexIdx );
2148  validatePolygon( *polygon );
2149  }
2150  else
2151  {
2152  // either remove a hole or the polygon when there are <= 3 corners
2153  if( vertexIdx.m_contour > 0 )
2154  {
2155  // remove hole
2156  commit.Modify( item );
2157  polygon->RemoveContour( vertexIdx.m_contour );
2158  }
2159  else
2160  {
2162  commit.Remove( item );
2163  }
2164  }
2165 
2166  setEditedPoint( nullptr );
2167 
2168  commit.Push( _( "Remove a zone/polygon corner" ) );
2169 
2170  // Refresh zone hatching
2171  if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2172  static_cast<ZONE*>( item )->HatchBorder();
2173 
2174  updatePoints();
2175  }
2176 
2177  return 0;
2178 }
2179 
2180 
2182 {
2183  updatePoints();
2184  return 0;
2185 }
2186 
2188 {
2190  return 0;
2191 }
2192 
2194 {
2204 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:148
bool NeedRefill() const
Definition: zone.h:240
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:63
int removeCorner(const TOOL_EVENT &aEvent)
int TotalVertices() const
Delete aIdx-th polygon from the set.
void SetStartX(int x)
Definition: pcb_shape.h:150
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
EDIT_CONSTRAINT for 3 segments: dragged and two adjacent ones, enforcing to keep their slopes and all...
wxPoint GetArcEnd() const
Definition: pcb_shape.cpp:373
void SetOffset(const wxPoint &aOffset)
Definition: pad.h:248
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
static const TOOL_EVENT SelectedEvent
Definition: actions.h:209
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:100
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void setTransitions() override
< Set up handlers for various events.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
EDIT_POINT get45DegConstrainer() const
Condition to display "Create corner" context menu entry.
static TOOL_ACTION activatePointEditor
Definition: actions.h:171
virtual void SetStart(const wxPoint &aPoint)
Definition: dimension.h:122
void updatePoints()
Update which point is being edited.
SHAPE_POLY_SET & GetPolyShape()
Definition: pcb_shape.h:268
virtual void SetPosition(const wxPoint &aPos) override
Definition: pcb_text.h:77
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:210
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Definition: pcb_shape.h:156
void updateEditedPoint(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
void SetBezControl2(const wxPoint &aPoint)
Definition: pcb_shape.h:135
int addCorner(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
This file is part of the common library.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
void ClearSelected()
Definition: eda_item.h:181
bool removeCornerCondition(const SELECTION &aSelection)
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
void buildForPolyOutline(std::shared_ptr< EDIT_POINTS > points, const SHAPE_POLY_SET *aOutline)
void setEditedPoint(EDIT_POINT *aPoint)
constexpr KICAD_T BaseType(const KICAD_T aType)
Returns the underlying type of the given type.
Definition: typeinfo.h:235
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
class CENTER_DIMENSION, a center point marking (graphic item)
Definition: typeinfo.h:102
SHAPE_POLY_SET * Outline()
Definition: zone.h:323
static TOOL_ACTION changeEditMethod
Definition: actions.h:172
virtual void Revert() override
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
Represent a line connecting two EDIT_POINTs.
Definition: edit_points.h:215
int GetWidth() const
Definition: pcb_shape.h:118
static void pinEditedCorner(int aEditedPointIndex, int aMinWidth, int aMinHeight, VECTOR2I &aTopLeft, VECTOR2I &aTopRight, VECTOR2I &aBotLeft, VECTOR2I &aBotRight, VECTOR2I aHole, VECTOR2I aHoleSize)
Update the coordinates of 4 corners of a rectangle, according to pad constraints and the moved corner...
virtual const wxPoint & GetStart() const
The dimension's origin is the first feature point for the dimension.
Definition: dimension.h:121
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:351
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:54
EDIT_CONSTRAINT for a EDIT_LINE, that constrains the line to move perpendicular to the line itself.
bool IsLocked() const override
Definition: pcbnew/pad.cpp:138
CONST_ITERATOR CIterateWithHoles(int aOutline) const
TOOL_MENU & GetToolMenu()
bool IsMotion() const
Definition: tool_event.h:316
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:141
double RAD2DECIDEG(double rad)
Definition: trigo.h:236
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
usual segment : line with rounded ends
Definition: board_item.h:50
double m_DrawArcCenterMaxAngle
When drawing an arc, the angle ( center - start ) - ( start - end ) can be limited to avoid extremely...
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:189
Arcs (with rounded ends)
Definition: board_item.h:52
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
PAD_SHAPE_T GetShape() const
Definition: pad.h:169
static std::pair< bool, SHAPE_POLY_SET::VERTEX_INDEX > findVertex(SHAPE_POLY_SET &aPolySet, const EDIT_POINT &aPoint)
bool IsFilled() const
Definition: zone.h:237
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
void SetSize(const wxSize &aSize)
Definition: pad.h:231
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Return an object to iterate through the points of the polygons between aFirst and aLast.
void Update()
Updates the dimension's cached text and geometry.
Definition: dimension.h:146
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
segment with non rounded ends
Definition: board_item.h:51
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
const wxPoint & GetCrossbarStart() const
Definition: dimension.h:363
std::shared_ptr< EDIT_POINTS > m_editPoints
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
static TOOL_ACTION zoneFill
Definition: pcb_actions.h:306
void editArcEndpointKeepCenter(PCB_SHAPE *aArc, VECTOR2I aCenter, VECTOR2I aStart, VECTOR2I aMid, VECTOR2I aEnd, const VECTOR2I aCursor) const
Move an end point of the arc around the circumference.
GRID_CONSTRAINT_TYPE GetGridConstraint() const
Definition: edit_points.h:177
EDIT_CONSTRAINT that imposes a constraint that a point has to lie on a line (determined by 2 points).
void SetCurrentCursor(KICURSOR cursor)
Set the current cursor shape for this panel.
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
EDIT_CONSTRAINT that imposes a constraint that two points have to be located at angle of 45 degree mu...
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:214
int modifiedSelection(const TOOL_EVENT &aEvent)
const wxPoint & GetCrossbarEnd() const
Definition: dimension.h:365
wxPoint GetArcStart() const
Definition: pcb_shape.h:179
EDIT_POINT * m_editedPoint
EDIT_POINT m_altConstrainer
std::shared_ptr< EDIT_POINTS > makePoints(EDA_ITEM *aItem)
Update item's points with edit points.
PCB_BASE_EDIT_FRAME * frame() const
int getEditedPointIndex() const
Return true if aPoint is the currently modified point.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
static bool canAddCorner(const EDA_ITEM &aItem)
Condition to display "Remove corner" context menu entry.
void SetArcGeometry(const wxPoint &aStart, const wxPoint &aMid, const wxPoint &aEnd)
Set the three controlling points for an arc.
Definition: pcb_shape.cpp:442
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
virtual void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:112
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...
Definition: pcb_shape.cpp:1206
const wxPoint & GetOffset() const
Definition: pad.h:249
bool GetGridSnapping() const
void SetActive(bool aActive=true)
Definition: edit_points.h:172
const wxSize & GetDrillSize() const
Definition: pad.h:242
wxPoint ShapePos() const
Definition: pcbnew/pad.cpp:657
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:306
void SetHeight(int aHeight)
Sets the distance from the feature points to the crossbar line.
Definition: dimension.h:371
LSET is a set of PCB_LAYER_IDs.
const PCB_SELECTION & selection() const
void SetEndY(int y)
Definition: pcb_shape.h:160
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:70
#define NULL
double GetOrientation() const
Return the rotation angle of the pad in a variety of units (the basic call returns tenths of degrees)...
Definition: pad.h:341
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
int OnSelectionChange(const TOOL_EVENT &aEvent)
Change selection event handler.
virtual wxPoint GetPosition() const override
Definition: pcb_text.h:72
DIMENSION_POINTS
A leader is a dimension-like object pointing to a specific point.
Definition: dimension.h:477
PCB_SELECTION_TOOL * m_selectionTool
STATUS_FLAGS GetEditFlags() const
Definition: eda_item.h:207
void HatchBorder()
Function HatchBorder computes the hatch lines depending on the hatch parameters and stores it in the ...
Definition: zone.cpp:923
ITERATOR IterateWithHoles(int aOutline)
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
SEG_POINTS
static TOOL_ACTION pointEditorAddCorner
Break outline (insert additional points to an edge)
Definition: pcb_actions.h:213
static TOOL_ACTION pointEditorRemoveCorner
Removes a corner.
Definition: pcb_actions.h:216
void setAltConstraint(bool aEnabled)
Return a point that should be used as a constrainer for 45 degrees mode.
const wxSize & GetSize() const
Definition: pad.h:232
PCB_TEXT & Text()
Definition: dimension.h:209
Generic, UI-independent tool event.
Definition: tool_event.h:173
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.cpp:341
int changeEditMethod(const TOOL_EVENT &aEvent)
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Definition: pcb_shape.h:145
DIR GetOrientation() const
Definition: dimension.h:448
COMMIT & StageItems(const Range &aRange, CHANGE_TYPE aChangeType)
Add a change of the item aItem of type aChangeType to the change list.
Definition: commit.h:117
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
Definition: dimension.h:414
KIGFX::PCB_VIEW * view() const
static const TOOL_EVENT UninhibitSelectionEditing
Definition: actions.h:221
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.h:422
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void SetEnd(const wxPoint &aPoint)
Definition: dimension.h:125
Text placement is manually set by the user.
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:290
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
static LSET AllLayersMask()
Definition: lset.cpp:787
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
class ZONE, a copper pour area
Definition: typeinfo.h:105
COMMIT & Remove(EDA_ITEM *aItem)
Notify observers that aItem has been removed.
Definition: commit.h:90
std::shared_ptr< EDIT_CONSTRAINT< EDIT_POINT > > m_altConstraint
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:373
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
Definition: pcb_shape.h:229
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
void SetBezControl1(const wxPoint &aPoint)
Definition: pcb_shape.h:132
class DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:99
bool m_isFootprintEditor
void SetOrientation(DIR aOrientation)
Sets the orientation of the dimension line (so, perpendicular to the feature lines)
Definition: dimension.h:447
void SetEndX(int x)
Definition: pcb_shape.h:161
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
void ClearFilledPolysList()
Function ClearFilledPolysList clears the list of filled polygons.
Definition: zone.h:636
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
FOOTPRINT * GetParent() const
Definition: seg.h:41
EDIT_POINT m_original
Original position for the current drag point.
void editArcMidKeepEndpoints(PCB_SHAPE *aArc, VECTOR2I aStart, VECTOR2I aEnd, const VECTOR2I aCursor) const
Move the mid point of the arc, while keeping the two endpoints.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:404
void editArcMidKeepCenter(PCB_SHAPE *aArc, VECTOR2I aCenter, VECTOR2I aStart, VECTOR2I aMid, VECTOR2I aEnd, const VECTOR2I aCursor) const
Move the mid point of the arc, while keeping the angle.
ARC_POINTS
bool Init() override
Init() is called once upon a registration of the tool.
KIGFX::VIEW_CONTROLS * controls() const
Common, abstract interface for edit frames.
RECT_POINTS
wxPoint GetPosition() const override
Definition: pad.h:177
void SetStart(const wxPoint &aStart)
Definition: pcb_shape.h:148
#define _(s)
Definition: 3d_actions.cpp:33
const wxPoint & GetBezControl2() const
Definition: pcb_shape.h:136
void RemoveVertex(int aGlobalIndex)
Delete the aGlobalIndex-th vertex.
CIRCLE_POINTS
Base class for iterating over all vertices in a given SHAPE_POLY_SET.
void SetPosition(const wxPoint &aPos) override
Definition: pad.h:171
void editArcEndpointKeepTangent(PCB_SHAPE *aArc, VECTOR2I aCenter, VECTOR2I aStart, VECTOR2I aMid, VECTOR2I aEnd, const VECTOR2I aCursor) const
Move an end point of the arc, while keeping the tangent at the other endpoint.
class ZONE, managed by a footprint
Definition: typeinfo.h:94
void SetHover(bool aHover=true)
Definition: edit_points.h:175
double GetAngle() const
Definition: pcb_shape.h:127
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
The selection tool: currently supports:
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
static const TOOL_EVENT InhibitSelectionEditing
Definition: actions.h:220
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
Definition: pcb_shape.cpp:315
void SetArcEnd(const wxPoint &aArcEndPoint)
Initialize the end arc point.
Definition: pcb_shape.h:222
bool isModified(const EDIT_POINT &aPoint) const
Set up an alternative constraint (typically enabled upon a modifier key being pressed).
ring
Definition: board_item.h:53
void Activate()
Run the tool.
void InsertVertex(int aGlobalIndex, VECTOR2I aNewVertex)
Adds a vertex in the globally indexed position aGlobalIndex.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
static bool addCornerCondition(const SELECTION &aSelection)
Determine if the tool can currently add a corner to the given item.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetStartY(int y)
Definition: pcb_shape.h:149
EDIT_POINT * m_hoveredPoint
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:103
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
wxPoint GetArcMid() const
Definition: pcb_shape.cpp:391
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:321
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:241
Represent a single point that can be used for modifying items.
Definition: edit_points.h:47
BEZIER_CURVE_POINTS
PCB_SHAPE_TYPE_T GetShape() const
Definition: pcb_shape.h:130
POLYGON & Polygon(int aIndex)
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
RECT_LINES
Definition: pad.h:60
For better understanding of the points that make a dimension:
Definition: dimension.h:334
bool validatePolygon(SHAPE_POLY_SET &aModified) const
Validate a polygon and displays a popup warning if invalid.
void SetTextPositionMode(DIM_TEXT_POSITION aMode)
Definition: dimension.h:178
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:465
void updateItem() const
Apply the last changes to the edited item.
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
Bezier Curve.
Definition: board_item.h:55
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
virtual const wxPoint & GetEnd() const
Definition: dimension.h:124
const wxPoint & GetBezControl1() const
Definition: pcb_shape.h:133
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:284
virtual void ApplyConstraint()
Correct coordinates of an EDIT_POINT by applying previously set constraint.
Definition: edit_points.h:165
void SetEnd(const wxPoint &aEnd)
Definition: pcb_shape.h:159
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:203
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1508
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
Definition: pcb_shape.h:213
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
virtual void UpdateMsgPanel()
Redraw the message panel.
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
void RemoveContour(int aContourIdx, int aPolygonIdx=-1)
Delete the aContourIdx-th contour of the aPolygonIdx-th polygon in the set.
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:106
Marks the center of a circle or arc with a cross shape The size and orientation of the cross is adjus...
Definition: dimension.h:516