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.

679 lines
18 KiB

18 years ago
18 years ago
18 years ago
5 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
18 years ago
18 years ago
18 years ago
18 years ago
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) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <collectors.h>
  25. #include <board_item.h> // class BOARD_ITEM
  26. #include <footprint.h>
  27. #include <fp_shape.h>
  28. #include <pad.h>
  29. #include <pcb_track.h>
  30. #include <pcb_marker.h>
  31. #include <pcb_dimension.h>
  32. #include <zone.h>
  33. #include <pcb_shape.h>
  34. #include <pcb_group.h>
  35. #include <macros.h>
  36. #include <math/util.h> // for KiROUND
  37. /*
  38. * This module contains out of line member functions for classes given in
  39. * collectors.h. Those classes augment the functionality of class PCB_EDIT_FRAME.
  40. */
  41. const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = {
  42. // there are some restrictions on the order of items in the general case.
  43. // all items in m_Drawings for instance should be contiguous.
  44. // *** all items in a same list (shown here) must be contiguous ****
  45. PCB_MARKER_T, // in m_markers
  46. PCB_TEXT_T, // in m_drawings
  47. PCB_TEXTBOX_T, // in m_drawings
  48. PCB_SHAPE_T, // in m_drawings
  49. PCB_DIM_ALIGNED_T, // in m_drawings
  50. PCB_DIM_CENTER_T, // in m_drawings
  51. PCB_DIM_RADIAL_T, // in m_drawings
  52. PCB_DIM_ORTHOGONAL_T, // in m_drawings
  53. PCB_DIM_LEADER_T, // in m_drawings
  54. PCB_TARGET_T, // in m_drawings
  55. PCB_VIA_T, // in m_tracks
  56. PCB_TRACE_T, // in m_tracks
  57. PCB_ARC_T, // in m_tracks
  58. PCB_PAD_T, // in footprints
  59. PCB_FP_TEXT_T, // in footprints
  60. PCB_FP_TEXTBOX_T, // in footprints
  61. PCB_FOOTPRINT_T, // in m_footprints
  62. PCB_GROUP_T, // in m_groups
  63. PCB_ZONE_T, // in m_zones
  64. EOT
  65. };
  66. const KICAD_T GENERAL_COLLECTOR::BoardLevelItems[] = {
  67. PCB_MARKER_T,
  68. PCB_TEXT_T,
  69. PCB_TEXTBOX_T,
  70. PCB_SHAPE_T,
  71. PCB_DIM_ALIGNED_T,
  72. PCB_DIM_ORTHOGONAL_T,
  73. PCB_DIM_CENTER_T,
  74. PCB_DIM_RADIAL_T,
  75. PCB_DIM_LEADER_T,
  76. PCB_TARGET_T,
  77. PCB_VIA_T,
  78. PCB_ARC_T,
  79. PCB_TRACE_T,
  80. PCB_FOOTPRINT_T,
  81. PCB_GROUP_T,
  82. PCB_ZONE_T,
  83. EOT
  84. };
  85. const KICAD_T GENERAL_COLLECTOR::Footprints[] = {
  86. PCB_FOOTPRINT_T,
  87. EOT
  88. };
  89. const KICAD_T GENERAL_COLLECTOR::PadsOrTracks[] = {
  90. PCB_PAD_T,
  91. PCB_VIA_T,
  92. PCB_TRACE_T,
  93. PCB_ARC_T,
  94. EOT
  95. };
  96. const KICAD_T GENERAL_COLLECTOR::FootprintItems[] = {
  97. PCB_FP_TEXT_T,
  98. PCB_FP_TEXTBOX_T,
  99. PCB_FP_SHAPE_T,
  100. PCB_FP_DIM_ALIGNED_T,
  101. PCB_FP_DIM_ORTHOGONAL_T,
  102. PCB_FP_DIM_CENTER_T,
  103. PCB_FP_DIM_RADIAL_T,
  104. PCB_FP_DIM_LEADER_T,
  105. PCB_PAD_T,
  106. PCB_FP_ZONE_T,
  107. PCB_GROUP_T,
  108. EOT
  109. };
  110. const KICAD_T GENERAL_COLLECTOR::Tracks[] = {
  111. PCB_TRACE_T,
  112. PCB_ARC_T,
  113. PCB_VIA_T,
  114. EOT
  115. };
  116. const KICAD_T GENERAL_COLLECTOR::LockableItems[] = {
  117. PCB_FOOTPRINT_T,
  118. PCB_GROUP_T, // Can a group be locked?
  119. PCB_TRACE_T,
  120. PCB_ARC_T,
  121. PCB_VIA_T,
  122. EOT
  123. };
  124. const KICAD_T GENERAL_COLLECTOR::Zones[] = {
  125. PCB_ZONE_T,
  126. PCB_FP_ZONE_T,
  127. EOT
  128. };
  129. const KICAD_T GENERAL_COLLECTOR::Dimensions[] = {
  130. PCB_DIM_ALIGNED_T,
  131. PCB_DIM_LEADER_T,
  132. PCB_DIM_ORTHOGONAL_T,
  133. PCB_DIM_CENTER_T,
  134. PCB_DIM_RADIAL_T,
  135. PCB_FP_DIM_ALIGNED_T,
  136. PCB_FP_DIM_LEADER_T,
  137. PCB_FP_DIM_ORTHOGONAL_T,
  138. PCB_FP_DIM_CENTER_T,
  139. PCB_FP_DIM_RADIAL_T,
  140. EOT
  141. };
  142. const KICAD_T GENERAL_COLLECTOR::DraggableItems[] = {
  143. PCB_TRACE_T,
  144. PCB_VIA_T,
  145. PCB_FOOTPRINT_T,
  146. PCB_ARC_T,
  147. EOT
  148. };
  149. SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  150. {
  151. BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  152. FOOTPRINT* footprint = nullptr;
  153. PCB_GROUP* group = nullptr;
  154. PAD* pad = nullptr;
  155. bool pad_through = false;
  156. PCB_VIA* via = nullptr;
  157. PCB_MARKER* marker = nullptr;
  158. ZONE* zone = nullptr;
  159. PCB_SHAPE* shape = nullptr;
  160. PCB_DIMENSION_BASE* dimension = nullptr;
  161. #if 0 // debugging
  162. static int breakhere = 0;
  163. switch( item->Type() )
  164. {
  165. case PCB_PAD_T:
  166. {
  167. FOOTPRINT* footprint = (FOOTPRINT*) item->GetParent();
  168. if( footprint->GetReference() == wxT( "Y2" ) )
  169. breakhere++;
  170. }
  171. break;
  172. case PCB_VIA_T:
  173. breakhere++;
  174. break;
  175. case PCB_TRACE_T:
  176. case PCB_ARC_T:
  177. breakhere++;
  178. break;
  179. case PCB_TEXT_T:
  180. breakhere++;
  181. break;
  182. case PCB_TEXTBOX_T:
  183. breakhere++;
  184. break;
  185. case PCB_SHAPE_T:
  186. breakhere++;
  187. break;
  188. case PCB_DIM_ALIGNED_T:
  189. breakhere++;
  190. break;
  191. case PCB_FP_TEXT_T:
  192. {
  193. FP_TEXT* fpText = (FP_TEXT*) item;
  194. if( fpText->GetText() == wxT( "10uH" ) )
  195. breakhere++;
  196. }
  197. break;
  198. case PCB_FP_TEXTBOX_T:
  199. breakhere++;
  200. break;
  201. case PCB_FOOTPRINT_T:
  202. {
  203. FOOTPRINT* footprint = (FOOTPRINT*) item;
  204. if( footprint->GetReference() == wxT( "C98" ) )
  205. breakhere++;
  206. }
  207. break;
  208. case PCB_MARKER_T:
  209. breakhere++;
  210. break;
  211. default:
  212. breakhere++;
  213. break;
  214. }
  215. #endif
  216. switch( item->Type() )
  217. {
  218. case PCB_PAD_T:
  219. // there are pad specific visibility controls.
  220. // Criteria to select a pad is:
  221. // for smd pads: the footprint parent must be visible, and pads on the corresponding
  222. // board side must be visible
  223. // if pad is a thru hole, then it can be visible when its parent footprint is not.
  224. // for through pads: pads on Front or Back board sides must be visible
  225. pad = static_cast<PAD*>( item );
  226. if( ( pad->GetAttribute() != PAD_ATTRIB::SMD ) &&
  227. ( pad->GetAttribute() != PAD_ATTRIB::CONN ) ) // a hole is present, so multiple layers
  228. {
  229. // proceed to the common tests below, but without the parent footprint test,
  230. // by leaving footprint==NULL, but having pad != null
  231. pad_through = true;
  232. }
  233. else // smd, so use pads test after footprint test
  234. {
  235. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  236. }
  237. break;
  238. case PCB_VIA_T: // vias are on many layers, so layer test is specific
  239. via = static_cast<PCB_VIA*>( item );
  240. break;
  241. case PCB_TRACE_T:
  242. case PCB_ARC_T:
  243. if( m_Guide->IgnoreTracks() )
  244. goto exit;
  245. break;
  246. case PCB_FP_ZONE_T:
  247. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  248. // Fallthrough to get the zone as well
  249. KI_FALLTHROUGH;
  250. case PCB_ZONE_T:
  251. zone = static_cast<ZONE*>( item );
  252. break;
  253. case PCB_TEXT_T:
  254. case PCB_TEXTBOX_T:
  255. break;
  256. case PCB_SHAPE_T:
  257. shape = static_cast<PCB_SHAPE*>( item );
  258. break;
  259. case PCB_FP_DIM_ALIGNED_T:
  260. case PCB_FP_DIM_CENTER_T:
  261. case PCB_FP_DIM_RADIAL_T:
  262. case PCB_FP_DIM_ORTHOGONAL_T:
  263. case PCB_FP_DIM_LEADER_T:
  264. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  265. // Fallthrough to get the zone as well
  266. KI_FALLTHROUGH;
  267. case PCB_DIM_ALIGNED_T:
  268. case PCB_DIM_CENTER_T:
  269. case PCB_DIM_RADIAL_T:
  270. case PCB_DIM_ORTHOGONAL_T:
  271. case PCB_DIM_LEADER_T:
  272. dimension = static_cast<PCB_DIMENSION_BASE*>( item );
  273. break;
  274. case PCB_TARGET_T:
  275. break;
  276. case PCB_FP_TEXT_T:
  277. case PCB_FP_TEXTBOX_T:
  278. {
  279. PCB_LAYER_ID layer = item->GetLayer();
  280. if( m_Guide->IgnoreHiddenFPText() && item->Type() == PCB_FP_TEXT_T )
  281. {
  282. FP_TEXT *text = static_cast<FP_TEXT*>( item );
  283. if( !text->IsVisible() )
  284. goto exit;
  285. }
  286. if( m_Guide->IgnoreFPTextOnBack() && IsBackLayer( layer ) )
  287. goto exit;
  288. if( m_Guide->IgnoreFPTextOnFront() && IsFrontLayer( layer ) )
  289. goto exit;
  290. /*
  291. * The three text types have different criteria: reference and value have their own
  292. * ignore flags; user text instead follows their layer visibility. Checking this here
  293. * is simpler than later (when layer visibility is checked for other entities)
  294. */
  295. FP_TEXT::TEXT_TYPE textType = FP_TEXT::TEXT_is_DIVERS;
  296. if( item->Type() == PCB_FP_TEXT_T )
  297. textType = static_cast<FP_TEXT*>( item )->GetType();
  298. switch( textType )
  299. {
  300. case FP_TEXT::TEXT_is_REFERENCE:
  301. if( m_Guide->IgnoreFPReferences() )
  302. goto exit;
  303. break;
  304. case FP_TEXT::TEXT_is_VALUE:
  305. if( m_Guide->IgnoreFPValues() )
  306. goto exit;
  307. break;
  308. case FP_TEXT::TEXT_is_DIVERS:
  309. if( !m_Guide->IsLayerVisible( layer ) )
  310. goto exit;
  311. break;
  312. }
  313. // Extract the footprint since it could be hidden
  314. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  315. break;
  316. }
  317. case PCB_FP_SHAPE_T:
  318. shape = static_cast<FP_SHAPE*>( item );
  319. break;
  320. case PCB_FOOTPRINT_T:
  321. footprint = static_cast<FOOTPRINT*>( item );
  322. break;
  323. case PCB_GROUP_T:
  324. group = static_cast<PCB_GROUP*>( item );
  325. break;
  326. case PCB_MARKER_T:
  327. marker = static_cast<PCB_MARKER*>( item );
  328. break;
  329. default:
  330. break;
  331. }
  332. // common tests:
  333. if( footprint ) // true from case PCB_PAD_T, PCB_FP_TEXT_T, or PCB_FOOTPRINT_T
  334. {
  335. if( m_Guide->IgnoreFootprintsOnBack() && ( footprint->GetLayer() == B_Cu ) )
  336. goto exit;
  337. if( m_Guide->IgnoreFootprintsOnFront() && ( footprint->GetLayer() == F_Cu ) )
  338. goto exit;
  339. }
  340. // Pads are not sensitive to the layer visibility controls.
  341. // They all have their own separate visibility controls
  342. // skip them if not visible
  343. if( pad )
  344. {
  345. if( m_Guide->IgnorePads() )
  346. goto exit;
  347. if( ! pad_through )
  348. {
  349. if( m_Guide->IgnorePadsOnFront() && pad->IsOnLayer(F_Cu ) )
  350. goto exit;
  351. if( m_Guide->IgnorePadsOnBack() && pad->IsOnLayer(B_Cu ) )
  352. goto exit;
  353. }
  354. }
  355. if( marker )
  356. {
  357. // Markers are not sensitive to the layer
  358. if( marker->HitTest( m_refPos ) )
  359. Append( item );
  360. goto exit;
  361. }
  362. if( group )
  363. {
  364. // Groups are not sensitive to the layer ... ?
  365. if( group->HitTest( m_refPos ) )
  366. Append( item );
  367. goto exit;
  368. }
  369. if( via )
  370. {
  371. auto type = via->GetViaType();
  372. if( ( m_Guide->IgnoreThroughVias() && type == VIATYPE::THROUGH )
  373. || ( m_Guide->IgnoreBlindBuriedVias() && type == VIATYPE::BLIND_BURIED )
  374. || ( m_Guide->IgnoreMicroVias() && type == VIATYPE::MICROVIA ) )
  375. {
  376. goto exit;
  377. }
  378. }
  379. if( ( item->IsOnLayer( m_Guide->GetPreferredLayer() ) )
  380. && ( !item->IsLocked() || !m_Guide->IgnoreLockedItems() ) )
  381. {
  382. // footprints and their subcomponents: reference, value and pads are not sensitive
  383. // to the layer visibility controls. They all have their own separate visibility
  384. // controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
  385. // text in a footprint *is* sensitive to layer visibility but that was already handled.
  386. int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
  387. if( zone )
  388. {
  389. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  390. || zone->HitTestForEdge( m_refPos, accuracy ) )
  391. {
  392. Append( item );
  393. goto exit;
  394. }
  395. else if( !m_Guide->IgnoreZoneFills() )
  396. {
  397. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  398. {
  399. if( m_Guide->IsLayerVisible( layer )
  400. && zone->HitTestFilledArea( layer, m_refPos ) )
  401. {
  402. Append( item );
  403. goto exit;
  404. }
  405. }
  406. }
  407. }
  408. else if( item == footprint )
  409. {
  410. if( footprint->HitTest( m_refPos, accuracy )
  411. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  412. {
  413. Append( item );
  414. goto exit;
  415. }
  416. }
  417. else if( pad || via )
  418. {
  419. if( item->HitTest( m_refPos, accuracy ) )
  420. {
  421. Append( item );
  422. goto exit;
  423. }
  424. }
  425. else
  426. {
  427. PCB_LAYER_ID layer = item->GetLayer();
  428. if( m_Guide->IsLayerVisible( layer ) )
  429. {
  430. if( dimension )
  431. {
  432. // Dimensions feel particularly hard to select, probably due to their
  433. // noisy shape making it feel like they should have a larger boundary.
  434. accuracy = KiROUND( accuracy * 1.5 );
  435. }
  436. if( item->HitTest( m_refPos, accuracy ) )
  437. {
  438. Append( item );
  439. goto exit;
  440. }
  441. }
  442. }
  443. }
  444. if( m_Guide->IncludeSecondary()
  445. && ( !item->IsLocked() || !m_Guide->IgnoreLockedItems() ) )
  446. {
  447. // for now, "secondary" means "tolerate any visible layer". It has no effect on other
  448. // criteria, since there is a separate "ignore" control for those in the COLLECTORS_GUIDE
  449. // footprints and their subcomponents: reference, value and pads are not sensitive
  450. // to the layer visibility controls. They all have their own separate visibility
  451. // controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
  452. // text in a footprint *is* sensitive to layer visibility but that was already handled.
  453. int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
  454. if( zone )
  455. {
  456. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  457. || zone->HitTestForEdge( m_refPos, accuracy ) )
  458. {
  459. Append2nd( item );
  460. goto exit;
  461. }
  462. else if( !m_Guide->IgnoreZoneFills() )
  463. {
  464. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  465. {
  466. if( m_Guide->IsLayerVisible( layer )
  467. && zone->HitTestFilledArea( layer, m_refPos ) )
  468. {
  469. Append2nd( item );
  470. goto exit;
  471. }
  472. }
  473. }
  474. }
  475. else if( item->Type() == PCB_FOOTPRINT_T )
  476. {
  477. if( footprint->HitTest( m_refPos, accuracy )
  478. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  479. {
  480. Append2nd( item );
  481. goto exit;
  482. }
  483. }
  484. else if( pad || via )
  485. {
  486. if( item->HitTest( m_refPos, accuracy ) )
  487. {
  488. Append2nd( item );
  489. goto exit;
  490. }
  491. }
  492. else
  493. {
  494. PCB_LAYER_ID layer = item->GetLayer();
  495. if( m_Guide->IsLayerVisible( layer ) )
  496. {
  497. if( dimension )
  498. {
  499. // Dimensions feel particularly hard to select, probably due to their
  500. // noisy shape making it feel like they should have a larger boundary.
  501. accuracy = KiROUND( accuracy * 1.5 );
  502. }
  503. if( item->HitTest( m_refPos, accuracy ) )
  504. {
  505. Append2nd( item );
  506. goto exit;
  507. }
  508. }
  509. }
  510. }
  511. exit:
  512. return SEARCH_RESULT::CONTINUE; // always when collecting
  513. }
  514. void GENERAL_COLLECTOR::Collect( BOARD_ITEM* aItem, const KICAD_T aScanList[],
  515. const VECTOR2I& aRefPos, const COLLECTORS_GUIDE& aGuide )
  516. {
  517. Empty(); // empty the collection, primary criteria list
  518. Empty2nd(); // empty the collection, secondary criteria list
  519. // remember guide, pass it to Inspect()
  520. SetGuide( &aGuide );
  521. SetScanTypes( aScanList );
  522. // remember where the snapshot was taken from and pass refPos to
  523. // the Inspect() function.
  524. SetRefPos( aRefPos );
  525. aItem->Visit( m_inspector, nullptr, m_scanTypes );
  526. // record the length of the primary list before concatenating on to it.
  527. m_PrimaryLength = m_list.size();
  528. // append 2nd list onto end of the first list
  529. for( unsigned i = 0; i<m_List2nd.size(); ++i )
  530. Append( m_List2nd[i] );
  531. Empty2nd();
  532. }
  533. SEARCH_RESULT PCB_TYPE_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  534. {
  535. // The Visit() function only visits the testItem if its type was in the
  536. // the scanList, so therefore we can collect anything given to us here.
  537. Append( testItem );
  538. return SEARCH_RESULT::CONTINUE; // always when collecting
  539. }
  540. void PCB_TYPE_COLLECTOR::Collect( BOARD_ITEM* aBoard, const KICAD_T aScanList[] )
  541. {
  542. Empty(); // empty any existing collection
  543. aBoard->Visit( m_inspector, nullptr, aScanList );
  544. }
  545. SEARCH_RESULT PCB_LAYER_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  546. {
  547. BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  548. if( item->IsOnLayer( m_layer_id ) )
  549. Append( testItem );
  550. return SEARCH_RESULT::CONTINUE;
  551. }
  552. void PCB_LAYER_COLLECTOR::Collect( BOARD_ITEM* aBoard, const KICAD_T aScanList[] )
  553. {
  554. Empty();
  555. aBoard->Visit( m_inspector, nullptr, aScanList );
  556. }