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.

1065 lines
38 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
  5. * Copyright (C) 1992-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. /**
  25. * @file create_layer_items.cpp
  26. * @brief This file implements the creation of the pcb board.
  27. *
  28. * It is based on the function found in the files:
  29. * board_items_to_polygon_shape_transform.cpp
  30. * board_items_to_polygon_shape_transform.cpp
  31. */
  32. #include "board_adapter.h"
  33. #include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
  34. #include <board_design_settings.h>
  35. #include <footprint.h>
  36. #include <pad.h>
  37. #include <pcb_text.h>
  38. #include <fp_shape.h>
  39. #include <zone.h>
  40. #include <convert_basic_shapes_to_polygon.h>
  41. #include <trigo.h>
  42. #include <vector>
  43. #include <thread>
  44. #include <core/arraydim.h>
  45. #include <algorithm>
  46. #include <atomic>
  47. #include <wx/log.h>
  48. #ifdef PRINT_STATISTICS_3D_VIEWER
  49. #include <profile.h>
  50. #endif
  51. void BOARD_ADAPTER::destroyLayers()
  52. {
  53. if( !m_layers_poly.empty() )
  54. {
  55. for( auto& poly : m_layers_poly )
  56. delete poly.second;
  57. m_layers_poly.clear();
  58. }
  59. delete m_frontPlatedPadPolys;
  60. m_frontPlatedPadPolys = nullptr;
  61. delete m_backPlatedPadPolys;
  62. m_backPlatedPadPolys = nullptr;
  63. if( !m_layerHoleIdPolys.empty() )
  64. {
  65. for( auto& poly : m_layerHoleIdPolys )
  66. delete poly.second;
  67. m_layerHoleIdPolys.clear();
  68. }
  69. if( !m_layerHoleOdPolys.empty() )
  70. {
  71. for( auto& poly : m_layerHoleOdPolys )
  72. delete poly.second;
  73. m_layerHoleOdPolys.clear();
  74. }
  75. if( !m_layerMap.empty() )
  76. {
  77. for( auto& poly : m_layerMap )
  78. delete poly.second;
  79. m_layerMap.clear();
  80. }
  81. delete m_platedPadsFront;
  82. m_platedPadsFront = nullptr;
  83. delete m_platedPadsBack;
  84. m_platedPadsBack = nullptr;
  85. if( !m_layerHoleMap.empty() )
  86. {
  87. for( auto& poly : m_layerHoleMap )
  88. delete poly.second;
  89. m_layerHoleMap.clear();
  90. }
  91. m_throughHoleIds.Clear();
  92. m_throughHoleOds.Clear();
  93. m_throughHoleAnnularRings.Clear();
  94. m_throughHoleViaOds.Clear();
  95. m_throughHoleViaIds.Clear();
  96. m_nonPlatedThroughHoleOdPolys.RemoveAllContours();
  97. m_throughHoleOdPolys.RemoveAllContours();
  98. m_throughHoleViaOdPolys.RemoveAllContours();
  99. m_throughHoleAnnularRingPolys.RemoveAllContours();
  100. }
  101. void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
  102. {
  103. destroyLayers();
  104. // Build Copper layers
  105. // Based on:
  106. // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
  107. #ifdef PRINT_STATISTICS_3D_VIEWER
  108. unsigned stats_startCopperLayersTime = GetRunningMicroSecs();
  109. unsigned start_Time = stats_startCopperLayersTime;
  110. #endif
  111. PCB_LAYER_ID cu_seq[MAX_CU_LAYERS];
  112. LSET cu_set = LSET::AllCuMask( m_copperLayersCount );
  113. m_trackCount = 0;
  114. m_averageTrackWidth = 0;
  115. m_viaCount = 0;
  116. m_averageViaHoleDiameter = 0;
  117. m_holeCount = 0;
  118. m_averageHoleDiameter = 0;
  119. if( !m_board )
  120. return;
  121. // Prepare track list, convert in a vector. Calc statistic for the holes
  122. std::vector<const PCB_TRACK*> trackList;
  123. trackList.clear();
  124. trackList.reserve( m_board->Tracks().size() );
  125. for( PCB_TRACK* track : m_board->Tracks() )
  126. {
  127. if( !Is3dLayerEnabled( track->GetLayer() ) ) // Skip non enabled layers
  128. continue;
  129. // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
  130. // drill values)
  131. trackList.push_back( track );
  132. if( track->Type() == PCB_VIA_T )
  133. {
  134. const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
  135. m_viaCount++;
  136. m_averageViaHoleDiameter += via->GetDrillValue() * m_biuTo3Dunits;
  137. }
  138. else
  139. {
  140. m_trackCount++;
  141. }
  142. m_averageTrackWidth += track->GetWidth() * m_biuTo3Dunits;
  143. }
  144. if( m_trackCount )
  145. m_averageTrackWidth /= (float)m_trackCount;
  146. if( m_viaCount )
  147. m_averageViaHoleDiameter /= (float)m_viaCount;
  148. // Prepare copper layers index and containers
  149. std::vector< PCB_LAYER_ID > layer_id;
  150. layer_id.clear();
  151. layer_id.reserve( m_copperLayersCount );
  152. for( unsigned i = 0; i < arrayDim( cu_seq ); ++i )
  153. cu_seq[i] = ToLAYER_ID( B_Cu - i );
  154. for( LSEQ cu = cu_set.Seq( cu_seq, arrayDim( cu_seq ) ); cu; ++cu )
  155. {
  156. const PCB_LAYER_ID curr_layer_id = *cu;
  157. if( !Is3dLayerEnabled( curr_layer_id ) ) // Skip non enabled layers
  158. continue;
  159. layer_id.push_back( curr_layer_id );
  160. BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
  161. m_layerMap[curr_layer_id] = layerContainer;
  162. if( m_Cfg->m_Render.opengl_copper_thickness
  163. && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
  164. {
  165. SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
  166. m_layers_poly[curr_layer_id] = layerPoly;
  167. }
  168. }
  169. if( m_Cfg->m_Render.renderPlatedPadsAsPlated && m_Cfg->m_Render.realistic )
  170. {
  171. m_frontPlatedPadPolys = new SHAPE_POLY_SET;
  172. m_backPlatedPadPolys = new SHAPE_POLY_SET;
  173. m_platedPadsFront = new BVH_CONTAINER_2D;
  174. m_platedPadsBack = new BVH_CONTAINER_2D;
  175. }
  176. if( aStatusReporter )
  177. aStatusReporter->Report( _( "Create tracks and vias" ) );
  178. // Create tracks as objects and add it to container
  179. for( PCB_LAYER_ID curr_layer_id : layer_id )
  180. {
  181. wxASSERT( m_layerMap.find( curr_layer_id ) != m_layerMap.end() );
  182. BVH_CONTAINER_2D *layerContainer = m_layerMap[curr_layer_id];
  183. // Add track segments shapes and via annulus shapes
  184. unsigned int nTracks = trackList.size();
  185. for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
  186. {
  187. const PCB_TRACK *track = trackList[trackIdx];
  188. // NOTE: Vias can be on multiple layers
  189. if( !track->IsOnLayer( curr_layer_id ) )
  190. continue;
  191. // Skip vias annulus when not connected on this layer (if removing is enabled)
  192. const PCB_VIA *via = dyn_cast< const PCB_VIA*>( track );
  193. if( via && !via->FlashLayer( curr_layer_id ) && IsCopperLayer( curr_layer_id ) )
  194. continue;
  195. // Add object item to layer container
  196. createTrack( track, layerContainer, 0.0f );
  197. }
  198. }
  199. // Create VIAS and THTs objects and add it to holes containers
  200. for( PCB_LAYER_ID curr_layer_id : layer_id )
  201. {
  202. // ADD TRACKS
  203. unsigned int nTracks = trackList.size();
  204. for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
  205. {
  206. const PCB_TRACK *track = trackList[trackIdx];
  207. if( !track->IsOnLayer( curr_layer_id ) )
  208. continue;
  209. // ADD VIAS and THT
  210. if( track->Type() == PCB_VIA_T )
  211. {
  212. const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
  213. const VIATYPE viatype = via->GetViaType();
  214. const float holediameter = via->GetDrillValue() * BiuTo3dUnits();
  215. // holes and layer copper extend half info cylinder wall to hide transition
  216. const float thickness = GetHolePlatingThickness() * BiuTo3dUnits() / 2.0f;
  217. const float hole_inner_radius = holediameter / 2.0f;
  218. const float ring_radius = via->GetWidth() * BiuTo3dUnits() / 2.0f;
  219. const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
  220. -via->GetStart().y * m_biuTo3Dunits );
  221. if( viatype != VIATYPE::THROUGH )
  222. {
  223. // Add hole objects
  224. BVH_CONTAINER_2D *layerHoleContainer = nullptr;
  225. // Check if the layer is already created
  226. if( m_layerHoleMap.find( curr_layer_id ) == m_layerHoleMap.end() )
  227. {
  228. // not found, create a new container
  229. layerHoleContainer = new BVH_CONTAINER_2D;
  230. m_layerHoleMap[curr_layer_id] = layerHoleContainer;
  231. }
  232. else
  233. {
  234. // found
  235. layerHoleContainer = m_layerHoleMap[curr_layer_id];
  236. }
  237. // Add a hole for this layer
  238. layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center,
  239. hole_inner_radius + thickness,
  240. *track ) );
  241. }
  242. else if( curr_layer_id == layer_id[0] ) // it only adds once the THT holes
  243. {
  244. // Add through hole object
  245. m_throughHoleOds.Add( new FILLED_CIRCLE_2D( via_center,
  246. hole_inner_radius + thickness,
  247. *track ) );
  248. m_throughHoleViaOds.Add( new FILLED_CIRCLE_2D( via_center,
  249. hole_inner_radius + thickness,
  250. *track ) );
  251. if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic )
  252. {
  253. m_throughHoleAnnularRings.Add( new FILLED_CIRCLE_2D( via_center,
  254. ring_radius,
  255. *track ) );
  256. }
  257. m_throughHoleIds.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius,
  258. *track ) );
  259. }
  260. }
  261. }
  262. }
  263. // Create VIAS and THTs objects and add it to holes containers
  264. for( PCB_LAYER_ID curr_layer_id : layer_id )
  265. {
  266. // ADD TRACKS
  267. const unsigned int nTracks = trackList.size();
  268. for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
  269. {
  270. const PCB_TRACK *track = trackList[trackIdx];
  271. if( !track->IsOnLayer( curr_layer_id ) )
  272. continue;
  273. // ADD VIAS and THT
  274. if( track->Type() == PCB_VIA_T )
  275. {
  276. const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
  277. const VIATYPE viatype = via->GetViaType();
  278. if( viatype != VIATYPE::THROUGH )
  279. {
  280. // Add PCB_VIA hole contours
  281. // Add outer holes of VIAs
  282. SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
  283. SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
  284. // Check if the layer is already created
  285. if( m_layerHoleOdPolys.find( curr_layer_id ) ==
  286. m_layerHoleOdPolys.end() )
  287. {
  288. // not found, create a new container
  289. layerOuterHolesPoly = new SHAPE_POLY_SET;
  290. m_layerHoleOdPolys[curr_layer_id] = layerOuterHolesPoly;
  291. wxASSERT( m_layerHoleIdPolys.find( curr_layer_id ) ==
  292. m_layerHoleIdPolys.end() );
  293. layerInnerHolesPoly = new SHAPE_POLY_SET;
  294. m_layerHoleIdPolys[curr_layer_id] = layerInnerHolesPoly;
  295. }
  296. else
  297. {
  298. // found
  299. layerOuterHolesPoly = m_layerHoleOdPolys[curr_layer_id];
  300. wxASSERT( m_layerHoleIdPolys.find( curr_layer_id ) !=
  301. m_layerHoleIdPolys.end() );
  302. layerInnerHolesPoly = m_layerHoleIdPolys[curr_layer_id];
  303. }
  304. const int holediameter = via->GetDrillValue();
  305. const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
  306. TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(),
  307. hole_outer_radius, ARC_HIGH_DEF, ERROR_INSIDE );
  308. TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(),
  309. holediameter / 2, ARC_HIGH_DEF, ERROR_INSIDE );
  310. }
  311. else if( curr_layer_id == layer_id[0] ) // it only adds once the THT holes
  312. {
  313. const int holediameter = via->GetDrillValue();
  314. const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
  315. const int hole_outer_ring_radius = via->GetWidth() / 2.0f;
  316. // Add through hole contours
  317. TransformCircleToPolygon( m_throughHoleOdPolys, via->GetStart(),
  318. hole_outer_radius, ARC_HIGH_DEF, ERROR_INSIDE );
  319. // Add same thing for vias only
  320. TransformCircleToPolygon( m_throughHoleViaOdPolys, via->GetStart(),
  321. hole_outer_radius, ARC_HIGH_DEF, ERROR_INSIDE );
  322. if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic )
  323. {
  324. TransformCircleToPolygon( m_throughHoleAnnularRingPolys, via->GetStart(),
  325. hole_outer_ring_radius, ARC_HIGH_DEF,
  326. ERROR_INSIDE );
  327. }
  328. }
  329. }
  330. }
  331. }
  332. // Creates vertical outline contours of the tracks and add it to the poly of the layer
  333. if( m_Cfg->m_Render.opengl_copper_thickness && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
  334. {
  335. for( PCB_LAYER_ID curr_layer_id : layer_id )
  336. {
  337. wxASSERT( m_layers_poly.find( curr_layer_id ) != m_layers_poly.end() );
  338. SHAPE_POLY_SET *layerPoly = m_layers_poly[curr_layer_id];
  339. // ADD TRACKS
  340. unsigned int nTracks = trackList.size();
  341. for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
  342. {
  343. const PCB_TRACK *track = trackList[trackIdx];
  344. if( !track->IsOnLayer( curr_layer_id ) )
  345. continue;
  346. // Skip vias annulus when not connected on this layer (if removing is enabled)
  347. const PCB_VIA *via = dyn_cast<const PCB_VIA*>( track );
  348. if( via && !via->FlashLayer( curr_layer_id ) && IsCopperLayer( curr_layer_id ) )
  349. continue;
  350. // Add the track/via contour
  351. track->TransformShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0,
  352. ARC_HIGH_DEF, ERROR_INSIDE );
  353. }
  354. }
  355. }
  356. // Add holes of footprints
  357. for( FOOTPRINT* footprint : m_board->Footprints() )
  358. {
  359. for( PAD* pad : footprint->Pads() )
  360. {
  361. const wxSize padHole = pad->GetDrillSize();
  362. if( !padHole.x ) // Not drilled pad like SMD pad
  363. continue;
  364. // The hole in the body is inflated by copper thickness, if not plated, no copper
  365. const int inflate = ( pad->GetAttribute () != PAD_ATTRIB::NPTH ) ?
  366. GetHolePlatingThickness() / 2 : 0;
  367. m_holeCount++;
  368. m_averageHoleDiameter += ( ( pad->GetDrillSize().x +
  369. pad->GetDrillSize().y ) / 2.0f ) * m_biuTo3Dunits;
  370. m_throughHoleOds.Add( createPadWithDrill( pad, inflate ) );
  371. if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic )
  372. m_throughHoleAnnularRings.Add( createPadWithDrill( pad, inflate ) );
  373. m_throughHoleIds.Add( createPadWithDrill( pad, 0 ) );
  374. }
  375. }
  376. if( m_holeCount )
  377. m_averageHoleDiameter /= (float)m_holeCount;
  378. // Add contours of the pad holes (pads can be Circle or Segment holes)
  379. for( FOOTPRINT* footprint : m_board->Footprints() )
  380. {
  381. for( PAD* pad : footprint->Pads() )
  382. {
  383. const wxSize padHole = pad->GetDrillSize();
  384. if( !padHole.x ) // Not drilled pad like SMD pad
  385. continue;
  386. // The hole in the body is inflated by copper thickness.
  387. const int inflate = GetHolePlatingThickness();
  388. if( pad->GetAttribute () != PAD_ATTRIB::NPTH )
  389. {
  390. if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic )
  391. {
  392. pad->TransformHoleWithClearanceToPolygon( m_throughHoleAnnularRingPolys,
  393. inflate, ARC_HIGH_DEF, ERROR_INSIDE );
  394. }
  395. pad->TransformHoleWithClearanceToPolygon( m_throughHoleOdPolys, inflate,
  396. ARC_HIGH_DEF, ERROR_INSIDE );
  397. }
  398. else
  399. {
  400. // If not plated, no copper.
  401. if( m_Cfg->m_Render.clip_silk_on_via_annulus && m_Cfg->m_Render.realistic )
  402. {
  403. pad->TransformHoleWithClearanceToPolygon( m_throughHoleAnnularRingPolys, 0,
  404. ARC_HIGH_DEF, ERROR_INSIDE );
  405. }
  406. pad->TransformHoleWithClearanceToPolygon( m_nonPlatedThroughHoleOdPolys, 0,
  407. ARC_HIGH_DEF, ERROR_INSIDE );
  408. }
  409. }
  410. }
  411. const bool renderPlatedPadsAsPlated = m_Cfg->m_Render.renderPlatedPadsAsPlated
  412. && m_Cfg->m_Render.realistic;
  413. // Add footprints PADs objects to containers
  414. for( PCB_LAYER_ID curr_layer_id : layer_id )
  415. {
  416. wxASSERT( m_layerMap.find( curr_layer_id ) != m_layerMap.end() );
  417. BVH_CONTAINER_2D *layerContainer = m_layerMap[curr_layer_id];
  418. // ADD PADS
  419. for( FOOTPRINT* footprint : m_board->Footprints() )
  420. {
  421. // Note: NPTH pads are not drawn on copper layers when the pad has the same shape
  422. // as its hole
  423. addPadsWithClearance( footprint, layerContainer, curr_layer_id, 0, true,
  424. renderPlatedPadsAsPlated, false );
  425. // Micro-wave footprints may have items on copper layers
  426. addFootprintShapesWithClearance( footprint, layerContainer, curr_layer_id, 0 );
  427. }
  428. }
  429. if( renderPlatedPadsAsPlated )
  430. {
  431. // ADD PLATED PADS
  432. for( FOOTPRINT* footprint : m_board->Footprints() )
  433. {
  434. addPadsWithClearance( footprint, m_platedPadsFront, F_Cu, 0, true, false, true );
  435. addPadsWithClearance( footprint, m_platedPadsBack, B_Cu, 0, true, false, true );
  436. }
  437. m_platedPadsFront->BuildBVH();
  438. m_platedPadsBack->BuildBVH();
  439. }
  440. // Add footprints PADs poly contours (vertical outlines)
  441. if( m_Cfg->m_Render.opengl_copper_thickness && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
  442. {
  443. for( PCB_LAYER_ID curr_layer_id : layer_id )
  444. {
  445. wxASSERT( m_layers_poly.find( curr_layer_id ) != m_layers_poly.end() );
  446. SHAPE_POLY_SET *layerPoly = m_layers_poly[curr_layer_id];
  447. // Add pads to polygon list
  448. for( FOOTPRINT* footprint : m_board->Footprints() )
  449. {
  450. // Note: NPTH pads are not drawn on copper layers when the pad
  451. // has same shape as its hole
  452. footprint->TransformPadsWithClearanceToPolygon( *layerPoly, curr_layer_id,
  453. 0, ARC_HIGH_DEF, ERROR_INSIDE,
  454. true, renderPlatedPadsAsPlated,
  455. false );
  456. transformFPShapesToPolygon( footprint, curr_layer_id, *layerPoly );
  457. }
  458. }
  459. if( renderPlatedPadsAsPlated )
  460. {
  461. // ADD PLATED PADS contours
  462. for( FOOTPRINT* footprint : m_board->Footprints() )
  463. {
  464. footprint->TransformPadsWithClearanceToPolygon( *m_frontPlatedPadPolys, F_Cu,
  465. 0, ARC_HIGH_DEF, ERROR_INSIDE,
  466. true, false, true );
  467. footprint->TransformPadsWithClearanceToPolygon( *m_backPlatedPadPolys, B_Cu,
  468. 0, ARC_HIGH_DEF, ERROR_INSIDE,
  469. true, false, true );
  470. }
  471. }
  472. }
  473. // Add graphic item on copper layers to object containers
  474. for( PCB_LAYER_ID curr_layer_id : layer_id )
  475. {
  476. wxASSERT( m_layerMap.find( curr_layer_id ) != m_layerMap.end() );
  477. BVH_CONTAINER_2D *layerContainer = m_layerMap[curr_layer_id];
  478. // Add graphic items on copper layers (texts and other graphics)
  479. for( BOARD_ITEM* item : m_board->Drawings() )
  480. {
  481. if( !item->IsOnLayer( curr_layer_id ) )
  482. continue;
  483. switch( item->Type() )
  484. {
  485. case PCB_SHAPE_T:
  486. addShapeWithClearance( static_cast<PCB_SHAPE*>( item ), layerContainer,
  487. curr_layer_id, 0 );
  488. break;
  489. case PCB_TEXT_T:
  490. addShapeWithClearance( static_cast<PCB_TEXT*>( item ), layerContainer,
  491. curr_layer_id, 0 );
  492. break;
  493. case PCB_DIM_ALIGNED_T:
  494. case PCB_DIM_CENTER_T:
  495. case PCB_DIM_RADIAL_T:
  496. case PCB_DIM_ORTHOGONAL_T:
  497. case PCB_DIM_LEADER_T:
  498. addShapeWithClearance( static_cast<PCB_DIMENSION_BASE*>( item ),
  499. layerContainer, curr_layer_id, 0 );
  500. break;
  501. default:
  502. wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
  503. item->Type() );
  504. break;
  505. }
  506. }
  507. }
  508. // Add graphic item on copper layers to poly contours (vertical outlines)
  509. if( m_Cfg->m_Render.opengl_copper_thickness && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
  510. {
  511. for( PCB_LAYER_ID cur_layer_id : layer_id )
  512. {
  513. wxASSERT( m_layers_poly.find( cur_layer_id ) != m_layers_poly.end() );
  514. SHAPE_POLY_SET *layerPoly = m_layers_poly[cur_layer_id];
  515. // Add graphic items on copper layers (texts and other )
  516. for( BOARD_ITEM* item : m_board->Drawings() )
  517. {
  518. if( !item->IsOnLayer( cur_layer_id ) )
  519. continue;
  520. switch( item->Type() )
  521. {
  522. case PCB_SHAPE_T:
  523. item->TransformShapeWithClearanceToPolygon( *layerPoly, cur_layer_id, 0,
  524. ARC_HIGH_DEF, ERROR_INSIDE );
  525. break;
  526. case PCB_TEXT_T:
  527. {
  528. PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
  529. text->TransformTextShapeWithClearanceToPolygon( *layerPoly, cur_layer_id, 0,
  530. ARC_HIGH_DEF, ERROR_INSIDE );
  531. }
  532. break;
  533. default:
  534. wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
  535. item->Type() );
  536. break;
  537. }
  538. }
  539. }
  540. }
  541. if( m_Cfg->m_Render.show_zones )
  542. {
  543. if( aStatusReporter )
  544. aStatusReporter->Report( _( "Create zones" ) );
  545. std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
  546. std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
  547. for( ZONE* zone : m_board->Zones() )
  548. {
  549. for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
  550. {
  551. zones.emplace_back( std::make_pair( zone, layer ) );
  552. layer_lock.emplace( layer, std::make_unique<std::mutex>() );
  553. }
  554. }
  555. // Add zones objects
  556. std::atomic<size_t> nextZone( 0 );
  557. std::atomic<size_t> threadsFinished( 0 );
  558. size_t parallelThreadCount = std::min<size_t>( zones.size(),
  559. std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
  560. for( size_t ii = 0; ii < parallelThreadCount; ++ii )
  561. {
  562. std::thread t = std::thread( [&]()
  563. {
  564. for( size_t areaId = nextZone.fetch_add( 1 );
  565. areaId < zones.size();
  566. areaId = nextZone.fetch_add( 1 ) )
  567. {
  568. ZONE* zone = zones[areaId].first;
  569. if( zone == nullptr )
  570. break;
  571. PCB_LAYER_ID layer = zones[areaId].second;
  572. auto layerContainer = m_layerMap.find( layer );
  573. auto layerPolyContainer = m_layers_poly.find( layer );
  574. if( layerContainer != m_layerMap.end() )
  575. {
  576. addSolidAreasShapes( zone, layerContainer->second, layer );
  577. }
  578. if( m_Cfg->m_Render.opengl_copper_thickness
  579. && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL
  580. && layerPolyContainer != m_layers_poly.end() )
  581. {
  582. auto mut_it = layer_lock.find( layer );
  583. std::lock_guard< std::mutex > lock( *( mut_it->second ) );
  584. zone->TransformSolidAreasShapesToPolygon( layer, *layerPolyContainer->second );
  585. }
  586. }
  587. threadsFinished++;
  588. } );
  589. t.detach();
  590. }
  591. while( threadsFinished < parallelThreadCount )
  592. std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
  593. }
  594. // Simplify layer polygons
  595. if( aStatusReporter )
  596. aStatusReporter->Report( _( "Simplifying copper layers polygons" ) );
  597. if( m_Cfg->m_Render.opengl_copper_thickness && m_Cfg->m_Render.engine == RENDER_ENGINE::OPENGL )
  598. {
  599. if( renderPlatedPadsAsPlated )
  600. {
  601. if( m_frontPlatedPadPolys && ( m_layers_poly.find( F_Cu ) != m_layers_poly.end() ) )
  602. {
  603. if( aStatusReporter )
  604. aStatusReporter->Report( _( "Simplifying polygons on F_Cu" ) );
  605. SHAPE_POLY_SET *layerPoly_F_Cu = m_layers_poly[F_Cu];
  606. layerPoly_F_Cu->BooleanSubtract( *m_frontPlatedPadPolys, SHAPE_POLY_SET::PM_FAST );
  607. m_frontPlatedPadPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
  608. }
  609. if( m_backPlatedPadPolys && ( m_layers_poly.find( B_Cu ) != m_layers_poly.end() ) )
  610. {
  611. if( aStatusReporter )
  612. aStatusReporter->Report( _( "Simplifying polygons on B_Cu" ) );
  613. SHAPE_POLY_SET *layerPoly_B_Cu = m_layers_poly[B_Cu];
  614. layerPoly_B_Cu->BooleanSubtract( *m_backPlatedPadPolys, SHAPE_POLY_SET::PM_FAST );
  615. m_backPlatedPadPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
  616. }
  617. }
  618. std::vector< PCB_LAYER_ID > &selected_layer_id = layer_id;
  619. std::vector< PCB_LAYER_ID > layer_id_without_F_and_B;
  620. if( renderPlatedPadsAsPlated )
  621. {
  622. layer_id_without_F_and_B.clear();
  623. layer_id_without_F_and_B.reserve( layer_id.size() );
  624. for( size_t i = 0; i < layer_id.size(); ++i )
  625. {
  626. if( ( layer_id[i] != F_Cu ) && ( layer_id[i] != B_Cu ) )
  627. layer_id_without_F_and_B.push_back( layer_id[i] );
  628. }
  629. selected_layer_id = layer_id_without_F_and_B;
  630. }
  631. if( selected_layer_id.size() > 0 )
  632. {
  633. if( aStatusReporter )
  634. {
  635. aStatusReporter->Report( wxString::Format( _( "Simplifying %d copper layers" ),
  636. (int) selected_layer_id.size() ) );
  637. }
  638. std::atomic<size_t> nextItem( 0 );
  639. std::atomic<size_t> threadsFinished( 0 );
  640. size_t parallelThreadCount = std::min<size_t>(
  641. std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
  642. selected_layer_id.size() );
  643. for( size_t ii = 0; ii < parallelThreadCount; ++ii )
  644. {
  645. std::thread t = std::thread(
  646. [&nextItem, &threadsFinished, &selected_layer_id, this]()
  647. {
  648. for( size_t i = nextItem.fetch_add( 1 );
  649. i < selected_layer_id.size();
  650. i = nextItem.fetch_add( 1 ) )
  651. {
  652. auto layerPoly = m_layers_poly.find( selected_layer_id[i] );
  653. if( layerPoly != m_layers_poly.end() )
  654. // This will make a union of all added contours
  655. layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
  656. }
  657. threadsFinished++;
  658. } );
  659. t.detach();
  660. }
  661. while( threadsFinished < parallelThreadCount )
  662. std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
  663. }
  664. }
  665. // Simplify holes polygon contours
  666. if( aStatusReporter )
  667. aStatusReporter->Report( _( "Simplify holes contours" ) );
  668. for( PCB_LAYER_ID layer : layer_id )
  669. {
  670. if( m_layerHoleOdPolys.find( layer ) != m_layerHoleOdPolys.end() )
  671. {
  672. // found
  673. SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
  674. polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
  675. wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
  676. polyLayer = m_layerHoleIdPolys[layer];
  677. polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
  678. }
  679. }
  680. // End Build Copper layers
  681. // This will make a union of all added contours
  682. m_throughHoleOdPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
  683. m_nonPlatedThroughHoleOdPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
  684. m_throughHoleViaOdPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
  685. m_throughHoleAnnularRingPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
  686. // Build Tech layers
  687. // Based on:
  688. // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
  689. if( aStatusReporter )
  690. aStatusReporter->Report( _( "Build Tech layers" ) );
  691. // draw graphic items, on technical layers
  692. static const PCB_LAYER_ID teckLayerList[] = {
  693. B_Adhes,
  694. F_Adhes,
  695. B_Paste,
  696. F_Paste,
  697. B_SilkS,
  698. F_SilkS,
  699. B_Mask,
  700. F_Mask,
  701. // Aux Layers
  702. Dwgs_User,
  703. Cmts_User,
  704. Eco1_User,
  705. Eco2_User,
  706. Edge_Cuts,
  707. Margin
  708. };
  709. // User layers are not drawn here, only technical layers
  710. for( LSEQ seq = LSET::AllNonCuMask().Seq( teckLayerList, arrayDim( teckLayerList ) );
  711. seq;
  712. ++seq )
  713. {
  714. const PCB_LAYER_ID curr_layer_id = *seq;
  715. if( !Is3dLayerEnabled( curr_layer_id ) )
  716. continue;
  717. if( aStatusReporter )
  718. aStatusReporter->Report( wxString::Format(
  719. _( "Build Tech layer %d" ), (int)curr_layer_id ) );
  720. BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
  721. m_layerMap[curr_layer_id] = layerContainer;
  722. SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
  723. m_layers_poly[curr_layer_id] = layerPoly;
  724. // Add drawing objects
  725. for( BOARD_ITEM* item : m_board->Drawings() )
  726. {
  727. if( !item->IsOnLayer( curr_layer_id ) )
  728. continue;
  729. switch( item->Type() )
  730. {
  731. case PCB_SHAPE_T:
  732. addShapeWithClearance( static_cast<PCB_SHAPE*>( item ), layerContainer,
  733. curr_layer_id, 0 );
  734. break;
  735. case PCB_TEXT_T:
  736. addShapeWithClearance( static_cast<PCB_TEXT*>( item ), layerContainer,
  737. curr_layer_id, 0 );
  738. break;
  739. case PCB_DIM_ALIGNED_T:
  740. case PCB_DIM_CENTER_T:
  741. case PCB_DIM_RADIAL_T:
  742. case PCB_DIM_ORTHOGONAL_T:
  743. case PCB_DIM_LEADER_T:
  744. addShapeWithClearance( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer,
  745. curr_layer_id, 0 );
  746. break;
  747. default:
  748. break;
  749. }
  750. }
  751. // Add drawing contours
  752. for( BOARD_ITEM* item : m_board->Drawings() )
  753. {
  754. if( !item->IsOnLayer( curr_layer_id ) )
  755. continue;
  756. switch( item->Type() )
  757. {
  758. case PCB_SHAPE_T:
  759. item->TransformShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0,
  760. ARC_HIGH_DEF, ERROR_INSIDE );
  761. break;
  762. case PCB_TEXT_T:
  763. {
  764. PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
  765. text->TransformTextShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0,
  766. ARC_HIGH_DEF, ERROR_INSIDE );
  767. }
  768. break;
  769. default:
  770. break;
  771. }
  772. }
  773. // Add footprints tech layers - objects
  774. for( FOOTPRINT* footprint : m_board->Footprints() )
  775. {
  776. if( ( curr_layer_id == F_SilkS ) || ( curr_layer_id == B_SilkS ) )
  777. {
  778. int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
  779. for( PAD* pad : footprint->Pads() )
  780. {
  781. if( !pad->IsOnLayer( curr_layer_id ) )
  782. continue;
  783. buildPadOutlineAsSegments( pad, layerContainer, linewidth );
  784. }
  785. }
  786. else
  787. {
  788. addPadsWithClearance( footprint, layerContainer, curr_layer_id, 0,
  789. false, false, false );
  790. }
  791. addFootprintShapesWithClearance( footprint, layerContainer, curr_layer_id, 0 );
  792. }
  793. // Add footprints tech layers - contours
  794. for( FOOTPRINT* footprint : m_board->Footprints() )
  795. {
  796. if( ( curr_layer_id == F_SilkS ) || ( curr_layer_id == B_SilkS ) )
  797. {
  798. int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
  799. for( PAD* pad : footprint->Pads() )
  800. {
  801. if( !pad->IsOnLayer( curr_layer_id ) )
  802. continue;
  803. buildPadOutlineAsPolygon( pad, *layerPoly, linewidth );
  804. }
  805. }
  806. else
  807. {
  808. footprint->TransformPadsWithClearanceToPolygon( *layerPoly, curr_layer_id, 0,
  809. ARC_HIGH_DEF, ERROR_INSIDE );
  810. }
  811. // On tech layers, use a poor circle approximation, only for texts (stroke font)
  812. footprint->TransformFPTextWithClearanceToPolygonSet( *layerPoly, curr_layer_id, 0,
  813. ARC_HIGH_DEF, ERROR_INSIDE );
  814. // Add the remaining things with dynamic seg count for circles
  815. transformFPShapesToPolygon( footprint, curr_layer_id, *layerPoly );
  816. }
  817. // Draw non copper zones
  818. if( m_Cfg->m_Render.show_zones )
  819. {
  820. for( ZONE* zone : m_board->Zones() )
  821. {
  822. if( zone->IsOnLayer( curr_layer_id ) )
  823. addSolidAreasShapes( zone, layerContainer, curr_layer_id );
  824. }
  825. for( ZONE* zone : m_board->Zones() )
  826. {
  827. if( zone->IsOnLayer( curr_layer_id ) )
  828. zone->TransformSolidAreasShapesToPolygon( curr_layer_id, *layerPoly );
  829. }
  830. }
  831. // This will make a union of all added contours
  832. layerPoly->Simplify( SHAPE_POLY_SET::PM_FAST );
  833. }
  834. // End Build Tech layers
  835. // Build BVH (Bounding volume hierarchy) for holes and vias
  836. if( aStatusReporter )
  837. aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
  838. m_throughHoleIds.BuildBVH();
  839. m_throughHoleOds.BuildBVH();
  840. m_throughHoleAnnularRings.BuildBVH();
  841. if( !m_layerHoleMap.empty() )
  842. {
  843. for( auto& hole : m_layerHoleMap )
  844. hole.second->BuildBVH();
  845. }
  846. // We only need the Solder mask to initialize the BVH
  847. // because..?
  848. if( m_layerMap[B_Mask] )
  849. m_layerMap[B_Mask]->BuildBVH();
  850. if( m_layerMap[F_Mask] )
  851. m_layerMap[F_Mask]->BuildBVH();
  852. }