KiCad PCB EDA Suite
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) 2015-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "render_3d_opengl.h"
26#include "opengl_utils.h"
27#include <board.h>
28#include <footprint.h>
29#include "../../3d_math.h"
30#include <trigo.h>
31#include <project.h>
32#include <profile.h> // To use GetRunningMicroSecs or another profiling utility
33#include <fp_lib_table.h>
34#include <eda_3d_canvas.h>
35#include <eda_3d_viewer_frame.h>
36
37
39 TRIANGLE_DISPLAY_LIST* aDstLayer, float aZtop,
40 float aZbot )
41{
42 const SFVEC2F& center = aFilledCircle->GetCenter();
43 const float radius = aFilledCircle->GetRadius() * 2.0f; // Double because the render triangle
44
45 // This is a small adjustment to the circle texture
46 const float texture_factor = ( 8.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
47 const float f = ( sqrtf( 2.0f ) / 2.0f ) * radius * texture_factor;
48
49 // Top and Bot segments ends are just triangle semi-circles, so need to add it in duplicated.
50 aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZtop ),
51 SFVEC3F( center.x - f, center.y, aZtop ),
52 SFVEC3F( center.x, center.y - f, aZtop ) );
53
54 aDstLayer->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZtop ),
55 SFVEC3F( center.x + f, center.y, aZtop ),
56 SFVEC3F( center.x, center.y + f, aZtop ) );
57
58 aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, aZbot ),
59 SFVEC3F( center.x + f, center.y, aZbot ),
60 SFVEC3F( center.x, center.y - f, aZbot ) );
61
62 aDstLayer->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, aZbot ),
63 SFVEC3F( center.x - f, center.y, aZbot ),
64 SFVEC3F( center.x, center.y + f, aZbot ) );
65}
66
67
69 TRIANGLE_DISPLAY_LIST* aDstLayer,
70 float aZtop, float aZbot )
71{
72 const SFVEC2F& v0 = aPoly->GetV0();
73 const SFVEC2F& v1 = aPoly->GetV1();
74 const SFVEC2F& v2 = aPoly->GetV2();
75 const SFVEC2F& v3 = aPoly->GetV3();
76
77 addTopAndBottomTriangles( aDstLayer, v0, v2, v1, aZtop, aZbot );
78 addTopAndBottomTriangles( aDstLayer, v2, v0, v3, aZtop, aZbot );
79}
80
81
82void RENDER_3D_OPENGL::generateRing( const SFVEC2F& aCenter, float aInnerRadius,
83 float aOuterRadius, unsigned int aNr_sides_per_circle,
84 std::vector< SFVEC2F >& aInnerContourResult,
85 std::vector< SFVEC2F >& aOuterContourResult,
86 bool aInvertOrder )
87{
88 aInnerContourResult.clear();
89 aInnerContourResult.reserve( aNr_sides_per_circle + 2 );
90
91 aOuterContourResult.clear();
92 aOuterContourResult.reserve( aNr_sides_per_circle + 2 );
93
94 const int delta = 3600 / aNr_sides_per_circle;
95
96 for( int ii = 0; ii < 3600; ii += delta )
97 {
98 float angle = (float)( aInvertOrder ? ( 3600 - ii ) : ii )
99 * 2.0f * glm::pi<float>() / 3600.0f;
100 const SFVEC2F rotatedDir = SFVEC2F( cos( angle ), sin( angle ) );
101
102 aInnerContourResult.emplace_back( aCenter.x + rotatedDir.x * aInnerRadius,
103 aCenter.y + rotatedDir.y * aInnerRadius );
104
105 aOuterContourResult.emplace_back( aCenter.x + rotatedDir.x * aOuterRadius,
106 aCenter.y + rotatedDir.y * aOuterRadius );
107 }
108
109 aInnerContourResult.push_back( aInnerContourResult[0] );
110 aOuterContourResult.push_back( aOuterContourResult[0] );
111
112 wxASSERT( aInnerContourResult.size() == aOuterContourResult.size() );
113}
114
115
117 float aZtop, float aZbot )
118{
119 const SFVEC2F& center = aRing->GetCenter();
120 const float inner = aRing->GetInnerRadius();
121 const float outer = aRing->GetOuterRadius();
122
123 std::vector< SFVEC2F > innerContour;
124 std::vector< SFVEC2F > outerContour;
125
126 generateRing( center, inner, outer, m_boardAdapter.GetCircleSegmentCount( outer * 2.0f ),
127 innerContour, outerContour, false );
128
129 // This will add the top and bot quads that will form the approximated ring
130 for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
131 {
132 const SFVEC2F& vi0 = innerContour[i + 0];
133 const SFVEC2F& vi1 = innerContour[i + 1];
134 const SFVEC2F& vo0 = outerContour[i + 0];
135 const SFVEC2F& vo1 = outerContour[i + 1];
136
137 aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
138 SFVEC3F( vi0.x, vi0.y, aZtop ),
139 SFVEC3F( vo0.x, vo0.y, aZtop ),
140 SFVEC3F( vo1.x, vo1.y, aZtop ) );
141
142 aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
143 SFVEC3F( vo1.x, vo1.y, aZbot ),
144 SFVEC3F( vo0.x, vo0.y, aZbot ),
145 SFVEC3F( vi0.x, vi0.y, aZbot ) );
146 }
147}
148
149
151 TRIANGLE_DISPLAY_LIST* aDstLayer,
152 float aZtop, float aZbot )
153{
154 const SFVEC2F& v1 = aTri->GetP1();
155 const SFVEC2F& v2 = aTri->GetP2();
156 const SFVEC2F& v3 = aTri->GetP3();
157
158 addTopAndBottomTriangles( aDstLayer, v1, v2, v3, aZtop, aZbot );
159}
160
161
163 TRIANGLE_DISPLAY_LIST* aDstLayer,
164 float aZtop, float aZbot )
165{
166 const SFVEC2F& leftStart = aSeg->GetLeftStar();
167 const SFVEC2F& leftEnd = aSeg->GetLeftEnd();
168 const SFVEC2F& leftDir = aSeg->GetLeftDir();
169
170 const SFVEC2F& rightStart = aSeg->GetRightStar();
171 const SFVEC2F& rightEnd = aSeg->GetRightEnd();
172 const SFVEC2F& rightDir = aSeg->GetRightDir();
173 const float radius = aSeg->GetRadius();
174
175 const SFVEC2F& start = aSeg->GetStart();
176 const SFVEC2F& end = aSeg->GetEnd();
177
178 const float texture_factor = ( 12.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
179 const float texture_factorF = ( 6.0f / (float) SIZE_OF_CIRCLE_TEXTURE ) + 1.0f;
180
181 const float radius_of_the_square = sqrtf( aSeg->GetRadiusSquared() * 2.0f );
182 const float radius_triangle_factor = ( radius_of_the_square - radius ) / radius;
183
184 const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor,
185 rightDir.x * radius * radius_triangle_factor );
186
187 const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor,
188 leftDir.x * radius * radius_triangle_factor );
189
190 // Top end segment triangles (semi-circles)
192 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
193 rightEnd.y + texture_factor * factorS.y,
194 aZtop ),
195 SFVEC3F( leftStart.x + texture_factor * factorE.x,
196 leftStart.y + texture_factor * factorE.y,
197 aZtop ),
198 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
199 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
200 aZtop ) );
201
203 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
204 leftEnd.y + texture_factor * factorE.y, aZtop ),
205 SFVEC3F( rightStart.x + texture_factor * factorS.x,
206 rightStart.y + texture_factor * factorS.y, aZtop ),
207 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
208 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
209 aZtop ) );
210
211 // Bot end segment triangles (semi-circles)
213 SFVEC3F( leftStart.x + texture_factor * factorE.x,
214 leftStart.y + texture_factor * factorE.y,
215 aZbot ),
216 SFVEC3F( rightEnd.x + texture_factor * factorS.x,
217 rightEnd.y + texture_factor * factorS.y,
218 aZbot ),
219 SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf( 2.0f ),
220 start.y - texture_factorF * leftDir.y * radius * sqrtf( 2.0f ),
221 aZbot ) );
222
224 SFVEC3F( rightStart.x + texture_factor * factorS.x,
225 rightStart.y + texture_factor * factorS.y, aZbot ),
226 SFVEC3F( leftEnd.x + texture_factor * factorE.x,
227 leftEnd.y + texture_factor * factorE.y, aZbot ),
228 SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf( 2.0f ),
229 end.y - texture_factorF * rightDir.y * radius * sqrtf( 2.0f ),
230 aZbot ) );
231
232 // Segment top and bot planes
233 aDstLayer->m_layer_top_triangles->AddQuad(
234 SFVEC3F( rightEnd.x, rightEnd.y, aZtop ),
235 SFVEC3F( rightStart.x, rightStart.y, aZtop ),
236 SFVEC3F( leftEnd.x, leftEnd.y, aZtop ),
237 SFVEC3F( leftStart.x, leftStart.y, aZtop ) );
238
239 aDstLayer->m_layer_bot_triangles->AddQuad(
240 SFVEC3F( rightEnd.x, rightEnd.y, aZbot ),
241 SFVEC3F( leftStart.x, leftStart.y, aZbot ),
242 SFVEC3F( leftEnd.x, leftEnd.y, aZbot ),
243 SFVEC3F( rightStart.x, rightStart.y, aZbot ) );
244}
245
246
248 const SHAPE_POLY_SET& aPoly, float aZtop,
249 float aZbot, bool aInvertFaces,
250 const BVH_CONTAINER_2D* aThroughHoles )
251{
252 OPENGL_RENDER_LIST* ret = nullptr;
253
254 if( aListHolesObject2d.size() > 0 )
255 {
256 TRIANGLE_DISPLAY_LIST* layerTriangles =
257 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* itemOnLayer : aListHolesObject2d )
261 {
262 const OBJECT_2D* object2d_A = itemOnLayer;
263
264 wxASSERT( ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::FILLED_CIRCLE )
265 || ( object2d_A->GetObjectType() == OBJECT_2D_TYPE::ROUNDSEG ) );
266
267 switch( object2d_A->GetObjectType() )
268 {
270 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d_A ),
271 layerTriangles, aZtop, aZbot );
272 break;
273
275 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d_A ),
276 layerTriangles, aZtop, aZbot );
277 break;
278
279 default:
280 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL::generateHoles: Object type not implemented" ) );
281 break;
282 }
283 }
284
285 // Note: he can have a aListHolesObject2d with holes but without contours
286 // eg: when there are only NPTH on the list and the contours were not added
287 if( aPoly.OutlineCount() > 0 )
288 {
289 layerTriangles->AddToMiddleContourns( aPoly, aZbot, aZtop,
291 aInvertFaces, aThroughHoles );
292 }
293
294 ret = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, aZbot, aZtop );
295
296 delete layerTriangles;
297 }
298
299 return ret;
300}
301
302
304 const SHAPE_POLY_SET* aPolyList,
305 PCB_LAYER_ID aLayerId,
306 const BVH_CONTAINER_2D* aThroughHoles )
307{
308 if( aContainer == nullptr )
309 return nullptr;
310
311 const LIST_OBJECT2D& listObject2d = aContainer->GetList();
312
313 if( listObject2d.size() == 0 )
314 return nullptr;
315
316 float layer_z_bot = 0.0f;
317 float layer_z_top = 0.0f;
318
319 getLayerZPos( aLayerId, layer_z_top, layer_z_bot );
320
321 // Calculate an estimation for the nr of triangles based on the nr of objects
322 unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
323
324 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( nrTrianglesEstimation );
325
326 // store in a list so it will be latter deleted
327 m_triangles.push_back( layerTriangles );
328
329 // Load the 2D (X,Y axis) component of shapes
330 for( const OBJECT_2D* itemOnLayer : listObject2d )
331 {
332 const OBJECT_2D* object2d_A = itemOnLayer;
333
334 switch( object2d_A->GetObjectType() )
335 {
337 addObjectTriangles( static_cast<const FILLED_CIRCLE_2D*>( object2d_A ),
338 layerTriangles, layer_z_top, layer_z_bot );
339 break;
340
342 addObjectTriangles( static_cast<const POLYGON_4PT_2D*>( object2d_A ),
343 layerTriangles, layer_z_top, layer_z_bot );
344 break;
345
347 addObjectTriangles( static_cast<const RING_2D*>( object2d_A ),
348 layerTriangles, layer_z_top, layer_z_bot );
349 break;
350
352 addObjectTriangles( static_cast<const TRIANGLE_2D*>( object2d_A ),
353 layerTriangles, layer_z_top, layer_z_bot );
354 break;
355
357 addObjectTriangles( static_cast<const ROUND_SEGMENT_2D*>( object2d_A ),
358 layerTriangles, layer_z_top, layer_z_bot );
359 break;
360
361 default:
362 wxFAIL_MSG( wxT( "RENDER_3D_OPENGL: Object type is not implemented" ) );
363 break;
364 }
365 }
366
367 if( aPolyList && aPolyList->OutlineCount() > 0 )
368 {
369 layerTriangles->AddToMiddleContourns( *aPolyList, layer_z_bot, layer_z_top,
370 m_boardAdapter.BiuTo3dUnits(), false, aThroughHoles );
371 }
372
373 // Create display list
374 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
375}
376
377
379{
380 float layer_z_bot = 0.0f;
381 float layer_z_top = 0.0f;
382
383 getLayerZPos( aLayerId, layer_z_top, layer_z_bot );
384
385 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( 1 );
386
387 // store in a list so it will be latter deleted
388 m_triangles.push_back( layerTriangles );
389
390 return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
391}
392
393
395 const BVH_CONTAINER_2D* aThroughHoles )
396{
397 OPENGL_RENDER_LIST* dispLists = nullptr;
398 CONTAINER_2D boardContainer;
399
400 ConvertPolygonToTriangles( aBoardPoly, boardContainer, m_boardAdapter.BiuTo3dUnits(),
401 (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
402
403 const LIST_OBJECT2D& listBoardObject2d = boardContainer.GetList();
404
405 if( listBoardObject2d.size() > 0 )
406 {
407 // We will set a unitary Z so it will in future used with transformations since the
408 // board poly will be used not only to draw itself but also the solder mask layers.
409 const float layer_z_top = 1.0f;
410 const float layer_z_bot = 0.0f;
411
412 TRIANGLE_DISPLAY_LIST* layerTriangles =
413 new TRIANGLE_DISPLAY_LIST( listBoardObject2d.size() );
414
415 // Convert the list of objects(triangles) to triangle layer structure
416 for( const OBJECT_2D* itemOnLayer : listBoardObject2d )
417 {
418 const OBJECT_2D* object2d_A = itemOnLayer;
419
420 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
421
422 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
423
424 const SFVEC2F& v1 = tri->GetP1();
425 const SFVEC2F& v2 = tri->GetP2();
426 const SFVEC2F& v3 = tri->GetP3();
427
428 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
429 }
430
431 if( aBoardPoly.OutlineCount() > 0 )
432 {
433 layerTriangles->AddToMiddleContourns( aBoardPoly, layer_z_bot, layer_z_top,
435 aThroughHoles );
436
437 dispLists = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
438 layer_z_top, layer_z_top );
439 }
440
441 delete layerTriangles;
442 }
443
444 return dispLists;
445}
446
447
448void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
449{
450 m_reloadRequested = false;
451
452 freeAllLists();
453
455
456 unsigned stats_startReloadTime = GetRunningMicroSecs();
457
458 m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
459
461 m_camera.SetBoardLookAtPos( camera_pos );
462
463 if( aStatusReporter )
464 aStatusReporter->Report( _( "Load OpenGL: board" ) );
465
466 // Create Board
468
470 {
473 m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2, -INT_MAX/2 ) );
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 ) );
478
482 }
483
489
490 m_boardWithHoles = createBoard( board_poly_with_holes );
491
492 if( m_antiBoard )
494
495 // Create Through Holes and vias
496 if( aStatusReporter )
497 aStatusReporter->Report( _( "Load OpenGL: holes and vias" ) );
498
500
502 {
505 }
506
508 outerPolyTHT, 1.0f, 0.0f, false,
510
513 m_boardAdapter.GetThroughHoleViaOdPolys(), 1.0f, 0.0f, false );
514
517 {
520 m_boardAdapter.GetThroughHoleAnnularRingPolys(), 1.0f, 0.0f, false );
521 }
522
523 const MAP_POLY& innerMapHoles = m_boardAdapter.GetHoleIdPolysMap();
524 const MAP_POLY& outerMapHoles = m_boardAdapter.GetHoleOdPolysMap();
525
526 wxASSERT( innerMapHoles.size() == outerMapHoles.size() );
527
529
530 if( outerMapHoles.size() > 0 )
531 {
532 float layer_z_bot = 0.0f;
533 float layer_z_top = 0.0f;
534
535 for( const std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET*>& ii : outerMapHoles )
536 {
537 const PCB_LAYER_ID layer_id = ii.first;
538 const SHAPE_POLY_SET* poly = ii.second;
539 const BVH_CONTAINER_2D* container = map_holes.at( layer_id );
540
541 getLayerZPos( layer_id, layer_z_top, layer_z_bot );
542
543 m_outerLayerHoles[layer_id] = generateHoles( container->GetList(), *poly,
544 layer_z_top, layer_z_bot, false );
545 }
546
547 for( const std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET*>& ii : innerMapHoles )
548 {
549 const PCB_LAYER_ID layer_id = ii.first;
550 const SHAPE_POLY_SET* poly = ii.second;
551 const BVH_CONTAINER_2D* container = map_holes.at( layer_id );
552
553 getLayerZPos( layer_id, layer_z_top, layer_z_bot );
554
555 m_innerLayerHoles[layer_id] = generateHoles( container->GetList(), *poly,
556 layer_z_top, layer_z_bot, false );
557 }
558 }
559
560 // Generate vertical cylinders of vias and pads (copper)
562
563 // Add layers maps
564 if( aStatusReporter )
565 aStatusReporter->Report( _( "Load OpenGL: layers" ) );
566
567 const MAP_POLY& map_poly = m_boardAdapter.GetPolyMap();
568
569 for( const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& ii : m_boardAdapter.GetLayerMap() )
570 {
571 const PCB_LAYER_ID layer_id = ii.first;
572
573 if( !m_boardAdapter.Is3dLayerEnabled( layer_id ) )
574 continue;
575
576 if( aStatusReporter )
577 {
578 aStatusReporter->Report( wxString::Format( _( "Load OpenGL layer %d" ),
579 (int) layer_id ) );
580 }
581
582 const BVH_CONTAINER_2D* container2d = ii.second;
583
584 SHAPE_POLY_SET polyListSubtracted;
585 SHAPE_POLY_SET* polyList = nullptr;
586
587 // Load the vertical (Z axis) component of shapes
588
589 if( map_poly.find( layer_id ) != map_poly.end() )
590 {
591 polyListSubtracted = *map_poly.at( layer_id );;
592
594 {
595 polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
597
598 if( layer_id != B_Mask && layer_id != F_Mask )
599 {
604 }
605
607 {
608 if( layer_id == B_SilkS && map_poly.find( B_Mask ) != map_poly.end() )
609 {
610 polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ),
612 }
613 else if( layer_id == F_SilkS && map_poly.find( F_Mask ) != map_poly.end() )
614 {
615 polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ),
617 }
618 }
619 }
620
621 polyList = &polyListSubtracted;
622 }
623
624 OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, polyList, layer_id,
626
627 if( oglList != nullptr )
628 m_layers[layer_id] = oglList;
629
630 }
631
634 {
635 const SHAPE_POLY_SET* frontPlatedPadPolys = m_boardAdapter.GetFrontPlatedPadPolys();
636 const SHAPE_POLY_SET* backPlatedPadPolys = m_boardAdapter.GetBackPlatedPadPolys();
637
638 if( frontPlatedPadPolys )
639 {
640 SHAPE_POLY_SET polySubtracted = frontPlatedPadPolys->CloneDropTriangulation();
647
649 &polySubtracted, F_Cu );
650
651 // An entry for F_Cu must exist in m_layers or we'll never look at m_platedPadsFront
652 if( m_layers.count( F_Cu ) == 0 )
654 }
655
656 if( backPlatedPadPolys )
657 {
658 SHAPE_POLY_SET polySubtracted = backPlatedPadPolys->CloneDropTriangulation();
665
667 &polySubtracted, B_Cu );
668
669 // An entry for B_Cu must exist in m_layers or we'll never look at m_platedPadsBack
670 if( m_layers.count( B_Cu ) == 0 )
672 }
673 }
674
675 // Load 3D models
676 if( aStatusReporter )
677 aStatusReporter->Report( _( "Loading 3D models..." ) );
678
679 load3dModels( aStatusReporter );
680
681 if( aStatusReporter )
682 {
683 // Calculation time in seconds
684 double calculation_time = (double)( GetRunningMicroSecs() - stats_startReloadTime) / 1e6;
685
686 aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
687 }
688}
689
690
692 const SFVEC2F& v1, const SFVEC2F& v2, float top,
693 float bot )
694{
695 aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
696 SFVEC3F( v1.x, v1.y, bot ),
697 SFVEC3F( v2.x, v2.y, bot ) );
698
700 SFVEC3F( v1.x, v1.y, top ),
701 SFVEC3F( v0.x, v0.y, top ) );
702}
703
704
705void RENDER_3D_OPENGL::getLayerZPos( PCB_LAYER_ID aLayer, float& aOutZtop, float& aOutZbot ) const
706{
707 aOutZbot = m_boardAdapter.GetLayerBottomZPos( aLayer );
708 aOutZtop = m_boardAdapter.GetLayerTopZPos( aLayer );
709
710 if( aOutZtop < aOutZbot )
711 {
712 float tmpFloat = aOutZbot;
713 aOutZbot = aOutZtop;
714 aOutZtop = tmpFloat;
715 }
716}
717
718
719void RENDER_3D_OPENGL::generateCylinder( const SFVEC2F& aCenter, float aInnerRadius,
720 float aOuterRadius, float aZtop, float aZbot,
721 unsigned int aNr_sides_per_circle,
722 TRIANGLE_DISPLAY_LIST* aDstLayer )
723{
724 std::vector< SFVEC2F > innerContour;
725 std::vector< SFVEC2F > outerContour;
726
727 generateRing( aCenter, aInnerRadius, aOuterRadius, aNr_sides_per_circle, innerContour,
728 outerContour, false );
729
730 for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
731 {
732 const SFVEC2F& vi0 = innerContour[i + 0];
733 const SFVEC2F& vi1 = innerContour[i + 1];
734 const SFVEC2F& vo0 = outerContour[i + 0];
735 const SFVEC2F& vo1 = outerContour[i + 1];
736
737 aDstLayer->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZtop ),
738 SFVEC3F( vi0.x, vi0.y, aZtop ),
739 SFVEC3F( vo0.x, vo0.y, aZtop ),
740 SFVEC3F( vo1.x, vo1.y, aZtop ) );
741
742 aDstLayer->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, aZbot ),
743 SFVEC3F( vo1.x, vo1.y, aZbot ),
744 SFVEC3F( vo0.x, vo0.y, aZbot ),
745 SFVEC3F( vi0.x, vi0.y, aZbot ) );
746 }
747
748 aDstLayer->AddToMiddleContourns( outerContour, aZbot, aZtop, true );
749 aDstLayer->AddToMiddleContourns( innerContour, aZbot, aZtop, false );
750}
751
752
754{
755 if( !m_boardAdapter.GetBoard() )
756 return;
757
758 const int platingThickness = m_boardAdapter.GetHolePlatingThickness();
759 const float platingThickness3d = platingThickness * m_boardAdapter.BiuTo3dUnits();
760
761 if( m_boardAdapter.GetViaCount() > 0 )
762 {
763 float averageDiameter = m_boardAdapter.GetAverageViaHoleDiameter();
764 unsigned int averageSegCount = m_boardAdapter.GetCircleSegmentCount( averageDiameter );
765 unsigned int trianglesEstimate = averageSegCount * 8 * m_boardAdapter.GetViaCount();
766
767 TRIANGLE_DISPLAY_LIST* layerTriangleVIA = new TRIANGLE_DISPLAY_LIST( trianglesEstimate );
768
769 // Insert plated vertical holes inside the board
770
771 // Insert vias holes (vertical cylinders)
772 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
773 {
774 if( track->Type() == PCB_VIA_T )
775 {
776 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
777
778 const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
779 const int nrSegments = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
780 const float hole_inner_radius = holediameter / 2.0f;
781
782 const SFVEC2F via_center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
783 -via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
784
785 PCB_LAYER_ID top_layer, bottom_layer;
786 via->LayerPair( &top_layer, &bottom_layer );
787
788 float ztop, zbot, dummy;
789
790 getLayerZPos( top_layer, ztop, dummy );
791 getLayerZPos( bottom_layer, dummy, zbot );
792
793 wxASSERT( zbot < ztop );
794
795 generateCylinder( via_center, hole_inner_radius,
796 hole_inner_radius + platingThickness3d,
797 ztop, zbot, nrSegments, layerTriangleVIA );
798 }
799 }
800
801 m_vias = new OPENGL_RENDER_LIST( *layerTriangleVIA, 0, 0.0f, 0.0f );
802
803 delete layerTriangleVIA;
804 }
805
806
807 if( m_boardAdapter.GetHoleCount() > 0 )
808 {
809 SHAPE_POLY_SET tht_outer_holes_poly; // Stores the outer poly of the copper holes (the pad)
810 SHAPE_POLY_SET tht_inner_holes_poly; // Stores the inner poly of the copper holes (the hole)
811
812 tht_outer_holes_poly.RemoveAllContours();
813 tht_inner_holes_poly.RemoveAllContours();
814
815 // Insert pads holes (vertical cylinders)
816 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
817 {
818 for( const PAD* pad : footprint->Pads() )
819 {
820 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
821 {
822 const VECTOR2I drillsize = pad->GetDrillSize();
823 const bool hasHole = drillsize.x && drillsize.y;
824
825 if( !hasHole )
826 continue;
827
828 pad->TransformHoleToPolygon( tht_outer_holes_poly, platingThickness,
830 pad->TransformHoleToPolygon( tht_inner_holes_poly, 0, ARC_HIGH_DEF,
831 ERROR_INSIDE );
832 }
833 }
834 }
835
836 // Subtract the holes
837 tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );
838
841
842 CONTAINER_2D holesContainer;
843
844 ConvertPolygonToTriangles( tht_outer_holes_poly, holesContainer,
846
847 const LIST_OBJECT2D& holes2D = holesContainer.GetList();
848
849 if( holes2D.size() > 0 )
850 {
851 float layer_z_top, layer_z_bot, dummy;
852
853 getLayerZPos( F_Cu, layer_z_top, dummy );
854 getLayerZPos( B_Cu, dummy, layer_z_bot );
855
856 TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( holes2D.size() );
857
858 // Convert the list of objects(triangles) to triangle layer structure
859 for( const OBJECT_2D* itemOnLayer : holes2D )
860 {
861 const OBJECT_2D* object2d_A = itemOnLayer;
862
863 wxASSERT( object2d_A->GetObjectType() == OBJECT_2D_TYPE::TRIANGLE );
864
865 const TRIANGLE_2D* tri = static_cast<const TRIANGLE_2D*>( object2d_A );
866
867 const SFVEC2F& v1 = tri->GetP1();
868 const SFVEC2F& v2 = tri->GetP2();
869 const SFVEC2F& v3 = tri->GetP3();
870
871 addTopAndBottomTriangles( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
872 }
873
874 wxASSERT( tht_outer_holes_poly.OutlineCount() > 0 );
875
876 if( tht_outer_holes_poly.OutlineCount() > 0 )
877 {
878 layerTriangles->AddToMiddleContourns( tht_outer_holes_poly,
879 layer_z_bot, layer_z_top,
880 m_boardAdapter.BiuTo3dUnits(), false );
881
882 m_padHoles = new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture,
883 layer_z_top, layer_z_top );
884 }
885
886 delete layerTriangles;
887 }
888 }
889}
890
891
893{
894 if( m_3dModelMap.size() > 0 )
895 return;
896
897 wxFrame* frame = dynamic_cast<EDA_3D_VIEWER_FRAME*>( m_canvas->GetParent() );
898
899 if( frame )
900 {
901 STATUSBAR_REPORTER activityReporter( frame->GetStatusBar(),
903 load3dModels( &activityReporter );
904 }
905 else
906 load3dModels( nullptr );
907}
908
909
911{
912 if( !m_boardAdapter.GetBoard() )
913 return;
914
918 {
919 return;
920 }
921
922 // Go for all footprints
923 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
924 {
925 wxString libraryName = footprint->GetFPID().GetLibNickname();
926 wxString footprintBasePath = wxEmptyString;
927
929 {
930 try
931 {
932 // FindRow() can throw an exception
933 const FP_LIB_TABLE_ROW* fpRow =
935 libraryName, false );
936
937 if( fpRow )
938 footprintBasePath = fpRow->GetFullURI( true );
939 }
940 catch( ... )
941 {
942 // Do nothing if the libraryName is not found in lib table
943 }
944 }
945
946 for( const FP_3DMODEL& fp_model : footprint->Models() )
947 {
948 if( fp_model.m_Show && !fp_model.m_Filename.empty() )
949 {
950 if( aStatusReporter )
951 {
952 // Display the short filename of the 3D fp_model loaded:
953 // (the full name is usually too long to be displayed)
954 wxFileName fn( fp_model.m_Filename );
955 aStatusReporter->Report( wxString::Format( _( "Loading %s..." ),
956 fn.GetFullName() ) );
957 }
958
959 // Check if the fp_model is not present in our cache map
960 // (Not already loaded in memory)
961 if( m_3dModelMap.find( fp_model.m_Filename ) == m_3dModelMap.end() )
962 {
963 // It is not present, try get it from cache
964 const S3DMODEL* modelPtr =
965 m_boardAdapter.Get3dCacheManager()->GetModel( fp_model.m_Filename, footprintBasePath );
966
967 // only add it if the return is not NULL
968 if( modelPtr )
969 {
971 MODEL_3D* model = new MODEL_3D( *modelPtr, materialMode );
972
973 m_3dModelMap[ fp_model.m_Filename ] = model;
974 }
975 }
976 }
977 }
978 }
979}
MATERIAL_MODE
Render 3d model shape materials mode.
Definition: 3d_enums.h:71
constexpr int ARC_HIGH_DEF
Definition: base_units.h:121
std::map< PCB_LAYER_ID, SHAPE_POLY_SET * > MAP_POLY
A type that stores polysets for each layer id.
Definition: board_adapter.h:57
std::map< PCB_LAYER_ID, BVH_CONTAINER_2D * > MAP_CONTAINER_2D_BASE
A type that stores a container of 2d objects for each layer id.
Definition: board_adapter.h:54
const BVH_CONTAINER_2D & GetThroughHoleViaOds() const noexcept
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
const MAP_CONTAINER_2D_BASE & GetLayerHoleMap() const noexcept
const SHAPE_POLY_SET & GetBoardPoly() const noexcept
Get the current polygon of the epoxy board.
const SHAPE_POLY_SET & GetThroughHoleOdPolys() const noexcept
Get through hole outside diameter 2D polygons.
const MAP_POLY & GetPolyMap() const noexcept
Get map of polygon's layers.
const MAP_POLY & GetHoleOdPolysMap() const noexcept
const BVH_CONTAINER_2D & GetThroughHoleIds() const noexcept
int GetHolePlatingThickness() const noexcept
Get the hole plating thickness (NB: in BOARD UNITS!).
void InitSettings(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
Function to be called by the render when it need to reload the settings for the board.
float GetLayerBottomZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the bottom z position.
const BVH_CONTAINER_2D * GetPlatedPadsBack() const noexcept
const MAP_POLY & GetHoleIdPolysMap() const noexcept
float GetAverageViaHoleDiameter() const noexcept
const SHAPE_POLY_SET * GetFrontPlatedPadPolys()
unsigned int GetViaCount() const noexcept
const BOARD * GetBoard() const noexcept
const SFVEC3F & GetBoardCenter() const noexcept
The board center position in 3D units.
float GetLayerTopZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the top z position.
const SHAPE_POLY_SET & GetOuterNonPlatedThroughHolePoly() const noexcept
const SHAPE_POLY_SET * GetBackPlatedPadPolys()
const MAP_CONTAINER_2D_BASE & GetLayerMap() const noexcept
Get the map of containers that have the objects per layer.
EDA_3D_VIEWER_SETTINGS * m_Cfg
unsigned int GetHoleCount() const noexcept
const SHAPE_POLY_SET & GetThroughHoleAnnularRingPolys() const noexcept
const BVH_CONTAINER_2D * GetPlatedPadsFront() const noexcept
unsigned int GetCircleSegmentCount(float aDiameter3DU) const
const BVH_CONTAINER_2D & GetThroughHoleAnnularRings() const noexcept
bool Is3dLayerEnabled(PCB_LAYER_ID aLayer) const
Check if a layer is enabled.
const SHAPE_POLY_SET & GetThroughHoleViaOdPolys() const noexcept
const BVH_CONTAINER_2D & GetThroughHoleOds() const noexcept
S3D_CACHE * Get3dCacheManager() const noexcept
Definition: board_adapter.h:81
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
FOOTPRINTS & Footprints()
Definition: board.h:307
TRACKS & Tracks()
Definition: board.h:304
PROJECT * GetProject() const
Definition: board.h:440
void SetBoardLookAtPos(const SFVEC3F &aBoardPos)
Definition: camera.cpp:124
const LIST_OBJECT2D & GetList() const
Definition: container_2d.h:66
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
const SFVEC2F & GetCenter() const
float GetRadius() const
Hold a record identifying a library accessed by the appropriate footprint library PLUGIN object in th...
Definition: fp_lib_table.h:41
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 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.
void SetItIsTransparent(bool aSetTransparent)
Definition: pad.h:59
Simple non-intersecting polygon with 4 points.
const SFVEC2F & GetV3() const
const SFVEC2F & GetV0() const
const SFVEC2F & GetV1() const
const SFVEC2F & GetV2() const
virtual FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
Definition: project.cpp:319
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
bool m_reloadRequested
The window size that this camera is working.
EDA_3D_CANVAS * m_canvas
Settings reference in use for this render.
BOARD_ADAPTER & m_boardAdapter
OPENGL_RENDER_LIST * m_board
void reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
OPENGL_RENDER_LIST * m_vias
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
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)
OPENGL_RENDER_LIST * generateEmptyLayerList(PCB_LAYER_ID aLayerId)
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 * 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
OPENGL_RENDER_LIST * generateLayerList(const BVH_CONTAINER_2D *aContainer, const SHAPE_POLY_SET *aPolyList, PCB_LAYER_ID aLayerId, const BVH_CONTAINER_2D *aThroughHoles=nullptr)
MAP_OGL_DISP_LISTS m_outerLayerHoles
LIST_TRIANGLES m_triangles
store pointers so can be deleted latter
OPENGL_RENDER_LIST * m_outerViaThroughHoles
OPENGL_RENDER_LIST * m_outerThroughHoles
std::map< wxString, MODEL_3D * > m_3dModelMap
OPENGL_RENDER_LIST * m_platedPadsFront
OPENGL_RENDER_LIST * m_antiBoard
void getLayerZPos(PCB_LAYER_ID aLayerID, float &aOutZtop, float &aOutZbot) const
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
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
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
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition: 3d_cache.cpp:645
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
SHAPE_LINE_CHAIN & Outline(int aIndex)
int NewOutline()
Creates a new hole in a given outline.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
SHAPE_POLY_SET CloneDropTriangulation() const
Creates a new empty polygon in the set and returns its index.
A wrapper for reporting to a specific text location in a statusbar.
Definition: reporter.h:287
const SFVEC2F & GetP2() const
Definition: triangle_2d.h:45
const SFVEC2F & GetP3() const
Definition: triangle_2d.h:46
const SFVEC2F & GetP1() const
Definition: triangle_2d.h:44
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)
std::list< OBJECT_2D * > LIST_OBJECT2D
Definition: container_2d.h:38
#define _(s)
@ ACTIVITY
@ ERROR_INSIDE
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ F_SilkS
Definition: layer_ids.h:104
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
@ NPTH
like PAD_PTH, but not plated
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
#define SIZE_OF_CIRCLE_TEXTURE
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:74
Store the a model based on meshes and materials.
Definition: c3dmodel.h:91
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
v1
VECTOR3I v3(1, 1, 1)
constexpr 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:102
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44