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.

914 lines
28 KiB

14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2010 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file clean.cpp
  27. * @brief functions to clean tracks: remove null lenght and redundant segments
  28. */
  29. #include "fctsys.h"
  30. #include "class_drawpanel.h"
  31. #include "pcbcommon.h"
  32. #include "wxPcbStruct.h"
  33. #include "pcbnew.h"
  34. #include "class_board.h"
  35. #include "class_track.h"
  36. /* local functions : */
  37. static void clean_segments( PCB_EDIT_FRAME* aFrame );
  38. static void clean_vias( BOARD* aPcb );
  39. static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame );
  40. static TRACK* MergeColinearSegmentIfPossible( BOARD* aPcb, TRACK* aTrackRef,
  41. TRACK* aCandidate, int aEndType );
  42. static void CleanupTracks( PCB_EDIT_FRAME* aFrame,
  43. bool aCleanVias, bool aMergeSegments,
  44. bool aDeleteUnconnectedSegm, bool aConnectToPads );
  45. #include "dialog_cleaning_options.h"
  46. #define CONN2PAD_ENBL
  47. #ifdef CONN2PAD_ENBL
  48. static void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame );
  49. static void ConnectDanglingEndToVia( BOARD* pcb );
  50. #endif
  51. /* Install the track operation dialog frame
  52. */
  53. void PCB_EDIT_FRAME::Clean_Pcb( wxDC* DC )
  54. {
  55. DIALOG_CLEANING_OPTIONS::connectToPads = false;
  56. DIALOG_CLEANING_OPTIONS dlg( this );
  57. if( dlg.ShowModal() == wxID_OK )
  58. CleanupTracks( this, dlg.cleanVias, dlg.mergeSegments,
  59. dlg.deleteUnconnectedSegm, dlg.connectToPads );
  60. DrawPanel->Refresh( true );
  61. }
  62. /* Main cleaning function.
  63. * Delete
  64. * - Redundant points on tracks (merge aligned segments)
  65. * - vias on pad
  66. * - null lenght segments
  67. * Create segments when track ends are incorrectly connected:
  68. * i.e. when a track end covers a pad or a via but is not exactly on the pad or the via center
  69. */
  70. void CleanupTracks( PCB_EDIT_FRAME* aFrame,
  71. bool aCleanVias, bool aMergeSegments,
  72. bool aDeleteUnconnectedSegm, bool aConnectToPads )
  73. {
  74. wxBusyCursor( dummy );
  75. aFrame->ClearMsgPanel();
  76. aFrame->GetBoard()->GetNumSegmTrack(); // update the count
  77. // Clear undo and redo lists to avoid inconsistencies between lists
  78. aFrame->GetScreen()->ClearUndoRedoList();
  79. aFrame->SetCurItem( NULL );
  80. /* Rebuild the pad infos (pad list and netcodes) to ensure an up to date info */
  81. aFrame->GetBoard()->m_Status_Pcb = 0;
  82. aFrame->GetBoard()->BuildListOfNets();
  83. if( aCleanVias ) // delete redundant vias
  84. {
  85. aFrame->SetStatusText( _( "Clean vias" ) );
  86. clean_vias( aFrame->GetBoard() );
  87. }
  88. #ifdef CONN2PAD_ENBL
  89. /* Create missing segments when a track end covers a pad or a via,
  90. * but is not on the pad or the via center */
  91. if( aConnectToPads )
  92. {
  93. aFrame->SetStatusText( _( "Reconnect pads" ) );
  94. /* Create missing segments when a track end covers a pad, but is not on the pad center */
  95. ConnectDanglingEndToPad( aFrame );
  96. /* Create missing segments when a track end covers a via, but is not on the via center */
  97. ConnectDanglingEndToVia( aFrame->GetBoard() );
  98. }
  99. #endif
  100. /* Remove null segments and intermediate points on aligned segments */
  101. if( aMergeSegments )
  102. {
  103. aFrame->SetStatusText( _( "Merge track segments" ) );
  104. clean_segments( aFrame );
  105. }
  106. /* Delete dangling tracks */
  107. if( aDeleteUnconnectedSegm )
  108. {
  109. aFrame->SetStatusText( _( "Delete unconnected tracks" ) );
  110. DeleteUnconnectedTracks( aFrame );
  111. }
  112. aFrame->SetStatusText( _( "Cleanup finished" ) );
  113. aFrame->Compile_Ratsnest( NULL, true );
  114. aFrame->OnModify();
  115. }
  116. void clean_vias( BOARD * aPcb )
  117. {
  118. TRACK* track;
  119. TRACK* next_track;
  120. for( track = aPcb->m_Track; track; track = track->Next() )
  121. {
  122. if( track->GetShape() != VIA_THROUGH )
  123. continue;
  124. // Search and delete others vias at same location
  125. TRACK* alt_track = track->Next();
  126. for( ; alt_track != NULL; alt_track = next_track )
  127. {
  128. next_track = alt_track->Next();
  129. if( alt_track->m_Shape != VIA_THROUGH )
  130. continue;
  131. if( alt_track->m_Start != track->m_Start )
  132. continue;
  133. /* delete via */
  134. alt_track->UnLink();
  135. delete alt_track;
  136. }
  137. }
  138. /* Delete Via on pads at same location */
  139. for( track = aPcb->m_Track; track != NULL; track = next_track )
  140. {
  141. next_track = track->Next();
  142. if( track->m_Shape != VIA_THROUGH )
  143. continue;
  144. D_PAD* pad = aPcb->GetPadFast( track->m_Start, ALL_CU_LAYERS );
  145. if( pad && (pad->m_layerMask & EXTERNAL_LAYERS) == EXTERNAL_LAYERS ) // redundant Via
  146. {
  147. /* delete via */
  148. track->UnLink();
  149. delete track;
  150. }
  151. }
  152. }
  153. /*
  154. * Delete dangling tracks
  155. * Vias:
  156. * If a via is only connected to a dangling track, it also will be removed
  157. */
  158. static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame )
  159. {
  160. TRACK* segment;
  161. TRACK* other;
  162. TRACK* startNetcode;
  163. TRACK* next;
  164. ZONE_CONTAINER* zone;
  165. int masklayer, oldnetcode;
  166. int type_end, flag_erase;
  167. if( aFrame->GetBoard()->m_Track == NULL )
  168. return;
  169. aFrame->DrawPanel->m_AbortRequest = false;
  170. // correct via m_End defects
  171. for( segment = aFrame->GetBoard()->m_Track; segment; segment = next )
  172. {
  173. next = segment->Next();
  174. if( segment->Type() == PCB_VIA_T )
  175. {
  176. if( segment->m_Start != segment->m_End )
  177. segment->m_End = segment->m_Start;
  178. continue;
  179. }
  180. }
  181. // removal of unconnected tracks
  182. segment = startNetcode = aFrame->GetBoard()->m_Track;
  183. oldnetcode = segment->GetNet();
  184. for( int ii = 0; segment ; segment = next, ii++ )
  185. {
  186. next = segment->Next();
  187. if( aFrame->DrawPanel->m_AbortRequest )
  188. break;
  189. if( segment->GetNet() != oldnetcode )
  190. {
  191. startNetcode = segment;
  192. oldnetcode = segment->GetNet();
  193. }
  194. flag_erase = 0; //Not connected indicator
  195. type_end = 0;
  196. /* Is a pad found on a track end ? */
  197. masklayer = segment->ReturnMaskLayer();
  198. D_PAD* pad;
  199. pad = aFrame->GetBoard()->GetPadFast( segment->m_Start, masklayer );
  200. if( pad != NULL )
  201. {
  202. segment->start = pad;
  203. type_end |= START_ON_PAD;
  204. }
  205. pad = aFrame->GetBoard()->GetPadFast( segment->m_End, masklayer );
  206. if( pad != NULL )
  207. {
  208. segment->end = pad;
  209. type_end |= END_ON_PAD;
  210. }
  211. // if not connected to a pad, test if segment's START is connected to another track
  212. // For via tests, an enhancement could to test if connected to 2 items on different layers.
  213. // Currently a via must be connected to 2 items, that can be on the same layer
  214. int top_layer, bottom_layer;
  215. if( (type_end & START_ON_PAD ) == 0 )
  216. {
  217. other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START );
  218. if( other == NULL ) // Test a connection to zones
  219. {
  220. if( segment->Type() != PCB_VIA_T )
  221. {
  222. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( segment->m_Start,
  223. segment->GetLayer() );
  224. }
  225. else
  226. {
  227. ((SEGVIA*)segment)->ReturnLayerPair( &top_layer, &bottom_layer );
  228. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( segment->m_Start,
  229. top_layer, bottom_layer );
  230. }
  231. }
  232. if( (other == NULL) && (zone == NULL) )
  233. {
  234. flag_erase |= 1;
  235. }
  236. else // segment, via or zone connected to this end
  237. {
  238. segment->start = other;
  239. // If a via is connected to this end, test if this via has a second item connected
  240. // if no, remove it with the current segment
  241. if( other && other->Type() == PCB_VIA_T )
  242. {
  243. // search for another segment following the via
  244. segment->SetState( BUSY, ON );
  245. SEGVIA* via = (SEGVIA*) other;
  246. other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, START );
  247. if( other == NULL )
  248. {
  249. via->ReturnLayerPair( &top_layer, &bottom_layer );
  250. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( via->m_Start,
  251. bottom_layer,
  252. top_layer );
  253. }
  254. if( (other == NULL) && (zone == NULL) )
  255. flag_erase |= 2;
  256. segment->SetState( BUSY, OFF );
  257. }
  258. }
  259. }
  260. // if not connected to a pad, test if segment's END is connected to another track
  261. if( (type_end & END_ON_PAD ) == 0 )
  262. {
  263. other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END );
  264. if( other == NULL ) // Test a connection to zones
  265. {
  266. if( segment->Type() != PCB_VIA_T )
  267. {
  268. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( segment->m_End,
  269. segment->GetLayer() );
  270. }
  271. else
  272. {
  273. ((SEGVIA*)segment)->ReturnLayerPair( &top_layer, &bottom_layer );
  274. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( segment->m_End,
  275. top_layer, bottom_layer );
  276. }
  277. }
  278. if ( (other == NULL) && (zone == NULL) )
  279. {
  280. flag_erase |= 0x10;
  281. }
  282. else // segment, via or zone connected to this end
  283. {
  284. segment->end = other;
  285. // If a via is connected to this end, test if this via has a second item connected
  286. // if no, remove it with the current segment
  287. if( other && other->Type() == PCB_VIA_T )
  288. {
  289. // search for another segment following the via
  290. segment->SetState( BUSY, ON );
  291. SEGVIA* via = (SEGVIA*) other;
  292. other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, END );
  293. if( other == NULL )
  294. {
  295. via->ReturnLayerPair( &top_layer, &bottom_layer );
  296. zone = aFrame->GetBoard()->HitTestForAnyFilledArea( via->m_End,
  297. bottom_layer,
  298. top_layer );
  299. }
  300. if( (other == NULL) && (zone == NULL) )
  301. flag_erase |= 0x20;
  302. segment->SetState( BUSY, OFF );
  303. }
  304. }
  305. }
  306. if( flag_erase )
  307. {
  308. // update the pointer to start of the contiguous netcode group
  309. if( segment == startNetcode )
  310. {
  311. next = segment->Next();
  312. startNetcode = next;
  313. }
  314. else
  315. {
  316. next = startNetcode;
  317. }
  318. // remove segment from board
  319. segment->DeleteStructure();
  320. if( next == NULL )
  321. break;
  322. }
  323. }
  324. }
  325. /* Delete null length segments, and intermediate points .. */
  326. static void clean_segments( PCB_EDIT_FRAME* aFrame )
  327. {
  328. TRACK* segment, * nextsegment;
  329. TRACK* other;
  330. int ii;
  331. int flag, no_inc;
  332. wxString msg;
  333. aFrame->DrawPanel->m_AbortRequest = false;
  334. // Delete null segments
  335. for( segment = aFrame->GetBoard()->m_Track; segment; segment = nextsegment )
  336. {
  337. nextsegment = segment->Next();
  338. if( !segment->IsNull() )
  339. continue;
  340. /* Length segment = 0; delete it */
  341. segment->DeleteStructure();
  342. }
  343. /* Delete redundant segments */
  344. for( segment = aFrame->GetBoard()->m_Track, ii = 0; segment; segment = segment->Next(), ii++ )
  345. {
  346. for( other = segment->Next(); other; other = nextsegment )
  347. {
  348. nextsegment = other->Next();
  349. int erase = 0;
  350. if( segment->Type() != other->Type() )
  351. continue;
  352. if( segment->GetLayer() != other->GetLayer() )
  353. continue;
  354. if( segment->GetNet() != other->GetNet() )
  355. break;
  356. if( segment->m_Start == other->m_Start )
  357. {
  358. if( segment->m_End == other->m_End )
  359. erase = 1;
  360. }
  361. if( segment->m_Start == other->m_End )
  362. {
  363. if( segment->m_End == other->m_Start )
  364. erase = 1;
  365. }
  366. /* Delete redundant point */
  367. if( erase )
  368. {
  369. ii--;
  370. other->DeleteStructure();
  371. }
  372. }
  373. }
  374. /* delete intermediate points */
  375. ii = 0;
  376. for( segment = aFrame->GetBoard()->m_Track; segment; segment = nextsegment )
  377. {
  378. TRACK* segStart;
  379. TRACK* segEnd;
  380. TRACK* segDelete;
  381. nextsegment = segment->Next();
  382. if( aFrame->DrawPanel->m_AbortRequest )
  383. return;
  384. if( segment->Type() != PCB_TRACE_T )
  385. continue;
  386. flag = no_inc = 0;
  387. // search for a possible point that connects on the START point of the segment
  388. for( segStart = segment->Next(); ; )
  389. {
  390. segStart = segment->GetTrace( segStart, NULL, START );
  391. if( segStart )
  392. {
  393. // the two segments must have the same width
  394. if( segment->m_Width != segStart->m_Width )
  395. break;
  396. // it cannot be a via
  397. if( segStart->Type() != PCB_TRACE_T )
  398. break;
  399. /* We must have only one segment connected */
  400. segStart->SetState( BUSY, ON );
  401. other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START );
  402. segStart->SetState( BUSY, OFF );
  403. if( other == NULL )
  404. flag = 1; /* OK */
  405. break;
  406. }
  407. break;
  408. }
  409. if( flag ) // We have the starting point of the segment is connected to an other segment
  410. {
  411. segDelete = MergeColinearSegmentIfPossible( aFrame->GetBoard(), segment, segStart,
  412. START );
  413. if( segDelete )
  414. {
  415. no_inc = 1;
  416. segDelete->DeleteStructure();
  417. }
  418. }
  419. /* search for a possible point that connects on the END point of the segment: */
  420. for( segEnd = segment->Next(); ; )
  421. {
  422. segEnd = segment->GetTrace( segEnd, NULL, END );
  423. if( segEnd )
  424. {
  425. if( segment->m_Width != segEnd->m_Width )
  426. break;
  427. if( segEnd->Type() != PCB_TRACE_T )
  428. break;
  429. /* We must have only one segment connected */
  430. segEnd->SetState( BUSY, ON );
  431. other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END );
  432. segEnd->SetState( BUSY, OFF );
  433. if( other == NULL )
  434. flag |= 2; /* Ok */
  435. break;
  436. }
  437. else
  438. {
  439. break;
  440. }
  441. }
  442. if( flag & 2 ) // We have the ending point of the segment is connected to an other segment
  443. {
  444. segDelete = MergeColinearSegmentIfPossible( aFrame->GetBoard(), segment, segEnd, END );
  445. if( segDelete )
  446. {
  447. no_inc = 1;
  448. segDelete->DeleteStructure();
  449. }
  450. }
  451. if( no_inc ) /* The current segment was modified, retry to merge it */
  452. nextsegment = segment->Next();
  453. }
  454. return;
  455. }
  456. /* Function used by clean_segments.
  457. * Test alignment of aTrackRef and aCandidate (which must have a common end).
  458. * and see if the common point is not on a pad (i.e. if this common point can be removed).
  459. * the ending point of pt_ref is the start point (aEndType == START)
  460. * or the end point (aEndType != START)
  461. * if the common point can be deleted, this function
  462. * change the common point coordinate of the aTrackRef segm
  463. * (and therefore connect the 2 other ending points)
  464. * and return aCandidate (which can be deleted).
  465. * else return NULL
  466. */
  467. TRACK* MergeColinearSegmentIfPossible( BOARD* aPcb, TRACK* aTrackRef, TRACK* aCandidate,
  468. int aEndType )
  469. {
  470. if( aTrackRef->m_Width != aCandidate->m_Width )
  471. return NULL;
  472. bool is_colinear = false;
  473. // Trivial case: superimposed tracks ( tracks, not vias ):
  474. if( aTrackRef->Type() == PCB_TRACE_T && aCandidate->Type() == PCB_TRACE_T )
  475. {
  476. if( aTrackRef->m_Start == aCandidate->m_Start )
  477. if( aTrackRef->m_End == aCandidate->m_End )
  478. return aCandidate;
  479. if( aTrackRef->m_Start == aCandidate->m_End )
  480. if( aTrackRef->m_End == aCandidate->m_Start )
  481. return aCandidate;
  482. }
  483. int refdx = aTrackRef->m_End.x - aTrackRef->m_Start.x;
  484. int refdy = aTrackRef->m_End.y - aTrackRef->m_Start.y;
  485. int segmdx = aCandidate->m_End.x - aCandidate->m_Start.x;
  486. int segmdy = aCandidate->m_End.y - aCandidate->m_Start.y;
  487. // test for vertical alignment (easy to handle)
  488. if( refdx == 0 )
  489. {
  490. if( segmdx != 0 )
  491. return NULL;
  492. else
  493. is_colinear = true;
  494. }
  495. // test for horizontal alignment (easy to handle)
  496. if( refdy == 0 )
  497. {
  498. if( segmdy != 0 )
  499. return NULL;
  500. else
  501. is_colinear = true;
  502. }
  503. /* test if alignment in other cases
  504. * We must have refdy/refdx == segmdy/segmdx, (i.e. same slope)
  505. * or refdy * segmdx == segmdy * refdx
  506. */
  507. if( is_colinear == false )
  508. {
  509. if( ( double)refdy * segmdx != (double)refdx * segmdy )
  510. return NULL;
  511. is_colinear = true;
  512. }
  513. /* Here we have 2 aligned segments:
  514. * We must change the pt_ref common point only if not on a pad
  515. * (this function) is called when there is only 2 connected segments,
  516. *and if this point is not on a pad, it can be removed and the 2 segments will be merged
  517. */
  518. if( aEndType == START )
  519. {
  520. // We must not have a pad, which is a always terminal point for a track
  521. if( aPcb->GetPadFast( aTrackRef->m_Start, aTrackRef->ReturnMaskLayer() ) )
  522. return NULL;
  523. /* change the common point coordinate of pt_segm to use the other point
  524. * of pt_segm (pt_segm will be removed later) */
  525. if( aTrackRef->m_Start == aCandidate->m_Start )
  526. {
  527. aTrackRef->m_Start = aCandidate->m_End;
  528. return aCandidate;
  529. }
  530. else
  531. {
  532. aTrackRef->m_Start = aCandidate->m_Start;
  533. return aCandidate;
  534. }
  535. }
  536. else // aEndType == END
  537. {
  538. // We must not have a pad, which is a always terminal point for a track
  539. if( aPcb->GetPadFast( aTrackRef->m_End, aTrackRef->ReturnMaskLayer() ) )
  540. return NULL;
  541. /* change the common point coordinate of pt_segm to use the other point
  542. * of pt_segm (pt_segm will be removed later) */
  543. if( aTrackRef->m_End == aCandidate->m_Start )
  544. {
  545. aTrackRef->m_End = aCandidate->m_End;
  546. return aCandidate;
  547. }
  548. else
  549. {
  550. aTrackRef->m_End = aCandidate->m_Start;
  551. return aCandidate;
  552. }
  553. }
  554. return NULL;
  555. }
  556. bool PCB_EDIT_FRAME::RemoveMisConnectedTracks( wxDC* aDC )
  557. {
  558. TRACK* segment;
  559. TRACK* other;
  560. TRACK* next;
  561. int net_code_s, net_code_e;
  562. bool isModified = false;
  563. for( segment = GetBoard()->m_Track; segment; segment = (TRACK*) segment->Next() )
  564. {
  565. segment->SetState( FLAG0, OFF );
  566. // find the netcode for segment using anything connected to the "start" of "segment"
  567. net_code_s = -1;
  568. if( segment->start && segment->start->Type()==PCB_PAD_T )
  569. {
  570. // get the netcode of the pad to propagate.
  571. net_code_s = ((D_PAD*)(segment->start))->GetNet();
  572. }
  573. else
  574. {
  575. other = segment->GetTrace( GetBoard()->m_Track, NULL, START );
  576. if( other )
  577. net_code_s = other->GetNet();
  578. }
  579. if( net_code_s < 0 )
  580. continue; // the "start" of segment is not connected
  581. // find the netcode for segment using anything connected to the "end" of "segment"
  582. net_code_e = -1;
  583. if( segment->end && segment->end->Type()==PCB_PAD_T )
  584. {
  585. net_code_e = ((D_PAD*)(segment->end))->GetNet();
  586. }
  587. else
  588. {
  589. other = segment->GetTrace( GetBoard()->m_Track, NULL, END );
  590. if( other )
  591. net_code_e = other->GetNet();
  592. }
  593. if( net_code_e < 0 )
  594. continue; // the "end" of segment is not connected
  595. // Netcodes do not agree, so mark the segment as needed to be removed
  596. if( net_code_s != net_code_e )
  597. {
  598. segment->SetState( FLAG0, ON );
  599. }
  600. }
  601. // Remove flagged segments
  602. for( segment = GetBoard()->m_Track; segment; segment = next )
  603. {
  604. next = (TRACK*) segment->Next();
  605. if( segment->GetState( FLAG0 ) ) // Segment is flagged to be removed
  606. {
  607. segment->SetState( FLAG0, OFF );
  608. isModified = true;
  609. GetBoard()->m_Status_Pcb = 0;
  610. Remove_One_Track( aDC, segment );
  611. // the current segment could be deleted, so restart to the beginning
  612. next = GetBoard()->m_Track;
  613. }
  614. }
  615. return isModified;
  616. }
  617. #if defined(CONN2PAD_ENBL)
  618. /**
  619. * Function ConnectDanglingEndToPad
  620. * looks for vias which have no netcode and which are in electrical contact
  621. * with a track to the degree that the track's end point falls on the via.
  622. * Note that this is not a rigorous electrical check, but is better than
  623. * testing for the track endpoint equaling the via center. When such a via
  624. * is found, then add a small track to bridge from the overlapping track to
  625. * the via and change the via's netcode so that subsequent continuity checks
  626. * can be done with the faster equality algorithm.
  627. */
  628. static void ConnectDanglingEndToVia( BOARD* pcb )
  629. {
  630. for( TRACK* track = pcb->m_Track; track; track = track->Next() )
  631. {
  632. SEGVIA* via;
  633. if( track->Type()!=PCB_VIA_T || (via = (SEGVIA*)track)->GetNet()!=0 )
  634. continue;
  635. for( TRACK* other = pcb->m_Track; other; other = other->Next() )
  636. {
  637. if( other == track )
  638. continue;
  639. if( !via->IsOnLayer( other->GetLayer() ) )
  640. continue;
  641. // if the other track's m_End does not match the via position, and the track's
  642. // m_Start is within the bounds of the via, and the other track has no start
  643. if( other->m_End != via->GetPosition() && via->HitTest( other->m_Start )
  644. && !other->start )
  645. {
  646. TRACK* newTrack = other->Copy();
  647. pcb->m_Track.Insert( newTrack, other->Next() );
  648. newTrack->m_End = via->GetPosition();
  649. newTrack->start = other;
  650. newTrack->end = via;
  651. other->start = newTrack;
  652. via->SetNet( other->GetNet() );
  653. if( !via->start )
  654. via->start = other;
  655. if( !via->end )
  656. via->end = other;
  657. }
  658. // if the other track's m_Start does not match the via position, and the track's
  659. // m_End is within the bounds of the via, and the other track has no end
  660. else if( other->m_Start != via->GetPosition() && via->HitTest( other->m_End )
  661. && !other->end )
  662. {
  663. TRACK* newTrack = other->Copy();
  664. pcb->m_Track.Insert( newTrack, other->Next() );
  665. newTrack->m_Start = via->GetPosition();
  666. newTrack->start = via;
  667. newTrack->end = other;
  668. other->end = newTrack;
  669. via->SetNet( other->GetNet() );
  670. if( !via->start )
  671. via->start = other;
  672. if( !via->end )
  673. via->end = other;
  674. }
  675. }
  676. }
  677. }
  678. /**
  679. * Function ConnectDanglingEndToPad
  680. * possibly adds a segment to the end of any and all tracks if their end is not exactly
  681. * connected into the center of the pad. This allows faster control of
  682. * connections.
  683. */
  684. void ConnectDanglingEndToPad( PCB_EDIT_FRAME* aFrame )
  685. {
  686. TRACK* segment;
  687. int nb_new_trace = 0;
  688. wxString msg;
  689. aFrame->DrawPanel->m_AbortRequest = false;
  690. for( segment = aFrame->GetBoard()->m_Track; segment; segment = segment->Next() )
  691. {
  692. D_PAD* pad;
  693. if( aFrame->DrawPanel->m_AbortRequest )
  694. return;
  695. pad = aFrame->GetBoard()->GetPad( segment, START );
  696. if( pad )
  697. {
  698. // test if the track start point is not exactly starting on the pad
  699. if( segment->m_Start != pad->m_Pos )
  700. {
  701. if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START ) == NULL )
  702. {
  703. TRACK* newTrack = segment->Copy();
  704. aFrame->GetBoard()->m_Track.Insert( newTrack, segment->Next() );
  705. newTrack->m_End = pad->m_Pos;
  706. newTrack->start = segment;
  707. newTrack->end = pad;
  708. nb_new_trace++;
  709. }
  710. }
  711. }
  712. pad = aFrame->GetBoard()->GetPad( segment, END );
  713. if( pad )
  714. {
  715. // test if the track end point is not exactly on the pad
  716. if( segment->m_End != pad->m_Pos )
  717. {
  718. if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END ) == NULL )
  719. {
  720. TRACK* newTrack = segment->Copy();
  721. aFrame->GetBoard()->m_Track.Insert( newTrack, segment->Next() );
  722. newTrack->m_Start = pad->m_Pos;
  723. newTrack->start = pad;
  724. newTrack->end = segment;
  725. nb_new_trace++;
  726. }
  727. }
  728. }
  729. }
  730. }
  731. #endif