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.

540 lines
16 KiB

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-2024 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 <pad.h>
  28. #include <pcb_track.h>
  29. #include <pcb_marker.h>
  30. #include <pcb_dimension.h>
  31. #include <zone.h>
  32. #include <pcb_shape.h>
  33. #include <pcb_group.h>
  34. #include <macros.h>
  35. #include <math/util.h> // for KiROUND
  36. const std::vector<KICAD_T> GENERAL_COLLECTOR::AllBoardItems = {
  37. PCB_MARKER_T, // in m_markers
  38. PCB_TEXT_T, // in m_drawings
  39. PCB_REFERENCE_IMAGE_T, // in m_drawings
  40. PCB_TEXTBOX_T, // in m_drawings
  41. PCB_TABLE_T, // in m_drawings
  42. PCB_TABLECELL_T, // in tables
  43. PCB_SHAPE_T, // in m_drawings
  44. PCB_DIM_ALIGNED_T, // in m_drawings
  45. PCB_DIM_CENTER_T, // in m_drawings
  46. PCB_DIM_RADIAL_T, // in m_drawings
  47. PCB_DIM_ORTHOGONAL_T, // in m_drawings
  48. PCB_DIM_LEADER_T, // in m_drawings
  49. PCB_TARGET_T, // in m_drawings
  50. PCB_VIA_T, // in m_tracks
  51. PCB_TRACE_T, // in m_tracks
  52. PCB_ARC_T, // in m_tracks
  53. PCB_PAD_T, // in footprints
  54. PCB_FIELD_T, // in footprints
  55. PCB_FOOTPRINT_T, // in m_footprints
  56. PCB_GROUP_T, // in m_groups
  57. PCB_ZONE_T, // in m_zones
  58. PCB_GENERATOR_T // in m_generators
  59. };
  60. const std::vector<KICAD_T> GENERAL_COLLECTOR::BoardLevelItems = {
  61. PCB_MARKER_T,
  62. PCB_REFERENCE_IMAGE_T,
  63. PCB_TEXT_T,
  64. PCB_TEXTBOX_T,
  65. PCB_TABLE_T,
  66. PCB_SHAPE_T,
  67. PCB_DIM_ALIGNED_T,
  68. PCB_DIM_ORTHOGONAL_T,
  69. PCB_DIM_CENTER_T,
  70. PCB_DIM_RADIAL_T,
  71. PCB_DIM_LEADER_T,
  72. PCB_TARGET_T,
  73. PCB_VIA_T,
  74. PCB_ARC_T,
  75. PCB_TRACE_T,
  76. PCB_FOOTPRINT_T,
  77. PCB_GROUP_T,
  78. PCB_ZONE_T,
  79. PCB_GENERATOR_T
  80. };
  81. const std::vector<KICAD_T> GENERAL_COLLECTOR::Footprints = {
  82. PCB_FOOTPRINT_T
  83. };
  84. const std::vector<KICAD_T> GENERAL_COLLECTOR::PadsOrTracks = {
  85. PCB_PAD_T,
  86. PCB_VIA_T,
  87. PCB_TRACE_T,
  88. PCB_ARC_T
  89. };
  90. const std::vector<KICAD_T> GENERAL_COLLECTOR::FootprintItems = {
  91. PCB_MARKER_T,
  92. PCB_FIELD_T,
  93. PCB_TEXT_T,
  94. PCB_TEXTBOX_T,
  95. PCB_TABLE_T,
  96. PCB_TABLECELL_T,
  97. PCB_SHAPE_T,
  98. PCB_DIM_ALIGNED_T,
  99. PCB_DIM_ORTHOGONAL_T,
  100. PCB_DIM_CENTER_T,
  101. PCB_DIM_RADIAL_T,
  102. PCB_DIM_LEADER_T,
  103. PCB_PAD_T,
  104. PCB_ZONE_T,
  105. PCB_GROUP_T,
  106. PCB_REFERENCE_IMAGE_T
  107. };
  108. const std::vector<KICAD_T> GENERAL_COLLECTOR::Tracks = {
  109. PCB_TRACE_T,
  110. PCB_ARC_T,
  111. PCB_VIA_T
  112. };
  113. const std::vector<KICAD_T> GENERAL_COLLECTOR::Dimensions = {
  114. PCB_DIM_ALIGNED_T,
  115. PCB_DIM_LEADER_T,
  116. PCB_DIM_ORTHOGONAL_T,
  117. PCB_DIM_CENTER_T,
  118. PCB_DIM_RADIAL_T
  119. };
  120. const std::vector<KICAD_T> GENERAL_COLLECTOR::DraggableItems = {
  121. PCB_TRACE_T,
  122. PCB_VIA_T,
  123. PCB_FOOTPRINT_T,
  124. PCB_ARC_T
  125. };
  126. INSPECT_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* aTestItem, void* aTestData )
  127. {
  128. BOARD_ITEM* boardItem = nullptr;
  129. FOOTPRINT* footprint = nullptr;
  130. PCB_GROUP* group = nullptr;
  131. PAD* pad = nullptr;
  132. bool pad_through = false;
  133. PCB_VIA* via = nullptr;
  134. PCB_MARKER* marker = nullptr;
  135. ZONE* zone = nullptr;
  136. PCB_FIELD* field = nullptr;
  137. PCB_TEXT* text = nullptr;
  138. PCB_DIMENSION_BASE* dimension = nullptr;
  139. switch( aTestItem->Type() )
  140. {
  141. case PCB_PAD_T:
  142. // there are pad specific visibility controls.
  143. // Criteria to select a pad is:
  144. // for smd pads: the footprint parent must be visible, and pads on the corresponding
  145. // board side must be visible
  146. // if pad is a thru hole, then it can be visible when its parent footprint is not.
  147. // for through pads: pads on Front or Back board sides must be visible
  148. pad = static_cast<PAD*>( aTestItem );
  149. boardItem = pad;
  150. if( ( pad->GetAttribute() != PAD_ATTRIB::SMD ) &&
  151. ( pad->GetAttribute() != PAD_ATTRIB::CONN ) ) // a hole is present, so multiple layers
  152. {
  153. // proceed to the common tests below, but without the parent footprint test,
  154. // by leaving footprint==NULL, but having pad != null
  155. pad_through = true;
  156. }
  157. break;
  158. case PCB_VIA_T: // vias are on many layers, so layer test is specific
  159. via = static_cast<PCB_VIA*>( aTestItem );
  160. boardItem = via;
  161. break;
  162. case PCB_TRACE_T:
  163. case PCB_ARC_T:
  164. if( m_Guide->IgnoreTracks() )
  165. return INSPECT_RESULT::CONTINUE;
  166. boardItem = static_cast<PCB_TRACK*>( aTestItem );
  167. break;
  168. case PCB_ZONE_T:
  169. zone = static_cast<ZONE*>( aTestItem );
  170. boardItem = zone;
  171. break;
  172. case PCB_TEXTBOX_T:
  173. case PCB_SHAPE_T:
  174. case PCB_TABLE_T:
  175. case PCB_TABLECELL_T:
  176. boardItem = static_cast<BOARD_ITEM*>( aTestItem );
  177. break;
  178. case PCB_DIM_ALIGNED_T:
  179. case PCB_DIM_CENTER_T:
  180. case PCB_DIM_RADIAL_T:
  181. case PCB_DIM_ORTHOGONAL_T:
  182. case PCB_DIM_LEADER_T:
  183. dimension = static_cast<PCB_DIMENSION_BASE*>( aTestItem );
  184. boardItem = dimension;
  185. break;
  186. case PCB_TARGET_T:
  187. boardItem = static_cast<BOARD_ITEM*>( aTestItem );
  188. break;
  189. case PCB_FIELD_T:
  190. field = static_cast<PCB_FIELD*>( aTestItem );
  191. if( field->IsReference() && m_Guide->IgnoreFPReferences() )
  192. return INSPECT_RESULT::CONTINUE;
  193. if( field->IsValue() && m_Guide->IgnoreFPValues() )
  194. return INSPECT_RESULT::CONTINUE;
  195. KI_FALLTHROUGH;
  196. case PCB_TEXT_T:
  197. text = static_cast<PCB_TEXT*>( aTestItem );
  198. boardItem = text;
  199. if( text->GetParentFootprint() )
  200. {
  201. PCB_LAYER_ID layer = text->GetLayer();
  202. if( m_Guide->IgnoreHiddenFPText() )
  203. {
  204. if( !text->IsVisible() )
  205. return INSPECT_RESULT::CONTINUE;
  206. }
  207. if( m_Guide->IgnoreFPTextOnBack() && IsBackLayer( layer ) )
  208. return INSPECT_RESULT::CONTINUE;
  209. if( m_Guide->IgnoreFPTextOnFront() && IsFrontLayer( layer ) )
  210. return INSPECT_RESULT::CONTINUE;
  211. }
  212. break;
  213. case PCB_FOOTPRINT_T:
  214. footprint = static_cast<FOOTPRINT*>( aTestItem );
  215. boardItem = footprint;
  216. break;
  217. case PCB_GROUP_T:
  218. group = static_cast<PCB_GROUP*>( aTestItem );
  219. boardItem = group;
  220. break;
  221. case PCB_MARKER_T:
  222. marker = static_cast<PCB_MARKER*>( aTestItem );
  223. boardItem = marker;
  224. break;
  225. default:
  226. boardItem = dynamic_cast<BOARD_ITEM*>( aTestItem );
  227. break;
  228. }
  229. if( boardItem && !footprint )
  230. footprint = boardItem->GetParentFootprint();
  231. // common tests:
  232. if( footprint )
  233. {
  234. if( m_Guide->IgnoreFootprintsOnBack() && footprint->GetSide() == B_Cu )
  235. return INSPECT_RESULT::CONTINUE;
  236. if( m_Guide->IgnoreFootprintsOnFront() && footprint->GetSide() == F_Cu )
  237. return INSPECT_RESULT::CONTINUE;
  238. }
  239. // Pads are not sensitive to the layer visibility controls; they all have their own separate
  240. // visibility controls.
  241. if( pad )
  242. {
  243. if( m_Guide->IgnorePads() )
  244. return INSPECT_RESULT::CONTINUE;
  245. if( ! pad_through )
  246. {
  247. if( m_Guide->IgnorePadsOnFront() && pad->IsOnLayer(F_Cu ) )
  248. return INSPECT_RESULT::CONTINUE;
  249. if( m_Guide->IgnorePadsOnBack() && pad->IsOnLayer(B_Cu ) )
  250. return INSPECT_RESULT::CONTINUE;
  251. }
  252. }
  253. if( marker )
  254. {
  255. // Markers are not sensitive to the layer
  256. if( marker->HitTest( m_refPos ) )
  257. Append( aTestItem );
  258. return INSPECT_RESULT::CONTINUE;
  259. }
  260. if( group )
  261. {
  262. // Groups are not sensitive to the layer ... ?
  263. if( group->HitTest( m_refPos ) )
  264. Append( aTestItem );
  265. return INSPECT_RESULT::CONTINUE;
  266. }
  267. if( via )
  268. {
  269. auto type = via->GetViaType();
  270. if( ( m_Guide->IgnoreThroughVias() && type == VIATYPE::THROUGH )
  271. || ( m_Guide->IgnoreBlindBuriedVias() && type == VIATYPE::BLIND_BURIED )
  272. || ( m_Guide->IgnoreMicroVias() && type == VIATYPE::MICROVIA ) )
  273. {
  274. return INSPECT_RESULT::CONTINUE;
  275. }
  276. }
  277. if( boardItem
  278. && ( boardItem->IsOnLayer( m_Guide->GetPreferredLayer() ) )
  279. && ( !boardItem->IsLocked() || !m_Guide->IgnoreLockedItems() ) )
  280. {
  281. // Footprints and their subcomponents: reference, value and pads are not sensitive to the
  282. // layer visibility controls; they all have their own separate visibility controls.
  283. // For vias, GetLayer() has no meaning, but IsOnLayer() works fine.
  284. // User text and fields in a footprint *are* sensitive to layer visibility but they were
  285. // already handled.
  286. int accuracy = m_Guide->Accuracy();
  287. if( zone )
  288. {
  289. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  290. || zone->HitTestForEdge( m_refPos, accuracy ) )
  291. {
  292. Append( aTestItem );
  293. return INSPECT_RESULT::CONTINUE;
  294. }
  295. else if( !m_Guide->IgnoreZoneFills() )
  296. {
  297. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  298. {
  299. if( m_Guide->IsLayerVisible( layer )
  300. && zone->HitTestFilledArea( layer, m_refPos ) )
  301. {
  302. Append( aTestItem );
  303. return INSPECT_RESULT::CONTINUE;
  304. }
  305. }
  306. }
  307. }
  308. else if( aTestItem == footprint )
  309. {
  310. if( footprint->HitTest( m_refPos, accuracy )
  311. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  312. {
  313. Append( aTestItem );
  314. return INSPECT_RESULT::CONTINUE;
  315. }
  316. }
  317. else if( pad || via )
  318. {
  319. if( aTestItem->HitTest( m_refPos, accuracy ) )
  320. {
  321. Append( aTestItem );
  322. return INSPECT_RESULT::CONTINUE;
  323. }
  324. }
  325. else
  326. {
  327. PCB_LAYER_ID layer = boardItem->GetLayer();
  328. if( m_Guide->IsLayerVisible( layer ) )
  329. {
  330. if( dimension )
  331. {
  332. // Dimensions feel particularly hard to select, probably due to their noisy
  333. // shape making it feel like they should have a larger boundary.
  334. accuracy = KiROUND( accuracy * 1.5 );
  335. }
  336. if( aTestItem->HitTest( m_refPos, accuracy ) )
  337. {
  338. Append( aTestItem );
  339. return INSPECT_RESULT::CONTINUE;
  340. }
  341. }
  342. }
  343. }
  344. if( m_Guide->IncludeSecondary()
  345. && ( !boardItem || !boardItem->IsLocked() || !m_Guide->IgnoreLockedItems() ) )
  346. {
  347. // For now, "secondary" means "tolerate any visible layer". It has no effect on other
  348. // criteria, since there is a separate "ignore" control for those in the COLLECTORS_GUIDE
  349. // Footprints and their subcomponents: reference, value and pads are not sensitive to the
  350. // layer visibility controls; they all have their own separate visibility controls.
  351. // For vias, GetLayer() has no meaning, but IsOnLayer() works fine.
  352. // User text and fields in a footprint *are* sensitive to layer visibility but they were
  353. // already handled.
  354. int accuracy = m_Guide->Accuracy();
  355. if( zone )
  356. {
  357. if( zone->HitTestForCorner( m_refPos, accuracy * 2 )
  358. || zone->HitTestForEdge( m_refPos, accuracy ) )
  359. {
  360. Append2nd( aTestItem );
  361. return INSPECT_RESULT::CONTINUE;
  362. }
  363. else if( !m_Guide->IgnoreZoneFills() )
  364. {
  365. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  366. {
  367. if( m_Guide->IsLayerVisible( layer )
  368. && zone->HitTestFilledArea( layer, m_refPos ) )
  369. {
  370. Append2nd( aTestItem );
  371. return INSPECT_RESULT::CONTINUE;
  372. }
  373. }
  374. }
  375. }
  376. else if( aTestItem->Type() == PCB_FOOTPRINT_T )
  377. {
  378. wxCHECK( footprint, INSPECT_RESULT::CONTINUE );
  379. if( footprint->HitTest( m_refPos, accuracy )
  380. && footprint->HitTestAccurate( m_refPos, accuracy ) )
  381. {
  382. Append2nd( aTestItem );
  383. return INSPECT_RESULT::CONTINUE;
  384. }
  385. }
  386. else if( pad || via )
  387. {
  388. if( aTestItem->HitTest( m_refPos, accuracy ) )
  389. {
  390. Append2nd( aTestItem );
  391. return INSPECT_RESULT::CONTINUE;
  392. }
  393. }
  394. else if( boardItem && m_Guide->IsLayerVisible( boardItem->GetLayer() ) )
  395. {
  396. if( dimension )
  397. {
  398. // Dimensions feel particularly hard to select, probably due to their noisy shape
  399. // making it feel like they should have a larger boundary.
  400. accuracy = KiROUND( accuracy * 1.5 );
  401. }
  402. if( aTestItem->HitTest( m_refPos, accuracy ) )
  403. {
  404. Append2nd( aTestItem );
  405. return INSPECT_RESULT::CONTINUE;
  406. }
  407. }
  408. }
  409. return INSPECT_RESULT::CONTINUE; // always when collecting
  410. }
  411. void GENERAL_COLLECTOR::Collect( BOARD_ITEM* aItem, const std::vector<KICAD_T>& aScanTypes,
  412. const VECTOR2I& aRefPos, const COLLECTORS_GUIDE& aGuide )
  413. {
  414. Empty(); // empty the collection, primary criteria list
  415. Empty2nd(); // empty the collection, secondary criteria list
  416. // remember guide, pass it to Inspect()
  417. SetGuide( &aGuide );
  418. SetScanTypes( aScanTypes );
  419. // remember where the snapshot was taken from and pass refPos to
  420. // the Inspect() function.
  421. SetRefPos( aRefPos );
  422. wxCHECK_RET( aItem, "" );
  423. aItem->Visit( m_inspector, nullptr, m_scanTypes );
  424. // append 2nd list onto end of the first list
  425. for( EDA_ITEM* item : m_List2nd )
  426. Append( item );
  427. Empty2nd();
  428. }
  429. INSPECT_RESULT PCB_TYPE_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  430. {
  431. // The Visit() function only visits the testItem if its type was in the the scanList,
  432. // so therefore we can collect anything given to us here.
  433. Append( testItem );
  434. return INSPECT_RESULT::CONTINUE; // always when collecting
  435. }
  436. void PCB_TYPE_COLLECTOR::Collect( BOARD_ITEM* aBoard, const std::vector<KICAD_T>& aTypes )
  437. {
  438. Empty();
  439. aBoard->Visit( m_inspector, nullptr, aTypes );
  440. }
  441. INSPECT_RESULT PCB_LAYER_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
  442. {
  443. BOARD_ITEM* item = (BOARD_ITEM*) testItem;
  444. if( item->IsOnLayer( m_layer_id ) )
  445. Append( testItem );
  446. return INSPECT_RESULT::CONTINUE;
  447. }
  448. void PCB_LAYER_COLLECTOR::Collect( BOARD_ITEM* aBoard, const std::vector<KICAD_T>& aTypes )
  449. {
  450. Empty();
  451. aBoard->Visit( m_inspector, nullptr, aTypes );
  452. }