You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

868 lines
26 KiB

18 years ago
18 years ago
18 years ago
  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. /**
  27. * @file move_or_drag_track.cpp
  28. * @brief Track editing routines to move and drag track segments or node.
  29. */
  30. #include <fctsys.h>
  31. #include <class_drawpanel.h>
  32. #include <confirm.h>
  33. #include <pcb_edit_frame.h>
  34. #include <trigo.h>
  35. #include <macros.h>
  36. #include <gr_basic.h>
  37. #include <class_board.h>
  38. #include <pcbnew.h>
  39. #include <drc.h>
  40. #include <drag.h>
  41. #include <pcbnew_id.h>
  42. static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  43. bool aErase );
  44. static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel,
  45. wxDC* aDC,
  46. const wxPoint& aPosition,
  47. bool aErase );
  48. static void Abort_MoveTrack( EDA_DRAW_PANEL* Panel, wxDC* DC );
  49. static bool InitialiseDragParameters();
  50. static wxPoint PosInit, s_LastPos;
  51. static double s_StartSegmentSlope, s_EndSegmentSlope,
  52. s_MovingSegmentSlope,
  53. s_StartSegment_Yorg, s_EndSegment_Yorg,
  54. s_MovingSegment_Yorg; //slope and intercept parameters of lines
  55. bool s_StartPointVertical, s_EndPointVertical,
  56. s_MovingSegmentVertical, s_MovingSegmentHorizontal,
  57. s_StartPointHorizontal, s_EndPointHorizontal; // vertical or
  58. // horizontal line
  59. // indicators
  60. bool s_StartSegmentPresent, s_EndSegmentPresent;
  61. static PICKED_ITEMS_LIST s_ItemsListPicker;
  62. /** Abort function for drag or move track
  63. */
  64. static void Abort_MoveTrack( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
  65. {
  66. PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) aPanel->GetParent();
  67. BOARD * pcb = frame->GetBoard();
  68. pcb->HighLightOFF();
  69. pcb->PopHighLight();
  70. frame->SetCurItem( NULL );
  71. aPanel->SetMouseCapture( NULL, NULL );
  72. // Undo move and redraw trace segments.
  73. for( unsigned jj=0 ; jj < g_DragSegmentList.size(); jj++ )
  74. {
  75. TRACK* track = g_DragSegmentList[jj].m_Track;
  76. g_DragSegmentList[jj].RestoreInitialValues();
  77. track->SetState( IN_EDIT, false );
  78. track->ClearFlags();
  79. }
  80. // Clear the undo picker list:
  81. s_ItemsListPicker.ClearListAndDeleteItems();
  82. EraseDragList();
  83. aPanel->Refresh();
  84. }
  85. // Redraw the moved node according to the mouse cursor position
  86. static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  87. bool aErase )
  88. {
  89. auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions();
  90. wxPoint moveVector;
  91. int tmp = displ_opts->m_DisplayPcbTrackFill;
  92. GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;
  93. displ_opts->m_DisplayPcbTrackFill = false;
  94. #ifndef USE_WX_OVERLAY
  95. aErase = true;
  96. #else
  97. aErase = false;
  98. #endif
  99. // set the new track coordinates
  100. wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();
  101. moveVector = Pos - s_LastPos;
  102. s_LastPos = Pos;
  103. TRACK *track = NULL;
  104. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  105. {
  106. track = g_DragSegmentList[ii].m_Track;
  107. if( aErase )
  108. track->Draw( aPanel, aDC, draw_mode );
  109. if( track->GetFlags() & STARTPOINT )
  110. track->SetStart( track->GetStart() + moveVector );
  111. if( track->GetFlags() & ENDPOINT )
  112. track->SetEnd( track->GetEnd() + moveVector );
  113. if( track->Type() == PCB_VIA_T )
  114. track->SetEnd( track->GetStart() );
  115. track->Draw( aPanel, aDC, draw_mode );
  116. }
  117. displ_opts->m_DisplayPcbTrackFill = tmp;
  118. // Display track length
  119. if( track )
  120. {
  121. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
  122. frame->SetMsgPanel( track );
  123. }
  124. }
  125. /* drawing the track segment movement
  126. * > s_MovingSegmentSlope slope = moving track segment slope
  127. * > s_StartSegmentSlope slope = slope of the segment connected to the start
  128. * point of the moving segment
  129. * > s_EndSegmentSlope slope = slope of the segment connected to the end point
  130. * of the moving segment
  131. *
  132. * moved segment function :
  133. * yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg
  134. *
  135. * segment connected to moved segment's start:
  136. * y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg
  137. *
  138. * segment connected to moved segment's end:
  139. * y2=s_EndSegmentSlope * x + s_EndSegment_Yorg
  140. *
  141. * first intersection point will be located at
  142. * y1=yt ->
  143. *
  144. * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope)
  145. * yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg
  146. * or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg
  147. *
  148. * second intersection point
  149. * y2=yt ->
  150. *
  151. * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope)
  152. * yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg
  153. * or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg
  154. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  155. * !!!!! special attention to vertical segments because
  156. * !!!!! their slope=infinite
  157. * !!!!! intersection point will be calculated using the
  158. * !!!!! segment intersecting it
  159. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  160. *
  161. * Slope parameters are computed once, because they can become undetermined
  162. * when moving segments
  163. * (i.e. when a segment length is 0) and we want keep them constant
  164. */
  165. static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  166. const wxPoint& aPosition, bool aErase )
  167. {
  168. double xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0; // calculated intersection points
  169. double tx1, tx2, ty1, ty2; // temporary storage of points
  170. int dx, dy;
  171. bool update = true;
  172. TRACK* Track;
  173. TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL;
  174. if( g_DragSegmentList.size() == 0 )
  175. return;
  176. /* get the segments :
  177. * from last to first in list are:
  178. * the segment to move
  179. * the segment connected to its end point (if exists)
  180. * the segment connected to its start point (if exists)
  181. */
  182. int ii = g_DragSegmentList.size() - 1;
  183. Track = g_DragSegmentList[ii].m_Track;
  184. if( Track == NULL )
  185. return;
  186. ii--;
  187. if( ii >= 0)
  188. {
  189. if( s_EndSegmentPresent )
  190. {
  191. // Get the segment connected to the end point
  192. tSegmentToEnd = g_DragSegmentList[ii].m_Track;
  193. ii--;
  194. }
  195. if( s_StartSegmentPresent )
  196. {
  197. // Get the segment connected to the start point
  198. if( ii >= 0 )
  199. tSegmentToStart = g_DragSegmentList[ii].m_Track;
  200. }
  201. }
  202. GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;
  203. // Undraw the current moved track segments before modification
  204. #ifndef USE_WX_OVERLAY
  205. // if( erase )
  206. {
  207. Track->Draw( aPanel, aDC, draw_mode );
  208. if( tSegmentToStart )
  209. tSegmentToStart->Draw( aPanel, aDC, draw_mode );
  210. if( tSegmentToEnd )
  211. tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
  212. }
  213. #endif
  214. // Compute the new track segment position
  215. wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();
  216. dx = Pos.x - s_LastPos.x;
  217. dy = Pos.y - s_LastPos.y;
  218. // move the line by dx and dy
  219. tx1 = (double) ( Track->GetStart().x + dx );
  220. ty1 = (double) ( Track->GetStart().y + dy );
  221. tx2 = (double) ( Track->GetEnd().x + dx );
  222. ty2 = (double) ( Track->GetEnd().y + dy );
  223. // recalculate the segments new parameters and intersection points
  224. // only the intercept will change, segment slopes does not change
  225. // because we are moving parallel with is initial state
  226. if( !s_MovingSegmentVertical )
  227. s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 );
  228. if( ( !s_EndPointVertical ) && ( !s_MovingSegmentVertical ) )
  229. {
  230. xi2 = ( s_MovingSegment_Yorg - s_EndSegment_Yorg )
  231. / ( s_EndSegmentSlope - s_MovingSegmentSlope );
  232. }
  233. else
  234. {
  235. if( !s_EndPointVertical )
  236. xi2 = tx2;
  237. else
  238. {
  239. //P1=P2
  240. if( !s_EndPointHorizontal )
  241. xi2 = tx2 - dx;
  242. else
  243. update = false;
  244. }
  245. }
  246. if( !s_MovingSegmentVertical )
  247. yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
  248. else
  249. {
  250. if( !s_EndPointVertical )
  251. yi2 = ( s_EndSegmentSlope * xi2 ) + s_EndSegment_Yorg;
  252. else
  253. {
  254. if( !s_EndPointHorizontal )
  255. update = false;
  256. else
  257. yi2 = ( s_MovingSegmentSlope * xi2 ) + s_MovingSegment_Yorg;
  258. }
  259. }
  260. if( ( !s_StartPointVertical ) && ( !s_MovingSegmentVertical ) )
  261. {
  262. xi1 = ( s_MovingSegment_Yorg - s_StartSegment_Yorg )
  263. / ( s_StartSegmentSlope - s_MovingSegmentSlope );
  264. }
  265. else
  266. {
  267. if( !s_StartPointVertical )
  268. xi1 = tx1;
  269. else
  270. {
  271. //P1=P2
  272. if( !s_StartPointHorizontal )
  273. xi1 = tx1 - dx;
  274. else
  275. {
  276. if( !s_StartPointHorizontal )
  277. update = false;
  278. }
  279. }
  280. }
  281. if( !s_MovingSegmentVertical )
  282. yi1 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
  283. else
  284. {
  285. if( !s_StartPointVertical )
  286. yi1 = ( s_StartSegmentSlope * xi1 ) + s_StartSegment_Yorg;
  287. else
  288. {
  289. if( !s_StartPointHorizontal )
  290. update = false;
  291. else
  292. yi2 = ( s_MovingSegmentSlope * xi1 ) + s_MovingSegment_Yorg;
  293. }
  294. }
  295. // update the segment coordinates (if possible)
  296. if( tSegmentToStart == NULL )
  297. {
  298. xi1 = tx1;
  299. yi1 = ty1;
  300. }
  301. if( tSegmentToEnd == NULL )
  302. {
  303. xi2 = tx2;
  304. yi2 = ty2;
  305. }
  306. if( update )
  307. {
  308. s_LastPos = Pos;
  309. Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) );
  310. Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) );
  311. if( tSegmentToEnd )
  312. {
  313. if( tSegmentToEnd->GetFlags() & STARTPOINT )
  314. tSegmentToEnd->SetStart( Track->GetEnd() );
  315. else
  316. tSegmentToEnd->SetEnd( Track->GetEnd() );
  317. }
  318. if( tSegmentToStart )
  319. {
  320. if( tSegmentToStart->GetFlags() & STARTPOINT )
  321. tSegmentToStart->SetStart( Track->GetStart() );
  322. else
  323. tSegmentToStart->SetEnd( Track->GetStart() );
  324. }
  325. }
  326. Track->Draw( aPanel, aDC, draw_mode );
  327. if( tSegmentToStart )
  328. tSegmentToStart->Draw( aPanel, aDC, draw_mode );
  329. if( tSegmentToEnd )
  330. tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
  331. // Display track length
  332. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
  333. frame->SetMsgPanel( Track );
  334. }
  335. /* Init variables (slope, Y intersect point, flags) for
  336. * Show_Drag_Track_Segment_With_Cte_Slope()
  337. * return true if Ok, false if dragging is not possible
  338. * (2 colinear segments)
  339. */
  340. bool InitialiseDragParameters()
  341. {
  342. double tx1, tx2, ty1, ty2; // temporary storage of points
  343. TRACK* Track;
  344. TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL;
  345. if( g_DragSegmentList.size() == 0 )
  346. return false;
  347. /* get the segments :
  348. * from last to first in list are:
  349. * the segment to move
  350. * the segment connected to its end point (if exists)
  351. * the segment connected to its start point (if exists)
  352. */
  353. int ii = g_DragSegmentList.size() - 1;
  354. Track = g_DragSegmentList[ii].m_Track;
  355. if( Track == NULL )
  356. return false;
  357. ii--;
  358. if( ii >= 0)
  359. {
  360. if( s_EndSegmentPresent )
  361. {
  362. tSegmentToEnd = g_DragSegmentList[ii].m_Track; // Get the segment connected to
  363. // the end point
  364. ii--;
  365. }
  366. if( s_StartSegmentPresent )
  367. {
  368. if( ii >= 0 )
  369. tSegmentToStart = g_DragSegmentList[ii].m_Track; // Get the segment connected to
  370. // the start point
  371. }
  372. }
  373. // would be nice to eliminate collinear segments here, so we don't
  374. // have to deal with that annoying "Unable to drag this segment: two
  375. // collinear segments"
  376. s_StartPointVertical = false;
  377. s_EndPointVertical = false;
  378. s_MovingSegmentVertical = false;
  379. s_StartPointHorizontal = false;
  380. s_EndPointHorizontal = false;
  381. s_MovingSegmentHorizontal = false;
  382. // Init parameters for the starting point of the moved segment
  383. if( tSegmentToStart )
  384. {
  385. if( tSegmentToStart->GetFlags() & ENDPOINT )
  386. {
  387. tx1 = (double) tSegmentToStart->GetStart().x;
  388. ty1 = (double) tSegmentToStart->GetStart().y;
  389. tx2 = (double) tSegmentToStart->GetEnd().x;
  390. ty2 = (double) tSegmentToStart->GetEnd().y;
  391. }
  392. else
  393. {
  394. tx1 = (double) tSegmentToStart->GetEnd().x;
  395. ty1 = (double) tSegmentToStart->GetEnd().y;
  396. tx2 = (double) tSegmentToStart->GetStart().x;
  397. ty2 = (double) tSegmentToStart->GetStart().y;
  398. }
  399. }
  400. else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track
  401. {
  402. tx1 = (double) Track->GetStart().x;
  403. ty1 = (double) Track->GetStart().y;
  404. tx2 = (double) Track->GetEnd().x;
  405. ty2 = (double) Track->GetEnd().y;
  406. RotatePoint( &tx2, &ty2, tx1, ty1, 900 );
  407. }
  408. if( tx1 != tx2 )
  409. {
  410. s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
  411. s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
  412. }
  413. else
  414. {
  415. s_StartPointVertical = true; //signal first segment vertical
  416. }
  417. if( ty1 == ty2 )
  418. {
  419. s_StartPointHorizontal = true;
  420. }
  421. // Init parameters for the ending point of the moved segment
  422. if( tSegmentToEnd )
  423. {
  424. //check if second line is vertical
  425. if( tSegmentToEnd->GetFlags() & STARTPOINT )
  426. {
  427. tx1 = (double) tSegmentToEnd->GetStart().x;
  428. ty1 = (double) tSegmentToEnd->GetStart().y;
  429. tx2 = (double) tSegmentToEnd->GetEnd().x;
  430. ty2 = (double) tSegmentToEnd->GetEnd().y;
  431. }
  432. else
  433. {
  434. tx1 = (double) tSegmentToEnd->GetEnd().x;
  435. ty1 = (double) tSegmentToEnd->GetEnd().y;
  436. tx2 = (double) tSegmentToEnd->GetStart().x;
  437. ty2 = (double) tSegmentToEnd->GetStart().y;
  438. }
  439. }
  440. else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track
  441. {
  442. tx1 = (double) Track->GetEnd().x;
  443. ty1 = (double) Track->GetEnd().y;
  444. tx2 = (double) Track->GetStart().x;
  445. ty2 = (double) Track->GetStart().y;
  446. RotatePoint( &tx2, &ty2, tx1, ty1, -900 );
  447. }
  448. if( tx2 != tx1 )
  449. {
  450. s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
  451. s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
  452. }
  453. else
  454. {
  455. s_EndPointVertical = true; //signal second segment vertical
  456. }
  457. if( ty1 == ty2 )
  458. {
  459. s_EndPointHorizontal = true;
  460. }
  461. // Init parameters for the moved segment
  462. tx1 = (double) Track->GetStart().x;
  463. ty1 = (double) Track->GetStart().y;
  464. tx2 = (double) Track->GetEnd().x;
  465. ty2 = (double) Track->GetEnd().y;
  466. if( tx2 != tx1 )
  467. {
  468. s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
  469. }
  470. else
  471. {
  472. s_MovingSegmentVertical = true; // signal vertical line
  473. }
  474. if( ty1 == ty2 )
  475. {
  476. s_MovingSegmentHorizontal = true;
  477. }
  478. // Test if drag is possible:
  479. if( s_MovingSegmentVertical )
  480. {
  481. if( s_EndPointVertical || s_StartPointVertical )
  482. return false;
  483. }
  484. else
  485. {
  486. if( !s_EndPointVertical && ( s_MovingSegmentSlope == s_EndSegmentSlope ) )
  487. return false;
  488. if( !s_StartPointVertical && ( s_MovingSegmentSlope == s_StartSegmentSlope ) )
  489. return false;
  490. }
  491. return true;
  492. }
  493. void PCB_EDIT_FRAME::StartMoveOneNodeOrSegment( TRACK* aTrack, wxDC* aDC, int aCommand )
  494. {
  495. if( !aTrack )
  496. return;
  497. EraseDragList();
  498. // Change highlighted net: the new one will be highlighted
  499. GetBoard()->PushHighLight();
  500. if( GetBoard()->IsHighLightNetON() )
  501. HighLight( aDC );
  502. PosInit = GetCrossHairPosition();
  503. if( aTrack->Type() == PCB_VIA_T )
  504. {
  505. aTrack->SetFlags( IS_DRAGGED | STARTPOINT | ENDPOINT );
  506. AddSegmentToDragList( aTrack->GetFlags(), aTrack );
  507. if( aCommand != ID_POPUP_PCB_MOVE_TRACK_SEGMENT )
  508. {
  509. Collect_TrackSegmentsToDrag( GetBoard(), aTrack->GetStart(),
  510. aTrack->GetLayerSet(),
  511. aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
  512. }
  513. PosInit = aTrack->GetStart();
  514. }
  515. else
  516. {
  517. STATUS_FLAGS diag = aTrack->IsPointOnEnds( GetCrossHairPosition(), -1 );
  518. wxPoint pos;
  519. switch( aCommand )
  520. {
  521. case ID_POPUP_PCB_MOVE_TRACK_SEGMENT: // Move segment
  522. aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
  523. AddSegmentToDragList( aTrack->GetFlags(), aTrack );
  524. break;
  525. case ID_POPUP_PCB_DRAG_TRACK_SEGMENT: // drag a segment
  526. pos = aTrack->GetStart();
  527. Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
  528. aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
  529. pos = aTrack->GetEnd();
  530. aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
  531. Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
  532. aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
  533. break;
  534. case ID_POPUP_PCB_MOVE_TRACK_NODE: // Drag via or move node
  535. pos = (diag & STARTPOINT) ? aTrack->GetStart() : aTrack->GetEnd();
  536. Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
  537. aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
  538. PosInit = pos;
  539. break;
  540. }
  541. aTrack->SetFlags( IS_DRAGGED );
  542. }
  543. // Prepare the Undo command
  544. ITEM_PICKER picker( aTrack, UR_CHANGED );
  545. picker.SetLink( aTrack->Clone() );
  546. s_ItemsListPicker.PushItem( picker );
  547. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  548. {
  549. TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
  550. picker.SetItem( draggedtrack );
  551. picker.SetLink( draggedtrack->Clone() );
  552. s_ItemsListPicker.PushItem( picker );
  553. draggedtrack = (TRACK*) picker.GetLink();
  554. draggedtrack->SetStatus( 0 );
  555. draggedtrack->ClearFlags();
  556. }
  557. s_LastPos = PosInit;
  558. m_canvas->SetMouseCapture( Show_MoveNode, Abort_MoveTrack );
  559. GetBoard()->SetHighLightNet( aTrack->GetNetCode() );
  560. GetBoard()->HighLightON();
  561. GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
  562. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );
  563. UndrawAndMarkSegmentsToDrag( m_canvas, aDC );
  564. }
  565. void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC )
  566. {
  567. TRACK* TrackToStartPoint = NULL;
  568. TRACK* TrackToEndPoint = NULL;
  569. bool error = false;
  570. if( !track )
  571. return;
  572. // TODO: Use cleanup functions to merge collinear segments if track
  573. // is connected to a collinear segment.
  574. s_StartSegmentPresent = s_EndSegmentPresent = true;
  575. if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
  576. TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );
  577. // Test if more than one segment is connected to this point
  578. if( TrackToStartPoint )
  579. {
  580. TrackToStartPoint->SetState( BUSY, true );
  581. if( ( TrackToStartPoint->Type() == PCB_VIA_T )
  582. || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
  583. error = true;
  584. TrackToStartPoint->SetState( BUSY, false );
  585. }
  586. if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
  587. TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );
  588. // Test if more than one segment is connected to this point
  589. if( TrackToEndPoint )
  590. {
  591. TrackToEndPoint->SetState( BUSY, true );
  592. if( (TrackToEndPoint->Type() == PCB_VIA_T)
  593. || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
  594. error = true;
  595. TrackToEndPoint->SetState( BUSY, false );
  596. }
  597. if( error )
  598. {
  599. DisplayError( this,
  600. _( "Unable to drag this segment: too many segments connected" ) );
  601. return;
  602. }
  603. if( !TrackToStartPoint || ( TrackToStartPoint->Type() != PCB_TRACE_T ) )
  604. s_StartSegmentPresent = false;
  605. if( !TrackToEndPoint || ( TrackToEndPoint->Type() != PCB_TRACE_T ) )
  606. s_EndSegmentPresent = false;
  607. // Change high light net: the new one will be highlighted
  608. GetBoard()->PushHighLight();
  609. if( GetBoard()->IsHighLightNetON() )
  610. HighLight( DC );
  611. EraseDragList();
  612. track->SetFlags( IS_DRAGGED );
  613. if( TrackToStartPoint )
  614. {
  615. STATUS_FLAGS flag = STARTPOINT;
  616. if( track->GetStart() != TrackToStartPoint->GetStart() )
  617. flag = ENDPOINT;
  618. AddSegmentToDragList( flag, TrackToStartPoint );
  619. track->SetFlags( STARTPOINT );
  620. }
  621. if( TrackToEndPoint )
  622. {
  623. STATUS_FLAGS flag = STARTPOINT;
  624. if( track->GetEnd() != TrackToEndPoint->GetStart() )
  625. flag = ENDPOINT;
  626. AddSegmentToDragList( flag, TrackToEndPoint );
  627. track->SetFlags( ENDPOINT );
  628. }
  629. AddSegmentToDragList( track->GetFlags(), track );
  630. UndrawAndMarkSegmentsToDrag( m_canvas, DC );
  631. PosInit = GetCrossHairPosition();
  632. s_LastPos = GetCrossHairPosition();
  633. m_canvas->SetMouseCapture( Show_Drag_Track_Segment_With_Cte_Slope, Abort_MoveTrack );
  634. GetBoard()->SetHighLightNet( track->GetNetCode() );
  635. GetBoard()->HighLightON();
  636. GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );
  637. // Prepare the Undo command
  638. ITEM_PICKER picker( NULL, UR_CHANGED );
  639. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  640. {
  641. TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
  642. picker.SetItem( draggedtrack);
  643. picker.SetLink ( draggedtrack->Clone() );
  644. s_ItemsListPicker.PushItem( picker );
  645. draggedtrack = (TRACK*) picker.GetLink();
  646. draggedtrack->SetStatus( 0 );
  647. draggedtrack->ClearFlags();
  648. }
  649. if( !InitialiseDragParameters() )
  650. {
  651. DisplayError( this, _( "Unable to drag this segment: two collinear segments" ) );
  652. m_canvas->SetMouseCaptureCallback( NULL );
  653. Abort_MoveTrack( m_canvas, DC );
  654. return;
  655. }
  656. }
  657. // Place a dragged (or moved) track segment or via
  658. bool PCB_EDIT_FRAME::PlaceDraggedOrMovedTrackSegment( TRACK* Track, wxDC* DC )
  659. {
  660. int errdrc;
  661. if( Track == NULL )
  662. return false;
  663. int current_net_code = Track->GetNetCode();
  664. // DRC control:
  665. if( Settings().m_legacyDrcOn )
  666. {
  667. errdrc = m_drc->DrcOnCreatingTrack( Track, GetBoard()->m_Track );
  668. if( errdrc == BAD_DRC )
  669. return false;
  670. // Test the dragged segments
  671. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  672. {
  673. errdrc = m_drc->DrcOnCreatingTrack( g_DragSegmentList[ii].m_Track, GetBoard()->m_Track );
  674. if( errdrc == BAD_DRC )
  675. return false;
  676. }
  677. }
  678. // DRC Ok: place track segments
  679. Track->ClearFlags();
  680. Track->SetState( IN_EDIT, false );
  681. // Draw dragged tracks
  682. for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
  683. {
  684. Track = g_DragSegmentList[ii].m_Track;
  685. Track->SetState( IN_EDIT, false );
  686. Track->ClearFlags();
  687. /* Test the connections modified by the move
  688. * (only pad connection must be tested, track connection will be
  689. * tested by TestNetConnection() ) */
  690. LSET layerMask( Track->GetLayer() );
  691. Track->start = GetBoard()->GetPadFast( Track->GetStart(), layerMask );
  692. if( Track->start )
  693. Track->SetState( BEGIN_ONPAD, true );
  694. else
  695. Track->SetState( BEGIN_ONPAD, false );
  696. Track->end = GetBoard()->GetPadFast( Track->GetEnd(), layerMask );
  697. if( Track->end )
  698. Track->SetState( END_ONPAD, true );
  699. else
  700. Track->SetState( END_ONPAD, false );
  701. }
  702. EraseDragList();
  703. SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
  704. s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  705. GetBoard()->PopHighLight();
  706. OnModify();
  707. m_canvas->SetMouseCapture( NULL, NULL );
  708. if( current_net_code > 0 )
  709. TestNetConnection( DC, current_net_code );
  710. m_canvas->Refresh();
  711. return true;
  712. }