KiCad PCB EDA Suite
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-2017 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 using namespace std::placeholders;
27 
28 #include <tool/tool_manager.h>
29 #include <view/view_controls.h>
31 #include <geometry/seg.h>
32 #include <confirm.h>
33 
34 #include "pcb_actions.h"
35 #include "selection_tool.h"
36 #include "point_editor.h"
37 #include <board_commit.h>
38 #include <bitmaps.h>
39 
40 #include <wxPcbStruct.h>
41 #include <class_edge_mod.h>
42 #include <class_dimension.h>
43 #include <class_zone.h>
44 #include <class_board.h>
45 #include <class_module.h>
46 #include <ratsnest_data.h>
47 
48 // Point editor
49 TOOL_ACTION PCB_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner",
50  AS_GLOBAL, 0,
51  _( "Create Corner" ), _( "Create a corner" ), add_corner_xpm );
52 
53 TOOL_ACTION PCB_ACTIONS::pointEditorRemoveCorner( "pcbnew.PointEditor.removeCorner",
54  AS_GLOBAL, 0,
55  _( "Remove Corner" ), _( "Remove corner" ), delete_xpm );
56 
57 
58 // Few constants to avoid using bare numbers for point indices
60 {
62 };
63 
65 {
67 };
68 
70 {
72 };
73 
75 {
80 };
81 
82 
84 {
85 public:
86  static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, KIGFX::GAL* aGal )
87  {
88  std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
89 
90  // Generate list of edit points basing on the item type
91  switch( aItem->Type() )
92  {
93  case PCB_LINE_T:
94  case PCB_MODULE_EDGE_T:
95  {
96  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( aItem );
97 
98  switch( segment->GetShape() )
99  {
100  case S_SEGMENT:
101  points->AddPoint( segment->GetStart() );
102  points->AddPoint( segment->GetEnd() );
103  break;
104 
105  case S_ARC:
106  points->AddPoint( segment->GetCenter() );
107  points->AddPoint( segment->GetArcStart() );
108  points->AddPoint( segment->GetArcEnd() );
109 
110  // Set constraints
111  // Arc end has to stay at the same radius as the start
112  points->Point( ARC_END ).SetConstraint( new EC_CIRCLE( points->Point( ARC_END ),
113  points->Point( ARC_CENTER ),
114  points->Point( ARC_START ) ) );
115  break;
116 
117  case S_CIRCLE:
118  points->AddPoint( segment->GetCenter() );
119  points->AddPoint( segment->GetEnd() );
120  break;
121 
122  default: // suppress warnings
123  break;
124  }
125 
126  break;
127  }
128 
129  case PCB_ZONE_AREA_T:
130  {
131  const SHAPE_POLY_SET* outline;
132  outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
133 
134  int cornersCount = outline->TotalVertices();
135 
136  for( auto iterator = outline->CIterateWithHoles(); iterator; iterator++ )
137  {
138  points->AddPoint( *iterator );
139 
140  if( iterator.IsEndContour() )
141  points->AddBreak();
142  }
143 
144  // Lines have to be added after creating edit points,
145  // as they use EDIT_POINT references
146  for( int i = 0; i < cornersCount - 1; ++i )
147  {
148  if( points->IsContourEnd( i ) )
149  {
150  points->AddLine( points->Point( i ),
151  points->Point( points->GetContourStartIdx( i ) ) );
152  }
153  else
154  {
155  points->AddLine( points->Point( i ), points->Point( i + 1 ) );
156  }
157 
158  points->Line( i ).SetConstraint( new EC_SNAPLINE( points->Line( i ),
159  std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
160  }
161 
162  // The last missing line, connecting the last and the first polygon point
163  points->AddLine( points->Point( cornersCount - 1 ),
164  points->Point( points->GetContourStartIdx( cornersCount - 1 ) ) );
165 
166  points->Line( points->LinesSize() - 1 ).SetConstraint(
167  new EC_SNAPLINE( points->Line( points->LinesSize() - 1 ),
168  std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
169  break;
170  }
171 
172  case PCB_DIMENSION_T:
173  {
174  const DIMENSION* dimension = static_cast<const DIMENSION*>( aItem );
175 
176  points->AddPoint( dimension->m_crossBarO );
177  points->AddPoint( dimension->m_crossBarF );
178  points->AddPoint( dimension->m_featureLineGO );
179  points->AddPoint( dimension->m_featureLineDO );
180 
181  // Dimension height setting - edit points should move only along the feature lines
182  points->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARO ),
183  points->Point( DIM_FEATUREGO ) ) );
184  points->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARF ),
185  points->Point( DIM_FEATUREDO ) ) );
186 
187  break;
188  }
189 
190  default:
191  points.reset();
192  break;
193  }
194 
195  return points;
196  }
197 
198 private:
200 };
201 
202 
204  TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL ), m_editedPoint( NULL ),
205  m_original( VECTOR2I( 0, 0 ) ), m_altConstrainer( VECTOR2I( 0, 0 ) )
206 {
207 }
208 
209 
211 {
212  m_editPoints.reset();
213  m_altConstraint.reset();
214 }
215 
216 
218 {
219  // Find the selection tool, so they can cooperate
220  m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) );
221 
222  if( !m_selectionTool )
223  {
224  DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
225  return false;
226  }
227 
228  auto& menu = m_selectionTool->GetToolMenu().GetMenu();
231  std::bind( &POINT_EDITOR::removeCornerCondition, this, _1 ) );
232 
233  return true;
234 }
235 
236 
238 {
239  EDIT_POINT* point = m_editedPoint;
240 
241  if( aEvent.IsMotion() )
242  {
243  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
244  }
245  else if( aEvent.IsDrag( BUT_LEFT ) )
246  {
247  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
248  }
249 
250  if( m_editedPoint != point )
251  setEditedPoint( point );
252 }
253 
254 
256 {
257  const SELECTION& selection = m_selectionTool->GetSelection();
258 
259  if( selection.Size() != 1 )
260  return 0;
261 
262  Activate();
263 
265  KIGFX::VIEW* view = getView();
266  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
267  auto item = selection.Front();
268 
269  m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
270 
271  if( !m_editPoints )
272  return 0;
273 
274  view->Add( m_editPoints.get() );
275  m_editedPoint = NULL;
276  bool modified = false;
277 
278  BOARD_COMMIT commit( editFrame );
279 
280  // Main loop: keep receiving events
281  while( OPT_TOOL_EVENT evt = Wait() )
282  {
283  if( !m_editPoints ||
284  evt->Matches( m_selectionTool->ClearedEvent ) ||
285  evt->Matches( m_selectionTool->UnselectedEvent ) ||
286  evt->Matches( m_selectionTool->SelectedEvent ) )
287  {
288  break;
289  }
290 
291  if ( !modified )
292  updateEditedPoint( *evt );
293 
294  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
295  {
296  if( !modified )
297  {
298  commit.StageItems( selection, CHT_MODIFY );
299 
300  controls->ForceCursorPosition( false );
301  m_original = *m_editedPoint; // Save the original position
302  controls->SetAutoPan( true );
303  modified = true;
304  }
305 
306  bool enableAltConstraint = !!evt->Modifier( MD_CTRL );
307 
308  if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint
309  setAltConstraint( enableAltConstraint );
310 
312 
313  if( m_altConstraint )
314  m_altConstraint->Apply();
315  else
317 
318  updateItem();
319  updatePoints();
320  }
321 
322  else if( evt->IsMouseUp( BUT_LEFT ) )
323  {
324  controls->SetAutoPan( false );
325  setAltConstraint( false );
326 
327  if( modified )
328  {
329  commit.Push( _( "Drag a line ending" ) );
330  modified = false;
331  }
332 
333  m_toolMgr->PassEvent();
334  }
335 
336  else if( evt->IsCancel() )
337  {
338  if( modified ) // Restore the last change
339  {
340  commit.Revert();
341  updatePoints();
342  modified = false;
343  }
344 
345  // Let the selection tool receive the event too
346  m_toolMgr->PassEvent();
347 
348  break;
349  }
350 
351  else
352  {
353  m_toolMgr->PassEvent();
354  }
355  }
356 
357  if( m_editPoints )
358  {
359  finishItem();
360  view->Remove( m_editPoints.get() );
361  m_editPoints.reset();
362  }
363 
364  return 0;
365 }
366 
367 
369 {
370  EDA_ITEM* item = m_editPoints->GetParent();
371 
372  switch( item->Type() )
373  {
374  case PCB_LINE_T:
375  case PCB_MODULE_EDGE_T:
376  {
377  DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
378  switch( segment->GetShape() )
379  {
380  case S_SEGMENT:
381  if( isModified( m_editPoints->Point( SEG_START ) ) )
382  segment->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x,
383  m_editPoints->Point( SEG_START ).GetPosition().y ) );
384 
385  else if( isModified( m_editPoints->Point( SEG_END ) ) )
386  segment->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x,
387  m_editPoints->Point( SEG_END ).GetPosition().y ) );
388 
389  break;
390 
391  case S_ARC:
392  {
393  const VECTOR2I& center = m_editPoints->Point( ARC_CENTER ).GetPosition();
394  const VECTOR2I& start = m_editPoints->Point( ARC_START ).GetPosition();
395  const VECTOR2I& end = m_editPoints->Point( ARC_END ).GetPosition();
396 
397  if( center != segment->GetCenter() )
398  {
399  wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
400  segment->Move( moveVector );
401 
402  m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() );
403  m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
404  }
405 
406  else
407  {
408  segment->SetArcStart( wxPoint( start.x, start.y ) );
409 
410  VECTOR2D startLine = start - center;
411  VECTOR2I endLine = end - center;
412  double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
413 
414  // Adjust the new angle to (counter)clockwise setting
415  bool clockwise = ( segment->GetAngle() > 0 );
416 
417  if( clockwise && newAngle < 0.0 )
418  newAngle += 3600.0;
419  else if( !clockwise && newAngle > 0.0 )
420  newAngle -= 3600.0;
421 
422  segment->SetAngle( newAngle );
423  }
424 
425  break;
426  }
427 
428  case S_CIRCLE:
429  {
430  const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition();
431  const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition();
432 
433  if( isModified( m_editPoints->Point( CIRC_CENTER ) ) )
434  {
435  wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
436  segment->Move( moveVector );
437  }
438  else
439  {
440  segment->SetEnd( wxPoint( end.x, end.y ) );
441  }
442 
443  break;
444  }
445 
446  default: // suppress warnings
447  break;
448  }
449 
450  // Update relative coordinates for module edges
451  if( EDGE_MODULE* edge = dyn_cast<EDGE_MODULE*>( item ) )
452  edge->SetLocalCoord();
453 
454  break;
455  }
456 
457  case PCB_ZONE_AREA_T:
458  {
459  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
460  zone->ClearFilledPolysList();
461  SHAPE_POLY_SET* outline = zone->Outline();
462 
463  for( int i = 0; i < outline->TotalVertices(); ++i )
464  {
465  VECTOR2I point = m_editPoints->Point( i ).GetPosition();
466  outline->Vertex( i ) = point;
467  }
468 
469  zone->Hatch();
470 
471  break;
472  }
473 
474  case PCB_DIMENSION_T:
475  {
476  DIMENSION* dimension = static_cast<DIMENSION*>( item );
477 
478  // Check which point is currently modified and updated dimension's points respectively
479  if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) )
480  {
481  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetOrigin() );
482  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
483 
484  if( featureLine.Cross( crossBar ) > 0 )
485  dimension->SetHeight( -featureLine.EuclideanNorm() );
486  else
487  dimension->SetHeight( featureLine.EuclideanNorm() );
488  }
489 
490  else if( isModified( m_editPoints->Point( DIM_CROSSBARF ) ) )
491  {
492  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() );
493  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
494 
495  if( featureLine.Cross( crossBar ) > 0 )
496  dimension->SetHeight( -featureLine.EuclideanNorm() );
497  else
498  dimension->SetHeight( featureLine.EuclideanNorm() );
499  }
500 
501  else if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
502  {
504  m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
505  m_editPoints->Point( DIM_FEATUREGO ) ) );
506  m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
507  m_editPoints->Point( DIM_FEATUREDO ) ) );
508  }
509 
510  else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
511  {
513  m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
514  m_editPoints->Point( DIM_FEATUREGO ) ) );
515  m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
516  m_editPoints->Point( DIM_FEATUREDO ) ) );
517  }
518 
519  break;
520  }
521 
522  default:
523  break;
524  }
525 }
526 
527 
529 {
530  EDA_ITEM* item = m_editPoints->GetParent();
531 
532  if( item->Type() == PCB_ZONE_AREA_T )
533  {
534  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
535 
536  if( zone->IsFilled() )
537  {
538  getEditFrame<PCB_EDIT_FRAME>()->Fill_Zone( zone );
539  zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
540  }
541  }
542 }
543 
544 
546 {
547  if( !m_editPoints )
548  return;
549 
550  EDA_ITEM* item = m_editPoints->GetParent();
551 
552  switch( item->Type() )
553  {
554  case PCB_LINE_T:
555  case PCB_MODULE_EDGE_T:
556  {
557  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
558  {
559  switch( segment->GetShape() )
560  {
561  case S_SEGMENT:
562  m_editPoints->Point( SEG_START ).SetPosition( segment->GetStart() );
563  m_editPoints->Point( SEG_END ).SetPosition( segment->GetEnd() );
564  break;
565 
566  case S_ARC:
567  m_editPoints->Point( ARC_CENTER ).SetPosition( segment->GetCenter() );
568  m_editPoints->Point( ARC_START).SetPosition( segment->GetArcStart() );
569  m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
570  break;
571 
572  case S_CIRCLE:
573  m_editPoints->Point( CIRC_CENTER ).SetPosition( segment->GetCenter() );
574  m_editPoints->Point( CIRC_END ).SetPosition( segment->GetEnd() );
575  break;
576 
577  default: // suppress warnings
578  break;
579  }
580 
581  break;
582  }
583  }
584 
585  case PCB_ZONE_AREA_T:
586  {
587  const ZONE_CONTAINER* zone = static_cast<const ZONE_CONTAINER*>( item );
588  const SHAPE_POLY_SET* outline = zone->Outline();
589 
590  if( m_editPoints->PointsSize() != (unsigned) outline->TotalVertices() )
591  {
592  getView()->Remove( m_editPoints.get() );
593  m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
594  getView()->Add( m_editPoints.get() );
595  }
596  else
597  {
598  for( int i = 0; i < outline->TotalVertices(); ++i )
599  m_editPoints->Point( i ).SetPosition( outline->CVertex( i ) );
600  }
601 
602  break;
603  }
604 
605  case PCB_DIMENSION_T:
606  {
607  const DIMENSION* dimension = static_cast<const DIMENSION*>( item );
608 
609  m_editPoints->Point( DIM_CROSSBARO ).SetPosition( dimension->m_crossBarO );
610  m_editPoints->Point( DIM_CROSSBARF ).SetPosition( dimension->m_crossBarF );
611  m_editPoints->Point( DIM_FEATUREGO ).SetPosition( dimension->m_featureLineGO );
612  m_editPoints->Point( DIM_FEATUREDO ).SetPosition( dimension->m_featureLineDO );
613  break;
614  }
615 
616  default:
617  break;
618  }
619 
620  getView()->Update( m_editPoints.get() );
621 }
622 
623 
625 {
627 
628  if( aPoint )
629  {
630  controls->ForceCursorPosition( true, aPoint->GetPosition() );
631  controls->ShowCursor( true );
632  controls->SetSnapping( true );
633  }
634  else
635  {
636  controls->ShowCursor( false );
637  controls->SetSnapping( false );
638  controls->ForceCursorPosition( false );
639  }
640 
641  m_editedPoint = aPoint;
642 }
643 
644 
645 void POINT_EDITOR::setAltConstraint( bool aEnabled )
646 {
647  if( aEnabled )
648  {
649  EDIT_LINE* line = dynamic_cast<EDIT_LINE*>( m_editedPoint );
650 
651  if( line )
652  {
653  if( m_editPoints->GetParent()->Type() == PCB_ZONE_AREA_T )
655  }
656  else
657  {
658  // Find a proper constraining point for 45 degrees mode
661  }
662  }
663  else
664  {
665  m_altConstraint.reset();
666  }
667 }
668 
669 
671 {
672  EDA_ITEM* item = m_editPoints->GetParent();
673 
674  switch( item->Type() )
675  {
676  case PCB_LINE_T:
677  case PCB_MODULE_EDGE_T:
678  {
679  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
680  {
681  switch( segment->GetShape() )
682  {
683  case S_SEGMENT:
684  return *( m_editPoints->Next( *m_editedPoint ) ); // select the other end of line
685 
686  case S_ARC:
687  case S_CIRCLE:
688  return m_editPoints->Point( CIRC_CENTER );
689 
690  default: // suppress warnings
691  break;
692  }
693  }
694 
695  break;
696  }
697 
698  case PCB_DIMENSION_T:
699  {
700  // Constraint for crossbar
701  if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
702  return m_editPoints->Point( DIM_FEATUREDO );
703 
704  else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
705  return m_editPoints->Point( DIM_FEATUREGO );
706 
707  else
708  return EDIT_POINT( m_editedPoint->GetPosition() ); // no constraint
709 
710  break;
711  }
712 
713  default:
714  break;
715  }
716 
717  // In any other case we may align item to its original position
718  return m_original;
719 }
720 
721 
723 {
729 }
730 
731 
733 {
734  if( aSelection.Size() != 1 )
735  return false;
736 
737  auto item = aSelection.Front();
738 
739  // Works only for zones and line segments
740  return item->Type() == PCB_ZONE_AREA_T ||
741  ( ( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) &&
742  static_cast<DRAWSEGMENT*>( item )->GetShape() == S_SEGMENT );
743 }
744 
745 
747 {
748  if( !m_editPoints )
749  return false;
750 
751  EDA_ITEM* item = m_editPoints->GetParent();
752 
753  if( item->Type() != PCB_ZONE_AREA_T )
754  return false;
755 
756  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
757 
758  if( zone->GetNumCorners() <= 3 )
759  return false;
760 
761  // Remove corner does not work with lines
762  if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
763  return false;
764 
765  return m_editedPoint != NULL;
766 }
767 
768 
770 {
771  EDA_ITEM* item = m_editPoints->GetParent();
772  PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
773  const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
774  BOARD_COMMIT commit( frame );
775 
776  if( item->Type() == PCB_ZONE_AREA_T )
777  {
778  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
779  SHAPE_POLY_SET* outline = zone->Outline();
780 
781  commit.Modify( zone );
782 
783  // Handle the last segment, so other segments can be easily handled in a loop
784  unsigned int nearestIdx = outline->TotalVertices() - 1, nextNearestIdx = 0;
785  SEG side( outline->Vertex( nearestIdx ), outline->Vertex( nextNearestIdx ) );
786  unsigned int nearestDist = side.Distance( cursorPos );
787 
788  for( int i = 0; i < outline->TotalVertices() - 1; ++i )
789  {
790  side = SEG( outline->Vertex( i ), outline->Vertex( i + 1 ) );
791 
792  unsigned int distance = side.Distance( cursorPos );
793  if( distance < nearestDist )
794  {
795  nearestDist = distance;
796  nearestIdx = i;
797  nextNearestIdx = i + 1;
798  }
799  }
800 
801  // Find the point on the closest segment
802  VECTOR2I sideOrigin = outline->Vertex( nearestIdx );
803  VECTOR2I sideEnd = outline->Vertex( nextNearestIdx );
804  SEG nearestSide( sideOrigin, sideEnd );
805  VECTOR2I nearestPoint = nearestSide.NearestPoint( cursorPos );
806 
807  // Do not add points that have the same coordinates as ones that already belong to polygon
808  // instead, add a point in the middle of the side
809  if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
810  nearestPoint = ( sideOrigin + sideEnd ) / 2;
811 
812  outline->InsertVertex( nearestIdx, nearestPoint );
813 
814  commit.Push( _( "Add a zone corner" ) );
815  }
816 
817  else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T )
818  {
819  bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T;
820 
821  DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
822 
823  if( segment->GetShape() == S_SEGMENT )
824  {
825  commit.Modify( segment );
826 
827  SEG seg( segment->GetStart(), segment->GetEnd() );
828  VECTOR2I nearestPoint = seg.NearestPoint( cursorPos );
829 
830  // Move the end of the line to the break point..
831  segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) );
832 
833  // and add another one starting from the break point
834  DRAWSEGMENT* newSegment;
835 
836  if( moduleEdge )
837  {
838  EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment );
839  assert( edge->Type() == PCB_MODULE_EDGE_T );
840  assert( edge->GetParent()->Type() == PCB_MODULE_T );
841  newSegment = new EDGE_MODULE( *edge );
842  }
843  else
844  {
845  newSegment = new DRAWSEGMENT( *segment );
846  }
847 
848  newSegment->ClearSelected();
849  newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) );
850  newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) );
851 
852  commit.Add( newSegment );
853  commit.Push( _( "Split segment" ) );
854  }
855  }
856  updatePoints();
857  return 0;
858 }
859 
860 
862 {
863  if( !m_editedPoint )
864  return 0;
865 
866  EDA_ITEM* item = m_editPoints->GetParent();
867 
868  if( item->Type() == PCB_ZONE_AREA_T )
869  {
870  PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
871  BOARD_COMMIT commit( frame );
872 
873  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
874  SHAPE_POLY_SET* outline = zone->Outline();
875  commit.Modify( zone );
876 
877  for( int i = 0; i < outline->TotalVertices(); ++i )
878  {
879  if( outline->Vertex( i ) == m_editedPoint->GetPosition() )
880  {
881  outline->RemoveVertex( i );
882  setEditedPoint( NULL );
883  commit.Push( _( "Remove a zone corner" ) );
884  break;
885  }
886  }
887 
888  updatePoints();
889  }
890 
891  return 0;
892 }
893 
894 
896 {
897  updatePoints();
898  return 0;
899 }
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
Class EC_CONVERGING.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
BOARD_ITEM_CONTAINER * GetParent() const
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
int OnSelectionChange(const TOOL_EVENT &aEvent)
Function OnSelected()
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
TOOL_BASE * FindTool(int aId) const
Function FindTool() Searches for a tool with given ID.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Returns the index-th vertex in a given hole outline within a given outline
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: class_zone.h:466
void updateItem() const
Updates item's points with edit points.
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:280
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
This file is part of the common library.
wxPoint m_crossBarF
const VECTOR2D & DragOrigin() const
Returns the point where dragging has started.
Definition: tool_event.h:255
void addCorner(const VECTOR2I &aPoint)
Adds a new edit point on a zone outline/line.
bool IsMotion() const
Definition: tool_event.h:290
const wxPoint GetCenter() const override
Function GetCenter()
void ClearSelected()
Definition: base_struct.h:231
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
VIEW_CONTROLS class definition.
void updateEditedPoint(const TOOL_EVENT &aEvent)
Updates which point is being edited.
Class SELECTION_TOOL.
Class BOARD to handle a board.
virtual void Revert() override
Revertes the commit by restoring the modifed items state.
Class that computes missing connections on a PCB.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:49
bool IsFilled() const
Definition: class_zone.h:200
TOOL_MENU & GetToolMenu()
EDA_ITEM * Front() const
Definition: selection.h:137
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Class EDIT_LINE.
Definition: edit_points.h:189
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:114
void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:340
OPT_TOOL_EVENT Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
int TotalVertices() const
Returns total number of vertices stored in the set.
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:247
virtual void SetSnapping(bool aEnabled)
Function SetSnapping() Enables/disables snapping cursor to grid.
double RAD2DECIDEG(double rad)
Definition: trigo.h:196
Classes to handle copper zones.
void setAltConstraint(bool aEnabled)
Sets up an alternative constraint (typically enabled upon a modifier key being pressed).
usual segment : line with rounded ends
const VECTOR2D & Position() const
Returns mouse cursor position in world coordinates.
Definition: tool_event.h:248
static const TOOL_EVENT ClearedEvent
Event sent after selection is cleared.
CIRCLE_POINTS
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
Class EC_LINE.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true) override
Executes the changes.
Class EC_45DEGREE.
bool removeCornerCondition(const SELECTION &aSelection)
Condition to display "Remove corner" context menu entry.
const wxPoint & GetArcStart() const
Class EC_CIRCLE.
VECTOR2I & Vertex(int aIndex, int aOutline, int aHole)
Returns the index-th vertex in a given hole outline within a given outline
wxPoint m_featureLineGO
void PassEvent()
Allows a tool to pass the already handled event to the next tool on the stack.
Definition: tool_manager.h:336
DIMENSION class definition.
std::shared_ptr< EDIT_POINTS > m_editPoints
Currently available edit points.
Definition: point_editor.h:73
class MODULE, a footprint
Definition: typeinfo.h:101
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:309
STROKE_T GetShape() const
void SetOrigin(const wxPoint &aOrigin)
Function SetOrigin Sets a new origin of the crossbar line.
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
const wxPoint & GetEnd()
Function GetEnd.
virtual VECTOR2D GetCursorPosition() const =0
Function GetCursorPosition() Returns the current cursor position in world coordinates.
Class SHAPE_POLY_SET.
SEG_POINTS
const wxPoint & GetOrigin() const
Function GetOrigin.
static TOOL_ACTION pointEditorAddCorner
Break outline (insert additional points to an edge)
Definition: pcb_actions.h:193
static TOOL_ACTION pointEditorRemoveCorner
Removes a corner.
Definition: pcb_actions.h:196
void SetEnd(const wxPoint &aEnd)
Function SetEnd Sets a new end of the crossbar line.
Arcs (with rounded ends)
Class TOOL_EVENT.
Definition: tool_event.h:162
std::shared_ptr< EDIT_CONSTRAINT< EDIT_POINT > > m_altConstraint
Definition: point_editor.h:76
COMMIT & StageItems(const Range &aRange, CHANGE_TYPE aChangeType)
Definition: commit.h:113
EDIT_POINT get45DegConstrainer() const
Returns a point that should be used as a constrainer for 45 degrees mode.
DIMENSION_POINTS
SELECTION & GetSelection()
Function GetSelection()
bool isModified(const EDIT_POINT &aPoint) const
Returns true if aPoint is the currently modified point.
Definition: point_editor.h:97
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
Definition: view_controls.h:94
static const TOOL_EVENT UnselectedEvent
Event sent after an item is unselected.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
SELECTION_TOOL * m_selectionTool
Selection tool used for obtaining selected items
Definition: point_editor.h:64
All active tools
Definition: tool_event.h:138
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:112
void Update(VIEW_ITEM *aItem)
Function Update() For dynamic VIEWs, informs the associated VIEW that the graphical representation of...
Definition: view.cpp:1378
virtual void Move(const wxPoint &aMoveVector) override
Function Move move this object.
RN_DATA * GetRatsnest() const
Function GetRatsnest() returns list of missing connections between components/tracks.
Definition: class_board.h:287
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg...
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:36
static const TOOL_EVENT SelectedEvent
Event sent after an item is selected.
void SetStart(const wxPoint &aStart)
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:30
void Recalculate(int aNet=-1)
Function Recalculate() Recomputes ratsnest for selected net number or all nets that need updating...
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
Definition: seg.h:397
int GetNetCode() const
Function GetNetCode.
Definition: seg.h:37
virtual VECTOR2I GetPosition() const
Function GetPosition()
Definition: edit_points.h:65
VECTOR2D GetGridPoint(const VECTOR2D &aPoint) const
Function GetGridPoint() For a given point it returns the nearest point belonging to the grid in world...
double GetAngle() const
Common, abstract interface for edit frames.
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Function AddItem()
void SetHeight(int aHeight)
Function SetHeight Sets the length of feature lines.
void RemoveVertex(int aGlobalIndex)
Function RemoveVertex deletes the aGlobalIndex-th vertex.
Class TOOL_ACTION.
Definition: tool_action.h:46
const wxPoint GetArcEnd() const
void Hatch()
Function Hatch computes the hatch lines depending on the hatch parameters and stores it in the zone's...
Definition: class_zone.cpp:911
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:151
void removeCorner(EDIT_POINT *aPoint)
Removes a corner.
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:80
void updatePoints()
Updates edit points with item's points.
void SetEnd(const wxPoint &aEnd)
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
EDIT_POINT m_original
Original position for the current drag point.
Definition: point_editor.h:70
void Activate()
Function Activate() Runs the tool.
void SetTransitions() override
Sets up handlers for various events.
void InsertVertex(int aGlobalIndex, VECTOR2I aNewVertex)
Function InsertVertex Adds a vertex in the globally indexed position aGlobalIndex.
wxPoint m_crossBarO
int Size() const
Returns the number of selected parts.
Definition: selection.h:112
void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:310
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
void finishItem() const
Applies the last changes to the edited item.
Class EDIT_POINT.
Definition: edit_points.h:46
Module description (excepted pads)
static TOOL_ACTION editModifiedSelection
Modified selection notification.
Definition: pcb_actions.h:99
Class VIEW.
Definition: view.h:58
EDIT_POINT m_altConstrainer
Definition: point_editor.h:79
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
EDIT_POINT * m_editedPoint
Currently edited point, NULL if there is none.
Definition: point_editor.h:67
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
wxPoint m_featureLineDO
int Distance(const SEG &aSeg) const
Function Distance()
Definition: seg.h:228
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
Class EC_SNAPLINE.
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
void setEditedPoint(EDIT_POINT *aPoint)
Sets the current point being edited. NULL means none.
Class DIMENSION.
virtual void ApplyConstraint()
Function ApplyConstraint()
Definition: edit_points.h:159
int modifiedSelection(const TOOL_EVENT &aEvent)
ARC_POINTS
void ClearFilledPolysList()
Function ClearFilledPolysList clears the list of filled polygons.
Definition: class_zone.h:577
static bool addCornerCondition(const SELECTION &aSelection)
Condition to display "Create corner" context menu entry.
Class GAL is the abstract interface for drawing on a 2D-surface.
static std::shared_ptr< EDIT_POINTS > Make(EDA_ITEM *aItem, KIGFX::GAL *aGal)
virtual void SetPosition(const VECTOR2I &aPosition)
Function SetPosition()
Definition: edit_points.h:97