KiCad PCB EDA Suite
Loading...
Searching...
No Matches
opengl/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 <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "render_3d_opengl.h"
27#include <board.h>
28#include <footprint.h>
29#include <pcb_track.h>
30#include "../../3d_math.h"
32#include <lset.h>
33#include <trigo.h>
34#include <project.h>
35#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
36#include <fp_lib_table.h>
37#include <eda_3d_viewer_frame.h>
38#include <project_pcb.h>
39
40
42 TRIANGLE_DISPLAY_LIST* aDstLayer, float aZtop,
43 float aZbot )
44{
45 const SFVEC2F& center = aCircle->GetCenter();
46 const float radius = aCircle->GetRadius() * 2.0f; // Double because the render triangle
47
48 // This is a small adjustment to the circle texture
49 const float texture_factor = ( 8.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
50 const float f = ( sqrtf( 2.0f ) / 2.0f ) * radius * texture_factor;
51
52 // Top and Bot segments ends are just triangle semi-circles, so need to add it in duplicated.
53 aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZtop ),
54 SFVEC3F( center.x - f, center.y, aZtop ),
55 SFVEC3F( center.x, center.y - f, aZtop ) );
56
57 aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZtop ),
58 SFVEC3F( center.x + f, center.y, aZtop ),
59 SFVEC3F( center.x, center.y + f, aZtop ) );
60
61 aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZbot ),
62 SFVEC3F( center.x + f, center.y, aZbot ),
63 SFVEC3F( center.x, center.y - f, aZbot ) );
64
65 aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZbot ),
66 SFVEC3F( center.x - f, center.y, aZbot ),
67 SFVEC3F( center.x, center.y + f, aZbot ) );
68}
69
70
72 TRIANGLE_DISPLAY_LIST* aDstLayer,
73 float aZtop, float aZbot )
74{
75 const SFVEC2F& v0 = aPoly->GetV0();
76 const SFVEC2F& v1 = aPoly->GetV1();
77 const SFVEC2F& v2 = aPoly->GetV2();
78 const SFVEC2F& v3 = aPoly->GetV3();
79
80 addTopAndBottomTriangles( aDstLayer, v0, v2, v1, aZtop, aZbot );
81 addTopAndBottomTriangles( aDstLayer, v2, v0, v3, aZtop, aZbot );
82}
83
84
85void RENDER_3D_OPENGL::generateRing( const SFVEC2F& aCenter, float aInnerRadius,
86 float aOuterRadius, unsigned int aNr_sides_per_circle,
87 std::vector< SFVEC2F >& aInnerContourResult,
88 std::vector< SFVEC2F >& aOuterContourResult,
89 bool aInvertOrder )
90{
91 aInnerContourResult.clear();
92 aInnerContourResult.reserve( aNr_sides_per_circle + 2 );
93
94 aOuterContourResult.clear();
95 aOuterContourResult.reserve( aNr_sides_per_circle + 2 );
96
97 const int delta = 3600 / aNr_sides_per_circle;
98
99 for( int ii = 0; ii < 3600; ii += delta )
100 {
101 float angle = (float)( aInvertOrder ? ( 3600 - ii ) : ii )
102 * 2.0f * glm::pi<float>() / 3600.0f;
103 const SFVEC2F rotatedDir = SFVEC2F( cos( angle ), sin( angle ) );
104
105 aInnerContourResult.emplace_back( aCenter.x + rotatedDir.x * aInnerRadius,
106 aCenter.y + rotatedDir.y * aInnerRadius );
107
108 aOuterContourResult.emplace_back( aCenter.x + rotatedDir.x * aOuterRadius,
109 aCenter.y + rotatedDir.y * aOuterRadius );
110 }
111
112 aInnerContourResult.push_back( aInnerContourResult[0] );
113 aOuterContourResult.push_back( aOuterContourResult[0] );
114
115 wxASSERT( aInnerContourResult.size() == aOuterContourResult.size() );
116}
117
118
120 float aZtop, float aZbot )
121{
122 const SFVEC2F& center = aRing->GetCenter();
123 const float inner = aRing->GetInnerRadius();
124 const float outer = aRing->GetOuterRadius();
125
126 std::vector< SFVEC2F > innerContour;
127 std::vector< SFVEC2F > outerContour;
128
129 generateRing( center, inner, outer, m_boardAdapter.GetCircleSegmentCount( outer * 2.0f ),
130 innerContour, outerContour, false );
131
132 // This will add the top and bot quads that will form the approximated ring
133 for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
134 {
135 const SFVEC2F& vi0 = innerContour[i + 0];
136 const SFVEC2F& vi1 = innerContour[i + 1];
137 const SFVEC2F& vo0 = outerContour[i + 0];
138 const SFVEC2F& vo1 = outerContour[i + 1];
139
140 aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
141 SFVEC3F( vi0.x, vi0.y, aZtop ),
142 SFVEC3F( vo0.x, vo0.y, aZtop ),
143 SFVEC3F( vo1.x, vo1.y, aZtop ) );
144
145 aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
146 SFVEC3F( vo1.x, vo1.y, aZbot ),
147 SFVEC3F( vo0.x, vo0.y, aZbot ),
148 SFVEC3F( vi0.x, vi0.y, aZbot ) );
149 }
150}
151
152
154 float aZtop, float aZbot )
155{
156 const SFVEC2F& v1 = aTri->GetP1();
157 const SFVEC2F& v2 = aTri->GetP2();
158 const SFVEC2F& v3 = aTri->GetP3();
159
160 addTopAndBottomTriangles( aDstLayer, v1, v2, v3, aZtop, aZbot );
161}
162
163
165 TRIANGLE_DISPLAY_LIST* aDstLayer,
166 float aZtop, float aZbot )
167{
168 const SFVEC2F& leftStart = aSeg->GetLeftStar();
169 const SFVEC2F& leftEnd = aSeg->GetLeftEnd();
170 const SFVEC2F& leftDir = aSeg->GetLeftDir();
171
172 const SFVEC2F& rightStart = aSeg->GetRightStar();
173 const SFVEC2F& rightEnd = aSeg->GetRightEnd();
174 const SFVEC2F& rightDir = aSeg->GetRightDir();
175 const float radius = aSeg->GetRadius();
176
177 const SFVEC2F& start = aSeg->GetStart();
178 const SFVEC2F& end = aSeg->GetEnd();
179
180 const float texture_factor = ( 12.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
181 const float texture_factorF = ( 6.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
182
183 const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
184 const float radius_triangle_factor = ( radius_of_the_square - radius ) / radius;
185
186 const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
187 rightDir.x * radius * radius_triangle_factor );
188
189 const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
190 leftDir.x * radius * radius_triangle_factor );
191
192 // Top end segment triangles (semi-circles)
194 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
195 rightEnd.y + texture_factor * factorS.y,
196 aZtop ),
197 SFVEC3F( leftStart.x + texture_factor * factorE.x,
198 leftStart.y + texture_factor * factorE.y,
199 aZtop ),
200 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
201 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
202 aZtop ) );
203
205 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
206 leftEnd.y + texture_factor * factorE.y, aZtop ),
207 SFVEC3F( rightStart.x + texture_factor * factorS.x,
208 rightStart.y + texture_factor * factorS.y, aZtop ),
209 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
210 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
211 aZtop ) );
212
213 // Bot end segment triangles (semi-circles)
215 SFVEC3F( leftStart.x + texture_factor * factorE.x,
216 leftStart.y + texture_factor * factorE.y,
217 aZbot ),
218 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
219 rightEnd.y + texture_factor * factorS.y,
220 aZbot ),
221 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
222 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
223 aZbot ) );
224
226 SFVEC3F( rightStart.x + texture_factor * factorS.x,
227 rightStart.y + texture_factor * factorS.y, aZbot ),
228 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
229 leftEnd.y + texture_factor * factorE.y, aZbot ),
230 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
231 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
232 aZbot ) );
233
234 // Segment top and bot planes
235 aDstLayer->m_layer_top_triangles->AddQuad(
236 SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
237 SFVEC3F( rightStart.x, rightStart.y, aZtop ),
238 SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
239 SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
240
241 aDstLayer->m_layer_bot_triangles->AddQuad(
242 SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
243 SFVEC3F( leftStart.x, leftStart.y, aZbot ),
244 SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
245 SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
246}
247
248
250 const SHAPE_POLY_SET& aPoly, float aZtop, float aZbot,
251 bool aInvertFaces, const BVH_CONTAINER_2D* aThroughHoles )
252{
253 if( aListHolesObject2d.size() == 0 )
254 return nullptr;
255
256 OPENGL_RENDER_LIST* ret = nullptr;
257 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( aListHolesObject2d.size() * 2 );
258
259 // Convert the list of objects(filled circles) to triangle layer structure
260 for( const OBJECT_2D* object2d : aListHolesObject2d )
261 {
262 switch( object2d->GetObjectType() )
263 {
265 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d ), layerTriangles, aZtop, aZbot );
266 break;
267
269 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d ), layerTriangles, aZtop, aZbot );
270 break;
271
272 default:
273 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL::generateHoles: Object type not implemented" ) );
274 break;
275 }
276 }
277
278 // Note: he can have a aListHolesObject2d with holes but without contours
279 // eg: when there are only NPTH on the list and the contours were not added
280 if( aPoly.OutlineCount() > 0 )
281 {
282 layerTriangles->AddToMiddleContours( aPoly, aZbot, aZtop, m_boardAdapter.BiuTo3dUnits(), aInvertFaces,
283 aThroughHoles );
284 }
285
286 ret = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, aZbot, aZtop );
287
288 delete layerTriangles;
289
290 return ret;
291}
292
293
295 const SHAPE_POLY_SET* aPolyList, PCB_LAYER_ID aLayer,
296 const BVH_CONTAINER_2D* aThroughHoles )
297{
298 if( aContainer == nullptr )
299 return nullptr;
300
301 const LIST_OBJECT2D& listObject2d = aContainer->GetList();
302
303 if( listObject2d.size() == 0 )
304 return nullptr;
305
306 float zBot = 0.0f;
307 float zTop = 0.0f;
308
309 getLayerZPos( aLayer, zTop, zBot );
310
311 // Calculate an estimation for the nr of triangles based on the nr of objects
312 unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
313
314 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( nrTrianglesEstimation );
315
316 // store in a list so it will be latter deleted
317 m_triangles.push_back( layerTriangles );
318
319 // Load the 2D (X,Y axis) component of shapes
320 for( const OBJECT_2D* object2d : listObject2d )
321 {
322 switch( object2d->GetObjectType() )
323 {
325 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d ), layerTriangles, zTop, zBot );
326 break;
327
329 addObjectTriangles( static_cast<const POLYGON_4PT_2D*>( object2d ), layerTriangles, zTop, zBot );
330 break;
331
333 addObjectTriangles( static_cast<const RING_2D*>( object2d ), layerTriangles, zTop, zBot );
334 break;
335
337 addObjectTriangles( static_cast<const TRIANGLE_2D*>( object2d ), layerTriangles, zTop, zBot );
338 break;
339
341 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d ), layerTriangles, zTop, zBot );
342 break;
343
344 default:
345 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL: Object type is not implemented" ) );
346 break;
347 }
348 }
349
350 if( aPolyList && aPolyList->OutlineCount() > 0 )
351 {
352 layerTriangles->AddToMiddleContours( *aPolyList, zBot, zTop, m_boardAdapter.BiuTo3dUnits(), false,
353 aThroughHoles );
354 }
355
356 // Create display list
357 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, zBot, zTop );
358}
359
360
362{
363 float layer_z_bot = 0.0f;
364 float layer_z_top = 0.0f;
365
366 getLayerZPos( aLayer, layer_z_top, layer_z_bot );
367
368 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( 1 );
369
370 // store in a list so it will be latter deleted
371 m_triangles.push_back( layerTriangles );
372
373 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
374}
375
376
378 const BVH_CONTAINER_2D* aThroughHoles )
379{
380 OPENGL_RENDER_LIST* dispLists = nullptr;
381 CONTAINER_2D boardContainer;
382
383 ConvertPolygonToTriangles( aBoardPoly, boardContainer, m_boardAdapter.BiuTo3dUnits(),
384 (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
385
386 const LIST_OBJECT2D& listBoardObject2d = boardContainer.GetList();
387
388 if( listBoardObject2d.size() > 0 )
389 {
390 // We will set a unitary Z so it will in future used with transformations since the
391 // board poly will be used not only to draw itself but also the solder mask layers.
392 const float layer_z_top = 1.0f;
393 const float layer_z_bot = 0.0f;
394
395 TRIANGLE_DISPLAY_LIST* layerTriangles =
396 new TRIANGLE_DISPLAY_LIST( listBoardObject2d.size() );
397
398 // Convert the list of objects(triangles) to triangle layer structure
399 for( const OBJECT_2D* itemOnLayer : listBoardObject2d )
400 {
401 const OBJECT_2D* object2d_A = itemOnLayer;
402
403 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
404
405 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
406
407 const SFVEC2F& v1 = tri->GetP1();
408 const SFVEC2F& v2 = tri->GetP2();
409 const SFVEC2F& v3 = tri->GetP3();
410
411 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
412 }
413
414 if( aBoardPoly.OutlineCount() > 0 )
415 {
416 layerTriangles->AddToMiddleContours( aBoardPoly, layer_z_bot, layer_z_top,
417 m_boardAdapter.BiuTo3dUnits(), false,
418 aThroughHoles );
419
420 dispLists = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
421 layer_z_top, layer_z_top );
422 }
423
424 delete layerTriangles;
425 }
426
427 return dispLists;
428}
429
430
431void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
432{
433 m_reloadRequested = false;
434
435 freeAllLists();
436
438
439 int64_t stats_startReloadTime = GetRunningMicroSecs();
440
441 m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
442
443 SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
444 m_camera.SetBoardLookAtPos( camera_pos );
445
446 if( aStatusReporter )
447 aStatusReporter->Report( _( "Load OpenGL: board" ) );
448
449 // Create Board
450 m_board = createBoard( m_boardAdapter.GetBoardPoly(), &m_boardAdapter.GetTH_IDs() );
451
452 m_antiBoardPolys.RemoveAllContours();
453 m_antiBoardPolys.NewOutline();
454 m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, -INT_MAX/2 ) );
455 m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, -INT_MAX/2 ) );
456 m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, INT_MAX/2 ) );
457 m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, INT_MAX/2 ) );
458 m_antiBoardPolys.Outline( 0 ).SetClosed( true );
459
460 m_antiBoardPolys.BooleanSubtract( m_boardAdapter.GetBoardPoly() );
462
463 SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly().CloneDropTriangulation();
464 board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
465
466 m_boardWithHoles = createBoard( board_poly_with_holes, &m_boardAdapter.GetTH_IDs() );
467
468 if( m_antiBoard )
469 m_antiBoard->SetItIsTransparent( true );
470
471 // Create Through Holes and vias
472 if( aStatusReporter )
473 aStatusReporter->Report( _( "Load OpenGL: holes and vias" ) );
474
475 SHAPE_POLY_SET outerPolyTHT = m_boardAdapter.GetTH_ODPolys().CloneDropTriangulation();
476
477 outerPolyTHT.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
478
479 m_outerThroughHoles = generateHoles( m_boardAdapter.GetTH_ODs().GetList(), outerPolyTHT,
480 1.0f, 0.0f, false, &m_boardAdapter.GetTH_IDs() );
481
482 m_outerViaThroughHoles = generateHoles( m_boardAdapter.GetViaTH_ODs().GetList(),
483 m_boardAdapter.GetViaTH_ODPolys(), 1.0f, 0.0f, false );
484
485 if( m_boardAdapter.m_Cfg->m_Render.clip_silk_on_via_annuli )
486 {
487 m_outerThroughHoleRings = generateHoles( m_boardAdapter.GetViaAnnuli().GetList(),
488 m_boardAdapter.GetViaAnnuliPolys(),
489 1.0f, 0.0f, false );
490 }
491
492 const MAP_POLY& innerMapHoles = m_boardAdapter.GetHoleIdPolysMap();
493 const MAP_POLY& outerMapHoles = m_boardAdapter.GetHoleOdPolysMap();
494
495 wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
496
497 const MAP_CONTAINER_2D_BASE& map_holes = m_boardAdapter.GetLayerHoleMap();
498
499 if( outerMapHoles.size() > 0 )
500 {
501 float layer_z_bot = 0.0f;
502 float layer_z_top = 0.0f;
503
504 for( const auto& [ layer, poly ] : outerMapHoles )
505 {
506 getLayerZPos( layer, layer_z_top, layer_z_bot );
507
508 m_outerLayerHoles[layer] = generateHoles( map_holes.at( layer )->GetList(), *poly,
509 layer_z_top, layer_z_bot, false );
510 }
511
512 for( const auto& [ layer, poly ] : innerMapHoles )
513 {
514 getLayerZPos( layer, layer_z_top, layer_z_bot );
515
516 m_innerLayerHoles[layer] = generateHoles( map_holes.at( layer )->GetList(), *poly,
517 layer_z_top, layer_z_bot, false );
518 }
519 }
520
521 // Generate vertical cylinders of vias and pads (copper)
523
524 // Add layers maps
525 if( aStatusReporter )
526 aStatusReporter->Report( _( "Load OpenGL: layers" ) );
527
528 std::bitset<LAYER_3D_END> visibilityFlags = m_boardAdapter.GetVisibleLayers();
529 const MAP_POLY& map_poly = m_boardAdapter.GetPolyMap();
530 wxString msg;
531
532 for( const auto& [ layer, container2d ] : m_boardAdapter.GetLayerMap() )
533 {
534 if( !m_boardAdapter.Is3dLayerEnabled( layer, visibilityFlags ) )
535 continue;
536
537 if( aStatusReporter )
538 {
539 msg = m_boardAdapter.GetBoard()->GetLayerName( layer );
540 aStatusReporter->Report( wxString::Format( _( "Load OpenGL layer %s" ), msg ) );
541 }
542
543 SHAPE_POLY_SET polyListSubtracted;
544 SHAPE_POLY_SET* polyList = nullptr;
545
546 // Load the vertical (Z axis) component of shapes
547
548 if( m_boardAdapter.m_Cfg->m_Render.opengl_copper_thickness )
549 {
550 if( map_poly.contains( layer ) )
551 {
552 polyListSubtracted = *map_poly.at( layer );
553
554 if( LSET::PhysicalLayersMask().test( layer ) )
555 {
556 polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
557 }
558
559 if( layer != B_Mask && layer != F_Mask )
560 {
561 polyListSubtracted.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
562 polyListSubtracted.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
563 }
564
565 if( m_boardAdapter.m_Cfg->m_Render.subtract_mask_from_silk )
566 {
567 if( layer == B_SilkS && map_poly.contains( B_Mask ) )
568 {
569 polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ) );
570 }
571 else if( layer == F_SilkS && map_poly.contains( F_Mask ) )
572 {
573 polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ) );
574 }
575 }
576
577 polyList = &polyListSubtracted;
578 }
579 }
580
581 OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, polyList, layer,
582 &m_boardAdapter.GetTH_IDs() );
583
584 if( oglList != nullptr )
585 m_layers[layer] = oglList;
586 }
587
588 if( m_boardAdapter.m_Cfg->m_Render.DifferentiatePlatedCopper() )
589 {
590 const SHAPE_POLY_SET* frontPlatedCopperPolys = m_boardAdapter.GetFrontPlatedCopperPolys();
591 const SHAPE_POLY_SET* backPlatedCopperPolys = m_boardAdapter.GetBackPlatedCopperPolys();
592
593 if( frontPlatedCopperPolys )
594 {
595 SHAPE_POLY_SET poly = frontPlatedCopperPolys->CloneDropTriangulation();
596 poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
597 poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
598 poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
599
600 m_platedPadsFront = generateLayerList( m_boardAdapter.GetPlatedPadsFront(), &poly,
601 F_Cu );
602
603 // An entry for F_Cu must exist in m_layers or we'll never look at m_platedPadsFront
604 if( m_layers.count( F_Cu ) == 0 )
606 }
607
608 if( backPlatedCopperPolys )
609 {
610 SHAPE_POLY_SET poly = backPlatedCopperPolys->CloneDropTriangulation();
611 poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
612 poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
613 poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
614
615 m_platedPadsBack = generateLayerList( m_boardAdapter.GetPlatedPadsBack(), &poly, B_Cu );
616
617 // An entry for B_Cu must exist in m_layers or we'll never look at m_platedPadsBack
618 if( m_layers.count( B_Cu ) == 0 )
620 }
621 }
622
623 if( m_boardAdapter.m_Cfg->m_Render.show_off_board_silk )
624 {
625 if( const BVH_CONTAINER_2D* padsFront = m_boardAdapter.GetOffboardPadsFront() )
626 m_offboardPadsFront = generateLayerList( padsFront, nullptr, F_Cu );
627
628 if( const BVH_CONTAINER_2D* padsBack = m_boardAdapter.GetOffboardPadsBack() )
629 m_offboardPadsBack = generateLayerList( padsBack, nullptr, B_Cu );
630 }
631
632 // Load 3D models
633 if( aStatusReporter )
634 aStatusReporter->Report( _( "Loading 3D models..." ) );
635
636 load3dModels( aStatusReporter );
637
638 if( aStatusReporter )
639 {
640 // Calculation time in seconds
641 double calculation_time = (double)( GetRunningMicroSecs() - stats_startReloadTime) / 1e6;
642
643 aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
644 }
645}
646
647
649 const SFVEC2F& v1, const SFVEC2F& v2, float top,
650 float bot )
651{
652 aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
653 SFVEC3F( v1.x, v1.y, bot ),
654 SFVEC3F( v2.x, v2.y, bot ) );
655
656 aDst->m_layer_top_triangles->AddTriangle( SFVEC3F( v2.x, v2.y, top ),
657 SFVEC3F( v1.x, v1.y, top ),
658 SFVEC3F( v0.x, v0.y, top ) );
659}
660
661
662void RENDER_3D_OPENGL::getLayerZPos( PCB_LAYER_ID aLayer, float& aOutZtop, float& aOutZbot ) const
663{
664 aOutZbot = m_boardAdapter.GetLayerBottomZPos( aLayer );
665 aOutZtop = m_boardAdapter.GetLayerTopZPos( aLayer );
666
667 if( aOutZtop < aOutZbot )
668 {
669 float tmpFloat = aOutZbot;
670 aOutZbot = aOutZtop;
671 aOutZtop = tmpFloat;
672 }
673}
674
675
676void RENDER_3D_OPENGL::generateCylinder( const SFVEC2F& aCenter, float aInnerRadius,
677 float aOuterRadius, float aZtop, float aZbot,
678 unsigned int aNr_sides_per_circle,
679 TRIANGLE_DISPLAY_LIST* aDstLayer )
680{
681 std::vector< SFVEC2F > innerContour;
682 std::vector< SFVEC2F > outerContour;
683
684 generateRing( aCenter, aInnerRadius, aOuterRadius, aNr_sides_per_circle, innerContour,
685 outerContour, false );
686
687 for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
688 {
689 const SFVEC2F& vi0 = innerContour[i + 0];
690 const SFVEC2F& vi1 = innerContour[i + 1];
691 const SFVEC2F& vo0 = outerContour[i + 0];
692 const SFVEC2F& vo1 = outerContour[i + 1];
693
694 aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
695 SFVEC3F( vi0.x, vi0.y, aZtop ),
696 SFVEC3F( vo0.x, vo0.y, aZtop ),
697 SFVEC3F( vo1.x, vo1.y, aZtop ) );
698
699 aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
700 SFVEC3F( vo1.x, vo1.y, aZbot ),
701 SFVEC3F( vo0.x, vo0.y, aZbot ),
702 SFVEC3F( vi0.x, vi0.y, aZbot ) );
703 }
704
705 aDstLayer->AddToMiddleContours( outerContour, aZbot, aZtop, true );
706 aDstLayer->AddToMiddleContours( innerContour, aZbot, aZtop, false );
707}
708
709
710void RENDER_3D_OPENGL::generateDisk( const SFVEC2F& aCenter, float aRadius, float aZ,
711 unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST* aDstLayer,
712 bool aTop )
713{
714 const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
715
716 for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
717 {
718 float a0 = delta * i;
719 float a1 = delta * ( i + 1 );
720 const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
721 aCenter.y + sinf( a0 ) * aRadius, aZ );
722 const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
723 aCenter.y + sinf( a1 ) * aRadius, aZ );
724 const SFVEC3F c( aCenter.x, aCenter.y, aZ );
725
726 if( aTop )
727 aDstLayer->m_layer_top_triangles->AddTriangle( p1, p0, c );
728 else
729 aDstLayer->m_layer_bot_triangles->AddTriangle( p0, p1, c );
730 }
731}
732
733
734void RENDER_3D_OPENGL::generateDimple( const SFVEC2F& aCenter, float aRadius, float aZ,
735 float aDepth, unsigned int aNr_sides_per_circle,
736 TRIANGLE_DISPLAY_LIST* aDstLayer, bool aTop )
737{
738 const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
739 const SFVEC3F c( aCenter.x, aCenter.y, aTop ? aZ - aDepth : aZ + aDepth );
740
741 for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
742 {
743 float a0 = delta * i;
744 float a1 = delta * ( i + 1 );
745 const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
746 aCenter.y + sinf( a0 ) * aRadius, aZ );
747 const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
748 aCenter.y + sinf( a1 ) * aRadius, aZ );
749
750 if( aTop )
751 aDstLayer->m_layer_top_triangles->AddTriangle( p0, p1, c );
752 else
753 aDstLayer->m_layer_bot_triangles->AddTriangle( p1, p0, c );
754 }
755}
756
757
759{
760 if( !m_boardAdapter.GetBoard() )
761 return;
762
763 const int platingThickness = m_boardAdapter.GetHolePlatingThickness();
764 const float platingThickness3d = platingThickness * m_boardAdapter.BiuTo3dUnits();
765
766 if( m_boardAdapter.GetViaCount() > 0 )
767 {
768 float averageDiameter = m_boardAdapter.GetAverageViaHoleDiameter();
769 unsigned int averageSegCount = m_boardAdapter.GetCircleSegmentCount( averageDiameter );
770 unsigned int trianglesEstimate = averageSegCount * 8 * m_boardAdapter.GetViaCount();
771
772 TRIANGLE_DISPLAY_LIST* layerTriangleVIA = new TRIANGLE_DISPLAY_LIST( trianglesEstimate );
773
774 // Insert plated vertical holes inside the board
775
776 // Insert vias holes (vertical cylinders)
777 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
778 {
779 if( track->Type() == PCB_VIA_T )
780 {
781 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
782
783 if( via->GetViaType() == VIATYPE::THROUGH )
784 continue; // handle with pad holes so castellation is taken into account
785
786 const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
787 const int nrSegments = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
788 const float hole_inner_radius = holediameter / 2.0f;
789
790 const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
791 -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
792
793 PCB_LAYER_ID top_layer, bottom_layer;
794 via->LayerPair( &top_layer, &bottom_layer );
795
796 float ztop, zbot, dummy;
797
798 getLayerZPos( top_layer, ztop, dummy );
799 getLayerZPos( bottom_layer, dummy, zbot );
800
801 wxASSERT( zbot < ztop );
802
803 if( m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
804 {
805 generateCylinder( via_center, hole_inner_radius, hole_inner_radius + platingThickness3d,
806 ztop, zbot, nrSegments, layerTriangleVIA );
807 }
808 }
809 }
810
811 m_microviaHoles = new OPENGL_RENDER_LIST( *layerTriangleVIA, 0, 0.0f, 0.0f );
812
813 delete layerTriangleVIA;
814 }
815
816
817 if( m_boardAdapter.GetHoleCount() > 0 || m_boardAdapter.GetViaCount() > 0 )
818 {
819 SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes
820 SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes
821
822 tht_outer_holes_poly.RemoveAllContours();
823 tht_inner_holes_poly.RemoveAllContours();
824
825 // Insert through-via holes (vertical cylinders)
826 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
827 {
828 if( track->Type() == PCB_VIA_T )
829 {
830 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
831
832 if( via->GetViaType() == VIATYPE::THROUGH )
833 {
834 TransformCircleToPolygon( tht_outer_holes_poly, via->GetPosition(),
835 via->GetDrill() / 2 + platingThickness,
836 via->GetMaxError(), ERROR_INSIDE );
837
838 TransformCircleToPolygon( tht_inner_holes_poly, via->GetPosition(), via->GetDrill() / 2,
839 via->GetMaxError(), ERROR_INSIDE );
840 }
841 }
842 }
843
844 // Insert pads holes (vertical cylinders)
845 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
846 {
847 for( const PAD* pad : footprint->Pads() )
848 {
849 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
850 {
851 if( !pad->HasHole() )
852 continue;
853
854 pad->TransformHoleToPolygon( tht_outer_holes_poly, platingThickness,
855 pad->GetMaxError(), ERROR_INSIDE );
856 pad->TransformHoleToPolygon( tht_inner_holes_poly, 0,
857 pad->GetMaxError(), ERROR_INSIDE );
858 }
859 }
860 }
861
862 // Subtract the holes
863 tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly );
864
865 tht_outer_holes_poly.BooleanSubtract( m_antiBoardPolys );
866
867 CONTAINER_2D holesContainer;
868
869 ConvertPolygonToTriangles( tht_outer_holes_poly, holesContainer,
870 m_boardAdapter.BiuTo3dUnits(), *m_boardAdapter.GetBoard() );
871
872 const LIST_OBJECT2D& holes2D = holesContainer.GetList();
873
874 if( holes2D.size() > 0 && m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
875 {
876 float layer_z_top, layer_z_bot, dummy;
877
878 getLayerZPos( F_Cu, layer_z_top, dummy );
879 getLayerZPos( B_Cu, dummy, layer_z_bot );
880
881 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( holes2D.size() );
882
883 // Convert the list of objects(triangles) to triangle layer structure
884 for( const OBJECT_2D* itemOnLayer : holes2D )
885 {
886 const OBJECT_2D* object2d_A = itemOnLayer;
887
888 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
889
890 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
891
892 const SFVEC2F& v1 = tri->GetP1();
893 const SFVEC2F& v2 = tri->GetP2();
894 const SFVEC2F& v3 = tri->GetP3();
895
896 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
897 }
898
899 wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
900
901 if( tht_outer_holes_poly.OutlineCount() > 0 )
902 {
903 layerTriangles->AddToMiddleContours( tht_outer_holes_poly,
904 layer_z_bot, layer_z_top,
905 m_boardAdapter.BiuTo3dUnits(), false );
906
907 m_padHoles = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
908 layer_z_top, layer_z_top );
909 }
910
911 delete layerTriangles;
912 }
913 }
914
915 TRIANGLE_DISPLAY_LIST* frontCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
916 TRIANGLE_DISPLAY_LIST* backCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
917
918 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
919 {
920 if( track->Type() != PCB_VIA_T )
921 continue;
922
923 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
924
925 const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
926 const float hole_radius = holediameter / 2.0f + 2.0 * platingThickness3d;
927 const SFVEC2F center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
928 -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
929 unsigned int seg = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
930
931 PCB_LAYER_ID top_layer, bottom_layer;
932 via->LayerPair( &top_layer, &bottom_layer );
933 float ztop, zbot, dummy;
934 getLayerZPos( top_layer, ztop, dummy );
935 getLayerZPos( bottom_layer, dummy, zbot );
936
937 bool frontCovering = via->GetFrontCoveringMode() == COVERING_MODE::COVERED || via->IsTented( F_Mask );
938 bool backCovering = via->GetBackCoveringMode() == COVERING_MODE::COVERED || via->IsTented( B_Mask );
939 bool frontPlugged = via->GetFrontPluggingMode() == PLUGGING_MODE::PLUGGED;
940 bool backPlugged = via->GetBackPluggingMode() == PLUGGING_MODE::PLUGGED;
941 bool filled = via->GetFillingMode() == FILLING_MODE::FILLED
942 || via->GetCappingMode() == CAPPING_MODE::CAPPED;
943
944 const float depth = hole_radius * 0.3f;
945
946 if( frontCovering )
947 {
948 if( filled || !frontPlugged )
949 generateDisk( center, hole_radius, ztop, seg, frontCover, true );
950 else
951 generateDimple( center, hole_radius, ztop, depth, seg, frontCover, true );
952 }
953
954 if( backCovering )
955 {
956 if( filled || !backPlugged )
957 generateDisk( center, hole_radius, zbot, seg, backCover, false );
958 else
959 generateDimple( center, hole_radius, zbot, depth, seg, backCover, false );
960 }
961 }
962
963 if( frontCover->m_layer_top_triangles->GetVertexSize() > 0 )
964 m_viaFrontCover = new OPENGL_RENDER_LIST( *frontCover, 0, 0.0f, 0.0f );
965
966 if( backCover->m_layer_bot_triangles->GetVertexSize() > 0 )
967 m_viaBackCover = new OPENGL_RENDER_LIST( *backCover, 0, 0.0f, 0.0f );
968
969 delete frontCover;
970 delete backCover;
971}
972
973
975{
976 if( m_3dModelMap.size() > 0 )
977 return;
978
979 if( wxFrame* frame = dynamic_cast<wxFrame*>( m_canvas->GetParent() ) )
980 {
981 STATUSBAR_REPORTER activityReporter( frame->GetStatusBar(),
983 load3dModels( &activityReporter );
984 }
985 else
986 {
987 load3dModels( nullptr );
988 }
989}
990
991
993{
994 if( !m_boardAdapter.GetBoard() )
995 return;
996
997 // Building the 3D models late crashes on recent versions of macOS
998 // Unclear the exact mechanism, but as a workaround, just build them
999 // all the time. See https://gitlab.com/kicad/code/kicad/-/issues/17198
1000#ifndef __WXMAC__
1001 if( !m_boardAdapter.m_IsPreviewer
1002 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
1003 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
1004 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
1005 {
1006 return;
1007 }
1008#endif
1009
1010 S3D_CACHE* cacheMgr = m_boardAdapter.Get3dCacheManager();
1011
1012 // Go for all footprints
1013 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1014 {
1015 wxString libraryName = footprint->GetFPID().GetLibNickname();
1016 wxString footprintBasePath = wxEmptyString;
1017
1018 if( m_boardAdapter.GetBoard()->GetProject() )
1019 {
1020 try
1021 {
1022 // FindRow() can throw an exception
1023 const FP_LIB_TABLE_ROW* fpRow =
1024 PROJECT_PCB::PcbFootprintLibs( m_boardAdapter.GetBoard()->GetProject() )
1025 ->FindRow( libraryName, false );
1026
1027 if( fpRow )
1028 footprintBasePath = fpRow->GetFullURI( true );
1029 }
1030 catch( ... )
1031 {
1032 // Do nothing if the libraryName is not found in lib table
1033 }
1034 }
1035
1036 for( const FP_3DMODEL& fp_model : footprint->Models() )
1037 {
1038 if( fp_model.m_Show && !fp_model.m_Filename.empty() )
1039 {
1040 if( aStatusReporter )
1041 {
1042 // Display the short filename of the 3D fp_model loaded:
1043 // (the full name is usually too long to be displayed)
1044 wxFileName fn( fp_model.m_Filename );
1045 aStatusReporter->Report( wxString::Format( _( "Loading %s..." ),
1046 fn.GetFullName() ) );
1047 }
1048
1049 // Check if the fp_model is not present in our cache map
1050 // (Not already loaded in memory)
1051 if( !m_3dModelMap.contains( fp_model.m_Filename ) )
1052 {
1053 // It is not present, try get it from cache
1054 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
1055 embeddedFilesStack.push_back( footprint->GetEmbeddedFiles() );
1056 embeddedFilesStack.push_back( m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
1057
1058 const S3DMODEL* modelPtr = cacheMgr->GetModel( fp_model.m_Filename, footprintBasePath,
1059 std::move( embeddedFilesStack ) );
1060
1061 // only add it if the return is not NULL
1062 if( modelPtr )
1063 {
1064 MATERIAL_MODE materialMode = m_boardAdapter.m_Cfg->m_Render.material_mode;
1065 MODEL_3D* model = new MODEL_3D( *modelPtr, materialMode );
1066
1067 m_3dModelMap[ fp_model.m_Filename ] = model;
1068 }
1069 }
1070 }
1071 }
1072 }
1073}
MATERIAL_MODE
Render 3d model shape materials mode.
Definition 3d_enums.h:71
Defines math related functions.
@ ERROR_INSIDE
std::map< PCB_LAYER_ID, SHAPE_POLY_SET * > MAP_POLY
A type that stores polysets for each layer id.
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.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
const LIST_OBJECT2D & GetList() const
const SFVEC2F & GetCenter() const
float GetRadius() const
Hold a record identifying a library accessed by the appropriate footprint library #PLUGIN object in t...
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:680
static OBJECT_2D_STATS & Instance()
Definition object_2d.h:137
void ResetStats()
Definition object_2d.h:122
OBJECT_2D_TYPE GetObjectType() const
Definition object_2d.h:107
Store the OpenGL display lists to related with a layer.
Definition pad.h:54
Simple non-intersecting polygon with 4 points.
const SFVEC2F & GetV3() const
const SFVEC2F & GetV0() const
const SFVEC2F & GetV1() const
const SFVEC2F & GetV2() const
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
OPENGL_RENDER_LIST * m_board
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
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)
void generateCylinder(const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, float aZtop, float aZbot, unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST *aDstLayer)
OPENGL_RENDER_LIST * m_outerThroughHoleRings
OPENGL_RENDER_LIST * m_offboardPadsFront
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)
SHAPE_POLY_SET m_antiBoardPolys
The negative polygon representation of the board outline.
void load3dModels(REPORTER *aStatusReporter)
Load footprint models from the cache and load it to openGL lists in the form of MODEL_3D objects.
OPENGL_RENDER_LIST * generateLayerList(const BVH_CONTAINER_2D *aContainer, const SHAPE_POLY_SET *aPolyList, PCB_LAYER_ID aLayer, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
OPENGL_RENDER_LIST * m_microviaHoles
OPENGL_RENDER_LIST * createBoard(const SHAPE_POLY_SET &aBoardPoly, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
void Load3dModelsIfNeeded()
Load footprint models if they are not already loaded, i.e.
void addObjectTriangles(const RING_2D *aRing, TRIANGLE_DISPLAY_LIST *aDstLayer, float aZtop, float aZbot)
MAP_OGL_DISP_LISTS m_layers
MAP_OGL_DISP_LISTS m_innerLayerHoles
OPENGL_RENDER_LIST * m_boardWithHoles
MAP_OGL_DISP_LISTS m_outerLayerHoles
OPENGL_RENDER_LIST * m_offboardPadsBack
std::map< wxString, MODEL_3D * > m_3dModelMap
OPENGL_RENDER_LIST * m_viaBackCover
OPENGL_RENDER_LIST * m_viaFrontCover
OPENGL_RENDER_LIST * generateEmptyLayerList(PCB_LAYER_ID aLayer)
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
OPENGL_RENDER_LIST * m_outerViaThroughHoles
OPENGL_RENDER_LIST * m_outerThroughHoles
OPENGL_RENDER_LIST * m_platedPadsFront
void generateDisk(const SFVEC2F &aCenter, float aRadius, float aZ, unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST *aDstLayer, bool aTop)
OPENGL_RENDER_LIST * m_antiBoard
void getLayerZPos(PCB_LAYER_ID aLayerID, float &aOutZtop, float &aOutZbot) const
EDA_3D_CANVAS * m_canvas
OPENGL_RENDER_LIST * m_padHoles
void addTopAndBottomTriangles(TRIANGLE_DISPLAY_LIST *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot)
OPENGL_RENDER_LIST * m_platedPadsBack
void generateDimple(const SFVEC2F &aCenter, float aRadius, float aZ, float aDepth, unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST *aDstLayer, bool aTop)
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
float GetOuterRadius() const
Definition ring_2d.h:48
float GetInnerRadius() const
Definition ring_2d.h:47
const SFVEC2F & GetCenter() const
Definition ring_2d.h:46
const SFVEC2F & GetLeftEnd() const
const SFVEC2F & GetRightEnd() const
const SFVEC2F & GetLeftStar() const
const SFVEC2F & GetLeftDir() const
const SFVEC2F & GetEnd() const
float GetRadius() const
float GetRadiusSquared() const
const SFVEC2F & GetStart() const
const SFVEC2F & GetRightDir() const
const SFVEC2F & GetRightStar() const
Cache for storing the 3D shapes.
Definition 3d_cache.h:55
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition 3d_cache.cpp:551
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
A wrapper for reporting to a specific text location in a statusbar.
Definition reporter.h:297
const SFVEC2F & GetP2() const
Definition triangle_2d.h:44
const SFVEC2F & GetP3() const
Definition triangle_2d.h:45
const SFVEC2F & GetP1() const
Definition triangle_2d.h:43
Store arrays of triangles to be used to create display lists.
TRIANGLE_LIST * m_layer_bot_segment_ends
void AddToMiddleContours(const SHAPE_LINE_CHAIN &outlinePath, float zBot, float zTop, double aBiuTo3Du, bool aInvertFaceDirection, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
TRIANGLE_LIST * m_layer_top_segment_ends
TRIANGLE_LIST * m_layer_bot_triangles
TRIANGLE_LIST * m_layer_top_triangles
void AddTriangle(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3)
void AddQuad(const SFVEC3F &aV1, const SFVEC3F &aV2, const SFVEC3F &aV3, const SFVEC3F &aV4)
unsigned int GetVertexSize() const
std::list< OBJECT_2D * > LIST_OBJECT2D
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
#define _(s)
Declaration of the eda_3d_viewer class.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ F_SilkS
Definition layer_ids.h:100
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:87
@ THROUGH
Definition pcb_track.h:68
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
#define SIZE_OF_CIRCLE_TEXTURE
std::vector< FAB_LAYER_COLOR > dummy
Store the a model based on meshes and materials.
Definition c3dmodel.h:95
VECTOR3I v1(5, 5, 5)
VECTOR2I center
int radius
VECTOR2I end
VECTOR2I v2(1, 0)
VECTOR2I v3(-2, 1)
int delta
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
glm::vec2 SFVEC2F
Definition xv3d_types.h:42
glm::vec3 SFVEC3F
Definition xv3d_types.h:44