KiCad PCB EDA Suite
legacy/create_scene.cpp
Go to the documentation of this file.
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) 2015-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 #include "render_3d_legacy.h"
26 #include "ogl_legacy_utils.h"
27 #include <board.h>
28 #include <footprint.h>
29 #include "../../3d_math.h"
30 #include <trigo.h>
31 #include <project.h>
32 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
33 
34 
36  TRIANGLE_DISPLAY_LIST* aDstLayer,
37  float aZtop, float aZbot )
38 {
39  const SFVEC2F& center = aFilledCircle->GetCenter();
40  const float radius = aFilledCircle->GetRadius() * 2.0f; // Double because the render triangle
41 
42  // This is a small adjustment to the circle texture
43  const float texture_factor = ( 8.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
44  const float f = ( sqrtf( 2.0f ) / 2.0f ) * radius * texture_factor;
45 
46  // Top and Bot segments ends are just triangle semi-circles, so need to add it in duplicated.
47  aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZtop ),
48  SFVEC3F( center.x - f, center.y, aZtop ),
49  SFVEC3F( center.x, center.y - f, aZtop ) );
50 
51  aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZtop ),
52  SFVEC3F( center.x + f, center.y, aZtop ),
53  SFVEC3F( center.x, center.y + f, aZtop ) );
54 
55  aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZbot ),
56  SFVEC3F( center.x + f, center.y, aZbot ),
57  SFVEC3F( center.x, center.y - f, aZbot ) );
58 
59  aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZbot ),
60  SFVEC3F( center.x - f, center.y, aZbot ),
61  SFVEC3F( center.x, center.y + f, aZbot ) );
62 }
63 
64 
66  TRIANGLE_DISPLAY_LIST* aDstLayer,
67  float aZtop, float aZbot )
68 {
69  const SFVEC2F& v0 = aPoly->GetV0();
70  const SFVEC2F& v1 = aPoly->GetV1();
71  const SFVEC2F& v2 = aPoly->GetV2();
72  const SFVEC2F& v3 = aPoly->GetV3();
73 
74  addTopAndBottomTriangles( aDstLayer, v0, v2, v1, aZtop, aZbot );
75  addTopAndBottomTriangles( aDstLayer, v2, v0, v3, aZtop, aZbot );
76 }
77 
78 
79 void RENDER_3D_LEGACY::generateRing( const SFVEC2F& aCenter, float aInnerRadius,
80  float aOuterRadius, unsigned int aNr_sides_per_circle,
81  std::vector< SFVEC2F >& aInnerContourResult,
82  std::vector< SFVEC2F >& aOuterContourResult,
83  bool aInvertOrder )
84 {
85  aInnerContourResult.clear();
86  aInnerContourResult.reserve( aNr_sides_per_circle + 2 );
87 
88  aOuterContourResult.clear();
89  aOuterContourResult.reserve( aNr_sides_per_circle + 2 );
90 
91  const int delta = 3600 / aNr_sides_per_circle;
92 
93  for( int ii = 0; ii < 3600; ii += delta )
94  {
95  float angle = (float)( aInvertOrder ? ( 3600 - ii ) : ii )
96  * 2.0f * glm::pi<float>() / 3600.0f;
97  const SFVEC2F rotatedDir = SFVEC2F( cos( angle ), sin( angle ) );
98 
99  aInnerContourResult.emplace_back( aCenter.x + rotatedDir.x * aInnerRadius,
100  aCenter.y + rotatedDir.y * aInnerRadius );
101 
102  aOuterContourResult.emplace_back( aCenter.x + rotatedDir.x * aOuterRadius,
103  aCenter.y + rotatedDir.y * aOuterRadius );
104  }
105 
106  aInnerContourResult.push_back( aInnerContourResult[0] );
107  aOuterContourResult.push_back( aOuterContourResult[0] );
108 
109  wxASSERT( aInnerContourResult.size() == aOuterContourResult.size() );
110 }
111 
112 
114  TRIANGLE_DISPLAY_LIST* aDstLayer,
115  float aZtop, float aZbot )
116 {
117  const SFVEC2F& center = aRing->GetCenter();
118  const float inner = aRing->GetInnerRadius();
119  const float outer = aRing->GetOuterRadius();
120 
121  std::vector< SFVEC2F > innerContour;
122  std::vector< SFVEC2F > outerContour;
123 
124  generateRing( center, inner, outer, m_boardAdapter.GetCircleSegmentCount( outer * 2.0f ),
125  innerContour, outerContour, false );
126 
127  // This will add the top and bot quads that will form the approximated ring
128  for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
129  {
130  const SFVEC2F& vi0 = innerContour[i + 0];
131  const SFVEC2F& vi1 = innerContour[i + 1];
132  const SFVEC2F& vo0 = outerContour[i + 0];
133  const SFVEC2F& vo1 = outerContour[i + 1];
134 
135  aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
136  SFVEC3F( vi0.x, vi0.y, aZtop ),
137  SFVEC3F( vo0.x, vo0.y, aZtop ),
138  SFVEC3F( vo1.x, vo1.y, aZtop ) );
139 
140  aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
141  SFVEC3F( vo1.x, vo1.y, aZbot ),
142  SFVEC3F( vo0.x, vo0.y, aZbot ),
143  SFVEC3F( vi0.x, vi0.y, aZbot ) );
144  }
145 }
146 
147 
149  TRIANGLE_DISPLAY_LIST* aDstLayer,
150  float aZtop, float aZbot )
151 {
152  const SFVEC2F& v1 = aTri->GetP1();
153  const SFVEC2F& v2 = aTri->GetP2();
154  const SFVEC2F& v3 = aTri->GetP3();
155 
156  addTopAndBottomTriangles( aDstLayer, v1, v2, v3, aZtop, aZbot );
157 }
158 
159 
161  TRIANGLE_DISPLAY_LIST* aDstLayer,
162  float aZtop, float aZbot )
163 {
164  const SFVEC2F& leftStart = aSeg->GetLeftStar();
165  const SFVEC2F& leftEnd = aSeg->GetLeftEnd();
166  const SFVEC2F& leftDir = aSeg->GetLeftDir();
167 
168  const SFVEC2F& rightStart = aSeg->GetRightStar();
169  const SFVEC2F& rightEnd = aSeg->GetRightEnd();
170  const SFVEC2F& rightDir = aSeg->GetRightDir();
171  const float radius = aSeg->GetRadius();
172 
173  const SFVEC2F& start = aSeg->GetStart();
174  const SFVEC2F& end = aSeg->GetEnd();
175 
176  const float texture_factor = ( 12.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
177  const float texture_factorF = ( 6.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
178 
179  const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
180  const float radius_triangle_factor = ( radius_of_the_square - radius ) / radius;
181 
182  const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
183  rightDir.x * radius * radius_triangle_factor );
184 
185  const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
186  leftDir.x * radius * radius_triangle_factor );
187 
188  // Top end segment triangles (semi-circles)
190  SFVEC3F( rightEnd.x + texture_factor * factorS.x,
191  rightEnd.y + texture_factor * factorS.y,
192  aZtop ),
193  SFVEC3F( leftStart.x + texture_factor * factorE.x,
194  leftStart.y + texture_factor * factorE.y,
195  aZtop ),
196  SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
197  start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
198  aZtop ) );
199 
201  SFVEC3F( leftEnd.x + texture_factor * factorE.x,
202  leftEnd.y + texture_factor * factorE.y, aZtop ),
203  SFVEC3F( rightStart.x + texture_factor * factorS.x,
204  rightStart.y + texture_factor * factorS.y, aZtop ),
205  SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
206  end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
207  aZtop ) );
208 
209  // Bot end segment triangles (semi-circles)
211  SFVEC3F( leftStart.x + texture_factor * factorE.x,
212  leftStart.y + texture_factor * factorE.y,
213  aZbot ),
214  SFVEC3F( rightEnd.x + texture_factor * factorS.x,
215  rightEnd.y + texture_factor * factorS.y,
216  aZbot ),
217  SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
218  start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
219  aZbot ) );
220 
222  SFVEC3F( rightStart.x + texture_factor * factorS.x,
223  rightStart.y + texture_factor * factorS.y, aZbot ),
224  SFVEC3F( leftEnd.x + texture_factor * factorE.x,
225  leftEnd.y + texture_factor * factorE.y, aZbot ),
226  SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
227  end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
228  aZbot ) );
229 
230  // Segment top and bot planes
231  aDstLayer->m_layer_top_triangles->AddQuad(
232  SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
233  SFVEC3F( rightStart.x, rightStart.y, aZtop ),
234  SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
235  SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
236 
237  aDstLayer->m_layer_bot_triangles->AddQuad(
238  SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
239  SFVEC3F( leftStart.x, leftStart.y, aZbot ),
240  SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
241  SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
242 }
243 
244 
246  const SHAPE_POLY_SET& aPoly, float aZtop,
247  float aZbot, bool aInvertFaces,
248  const BVH_CONTAINER_2D* aThroughHoles )
249 {
250  OPENGL_RENDER_LIST* ret = nullptr;
251 
252  if( aListHolesObject2d.size() > 0 )
253  {
254  TRIANGLE_DISPLAY_LIST* layerTriangles =
255  new TRIANGLE_DISPLAY_LIST( aListHolesObject2d.size() * 2 );
256 
257  // Convert the list of objects(filled circles) to triangle layer structure
258  for( LIST_OBJECT2D::const_iterator itemOnLayer = aListHolesObject2d.begin();
259  itemOnLayer != aListHolesObject2d.end();
260  ++itemOnLayer )
261  {
262  const OBJECT_2D* object2d_A = static_cast<const OBJECT_2D*>( *itemOnLayer );
263 
264  wxASSERT( ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::FILLED_CIRCLE )
265  || ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::ROUNDSEG ) );
266 
267  switch( object2d_A->GetObjectType() )
268  {
270  addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d_A ),
271  layerTriangles, aZtop, aZbot );
272  break;
273 
275  addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d_A ),
276  layerTriangles, aZtop, aZbot );
277  break;
278 
279  default:
280  wxFAIL_MSG( "RENDER_3D_LEGACY::generateHoles: Object type is not implemented" );
281  break;
282  }
283  }
284 
285  // Note: he can have a aListHolesObject2d whith holes but without countours
286  // eg: when there are only NPTH on the list and the contours were not added
287  if( aPoly.OutlineCount() > 0 )
288  {
289  layerTriangles->AddToMiddleContourns( aPoly, aZbot, aZtop,
291  aInvertFaces, aThroughHoles );
292  }
293 
294  ret = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, aZbot, aZtop );
295 
296  delete layerTriangles;
297  }
298 
299  return ret;
300 }
301 
302 
304  const SHAPE_POLY_SET* aPolyList,
305  PCB_LAYER_ID aLayerId,
306  const BVH_CONTAINER_2D* aThroughHoles )
307 {
308  if( aContainer == nullptr )
309  return nullptr;
310 
311  const LIST_OBJECT2D& listObject2d = aContainer->GetList();
312 
313  if( listObject2d.size() == 0 )
314  return nullptr;
315 
316  float layer_z_bot = 0.0f;
317  float layer_z_top = 0.0f;
318 
319  getLayerZPos( aLayerId, layer_z_top, layer_z_bot );
320 
321  // Calculate an estimation for the nr of triangles based on the nr of objects
322  unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
323 
324  TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( nrTrianglesEstimation );
325 
326  // store in a list so it will be latter deleted
327  m_triangles.push_back( layerTriangles );
328 
329  // Load the 2D (X,Y axis) component of shapes
330  for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
331  itemOnLayer != listObject2d.end();
332  ++itemOnLayer )
333  {
334  const OBJECT_2D* object2d_A = static_cast<const OBJECT_2D*>( *itemOnLayer );
335 
336  switch( object2d_A->GetObjectType() )
337  {
339  addObjectTriangles( (const FILLED_CIRCLE_2D *)object2d_A, layerTriangles,
340  layer_z_top, layer_z_bot );
341  break;
342 
344  addObjectTriangles( (const POLYGON_4PT_2D*)object2d_A, layerTriangles,
345  layer_z_top, layer_z_bot );
346  break;
347 
349  addObjectTriangles( (const RING_2D*)object2d_A, layerTriangles, layer_z_top,
350  layer_z_bot );
351  break;
352 
354  addObjectTriangles( (const TRIANGLE_2D*)object2d_A, layerTriangles, layer_z_top,
355  layer_z_bot );
356  break;
357 
359  addObjectTriangles( (const ROUND_SEGMENT_2D*) object2d_A, layerTriangles,
360  layer_z_top, layer_z_bot );
361  break;
362 
363  default:
364  wxFAIL_MSG( "RENDER_3D_LEGACY: Object type is not implemented" );
365  break;
366  }
367  }
368 
369  if( aPolyList &&aPolyList->OutlineCount() > 0 )
370  {
371  layerTriangles->AddToMiddleContourns( *aPolyList, layer_z_bot, layer_z_top,
372  m_boardAdapter.BiuTo3dUnits(), false, aThroughHoles );
373  }
374 
375  // Create display list
376  return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
377 }
378 
379 
381  const BVH_CONTAINER_2D* aThroughHoles )
382 {
383  OPENGL_RENDER_LIST* dispLists = nullptr;
384  CONTAINER_2D boardContainer;
385  SHAPE_POLY_SET brd_outlines = aBoardPoly;
386 
387  ConvertPolygonToTriangles( brd_outlines, boardContainer, m_boardAdapter.BiuTo3dUnits(),
388  (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
389 
390  const LIST_OBJECT2D& listBoardObject2d = boardContainer.GetList();
391 
392  if( listBoardObject2d.size() > 0 )
393  {
394  // We will set a unitary Z so it will in future used with transformations
395  // since the board poly will be used not only to draw itself but also the
396  // solder mask layers.
397  const float layer_z_top = 1.0f;
398  const float layer_z_bot = 0.0f;
399 
400  TRIANGLE_DISPLAY_LIST* layerTriangles =
401  new TRIANGLE_DISPLAY_LIST( listBoardObject2d.size() );
402 
403  // Convert the list of objects(triangles) to triangle layer structure
404  for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
405  itemOnLayer != listBoardObject2d.end();
406  ++itemOnLayer )
407  {
408  const OBJECT_2D* object2d_A = static_cast<const OBJECT_2D*>( *itemOnLayer );
409 
410  wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
411 
412  const TRIANGLE_2D* tri = (const TRIANGLE_2D *)object2d_A;
413 
414  const SFVEC2F& v1 = tri->GetP1();
415  const SFVEC2F& v2 = tri->GetP2();
416  const SFVEC2F& v3 = tri->GetP3();
417 
418  addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
419  }
420 
421  if( aBoardPoly.OutlineCount() > 0 )
422  {
423  layerTriangles->AddToMiddleContourns( aBoardPoly, layer_z_bot, layer_z_top,
424  m_boardAdapter.BiuTo3dUnits(), false,
425  aThroughHoles );
426 
427  dispLists = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
428  layer_z_top, layer_z_top );
429  }
430 
431  delete layerTriangles;
432  }
433 
434  return dispLists;
435 }
436 
437 
438 void RENDER_3D_LEGACY::reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
439 {
440  m_reloadRequested = false;
441 
442  freeAllLists();
443 
445 
446  unsigned stats_startReloadTime = GetRunningMicroSecs();
447 
448  m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
449 
450  SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
451  m_camera.SetBoardLookAtPos( camera_pos );
452 
453  if( aStatusReporter )
454  aStatusReporter->Report( _( "Load OpenGL: board" ) );
455 
456  // Create Board
458 
460  {
463  m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, -INT_MAX/2 ) );
464  m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, -INT_MAX/2 ) );
465  m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, INT_MAX/2 ) );
466  m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, INT_MAX/2 ) );
467  m_antiBoardPolys.Outline( 0 ).SetClosed( true );
468 
472  }
473 
474  SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly();
475  board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
479 
480  m_boardWithHoles = createBoard( board_poly_with_holes );
481 
482  if( m_antiBoard )
484 
485  // Create Through Holes and vias
486  if( aStatusReporter )
487  aStatusReporter->Report( _( "Load OpenGL: holes and vias" ) );
488 
490 
494 
496  outerPolyTHT, 1.0f, 0.0f, false,
498 
501  m_boardAdapter.GetThroughHoleViaOdPolys(), 1.0f, 0.0f, false );
502 
505  {
508  m_boardAdapter.GetThroughHoleAnnularRingPolys(), 1.0f, 0.0f, false );
509  }
510 
511  const MAP_POLY& innerMapHoles = m_boardAdapter.GetHoleIdPolysMap();
512  const MAP_POLY& outerMapHoles = m_boardAdapter.GetHoleOdPolysMap();
513 
514  wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
515 
517 
518  if( outerMapHoles.size() > 0 )
519  {
520  float layer_z_bot = 0.0f;
521  float layer_z_top = 0.0f;
522 
523  for( MAP_POLY::const_iterator ii = outerMapHoles.begin(); ii != outerMapHoles.end(); ++ii )
524  {
525  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
526  const SHAPE_POLY_SET* poly = static_cast<const SHAPE_POLY_SET*>( ii->second );
527  const BVH_CONTAINER_2D* container = map_holes.at( layer_id );
528 
529  getLayerZPos( layer_id, layer_z_top, layer_z_bot );
530 
531  m_outerLayerHoles[layer_id] = generateHoles( container->GetList(), *poly,
532  layer_z_top, layer_z_bot, false );
533  }
534 
535  for( MAP_POLY::const_iterator ii = innerMapHoles.begin(); ii != innerMapHoles.end(); ++ii )
536  {
537  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>( ii->first );
538  const SHAPE_POLY_SET* poly = static_cast<const SHAPE_POLY_SET*>( ii->second );
539  const BVH_CONTAINER_2D* container = map_holes.at( layer_id );
540 
541  getLayerZPos( layer_id, layer_z_top, layer_z_bot );
542 
543  m_innerLayerHoles[layer_id] = generateHoles( container->GetList(), *poly,
544  layer_z_top, layer_z_bot, false );
545  }
546  }
547 
548  // Generate vertical cylinders of vias and pads (copper)
550 
551  // Add layers maps
552  if( aStatusReporter )
553  aStatusReporter->Report( _( "Load OpenGL: layers" ) );
554 
555  const MAP_POLY& map_poly = m_boardAdapter.GetPolyMap();
556 
557  for( MAP_CONTAINER_2D_BASE::const_iterator ii = m_boardAdapter.GetLayerMap().begin();
558  ii != m_boardAdapter.GetLayerMap().end();
559  ++ii )
560  {
561  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>( ii->first );
562 
563  if( !m_boardAdapter.Is3dLayerEnabled( layer_id ) )
564  continue;
565 
566  const BVH_CONTAINER_2D* container2d = static_cast<const BVH_CONTAINER_2D*>( ii->second );
567 
568  SHAPE_POLY_SET polyListSubtracted;
569  SHAPE_POLY_SET* aPolyList = nullptr;
570 
571  // Load the vertical (Z axis) component of shapes
572 
573  if( map_poly.find( layer_id ) != map_poly.end() )
574  {
575  polyListSubtracted = *map_poly.at( layer_id );;
576 
577  if( ( layer_id != B_Paste ) && ( layer_id != F_Paste ) &&
579  {
580  polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
582 
583  if( ( layer_id != B_Mask ) && ( layer_id != F_Mask ) )
584  {
587  polyListSubtracted.BooleanSubtract(
590  }
591 
593  {
594  if( layer_id == B_SilkS && map_poly.find( B_Mask ) != map_poly.end() )
595  {
596  polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ),
598  }
599  else if( layer_id == F_SilkS && map_poly.find( F_Mask ) != map_poly.end() )
600  {
601  polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ),
603  }
604 
605  }
606  }
607 
608  aPolyList = &polyListSubtracted;
609  }
610 
611  OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, aPolyList, layer_id,
613 
614  if( oglList != nullptr )
615  m_layers[layer_id] = oglList;
616 
617  }
618 
621  {
623  {
631 
633  &polySubtracted, F_Cu );
634  }
635 
637  {
645 
647  &polySubtracted, B_Cu );
648  }
649  }
650 
651  // Load 3D models
652  if( aStatusReporter )
653  aStatusReporter->Report( _( "Loading 3D models" ) );
654 
655  load3dModels( aStatusReporter );
656 
657  if( aStatusReporter )
658  {
659  // Calculation time in seconds
660  const double calculation_time = (double)( GetRunningMicroSecs() -
661  stats_startReloadTime) / 1e6;
662 
663  aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
664  }
665 }
666 
667 
669  const SFVEC2F& v1, const SFVEC2F& v2,
670  float top, float bot )
671 {
672  aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
673  SFVEC3F( v1.x, v1.y, bot ),
674  SFVEC3F( v2.x, v2.y, bot ) );
675 
676  aDst->m_layer_top_triangles->AddTriangle( SFVEC3F( v2.x, v2.y, top ),
677  SFVEC3F( v1.x, v1.y, top ),
678  SFVEC3F( v0.x, v0.y, top ) );
679 }
680 
681 
682 void RENDER_3D_LEGACY::getLayerZPos( PCB_LAYER_ID aLayerID, float& aOutZtop,
683  float& aOutZbot ) const
684 {
685  aOutZbot = m_boardAdapter.GetLayerBottomZPos( aLayerID );
686  aOutZtop = m_boardAdapter.GetLayerTopZPos( aLayerID );
687 
688  if( aOutZtop < aOutZbot )
689  {
690  float tmpFloat = aOutZbot;
691  aOutZbot = aOutZtop;
692  aOutZtop = tmpFloat;
693  }
694 }
695 
696 
697 void RENDER_3D_LEGACY::generateCylinder( const SFVEC2F& aCenter, float aInnerRadius,
698  float aOuterRadius, float aZtop, float aZbot,
699  unsigned int aNr_sides_per_circle,
700  TRIANGLE_DISPLAY_LIST* aDstLayer )
701 {
702  std::vector< SFVEC2F > innerContour;
703  std::vector< SFVEC2F > outerContour;
704 
705  generateRing( aCenter, aInnerRadius, aOuterRadius, aNr_sides_per_circle, innerContour,
706  outerContour, false );
707 
708  for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
709  {
710  const SFVEC2F& vi0 = innerContour[i + 0];
711  const SFVEC2F& vi1 = innerContour[i + 1];
712  const SFVEC2F& vo0 = outerContour[i + 0];
713  const SFVEC2F& vo1 = outerContour[i + 1];
714 
715  aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
716  SFVEC3F( vi0.x, vi0.y, aZtop ),
717  SFVEC3F( vo0.x, vo0.y, aZtop ),
718  SFVEC3F( vo1.x, vo1.y, aZtop ) );
719 
720  aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
721  SFVEC3F( vo1.x, vo1.y, aZbot ),
722  SFVEC3F( vo0.x, vo0.y, aZbot ),
723  SFVEC3F( vi0.x, vi0.y, aZbot ) );
724  }
725 
726  aDstLayer->AddToMiddleContourns( outerContour, aZbot, aZtop, true );
727  aDstLayer->AddToMiddleContourns( innerContour, aZbot, aZtop, false );
728 }
729 
730 
732 {
734  {
735  const unsigned int reserve_nr_triangles_estimation =
739 
740  TRIANGLE_DISPLAY_LIST* layerTriangleVIA =
741  new TRIANGLE_DISPLAY_LIST( reserve_nr_triangles_estimation );
742 
743  // Insert plated vertical holes inside the board
744 
745  // Insert vias holes (vertical cylinders)
746  for( auto track : m_boardAdapter.GetBoard()->Tracks() )
747  {
748  if( track->Type() == PCB_VIA_T )
749  {
750  const VIA* via = static_cast<const VIA*>(track);
751 
752  const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
753  const float thickness = m_boardAdapter.GetCopperThickness();
754  const int nrSegments = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
755  const float hole_inner_radius = holediameter / 2.0f;
756 
757  const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
758  -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
759 
760  PCB_LAYER_ID top_layer, bottom_layer;
761  via->LayerPair( &top_layer, &bottom_layer );
762 
763  float ztop, zbot, dummy;
764 
765  getLayerZPos( top_layer, ztop, dummy );
766  getLayerZPos( bottom_layer, dummy, zbot );
767 
768  wxASSERT( zbot < ztop );
769 
770  generateCylinder( via_center, hole_inner_radius, hole_inner_radius + thickness,
771  ztop, zbot, nrSegments, layerTriangleVIA );
772  }
773  }
774 
775  m_vias = new OPENGL_RENDER_LIST( *layerTriangleVIA, 0, 0.0f, 0.0f );
776 
777  delete layerTriangleVIA;
778  }
779 
780 
781  if( m_boardAdapter.GetHoleCount() > 0 )
782  {
783  SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes (the pad)
784  SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes (the hole)
785 
786  tht_outer_holes_poly.RemoveAllContours();
787  tht_inner_holes_poly.RemoveAllContours();
788 
789  // Insert pads holes (vertical cylinders)
790  for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
791  {
792  for( PAD* pad : footprint->Pads() )
793  {
794  if( pad->GetAttribute() != PAD_ATTRIB_NPTH )
795  {
796  const wxSize drillsize = pad->GetDrillSize();
797  const bool hasHole = drillsize.x && drillsize.y;
798 
799  if( !hasHole )
800  continue;
801 
802  const int copperThickness = m_boardAdapter.GetHolePlatingThickness();
803 
804  pad->TransformHoleWithClearanceToPolygon( tht_outer_holes_poly,
805  copperThickness,
806  ARC_LOW_DEF, ERROR_INSIDE );
807  pad->TransformHoleWithClearanceToPolygon( tht_inner_holes_poly, 0,
808  ARC_LOW_DEF, ERROR_INSIDE );
809  }
810  }
811  }
812 
813  // Subtract the holes
814  tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );
815 
818 
819  CONTAINER_2D holesContainer;
820 
821  ConvertPolygonToTriangles( tht_outer_holes_poly, holesContainer,
823  (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
824 
825  const LIST_OBJECT2D& listHolesObject2d = holesContainer.GetList();
826 
827  if( listHolesObject2d.size() > 0 )
828  {
829  float layer_z_top, layer_z_bot, dummy;
830 
831  getLayerZPos( F_Cu, layer_z_top, dummy );
832  getLayerZPos( B_Cu, dummy, layer_z_bot );
833 
834  TRIANGLE_DISPLAY_LIST* layerTriangles =
835  new TRIANGLE_DISPLAY_LIST( listHolesObject2d.size() );
836 
837  // Convert the list of objects(triangles) to triangle layer structure
838  for( LIST_OBJECT2D::const_iterator itemOnLayer = listHolesObject2d.begin();
839  itemOnLayer != listHolesObject2d.end();
840  ++itemOnLayer )
841  {
842  const OBJECT_2D* object2d_A = static_cast<const OBJECT_2D*>( *itemOnLayer );
843 
844  wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
845 
846  const TRIANGLE_2D* tri = (const TRIANGLE_2D *)object2d_A;
847 
848  const SFVEC2F& v1 = tri->GetP1();
849  const SFVEC2F& v2 = tri->GetP2();
850  const SFVEC2F& v3 = tri->GetP3();
851 
852  addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
853  }
854 
855  wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
856 
857  if( tht_outer_holes_poly.OutlineCount() > 0 )
858  {
859  layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
860  layer_z_bot, layer_z_top,
861  m_boardAdapter.BiuTo3dUnits(), false );
862 
863  m_padHoles = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
864  layer_z_top, layer_z_top );
865  }
866 
867  delete layerTriangles;
868  }
869  }
870 }
871 
872 
873 void RENDER_3D_LEGACY::load3dModels( REPORTER* aStatusReporter )
874 {
878  {
879  return;
880  }
881 
882  // Go for all footprints
883  for( FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
884  {
885  for( const FP_3DMODEL& model : footprint->Models() )
886  {
887  if( model.m_Show && !model.m_Filename.empty() )
888  {
889  if( aStatusReporter )
890  {
891  // Display the short filename of the 3D model loaded:
892  // (the full name is usually too long to be displayed)
893  wxFileName fn( model.m_Filename );
894  wxString msg;
895  msg.Printf( _( "Loading %s" ), fn.GetFullName() );
896  aStatusReporter->Report( msg );
897  }
898 
899  // Check if the model is not present in our cache map
900  // (Not already loaded in memory)
901  if( m_3dModelMap.find( model.m_Filename ) == m_3dModelMap.end() )
902  {
903  // It is not present, try get it from cache
904  const S3DMODEL* modelPtr =
905  m_boardAdapter.Get3dCacheManager()->GetModel( model.m_Filename );
906 
907  // only add it if the return is not NULL
908  if( modelPtr )
909  {
911  MODEL_3D* ogl_model = new MODEL_3D( *modelPtr, materialMode );
912 
913  if( ogl_model )
914  m_3dModelMap[ model.m_Filename ] = ogl_model;
915  }
916  }
917  }
918  }
919  }
920 }
float GetRadius() const
bool GetFlag(DISPLAY3D_FLG aFlag) const
Get a configuration status of a flag.
void SetBoardLookAtPos(const SFVEC3F &aBoardPos)
Definition: camera.h:114
BOARD_ADAPTER & m_boardAdapter
const SFVEC2F & GetV1() const
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
Definition: track.cpp:435
Definition: track.h:343
void ConvertPolygonToTriangles(SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
OPENGL_RENDER_LIST * createBoard(const SHAPE_POLY_SET &aBoardPoly, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
const SFVEC2F & GetCenter() const
const SFVEC2F & GetP1() const
Definition: triangle_2d.h:44
Store arrays of triangles to be used to create display lists.
float GetRadiusSquared() const
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
float GetInnerRadius() const
Definition: ring_2d.h:47
std::map< PCB_LAYER_ID, SHAPE_POLY_SET * > MAP_POLY
A type that stores polysets for each layer id.
Definition: board_adapter.h:56
float GetRadius() const
const SFVEC2F & GetP2() const
Definition: triangle_2d.h:45
const SHAPE_POLY_SET & GetOuterNonPlatedThroughHolePoly() const noexcept
const wxPoint & GetStart() const
Definition: track.h:116
MAP_OGL_DISP_LISTS m_layers
const BVH_CONTAINER_2D & GetThroughHoleAnnularRings() const noexcept
Get the through hole annular rings container.
const SHAPE_POLY_SET & GetThroughHoleOdPolys() const noexcept
Get through hole outside diameter 2D polygons.
const MAP_CONTAINER_2D_BASE & GetLayerMap() const noexcept
Get the map of containers that have the objects per layer.
TRIANGLE_LIST * m_layer_top_triangles
void InitSettings(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
Function to be called by the render when it need to reload the settings for the board.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
OPENGL_RENDER_LIST * m_platedPadsFront
const SHAPE_POLY_SET & GetThroughHoleViaOdPolys() const noexcept
const SHAPE_POLY_SET * GetFrontPlatedPadPolys()
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
float GetOuterRadius() const
Definition: ring_2d.h:48
MAP_3DMODEL m_3dModelMap
void addTopAndBottomTriangles(TRIANGLE_DISPLAY_LIST *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
void getLayerZPos(PCB_LAYER_ID aLayerID, float &aOutZtop, float &aOutZbot) const
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
void generateRing(const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, unsigned int aNr_sides_per_circle, std::vector< SFVEC2F > &aInnerContourResult, std::vector< SFVEC2F > &aOuterContourResult, bool aInvertOrder)
void generateCylinder(const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, float aZtop, float aZbot, unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST *aDstLayer)
const SHAPE_POLY_SET * GetBackPlatedPadPolys()
OPENGL_RENDER_LIST * m_outerThroughHoles
const SHAPE_POLY_SET & GetThroughHoleAnnularRingPolys() const noexcept
const LIST_OBJECT2D & GetList() const
Definition: container_2d.h:66
S3DMODEL * GetModel(const wxString &aModelFileName)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition: 3d_cache.cpp:651
const BVH_CONTAINER_2D & GetThroughHoleIds() const noexcept
Get the through hole inner diameter container.
OPENGL_RENDER_LIST * m_outerThroughHoleRings
OPENGL_RENDER_LIST * m_boardWithHoles
bool Is3dLayerEnabled(PCB_LAYER_ID aLayer) const
Check if a layer is enabled.
void SetClosed(bool aClosed)
Function SetClosed()
PCB_LAYER_ID
A quick note on layer IDs:
const BVH_CONTAINER_2D * GetPlatedPadsBack() const noexcept
#define SIZE_OF_CIRCLE_TEXTURE
const SFVEC2F & GetV2() const
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: track.cpp:173
S3D_CACHE * Get3dCacheManager() const noexcept
Return the 3D cache manager pointer.
Definition: board_adapter.h:87
const SFVEC2F & GetLeftEnd() const
MAP_OGL_DISP_LISTS m_outerLayerHoles
OPENGL_RENDER_LIST * m_antiBoard
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
float GetLayerTopZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the top z position.
const SFVEC2F & GetEnd() const
const SFVEC2F & GetLeftStar() const
FOOTPRINTS & Footprints()
Definition: board.h:296
float GetLayerBottomZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the bottom z position.
MATERIAL_MODE GetMaterialMode() const noexcept
static OBJECT_2D_STATS & Instance()
Definition: object_2d.h:139
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
void AddQuad(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3, const SFVEC3F &aV4)
void AddTriangle(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3)
OPENGL_RENDER_LIST * m_board
const BOARD * GetBoard() const noexcept
Get current board to be rendered.
const MAP_POLY & GetHoleIdPolysMap() const noexcept
void addObjectTriangles(const RING_2D *aRing, TRIANGLE_DISPLAY_LIST *aDstLayer, float aZtop, float aZbot)
const SFVEC2F & GetRightDir() const
const BVH_CONTAINER_2D & GetThroughHoleOds() const noexcept
Get the inflated through hole outside diameters container.
const MAP_POLY & GetHoleOdPolysMap() const noexcept
void AddToMiddleContourns(const SHAPE_LINE_CHAIN &outlinePath, float zBot, float zTop, double aBiuTo3Du, bool aInvertFaceDirection, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
TRIANGLE_LIST * m_layer_bot_triangles
OBJECT_2D_TYPE GetObjectType() const
Definition: object_2d.h:107
OPENGL_RENDER_LIST * generateHoles(const LIST_OBJECT2D &aListHolesObject2d, const SHAPE_POLY_SET &aPoly, float aZtop, float aZbot, bool aInvertFaces, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
const SHAPE_POLY_SET & GetBoardPoly() const noexcept
Get the current polygon of the epoxy board.
MATERIAL_MODE
Render 3d model shape materials mode.
Definition: 3d_enums.h:117
std::map< PCB_LAYER_ID, BVH_CONTAINER_2D * > MAP_CONTAINER_2D_BASE
A type that stores a container of 2d objects for each layer id.
Definition: board_adapter.h:50
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
int NewOutline()
Creates a new hole in a given outline.
OPENGL_RENDER_LIST * generateLayerList(const BVH_CONTAINER_2D *aContainer, const SHAPE_POLY_SET *aPolyList, PCB_LAYER_ID aLayerId, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
void load3dModels(REPORTER *aStatusReporter)
Load footprint models from the cache and load it to openGL lists in the form of MODEL_3D objects.
const MAP_POLY & GetPolyMap() const noexcept
Get map of polygon's layers.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Store the OpenGL display lists to related with a layer.
bool m_reloadRequested
The window size that this camera is working.
Simple non-intersecting polygon with 4 points.
unsigned int GetViaCount() const noexcept
Get number of vias in this board.
unsigned int GetHoleCount() const noexcept
Get number of holes in this board.
const BVH_CONTAINER_2D * GetPlatedPadsFront() const noexcept
const SFVEC2F & GetLeftDir() const
#define _(s)
Definition: 3d_actions.cpp:33
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapset time (in microsecondes) to class PROF_COUNTER.
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
const BVH_CONTAINER_2D & GetThroughHoleViaOds() const noexcept
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
SHAPE_POLY_SET m_antiBoardPolys
The negative polygon representation of the board outline.
const SFVEC3F & GetBoardCenter() const noexcept
The board center position in 3D units.
const SFVEC2F & GetRightEnd() const
float GetAverageViaHoleDiameter() const noexcept
Thee average diameter of the via holes.
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
void SetItIsTransparent(bool aSetTransparent)
std::list< OBJECT_2D * > LIST_OBJECT2D
Definition: container_2d.h:36
float GetCopperThickness() const noexcept
Get the current copper layer thickness.
const SFVEC2F & GetV3() const
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
Store the a model based on meshes and materials.
Definition: c3dmodel.h:90
OPENGL_RENDER_LIST * m_platedPadsBack
MAP_OGL_DISP_LISTS m_innerLayerHoles
TRIANGLE_LIST * m_layer_bot_segment_ends
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void ResetStats()
Definition: object_2d.h:122
Definition: pad.h:60
OPENGL_RENDER_LIST * m_vias
const SFVEC2F & GetP3() const
Definition: triangle_2d.h:46
const MAP_CONTAINER_2D_BASE & GetLayerHoleMap() const noexcept
Get the map of container that have the holes per layer.
const SFVEC2F & GetCenter() const
Definition: ring_2d.h:46
const SFVEC2F & GetStart() const
unsigned int GetCircleSegmentCount(float aDiameter3DU) const
OPENGL_RENDER_LIST * m_padHoles
const SFVEC2F & GetV0() const
TRACKS & Tracks()
Definition: board.h:293
TRIANGLE_LIST * m_layer_top_segment_ends
OPENGL_RENDER_LIST * m_outerViaThroughHoles
int GetHolePlatingThickness() const noexcept
Get the current copper layer thickness.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
const SFVEC2F & GetRightStar() const