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.

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