KiCad PCB EDA Suite
move_or_drag_track.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) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
32 #include <fctsys.h>
33 #include <class_drawpanel.h>
34 #include <confirm.h>
35 #include <pcb_edit_frame.h>
36 #include <trigo.h>
37 #include <macros.h>
38 #include <gr_basic.h>
39 
40 #include <class_board.h>
41 
42 #include <pcbnew.h>
43 #include <drc.h>
44 #include <drag.h>
45 #include <pcbnew_id.h>
46 
47 
48 static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
49  bool aErase );
51  wxDC* aDC,
52  const wxPoint& aPosition,
53  bool aErase );
54 static void Abort_MoveTrack( EDA_DRAW_PANEL* Panel, wxDC* DC );
55 static bool InitialiseDragParameters();
56 
57 
62  s_MovingSegment_Yorg; //slope and intercept parameters of lines
66  // horizontal line
67  // indicators
69 
71 
72 
75 static void Abort_MoveTrack( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
76 {
77  PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) aPanel->GetParent();
78  BOARD * pcb = frame->GetBoard();
79 
80  pcb->HighLightOFF();
81  pcb->PopHighLight();
82 
83  frame->SetCurItem( NULL );
84  aPanel->SetMouseCapture( NULL, NULL );
85 
86  // Undo move and redraw trace segments.
87  for( unsigned jj=0 ; jj < g_DragSegmentList.size(); jj++ )
88  {
89  TRACK* track = g_DragSegmentList[jj].m_Track;
90  g_DragSegmentList[jj].RestoreInitialValues();
91  track->SetState( IN_EDIT, false );
92  track->ClearFlags();
93  }
94 
95  // Clear the undo picker list:
96  s_ItemsListPicker.ClearListAndDeleteItems();
97  EraseDragList();
98  aPanel->Refresh();
99 }
100 
101 
102 // Redraw the moved node according to the mouse cursor position
103 static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
104  bool aErase )
105 {
106  auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions();
107  wxPoint moveVector;
108  int tmp = displ_opts->m_DisplayPcbTrackFill;
109  GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;
110 
111  displ_opts->m_DisplayPcbTrackFill = false;
112 
113 #ifndef USE_WX_OVERLAY
114  aErase = true;
115 #else
116  aErase = false;
117 #endif
118 
119  // set the new track coordinates
120  wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();
121 
122  moveVector = Pos - s_LastPos;
123  s_LastPos = Pos;
124 
125  TRACK *track = NULL;
126 
127  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
128  {
129  track = g_DragSegmentList[ii].m_Track;
130 
131  if( aErase )
132  track->Draw( aPanel, aDC, draw_mode );
133 
134  if( track->GetFlags() & STARTPOINT )
135  track->SetStart( track->GetStart() + moveVector );
136 
137  if( track->GetFlags() & ENDPOINT )
138  track->SetEnd( track->GetEnd() + moveVector );
139 
140  if( track->Type() == PCB_VIA_T )
141  track->SetEnd( track->GetStart() );
142 
143  track->Draw( aPanel, aDC, draw_mode );
144  }
145 
146  displ_opts->m_DisplayPcbTrackFill = tmp;
147 
148  // Display track length
149  if( track )
150  {
151  PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
152  frame->SetMsgPanel( track );
153  }
154 }
155 
156 
157 /* drawing the track segment movement
158  * > s_MovingSegmentSlope slope = moving track segment slope
159  * > s_StartSegmentSlope slope = slope of the segment connected to the start
160  * point of the moving segment
161  * > s_EndSegmentSlope slope = slope of the segment connected to the end point
162  * of the moving segment
163  *
164  * moved segment function :
165  * yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg
166  *
167  * segment connected to moved segment's start:
168  * y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg
169  *
170  * segment connected to moved segment's end:
171  * y2=s_EndSegmentSlope * x + s_EndSegment_Yorg
172  *
173  * first intersection point will be located at
174  * y1=yt ->
175  *
176  * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope)
177  * yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg
178  * or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg
179  *
180  * second intersection point
181  * y2=yt ->
182  *
183  * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope)
184  * yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg
185  * or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg
186  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
187  * !!!!! special attention to vertical segments because
188  * !!!!! their slope=infinite
189  * !!!!! intersection point will be calculated using the
190  * !!!!! segment intersecting it
191  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
192  *
193  * Slope parameters are computed once, because they can become undetermined
194  * when moving segments
195  * (i.e. when a segment length is 0) and we want keep them constant
196  */
198  const wxPoint& aPosition, bool aErase )
199 {
200  double xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0; // calculated intersection points
201  double tx1, tx2, ty1, ty2; // temporary storage of points
202  int dx, dy;
203  bool update = true;
204  TRACK* Track;
205  TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL;
206 
207  if( g_DragSegmentList.size() == 0 )
208  return;
209 
210  /* get the segments :
211  * from last to first in list are:
212  * the segment to move
213  * the segment connected to its end point (if exists)
214  * the segment connected to its start point (if exists)
215  */
216  int ii = g_DragSegmentList.size() - 1;
217  Track = g_DragSegmentList[ii].m_Track;
218 
219  if( Track == NULL )
220  return;
221 
222  ii--;
223 
224  if( ii >= 0)
225  {
226  if( s_EndSegmentPresent )
227  {
228  // Get the segment connected to the end point
229  tSegmentToEnd = g_DragSegmentList[ii].m_Track;
230  ii--;
231  }
232 
234  {
235  // Get the segment connected to the start point
236  if( ii >= 0 )
237  tSegmentToStart = g_DragSegmentList[ii].m_Track;
238  }
239  }
240 
241  GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;
242 
243  // Undraw the current moved track segments before modification
244 
245 #ifndef USE_WX_OVERLAY
246 // if( erase )
247  {
248  Track->Draw( aPanel, aDC, draw_mode );
249 
250  if( tSegmentToStart )
251  tSegmentToStart->Draw( aPanel, aDC, draw_mode );
252 
253  if( tSegmentToEnd )
254  tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
255  }
256 #endif
257 
258  // Compute the new track segment position
259  wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();
260 
261  dx = Pos.x - s_LastPos.x;
262  dy = Pos.y - s_LastPos.y;
263 
264  // move the line by dx and dy
265  tx1 = (double) ( Track->GetStart().x + dx );
266  ty1 = (double) ( Track->GetStart().y + dy );
267  tx2 = (double) ( Track->GetEnd().x + dx );
268  ty2 = (double) ( Track->GetEnd().y + dy );
269 
270  // recalculate the segments new parameters and intersection points
271  // only the intercept will change, segment slopes does not change
272  // because we are moving parallel with is initial state
274  s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 );
275 
277  {
280  }
281  else
282  {
283  if( !s_EndPointVertical )
284  xi2 = tx2;
285  else
286  {
287  //P1=P2
288  if( !s_EndPointHorizontal )
289  xi2 = tx2 - dx;
290  else
291  update = false;
292  }
293  }
294 
296  yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
297  else
298  {
299  if( !s_EndPointVertical )
300  yi2 = ( s_EndSegmentSlope * xi2 ) + s_EndSegment_Yorg;
301  else
302  {
303  if( !s_EndPointHorizontal )
304  update = false;
305  else
306  yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
307  }
308  }
309 
311  {
314  }
315  else
316  {
317  if( !s_StartPointVertical )
318  xi1 = tx1;
319  else
320  {
321  //P1=P2
323  xi1 = tx1 - dx;
324  else
325  {
327  update = false;
328  }
329  }
330  }
331 
333  yi1 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
334  else
335  {
336  if( !s_StartPointVertical )
337  yi1 = ( s_StartSegmentSlope * xi1 ) + s_StartSegment_Yorg;
338  else
339  {
341  update = false;
342  else
343  yi2 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
344  }
345  }
346 
347  // update the segment coordinates (if possible)
348  if( tSegmentToStart == NULL )
349  {
350  xi1 = tx1;
351  yi1 = ty1;
352  }
353 
354  if( tSegmentToEnd == NULL )
355  {
356  xi2 = tx2;
357  yi2 = ty2;
358  }
359 
360  if( update )
361  {
362  s_LastPos = Pos;
363  Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) );
364  Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) );
365 
366  if( tSegmentToEnd )
367  {
368  if( tSegmentToEnd->GetFlags() & STARTPOINT )
369  tSegmentToEnd->SetStart( Track->GetEnd() );
370  else
371  tSegmentToEnd->SetEnd( Track->GetEnd() );
372  }
373 
374  if( tSegmentToStart )
375  {
376  if( tSegmentToStart->GetFlags() & STARTPOINT )
377  tSegmentToStart->SetStart( Track->GetStart() );
378  else
379  tSegmentToStart->SetEnd( Track->GetStart() );
380  }
381  }
382 
383  Track->Draw( aPanel, aDC, draw_mode );
384 
385  if( tSegmentToStart )
386  tSegmentToStart->Draw( aPanel, aDC, draw_mode );
387 
388  if( tSegmentToEnd )
389  tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
390 
391  // Display track length
392  PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
393  frame->SetMsgPanel( Track );
394 }
395 
396 
397 /* Init variables (slope, Y intersect point, flags) for
398  * Show_Drag_Track_Segment_With_Cte_Slope()
399  * return true if Ok, false if dragging is not possible
400  * (2 colinear segments)
401  */
403 {
404  double tx1, tx2, ty1, ty2; // temporary storage of points
405  TRACK* Track;
406  TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL;
407 
408  if( g_DragSegmentList.size() == 0 )
409  return false;
410 
411  /* get the segments :
412  * from last to first in list are:
413  * the segment to move
414  * the segment connected to its end point (if exists)
415  * the segment connected to its start point (if exists)
416  */
417  int ii = g_DragSegmentList.size() - 1;
418  Track = g_DragSegmentList[ii].m_Track;
419  if( Track == NULL )
420  return false;
421 
422  ii--;
423 
424  if( ii >= 0)
425  {
426  if( s_EndSegmentPresent )
427  {
428  tSegmentToEnd = g_DragSegmentList[ii].m_Track; // Get the segment connected to
429  // the end point
430  ii--;
431  }
432 
434  {
435  if( ii >= 0 )
436  tSegmentToStart = g_DragSegmentList[ii].m_Track; // Get the segment connected to
437  // the start point
438  }
439  }
440 
441  // would be nice to eliminate collinear segments here, so we don't
442  // have to deal with that annoying "Unable to drag this segment: two
443  // collinear segments"
444 
445  s_StartPointVertical = false;
446  s_EndPointVertical = false;
447  s_MovingSegmentVertical = false;
448  s_StartPointHorizontal = false;
449  s_EndPointHorizontal = false;
451 
452  // Init parameters for the starting point of the moved segment
453  if( tSegmentToStart )
454  {
455  if( tSegmentToStart->GetFlags() & ENDPOINT )
456  {
457  tx1 = (double) tSegmentToStart->GetStart().x;
458  ty1 = (double) tSegmentToStart->GetStart().y;
459  tx2 = (double) tSegmentToStart->GetEnd().x;
460  ty2 = (double) tSegmentToStart->GetEnd().y;
461  }
462  else
463  {
464  tx1 = (double) tSegmentToStart->GetEnd().x;
465  ty1 = (double) tSegmentToStart->GetEnd().y;
466  tx2 = (double) tSegmentToStart->GetStart().x;
467  ty2 = (double) tSegmentToStart->GetStart().y;
468  }
469  }
470  else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track
471  {
472  tx1 = (double) Track->GetStart().x;
473  ty1 = (double) Track->GetStart().y;
474  tx2 = (double) Track->GetEnd().x;
475  ty2 = (double) Track->GetEnd().y;
476  RotatePoint( &tx2, &ty2, tx1, ty1, 900 );
477  }
478 
479  if( tx1 != tx2 )
480  {
481  s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
482  s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
483  }
484  else
485  {
486  s_StartPointVertical = true; //signal first segment vertical
487  }
488 
489  if( ty1 == ty2 )
490  {
491  s_StartPointHorizontal = true;
492  }
493 
494  // Init parameters for the ending point of the moved segment
495  if( tSegmentToEnd )
496  {
497  //check if second line is vertical
498  if( tSegmentToEnd->GetFlags() & STARTPOINT )
499  {
500  tx1 = (double) tSegmentToEnd->GetStart().x;
501  ty1 = (double) tSegmentToEnd->GetStart().y;
502  tx2 = (double) tSegmentToEnd->GetEnd().x;
503  ty2 = (double) tSegmentToEnd->GetEnd().y;
504  }
505  else
506  {
507  tx1 = (double) tSegmentToEnd->GetEnd().x;
508  ty1 = (double) tSegmentToEnd->GetEnd().y;
509  tx2 = (double) tSegmentToEnd->GetStart().x;
510  ty2 = (double) tSegmentToEnd->GetStart().y;
511  }
512  }
513  else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track
514  {
515  tx1 = (double) Track->GetEnd().x;
516  ty1 = (double) Track->GetEnd().y;
517  tx2 = (double) Track->GetStart().x;
518  ty2 = (double) Track->GetStart().y;
519  RotatePoint( &tx2, &ty2, tx1, ty1, -900 );
520  }
521 
522  if( tx2 != tx1 )
523  {
524  s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
525  s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
526  }
527  else
528  {
529  s_EndPointVertical = true; //signal second segment vertical
530  }
531 
532  if( ty1 == ty2 )
533  {
534  s_EndPointHorizontal = true;
535  }
536 
537  // Init parameters for the moved segment
538  tx1 = (double) Track->GetStart().x;
539  ty1 = (double) Track->GetStart().y;
540  tx2 = (double) Track->GetEnd().x;
541  ty2 = (double) Track->GetEnd().y;
542 
543  if( tx2 != tx1 )
544  {
545  s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
546  }
547  else
548  {
549  s_MovingSegmentVertical = true; // signal vertical line
550  }
551 
552  if( ty1 == ty2 )
553  {
555  }
556 
557  // Test if drag is possible:
559  {
561  return false;
562  }
563  else
564  {
566  return false;
567 
569  return false;
570  }
571 
572  return true;
573 }
574 
575 
576 void PCB_EDIT_FRAME::StartMoveOneNodeOrSegment( TRACK* aTrack, wxDC* aDC, int aCommand )
577 {
578  if( !aTrack )
579  return;
580 
581  EraseDragList();
582 
583  // Change highlighted net: the new one will be highlighted
584  GetBoard()->PushHighLight();
585 
586  if( GetBoard()->IsHighLightNetON() )
587  HighLight( aDC );
588 
589  PosInit = GetCrossHairPosition();
590 
591  if( aTrack->Type() == PCB_VIA_T )
592  {
593  aTrack->SetFlags( IS_DRAGGED | STARTPOINT | ENDPOINT );
594  AddSegmentToDragList( aTrack->GetFlags(), aTrack );
595 
596  if( aCommand != ID_POPUP_PCB_MOVE_TRACK_SEGMENT )
597  {
599  aTrack->GetLayerSet(),
600  aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
601  }
602 
603  PosInit = aTrack->GetStart();
604  }
605  else
606  {
607  STATUS_FLAGS diag = aTrack->IsPointOnEnds( GetCrossHairPosition(), -1 );
608  wxPoint pos;
609 
610  switch( aCommand )
611  {
612  case ID_POPUP_PCB_MOVE_TRACK_SEGMENT: // Move segment
613  aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
614  AddSegmentToDragList( aTrack->GetFlags(), aTrack );
615  break;
616 
617  case ID_POPUP_PCB_DRAG_TRACK_SEGMENT: // drag a segment
618  pos = aTrack->GetStart();
620  aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
621  pos = aTrack->GetEnd();
622  aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
624  aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
625  break;
626 
627  case ID_POPUP_PCB_MOVE_TRACK_NODE: // Drag via or move node
628  pos = (diag & STARTPOINT) ? aTrack->GetStart() : aTrack->GetEnd();
630  aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
631  PosInit = pos;
632  break;
633  }
634 
635  aTrack->SetFlags( IS_DRAGGED );
636  }
637 
638  // Prepare the Undo command
639  ITEM_PICKER picker( aTrack, UR_CHANGED );
640  picker.SetLink( aTrack->Clone() );
641  s_ItemsListPicker.PushItem( picker );
642 
643  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
644  {
645  TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
646  picker.SetItem( draggedtrack );
647  picker.SetLink( draggedtrack->Clone() );
648  s_ItemsListPicker.PushItem( picker );
649  draggedtrack = (TRACK*) picker.GetLink();
650  draggedtrack->SetStatus( 0 );
651  draggedtrack->ClearFlags();
652  }
653 
654  s_LastPos = PosInit;
656 
657  GetBoard()->SetHighLightNet( aTrack->GetNetCode() );
658  GetBoard()->HighLightON();
659 
660  GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
661  m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );
662 
664 }
665 
666 
668 {
669  TRACK* TrackToStartPoint = NULL;
670  TRACK* TrackToEndPoint = NULL;
671  bool error = false;
672 
673  if( !track )
674  return;
675 
676  // TODO: Use cleanup functions to merge collinear segments if track
677  // is connected to a collinear segment.
678 
680 
681  if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
682  TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );
683 
684  // Test if more than one segment is connected to this point
685  if( TrackToStartPoint )
686  {
687  TrackToStartPoint->SetState( BUSY, true );
688 
689  if( ( TrackToStartPoint->Type() == PCB_VIA_T )
690  || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
691  error = true;
692 
693  TrackToStartPoint->SetState( BUSY, false );
694  }
695 
696  if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
697  TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );
698 
699  // Test if more than one segment is connected to this point
700  if( TrackToEndPoint )
701  {
702  TrackToEndPoint->SetState( BUSY, true );
703 
704  if( (TrackToEndPoint->Type() == PCB_VIA_T)
705  || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
706  error = true;
707 
708  TrackToEndPoint->SetState( BUSY, false );
709  }
710 
711  if( error )
712  {
713  DisplayError( this,
714  _( "Unable to drag this segment: too many segments connected" ) );
715  return;
716  }
717 
718  if( !TrackToStartPoint || ( TrackToStartPoint->Type() != PCB_TRACE_T ) )
719  s_StartSegmentPresent = false;
720 
721  if( !TrackToEndPoint || ( TrackToEndPoint->Type() != PCB_TRACE_T ) )
722  s_EndSegmentPresent = false;
723 
724  // Change high light net: the new one will be highlighted
725  GetBoard()->PushHighLight();
726 
727  if( GetBoard()->IsHighLightNetON() )
728  HighLight( DC );
729 
730  EraseDragList();
731 
732  track->SetFlags( IS_DRAGGED );
733 
734  if( TrackToStartPoint )
735  {
736  STATUS_FLAGS flag = STARTPOINT;
737 
738  if( track->GetStart() != TrackToStartPoint->GetStart() )
739  flag = ENDPOINT;
740 
741  AddSegmentToDragList( flag, TrackToStartPoint );
742  track->SetFlags( STARTPOINT );
743  }
744 
745  if( TrackToEndPoint )
746  {
747  STATUS_FLAGS flag = STARTPOINT;
748 
749  if( track->GetEnd() != TrackToEndPoint->GetStart() )
750  flag = ENDPOINT;
751 
752  AddSegmentToDragList( flag, TrackToEndPoint );
753  track->SetFlags( ENDPOINT );
754  }
755 
756  AddSegmentToDragList( track->GetFlags(), track );
757 
759 
760 
761  PosInit = GetCrossHairPosition();
762  s_LastPos = GetCrossHairPosition();
764 
765  GetBoard()->SetHighLightNet( track->GetNetCode() );
766  GetBoard()->HighLightON();
767  GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );
768 
769  // Prepare the Undo command
770  ITEM_PICKER picker( NULL, UR_CHANGED );
771 
772  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
773  {
774  TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
775  picker.SetItem( draggedtrack);
776  picker.SetLink ( draggedtrack->Clone() );
777  s_ItemsListPicker.PushItem( picker );
778  draggedtrack = (TRACK*) picker.GetLink();
779  draggedtrack->SetStatus( 0 );
780  draggedtrack->ClearFlags();
781  }
782 
783  if( !InitialiseDragParameters() )
784  {
785  DisplayError( this, _( "Unable to drag this segment: two collinear segments" ) );
787  Abort_MoveTrack( m_canvas, DC );
788  return;
789  }
790 }
791 
792 
793 // Place a dragged (or moved) track segment or via
795 {
796  int errdrc;
797 
798  if( Track == NULL )
799  return false;
800 
801  int current_net_code = Track->GetNetCode();
802 
803  // DRC control:
804  if( Settings().m_legacyDrcOn )
805  {
806  errdrc = m_drc->DrcOnCreatingTrack( Track, GetBoard()->m_Track );
807 
808  if( errdrc == BAD_DRC )
809  return false;
810 
811  // Test the dragged segments
812  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
813  {
814  errdrc = m_drc->DrcOnCreatingTrack( g_DragSegmentList[ii].m_Track, GetBoard()->m_Track );
815 
816  if( errdrc == BAD_DRC )
817  return false;
818  }
819  }
820 
821  // DRC Ok: place track segments
822  Track->ClearFlags();
823  Track->SetState( IN_EDIT, false );
824 
825  // Draw dragged tracks
826  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
827  {
828  Track = g_DragSegmentList[ii].m_Track;
829  Track->SetState( IN_EDIT, false );
830  Track->ClearFlags();
831 
832  /* Test the connections modified by the move
833  * (only pad connection must be tested, track connection will be
834  * tested by TestNetConnection() ) */
835  LSET layerMask( Track->GetLayer() );
836 
837  Track->start = GetBoard()->GetPadFast( Track->GetStart(), layerMask );
838 
839  if( Track->start )
840  Track->SetState( BEGIN_ONPAD, true );
841  else
842  Track->SetState( BEGIN_ONPAD, false );
843 
844  Track->end = GetBoard()->GetPadFast( Track->GetEnd(), layerMask );
845 
846  if( Track->end )
847  Track->SetState( END_ONPAD, true );
848  else
849  Track->SetState( END_ONPAD, false );
850  }
851 
852  EraseDragList();
853 
854  SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
855  s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
856 
857  GetBoard()->PopHighLight();
858 
859  OnModify();
860  m_canvas->SetMouseCapture( NULL, NULL );
861 
862  if( current_net_code > 0 )
863  TestNetConnection( DC, current_net_code );
864 
865  m_canvas->Refresh();
866 
867  return true;
868 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
virtual void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
bool s_StartPointHorizontal
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:258
TRACK * GetTrack(TRACK *aStartTrace, TRACK *aEndTrace, ENDPOINT_T aEndPoint, bool aSameNetOnly, bool aSequential)
Function GetTrack returns the trace segment connected to the segment at aEndPoint from aStartTrace to...
void AddSegmentToDragList(int flag, TRACK *aTrack)
Definition: dragsegm.cpp:302
#define IN_EDIT
Item currently edited.
Definition: base_struct.h:112
#define END_ONPAD
Pcbnew: flag set for track segment ending on a pad.
Definition: base_struct.h:134
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
This file is part of the common library.
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:118
bool s_StartSegmentPresent
void TestNetConnection(wxDC *aDC, int aNetCode)
Function TestNetConnection tests the connections relative to aNetCode.
Definition: connect.cpp:40
D_PAD * GetPadFast(const wxPoint &aPosition, LSET aLayerMask)
Function GetPadFast return pad found at aPosition on aLayerMask using the fast search method...
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
static double s_EndSegment_Yorg
static double s_MovingSegment_Yorg
Class BOARD to handle a board.
STATUS_FLAGS IsPointOnEnds(const wxPoint &point, int min_dist=0)
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point...
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
void EraseDragList()
Function EraseDragList clear the .m_Flags of all track segments stored in g_DragSegmentList and clear...
Definition: dragsegm.cpp:293
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
void HighLightOFF()
Function HighLightOFF Disable highlight.
Definition: class_board.h:393
BOARD * GetBoard() const
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
#define BUSY
Pcbnew: flag indicating that the structure has.
Definition: base_struct.h:135
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
DRC * m_drc
the DRC controller, see drc.cpp
#define BEGIN_ONPAD
Pcbnew: flag set for track segment starting on a pad.
Definition: base_struct.h:133
void SetLink(EDA_ITEM *aItem)
const wxPoint & GetEnd() const
Definition: class_track.h:119
int DrcOnCreatingTrack(TRACK *aRefSeg, TRACK *aList)
Function Drc tests the current segment and returns the result and displays the error in the status pa...
Definition: drc.cpp:169
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
static wxPoint PosInit
This file contains miscellaneous commonly used macros and functions.
static double s_EndSegmentSlope
virtual EDA_DRAW_FRAME * GetParent() const =0
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:116
static double s_MovingSegmentSlope
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings...
std::vector< DRAG_SEGM_PICKER > g_DragSegmentList
Definition: dragsegm.cpp:47
Class LSET is a set of PCB_LAYER_IDs.
void PopHighLight()
Function PopHighLight retrieve a previously saved high light info.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
PCB_GENERAL_SETTINGS & Settings()
const wxPoint & GetStart() const
Definition: class_track.h:122
Useful classes and functions used to collect tracks to drag.
virtual void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
void UndrawAndMarkSegmentsToDrag(EDA_DRAW_PANEL *aCanvas, wxDC *aDC)
Definition: dragsegm.cpp:388
virtual void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
static bool InitialiseDragParameters()
static double s_StartSegmentSlope
unsigned STATUS_FLAGS
Definition: base_struct.h:147
static PICKED_ITEMS_LIST s_ItemsListPicker
void HighLight(wxDC *DC)
Function HighLight.
Definition: highlight.cpp:105
void StartMoveOneNodeOrSegment(TRACK *aTrack, wxDC *aDC, int aCommand)
Function StartMoveOneNodeOrSegment initializes the parameters to move one via or/and a terminal point...
void Start_DragTrackSegmentAndKeepSlope(TRACK *track, wxDC *DC)
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
bool s_EndPointHorizontal
void SaveCopyInUndoList(BOARD_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, const wxPoint &aTransformPoint=wxPoint(0, 0)) override
Function SaveCopyInUndoList Creates a new entry in undo list of commands.
Definition: undo_redo.cpp:202
bool PlaceDraggedOrMovedTrackSegment(TRACK *Track, wxDC *DC)
void SetItem(EDA_ITEM *aItem)
static void Show_Drag_Track_Segment_With_Cte_Slope(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
#define BAD_DRC
Definition: drc.h:37
void HighLightON()
Function HighLightON Enable highlight.
Definition: class_board.h:400
bool s_MovingSegmentHorizontal
static void Show_MoveNode(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
int GetNetCode() const
Function GetNetCode.
void SetHighLightNet(int aNetCode)
Function SetHighLightNet.
Definition: class_board.h:378
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
void Collect_TrackSegmentsToDrag(BOARD *aPcb, const wxPoint &aRefPos, LSET aLayerMask, int aNetCode, int aMaxDist)
Function Collect_TrackSegmentsToDrag.
Definition: dragsegm.cpp:322
static wxPoint s_LastPos
void SetState(int type, int state)
Definition: base_struct.h:245
bool s_MovingSegmentVertical
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
int GetWidth() const
Definition: class_track.h:116
#define ENDPOINT
Definition: base_struct.h:120
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
void PushHighLight()
Function PushHighLight save current high light info for later use.
void ClearItemsList()
Function ClearItemsList deletes only the list of pickers, NOT the picked data itself.
void SetStatus(STATUS_FLAGS aStatus)
Definition: base_struct.h:254
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
void SetStart(const wxPoint &aStart)
Definition: class_track.h:121
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
bool s_EndPointVertical
virtual void * GetDisplayOptions()
Function GetDisplayOptions A way to pass info to draw functions.
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
void DrawHighLight(EDA_DRAW_PANEL *aDrawPanel, wxDC *aDC, int aNetCode)
Function DrawHighLight redraws the objects in the board that are associated with the given aNetCode a...
static void Abort_MoveTrack(EDA_DRAW_PANEL *Panel, wxDC *DC)
Abort function for drag or move track.
BOARD_CONNECTED_ITEM * end
Definition: class_track.h:91
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
BOARD_CONNECTED_ITEM * start
Definition: class_track.h:90
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
virtual void SetMouseCaptureCallback(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback)
EDA_ITEM * GetLink() const
void ClearListAndDeleteItems()
Function ClearListAndDeleteItems deletes the list of pickers, AND the data pointed by m_PickedItem or...
bool s_EndSegmentPresent
bool s_StartPointVertical
#define STARTPOINT
Definition: base_struct.h:119
static double s_StartSegment_Yorg