KiCad PCB EDA Suite
c3d_render_createscene_ogl_legacy.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) 1992-2016 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 
30 #include "c3d_render_ogl_legacy.h"
31 #include "ogl_legacy_utils.h"
32 #include <class_board.h>
33 #include <class_module.h>
34 #include "../../3d_math.h"
35 #include "../../3d_fastmath.h"
36 #include <trigo.h>
37 #include <project.h>
38 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
39 
40 
42  CLAYER_TRIANGLES *aDstLayer,
43  float aZtop,
44  float aZbot )
45 {
46  const SFVEC2F &center = aFilledCircle->GetCenter();
47  const float radius = aFilledCircle->GetRadius() *
48  2.0f; // Double because the render triangle
49 
50  // This is a small adjustment to the circle texture
51  const float texture_factor = (8.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
52  const float f = (sqrtf(2.0f) / 2.0f) * radius * texture_factor;
53 
54  // Top and Bot segments ends are just triangle semi-circles, so need to add
55  // it in duplicated
56  aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZtop ),
57  SFVEC3F( center.x - f, center.y, aZtop ),
58  SFVEC3F( center.x,
59  center.y - f, aZtop ) );
60 
61  aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZtop ),
62  SFVEC3F( center.x + f, center.y, aZtop ),
63  SFVEC3F( center.x,
64  center.y + f, aZtop ) );
65 
66  aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZbot ),
67  SFVEC3F( center.x + f, center.y, aZbot ),
68  SFVEC3F( center.x,
69  center.y - f, aZbot ) );
70 
71  aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZbot ),
72  SFVEC3F( center.x - f, center.y, aZbot ),
73  SFVEC3F( center.x,
74  center.y + f, aZbot ) );
75 }
76 
77 
79  CLAYER_TRIANGLES *aDstLayer,
80  float aZtop,
81  float aZbot )
82 {
83  const SFVEC2F &v0 = aPoly->GetV0();
84  const SFVEC2F &v1 = aPoly->GetV1();
85  const SFVEC2F &v2 = aPoly->GetV2();
86  const SFVEC2F &v3 = aPoly->GetV3();
87 
88  add_triangle_top_bot( aDstLayer, v0, v2, v1, aZtop, aZbot );
89  add_triangle_top_bot( aDstLayer, v2, v0, v3, aZtop, aZbot );
90 }
91 
92 
94  float aInnerRadius,
95  float aOuterRadius,
96  unsigned int aNr_sides_per_circle,
97  std::vector< SFVEC2F > &aInnerContourResult,
98  std::vector< SFVEC2F > &aOuterContourResult,
99  bool aInvertOrder )
100 {
101  aInnerContourResult.clear();
102  aInnerContourResult.reserve( aNr_sides_per_circle + 2 );
103 
104  aOuterContourResult.clear();
105  aOuterContourResult.reserve( aNr_sides_per_circle + 2 );
106 
107  const int delta = 3600 / aNr_sides_per_circle;
108 
109  for( int ii = 0; ii < 3600; ii += delta )
110  {
111  float angle = (float)( aInvertOrder ? ( 3600 - ii ) : ii )
112  * 2.0f * glm::pi<float>() / 3600.0f;
113  const SFVEC2F rotatedDir = SFVEC2F( cos( angle ), sin( angle ) );
114 
115  aInnerContourResult.push_back( SFVEC2F( aCenter.x + rotatedDir.x * aInnerRadius,
116  aCenter.y + rotatedDir.y * aInnerRadius ) );
117 
118  aOuterContourResult.push_back( SFVEC2F( aCenter.x + rotatedDir.x * aOuterRadius,
119  aCenter.y + rotatedDir.y * aOuterRadius ) );
120  }
121 
122  aInnerContourResult.push_back( aInnerContourResult[0] );
123  aOuterContourResult.push_back( aOuterContourResult[0] );
124 
125  wxASSERT( aInnerContourResult.size() == aOuterContourResult.size() );
126 }
127 
128 
130  CLAYER_TRIANGLES *aDstLayer,
131  float aZtop,
132  float aZbot )
133 {
134  const SFVEC2F &center = aRing->GetCenter();
135  const float inner = aRing->GetInnerRadius();
136  const float outer = aRing->GetOuterRadius();
137 
138  std::vector< SFVEC2F > innerContour;
139  std::vector< SFVEC2F > outerContour;
140 
141  generate_ring_contour( center,
142  inner,
143  outer,
144  m_settings.GetNrSegmentsCircle( outer * 2.0f ),
145  innerContour,
146  outerContour,
147  false );
148 
149  // This will add the top and bot quads that will form the approximated ring
150 
151  for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
152  {
153  const SFVEC2F &vi0 = innerContour[i + 0];
154  const SFVEC2F &vi1 = innerContour[i + 1];
155  const SFVEC2F &vo0 = outerContour[i + 0];
156  const SFVEC2F &vo1 = outerContour[i + 1];
157 
158  aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
159  SFVEC3F( vi0.x, vi0.y, aZtop ),
160  SFVEC3F( vo0.x, vo0.y, aZtop ),
161  SFVEC3F( vo1.x, vo1.y, aZtop ) );
162 
163  aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
164  SFVEC3F( vo1.x, vo1.y, aZbot ),
165  SFVEC3F( vo0.x, vo0.y, aZbot ),
166  SFVEC3F( vi0.x, vi0.y, aZbot ) );
167  }
168 }
169 
170 
172  CLAYER_TRIANGLES *aDstLayer,
173  float aZtop,
174  float aZbot )
175 {
176  const SFVEC2F &v1 = aTri->GetP1();
177  const SFVEC2F &v2 = aTri->GetP2();
178  const SFVEC2F &v3 = aTri->GetP3();
179 
180  add_triangle_top_bot( aDstLayer, v1, v2, v3, aZtop, aZbot );
181 }
182 
183 
185  CLAYER_TRIANGLES *aDstLayer,
186  float aZtop,
187  float aZbot )
188 {
189  const SFVEC2F leftStart = aSeg->GetLeftStar();
190  const SFVEC2F leftEnd = aSeg->GetLeftEnd();
191  const SFVEC2F leftDir = aSeg->GetLeftDir();
192 
193  const SFVEC2F rightStart = aSeg->GetRightStar();
194  const SFVEC2F rightEnd = aSeg->GetRightEnd();
195  const SFVEC2F rightDir = aSeg->GetRightDir();
196  const float radius = aSeg->GetRadius();
197 
198  const SFVEC2F start = aSeg->GetStart();
199  const SFVEC2F end = aSeg->GetEnd();
200 
201  const float texture_factor = (12.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
202  const float texture_factorF= ( 6.0f / (float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
203 
204  const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
205  const float radius_triangle_factor = (radius_of_the_square - radius) / radius;
206 
207  const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
208  rightDir.x * radius * radius_triangle_factor );
209 
210  const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
211  leftDir.x * radius * radius_triangle_factor );
212 
213  // Top end segment triangles (semi-circles)
215  SFVEC3F( rightEnd.x + texture_factor * factorS.x,
216  rightEnd.y + texture_factor * factorS.y,
217  aZtop ),
218  SFVEC3F( leftStart.x + texture_factor * factorE.x,
219  leftStart.y + texture_factor * factorE.y,
220  aZtop ),
221  SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
222  start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
223  aZtop ) );
224 
226  SFVEC3F( leftEnd.x + texture_factor * factorE.x,
227  leftEnd.y + texture_factor * factorE.y, aZtop ),
228  SFVEC3F( rightStart.x + texture_factor * factorS.x,
229  rightStart.y + texture_factor * factorS.y, aZtop ),
230  SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
231  end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
232  aZtop ) );
233 
234  // Bot end segment triangles (semi-circles)
236  SFVEC3F( leftStart.x + texture_factor * factorE.x,
237  leftStart.y + texture_factor * factorE.y,
238  aZbot ),
239  SFVEC3F( rightEnd.x + texture_factor * factorS.x,
240  rightEnd.y + texture_factor * factorS.y,
241  aZbot ),
242  SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
243  start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
244  aZbot ) );
245 
247  SFVEC3F( rightStart.x + texture_factor * factorS.x,
248  rightStart.y + texture_factor * factorS.y, aZbot ),
249  SFVEC3F( leftEnd.x + texture_factor * factorE.x,
250  leftEnd.y + texture_factor * factorE.y, aZbot ),
251  SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
252  end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
253  aZbot ) );
254 
255  // Segment top and bot planes
256  aDstLayer->m_layer_top_triangles->AddQuad(
257  SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
258  SFVEC3F( rightStart.x, rightStart.y, aZtop ),
259  SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
260  SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
261 
262  aDstLayer->m_layer_bot_triangles->AddQuad(
263  SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
264  SFVEC3F( leftStart.x, leftStart.y, aZbot ),
265  SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
266  SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
267 }
268 
269 
271  const LIST_OBJECT2D &aListHolesObject2d,
272  const SHAPE_POLY_SET &aPoly,
273  float aZtop,
274  float aZbot,
275  bool aInvertFaces )
276 {
277  CLAYERS_OGL_DISP_LISTS *ret = NULL;
278 
279  if( aListHolesObject2d.size() > 0 )
280  {
281  CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( aListHolesObject2d.size() * 2 );
282 
283  // Convert the list of objects(filled circles) to triangle layer structure
284  for( LIST_OBJECT2D::const_iterator itemOnLayer = aListHolesObject2d.begin();
285  itemOnLayer != aListHolesObject2d.end();
286  ++itemOnLayer )
287  {
288  const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
289 
290  wxASSERT( (object2d_A->GetObjectType() == OBJ2D_FILLED_CIRCLE) ||
291  (object2d_A->GetObjectType() == OBJ2D_ROUNDSEG) );
292 
293  switch( object2d_A->GetObjectType() )
294  {
295  case OBJ2D_FILLED_CIRCLE:
296  add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
297  layerTriangles,
298  aZtop, aZbot );
299  break;
300 
301  case OBJ2D_ROUNDSEG:
302  add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
303  layerTriangles,
304  aZtop, aZbot );
305  break;
306 
307  default:
308  wxFAIL_MSG("C3D_RENDER_OGL_LEGACY::generate_holes_display_list: Object type is not implemented");
309  break;
310  }
311  }
312 
313  // Note: he can have a aListHolesObject2d whith holes but without countours
314  // eg: when there are only NPTH on the list and the contours were not
315  // added
316 
317  if( aPoly.OutlineCount() > 0 )
318  {
319  layerTriangles->AddToMiddleContourns( aPoly,
320  aZbot,
321  aZtop,
323  aInvertFaces );
324  }
325 
326  ret = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
328  aZbot,
329  aZtop );
330 
331  delete layerTriangles;
332  }
333 
334  return ret;
335 }
336 
337 
338 void C3D_RENDER_OGL_LEGACY::reload( REPORTER *aStatusTextReporter )
339 {
340  m_reloadRequested = false;
341 
343 
345 
346 #ifdef PRINT_STATISTICS_3D_VIEWER
347  printf("InitSettings...\n");
348 #endif
349 
350  unsigned stats_startReloadTime = GetRunningMicroSecs();
351 
352  m_settings.InitSettings( aStatusTextReporter );
353 
354 #ifdef PRINT_STATISTICS_3D_VIEWER
355  unsigned stats_endReloadTime = GetRunningMicroSecs();
356 #endif
357 
358  SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
359  m_settings.CameraGet().SetBoardLookAtPos( camera_pos );
360 
361 #ifdef PRINT_STATISTICS_3D_VIEWER
362  unsigned stats_start_OpenGL_Load_Time = GetRunningMicroSecs();
363 #endif
364 
365  if( aStatusTextReporter )
366  aStatusTextReporter->Report( _( "Load OpenGL: board" ) );
367 
368  // Create Board
369  // /////////////////////////////////////////////////////////////////////////
370 
371  CCONTAINER2D boardContainer;
373  boardContainer,
375  (const BOARD_ITEM &)*m_settings.GetBoard() );
376 
377  const LIST_OBJECT2D &listBoardObject2d = boardContainer.GetList();
378 
379  if( listBoardObject2d.size() > 0 )
380  {
381  // We will set a unitary Z so it will in future used with transformations
382  // since the board poly will be used not only to draw itself but also the
383  // solder mask layers.
384  const float layer_z_top = 1.0f;
385  const float layer_z_bot = 0.0f;
386 
387  CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );
388 
389  // Convert the list of objects(triangles) to triangle layer structure
390  for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
391  itemOnLayer != listBoardObject2d.end();
392  ++itemOnLayer )
393  {
394  const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
395 
396  wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );
397 
398  const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
399 
400  const SFVEC2F &v1 = tri->GetP1();
401  const SFVEC2F &v2 = tri->GetP2();
402  const SFVEC2F &v3 = tri->GetP3();
403 
404  add_triangle_top_bot( layerTriangles,
405  v1,
406  v2,
407  v3,
408  layer_z_top,
409  layer_z_bot );
410  }
411 
412  const SHAPE_POLY_SET &boardPoly = m_settings.GetBoardPoly();
413 
414  wxASSERT( boardPoly.OutlineCount() > 0 );
415 
416  if( boardPoly.OutlineCount() > 0 )
417  {
418  layerTriangles->AddToMiddleContourns( boardPoly,
419  layer_z_bot,
420  layer_z_top,
422  false );
423 
424  m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
426  layer_z_top,
427  layer_z_top );
428  }
429 
430  delete layerTriangles;
431  }
432 
433  // Create Through Holes and vias
434  // /////////////////////////////////////////////////////////////////////////
435 
436  if( aStatusTextReporter )
437  aStatusTextReporter->Report( _( "Load OpenGL: holes and vias" ) );
438 
442  1.0f,
443  0.0f,
444  false );
445 
447 
450 
453  bodyHoles,
454  1.0f,
455  0.0f,
456  false );
457 
461  1.0f,
462  0.0f,
463  true );
464 
465 
469  1.0f,
470  0.0f,
471  false );
472 
473  // Not in use
474  //m_ogl_disp_list_through_holes_vias_inner = generate_holes_display_list(
475  // m_settings.GetThroughHole_Vias_Inner().GetList(),
476  // m_settings.GetThroughHole_Vias_Inner_poly(),
477  // 1.0f, 0.0f,
478  // false );
479 
480  const MAP_POLY & innerMapHoles = m_settings.GetPolyMapHoles_Inner();
481  const MAP_POLY & outerMapHoles = m_settings.GetPolyMapHoles_Outer();
482 
483  wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
484 
485  const MAP_CONTAINER_2D &map_holes = m_settings.GetMapLayersHoles();
486 
487  if( outerMapHoles.size() > 0 )
488  {
489  float layer_z_bot = 0.0f;
490  float layer_z_top = 0.0f;
491 
492  for( MAP_POLY::const_iterator ii = outerMapHoles.begin();
493  ii != outerMapHoles.end();
494  ++ii )
495  {
496  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
497  const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
498  const CBVHCONTAINER2D *container = map_holes.at( layer_id );
499 
500  get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
501 
503  container->GetList(),
504  *poly,
505  layer_z_top,
506  layer_z_bot,
507  false );
508  }
509 
510  for( MAP_POLY::const_iterator ii = innerMapHoles.begin();
511  ii != innerMapHoles.end();
512  ++ii )
513  {
514  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
515  const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
516  const CBVHCONTAINER2D *container = map_holes.at( layer_id );
517 
518  get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
519 
521  container->GetList(),
522  *poly,
523  layer_z_top,
524  layer_z_bot,
525  false );
526  }
527  }
528 
529  // Generate vertical cylinders of vias and pads (copper)
531 
532  // Add layers maps
533  // /////////////////////////////////////////////////////////////////////////
534 
535  if( aStatusTextReporter )
536  aStatusTextReporter->Report( _( "Load OpenGL: layers" ) );
537 
538  for( MAP_CONTAINER_2D::const_iterator ii = m_settings.GetMapLayers().begin();
539  ii != m_settings.GetMapLayers().end();
540  ++ii )
541  {
542  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>(ii->first);
543 
544  if( !m_settings.Is3DLayerEnabled( layer_id ) )
545  continue;
546 
547  const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(ii->second);
548  const LIST_OBJECT2D &listObject2d = container2d->GetList();
549 
550  if( listObject2d.size() == 0 )
551  continue;
552 
553  float layer_z_bot = 0.0f;
554  float layer_z_top = 0.0f;
555 
556  get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );
557 
558  // Calculate an estimation for the nr of triangles based on the nr of objects
559  unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
560 
561  CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );
562 
563  m_triangles[layer_id] = layerTriangles;
564 
565  // Load the 2D (X,Y axis) component of shapes
566  for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
567  itemOnLayer != listObject2d.end();
568  ++itemOnLayer )
569  {
570  const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
571 
572  switch( object2d_A->GetObjectType() )
573  {
574  case OBJ2D_FILLED_CIRCLE:
575  add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
576  layerTriangles,
577  layer_z_top, layer_z_bot );
578  break;
579 
580  case OBJ2D_POLYGON4PT:
581  add_object_to_triangle_layer( (const CPOLYGON4PTS2D *)object2d_A,
582  layerTriangles,
583  layer_z_top, layer_z_bot );
584  break;
585 
586  case OBJ2D_RING:
587  add_object_to_triangle_layer( (const CRING2D *)object2d_A,
588  layerTriangles,
589  layer_z_top, layer_z_bot );
590  break;
591 
592  case OBJ2D_TRIANGLE:
593  add_object_to_triangle_layer( (const CTRIANGLE2D *)object2d_A,
594  layerTriangles,
595  layer_z_top, layer_z_bot );
596  break;
597 
598  case OBJ2D_ROUNDSEG:
599  add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
600  layerTriangles,
601  layer_z_top, layer_z_bot );
602  break;
603 
604  default:
605  wxFAIL_MSG("C3D_RENDER_OGL_LEGACY: Object type is not implemented");
606  break;
607  }
608  }
609 
610  const MAP_POLY &map_poly = m_settings.GetPolyMap();
611 
612  // Load the vertical (Z axis) component of shapes
613  if( map_poly.find( layer_id ) != map_poly.end() )
614  {
615  const SHAPE_POLY_SET *polyList = map_poly.at( layer_id );
616 
617  layerTriangles->AddToMiddleContourns( *polyList,
618  layer_z_bot,
619  layer_z_top,
621  false );
622  }
623 
624  // Create display list
625  // /////////////////////////////////////////////////////////////////////
626  m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
628  layer_z_bot,
629  layer_z_top );
630  }// for each layer on map
631 
632 #ifdef PRINT_STATISTICS_3D_VIEWER
633  unsigned stats_end_OpenGL_Load_Time = GetRunningMicroSecs();
634 #endif
635 
636  // Load 3D models
637  // /////////////////////////////////////////////////////////////////////////
638 #ifdef PRINT_STATISTICS_3D_VIEWER
639  unsigned stats_start_models_Load_Time = GetRunningMicroSecs();
640 #endif
641 
642  if( aStatusTextReporter )
643  aStatusTextReporter->Report( _( "Loading 3D models" ) );
644 
645  load_3D_models( aStatusTextReporter );
646 
647 #ifdef PRINT_STATISTICS_3D_VIEWER
648  unsigned stats_end_models_Load_Time = GetRunningMicroSecs();
649 
650 
651  printf( "C3D_RENDER_OGL_LEGACY::reload times:\n" );
652  printf( " Reload board: %.3f ms\n",
653  (float)( stats_endReloadTime - stats_startReloadTime ) / 1000.0f );
654  printf( " Loading to openGL: %.3f ms\n",
655  (float)( stats_end_OpenGL_Load_Time - stats_start_OpenGL_Load_Time ) / 1000.0f );
656  printf( " Loading 3D models: %.3f ms\n",
657  (float)( stats_end_models_Load_Time - stats_start_models_Load_Time ) / 1000.0f );
659 #endif
660 
661  if( aStatusTextReporter )
662  {
663  // Calculation time in seconds
664  const double calculation_time = (double)( GetRunningMicroSecs() -
665  stats_startReloadTime) / 1e6;
666 
667  aStatusTextReporter->Report( wxString::Format( _( "Reload time %.3f s" ),
668  calculation_time ) );
669  }
670 }
671 
672 
674  const SFVEC2F &v0,
675  const SFVEC2F &v1,
676  const SFVEC2F &v2,
677  float top,
678  float bot )
679 {
680  aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
681  SFVEC3F( v1.x, v1.y, bot ),
682  SFVEC3F( v2.x, v2.y, bot ) );
683 
684  aDst->m_layer_top_triangles->AddTriangle( SFVEC3F( v2.x, v2.y, top ),
685  SFVEC3F( v1.x, v1.y, top ),
686  SFVEC3F( v0.x, v0.y, top ) );
687 }
688 
689 
691  float &aOutZtop,
692  float &aOutZbot ) const
693 {
694  aOutZbot = m_settings.GetLayerBottomZpos3DU( aLayerID );
695  aOutZtop = m_settings.GetLayerTopZpos3DU( aLayerID );
696 
697  if( aOutZtop < aOutZbot )
698  {
699  float tmpFloat = aOutZbot;
700  aOutZbot = aOutZtop;
701  aOutZtop = tmpFloat;
702  }
703 }
704 
705 
707  float aInnerRadius,
708  float aOuterRadius,
709  float aZtop,
710  float aZbot,
711  unsigned int aNr_sides_per_circle,
712  CLAYER_TRIANGLES *aDstLayer )
713 {
714  std::vector< SFVEC2F > innerContour;
715  std::vector< SFVEC2F > outerContour;
716 
717  generate_ring_contour( aCenter,
718  aInnerRadius,
719  aOuterRadius,
720  aNr_sides_per_circle,
721  innerContour,
722  outerContour,
723  false );
724 
725  for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
726  {
727  const SFVEC2F &vi0 = innerContour[i + 0];
728  const SFVEC2F &vi1 = innerContour[i + 1];
729  const SFVEC2F &vo0 = outerContour[i + 0];
730  const SFVEC2F &vo1 = outerContour[i + 1];
731 
732  aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
733  SFVEC3F( vi0.x, vi0.y, aZtop ),
734  SFVEC3F( vo0.x, vo0.y, aZtop ),
735  SFVEC3F( vo1.x, vo1.y, aZtop ) );
736 
737  aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
738  SFVEC3F( vo1.x, vo1.y, aZbot ),
739  SFVEC3F( vo0.x, vo0.y, aZbot ),
740  SFVEC3F( vi0.x, vi0.y, aZbot ) );
741  }
742 
743  aDstLayer->AddToMiddleContourns( outerContour, aZbot, aZtop, true );
744  aDstLayer->AddToMiddleContourns( innerContour, aZbot, aZtop, false );
745 }
746 
747 
749 {
751  {
752  const unsigned int reserve_nr_triangles_estimation =
754  8 *
756 
757  CLAYER_TRIANGLES *layerTriangleVIA = new CLAYER_TRIANGLES( reserve_nr_triangles_estimation );
758 
759  // Insert plated vertical holes inside the board
760  // /////////////////////////////////////////////////////////////////////////
761 
762  // Insert vias holes (vertical cylinders)
763  for( const TRACK* track = m_settings.GetBoard()->m_Track;
764  track;
765  track = track->Next() )
766  {
767  if( track->Type() == PCB_VIA_T )
768  {
769  const VIA *via = static_cast<const VIA*>(track);
770 
771  const float holediameter = via->GetDrillValue() * m_settings.BiuTo3Dunits();
772  const float thickness = m_settings.GetCopperThickness3DU();
773  const int nrSegments = m_settings.GetNrSegmentsCircle( via->GetDrillValue() );
774  const double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
775  const float hole_inner_radius = ( holediameter / 2.0f ) * correctionFactor;
776 
777  const SFVEC2F via_center( via->GetStart().x * m_settings.BiuTo3Dunits(),
778  -via->GetStart().y * m_settings.BiuTo3Dunits() );
779 
780  PCB_LAYER_ID top_layer, bottom_layer;
781  via->LayerPair( &top_layer, &bottom_layer );
782 
783  float ztop, zbot, dummy;
784 
785  get_layer_z_pos( top_layer, ztop, dummy );
786  get_layer_z_pos( bottom_layer, dummy, zbot );
787 
788  wxASSERT( zbot < ztop );
789 
790  generate_cylinder( via_center,
791  hole_inner_radius,
792  hole_inner_radius + thickness,
793  ztop,
794  zbot,
795  nrSegments,
796  layerTriangleVIA );
797  }
798  }
799 
800  m_ogl_disp_list_via = new CLAYERS_OGL_DISP_LISTS( *layerTriangleVIA,
801  0,
802  0.0f,
803  0.0f );
804 
805  delete layerTriangleVIA;
806  }
807 
808 
809  if( m_settings.GetStats_Nr_Holes() > 0 )
810  {
811  SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes (the pad)
812  SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes (the hole)
813 
814  tht_outer_holes_poly.RemoveAllContours();
815  tht_inner_holes_poly.RemoveAllContours();
816 
817  // Insert pads holes (vertical cylinders)
818  for( const MODULE* module = m_settings.GetBoard()->m_Modules;
819  module;
820  module = module->Next() )
821  {
822  for( const D_PAD* pad = module->PadsList(); pad; pad = pad->Next() )
823  {
824  if( pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
825  {
826  const wxSize drillsize = pad->GetDrillSize();
827  const bool hasHole = drillsize.x && drillsize.y;
828 
829  if( !hasHole )
830  continue;
831 
832  // we use the hole diameter to calculate the seg count.
833  // for round holes, drillsize.x == drillsize.y
834  // for slots, the diameter is the smaller of (drillsize.x, drillsize.y)
835  int copperThickness = m_settings.GetCopperThicknessBIU();
836  int radius = std::min( drillsize.x, drillsize.y ) / 2 + copperThickness;
837  int nrSegments = m_settings.GetNrSegmentsCircle( radius * 2 );
838  double correctionFactor = m_settings.GetCircleCorrectionFactor( nrSegments );
839  int correction = radius * ( correctionFactor - 1 );
840 
841  pad->BuildPadDrillShapePolygon( tht_outer_holes_poly,
842  copperThickness + correction,
843  nrSegments );
844 
845  pad->BuildPadDrillShapePolygon( tht_inner_holes_poly,
846  correction,
847  nrSegments );
848  }
849  }
850  }
851 
852  // Subtract the holes
853  tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );
854 
855 
856  CCONTAINER2D holesContainer;
857 
858  Convert_shape_line_polygon_to_triangles( tht_outer_holes_poly,
859  holesContainer,
861  (const BOARD_ITEM &)*m_settings.GetBoard() );
862 
863  const LIST_OBJECT2D &listHolesObject2d = holesContainer.GetList();
864 
865  if( listHolesObject2d.size() > 0 )
866  {
867  float layer_z_top, layer_z_bot, dummy;
868 
869  get_layer_z_pos( F_Cu, layer_z_top, dummy );
870  get_layer_z_pos( B_Cu, dummy, layer_z_bot );
871 
872  CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listHolesObject2d.size() );
873 
874  // Convert the list of objects(triangles) to triangle layer structure
875  for( LIST_OBJECT2D::const_iterator itemOnLayer = listHolesObject2d.begin();
876  itemOnLayer != listHolesObject2d.end();
877  ++itemOnLayer )
878  {
879  const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
880 
881  wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );
882 
883  const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
884 
885  const SFVEC2F &v1 = tri->GetP1();
886  const SFVEC2F &v2 = tri->GetP2();
887  const SFVEC2F &v3 = tri->GetP3();
888 
889  add_triangle_top_bot( layerTriangles,
890  v1,
891  v2,
892  v3,
893  layer_z_top,
894  layer_z_bot );
895  }
896 
897  wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
898 
899  if( tht_outer_holes_poly.OutlineCount() > 0 )
900  {
901  layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
902  layer_z_bot,
903  layer_z_top,
905  false );
906 
908  *layerTriangles,
909  m_ogl_circle_texture, // not need
910  layer_z_top,
911  layer_z_top );
912  }
913 
914  delete layerTriangles;
915  }
916  }
917 }
918 
919 
920 /*
921  * This function will get models from the cache and load it to openGL lists
922  * in the form of C_OGL_3DMODEL. So this map of models will work as a local
923  * cache for this render. (cache based on C_OGL_3DMODEL with associated
924  * openGL lists in GPU memory)
925  */
927 {
931  return;
932 
933  // Go for all modules
934  for( const MODULE* module = m_settings.GetBoard()->m_Modules;
935  module;
936  module = module->Next() )
937  {
938  if( !module->Models().empty() )
939  {
940  // Get the list of model files for this model
941  auto sM = module->Models().begin();
942  auto eM = module->Models().end();
943 
944  while( sM != eM )
945  {
946  if( !sM->m_Filename.empty() )
947  {
948  if( aStatusTextReporter )
949  {
950  // Display the short filename of the 3D model loaded:
951  // (the full name is usually too long to be displayed)
952  wxFileName fn( sM->m_Filename );
953  wxString msg;
954  msg.Printf( _( "Loading %s" ), fn.GetFullName() );
955  aStatusTextReporter->Report( msg );
956  }
957 
958  // Check if the model is not present in our cache map
959  // (Not already loaded in memory)
960  if( m_3dmodel_map.find( sM->m_Filename ) == m_3dmodel_map.end() )
961  {
962  // It is not present, try get it from cache
963  const S3DMODEL *modelPtr =
964  m_settings.Get3DCacheManager()->GetModel( sM->m_Filename );
965 
966  // only add it if the return is not NULL
967  if( modelPtr )
968  {
969  C_OGL_3DMODEL* ogl_model =
970  new C_OGL_3DMODEL( *modelPtr,
972 
973  if( ogl_model )
974  m_3dmodel_map[ sM->m_Filename ] = ogl_model;
975  }
976  }
977  }
978 
979  ++sM;
980  }
981  }
982  }
983 }
std::map< PCB_LAYER_ID, CBVHCONTAINER2D * > MAP_CONTAINER_2D
A type that stores a container of 2d objects for each layer id.
Definition: cinfo3d_visu.h:55
void generate_ring_contour(const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, unsigned int aNr_sides_per_circle, std::vector< SFVEC2F > &aInnerContourResult, std::vector< SFVEC2F > &aOuterContourResult, bool aInvertOrder)
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers
std::map< PCB_LAYER_ID, SHAPE_POLY_SET * > MAP_POLY
A type that stores polysets for each layer id.
Definition: cinfo3d_visu.h:58
void add_object_to_triangle_layer(const CRING2D *aRing, CLAYER_TRIANGLES *aDstLayer, float aZtop, float aZbot)
const LIST_OBJECT2D & GetList() const
Definition: ccontainer2d.h:62
S3D_CACHE * Get3DCacheManager() const
Get3DCacheManager - Return the 3d cache manager pointer.
Definition: cinfo3d_visu.h:88
const SFVEC2F & GetRightEnd() const
const SFVEC2F & GetStart() const
float GetRadiusSquared() const
The CLAYER_TRIANGLES class stores arrays of triangles to be used to create display lists...
float GetCopperThickness3DU() const
GetCopperThickness3DU - Get the current copper layer thickness.
Definition: cinfo3d_visu.h:165
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
MATERIAL_MODE MaterialModeGet() const
MaterialModeGet.
Definition: cinfo3d_visu.h:246
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset union For aFastMode meaning, see function booleanOp
void PrintStats()
Definition: cobject2d.cpp:60
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
const SHAPE_POLY_SET & GetThroughHole_Vias_Outer_poly() const
GetThroughHole_Vias_Outer_poly -.
Definition: cinfo3d_visu.h:336
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_outer
const SHAPE_POLY_SET & GetBoardPoly() const
GetBoardPoly - Get the current polygon of the epoxy board.
Definition: cinfo3d_visu.h:252
Class BOARD to handle a board.
MODULE * Next() const
Definition: class_module.h:123
const SHAPE_POLY_SET & GetThroughHole_Outer_poly_NPTH() const
GetThroughHole_Outer_poly_NPTH -.
Definition: cinfo3d_visu.h:317
int GetCopperThicknessBIU() const
GetCopperThicknessBIU - Get the current copper layer thickness.
int OutlineCount() const
Returns the number of outlines in the set
const SFVEC2F & GetV2() const
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
float GetStats_Med_Via_Hole_Diameter3DU() const
GetStats_Med_Via_Hole_Diameter3DU - Average diameter of the via holes.
Definition: cinfo3d_visu.h:374
CINFO3D_VISU & m_settings
settings refrence in use for this render
float GetLayerTopZpos3DU(PCB_LAYER_ID aLayerId) const
GetLayerTopZpos3DU - Get the top z position.
Definition: cinfo3d_visu.h:280
const SFVEC2F & GetV3() const
static const int delta[8][2]
Definition: solve.cpp:112
const SFVEC2F & GetV1() const
S3DMODEL * GetModel(const wxString &aModelFileName)
Function GetModel attempts to load the scene data for a model and to translate it into an S3D_MODEL s...
Definition: 3d_cache.cpp:781
const SFVEC2F & GetCenter() const
Definition: cring2d.h:38
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_through_holes_inner
const SFVEC2F & GetP1() const
Definition: ctriangle2d.h:58
const SFVEC2F & GetCenter() const
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_through_holes_outer
float GetOuterRadius() const
Definition: cring2d.h:40
const MAP_CONTAINER_2D & GetMapLayersHoles() const
GetMapLayersHoles -Get the map of container that have the holes per layer.
Definition: cinfo3d_visu.h:299
PCB_LAYER_ID
A quick note on layer IDs:
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
const SFVEC3F & GetBoardCenter3DU() const
GetBoardCenter - the board center position in 3d units.
Definition: cinfo3d_visu.h:189
float GetRadius() const
float GetLayerBottomZpos3DU(PCB_LAYER_ID aLayerId) const
GetLayerBottomZpos3DU - Get the bottom z position.
Definition: cinfo3d_visu.h:287
Class SHAPE_POLY_SET.
const wxPoint & GetStart() const
Definition: class_track.h:122
void Convert_shape_line_polygon_to_triangles(const SHAPE_POLY_SET &aPolyList, CGENERICCONTAINER2D &aDstContainer, float aBiuTo3DunitsScale, const BOARD_ITEM &aBoardItem)
CLAYER_TRIANGLE_CONTAINER * m_layer_top_triangles
const SFVEC2F & GetEnd() const
D_PAD * Next() const
Definition: class_pad.h:159
const SHAPE_POLY_SET & GetThroughHole_Outer_poly() const
GetThroughHole_Outer_poly -.
Definition: cinfo3d_visu.h:311
const MAP_POLY & GetPolyMapHoles_Outer() const
Definition: cinfo3d_visu.h:418
const SFVEC2F & GetLeftEnd() const
void reload(REPORTER *aStatusTextReporter)
OBJECT2D_TYPE GetObjectType() const
Definition: cobject2d.h:125
const SFVEC2F & GetRightStar() const
void AddTriangle(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3)
AddTriangle.
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_through_holes_vias_outer
void get_layer_z_pos(PCB_LAYER_ID aLayerID, float &aOutZtop, float &aOutZbot) const
const CBVHCONTAINER2D & GetThroughHole_Vias_Outer() const
GetThroughHole_Vias_Outer -.
Definition: cinfo3d_visu.h:324
const MAP_POLY & GetPolyMap() const
GetPolyMap - Get maps of polygons&#39;s layers.
Definition: cinfo3d_visu.h:414
bool Is3DLayerEnabled(PCB_LAYER_ID aLayer) const
Is3DLayerEnabled - Check if a layer is enabled.
float GetRadius() const
void AddToMiddleContourns(const SHAPE_LINE_CHAIN &outlinePath, float zBot, float zTop, double aBiuTo3Du, bool aInvertFaceDirection)
const CBVHCONTAINER2D & GetThroughHole_Inner() const
GetThroughHole_Inner - Get the ThroughHole container.
Definition: cinfo3d_visu.h:350
static COBJECT2D_STATS & Instance()
Definition: cobject2d.h:146
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...
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_via
unsigned int GetNrSegmentsCircle(float aDiameter3DU) const
GetNrSegmentsCircle.
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers_holes_inner
The CLAYERS_OGL_DISP_LISTS class stores the openGL display lists to related with a layer...
#define SIZE_OF_CIRCLE_TEXTURE
CLAYERS_OGL_DISP_LISTS * generate_holes_display_list(const LIST_OBJECT2D &aListHolesObject2d, const SHAPE_POLY_SET &aPoly, float aZtop, float aZbot, bool aInvertFaces)
bool GetFlag(DISPLAY3D_FLG aFlag) const
GetFlag - get a configuration status of a flag.
const SFVEC2F & GetP2() const
Definition: ctriangle2d.h:59
const SFVEC2F & GetLeftStar() const
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_through_holes_outer_with_npth
This handles simple polygons with 4 points.
const SFVEC2F & GetRightDir() const
TRACK * Next() const
Definition: class_track.h:99
double GetCircleCorrectionFactor(int aNrSides) const
GetCircleCorrectionFactor - computes a angle correction factor used when creating circles...
CLAYER_TRIANGLE_CONTAINER * m_layer_bot_segment_ends
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
bool m_reloadRequested
!TODO: this must be reviewed in order to flag change types
void load_3D_models(REPORTER *aStatusTextReporter)
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
CLAYER_TRIANGLE_CONTAINER * m_layer_bot_triangles
std::list< COBJECT2D * > LIST_OBJECT2D
Definition: ccontainer2d.h:36
DLIST< MODULE > m_Modules
Definition: class_board.h:247
CCAMERA & CameraGet() const
CameraGet - get current camera in use.
Definition: cinfo3d_visu.h:210
unsigned GetRunningMicroSecs()
Function GetRunningMicroSecs An alternate way to calculate an elapset time (in microsecondes) to clas...
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
const SFVEC2F & GetP3() const
Definition: ctriangle2d.h:60
const MAP_POLY & GetPolyMapHoles_Inner() const
Definition: cinfo3d_visu.h:416
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void SetBoardLookAtPos(const SFVEC3F &aBoardPos)
Definition: ccamera.h:115
size_t i
Definition: json11.cpp:597
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
void ResetStats()
Definition: cobject2d.h:135
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_board
unsigned int GetStats_Nr_Vias() const
GetStats_Nr_Vias - Get statistics of the nr of vias.
Definition: cinfo3d_visu.h:362
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
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
const SHAPE_POLY_SET & GetThroughHole_Inner_poly() const
GetThroughHole_Inner_poly -.
Definition: cinfo3d_visu.h:356
DLIST< TRACK > m_Track
Definition: class_board.h:248
const SFVEC2F & GetLeftDir() const
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp ...
Module description (excepted pads)
const CBVHCONTAINER2D & GetThroughHole_Outer() const
GetThroughHole_Outer - Get the inflated ThroughHole container.
Definition: cinfo3d_visu.h:305
CLAYER_TRIANGLE_CONTAINER * m_layer_top_segment_ends
const SFVEC2F & GetV0() const
void add_triangle_top_bot(CLAYER_TRIANGLES *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot)
CLAYERS_OGL_DISP_LISTS * m_ogl_disp_list_pads_holes
float GetInnerRadius() const
Definition: cring2d.h:39
const BOARD * GetBoard() const
GetBoard - Get current board to be rendered.
Definition: cinfo3d_visu.h:128
double BiuTo3Dunits() const
BiuTo3Dunits - Board integer units To 3D units.
Definition: cinfo3d_visu.h:141
void generate_cylinder(const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, float aZtop, float aZbot, unsigned int aNr_sides_per_circle, CLAYER_TRIANGLES *aDstLayer)
const MAP_CONTAINER_2D & GetMapLayers() const
GetMapLayers - Get the map of container that have the objects per layer.
Definition: cinfo3d_visu.h:293
#define min(a, b)
Definition: auxiliary.h:85
void InitSettings(REPORTER *aStatusTextReporter)
InitSettings - Function to be called by the render when it need to reload the settings for the board...
unsigned int GetStats_Nr_Holes() const
GetStats_Nr_Holes - Get statistics of the nr of holes.
Definition: cinfo3d_visu.h:368
void AddQuad(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3, const SFVEC3F &aV4)
AddQuad.