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 <wxPcbStruct.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_stuff.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  DISPLAY_OPTIONS* displ_opts = (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( g_Drc_On )
805  {
806  errdrc = m_drc->Drc( Track, GetBoard()->m_Track );
807 
808  if( errdrc == BAD_DRC )
809  return false;
810 
811  // Redraw the dragged segments
812  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
813  {
814  errdrc = m_drc->Drc( 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:198
virtual void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
Definition: pcbframe.cpp:996
bool s_StartPointHorizontal
bool g_Drc_On
Definition: pcbnew.cpp:70
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:255
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:318
#define IN_EDIT
Item currently edited.
Definition: base_struct.h:111
#define END_ONPAD
Pcbnew: flag set for track segment ending on a pad.
Definition: base_struct.h:133
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Definition: draw_panel.cpp:326
This file is part of the common library.
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:117
bool s_StartSegmentPresent
void TestNetConnection(wxDC *aDC, int aNetCode)
Function TestNetConnection tests the connections relative to aNetCode.
Definition: connect.cpp:786
D_PAD * GetPadFast(const wxPoint &aPosition, LSET aLayerMask)
Function GetPadFast return pad found at aPosition on aLayerMask using the fast search method...
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:309
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:376
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:134
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
DRC * m_drc
the DRC controller, see drc.cpp
Definition: wxPcbStruct.h:96
#define BEGIN_ONPAD
Pcbnew: flag set for track segment starting on a pad.
Definition: base_struct.h:132
void SetLink(EDA_ITEM *aItem)
const wxPoint & GetEnd() const
Definition: class_track.h:118
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
static wxPoint PosInit
This file contains miscellaneous commonly used macros and functions.
#define BAD_DRC
Definition: drc_stuff.h:36
static double s_EndSegmentSlope
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:115
static double s_MovingSegmentSlope
bool m_DisplayPcbTrackFill
Definition: pcbstruct.h:71
std::vector< DRAG_SEGM_PICKER > g_DragSegmentList
Definition: dragsegm.cpp:48
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:253
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Function SetMsgPanel clears the message panel and populates it with the contents of aList...
Definition: draw_frame.cpp:754
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:41
const wxPoint & GetStart() const
Definition: class_track.h:121
Useful classes and functions used to collect tracks to drag.
void UndrawAndMarkSegmentsToDrag(EDA_DRAW_PANEL *aCanvas, wxDC *aDC)
Definition: dragsegm.cpp:404
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:144
static PICKED_ITEMS_LIST s_ItemsListPicker
void HighLight(wxDC *DC)
Function HighLight.
Definition: highlight.cpp:101
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)
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:175
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:172
bool PlaceDraggedOrMovedTrackSegment(TRACK *Track, wxDC *DC)
void SetItem(EDA_ITEM *aItem)
void SetMouseCaptureCallback(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback)
static void Show_Drag_Track_Segment_With_Cte_Slope(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
void HighLightON()
Function HighLightON Enable highlight.
Definition: class_board.h:383
bool s_MovingSegmentHorizontal
Class DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
Definition: pcbstruct.h:62
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:361
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:92
void Collect_TrackSegmentsToDrag(BOARD *aPcb, const wxPoint &aRefPos, LSET aLayerMask, int aNetCode, int aMaxDist)
Function Collect_TrackSegmentsToDrag.
Definition: dragsegm.cpp:338
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
static wxPoint s_LastPos
void SetState(int type, int state)
Definition: base_struct.h:242
bool s_MovingSegmentVertical
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
int GetWidth() const
Definition: class_track.h:115
#define ENDPOINT
Definition: base_struct.h:119
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:251
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:254
void SetStart(const wxPoint &aStart)
Definition: class_track.h:120
int Drc(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:153
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
bool s_EndPointVertical
void * GetDisplayOptions()
Function GetDisplayOptions A way to pass info to draw functions.
Definition: draw_panel.cpp:182
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 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...
Definition: tracepcb.cpp:247
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:90
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition return the current cross hair position in logical (drawing) coordinates...
BOARD_CONNECTED_ITEM * start
Definition: class_track.h:89
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
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:118
static double s_StartSegment_Yorg