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.

622 lines
18 KiB

18 years ago
18 years ago
5 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
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-2018 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 <track.h>
  30. #include <pcb_marker.h>
  31. #include <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_SHAPE_T, // in m_drawings
  48. PCB_DIM_ALIGNED_T, // in m_drawings
  49. PCB_DIM_CENTER_T, // in m_drawings
  50. PCB_DIM_ORTHOGONAL_T, // in m_drawings
  51. PCB_DIM_LEADER_T, // in m_drawings
  52. PCB_TARGET_T, // in m_drawings
  53. PCB_VIA_T, // in m_tracks
  54. PCB_TRACE_T, // in m_tracks
  55. PCB_ARC_T, // in m_tracks
  56. PCB_PAD_T, // in footprints
  57. PCB_FP_TEXT_T, // in footprints
  58. PCB_FOOTPRINT_T, // in m_footprints
  59. PCB_GROUP_T, // in m_groups
  60. PCB_ZONE_T, // in m_zones
  61. EOT
  62. };
  63. const KICAD_T GENERAL_COLLECTOR::BoardLevelItems[] = {
  64. PCB_MARKER_T,
  65. PCB_TEXT_T,
  66. PCB_SHAPE_T,
  67. PCB_DIM_ALIGNED_T,
  68. PCB_DIM_ORTHOGONAL_T,
  69. PCB_DIM_CENTER_T,
  70. PCB_DIM_LEADER_T,
  71. PCB_TARGET_T,
  72. PCB_VIA_T,
  73. PCB_ARC_T,
  74. PCB_TRACE_T,
  75. PCB_FOOTPRINT_T,
  76. PCB_GROUP_T,
  77. PCB_ZONE_T,
  78. EOT
  79. };
  80. const KICAD_T GENERAL_COLLECTOR::Footprints[] = {
  81. PCB_FOOTPRINT_T,
  82. EOT
  83. };
  84. const KICAD_T GENERAL_COLLECTOR::PadsOrTracks[] = {
  85. PCB_PAD_T,
  86. PCB_VIA_T,
  87. PCB_TRACE_T,
  88. PCB_ARC_T,
  89. EOT
  90. };
  91. const KICAD_T GENERAL_COLLECTOR::FootprintItems[] = {
  92. PCB_FP_TEXT_T,
  93. PCB_FP_SHAPE_T,
  94. PCB_PAD_T,
  95. PCB_FP_ZONE_T,
  96. PCB_GROUP_T,
  97. EOT
  98. };
  99. const KICAD_T GENERAL_COLLECTOR::Tracks[] = {
  100. PCB_TRACE_T,
  101. PCB_ARC_T,
  102. PCB_VIA_T,
  103. EOT
  104. };
  105. const KICAD_T GENERAL_COLLECTOR::LockableItems[] = {
  106. PCB_FOOTPRINT_T,
  107. PCB_GROUP_T, // Can a group be locked?
  108. PCB_TRACE_T,
  109. PCB_ARC_T,
  110. PCB_VIA_T,
  111. EOT
  112. };
  113. const KICAD_T GENERAL_COLLECTOR::Zones[] = {
  114. PCB_ZONE_T,
  115. PCB_FP_ZONE_T,
  116. EOT
  117. };
  118. const KICAD_T GENERAL_COLLECTOR::Dimensions[] = {
  119. PCB_DIM_ALIGNED_T,
  120. PCB_DIM_LEADER_T,
  121. PCB_DIM_ORTHOGONAL_T,
  122. PCB_DIM_CENTER_T,
  123. EOT
  124. };
  125. SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  126. {
  127. BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  128. FOOTPRINT* footprint = nullptr;
  129. PCB_GROUP* group = nullptr;
  130. PAD* pad = nullptr;
  131. bool pad_through = false;
  132. VIA* via = nullptr;
  133. PCB_MARKER* marker = nullptr;
  134. ZONE* zone = nullptr;
  135. PCB_SHAPE* shape = nullptr;
  136. DIMENSION_BASE* dimension = nullptr;
  137. #if 0 // debugging
  138. static int breakhere = 0;
  139. switch( item->Type() )
  140. {
  141. case PCB_PAD_T:
  142. {
  143. FOOTPRINT* footprint = (FOOTPRINT*) item->GetParent();
  144. if( footprint->GetReference() == wxT( "Y2" ) )
  145. breakhere++;
  146. }
  147. break;
  148. case PCB_VIA_T:
  149. breakhere++;
  150. break;
  151. case PCB_TRACE_T:
  152. case PCB_ARC_T:
  153. breakhere++;
  154. break;
  155. case PCB_TEXT_T:
  156. breakhere++;
  157. break;
  158. case PCB_SHAPE_T:
  159. breakhere++;
  160. break;
  161. case PCB_DIM_ALIGNED_T:
  162. breakhere++;
  163. break;
  164. case PCB_FP_TEXT_T:
  165. {
  166. FP_TEXT* fpText = (FP_TEXT*) item;
  167. if( fpText->GetText() == wxT( "10uH" ) )
  168. breakhere++;
  169. }
  170. break;
  171. case PCB_FOOTPRINT_T:
  172. {
  173. FOOTPRINT* footprint = (FOOTPRINT*) item;
  174. if( footprint->GetReference() == wxT( "C98" ) )
  175. breakhere++;
  176. }
  177. break;
  178. case PCB_MARKER_T:
  179. breakhere++;
  180. break;
  181. default:
  182. breakhere++;
  183. break;
  184. }
  185. #endif
  186. switch( item->Type() )
  187. {
  188. case PCB_PAD_T:
  189. // there are pad specific visibility controls.
  190. // Criterias to select a pad is:
  191. // for smd pads: the footprint parent must be visible, and pads on the corresponding
  192. // board side must be visible
  193. // if pad is a thru hole, then it can be visible when its parent footprint is not.
  194. // for through pads: pads on Front or Back board sides must be visible
  195. pad = static_cast<PAD*>( item );
  196. if( (pad->GetAttribute() != PAD_ATTRIB_SMD) &&
  197. (pad->GetAttribute() != PAD_ATTRIB_CONN) ) // a hole is present, so multiple layers
  198. {
  199. // proceed to the common tests below, but without the parent footprint test,
  200. // by leaving footprint==NULL, but having pad != null
  201. pad_through = true;
  202. }
  203. else // smd, so use pads test after footprint test
  204. {
  205. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  206. }
  207. break;
  208. case PCB_VIA_T: // vias are on many layers, so layer test is specific
  209. via = static_cast<VIA*>( item );
  210. break;
  211. case PCB_TRACE_T:
  212. case PCB_ARC_T:
  213. if( m_Guide->IgnoreTracks() )
  214. goto exit;
  215. break;
  216. case PCB_FP_ZONE_T:
  217. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  218. // Fallthrough to get the zone as well
  219. KI_FALLTHROUGH;
  220. case PCB_ZONE_T:
  221. zone = static_cast<ZONE*>( item );
  222. break;
  223. case PCB_TEXT_T:
  224. break;
  225. case PCB_SHAPE_T:
  226. shape = static_cast<PCB_SHAPE*>( item );
  227. break;
  228. case PCB_DIM_ALIGNED_T:
  229. case PCB_DIM_CENTER_T:
  230. case PCB_DIM_ORTHOGONAL_T:
  231. case PCB_DIM_LEADER_T:
  232. dimension = static_cast<DIMENSION_BASE*>( item );
  233. break;
  234. case PCB_TARGET_T:
  235. break;
  236. case PCB_FP_TEXT_T:
  237. {
  238. FP_TEXT *text = static_cast<FP_TEXT*>( item );
  239. if( m_Guide->IgnoreHiddenFPText() && !text->IsVisible() )
  240. goto exit;
  241. if( m_Guide->IgnoreFPTextOnBack() && IsBackLayer( text->GetLayer() ) )
  242. goto exit;
  243. if( m_Guide->IgnoreFPTextOnFront() && IsFrontLayer( text->GetLayer() ) )
  244. goto exit;
  245. /* The three text types have different criteria: reference
  246. * and value have their own ignore flags; user text instead
  247. * follows their layer visibility. Checking this here is
  248. * simpler than later (when layer visibility is checked for
  249. * other entities) */
  250. switch( text->GetType() )
  251. {
  252. case FP_TEXT::TEXT_is_REFERENCE:
  253. if( m_Guide->IgnoreFPReferences() )
  254. goto exit;
  255. break;
  256. case FP_TEXT::TEXT_is_VALUE:
  257. if( m_Guide->IgnoreFPValues() )
  258. goto exit;
  259. break;
  260. case FP_TEXT::TEXT_is_DIVERS:
  261. if( !m_Guide->IsLayerVisible( text->GetLayer() )
  262. && m_Guide->IgnoreNonVisibleLayers() )
  263. goto exit;
  264. break;
  265. }
  266. // Extract the footprint since it could be hidden
  267. footprint = static_cast<FOOTPRINT*>( item->GetParent() );
  268. }
  269. break;
  270. case PCB_FP_SHAPE_T:
  271. shape = static_cast<FP_SHAPE*>( item );
  272. break;
  273. case PCB_FOOTPRINT_T:
  274. footprint = static_cast<FOOTPRINT*>( item );
  275. break;
  276. case PCB_GROUP_T:
  277. group = static_cast<PCB_GROUP*>( item );
  278. break;
  279. case PCB_MARKER_T:
  280. marker = static_cast<PCB_MARKER*>( item );
  281. break;
  282. default:
  283. break;
  284. }
  285. // common tests:
  286. if( footprint ) // true from case PCB_PAD_T, PCB_FP_TEXT_T, or PCB_FOOTPRINT_T
  287. {
  288. if( m_Guide->IgnoreFootprintsOnBack() && ( footprint->GetLayer() == B_Cu) )
  289. goto exit;
  290. if( m_Guide->IgnoreFootprintsOnFront() && ( footprint->GetLayer() == F_Cu) )
  291. goto exit;
  292. }
  293. // Pads are not sensitive to the layer visibility controls.
  294. // They all have their own separate visibility controls
  295. // skip them if not visible
  296. if( pad )
  297. {
  298. if( m_Guide->IgnorePads() )
  299. goto exit;
  300. if( ! pad_through )
  301. {
  302. if( m_Guide->IgnorePadsOnFront() && pad->IsOnLayer(F_Cu ) )
  303. goto exit;
  304. if( m_Guide->IgnorePadsOnBack() && pad->IsOnLayer(B_Cu ) )
  305. goto exit;
  306. }
  307. }
  308. if( marker )
  309. {
  310. // Markers are not sensitive to the layer
  311. if( marker->HitTest( m_refPos ) )
  312. Append( item );
  313. goto exit;
  314. }
  315. if( group )
  316. {
  317. // Groups are not sensitive to the layer ... ?
  318. if( group->HitTest( m_refPos ) )
  319. Append( item );
  320. goto exit;
  321. }
  322. if( via )
  323. {
  324. auto type = via->GetViaType();
  325. if( ( m_Guide->IgnoreThroughVias() && type == VIATYPE::THROUGH )
  326. || ( m_Guide->IgnoreBlindBuriedVias() && type == VIATYPE::BLIND_BURIED )
  327. || ( m_Guide->IgnoreMicroVias() && type == VIATYPE::MICROVIA ) )
  328. {
  329. goto exit;
  330. }
  331. }
  332. if( item->IsOnLayer( m_Guide->GetPreferredLayer() ) || m_Guide->IgnorePreferredLayer() )
  333. {
  334. PCB_LAYER_ID layer = item->GetLayer();
  335. // footprints and their subcomponents: reference, value and pads are not sensitive
  336. // to the layer visibility controls. They all have their own separate visibility
  337. // controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
  338. // text in a footprint *is* sensitive to layer visibility but that was already handled.
  339. if( via || footprint || pad || m_Guide->IsLayerVisible( layer )
  340. || !m_Guide->IgnoreNonVisibleLayers() )
  341. {
  342. if( !m_Guide->IsLayerLocked( layer ) || !m_Guide->IgnoreLockedLayers() )
  343. {
  344. if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
  345. {
  346. int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
  347. if( zone )
  348. {
  349. bool testFill = !m_Guide->IgnoreZoneFills();
  350. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  351. || zone->HitTestForEdge( m_refPos, accuracy )
  352. || ( testFill && zone->HitTestFilledArea( layer, m_refPos ) ) )
  353. {
  354. Append( item );
  355. goto exit;
  356. }
  357. }
  358. else if( item->Type() == PCB_FOOTPRINT_T )
  359. {
  360. if( footprint->HitTest( m_refPos, accuracy )
  361. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  362. {
  363. Append( item );
  364. goto exit;
  365. }
  366. }
  367. else if( shape )
  368. {
  369. if( shape->HitTest( m_refPos, accuracy ) )
  370. {
  371. Append( shape );
  372. goto exit;
  373. }
  374. }
  375. else if( dimension )
  376. {
  377. // Dimensions feels particularly hard to select, probably due to their
  378. // noisy shape making it feel like they should have a larger bounary.
  379. if( dimension->HitTest( m_refPos, KiROUND( accuracy * 1.5 ) ) )
  380. {
  381. Append( dimension );
  382. goto exit;
  383. }
  384. }
  385. else
  386. {
  387. if( item->HitTest( m_refPos, 0 ) )
  388. {
  389. Append( item );
  390. goto exit;
  391. }
  392. }
  393. }
  394. }
  395. }
  396. }
  397. if( m_Guide->IncludeSecondary() )
  398. {
  399. // for now, "secondary" means "tolerate any layer". It has
  400. // no effect on other criteria, since there is a separate "ignore" control for
  401. // those in the COLLECTORS_GUIDE
  402. PCB_LAYER_ID layer = item->GetLayer();
  403. // footprints and their subcomponents: reference, value and pads are not sensitive
  404. // to the layer visibility controls. They all have their own separate visibility
  405. // controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
  406. // text in a footprint *is* sensitive to layer visibility but that was already handled.
  407. if( via || footprint || pad || zone || m_Guide->IsLayerVisible( layer )
  408. || !m_Guide->IgnoreNonVisibleLayers() )
  409. {
  410. if( !m_Guide->IsLayerLocked( layer ) || !m_Guide->IgnoreLockedLayers() )
  411. {
  412. if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
  413. {
  414. int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
  415. if( zone )
  416. {
  417. bool testFill = !m_Guide->IgnoreZoneFills();
  418. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  419. || zone->HitTestForEdge( m_refPos, accuracy )
  420. || ( testFill && zone->HitTestFilledArea( layer, m_refPos ) ) )
  421. {
  422. Append2nd( item );
  423. goto exit;
  424. }
  425. }
  426. else if( item->Type() == PCB_FOOTPRINT_T )
  427. {
  428. if( footprint->HitTest( m_refPos, accuracy )
  429. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  430. {
  431. Append( item );
  432. goto exit;
  433. }
  434. }
  435. else if( shape )
  436. {
  437. if( shape->HitTest( m_refPos, accuracy ) )
  438. {
  439. Append( shape );
  440. goto exit;
  441. }
  442. }
  443. else if( dimension )
  444. {
  445. // Dimensions feels particularly hard to select, probably due to their
  446. // noisy shape making it feel like they should have a larger bounary.
  447. if( dimension->HitTest( m_refPos, KiROUND( accuracy * 1.5 ) ) )
  448. {
  449. Append( dimension );
  450. goto exit;
  451. }
  452. }
  453. else
  454. {
  455. if( item->HitTest( m_refPos, 0 ) )
  456. {
  457. Append( item );
  458. goto exit;
  459. }
  460. }
  461. }
  462. }
  463. }
  464. }
  465. exit:
  466. return SEARCH_RESULT::CONTINUE; // always when collecting
  467. }
  468. void GENERAL_COLLECTOR::Collect( BOARD_ITEM* aItem, const KICAD_T aScanList[],
  469. const wxPoint& aRefPos, const COLLECTORS_GUIDE& aGuide )
  470. {
  471. Empty(); // empty the collection, primary criteria list
  472. Empty2nd(); // empty the collection, secondary criteria list
  473. // remember guide, pass it to Inspect()
  474. SetGuide( &aGuide );
  475. SetScanTypes( aScanList );
  476. // remember where the snapshot was taken from and pass refPos to
  477. // the Inspect() function.
  478. SetRefPos( aRefPos );
  479. aItem->Visit( m_inspector, NULL, m_scanTypes );
  480. // record the length of the primary list before concatenating on to it.
  481. m_PrimaryLength = m_list.size();
  482. // append 2nd list onto end of the first list
  483. for( unsigned i = 0; i<m_List2nd.size(); ++i )
  484. Append( m_List2nd[i] );
  485. Empty2nd();
  486. }
  487. SEARCH_RESULT PCB_TYPE_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  488. {
  489. // The Visit() function only visits the testItem if its type was in the
  490. // the scanList, so therefore we can collect anything given to us here.
  491. Append( testItem );
  492. return SEARCH_RESULT::CONTINUE; // always when collecting
  493. }
  494. void PCB_TYPE_COLLECTOR::Collect( BOARD_ITEM* aBoard, const KICAD_T aScanList[] )
  495. {
  496. Empty(); // empty any existing collection
  497. aBoard->Visit( m_inspector, NULL, aScanList );
  498. }
  499. SEARCH_RESULT PCB_LAYER_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  500. {
  501. BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  502. if( item->IsOnLayer( m_layer_id ) )
  503. Append( testItem );
  504. return SEARCH_RESULT::CONTINUE;
  505. }
  506. void PCB_LAYER_COLLECTOR::Collect( BOARD_ITEM* aBoard, const KICAD_T aScanList[] )
  507. {
  508. Empty();
  509. aBoard->Visit( m_inspector, NULL, aScanList );
  510. }