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.

602 lines
17 KiB

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