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 <connectivity.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  if( !aItem )
91  return points;
92 
93  // Generate list of edit points basing on the item type
94  switch( aItem->Type() )
95  {
96  case PCB_LINE_T:
97  case PCB_MODULE_EDGE_T:
98  {
99  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( aItem );
100 
101  switch( segment->GetShape() )
102  {
103  case S_SEGMENT:
104  points->AddPoint( segment->GetStart() );
105  points->AddPoint( segment->GetEnd() );
106  break;
107 
108  case S_ARC:
109  points->AddPoint( segment->GetCenter() );
110  points->AddPoint( segment->GetArcStart() );
111  points->AddPoint( segment->GetArcEnd() );
112 
113  // Set constraints
114  // Arc end has to stay at the same radius as the start
115  points->Point( ARC_END ).SetConstraint( new EC_CIRCLE( points->Point( ARC_END ),
116  points->Point( ARC_CENTER ),
117  points->Point( ARC_START ) ) );
118  break;
119 
120  case S_CIRCLE:
121  points->AddPoint( segment->GetCenter() );
122  points->AddPoint( segment->GetEnd() );
123  break;
124 
125  default: // suppress warnings
126  break;
127  }
128 
129  break;
130  }
131 
132  case PCB_ZONE_AREA_T:
133  {
134  const SHAPE_POLY_SET* outline;
135  outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
136 
137  int cornersCount = outline->TotalVertices();
138 
139  for( auto iterator = outline->CIterateWithHoles(); iterator; iterator++ )
140  {
141  points->AddPoint( *iterator );
142 
143  if( iterator.IsEndContour() )
144  points->AddBreak();
145  }
146 
147  // Lines have to be added after creating edit points,
148  // as they use EDIT_POINT references
149  for( int i = 0; i < cornersCount - 1; ++i )
150  {
151  if( points->IsContourEnd( i ) )
152  {
153  points->AddLine( points->Point( i ),
154  points->Point( points->GetContourStartIdx( i ) ) );
155  }
156  else
157  {
158  points->AddLine( points->Point( i ), points->Point( i + 1 ) );
159  }
160 
161  points->Line( i ).SetConstraint( new EC_SNAPLINE( points->Line( i ),
162  std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
163  }
164 
165  // The last missing line, connecting the last and the first polygon point
166  points->AddLine( points->Point( cornersCount - 1 ),
167  points->Point( points->GetContourStartIdx( cornersCount - 1 ) ) );
168 
169  points->Line( points->LinesSize() - 1 ).SetConstraint(
170  new EC_SNAPLINE( points->Line( points->LinesSize() - 1 ),
171  std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
172  break;
173  }
174 
175  case PCB_DIMENSION_T:
176  {
177  const DIMENSION* dimension = static_cast<const DIMENSION*>( aItem );
178 
179  points->AddPoint( dimension->m_crossBarO );
180  points->AddPoint( dimension->m_crossBarF );
181  points->AddPoint( dimension->m_featureLineGO );
182  points->AddPoint( dimension->m_featureLineDO );
183 
184  // Dimension height setting - edit points should move only along the feature lines
185  points->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARO ),
186  points->Point( DIM_FEATUREGO ) ) );
187  points->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARF ),
188  points->Point( DIM_FEATUREDO ) ) );
189 
190  break;
191  }
192 
193  default:
194  points.reset();
195  break;
196  }
197 
198  return points;
199  }
200 
201 private:
203 };
204 
205 
207  TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL ), m_editedPoint( NULL ),
208  m_original( VECTOR2I( 0, 0 ) ), m_altConstrainer( VECTOR2I( 0, 0 ) )
209 {
210 }
211 
212 
214 {
215  m_editPoints.reset();
216  m_altConstraint.reset();
217 }
218 
219 
221 {
222  // Find the selection tool, so they can cooperate
223  m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) );
224 
225  if( !m_selectionTool )
226  {
227  DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
228  return false;
229  }
230 
231  auto& menu = m_selectionTool->GetToolMenu().GetMenu();
234  std::bind( &POINT_EDITOR::removeCornerCondition, this, _1 ) );
235 
236  return true;
237 }
238 
239 
241 {
242  EDIT_POINT* point = m_editedPoint;
243 
244  if( aEvent.IsMotion() )
245  {
246  point = m_editPoints->FindPoint( aEvent.Position(), getView() );
247  }
248  else if( aEvent.IsDrag( BUT_LEFT ) )
249  {
250  point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
251  }
252 
253  if( m_editedPoint != point )
254  setEditedPoint( point );
255 }
256 
257 
259 {
260  const SELECTION& selection = m_selectionTool->GetSelection();
261 
262  if( selection.Size() != 1 )
263  return 0;
264 
265  Activate();
266 
268  KIGFX::VIEW* view = getView();
269  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
270  auto item = selection.Front();
271 
272  m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
273 
274  if( !m_editPoints )
275  return 0;
276 
277  view->Add( m_editPoints.get() );
278  m_editedPoint = NULL;
279  bool modified = false;
280  bool revert = false;
281 
282  BOARD_COMMIT commit( editFrame );
283 
284  // Main loop: keep receiving events
285  while( OPT_TOOL_EVENT evt = Wait() )
286  {
287  if( revert )
288  break;
289 
290  if( !m_editPoints ||
291  evt->Matches( m_selectionTool->ClearedEvent ) ||
292  evt->Matches( m_selectionTool->UnselectedEvent ) ||
293  evt->Matches( m_selectionTool->SelectedEvent ) )
294  {
295  break;
296  }
297 
298  if ( !modified )
299  updateEditedPoint( *evt );
300 
301  if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
302  {
303  if( !modified )
304  {
305  commit.StageItems( selection, CHT_MODIFY );
306 
307  controls->ForceCursorPosition( false );
308  m_original = *m_editedPoint; // Save the original position
309  controls->SetAutoPan( true );
310  modified = true;
311  }
312 
313  bool enableAltConstraint = !!evt->Modifier( MD_CTRL );
314 
315  if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint
316  setAltConstraint( enableAltConstraint );
317 
319 
320  if( m_altConstraint )
321  m_altConstraint->Apply();
322  else
324 
325  updateItem();
326  updatePoints();
327  }
328 
329  else if( evt->IsMouseUp( BUT_LEFT ) )
330  {
331  controls->SetAutoPan( false );
332  setAltConstraint( false );
333 
334  if( modified )
335  {
336  commit.Push( _( "Drag a line ending" ) );
337  modified = false;
338  }
339 
340  m_toolMgr->PassEvent();
341  }
342 
343  else if( evt->IsCancel() )
344  {
345  if( modified ) // Restore the last change
346  revert = true;
347 
348  // Let the selection tool receive the event too
349  m_toolMgr->PassEvent();
350 
351  // Do not exit right now, let the selection clear the selection
352  //break;
353  }
354 
355  else
356  {
357  m_toolMgr->PassEvent();
358  }
359  }
360 
361  if( m_editPoints )
362  {
363  view->Remove( m_editPoints.get() );
364 
365  if( modified && revert )
366  commit.Revert();
367  else
368  finishItem();
369 
370  m_editPoints.reset();
371  }
372 
373  return 0;
374 }
375 
376 
378 {
379  EDA_ITEM* item = m_editPoints->GetParent();
380 
381  if( !item )
382  return;
383 
384  switch( item->Type() )
385  {
386  case PCB_LINE_T:
387  case PCB_MODULE_EDGE_T:
388  {
389  DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
390  switch( segment->GetShape() )
391  {
392  case S_SEGMENT:
393  if( isModified( m_editPoints->Point( SEG_START ) ) )
394  segment->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x,
395  m_editPoints->Point( SEG_START ).GetPosition().y ) );
396 
397  else if( isModified( m_editPoints->Point( SEG_END ) ) )
398  segment->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x,
399  m_editPoints->Point( SEG_END ).GetPosition().y ) );
400 
401  break;
402 
403  case S_ARC:
404  {
405  const VECTOR2I& center = m_editPoints->Point( ARC_CENTER ).GetPosition();
406  const VECTOR2I& start = m_editPoints->Point( ARC_START ).GetPosition();
407  const VECTOR2I& end = m_editPoints->Point( ARC_END ).GetPosition();
408 
409  if( center != segment->GetCenter() )
410  {
411  wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
412  segment->Move( moveVector );
413 
414  m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() );
415  m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
416  }
417 
418  else
419  {
420  segment->SetArcStart( wxPoint( start.x, start.y ) );
421 
422  VECTOR2D startLine = start - center;
423  VECTOR2I endLine = end - center;
424  double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
425 
426  // Adjust the new angle to (counter)clockwise setting
427  bool clockwise = ( segment->GetAngle() > 0 );
428 
429  if( clockwise && newAngle < 0.0 )
430  newAngle += 3600.0;
431  else if( !clockwise && newAngle > 0.0 )
432  newAngle -= 3600.0;
433 
434  segment->SetAngle( newAngle );
435  }
436 
437  break;
438  }
439 
440  case S_CIRCLE:
441  {
442  const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition();
443  const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition();
444 
445  if( isModified( m_editPoints->Point( CIRC_CENTER ) ) )
446  {
447  wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
448  segment->Move( moveVector );
449  }
450  else
451  {
452  segment->SetEnd( wxPoint( end.x, end.y ) );
453  }
454 
455  break;
456  }
457 
458  default: // suppress warnings
459  break;
460  }
461 
462  // Update relative coordinates for module edges
463  if( EDGE_MODULE* edge = dyn_cast<EDGE_MODULE*>( item ) )
464  edge->SetLocalCoord();
465 
466  break;
467  }
468 
469  case PCB_ZONE_AREA_T:
470  {
471  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
472  zone->ClearFilledPolysList();
473  SHAPE_POLY_SET* outline = zone->Outline();
474 
475  for( int i = 0; i < outline->TotalVertices(); ++i )
476  {
477  VECTOR2I point = m_editPoints->Point( i ).GetPosition();
478  outline->Vertex( i ) = point;
479  }
480 
481  zone->Hatch();
482 
483  break;
484  }
485 
486  case PCB_DIMENSION_T:
487  {
488  DIMENSION* dimension = static_cast<DIMENSION*>( item );
489 
490  // Check which point is currently modified and updated dimension's points respectively
491  if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) )
492  {
493  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetOrigin() );
494  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
495 
496  if( featureLine.Cross( crossBar ) > 0 )
497  dimension->SetHeight( -featureLine.EuclideanNorm() );
498  else
499  dimension->SetHeight( featureLine.EuclideanNorm() );
500  }
501 
502  else if( isModified( m_editPoints->Point( DIM_CROSSBARF ) ) )
503  {
504  VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() );
505  VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
506 
507  if( featureLine.Cross( crossBar ) > 0 )
508  dimension->SetHeight( -featureLine.EuclideanNorm() );
509  else
510  dimension->SetHeight( featureLine.EuclideanNorm() );
511  }
512 
513  else if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
514  {
516  m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
517  m_editPoints->Point( DIM_FEATUREGO ) ) );
518  m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
519  m_editPoints->Point( DIM_FEATUREDO ) ) );
520  }
521 
522  else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
523  {
525  m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
526  m_editPoints->Point( DIM_FEATUREGO ) ) );
527  m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
528  m_editPoints->Point( DIM_FEATUREDO ) ) );
529  }
530 
531  break;
532  }
533 
534  default:
535  break;
536  }
537 }
538 
539 
541 {
542  EDA_ITEM* item = m_editPoints->GetParent();
543 
544  if( !item )
545  return;
546 
547  if( item->Type() == PCB_ZONE_AREA_T )
548  {
549  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
550 
551  if( zone->IsFilled() )
552  {
553  getEditFrame<PCB_EDIT_FRAME>()->Fill_Zone( zone );
554 // zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
555  }
556  }
557 }
558 
559 
561 {
562  if( !m_editPoints )
563  return;
564 
565  EDA_ITEM* item = m_editPoints->GetParent();
566 
567  if( !item )
568  return;
569 
570  switch( item->Type() )
571  {
572  case PCB_LINE_T:
573  case PCB_MODULE_EDGE_T:
574  {
575  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
576  {
577  switch( segment->GetShape() )
578  {
579  case S_SEGMENT:
580  m_editPoints->Point( SEG_START ).SetPosition( segment->GetStart() );
581  m_editPoints->Point( SEG_END ).SetPosition( segment->GetEnd() );
582  break;
583 
584  case S_ARC:
585  m_editPoints->Point( ARC_CENTER ).SetPosition( segment->GetCenter() );
586  m_editPoints->Point( ARC_START).SetPosition( segment->GetArcStart() );
587  m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
588  break;
589 
590  case S_CIRCLE:
591  m_editPoints->Point( CIRC_CENTER ).SetPosition( segment->GetCenter() );
592  m_editPoints->Point( CIRC_END ).SetPosition( segment->GetEnd() );
593  break;
594 
595  default: // suppress warnings
596  break;
597  }
598 
599  break;
600  }
601  }
602 
603  case PCB_ZONE_AREA_T:
604  {
605  const ZONE_CONTAINER* zone = static_cast<const ZONE_CONTAINER*>( item );
606  const SHAPE_POLY_SET* outline = zone->Outline();
607 
608  if( m_editPoints->PointsSize() != (unsigned) outline->TotalVertices() )
609  {
610  getView()->Remove( m_editPoints.get() );
611  m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
612  getView()->Add( m_editPoints.get() );
613  }
614  else
615  {
616  for( int i = 0; i < outline->TotalVertices(); ++i )
617  m_editPoints->Point( i ).SetPosition( outline->CVertex( i ) );
618  }
619 
620  break;
621  }
622 
623  case PCB_DIMENSION_T:
624  {
625  const DIMENSION* dimension = static_cast<const DIMENSION*>( item );
626 
627  m_editPoints->Point( DIM_CROSSBARO ).SetPosition( dimension->m_crossBarO );
628  m_editPoints->Point( DIM_CROSSBARF ).SetPosition( dimension->m_crossBarF );
629  m_editPoints->Point( DIM_FEATUREGO ).SetPosition( dimension->m_featureLineGO );
630  m_editPoints->Point( DIM_FEATUREDO ).SetPosition( dimension->m_featureLineDO );
631  break;
632  }
633 
634  default:
635  break;
636  }
637 
638  getView()->Update( m_editPoints.get() );
639 }
640 
641 
643 {
645 
646  if( aPoint )
647  {
648  controls->ForceCursorPosition( true, aPoint->GetPosition() );
649  controls->ShowCursor( true );
650  controls->SetSnapping( true );
651  }
652  else
653  {
654  controls->ShowCursor( false );
655  controls->SetSnapping( false );
656  controls->ForceCursorPosition( false );
657  }
658 
659  m_editedPoint = aPoint;
660 }
661 
662 
663 void POINT_EDITOR::setAltConstraint( bool aEnabled )
664 {
665  if( aEnabled )
666  {
667  EDIT_LINE* line = dynamic_cast<EDIT_LINE*>( m_editedPoint );
668 
669  if( line )
670  {
671  if( m_editPoints->GetParent()->Type() == PCB_ZONE_AREA_T )
673  }
674  else
675  {
676  // Find a proper constraining point for 45 degrees mode
679  }
680  }
681  else
682  {
683  m_altConstraint.reset();
684  }
685 }
686 
687 
689 {
690  EDA_ITEM* item = m_editPoints->GetParent();
691 
692  switch( item->Type() )
693  {
694  case PCB_LINE_T:
695  case PCB_MODULE_EDGE_T:
696  {
697  const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
698  {
699  switch( segment->GetShape() )
700  {
701  case S_SEGMENT:
702  return *( m_editPoints->Next( *m_editedPoint ) ); // select the other end of line
703 
704  case S_ARC:
705  case S_CIRCLE:
706  return m_editPoints->Point( CIRC_CENTER );
707 
708  default: // suppress warnings
709  break;
710  }
711  }
712 
713  break;
714  }
715 
716  case PCB_DIMENSION_T:
717  {
718  // Constraint for crossbar
719  if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
720  return m_editPoints->Point( DIM_FEATUREDO );
721 
722  else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
723  return m_editPoints->Point( DIM_FEATUREGO );
724 
725  else
726  return EDIT_POINT( m_editedPoint->GetPosition() ); // no constraint
727 
728  break;
729  }
730 
731  default:
732  break;
733  }
734 
735  // In any other case we may align item to its original position
736  return m_original;
737 }
738 
739 
741 {
747 }
748 
749 
751 {
752  if( aSelection.Size() != 1 )
753  return false;
754 
755  auto item = aSelection.Front();
756 
757  // Works only for zones and line segments
758  return item->Type() == PCB_ZONE_AREA_T ||
759  ( ( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) &&
760  static_cast<DRAWSEGMENT*>( item )->GetShape() == S_SEGMENT );
761 }
762 
763 
765 {
766  if( !m_editPoints )
767  return false;
768 
769  EDA_ITEM* item = m_editPoints->GetParent();
770 
771  if( item->Type() != PCB_ZONE_AREA_T )
772  return false;
773 
774  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
775 
776  if( zone->GetNumCorners() <= 3 )
777  return false;
778 
779  // Remove corner does not work with lines
780  if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
781  return false;
782 
783  return m_editedPoint != NULL;
784 }
785 
786 
788 {
789  EDA_ITEM* item = m_editPoints->GetParent();
790  PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
791  const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
792  BOARD_COMMIT commit( frame );
793 
794  if( item->Type() == PCB_ZONE_AREA_T )
795  {
796  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
797  SHAPE_POLY_SET* zoneOutline = zone->Outline();
798 
799  commit.Modify( zone );
800 
801  unsigned int nearestIdx = 0;
802  unsigned int nextNearestIdx = 0;
803  unsigned int nearestDist = INT_MAX;
804  unsigned int firstPointInContour = 0;
805 
806  // Search the best outline segment to add a new corner
807  // and therefore break this segment into two segments
808 
809  // Object to iterate through the corners of the outlines (main contour and its holes)
810  SHAPE_POLY_SET::ITERATOR iterator = zoneOutline->Iterate( 0,
811  zoneOutline->OutlineCount()-1, /* IterateHoles */ true );
812  int curr_idx = 0;
813 
814  // Iterate through all the corners of the outlines and search the best segment
815  for( ; iterator; iterator++, curr_idx++ )
816  {
817  int jj = curr_idx+1;
818 
819  if( iterator.IsEndContour() )
820  { // We reach the last point of the current contour (main or hole)
821  jj = firstPointInContour;
822  firstPointInContour = curr_idx+1; // Prepare next contour analysis
823  }
824 
825  SEG curr_segment( zoneOutline->Vertex( curr_idx ), zoneOutline->Vertex( jj ) );
826 
827  unsigned int distance = curr_segment.Distance( cursorPos );
828 
829  if( distance < nearestDist )
830  {
831  nearestDist = distance;
832  nearestIdx = curr_idx;
833  nextNearestIdx = jj;
834  }
835  }
836 
837 
838  // Find the point on the closest segment
839  VECTOR2I sideOrigin = zoneOutline->Vertex( nearestIdx );
840  VECTOR2I sideEnd = zoneOutline->Vertex( nextNearestIdx );
841  SEG nearestSide( sideOrigin, sideEnd );
842  VECTOR2I nearestPoint = nearestSide.NearestPoint( cursorPos );
843 
844  // Do not add points that have the same coordinates as ones that already belong to polygon
845  // instead, add a point in the middle of the side
846  if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
847  nearestPoint = ( sideOrigin + sideEnd ) / 2;
848 
849  // Add corner between nearestIdx and nextNearestIdx:
850  zoneOutline->InsertVertex( nextNearestIdx, nearestPoint );
851  zone->Hatch();
852 
853  commit.Push( _( "Add a zone corner" ) );
854  }
855 
856  else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T )
857  {
858  bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T;
859 
860  DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
861 
862  if( segment->GetShape() == S_SEGMENT )
863  {
864  commit.Modify( segment );
865 
866  SEG seg( segment->GetStart(), segment->GetEnd() );
867  VECTOR2I nearestPoint = seg.NearestPoint( cursorPos );
868 
869  // Move the end of the line to the break point..
870  segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) );
871 
872  // and add another one starting from the break point
873  DRAWSEGMENT* newSegment;
874 
875  if( moduleEdge )
876  {
877  EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment );
878  assert( edge->Type() == PCB_MODULE_EDGE_T );
879  assert( edge->GetParent()->Type() == PCB_MODULE_T );
880  newSegment = new EDGE_MODULE( *edge );
881  }
882  else
883  {
884  newSegment = new DRAWSEGMENT( *segment );
885  }
886 
887  newSegment->ClearSelected();
888  newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) );
889  newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) );
890 
891  commit.Add( newSegment );
892  commit.Push( _( "Split segment" ) );
893  }
894  }
895 
896  updatePoints();
897  return 0;
898 }
899 
900 
902 {
903  if( !m_editedPoint )
904  return 0;
905 
906  EDA_ITEM* item = m_editPoints->GetParent();
907 
908  if( !item )
909  return 0;
910 
911  if( item->Type() == PCB_ZONE_AREA_T )
912  {
913  PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
914  BOARD_COMMIT commit( frame );
915 
916  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
917  SHAPE_POLY_SET* zoneOutline = zone->Outline();
918  commit.Modify( zone );
919 
920  for( int i = 0; i < zoneOutline->TotalVertices(); ++i )
921  {
922  if( zoneOutline->Vertex( i ) == m_editedPoint->GetPosition() )
923  {
924  zoneOutline->RemoveVertex( i );
925  setEditedPoint( NULL );
926  commit.Push( _( "Remove a zone corner" ) );
927  break;
928  }
929  }
930 
931  updatePoints();
932  }
933 
934  return 0;
935 }
936 
937 
939 {
940  updatePoints();
941  return 0;
942 }
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:465
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.
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:144
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:341
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.
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Function Iterate returns an object to iterate through the points of the polygons between aFirst and a...
int OutlineCount() const
Returns the number of outlines in the set
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.
static TOOL_ACTION selectionModified
Modified selection notification.
Definition: pcb_actions.h:105
bool removeCornerCondition(const SELECTION &aSelection)
Condition to display "Remove corner" context menu entry.
bool IsEndContour() const
Function IsEndContour.
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.
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:202
static TOOL_ACTION pointEditorRemoveCorner
Removes a corner.
Definition: pcb_actions.h:205
void SetEnd(const wxPoint &aEnd)
Function SetEnd Sets a new end of the crossbar line.
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
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:116
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
void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1385
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:112
virtual void Move(const wxPoint &aMoveVector) override
Function Move move this object.
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
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
Definition: seg.h:355
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 ITERATOR_TEMPLATE.
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:951
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)
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:311
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)
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:186
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:572
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