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 TRIANGLE_DISPLAY_LIST* aDstLayer,
155 float aZtop, float aZbot )
156{
157 const SFVEC2F& v1 = aTri->GetP1();
158 const SFVEC2F& v2 = aTri->GetP2();
159 const SFVEC2F& v3 = aTri->GetP3();
160
161 addTopAndBottomTriangles( aDstLayer, v1, v2, v3, aZtop, aZbot );
162}
163
164
166 TRIANGLE_DISPLAY_LIST* aDstLayer,
167 float aZtop, float aZbot )
168{
169 const SFVEC2F& leftStart = aSeg->GetLeftStar();
170 const SFVEC2F& leftEnd = aSeg->GetLeftEnd();
171 const SFVEC2F& leftDir = aSeg->GetLeftDir();
172
173 const SFVEC2F& rightStart = aSeg->GetRightStar();
174 const SFVEC2F& rightEnd = aSeg->GetRightEnd();
175 const SFVEC2F& rightDir = aSeg->GetRightDir();
176 const float radius = aSeg->GetRadius();
177
178 const SFVEC2F& start = aSeg->GetStart();
179 const SFVEC2F& end = aSeg->GetEnd();
180
181 const float texture_factor = ( 12.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
182 const float texture_factorF = ( 6.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
183
184 const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
185 const float radius_triangle_factor = ( radius_of_the_square - radius ) / radius;
186
187 const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
188 rightDir.x * radius * radius_triangle_factor );
189
190 const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
191 leftDir.x * radius * radius_triangle_factor );
192
193 // Top end segment triangles (semi-circles)
195 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
196 rightEnd.y + texture_factor * factorS.y,
197 aZtop ),
198 SFVEC3F( leftStart.x + texture_factor * factorE.x,
199 leftStart.y + texture_factor * factorE.y,
200 aZtop ),
201 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
202 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
203 aZtop ) );
204
206 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
207 leftEnd.y + texture_factor * factorE.y, aZtop ),
208 SFVEC3F( rightStart.x + texture_factor * factorS.x,
209 rightStart.y + texture_factor * factorS.y, aZtop ),
210 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
211 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
212 aZtop ) );
213
214 // Bot end segment triangles (semi-circles)
216 SFVEC3F( leftStart.x + texture_factor * factorE.x,
217 leftStart.y + texture_factor * factorE.y,
218 aZbot ),
219 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
220 rightEnd.y + texture_factor * factorS.y,
221 aZbot ),
222 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
223 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
224 aZbot ) );
225
227 SFVEC3F( rightStart.x + texture_factor * factorS.x,
228 rightStart.y + texture_factor * factorS.y, aZbot ),
229 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
230 leftEnd.y + texture_factor * factorE.y, aZbot ),
231 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
232 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
233 aZbot ) );
234
235 // Segment top and bot planes
236 aDstLayer->m_layer_top_triangles->AddQuad(
237 SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
238 SFVEC3F( rightStart.x, rightStart.y, aZtop ),
239 SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
240 SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
241
242 aDstLayer->m_layer_bot_triangles->AddQuad(
243 SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
244 SFVEC3F( leftStart.x, leftStart.y, aZbot ),
245 SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
246 SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
247}
248
249
251 const SHAPE_POLY_SET& aPoly, float aZtop,
252 float aZbot, bool aInvertFaces,
253 const BVH_CONTAINER_2D* aThroughHoles )
254{
255 OPENGL_RENDER_LIST* ret = nullptr;
256
257 if( aListHolesObject2d.size() > 0 )
258 {
259 TRIANGLE_DISPLAY_LIST* layerTriangles =
260 new TRIANGLE_DISPLAY_LIST( aListHolesObject2d.size() * 2 );
261
262 // Convert the list of objects(filled circles) to triangle layer structure
263 for( const OBJECT_2D* itemOnLayer : aListHolesObject2d )
264 {
265 const OBJECT_2D* object2d_A = itemOnLayer;
266
267 wxASSERT( ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::FILLED_CIRCLE )
268 || ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::ROUNDSEG ) );
269
270 switch( object2d_A->GetObjectType() )
271 {
273 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d_A ),
274 layerTriangles, aZtop, aZbot );
275 break;
276
278 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d_A ),
279 layerTriangles, aZtop, aZbot );
280 break;
281
282 default:
283 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL::generateHoles: Object type not implemented" ) );
284 break;
285 }
286 }
287
288 // Note: he can have a aListHolesObject2d with holes but without contours
289 // eg: when there are only NPTH on the list and the contours were not added
290 if( aPoly.OutlineCount() > 0 )
291 {
292 layerTriangles->AddToMiddleContourns( aPoly, aZbot, aZtop,
293 m_boardAdapter.BiuTo3dUnits(),
294 aInvertFaces, aThroughHoles );
295 }
296
297 ret = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, aZbot, aZtop );
298
299 delete layerTriangles;
300 }
301
302 return ret;
303}
304
305
307 const SHAPE_POLY_SET* aPolyList,
308 PCB_LAYER_ID aLayer,
309 const BVH_CONTAINER_2D* aThroughHoles )
310{
311 if( aContainer == nullptr )
312 return nullptr;
313
314 const LIST_OBJECT2D& listObject2d = aContainer->GetList();
315
316 if( listObject2d.size() == 0 )
317 return nullptr;
318
319 float layer_z_bot = 0.0f;
320 float layer_z_top = 0.0f;
321
322 getLayerZPos( aLayer, layer_z_top, layer_z_bot );
323
324 // Calculate an estimation for the nr of triangles based on the nr of objects
325 unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
326
327 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( nrTrianglesEstimation );
328
329 // store in a list so it will be latter deleted
330 m_triangles.push_back( layerTriangles );
331
332 // Load the 2D (X,Y axis) component of shapes
333 for( const OBJECT_2D* itemOnLayer : listObject2d )
334 {
335 const OBJECT_2D* object2d_A = itemOnLayer;
336
337 switch( object2d_A->GetObjectType() )
338 {
340 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d_A ),
341 layerTriangles, layer_z_top, layer_z_bot );
342 break;
343
345 addObjectTriangles( static_cast<const POLYGON_4PT_2D*>( object2d_A ),
346 layerTriangles, layer_z_top, layer_z_bot );
347 break;
348
350 addObjectTriangles( static_cast<const RING_2D*>( object2d_A ),
351 layerTriangles, layer_z_top, layer_z_bot );
352 break;
353
355 addObjectTriangles( static_cast<const TRIANGLE_2D*>( object2d_A ),
356 layerTriangles, layer_z_top, layer_z_bot );
357 break;
358
360 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d_A ),
361 layerTriangles, layer_z_top, layer_z_bot );
362 break;
363
364 default:
365 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL: Object type is not implemented" ) );
366 break;
367 }
368 }
369
370 if( aPolyList && aPolyList->OutlineCount() > 0 )
371 {
372 layerTriangles->AddToMiddleContourns( *aPolyList, layer_z_bot, layer_z_top,
373 m_boardAdapter.BiuTo3dUnits(), false, aThroughHoles );
374 }
375
376 // Create display list
377 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
378}
379
380
382{
383 float layer_z_bot = 0.0f;
384 float layer_z_top = 0.0f;
385
386 getLayerZPos( aLayer, layer_z_top, layer_z_bot );
387
388 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( 1 );
389
390 // store in a list so it will be latter deleted
391 m_triangles.push_back( layerTriangles );
392
393 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
394}
395
396
398 const BVH_CONTAINER_2D* aThroughHoles )
399{
400 OPENGL_RENDER_LIST* dispLists = nullptr;
401 CONTAINER_2D boardContainer;
402
403 ConvertPolygonToTriangles( aBoardPoly, boardContainer, m_boardAdapter.BiuTo3dUnits(),
404 (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
405
406 const LIST_OBJECT2D& listBoardObject2d = boardContainer.GetList();
407
408 if( listBoardObject2d.size() > 0 )
409 {
410 // We will set a unitary Z so it will in future used with transformations since the
411 // board poly will be used not only to draw itself but also the solder mask layers.
412 const float layer_z_top = 1.0f;
413 const float layer_z_bot = 0.0f;
414
415 TRIANGLE_DISPLAY_LIST* layerTriangles =
416 new TRIANGLE_DISPLAY_LIST( listBoardObject2d.size() );
417
418 // Convert the list of objects(triangles) to triangle layer structure
419 for( const OBJECT_2D* itemOnLayer : listBoardObject2d )
420 {
421 const OBJECT_2D* object2d_A = itemOnLayer;
422
423 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
424
425 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
426
427 const SFVEC2F& v1 = tri->GetP1();
428 const SFVEC2F& v2 = tri->GetP2();
429 const SFVEC2F& v3 = tri->GetP3();
430
431 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
432 }
433
434 if( aBoardPoly.OutlineCount() > 0 )
435 {
436 layerTriangles->AddToMiddleContourns( aBoardPoly, layer_z_bot, layer_z_top,
437 m_boardAdapter.BiuTo3dUnits(), false,
438 aThroughHoles );
439
440 dispLists = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
441 layer_z_top, layer_z_top );
442 }
443
444 delete layerTriangles;
445 }
446
447 return dispLists;
448}
449
450
451void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
452{
453 m_reloadRequested = false;
454
455 freeAllLists();
456
458
459 int64_t stats_startReloadTime = GetRunningMicroSecs();
460
461 m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
462
463 SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
464 m_camera.SetBoardLookAtPos( camera_pos );
465
466 if( aStatusReporter )
467 aStatusReporter->Report( _( "Load OpenGL: board" ) );
468
469 // Create Board
470 m_board = createBoard( m_boardAdapter.GetBoardPoly(), &m_boardAdapter.GetTH_IDs() );
471
472 m_antiBoardPolys.RemoveAllContours();
473 m_antiBoardPolys.NewOutline();
474 m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, -INT_MAX/2 ) );
475 m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, -INT_MAX/2 ) );
476 m_antiBoardPolys.Append( VECTOR2I( INT_MAX/2, INT_MAX/2 ) );
477 m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, INT_MAX/2 ) );
478 m_antiBoardPolys.Outline( 0 ).SetClosed( true );
479
480 m_antiBoardPolys.BooleanSubtract( m_boardAdapter.GetBoardPoly() );
482
483 SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly().CloneDropTriangulation();
484 board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
485
486 m_boardWithHoles = createBoard( board_poly_with_holes, &m_boardAdapter.GetTH_IDs() );
487
488 if( m_antiBoard )
489 m_antiBoard->SetItIsTransparent( true );
490
491 // Create Through Holes and vias
492 if( aStatusReporter )
493 aStatusReporter->Report( _( "Load OpenGL: holes and vias" ) );
494
495 SHAPE_POLY_SET outerPolyTHT = m_boardAdapter.GetTH_ODPolys().CloneDropTriangulation();
496
497 outerPolyTHT.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
498
499 m_outerThroughHoles = generateHoles( m_boardAdapter.GetTH_ODs().GetList(), outerPolyTHT,
500 1.0f, 0.0f, false, &m_boardAdapter.GetTH_IDs() );
501
502 m_outerViaThroughHoles = generateHoles( m_boardAdapter.GetViaTH_ODs().GetList(),
503 m_boardAdapter.GetViaTH_ODPolys(), 1.0f, 0.0f, false );
504
505 if( m_boardAdapter.m_Cfg->m_Render.clip_silk_on_via_annuli )
506 {
507 m_outerThroughHoleRings = generateHoles( m_boardAdapter.GetViaAnnuli().GetList(),
508 m_boardAdapter.GetViaAnnuliPolys(),
509 1.0f, 0.0f, false );
510 }
511
512 const MAP_POLY& innerMapHoles = m_boardAdapter.GetHoleIdPolysMap();
513 const MAP_POLY& outerMapHoles = m_boardAdapter.GetHoleOdPolysMap();
514
515 wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
516
517 const MAP_CONTAINER_2D_BASE& map_holes = m_boardAdapter.GetLayerHoleMap();
518
519 if( outerMapHoles.size() > 0 )
520 {
521 float layer_z_bot = 0.0f;
522 float layer_z_top = 0.0f;
523
524 for( const auto& [ layer, poly ] : outerMapHoles )
525 {
526 getLayerZPos( layer, layer_z_top, layer_z_bot );
527
528 m_outerLayerHoles[layer] = generateHoles( map_holes.at( layer )->GetList(), *poly,
529 layer_z_top, layer_z_bot, false );
530 }
531
532 for( const auto& [ layer, poly ] : innerMapHoles )
533 {
534 getLayerZPos( layer, layer_z_top, layer_z_bot );
535
536 m_innerLayerHoles[layer] = generateHoles( map_holes.at( layer )->GetList(), *poly,
537 layer_z_top, layer_z_bot, false );
538 }
539 }
540
541 // Generate vertical cylinders of vias and pads (copper)
543
544 // Add layers maps
545 if( aStatusReporter )
546 aStatusReporter->Report( _( "Load OpenGL: layers" ) );
547
548 std::bitset<LAYER_3D_END> visibilityFlags = m_boardAdapter.GetVisibleLayers();
549 const MAP_POLY& map_poly = m_boardAdapter.GetPolyMap();
550 wxString msg;
551
552 for( const auto& [ layer, container2d ] : m_boardAdapter.GetLayerMap() )
553 {
554 if( !m_boardAdapter.Is3dLayerEnabled( layer, visibilityFlags ) )
555 continue;
556
557 if( aStatusReporter )
558 {
559 msg = m_boardAdapter.GetBoard()->GetLayerName( layer );
560 aStatusReporter->Report( wxString::Format( _( "Load OpenGL layer %s" ), msg ) );
561 }
562
563 SHAPE_POLY_SET polyListSubtracted;
564 SHAPE_POLY_SET* polyList = nullptr;
565
566 // Load the vertical (Z axis) component of shapes
567
568 if( m_boardAdapter.m_Cfg->m_Render.opengl_copper_thickness )
569 {
570 if( map_poly.contains( layer ) )
571 {
572 polyListSubtracted = *map_poly.at( layer );
573
574 if( LSET::PhysicalLayersMask().test( layer ) )
575 {
576 polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
577 }
578
579 if( layer != B_Mask && layer != F_Mask )
580 {
581 polyListSubtracted.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
582 polyListSubtracted.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
583 }
584
585 if( m_boardAdapter.m_Cfg->m_Render.subtract_mask_from_silk )
586 {
587 if( layer == B_SilkS && map_poly.contains( B_Mask ) )
588 {
589 polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ) );
590 }
591 else if( layer == F_SilkS && map_poly.contains( F_Mask ) )
592 {
593 polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ) );
594 }
595 }
596
597 polyList = &polyListSubtracted;
598 }
599 }
600
601 OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, polyList, layer,
602 &m_boardAdapter.GetTH_IDs() );
603
604 if( oglList != nullptr )
605 m_layers[layer] = oglList;
606 }
607
608 if( m_boardAdapter.m_Cfg->m_Render.DifferentiatePlatedCopper() )
609 {
610 const SHAPE_POLY_SET* frontPlatedCopperPolys = m_boardAdapter.GetFrontPlatedCopperPolys();
611 const SHAPE_POLY_SET* backPlatedCopperPolys = m_boardAdapter.GetBackPlatedCopperPolys();
612
613 if( frontPlatedCopperPolys )
614 {
615 SHAPE_POLY_SET poly = frontPlatedCopperPolys->CloneDropTriangulation();
616 poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
617 poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
618 poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
619
620 m_platedPadsFront = generateLayerList( m_boardAdapter.GetPlatedPadsFront(), &poly,
621 F_Cu );
622
623 // An entry for F_Cu must exist in m_layers or we'll never look at m_platedPadsFront
624 if( m_layers.count( F_Cu ) == 0 )
626 }
627
628 if( backPlatedCopperPolys )
629 {
630 SHAPE_POLY_SET poly = backPlatedCopperPolys->CloneDropTriangulation();
631 poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
632 poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
633 poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
634
635 m_platedPadsBack = generateLayerList( m_boardAdapter.GetPlatedPadsBack(), &poly, B_Cu );
636
637 // An entry for B_Cu must exist in m_layers or we'll never look at m_platedPadsBack
638 if( m_layers.count( B_Cu ) == 0 )
640 }
641 }
642
643 if( m_boardAdapter.m_Cfg->m_Render.show_off_board_silk )
644 {
645 if( const BVH_CONTAINER_2D* padsFront = m_boardAdapter.GetOffboardPadsFront() )
646 m_offboardPadsFront = generateLayerList( padsFront, nullptr, F_Cu );
647
648 if( const BVH_CONTAINER_2D* padsBack = m_boardAdapter.GetOffboardPadsBack() )
649 m_offboardPadsBack = generateLayerList( padsBack, nullptr, B_Cu );
650 }
651
652 // Load 3D models
653 if( aStatusReporter )
654 aStatusReporter->Report( _( "Loading 3D models..." ) );
655
656 load3dModels( aStatusReporter );
657
658 if( aStatusReporter )
659 {
660 // Calculation time in seconds
661 double calculation_time = (double)( GetRunningMicroSecs() - 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, float top,
670 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
682void RENDER_3D_OPENGL::getLayerZPos( PCB_LAYER_ID aLayer, float& aOutZtop, float& aOutZbot ) const
683{
684 aOutZbot = m_boardAdapter.GetLayerBottomZPos( aLayer );
685 aOutZtop = m_boardAdapter.GetLayerTopZPos( aLayer );
686
687 if( aOutZtop < aOutZbot )
688 {
689 float tmpFloat = aOutZbot;
690 aOutZbot = aOutZtop;
691 aOutZtop = tmpFloat;
692 }
693}
694
695
696void RENDER_3D_OPENGL::generateCylinder( const SFVEC2F& aCenter, float aInnerRadius,
697 float aOuterRadius, float aZtop, float aZbot,
698 unsigned int aNr_sides_per_circle,
699 TRIANGLE_DISPLAY_LIST* aDstLayer )
700{
701 std::vector< SFVEC2F > innerContour;
702 std::vector< SFVEC2F > outerContour;
703
704 generateRing( aCenter, aInnerRadius, aOuterRadius, aNr_sides_per_circle, innerContour,
705 outerContour, false );
706
707 for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
708 {
709 const SFVEC2F& vi0 = innerContour[i + 0];
710 const SFVEC2F& vi1 = innerContour[i + 1];
711 const SFVEC2F& vo0 = outerContour[i + 0];
712 const SFVEC2F& vo1 = outerContour[i + 1];
713
714 aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
715 SFVEC3F( vi0.x, vi0.y, aZtop ),
716 SFVEC3F( vo0.x, vo0.y, aZtop ),
717 SFVEC3F( vo1.x, vo1.y, aZtop ) );
718
719 aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
720 SFVEC3F( vo1.x, vo1.y, aZbot ),
721 SFVEC3F( vo0.x, vo0.y, aZbot ),
722 SFVEC3F( vi0.x, vi0.y, aZbot ) );
723 }
724
725 aDstLayer->AddToMiddleContourns( outerContour, aZbot, aZtop, true );
726 aDstLayer->AddToMiddleContourns( innerContour, aZbot, aZtop, false );
727}
728
729
730void RENDER_3D_OPENGL::generateDisk( const SFVEC2F& aCenter, float aRadius, float aZ,
731 unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST* aDstLayer,
732 bool aTop )
733{
734 const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
735
736 for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
737 {
738 float a0 = delta * i;
739 float a1 = delta * ( i + 1 );
740 const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
741 aCenter.y + sinf( a0 ) * aRadius, aZ );
742 const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
743 aCenter.y + sinf( a1 ) * aRadius, aZ );
744 const SFVEC3F c( aCenter.x, aCenter.y, aZ );
745
746 if( aTop )
747 aDstLayer->m_layer_top_triangles->AddTriangle( p1, p0, c );
748 else
749 aDstLayer->m_layer_bot_triangles->AddTriangle( p0, p1, c );
750 }
751}
752
753
754void RENDER_3D_OPENGL::generateDimple( const SFVEC2F& aCenter, float aRadius, float aZ,
755 float aDepth, unsigned int aNr_sides_per_circle,
756 TRIANGLE_DISPLAY_LIST* aDstLayer, bool aTop )
757{
758 const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
759 const SFVEC3F c( aCenter.x, aCenter.y, aTop ? aZ - aDepth : aZ + aDepth );
760
761 for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
762 {
763 float a0 = delta * i;
764 float a1 = delta * ( i + 1 );
765 const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
766 aCenter.y + sinf( a0 ) * aRadius, aZ );
767 const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
768 aCenter.y + sinf( a1 ) * aRadius, aZ );
769
770 if( aTop )
771 aDstLayer->m_layer_top_triangles->AddTriangle( p0, p1, c );
772 else
773 aDstLayer->m_layer_bot_triangles->AddTriangle( p1, p0, c );
774 }
775}
776
777
779{
780 if( !m_boardAdapter.GetBoard() )
781 return;
782
783 const int platingThickness = m_boardAdapter.GetHolePlatingThickness();
784 const float platingThickness3d = platingThickness * m_boardAdapter.BiuTo3dUnits();
785
786 if( m_boardAdapter.GetViaCount() > 0 )
787 {
788 float averageDiameter = m_boardAdapter.GetAverageViaHoleDiameter();
789 unsigned int averageSegCount = m_boardAdapter.GetCircleSegmentCount( averageDiameter );
790 unsigned int trianglesEstimate = averageSegCount * 8 * m_boardAdapter.GetViaCount();
791
792 TRIANGLE_DISPLAY_LIST* layerTriangleVIA = new TRIANGLE_DISPLAY_LIST( trianglesEstimate );
793
794 // Insert plated vertical holes inside the board
795
796 // Insert vias holes (vertical cylinders)
797 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
798 {
799 if( track->Type() == PCB_VIA_T )
800 {
801 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
802
803 if( via->GetViaType() == VIATYPE::THROUGH )
804 continue; // handle with pad holes so castellation is taken into account
805
806 const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
807 const int nrSegments = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
808 const float hole_inner_radius = holediameter / 2.0f;
809
810 const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
811 -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
812
813 PCB_LAYER_ID top_layer, bottom_layer;
814 via->LayerPair( &top_layer, &bottom_layer );
815
816 float ztop, zbot, dummy;
817
818 getLayerZPos( top_layer, ztop, dummy );
819 getLayerZPos( bottom_layer, dummy, zbot );
820
821 wxASSERT( zbot < ztop );
822
823 if( m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
824 {
825 generateCylinder( via_center, hole_inner_radius, hole_inner_radius + platingThickness3d,
826 ztop, zbot, nrSegments, layerTriangleVIA );
827 }
828 }
829 }
830
831 m_microviaHoles = new OPENGL_RENDER_LIST( *layerTriangleVIA, 0, 0.0f, 0.0f );
832
833 delete layerTriangleVIA;
834 }
835
836
837 if( m_boardAdapter.GetHoleCount() > 0 || m_boardAdapter.GetViaCount() > 0 )
838 {
839 SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes
840 SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes
841
842 tht_outer_holes_poly.RemoveAllContours();
843 tht_inner_holes_poly.RemoveAllContours();
844
845 // Insert through-via holes (vertical cylinders)
846 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
847 {
848 if( track->Type() == PCB_VIA_T )
849 {
850 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
851
852 if( via->GetViaType() == VIATYPE::THROUGH )
853 {
854 TransformCircleToPolygon( tht_outer_holes_poly, via->GetPosition(),
855 via->GetDrill() / 2 + platingThickness,
856 via->GetMaxError(), ERROR_INSIDE );
857
858 TransformCircleToPolygon( tht_inner_holes_poly, via->GetPosition(), via->GetDrill() / 2,
859 via->GetMaxError(), ERROR_INSIDE );
860 }
861 }
862 }
863
864 // Insert pads holes (vertical cylinders)
865 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
866 {
867 for( const PAD* pad : footprint->Pads() )
868 {
869 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
870 {
871 if( !pad->HasHole() )
872 continue;
873
874 pad->TransformHoleToPolygon( tht_outer_holes_poly, platingThickness,
875 pad->GetMaxError(), ERROR_INSIDE );
876 pad->TransformHoleToPolygon( tht_inner_holes_poly, 0,
877 pad->GetMaxError(), ERROR_INSIDE );
878 }
879 }
880 }
881
882 // Subtract the holes
883 tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly );
884
885 tht_outer_holes_poly.BooleanSubtract( m_antiBoardPolys );
886
887 CONTAINER_2D holesContainer;
888
889 ConvertPolygonToTriangles( tht_outer_holes_poly, holesContainer,
890 m_boardAdapter.BiuTo3dUnits(), *m_boardAdapter.GetBoard() );
891
892 const LIST_OBJECT2D& holes2D = holesContainer.GetList();
893
894 if( holes2D.size() > 0 && m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
895 {
896 float layer_z_top, layer_z_bot, dummy;
897
898 getLayerZPos( F_Cu, layer_z_top, dummy );
899 getLayerZPos( B_Cu, dummy, layer_z_bot );
900
901 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( holes2D.size() );
902
903 // Convert the list of objects(triangles) to triangle layer structure
904 for( const OBJECT_2D* itemOnLayer : holes2D )
905 {
906 const OBJECT_2D* object2d_A = itemOnLayer;
907
908 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
909
910 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
911
912 const SFVEC2F& v1 = tri->GetP1();
913 const SFVEC2F& v2 = tri->GetP2();
914 const SFVEC2F& v3 = tri->GetP3();
915
916 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
917 }
918
919 wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
920
921 if( tht_outer_holes_poly.OutlineCount() > 0 )
922 {
923 layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
924 layer_z_bot, layer_z_top,
925 m_boardAdapter.BiuTo3dUnits(), false );
926
927 m_padHoles = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
928 layer_z_top, layer_z_top );
929 }
930
931 delete layerTriangles;
932 }
933 }
934
935 TRIANGLE_DISPLAY_LIST* frontCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
936 TRIANGLE_DISPLAY_LIST* backCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
937
938 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
939 {
940 if( track->Type() != PCB_VIA_T )
941 continue;
942
943 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
944
945 const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
946 const float hole_radius = holediameter / 2.0f + 2.0 * platingThickness3d;
947 const SFVEC2F center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
948 -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
949 unsigned int seg = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
950
951 PCB_LAYER_ID top_layer, bottom_layer;
952 via->LayerPair( &top_layer, &bottom_layer );
953 float ztop, zbot, dummy;
954 getLayerZPos( top_layer, ztop, dummy );
955 getLayerZPos( bottom_layer, dummy, zbot );
956
957 bool frontCovering = via->GetFrontCoveringMode() == COVERING_MODE::COVERED || via->IsTented( F_Mask );
958 bool backCovering = via->GetBackCoveringMode() == COVERING_MODE::COVERED || via->IsTented( B_Mask );
959 bool frontPlugged = via->GetFrontPluggingMode() == PLUGGING_MODE::PLUGGED;
960 bool backPlugged = via->GetBackPluggingMode() == PLUGGING_MODE::PLUGGED;
961 bool filled = via->GetFillingMode() == FILLING_MODE::FILLED
962 || via->GetCappingMode() == CAPPING_MODE::CAPPED;
963
964 const float depth = hole_radius * 0.3f;
965
966 if( frontCovering )
967 {
968 if( filled || !frontPlugged )
969 generateDisk( center, hole_radius, ztop, seg, frontCover, true );
970 else
971 generateDimple( center, hole_radius, ztop, depth, seg, frontCover, true );
972 }
973
974 if( backCovering )
975 {
976 if( filled || !backPlugged )
977 generateDisk( center, hole_radius, zbot, seg, backCover, false );
978 else
979 generateDimple( center, hole_radius, zbot, depth, seg, backCover, false );
980 }
981 }
982
983 if( frontCover->m_layer_top_triangles->GetVertexSize() > 0 )
984 m_viaFrontCover = new OPENGL_RENDER_LIST( *frontCover, 0, 0.0f, 0.0f );
985
986 if( backCover->m_layer_bot_triangles->GetVertexSize() > 0 )
987 m_viaBackCover = new OPENGL_RENDER_LIST( *backCover, 0, 0.0f, 0.0f );
988
989 delete frontCover;
990 delete backCover;
991}
992
993
995{
996 if( m_3dModelMap.size() > 0 )
997 return;
998
999 if( wxFrame* frame = dynamic_cast<wxFrame*>( m_canvas->GetParent() ) )
1000 {
1001 STATUSBAR_REPORTER activityReporter( frame->GetStatusBar(),
1003 load3dModels( &activityReporter );
1004 }
1005 else
1006 {
1007 load3dModels( nullptr );
1008 }
1009}
1010
1011
1013{
1014 if( !m_boardAdapter.GetBoard() )
1015 return;
1016
1017 // Building the 3D models late crashes on recent versions of macOS
1018 // Unclear the exact mechanism, but as a workaround, just build them
1019 // all the time. See https://gitlab.com/kicad/code/kicad/-/issues/17198
1020#ifndef __WXMAC__
1021 if( !m_boardAdapter.m_IsPreviewer
1022 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
1023 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
1024 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
1025 {
1026 return;
1027 }
1028#endif
1029
1030 // Go for all footprints
1031 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1032 {
1033 wxString libraryName = footprint->GetFPID().GetLibNickname();
1034 wxString footprintBasePath = wxEmptyString;
1035
1036 if( m_boardAdapter.GetBoard()->GetProject() )
1037 {
1038 try
1039 {
1040 // FindRow() can throw an exception
1041 const FP_LIB_TABLE_ROW* fpRow =
1042 PROJECT_PCB::PcbFootprintLibs( m_boardAdapter.GetBoard()->GetProject() )
1043 ->FindRow( libraryName, false );
1044
1045 if( fpRow )
1046 footprintBasePath = fpRow->GetFullURI( true );
1047 }
1048 catch( ... )
1049 {
1050 // Do nothing if the libraryName is not found in lib table
1051 }
1052 }
1053
1054 for( const FP_3DMODEL& fp_model : footprint->Models() )
1055 {
1056 if( fp_model.m_Show && !fp_model.m_Filename.empty() )
1057 {
1058 if( aStatusReporter )
1059 {
1060 // Display the short filename of the 3D fp_model loaded:
1061 // (the full name is usually too long to be displayed)
1062 wxFileName fn( fp_model.m_Filename );
1063 aStatusReporter->Report( wxString::Format( _( "Loading %s..." ),
1064 fn.GetFullName() ) );
1065 }
1066
1067 // Check if the fp_model is not present in our cache map
1068 // (Not already loaded in memory)
1069 if( !m_3dModelMap.contains( fp_model.m_Filename ) )
1070 {
1071 // It is not present, try get it from cache
1072 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
1073 embeddedFilesStack.push_back( footprint->GetEmbeddedFiles() );
1074 embeddedFilesStack.push_back( m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
1075
1076 const S3DMODEL* modelPtr = m_boardAdapter.Get3dCacheManager()->GetModel( fp_model.m_Filename,
1077 footprintBasePath,
1078 embeddedFilesStack );
1079
1080 // only add it if the return is not NULL
1081 if( modelPtr )
1082 {
1083 MATERIAL_MODE materialMode = m_boardAdapter.m_Cfg->m_Render.material_mode;
1084 MODEL_3D* model = new MODEL_3D( *modelPtr, materialMode );
1085
1086 m_3dModelMap[ fp_model.m_Filename ] = model;
1087 }
1088 }
1089 }
1090 }
1091 }
1092}
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
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
TRIANGLE_LIST * m_layer_top_segment_ends
TRIANGLE_LIST * m_layer_bot_triangles
TRIANGLE_LIST * m_layer_top_triangles
void AddToMiddleContourns(const SHAPE_LINE_CHAIN &outlinePath, float zBot, float zTop, double aBiuTo3Du, bool aInvertFaceDirection, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
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:67
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