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.

1107 lines
34 KiB

14 years ago
14 years ago
14 years ago
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
14 years ago
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
14 years ago
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
13 years ago
13 years ago
14 years ago
14 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
14 years ago
18 years ago
18 years ago
14 years ago
18 years ago
14 years ago
18 years ago
14 years ago
18 years ago
18 years ago
14 years ago
18 years ago
18 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
18 years ago
14 years ago
17 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
14 years ago
14 years ago
13 years ago
14 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 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 editrack.cpp
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <trigo.h>
  32. #include <pcbcommon.h>
  33. #include <wxPcbStruct.h>
  34. #include <colors_selection.h>
  35. #include <pcbnew.h>
  36. #include <drc_stuff.h>
  37. #include <protos.h>
  38. #include <class_board.h>
  39. #include <class_track.h>
  40. #include <class_zone.h>
  41. static void Abort_Create_Track( EDA_DRAW_PANEL* panel, wxDC* DC );
  42. void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  43. const wxPoint& aPosition, bool aErase );
  44. static void ComputeBreakPoint( TRACK* track, int n, wxPoint end );
  45. static void DeleteNullTrackSegments( BOARD* pcb, DLIST<TRACK>& aTrackList );
  46. static void EnsureEndTrackOnPad( D_PAD* Pad );
  47. // A PICKED_ITEMS_LIST to store tracks which are modified/added/deleted
  48. // during a track edition:
  49. static PICKED_ITEMS_LIST s_ItemsListPicker;
  50. /* Function called to abort a track creation
  51. */
  52. static void Abort_Create_Track( EDA_DRAW_PANEL* Panel, wxDC* DC )
  53. {
  54. PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Panel->GetParent();
  55. BOARD* pcb = frame->GetBoard();
  56. TRACK* track = (TRACK*) frame->GetCurItem();
  57. if( track && ( track->Type()==PCB_VIA_T || track->Type()==PCB_TRACE_T ) )
  58. {
  59. // Erase the current drawing
  60. ShowNewTrackWhenMovingCursor( Panel, DC, wxDefaultPosition, false );
  61. if( pcb->IsHighLightNetON() )
  62. frame->HighLight( DC );
  63. pcb->PopHighLight();
  64. if( pcb->IsHighLightNetON() )
  65. pcb->DrawHighLight( Panel, DC, pcb->GetHighLightNetCode() );
  66. frame->ClearMsgPanel();
  67. // Undo pending changes (mainly a lock point creation) and clear the
  68. // undo picker list:
  69. frame->PutDataInPreviousState( &s_ItemsListPicker, false, false );
  70. s_ItemsListPicker.ClearListAndDeleteItems();
  71. // Delete current (new) track
  72. g_CurrentTrackList.DeleteAll();
  73. }
  74. frame->SetCurItem( NULL );
  75. }
  76. /*
  77. * This function starts a new track segment.
  78. * If a new track segment is in progress, ends this current new segment,
  79. * and created a new one.
  80. */
  81. TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
  82. {
  83. TRACK* TrackOnStartPoint = NULL;
  84. LAYER_MSK layerMask = GetLayerMask( GetScreen()->m_Active_Layer );
  85. BOARD_CONNECTED_ITEM* LockPoint;
  86. wxPoint pos = GetCrossHairPosition();
  87. if( aTrack == NULL ) // Starting a new track segment
  88. {
  89. m_canvas->SetMouseCapture( ShowNewTrackWhenMovingCursor, Abort_Create_Track );
  90. // Prepare the undo command info
  91. s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but...
  92. GetBoard()->PushHighLight();
  93. // erase old highlight
  94. if( GetBoard()->IsHighLightNetON() )
  95. HighLight( aDC );
  96. g_CurrentTrackList.PushBack( new TRACK( GetBoard() ) );
  97. g_CurrentTrackSegment->SetFlags( IS_NEW );
  98. GetBoard()->SetHighLightNet( 0 );
  99. // Search for a starting point of the new track, a track or pad
  100. LockPoint = GetBoard()->GetLockPoint( pos, layerMask );
  101. D_PAD* pad = NULL;
  102. if( LockPoint ) // An item (pad or track) is found
  103. {
  104. if( LockPoint->Type() == PCB_PAD_T )
  105. {
  106. pad = (D_PAD*) LockPoint;
  107. // A pad is found: put the starting point on pad center
  108. pos = pad->GetPosition();
  109. GetBoard()->SetHighLightNet( pad->GetNet() );
  110. }
  111. else // A track segment is found
  112. {
  113. TrackOnStartPoint = (TRACK*) LockPoint;
  114. GetBoard()->SetHighLightNet( TrackOnStartPoint->GetNet() );
  115. GetBoard()->CreateLockPoint( pos, TrackOnStartPoint, &s_ItemsListPicker );
  116. }
  117. }
  118. else
  119. {
  120. // Not a starting point, but a filled zone area can exist. This is also a
  121. // good starting point.
  122. ZONE_CONTAINER* zone;
  123. zone = GetBoard()->HitTestForAnyFilledArea( pos,
  124. GetScreen()-> m_Active_Layer,
  125. GetScreen()-> m_Active_Layer,
  126. -1 );
  127. if( zone )
  128. GetBoard()->SetHighLightNet( zone->GetNet() );
  129. }
  130. DBG( g_CurrentTrackList.VerifyListIntegrity() );
  131. BuildAirWiresTargetsList( LockPoint, wxPoint( 0, 0 ), true );
  132. DBG( g_CurrentTrackList.VerifyListIntegrity() );
  133. GetBoard()->HighLightON();
  134. GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
  135. // Display info about track Net class, and init track and vias sizes:
  136. g_CurrentTrackSegment->SetNet( GetBoard()->GetHighLightNetCode() );
  137. GetBoard()->SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() );
  138. g_CurrentTrackSegment->SetLayer( GetScreen()->m_Active_Layer );
  139. g_CurrentTrackSegment->SetWidth( GetBoard()->GetCurrentTrackWidth() );
  140. if( GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
  141. {
  142. if( TrackOnStartPoint && TrackOnStartPoint->Type() == PCB_TRACE_T )
  143. g_CurrentTrackSegment->SetWidth( TrackOnStartPoint->GetWidth());
  144. }
  145. g_CurrentTrackSegment->SetStart( pos );
  146. g_CurrentTrackSegment->SetEnd( pos );
  147. if( pad )
  148. {
  149. g_CurrentTrackSegment->m_PadsConnected.push_back( pad );
  150. // Useful to display track length, if the pad has a die length:
  151. g_CurrentTrackSegment->SetState( BEGIN_ONPAD, true );
  152. g_CurrentTrackSegment->start = pad;
  153. }
  154. if( g_TwoSegmentTrackBuild )
  155. {
  156. // Create 2nd segment
  157. g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() );
  158. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  159. g_CurrentTrackSegment->start = g_FirstTrackSegment;
  160. g_FirstTrackSegment->end = g_CurrentTrackSegment;
  161. g_FirstTrackSegment->SetState( BEGIN_ONPAD | END_ONPAD, false );
  162. }
  163. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  164. SetMsgPanel( g_CurrentTrackSegment );
  165. SetCurItem( g_CurrentTrackSegment, false );
  166. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  167. if( g_Drc_On )
  168. {
  169. if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
  170. {
  171. return g_CurrentTrackSegment;
  172. }
  173. }
  174. }
  175. else // Track in progress : segment coordinates are updated by ShowNewTrackWhenMovingCursor.
  176. {
  177. // Test for a D.R.C. error:
  178. if( g_Drc_On )
  179. {
  180. if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
  181. return NULL;
  182. // We must handle 2 segments
  183. if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->Back() )
  184. {
  185. if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment->Back(), GetBoard()->m_Track ) )
  186. return NULL;
  187. }
  188. }
  189. /* Current track is Ok: current segment is kept, and a new one is
  190. * created unless the current segment is null, or 2 last are null
  191. * if this is a 2 segments track build.
  192. */
  193. bool CanCreateNewSegment = true;
  194. if( !g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() )
  195. CanCreateNewSegment = false;
  196. if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull()
  197. && g_CurrentTrackSegment->Back()
  198. && g_CurrentTrackSegment->Back()->IsNull() )
  199. CanCreateNewSegment = false;
  200. if( CanCreateNewSegment )
  201. {
  202. // Erase old track on screen
  203. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  204. ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
  205. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  206. if( g_Raccord_45_Auto )
  207. Add45DegreeSegment( aDC );
  208. TRACK* previousTrack = g_CurrentTrackSegment;
  209. TRACK* newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
  210. g_CurrentTrackList.PushBack( newTrack );
  211. newTrack->SetFlags( IS_NEW );
  212. newTrack->SetState( BEGIN_ONPAD | END_ONPAD, false );
  213. D_PAD* pad = GetBoard()->GetPad( previousTrack, FLG_END );
  214. if( pad )
  215. {
  216. newTrack->m_PadsConnected.push_back( pad );
  217. previousTrack->m_PadsConnected.push_back( pad );
  218. }
  219. newTrack->start = previousTrack->end;
  220. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  221. newTrack->SetStart( newTrack->GetEnd() );
  222. newTrack->SetLayer( GetScreen()->m_Active_Layer );
  223. if( !GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
  224. newTrack->SetWidth( GetBoard()->GetCurrentTrackWidth() );
  225. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  226. // Show the new position
  227. ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
  228. }
  229. }
  230. SetCurItem( g_CurrentTrackSegment, false );
  231. return g_CurrentTrackSegment;
  232. }
  233. bool PCB_EDIT_FRAME::Add45DegreeSegment( wxDC* aDC )
  234. {
  235. int dx0, dy0, dx1, dy1;
  236. if( g_CurrentTrackList.GetCount() < 2 )
  237. return false; // There must be 2 segments.
  238. TRACK* curTrack = g_CurrentTrackSegment;
  239. TRACK* prevTrack = curTrack->Back();
  240. // Test if we have 2 consecutive track segments ( not via ) to connect.
  241. if( curTrack->Type() != PCB_TRACE_T || prevTrack->Type() != PCB_TRACE_T )
  242. {
  243. return false;
  244. }
  245. int segm_step_45 = KiROUND( GetScreen()->GetGridSize().x / 2 );
  246. if( segm_step_45 < ( curTrack->GetWidth() * 2 ) )
  247. segm_step_45 = curTrack->GetWidth() * 2;
  248. // Test if the segments are horizontal or vertical.
  249. dx0 = prevTrack->GetEnd().x - prevTrack->GetStart().x;
  250. dy0 = prevTrack->GetEnd().y - prevTrack->GetStart().y;
  251. dx1 = curTrack->GetEnd().x - curTrack->GetStart().x;
  252. dy1 = curTrack->GetEnd().y - curTrack->GetStart().y;
  253. // Segments should have a min length.
  254. if( std::max( abs( dx0 ), abs( dy0 ) ) < ( segm_step_45 * 2 ) )
  255. return false;
  256. if( std::max( abs( dx1 ), abs( dy1 ) ) < ( segm_step_45 * 2 ) )
  257. return false;
  258. // Create a new segment and connect it with the previous 2 segments.
  259. TRACK* newTrack = (TRACK*)curTrack->Clone();
  260. newTrack->SetStart( prevTrack->GetEnd() );
  261. newTrack->SetEnd( curTrack->GetStart() );
  262. if( dx0 == 0 ) // Previous segment is Vertical
  263. {
  264. if( dy1 != 0 ) // 2 segments are not 90 degrees.
  265. {
  266. delete newTrack;
  267. return false;
  268. }
  269. /* Calculate coordinates the connection point.
  270. * The new segment connects the 1st vertical segment and the 2nd
  271. * horizontal segment.
  272. */
  273. if( dy0 > 0 )
  274. newTrack->SetStart( wxPoint(newTrack->GetStart().x, newTrack->GetStart().y -segm_step_45) );
  275. else
  276. newTrack->SetStart( wxPoint(newTrack->GetStart().x, newTrack->GetStart().y + segm_step_45) );
  277. if( dx1 > 0 )
  278. newTrack->SetEnd( wxPoint(newTrack->GetEnd().x + segm_step_45, newTrack->GetEnd().y) );
  279. else
  280. newTrack->SetEnd( wxPoint(newTrack->GetEnd().x - segm_step_45, newTrack->GetEnd().y) );
  281. if( g_Drc_On && BAD_DRC == m_drc->Drc( curTrack, GetBoard()->m_Track ) )
  282. {
  283. delete newTrack;
  284. return false;
  285. }
  286. prevTrack->SetEnd( newTrack->GetStart());
  287. curTrack->SetStart( newTrack->GetEnd());
  288. g_CurrentTrackList.Insert( newTrack, curTrack );
  289. return true;
  290. }
  291. if( dy0 == 0 ) // Previous segment is horizontal
  292. {
  293. if( dx1 != 0 ) // 2 segments are not 90 degrees
  294. {
  295. delete newTrack;
  296. return false;
  297. }
  298. /* Calculate the coordinates of the point of connection:
  299. * A new segment has been created, connecting segment 1
  300. * (horizontal) and segment 2 (vertical)
  301. */
  302. if( dx0 > 0 )
  303. newTrack->SetStart( wxPoint(newTrack->GetStart().x - segm_step_45 , newTrack->GetStart().y));
  304. else
  305. newTrack->SetStart( wxPoint(newTrack->GetStart().x + segm_step_45, newTrack->GetStart().y) );
  306. if( dy1 > 0 )
  307. newTrack->SetEnd( wxPoint(newTrack->GetEnd().x, newTrack->GetEnd().y + segm_step_45) );
  308. else
  309. newTrack->SetEnd( wxPoint(newTrack->GetEnd().x, newTrack->GetEnd().y - segm_step_45) );
  310. if( g_Drc_On && BAD_DRC==m_drc->Drc( newTrack, GetBoard()->m_Track ) )
  311. {
  312. delete newTrack;
  313. return false;
  314. }
  315. prevTrack->SetEnd( newTrack->GetStart());
  316. curTrack->SetStart( newTrack->GetEnd());
  317. g_CurrentTrackList.Insert( newTrack, curTrack );
  318. return true;
  319. }
  320. return false;
  321. }
  322. bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
  323. {
  324. LAYER_MSK layerMask = GetLayerMask( GetScreen()->m_Active_Layer );
  325. if( aTrack == NULL )
  326. return false;
  327. if( g_Drc_On && BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
  328. return false;
  329. // Saving the coordinate of end point of the trace
  330. wxPoint pos = g_CurrentTrackSegment->GetEnd();
  331. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  332. if( Begin_Route( aTrack, aDC ) == NULL )
  333. return false;
  334. ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, true );
  335. ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
  336. TraceAirWiresToTargets( aDC );
  337. /* cleanup
  338. * if( g_CurrentTrackSegment->Next() != NULL )
  339. * {
  340. * delete g_CurrentTrackSegment->Next();
  341. * g_CurrentTrackSegment->SetNext( NULL );
  342. * }
  343. */
  344. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  345. /* The track here is now chained to the list of track segments.
  346. * It must be seen in the area of net
  347. * As close as possible to the segment base (or end), because
  348. * This helps to reduce the computing time */
  349. // Attaching the end point of the new track to a pad or a track
  350. BOARD_CONNECTED_ITEM* LockPoint = GetBoard()->GetLockPoint( pos, layerMask );
  351. if( LockPoint )
  352. {
  353. if( LockPoint->Type() == PCB_PAD_T ) // End of track is on a pad.
  354. {
  355. EnsureEndTrackOnPad( (D_PAD*) LockPoint );
  356. }
  357. else // If end point of is on a different track,
  358. // creates a lock point if not exists
  359. {
  360. // Creates a lock point, if not already exists:
  361. wxPoint hp = g_CurrentTrackSegment->GetEnd();
  362. LockPoint = GetBoard()->CreateLockPoint( hp, (TRACK*) LockPoint, &s_ItemsListPicker );
  363. g_CurrentTrackSegment->SetEnd(hp);
  364. }
  365. }
  366. // Delete null length segments:
  367. DeleteNullTrackSegments( GetBoard(), g_CurrentTrackList );
  368. // Insert new segments if they exist.
  369. // g_FirstTrackSegment can be NULL on a double click on the starting point
  370. if( g_FirstTrackSegment != NULL )
  371. {
  372. int netcode = g_FirstTrackSegment->GetNet();
  373. TRACK* firstTrack = g_FirstTrackSegment;
  374. int newCount = g_CurrentTrackList.GetCount();
  375. // Put entire new current segment list in BOARD, and prepare undo command
  376. TRACK* track;
  377. TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( GetBoard() );
  378. while( ( track = g_CurrentTrackList.PopFront() ) != NULL )
  379. {
  380. ITEM_PICKER picker( track, UR_NEW );
  381. s_ItemsListPicker.PushItem( picker );
  382. GetBoard()->m_Track.Insert( track, insertBeforeMe );
  383. }
  384. TraceAirWiresToTargets( aDC );
  385. int i = 0;
  386. for( track = firstTrack; track && i < newCount; ++i, track = track->Next() )
  387. {
  388. track->ClearFlags();
  389. track->SetState( BUSY, false );
  390. }
  391. // delete the old track, if it exists and is redundant
  392. if( g_AutoDeleteOldTrack )
  393. {
  394. EraseRedundantTrack( aDC, firstTrack, newCount, &s_ItemsListPicker );
  395. }
  396. SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
  397. s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
  398. // compute the new ratsnest
  399. TestNetConnection( aDC, netcode );
  400. OnModify();
  401. SetMsgPanel( GetBoard() );
  402. // Redraw the entire new track.
  403. DrawTraces( m_canvas, aDC, firstTrack, newCount, GR_OR );
  404. }
  405. wxASSERT( g_FirstTrackSegment == NULL );
  406. wxASSERT( g_CurrentTrackSegment == NULL );
  407. wxASSERT( g_CurrentTrackList.GetCount() == 0 );
  408. if( GetBoard()->IsHighLightNetON() )
  409. HighLight( aDC );
  410. GetBoard()->PopHighLight();
  411. if( GetBoard()->IsHighLightNetON() )
  412. GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
  413. m_canvas->SetMouseCapture( NULL, NULL );
  414. SetCurItem( NULL );
  415. return true;
  416. }
  417. TRACK* LocateIntrusion( TRACK* listStart, TRACK* aTrack, LAYER_NUM aLayer, const wxPoint& aRef )
  418. {
  419. int net = aTrack->GetNet();
  420. int width = aTrack->GetWidth();
  421. TRACK* found = NULL;
  422. for( TRACK* track = listStart; track; track = track->Next() )
  423. {
  424. if( track->Type() == PCB_TRACE_T ) // skip vias
  425. {
  426. if( track->GetState( BUSY | IS_DELETED ) )
  427. continue;
  428. if( aLayer != track->GetLayer() )
  429. continue;
  430. if( track->GetNet() == net )
  431. continue;
  432. // TRACK::HitTest
  433. int dist = (width + track->GetWidth()) / 2 + aTrack->GetClearance( track );
  434. if( !TestSegmentHit( aRef, track->GetStart(), track->GetEnd(), dist ) )
  435. continue;
  436. found = track;
  437. // prefer intrusions from the side, not the end
  438. wxPoint pos = aRef - track->GetStart();
  439. wxPoint vec = track->GetEnd() - track->GetStart();
  440. double tmp = (double) pos.x * vec.x + (double) pos.y * vec.y;
  441. if( tmp >= 0 && tmp <= (double) vec.x * vec.x + (double) vec.y * vec.y )
  442. break;
  443. }
  444. }
  445. return found;
  446. }
  447. /**
  448. * Function PushTrack
  449. * detects if the mouse is pointing into a conflicting track.
  450. * In this case, it tries to push the new track out of the conflicting track's
  451. * clearance zone. This gives us a cheap mechanism for drawing tracks that
  452. * tightly follow others, independent of grid settings.
  453. *
  454. * KNOWN BUGS:
  455. * - we do the same sort of search and calculation up to three times:
  456. * 1) we search for magnetic hits (in controle.cpp)
  457. * 2) we check if there's a DRC violation in the making (also controle.cpp)
  458. * 3) we try to fix the DRC violation (here)
  459. * - if we have a magnetic hit and a DRC violation at the same time, we choose
  460. * the magnetic hit instead of solving the violation
  461. * - should locate conflicting tracks also when we're crossing over them
  462. */
  463. static void PushTrack( EDA_DRAW_PANEL* panel )
  464. {
  465. PCB_SCREEN* screen = (PCB_SCREEN*) panel->GetParent()->GetScreen();
  466. BOARD* pcb = ( (PCB_BASE_FRAME*) (panel->GetParent()) )->GetBoard();
  467. wxPoint cursor = panel->GetParent()->GetCrossHairPosition();
  468. wxPoint cv, vec, n;
  469. TRACK* track = g_CurrentTrackSegment;
  470. TRACK* other;
  471. double det;
  472. int dist;
  473. double f;
  474. other = LocateIntrusion( pcb->m_Track, track, screen->m_Active_Layer, panel->GetParent()->RefPos( true ) );
  475. // are we currently pointing into a conflicting trace ?
  476. if( !other )
  477. return;
  478. if( other->GetNet() == track->GetNet() )
  479. return;
  480. cv = cursor - other->GetStart();
  481. vec = other->GetEnd() - other->GetStart();
  482. det = (double) cv.x * vec.y - (double) cv.y * vec.x;
  483. // cursor is right at the center of the old track
  484. if( !det )
  485. return;
  486. dist = (track->GetWidth() + 1) / 2 + (other->GetWidth() + 1) / 2 + track->GetClearance( other ) + 2;
  487. /*
  488. * DRC wants >, so +1.
  489. * We may have a quantization error of 1/sqrt(2), so +1 again.
  490. */
  491. // Vector "n" is perpendicular to "other", pointing towards the cursor.
  492. if( det > 0 )
  493. {
  494. n.x = vec.y;
  495. n.y = -vec.x;
  496. }
  497. else
  498. {
  499. n.x = -vec.y;
  500. n.y = vec.x;
  501. }
  502. f = dist / hypot( double(n.x), double(n.y) );
  503. n.x = KiROUND( f * n.x );
  504. n.y = KiROUND( f * n.y );
  505. wxPoint hp = track->GetEnd();
  506. Project( &hp, cursor, other );
  507. track->SetEnd( hp + n );
  508. }
  509. //Helper function: Draws Via circle and Via Clearance circle.
  510. inline void DrawViaCirclesWhenEditingNewTrack( EDA_RECT* aPanelClipBox,
  511. wxDC* aDC, const wxPoint& aPos,
  512. int aViaRadius,
  513. int aViaRadiusWithClearence,
  514. EDA_COLOR_T aColor)
  515. {
  516. //Current viasize clearence circle
  517. GRCircle( aPanelClipBox, aDC, aPos.x, aPos.y, aViaRadiusWithClearence, aColor );
  518. //Current viasize circle
  519. GRCircle( aPanelClipBox, aDC, aPos.x, aPos.y, aViaRadius, aColor );
  520. }
  521. /* Redraw the current track being created when the mouse cursor is moved
  522. */
  523. void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  524. bool aErase )
  525. {
  526. // DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  527. PCB_SCREEN* screen = (PCB_SCREEN*) aPanel->GetScreen();
  528. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
  529. bool Track_fill_copy = DisplayOpt.DisplayPcbTrackFill;
  530. DisplayOpt.DisplayPcbTrackFill = true;
  531. TRACE_CLEARANCE_DISPLAY_MODE_T showTrackClearanceMode = DisplayOpt.ShowTrackClearanceMode;
  532. if ( g_FirstTrackSegment == NULL )
  533. return;
  534. NETCLASS* netclass = g_FirstTrackSegment->GetNetClass();
  535. if( showTrackClearanceMode != DO_NOT_SHOW_CLEARANCE )
  536. DisplayOpt.ShowTrackClearanceMode = SHOW_CLEARANCE_ALWAYS;
  537. // Values to Via circle
  538. int boardViaRadius = frame->GetBoard()->GetCurrentViaSize()/2;
  539. int viaRadiusWithClearence = boardViaRadius+netclass->GetClearance();
  540. EDA_RECT* panelClipBox=aPanel->GetClipBox();
  541. #ifndef USE_WX_OVERLAY
  542. // Erase old track
  543. if( aErase )
  544. {
  545. DrawTraces( aPanel, aDC, g_FirstTrackSegment, g_CurrentTrackList.GetCount(), GR_XOR );
  546. frame->TraceAirWiresToTargets( aDC );
  547. if( showTrackClearanceMode >= SHOW_CLEARANCE_NEW_TRACKS_AND_VIA_AREAS )
  548. {
  549. EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( g_CurrentTrackSegment->GetLayer() );
  550. DrawViaCirclesWhenEditingNewTrack( panelClipBox, aDC, g_CurrentTrackSegment->GetEnd(),
  551. boardViaRadius, viaRadiusWithClearence, color);
  552. }
  553. }
  554. #endif
  555. // MacOSX seems to need this.
  556. if( g_CurrentTrackList.GetCount() == 0 )
  557. return;
  558. // Set track parameters, that can be modified while creating the track
  559. g_CurrentTrackSegment->SetLayer( screen->m_Active_Layer );
  560. if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
  561. g_CurrentTrackSegment->SetWidth( frame->GetBoard()->GetCurrentTrackWidth() );
  562. if( g_TwoSegmentTrackBuild )
  563. {
  564. TRACK* previous_track = g_CurrentTrackSegment->Back();
  565. if( previous_track && previous_track->Type()==PCB_TRACE_T )
  566. {
  567. previous_track->SetLayer( screen->m_Active_Layer );
  568. if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
  569. previous_track->SetWidth( frame->GetBoard()->GetCurrentTrackWidth() );
  570. }
  571. }
  572. if( g_Track_45_Only_Allowed )
  573. {
  574. if( g_TwoSegmentTrackBuild )
  575. {
  576. g_CurrentTrackSegment->SetEnd( frame->GetCrossHairPosition() );
  577. if( g_Drc_On )
  578. PushTrack( aPanel );
  579. ComputeBreakPoint( g_CurrentTrackSegment,
  580. g_CurrentTrackList.GetCount(),
  581. g_CurrentTrackSegment->GetEnd() );
  582. }
  583. else
  584. {
  585. /* Calculate of the end of the path for the permitted directions:
  586. * horizontal, vertical or 45 degrees.
  587. */
  588. wxPoint hp = g_CurrentTrackSegment->GetEnd();
  589. CalculateSegmentEndPoint( frame->GetCrossHairPosition(),
  590. g_CurrentTrackSegment->GetStart().x,
  591. g_CurrentTrackSegment->GetStart().y,
  592. &hp.x,
  593. &hp.y );
  594. g_CurrentTrackSegment->SetEnd(hp);
  595. }
  596. }
  597. else // Here the angle is arbitrary
  598. {
  599. g_CurrentTrackSegment->SetEnd( frame->GetCrossHairPosition() );
  600. }
  601. // Redraw the new track
  602. DBG( g_CurrentTrackList.VerifyListIntegrity(); );
  603. DrawTraces( aPanel, aDC, g_FirstTrackSegment, g_CurrentTrackList.GetCount(), GR_XOR );
  604. if( showTrackClearanceMode >= SHOW_CLEARANCE_NEW_TRACKS_AND_VIA_AREAS )
  605. {
  606. EDA_COLOR_T color = g_ColorsSettings.GetLayerColor(g_CurrentTrackSegment->GetLayer());
  607. //Via diameter must have taken what we are using, rather than netclass value.
  608. DrawViaCirclesWhenEditingNewTrack( panelClipBox, aDC, g_CurrentTrackSegment->GetEnd(),
  609. boardViaRadius, viaRadiusWithClearence, color);
  610. }
  611. /* Display info about current segment and the full new track:
  612. * Choose the interesting segment: because we are using a 2 segments step,
  613. * the last segment can be null, and the previous segment can be the
  614. * interesting segment.
  615. */
  616. TRACK* isegm = g_CurrentTrackSegment;
  617. if( isegm->GetLength() == 0 && g_CurrentTrackSegment->Back() )
  618. isegm = g_CurrentTrackSegment->Back();
  619. // display interesting segment info only:
  620. frame->SetMsgPanel( isegm );
  621. // Display current track length (on board) and the the actual track len
  622. // if there is an extra len due to the len die on the starting pad (if any)
  623. double trackLen = 0.0;
  624. double lenPadToDie = 0.0;
  625. wxString msg;
  626. // If the starting point is on a pad, add current track length+ length die
  627. if( g_FirstTrackSegment->GetState( BEGIN_ONPAD ) )
  628. {
  629. D_PAD * pad = (D_PAD *) g_FirstTrackSegment->start;
  630. lenPadToDie = (double) pad->GetPadToDieLength();
  631. }
  632. // calculate track len on board:
  633. for( TRACK* track = g_FirstTrackSegment; track; track = track->Next() )
  634. trackLen += track->GetLength();
  635. msg = frame->LengthDoubleToString( trackLen );
  636. frame->AppendMsgPanel( _( "Track Len" ), msg, DARKCYAN );
  637. if( lenPadToDie != 0 ) // display the track len on board and the actual track len
  638. {
  639. frame->AppendMsgPanel( _( "Full Len" ), msg, DARKCYAN );
  640. msg = frame->LengthDoubleToString( trackLen+lenPadToDie );
  641. frame->AppendMsgPanel( _( "Pad to die" ), msg, DARKCYAN );
  642. }
  643. // Add current segments count (number of segments in this new track):
  644. msg.Printf( wxT( "%d" ), g_CurrentTrackList.GetCount() );
  645. frame->AppendMsgPanel( _( "Segs Count" ), msg, DARKCYAN );
  646. DisplayOpt.ShowTrackClearanceMode = showTrackClearanceMode;
  647. DisplayOpt.DisplayPcbTrackFill = Track_fill_copy;
  648. frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->GetEnd(), false );
  649. frame->TraceAirWiresToTargets( aDC );
  650. }
  651. /* Determine the coordinate to advanced the the current segment
  652. * in 0, 90, or 45 degrees, depending on position of origin and \a aPosition.
  653. */
  654. void CalculateSegmentEndPoint( const wxPoint& aPosition, int ox, int oy, int* fx, int* fy )
  655. {
  656. int deltax, deltay, angle;
  657. deltax = aPosition.x - ox;
  658. deltay = aPosition.y - oy;
  659. deltax = abs( deltax );
  660. deltay = abs( deltay );
  661. angle = 45;
  662. if( deltax >= deltay )
  663. {
  664. if( deltax == 0 )
  665. angle = 0;
  666. else if( ( (deltay << 6 ) / deltax ) < 26 )
  667. angle = 0;
  668. }
  669. else
  670. {
  671. angle = 45;
  672. if( deltay == 0 )
  673. angle = 90;
  674. else if( ( (deltax << 6 ) / deltay ) < 26 )
  675. angle = 90;
  676. }
  677. switch( angle )
  678. {
  679. case 0:
  680. *fx = aPosition.x;
  681. *fy = oy;
  682. break;
  683. case 45:
  684. deltax = std::min( deltax, deltay );
  685. deltay = deltax;
  686. // Recalculate the signs for deltax and deltaY.
  687. if( ( aPosition.x - ox ) < 0 )
  688. deltax = -deltax;
  689. if( ( aPosition.y - oy ) < 0 )
  690. deltay = -deltay;
  691. *fx = ox + deltax;
  692. *fy = oy + deltay;
  693. break;
  694. case 90:
  695. *fx = ox;
  696. *fy = aPosition.y;
  697. break;
  698. }
  699. }
  700. /**
  701. * Compute new track angle based on previous track.
  702. */
  703. void ComputeBreakPoint( TRACK* track, int SegmentCount, wxPoint end )
  704. {
  705. int iDx = 0;
  706. int iDy = 0;
  707. int iAngle = 0;
  708. if( SegmentCount <= 0 )
  709. return;
  710. if( track == NULL )
  711. return;
  712. TRACK* newTrack = track;
  713. track = track->Back();
  714. SegmentCount--;
  715. if( track )
  716. {
  717. iDx = end.x - track->GetStart().x;
  718. iDy = end.y - track->GetStart().y;
  719. iDx = abs( iDx );
  720. iDy = abs( iDy );
  721. }
  722. TRACK* lastTrack = track ? track->Back() : NULL;
  723. if( lastTrack )
  724. {
  725. if(( (lastTrack->GetEnd().x == lastTrack->GetStart().x)
  726. || (lastTrack->GetEnd().y == lastTrack->GetStart().y) )
  727. && !g_Alternate_Track_Posture)
  728. {
  729. iAngle = 45;
  730. }
  731. }
  732. else
  733. {
  734. if( g_Alternate_Track_Posture )
  735. {
  736. iAngle = 45;
  737. }
  738. }
  739. if( iAngle == 0 )
  740. {
  741. if( iDx >= iDy )
  742. iAngle = 0;
  743. else
  744. iAngle = 90;
  745. }
  746. if( track == NULL )
  747. iAngle = -1;
  748. switch( iAngle )
  749. {
  750. case -1:
  751. break;
  752. case 0:
  753. if( ( end.x - track->GetStart().x ) < 0 )
  754. track->SetEnd(wxPoint( end.x + iDy, track->GetStart().y));
  755. else
  756. track->SetEnd(wxPoint( end.x - iDy, track->GetStart().y));
  757. break;
  758. case 45:
  759. iDx = std::min( iDx, iDy );
  760. iDy = iDx;
  761. // Recalculate the signs for deltax and deltaY.
  762. if( ( end.x - track->GetStart().x ) < 0 )
  763. iDx = -iDx;
  764. if( ( end.y - track->GetStart().y ) < 0 )
  765. iDy = -iDy;
  766. track->SetEnd(wxPoint(track->GetStart().x + iDx, track->GetStart().y + iDy));
  767. break;
  768. case 90:
  769. if( ( end.y - track->GetStart().y ) < 0 )
  770. track->SetEnd(wxPoint(track->GetStart().x , end.y + iDx));
  771. else
  772. track->SetEnd(wxPoint(track->GetStart().x , end.y - iDx));
  773. break;
  774. }
  775. if( track )
  776. {
  777. if( track->IsNull() )
  778. track->SetEnd( end );
  779. newTrack->SetStart( track->GetEnd() );
  780. }
  781. newTrack->SetEnd( end );
  782. }
  783. /* Delete track segments which have len = 0 after creating a new track
  784. * return a pointer on the first segment (start of track list)
  785. */
  786. void DeleteNullTrackSegments( BOARD* pcb, DLIST<TRACK>& aTrackList )
  787. {
  788. if( aTrackList.GetCount() == 0 )
  789. return;
  790. TRACK* track = aTrackList.GetFirst();
  791. TRACK* firsttrack = track;
  792. TRACK* oldtrack;
  793. BOARD_CONNECTED_ITEM* LockPoint = track->start;
  794. while( track != NULL )
  795. {
  796. oldtrack = track;
  797. track = track->Next();
  798. if( !oldtrack->IsNull() )
  799. {
  800. continue;
  801. }
  802. // NULL segment, delete it
  803. if( firsttrack == oldtrack )
  804. firsttrack = track;
  805. delete aTrackList.Remove( oldtrack );
  806. }
  807. if( aTrackList.GetCount() == 0 )
  808. return; // all the new track segments have been deleted
  809. // we must set the pointers on connected items and the connection status
  810. oldtrack = track = firsttrack;
  811. firsttrack->start = NULL;
  812. while( track != NULL )
  813. {
  814. oldtrack = track;
  815. track = track->Next();
  816. oldtrack->end = track;
  817. if( track )
  818. track->start = oldtrack;
  819. oldtrack->SetStatus( 0 );
  820. }
  821. firsttrack->start = LockPoint;
  822. if( LockPoint && LockPoint->Type()==PCB_PAD_T )
  823. firsttrack->SetState( BEGIN_ONPAD, true );
  824. track = firsttrack;
  825. while( track != NULL )
  826. {
  827. TRACK* next_track = track->Next();
  828. LockPoint = pcb->GetPad( track, FLG_END );
  829. if( LockPoint )
  830. {
  831. track->end = LockPoint;
  832. track->SetState( END_ONPAD, true );
  833. if( next_track )
  834. {
  835. next_track->start = LockPoint;
  836. next_track->SetState( BEGIN_ONPAD, true );
  837. }
  838. }
  839. track = next_track;
  840. }
  841. }
  842. /* Ensure the end point of g_CurrentTrackSegment is on the pad "Pad"
  843. * if no, create a new track segment if necessary
  844. * and move current (or new) end segment on pad
  845. */
  846. void EnsureEndTrackOnPad( D_PAD* aPad )
  847. {
  848. if( g_CurrentTrackSegment->GetEnd() == aPad->GetPosition() ) // Ok !
  849. {
  850. g_CurrentTrackSegment->end = aPad;
  851. g_CurrentTrackSegment->SetState( END_ONPAD, true );
  852. return;
  853. }
  854. TRACK* lasttrack = g_CurrentTrackSegment;
  855. if( !g_CurrentTrackSegment->IsNull() )
  856. {
  857. // Must create a new segment, from track end to pad center
  858. g_CurrentTrackList.PushBack( (TRACK*)lasttrack->Clone() );
  859. lasttrack->end = g_CurrentTrackSegment;
  860. }
  861. g_CurrentTrackSegment->SetEnd( aPad->GetPosition() );
  862. g_CurrentTrackSegment->SetState( END_ONPAD, false );
  863. g_CurrentTrackSegment->end = aPad;
  864. g_CurrentTrackSegment->SetState( END_ONPAD, true );
  865. }