KiCad PCB EDA Suite
Loading...
Searching...
No Matches
raytracing/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-2022 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
27#include "shapes3D/plane_3d.h"
31#include "shapes3D/frustum_3d.h"
35#include "shapes2D/ring_2d.h"
36#include "shapes2D/polygon_2d.h"
41#include "3d_fastmath.h"
42#include "3d_math.h"
44
45#include <board.h>
46#include <footprint.h>
48#include <eda_3d_viewer_frame.h>
49#include <project_pcb.h>
50#include <pad.h>
51#include <pcb_track.h>
52
53#include <base_units.h>
54#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
55
64static float TransparencyControl( float aGrayColorValue, float aTransparency )
65{
66 const float aaa = aTransparency * aTransparency * aTransparency;
67
68 // 1.00-1.05*(1.0-x)^3
69 float ca = 1.0f - aTransparency;
70 ca = 1.00f - 1.05f * ca * ca * ca;
71
72 return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
73}
74
78#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
79
80
82{
84 m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_refractions );
86 m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_reflections );
87
89 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_refractions );
91 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_reflections );
92
93 double mmTo3Dunits = pcbIUScale.IU_PER_MM * m_boardAdapter.BiuTo3dUnits();
94
95 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
96 {
97 m_boardMaterial = BOARD_NORMAL( 0.40f * mmTo3Dunits );
98 m_copperMaterial = COPPER_NORMAL( 4.0f * mmTo3Dunits, &m_boardMaterial );
99 m_platedCopperMaterial = PLATED_COPPER_NORMAL( 0.5f * mmTo3Dunits );
101 m_plasticMaterial = PLASTIC_NORMAL( 0.05f * mmTo3Dunits );
102 m_shinyPlasticMaterial = PLASTIC_SHINE_NORMAL( 0.1f * mmTo3Dunits );
103 m_brushedMetalMaterial = BRUSHED_METAL_NORMAL( 0.05f * mmTo3Dunits );
104 m_silkScreenMaterial = SILK_SCREEN_NORMAL( 0.25f * mmTo3Dunits );
105 }
106
107 // http://devernay.free.fr/cours/opengl/materials.html
108 // Copper
109 const SFVEC3F copperSpecularLinear =
110 ConvertSRGBToLinear( glm::clamp( (SFVEC3F) m_boardAdapter.m_CopperColor * 0.5f + 0.25f,
111 SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) ) );
112
114 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_CopperColor * 0.3f ),
115 SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
116
117 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
118 m_materials.m_Copper.SetGenerator( &m_platedCopperMaterial );
119
120 m_materials.m_NonPlatedCopper = BLINN_PHONG_MATERIAL(
121 ConvertSRGBToLinear( SFVEC3F( 0.191f, 0.073f, 0.022f ) ), SFVEC3F( 0.0f, 0.0f, 0.0f ),
122 SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
123
124 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
125 m_materials.m_NonPlatedCopper.SetGenerator( &m_copperMaterial );
126
128 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor )
129 * ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor ),
130 SFVEC3F( 0.0f, 0.0f, 0.0f ),
131 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor )
133 (SFVEC3F) m_boardAdapter.m_SolderPasteColor ),
134 0.10f * 128.0f, 0.0f, 0.0f );
135
137 SFVEC3F( 0.0f, 0.0f, 0.0f ),
138 glm::clamp( ( ( SFVEC3F )( 1.0f ) - ConvertSRGBToLinear(
139 (SFVEC3F) m_boardAdapter.m_SilkScreenColorTop ) ),
140 SFVEC3F( 0.0f ), SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
141
142 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
143 m_materials.m_SilkS.SetGenerator( &m_silkScreenMaterial );
144
145 // Assume that SolderMaskTop == SolderMaskBot
146 const float solderMask_gray =
147 ( m_boardAdapter.m_SolderMaskColorTop.r + m_boardAdapter.m_SolderMaskColorTop.g
148 + m_boardAdapter.m_SolderMaskColorTop.b )
149 / 3.0f;
150
151 const float solderMask_transparency = TransparencyControl( solderMask_gray,
152 1.0f - m_boardAdapter.m_SolderMaskColorTop.a );
153
154 // For darker solder mask colors, increase shininess for a more realistic appearance.
155 // Darker colors appear to have a sharper specular highlight in real life.
156 const float minSolderMaskShininess = 0.85f * 128.0f;
157 const float maxSolderMaskShininess = 512.0f;
158 const float solderMaskShininess = minSolderMaskShininess
159 + ( maxSolderMaskShininess - minSolderMaskShininess ) * ( 1.0f - solderMask_gray );
160
161 // Darker solder mask colors need lower reflection to prevent washed-out appearance
162 const float solderMaskReflection = glm::clamp( solderMask_gray * 0.3f, 0.02f, 0.16f );
163
164 m_materials.m_SolderMask = BLINN_PHONG_MATERIAL(
165 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderMaskColorTop ) * 0.10f,
166 SFVEC3F( 0.0f, 0.0f, 0.0f ),
167 SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.30f, 1.0f ) ), solderMaskShininess,
168 solderMask_transparency, solderMaskReflection );
169
170 m_materials.m_SolderMask.SetCastShadows( true );
171 m_materials.m_SolderMask.SetRefractionRayCount( 1 );
172
173 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
174 m_materials.m_SolderMask.SetGenerator( &m_solderMaskMaterial );
175
176 m_materials.m_EpoxyBoard =
177 BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( SFVEC3F( 16.0f / 255.0f, 14.0f / 255.0f,
178 10.0f / 255.0f ) ),
179 SFVEC3F( 0.0f, 0.0f, 0.0f ),
180 ConvertSRGBToLinear( SFVEC3F( 10.0f / 255.0f, 8.0f / 255.0f,
181 10.0f / 255.0f ) ),
182 0.1f * 128.0f, 1.0f - m_boardAdapter.m_BoardBodyColor.a, 0.0f );
183
184 m_materials.m_EpoxyBoard.SetAbsorvance( 10.0f );
185
186 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
187 m_materials.m_EpoxyBoard.SetGenerator( &m_boardMaterial );
188
189 SFVEC3F bgTop = ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_BgColorTop );
190
191 m_materials.m_Floor = BLINN_PHONG_MATERIAL( bgTop * 0.125f, SFVEC3F( 0.0f, 0.0f, 0.0f ),
192 ( SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
193 0.10f * 128.0f, 1.0f, 0.50f );
194 m_materials.m_Floor.SetCastShadows( false );
195 m_materials.m_Floor.SetReflectionRecursionCount( 1 );
196}
197
198
199void RENDER_3D_RAYTRACE_BASE::createObject( CONTAINER_3D& aDstContainer, const OBJECT_2D* aObject2D,
200 float aZMin, float aZMax, const MATERIAL* aMaterial,
201 const SFVEC3F& aObjColor )
202{
203 switch( aObject2D->GetObjectType() )
204 {
206 {
208
209 XY_PLANE* objPtr;
210 objPtr = new XY_PLANE( BBOX_3D(
211 SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMin ),
212 SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMin ) ) );
213 objPtr->SetMaterial( aMaterial );
214 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
215 aDstContainer.Add( objPtr );
216
217 objPtr = new XY_PLANE( BBOX_3D(
218 SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMax ),
219 SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMax ) ) );
220 objPtr->SetMaterial( aMaterial );
221 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
222 aDstContainer.Add( objPtr );
223 break;
224 }
225
227 {
229
230 const ROUND_SEGMENT_2D* aRoundSeg2D = static_cast<const ROUND_SEGMENT_2D*>( aObject2D );
231 ROUND_SEGMENT* objPtr = new ROUND_SEGMENT( *aRoundSeg2D, aZMin, aZMax );
232 objPtr->SetMaterial( aMaterial );
233 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
234 aDstContainer.Add( objPtr );
235 break;
236 }
237
238 default:
239 {
240 LAYER_ITEM* objPtr = new LAYER_ITEM( aObject2D, aZMin, aZMax );
241 objPtr->SetMaterial( aMaterial );
242 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
243 aDstContainer.Add( objPtr );
244 break;
245 }
246 }
247}
248
249
251 PCB_LAYER_ID aLayer_id,
252 const MATERIAL* aMaterialLayer,
253 const SFVEC3F& aLayerColor,
254 float aLayerZOffset )
255{
256 if( aContainer2d == nullptr )
257 return;
258
260 bool isSilk = aLayer_id == B_SilkS || aLayer_id == F_SilkS;
261 const LIST_OBJECT2D& listObject2d = aContainer2d->GetList();
262
263 if( listObject2d.size() == 0 )
264 return;
265
266 for( const OBJECT_2D* object2d_A : listObject2d )
267 {
268 // not yet used / implemented (can be used in future to clip the objects in the
269 // board borders
270 OBJECT_2D* object2d_C = CSGITEM_FULL;
271
272 std::vector<const OBJECT_2D*>* object2d_B = CSGITEM_EMPTY;
273
274 object2d_B = new std::vector<const OBJECT_2D*>();
275
276 // Subtract holes but not in SolderPaste
277 // (can be added as an option in future)
278 if( !( aLayer_id == B_Paste || aLayer_id == F_Paste ) )
279 {
280 // Check if there are any layerhole that intersects this object
281 // Eg: a segment is cut by a via hole or THT hole.
282 const MAP_CONTAINER_2D_BASE& layerHolesMap = m_boardAdapter.GetLayerHoleMap();
283
284 if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
285 {
286 const BVH_CONTAINER_2D* holes2d = layerHolesMap.at( aLayer_id );
287
288 CONST_LIST_OBJECT2D intersecting;
289
290 holes2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
291
292 for( const OBJECT_2D* hole2d : intersecting )
293 object2d_B->push_back( hole2d );
294 }
295
296 // Check if there are any THT that intersects this object. If we're processing a silk
297 // layer and the flag is set, then clip the silk at the outer edge of the annular ring,
298 // rather than the at the outer edge of the copper plating.
299 const BVH_CONTAINER_2D& throughHoleOuter =
300 cfg.clip_silk_on_via_annuli && isSilk ? m_boardAdapter.GetViaAnnuli()
301 : m_boardAdapter.GetTH_ODs();
302
303 if( !throughHoleOuter.GetList().empty() )
304 {
305 CONST_LIST_OBJECT2D intersecting;
306
307 throughHoleOuter.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
308
309 for( const OBJECT_2D* hole2d : intersecting )
310 object2d_B->push_back( hole2d );
311 }
312
313 // Clip counterbore/countersink cutouts from copper layers
314 // Front cutouts affect F_Cu, back cutouts affect B_Cu
315 auto clipCutouts = [this, &object2d_A, &object2d_B]( const BVH_CONTAINER_2D& cutouts )
316 {
317 if( !cutouts.GetList().empty() )
318 {
319 CONST_LIST_OBJECT2D intersecting;
320 cutouts.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
321
322 for( const OBJECT_2D* cutout : intersecting )
323 object2d_B->push_back( cutout );
324 }
325 };
326
327 if( aLayer_id == F_Cu )
328 {
329 clipCutouts( m_boardAdapter.GetFrontCounterboreCutouts() );
330 clipCutouts( m_boardAdapter.GetFrontCountersinkCutouts() );
331 clipCutouts( m_boardAdapter.GetTertiarydrillCutouts() );
332 }
333 else if( aLayer_id == B_Cu )
334 {
335 clipCutouts( m_boardAdapter.GetBackCounterboreCutouts() );
336 clipCutouts( m_boardAdapter.GetBackCountersinkCutouts() );
337 clipCutouts( m_boardAdapter.GetBackdrillCutouts() );
338 }
339 }
340
341 if( !m_antioutlineBoard2dObjects->GetList().empty() )
342 {
343 CONST_LIST_OBJECT2D intersecting;
344
345 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
346 intersecting );
347
348 for( const OBJECT_2D* obj : intersecting )
349 object2d_B->push_back( obj );
350 }
351
352 const MAP_CONTAINER_2D_BASE& mapLayers = m_boardAdapter.GetLayerMap();
353
355 && ( ( aLayer_id == B_SilkS && mapLayers.find( B_Mask ) != mapLayers.end() )
356 || ( aLayer_id == F_SilkS && mapLayers.find( F_Mask ) != mapLayers.end() ) ) )
357 {
358 const PCB_LAYER_ID maskLayer = ( aLayer_id == B_SilkS ) ? B_Mask : F_Mask;
359
360 const BVH_CONTAINER_2D* containerMaskLayer2d = mapLayers.at( maskLayer );
361
362 CONST_LIST_OBJECT2D intersecting;
363
364 if( containerMaskLayer2d ) // can be null if B_Mask or F_Mask is not shown
365 containerMaskLayer2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
366
367 for( const OBJECT_2D* obj2d : intersecting )
368 object2d_B->push_back( obj2d );
369 }
370
371 if( object2d_B->empty() )
372 {
373 delete object2d_B;
374 object2d_B = CSGITEM_EMPTY;
375 }
376
377 if( ( object2d_B == CSGITEM_EMPTY ) && ( object2d_C == CSGITEM_FULL ) )
378 {
379 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
380 m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
381 m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
382 objPtr->SetMaterial( aMaterialLayer );
383 objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
384 m_objectContainer.Add( objPtr );
385 }
386 else
387 {
388 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, object2d_C,
389 object2d_A->GetBoardItem() );
390 m_containerWithObjectsToDelete.Add( itemCSG2d );
391
392 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
393 m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
394 m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
395
396 objPtr->SetMaterial( aMaterialLayer );
397 objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
398
399 m_objectContainer.Add( objPtr );
400 }
401 }
402}
403
404
405extern void buildBoardBoundingBoxPoly( const BOARD* aBoard, SHAPE_POLY_SET& aOutline );
406
407
408void RENDER_3D_RAYTRACE_BASE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter,
409 bool aOnlyLoadCopperAndShapes )
410{
411 m_reloadRequested = false;
412
413 m_modelMaterialMap.clear();
414
417
418 int64_t stats_startReloadTime = GetRunningMicroSecs();
419
420 if( !aOnlyLoadCopperAndShapes )
421 {
422 m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
423
424 SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
425 m_camera.SetBoardLookAtPos( camera_pos );
426 }
427
428 m_objectContainer.Clear();
430 m_extrusionMaterials.clear();
431
433
434 if( aStatusReporter )
435 aStatusReporter->Report( _( "Load Raytracing: board" ) );
436
437 // Create and add the outline board
440
443
444 std::bitset<LAYER_3D_END> layerFlags = m_boardAdapter.GetVisibleLayers();
445
446 if( !aOnlyLoadCopperAndShapes )
447 {
448 const int outlineCount = m_boardAdapter.GetBoardPoly().OutlineCount();
449
450 if( outlineCount > 0 )
451 {
452 float divFactor = 0.0f;
453
454 if( m_boardAdapter.GetViaCount() )
455 divFactor = m_boardAdapter.GetAverageViaHoleDiameter() * 18.0f;
456 else if( m_boardAdapter.GetHoleCount() )
457 divFactor = m_boardAdapter.GetAverageHoleDiameter() * 8.0f;
458
459 SHAPE_POLY_SET boardPolyCopy = m_boardAdapter.GetBoardPoly();
460
461 // Calculate an antiboard outline
462 SHAPE_POLY_SET antiboardPoly;
463
464 buildBoardBoundingBoxPoly( m_boardAdapter.GetBoard(), antiboardPoly );
465
466 antiboardPoly.BooleanSubtract( boardPolyCopy );
467 antiboardPoly.Fracture();
468
469 for( int ii = 0; ii < antiboardPoly.OutlineCount(); ii++ )
470 {
472 m_boardAdapter.BiuTo3dUnits(), -1.0f,
473 *m_boardAdapter.GetBoard(), ii );
474 }
475
476 m_antioutlineBoard2dObjects->BuildBVH();
477
478 boardPolyCopy.Fracture();
479
480 for( int ii = 0; ii < boardPolyCopy.OutlineCount(); ii++ )
481 {
483 m_boardAdapter.BiuTo3dUnits(), divFactor,
484 *m_boardAdapter.GetBoard(), ii );
485 }
486
487 if( layerFlags.test( LAYER_3D_BOARD ) )
488 {
489 const LIST_OBJECT2D& listObjects = m_outlineBoard2dObjects->GetList();
490
491 for( const OBJECT_2D* object2d_A : listObjects )
492 {
493 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
494
495 // Check if there are any THT that intersects this outline object part
496 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
497 {
498 const BVH_CONTAINER_2D& throughHoles = m_boardAdapter.GetTH_ODs();
499 CONST_LIST_OBJECT2D intersecting;
500
501 throughHoles.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
502
503 for( const OBJECT_2D* hole : intersecting )
504 {
505 if( object2d_A->Intersects( hole->GetBBox() ) )
506 object2d_B->push_back( hole );
507 }
508 }
509
510 // Subtract counterbore/countersink cutouts from board body
511 auto addCutoutsFromContainer =
512 [&]( const BVH_CONTAINER_2D& aContainer )
513 {
514 if( !aContainer.GetList().empty() )
515 {
516 CONST_LIST_OBJECT2D intersecting;
517 aContainer.GetIntersectingObjects( object2d_A->GetBBox(),
518 intersecting );
519
520 for( const OBJECT_2D* cutout : intersecting )
521 {
522 if( object2d_A->Intersects( cutout->GetBBox() ) )
523 object2d_B->push_back( cutout );
524 }
525 }
526 };
527
528 addCutoutsFromContainer( m_boardAdapter.GetFrontCounterboreCutouts() );
529 addCutoutsFromContainer( m_boardAdapter.GetBackCounterboreCutouts() );
530 addCutoutsFromContainer( m_boardAdapter.GetFrontCountersinkCutouts() );
531 addCutoutsFromContainer( m_boardAdapter.GetBackCountersinkCutouts() );
532
533 // Subtract backdrill holes (which are in layerHoleMap for F_Cu and B_Cu)
534 const MAP_CONTAINER_2D_BASE& layerHolesMap = m_boardAdapter.GetLayerHoleMap();
535
536 if( layerHolesMap.find( F_Cu ) != layerHolesMap.end() )
537 {
538 const BVH_CONTAINER_2D* holes2d = layerHolesMap.at( F_Cu );
539 CONST_LIST_OBJECT2D intersecting;
540
541 holes2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
542
543 for( const OBJECT_2D* hole2d : intersecting )
544 {
545 if( object2d_A->Intersects( hole2d->GetBBox() ) )
546 object2d_B->push_back( hole2d );
547 }
548 }
549
550 if( layerHolesMap.find( B_Cu ) != layerHolesMap.end() )
551 {
552 const BVH_CONTAINER_2D* holes2d = layerHolesMap.at( B_Cu );
553 CONST_LIST_OBJECT2D intersecting;
554
555 holes2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
556
557 for( const OBJECT_2D* hole2d : intersecting )
558 {
559 if( object2d_A->Intersects( hole2d->GetBBox() ) )
560 object2d_B->push_back( hole2d );
561 }
562 }
563
564 if( !m_antioutlineBoard2dObjects->GetList().empty() )
565 {
566 CONST_LIST_OBJECT2D intersecting;
567
568 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
569 intersecting );
570
571 for( const OBJECT_2D* obj : intersecting )
572 object2d_B->push_back( obj );
573 }
574
575 if( object2d_B->empty() )
576 {
577 delete object2d_B;
578 object2d_B = CSGITEM_EMPTY;
579 }
580
581 if( object2d_B == CSGITEM_EMPTY )
582 {
583 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
584 m_boardAdapter.GetLayerBottomZPos( F_Cu ),
585 m_boardAdapter.GetLayerBottomZPos( B_Cu ) );
586
587 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
588 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
589 m_objectContainer.Add( objPtr );
590 }
591 else
592 {
593
594 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B,
596 *m_boardAdapter.GetBoard() );
597
598 m_containerWithObjectsToDelete.Add( itemCSG2d );
599
600 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
601 m_boardAdapter.GetLayerBottomZPos( F_Cu ),
602 m_boardAdapter.GetLayerBottomZPos( B_Cu ) );
603
604 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
605 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
606 m_objectContainer.Add( objPtr );
607 }
608 }
609
610 // Add cylinders of the board body to container
611 // Note: This is actually a workaround for the holes in the board.
612 // The issue is because if a hole is in a border of a divided polygon ( ex
613 // a polygon or dummy block) it will cut also the render of the hole.
614 // So this will add a full hole.
615 // In fact, that is not need if the hole have copper.
616 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
617 {
618 const LIST_OBJECT2D& holeList = m_boardAdapter.GetTH_ODs().GetList();
619
620 for( const OBJECT_2D* hole2d : holeList )
621 {
622 if( !m_antioutlineBoard2dObjects->GetList().empty() )
623 {
624 CONST_LIST_OBJECT2D intersecting;
625
626 m_antioutlineBoard2dObjects->GetIntersectingObjects( hole2d->GetBBox(),
627 intersecting );
628
629 // Do not add cylinder if it intersects the edge of the board
630 if( !intersecting.empty() )
631 continue;
632 }
633
634 switch( hole2d->GetObjectType() )
635 {
637 {
638 const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
639
640 CYLINDER* objPtr = new CYLINDER( hole2d->GetCentroid(),
641 NextFloatDown( m_boardAdapter.GetLayerBottomZPos( F_Cu ) ),
642 NextFloatUp( m_boardAdapter.GetLayerBottomZPos( B_Cu ) ),
643 radius );
644
645 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
646 objPtr->SetColor(
647 ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
648
649 m_objectContainer.Add( objPtr );
650 }
651 break;
652
653 default:
654 break;
655 }
656 }
657 }
658
659 // Create plugs for backdrilled and post-machined areas
661 }
662 }
663 }
664
665 if( aStatusReporter )
666 aStatusReporter->Report( _( "Load Raytracing: layers" ) );
667
668 // Add layers maps (except B_Mask and F_Mask)
669 for( const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
670 m_boardAdapter.GetLayerMap() )
671 {
672 const PCB_LAYER_ID layer_id = entry.first;
673 const BVH_CONTAINER_2D* container2d = entry.second;
674
675 // Only process layers that exist
676 if( !container2d )
677 continue;
678
679 if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) )
680 continue;
681
682 // Mask layers are not processed here because they are a special case
683 if( layer_id == B_Mask || layer_id == F_Mask )
684 continue;
685
686 MATERIAL* materialLayer = &m_materials.m_SilkS;
687 SFVEC3F layerColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
688
689 switch( layer_id )
690 {
691 case B_Adhes:
692 case F_Adhes:
693 break;
694
695 case B_Paste:
696 case F_Paste:
697 materialLayer = &m_materials.m_Paste;
698 layerColor = m_boardAdapter.m_SolderPasteColor;
699 break;
700
701 case B_SilkS:
702 materialLayer = &m_materials.m_SilkS;
703 layerColor = m_boardAdapter.m_SilkScreenColorBot;
704 break;
705
706 case F_SilkS:
707 materialLayer = &m_materials.m_SilkS;
708 layerColor = m_boardAdapter.m_SilkScreenColorTop;
709 break;
710
711 case Dwgs_User:
712 layerColor = m_boardAdapter.m_UserDrawingsColor;
713 break;
714
715 case Cmts_User:
716 layerColor = m_boardAdapter.m_UserCommentsColor;
717 break;
718
719 case Eco1_User:
720 layerColor = m_boardAdapter.m_ECO1Color;
721 break;
722
723 case Eco2_User:
724 layerColor = m_boardAdapter.m_ECO2Color;
725 break;
726
727 case B_CrtYd:
728 case F_CrtYd:
729 break;
730
731 case B_Fab:
732 case F_Fab:
733 break;
734
735 default:
736 {
737 int layer3D = MapPCBLayerTo3DLayer( layer_id );
738
739 // Note: MUST do this in LAYER_3D space; User_1..User_45 are NOT contiguous
740 if( layer3D >= LAYER_3D_USER_1 && layer3D <= LAYER_3D_USER_45 )
741 {
742 layerColor = m_boardAdapter.m_UserDefinedLayerColor[ layer3D - LAYER_3D_USER_1 ];
743 }
744 else if( m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
745 {
746 layerColor = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
747 materialLayer = &m_materials.m_NonPlatedCopper;
748 }
749 else
750 {
751 layerColor = m_boardAdapter.m_CopperColor;
752 materialLayer = &m_materials.m_Copper;
753 }
754
755 break;
756 }
757 }
758
759 createItemsFromContainer( container2d, layer_id, materialLayer, layerColor, 0.0f );
760 } // for each layer on map
761
762 // Create plated copper
763 if( m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
764 {
765 createItemsFromContainer( m_boardAdapter.GetPlatedPadsFront(), F_Cu, &m_materials.m_Copper,
766 m_boardAdapter.m_CopperColor,
767 m_boardAdapter.GetFrontCopperThickness() * 0.1f );
768
769 createItemsFromContainer( m_boardAdapter.GetPlatedPadsBack(), B_Cu, &m_materials.m_Copper,
770 m_boardAdapter.m_CopperColor,
771 -m_boardAdapter.GetBackCopperThickness() * 0.1f );
772 }
773
774 if( !aOnlyLoadCopperAndShapes )
775 {
776 // Add Mask layer
777 // Solder mask layers are "negative" layers so the elements that we have in the container
778 // should remove the board outline. We will check for all objects in the outline if it
779 // intersects any object in the layer container and also any hole.
780 if( ( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
781 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
782 && !m_outlineBoard2dObjects->GetList().empty() )
783 {
784 const MATERIAL* materialLayer = &m_materials.m_SolderMask;
785
786 for( const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
787 m_boardAdapter.GetLayerMap() )
788 {
789 const PCB_LAYER_ID layer_id = entry.first;
790 const BVH_CONTAINER_2D* container2d = entry.second;
791
792 // Only process layers that exist
793 if( !container2d )
794 continue;
795
796 // Only get the Solder mask layers (and only if the board has them)
797 if( layer_id == F_Mask && !layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
798 continue;
799
800 if( layer_id == B_Mask && !layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
801 continue;
802
803 // Only Mask layers are processed here because they are negative layers
804 if( layer_id != F_Mask && layer_id != B_Mask )
805 continue;
806
807 SFVEC3F layerColor;
808
809 if( layer_id == B_Mask )
810 layerColor = m_boardAdapter.m_SolderMaskColorBot;
811 else
812 layerColor = m_boardAdapter.m_SolderMaskColorTop;
813
814 const float zLayerMin = m_boardAdapter.GetLayerBottomZPos( layer_id );
815 const float zLayerMax = m_boardAdapter.GetLayerTopZPos( layer_id );
816
817 // Get the outline board objects
818 for( const OBJECT_2D* object2d_A : m_outlineBoard2dObjects->GetList() )
819 {
820 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
821
822 // Check if there are any THT that intersects this outline object part
823 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
824 {
825 const BVH_CONTAINER_2D& throughHoles = m_boardAdapter.GetTH_ODs();
826 CONST_LIST_OBJECT2D intersecting;
827
828 throughHoles.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
829
830 for( const OBJECT_2D* hole : intersecting )
831 {
832 if( object2d_A->Intersects( hole->GetBBox() ) )
833 object2d_B->push_back( hole );
834 }
835 }
836
837 // Check if there are any objects in the layer to subtract with the current
838 // object
839 if( !container2d->GetList().empty() )
840 {
841 CONST_LIST_OBJECT2D intersecting;
842
843 container2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
844
845 for( const OBJECT_2D* obj : intersecting )
846 object2d_B->push_back( obj );
847 }
848
849 if( object2d_B->empty() )
850 {
851 delete object2d_B;
852 object2d_B = CSGITEM_EMPTY;
853 }
854
855 if( object2d_B == CSGITEM_EMPTY )
856 {
857#if 0
858 createObject( m_objectContainer, object2d_A, zLayerMin, zLayerMax,
859 materialLayer, layerColor );
860#else
861 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, zLayerMin, zLayerMax );
862
863 objPtr->SetMaterial( materialLayer );
864 objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
865
866 m_objectContainer.Add( objPtr );
867#endif
868 }
869 else
870 {
871 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B,
873 object2d_A->GetBoardItem() );
874
875 m_containerWithObjectsToDelete.Add( itemCSG2d );
876
877 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, zLayerMin, zLayerMax );
878 objPtr->SetMaterial( materialLayer );
879 objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
880
881 m_objectContainer.Add( objPtr );
882 }
883 }
884 }
885 }
886
888 }
889
890#ifdef PRINT_STATISTICS_3D_VIEWER
891 int64_t stats_endConvertTime = GetRunningMicroSecs();
892 int64_t stats_startLoad3DmodelsTime = stats_endConvertTime;
893#endif
894
895 if( aStatusReporter )
896 aStatusReporter->Report( _( "Loading 3D models..." ) );
897
898 load3DModels( m_objectContainer, aOnlyLoadCopperAndShapes );
899
900#ifdef PRINT_STATISTICS_3D_VIEWER
901 int64_t stats_endLoad3DmodelsTime = GetRunningMicroSecs();
902#endif
903
904 if( !aOnlyLoadCopperAndShapes )
905 {
906 // Add floor
907 if( m_boardAdapter.m_Cfg->m_Render.raytrace_backfloor )
908 {
909 BBOX_3D boardBBox = m_boardAdapter.GetBBox();
910
911 if( boardBBox.IsInitialized() )
912 {
913 boardBBox.Scale( 3.0f );
914
915 if( m_objectContainer.GetList().size() > 0 )
916 {
917 BBOX_3D containerBBox = m_objectContainer.GetBBox();
918
919 containerBBox.Scale( 1.3f );
920
921 const SFVEC3F centerBBox = containerBBox.GetCenter();
922
923 // Floor triangles
924 const float minZ = glm::min( containerBBox.Min().z, boardBBox.Min().z );
925
926 const SFVEC3F v1 =
927 SFVEC3F( -RANGE_SCALE_3D * 4.0f, -RANGE_SCALE_3D * 4.0f, minZ )
928 + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
929
930 const SFVEC3F v3 =
931 SFVEC3F( +RANGE_SCALE_3D * 4.0f, +RANGE_SCALE_3D * 4.0f, minZ )
932 + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
933
934 const SFVEC3F v2 = SFVEC3F( v1.x, v3.y, v1.z );
935 const SFVEC3F v4 = SFVEC3F( v3.x, v1.y, v1.z );
936
937 SFVEC3F floorColor = ConvertSRGBToLinear( m_boardAdapter.m_BgColorTop );
938
939 TRIANGLE* newTriangle1 = new TRIANGLE( v1, v2, v3 );
940 TRIANGLE* newTriangle2 = new TRIANGLE( v3, v4, v1 );
941
942 m_objectContainer.Add( newTriangle1 );
943 m_objectContainer.Add( newTriangle2 );
944
945 newTriangle1->SetMaterial( &m_materials.m_Floor );
946 newTriangle2->SetMaterial( &m_materials.m_Floor );
947
948 newTriangle1->SetColor( floorColor );
949 newTriangle2->SetColor( floorColor );
950
951 // Ceiling triangles
952 const float maxZ = glm::max( containerBBox.Max().z, boardBBox.Max().z );
953
954 const SFVEC3F v5 = SFVEC3F( v1.x, v1.y, maxZ );
955 const SFVEC3F v6 = SFVEC3F( v2.x, v2.y, maxZ );
956 const SFVEC3F v7 = SFVEC3F( v3.x, v3.y, maxZ );
957 const SFVEC3F v8 = SFVEC3F( v4.x, v4.y, maxZ );
958
959 TRIANGLE* newTriangle3 = new TRIANGLE( v7, v6, v5 );
960 TRIANGLE* newTriangle4 = new TRIANGLE( v5, v8, v7 );
961
962 m_objectContainer.Add( newTriangle3 );
963 m_objectContainer.Add( newTriangle4 );
964
965 newTriangle3->SetMaterial( &m_materials.m_Floor );
966 newTriangle4->SetMaterial( &m_materials.m_Floor );
967
968 newTriangle3->SetColor( floorColor );
969 newTriangle4->SetColor( floorColor );
970 }
971 }
972 }
973
974 // Init initial lights
975 for( LIGHT* light : m_lights )
976 delete light;
977
978 m_lights.clear();
979
980 auto IsColorZero =
981 []( const SFVEC3F& aSource )
982 {
983 return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
984 && ( aSource.b < ( 1.0f / 255.0f ) ) );
985 };
986
987 SFVEC3F cameraLightColor =
988 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorCamera );
989 SFVEC3F topLightColor =
990 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorTop );
991 SFVEC3F bottomLightColor =
992 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorBottom );
993
994 m_cameraLight = new DIRECTIONAL_LIGHT( SFVEC3F( 0.0f, 0.0f, 0.0f ), cameraLightColor );
995 m_cameraLight->SetCastShadows( false );
996
997 if( !IsColorZero( cameraLightColor ) )
998 m_lights.push_back( m_cameraLight );
999
1000 const SFVEC3F& boardCenter = m_boardAdapter.GetBBox().GetCenter();
1001
1002 if( !IsColorZero( topLightColor ) )
1003 {
1004 m_lights.push_back( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
1005 +RANGE_SCALE_3D * 2.0f ),
1006 topLightColor ) );
1007 }
1008
1009 if( !IsColorZero( bottomLightColor ) )
1010 {
1011 m_lights.push_back( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
1012 -RANGE_SCALE_3D * 2.0f ),
1013 bottomLightColor ) );
1014 }
1015
1016 for( size_t i = 0; i < m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor.size(); ++i )
1017 {
1018 SFVEC3F lightColor =
1019 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor[i] );
1020
1021 if( !IsColorZero( lightColor ) )
1022 {
1023 const SFVEC2F sc = m_boardAdapter.GetSphericalCoord( i );
1024
1025 m_lights.push_back( new DIRECTIONAL_LIGHT(
1026 SphericalToCartesian( glm::pi<float>() * sc.x, glm::pi<float>() * sc.y ),
1027 lightColor ) );
1028 }
1029 }
1030 }
1031
1032 // Set min. and max. zoom range. This doesn't really fit here, but moving this outside of this
1033 // class would require reimplementing bounding box calculation (feel free to do this if you
1034 // have time and patience).
1035 if( m_objectContainer.GetList().size() > 0 )
1036 {
1037 float ratio =
1038 std::max( 1.0f, m_objectContainer.GetBBox().GetMaxDimension() / RANGE_SCALE_3D );
1039
1040 float max_zoom = CAMERA::DEFAULT_MAX_ZOOM * ratio;
1041 float min_zoom = static_cast<float>( MIN_DISTANCE_IU * m_boardAdapter.BiuTo3dUnits()
1042 / -m_camera.GetCameraInitPos().z );
1043
1044 if( min_zoom > max_zoom )
1045 std::swap( min_zoom, max_zoom );
1046
1047 float zoom_ratio = max_zoom / min_zoom;
1048
1049 // Set the minimum number of zoom 'steps' between max and min.
1050 int steps = 3 * 3;
1051 steps -= static_cast<int>( ceil( log( zoom_ratio ) / log( 1.26f ) ) );
1052 steps = std::max( steps, 0 );
1053
1054 // Resize max and min zoom to accomplish the number of steps.
1055 float increased_zoom = pow( 1.26f, steps / 2 );
1056 max_zoom *= increased_zoom;
1057 min_zoom /= increased_zoom;
1058
1059 if( steps & 1 )
1060 min_zoom /= 1.26f;
1061
1062 min_zoom = std::min( min_zoom, 1.0f );
1063
1064 m_camera.SetMaxZoom( max_zoom );
1065 m_camera.SetMinZoom( min_zoom );
1066 }
1067
1068 // Create an accelerator
1069 delete m_accelerator;
1071
1072 if( aStatusReporter )
1073 {
1074 // Calculation time in seconds
1075 double calculation_time = (double) ( GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
1076
1077 aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
1078 }
1079}
1080
1081
1083 const SFVEC2F& aCenter,
1084 float aInnerRadius, float aDepth,
1085 float aSurfaceZ, bool aIsFront )
1086{
1087 const float platingThickness = m_boardAdapter.GetHolePlatingThickness()
1088 * m_boardAdapter.BiuTo3dUnits();
1089
1090 if( platingThickness <= 0.0f || aInnerRadius <= 0.0f || aDepth <= 0.0f )
1091 return;
1092
1093 const float outerRadius = aInnerRadius + platingThickness;
1094 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1095 const float zMin = std::min( aSurfaceZ, zOther );
1096 const float zMax = std::max( aSurfaceZ, zOther );
1097
1098 RING_2D* ring = new RING_2D( aCenter, aInnerRadius, outerRadius, aSource );
1100
1101 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, zMin, zMax );
1102 objPtr->SetMaterial( &m_materials.m_Copper );
1103 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_CopperColor ) );
1104
1105 m_objectContainer.Add( objPtr );
1106}
1107
1108
1110 float aTopInnerRadius,
1111 float aBottomInnerRadius,
1112 float aSurfaceZ, float aDepth,
1113 bool aIsFront )
1114{
1115 const float platingThickness = m_boardAdapter.GetHolePlatingThickness()
1116 * m_boardAdapter.BiuTo3dUnits();
1117
1118 if( platingThickness <= 0.0f || aTopInnerRadius <= 0.0f || aBottomInnerRadius <= 0.0f
1119 || aDepth <= 0.0f )
1120 {
1121 return;
1122 }
1123
1124 const float topOuterRadius = aTopInnerRadius + platingThickness;
1125 const float bottomOuterRadius = aBottomInnerRadius + platingThickness;
1126
1127 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1128 const float zTop = std::max( aSurfaceZ, zOther );
1129 const float zBot = std::min( aSurfaceZ, zOther );
1130
1131 if( topOuterRadius <= 0.0f || bottomOuterRadius <= 0.0f )
1132 return;
1133
1134 const float largestDiameter = 2.0f * std::max( aTopInnerRadius, aBottomInnerRadius );
1135 unsigned int segments = std::max( 12u, m_boardAdapter.GetCircleSegmentCount( largestDiameter ) );
1136
1137 const SFVEC3F copperColor = ConvertSRGBToLinear( m_boardAdapter.m_CopperColor );
1138
1139 auto addQuad = [&]( const SFVEC3F& p0, const SFVEC3F& p1,
1140 const SFVEC3F& p2, const SFVEC3F& p3 )
1141 {
1142 TRIANGLE* tri1 = new TRIANGLE( p0, p1, p2 );
1143 TRIANGLE* tri2 = new TRIANGLE( p0, p2, p3 );
1144
1145 tri1->SetMaterial( &m_materials.m_Copper );
1146 tri2->SetMaterial( &m_materials.m_Copper );
1147 tri1->SetColor( copperColor );
1148 tri2->SetColor( copperColor );
1149
1150 m_objectContainer.Add( tri1 );
1151 m_objectContainer.Add( tri2 );
1152 };
1153
1154 auto makePoint = [&]( float radius, float angle, float z )
1155 {
1156 return SFVEC3F( aCenter.x + cosf( angle ) * radius,
1157 aCenter.y + sinf( angle ) * radius,
1158 z );
1159 };
1160
1161 const float step = 2.0f * glm::pi<float>() / (float) segments;
1162
1163 SFVEC3F innerTopPrev = makePoint( aTopInnerRadius, 0.0f, zTop );
1164 SFVEC3F innerBotPrev = makePoint( aBottomInnerRadius, 0.0f, zBot );
1165 SFVEC3F outerTopPrev = makePoint( topOuterRadius, 0.0f, zTop );
1166 SFVEC3F outerBotPrev = makePoint( bottomOuterRadius, 0.0f, zBot );
1167
1168 const SFVEC3F innerTopFirst = innerTopPrev;
1169 const SFVEC3F innerBotFirst = innerBotPrev;
1170 const SFVEC3F outerTopFirst = outerTopPrev;
1171 const SFVEC3F outerBotFirst = outerBotPrev;
1172
1173 for( unsigned int i = 1; i <= segments; ++i )
1174 {
1175 const float angle = ( i == segments ) ? 0.0f : step * i;
1176
1177 const SFVEC3F innerTopCurr = ( i == segments ) ? innerTopFirst
1178 : makePoint( aTopInnerRadius, angle, zTop );
1179 const SFVEC3F innerBotCurr = ( i == segments ) ? innerBotFirst
1180 : makePoint( aBottomInnerRadius, angle, zBot );
1181 const SFVEC3F outerTopCurr = ( i == segments ) ? outerTopFirst
1182 : makePoint( topOuterRadius, angle, zTop );
1183 const SFVEC3F outerBotCurr = ( i == segments ) ? outerBotFirst
1184 : makePoint( bottomOuterRadius, angle, zBot );
1185
1186 // Inner wall
1187 addQuad( innerTopPrev, innerTopCurr, innerBotCurr, innerBotPrev );
1188
1189 // Outer wall
1190 addQuad( outerTopPrev, outerBotPrev, outerBotCurr, outerTopCurr );
1191
1192 // Top rim
1193 addQuad( outerTopPrev, outerTopCurr, innerTopCurr, innerTopPrev );
1194
1195 // Bottom rim
1196 addQuad( outerBotPrev, innerBotPrev, innerBotCurr, outerBotCurr );
1197
1198 innerTopPrev = innerTopCurr;
1199 innerBotPrev = innerBotCurr;
1200 outerTopPrev = outerTopCurr;
1201 outerBotPrev = outerBotCurr;
1202 }
1203}
1204
1205
1207{
1208 if( !m_boardAdapter.GetBoard() )
1209 return;
1210
1211 const float unitScale = m_boardAdapter.BiuTo3dUnits();
1212 const int platingThickness = m_boardAdapter.GetHolePlatingThickness();
1213 const float platingThickness3d = platingThickness * unitScale;
1214 const SFVEC3F boardColor = ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor );
1215
1216 const float boardZTop = m_boardAdapter.GetLayerBottomZPos( F_Cu );
1217 const float boardZBot = m_boardAdapter.GetLayerBottomZPos( B_Cu );
1218
1219 // Process vias for backdrill and post-machining plugs
1220 for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
1221 {
1222 if( track->Type() != PCB_VIA_T )
1223 continue;
1224
1225 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1226
1227 const float holeDiameter = via->GetDrillValue() * unitScale;
1228 const float holeInnerRadius = holeDiameter / 2.0f;
1229 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1230 const SFVEC2F center( via->GetStart().x * unitScale, -via->GetStart().y * unitScale );
1231
1232 PCB_LAYER_ID topLayer, bottomLayer;
1233 via->LayerPair( &topLayer, &bottomLayer );
1234
1235 const float viaZTop = m_boardAdapter.GetLayerBottomZPos( topLayer );
1236 const float viaZBot = m_boardAdapter.GetLayerBottomZPos( bottomLayer );
1237
1238 // Handle backdrill plugs
1239 const auto secondaryDrillSize = via->GetSecondaryDrillSize();
1240
1241 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
1242 {
1243 const float backdrillRadius = secondaryDrillSize.value() * 0.5f * unitScale;
1244
1245 if( backdrillRadius > holeOuterRadius )
1246 {
1247 PCB_LAYER_ID secStart = via->GetSecondaryDrillStartLayer();
1248 PCB_LAYER_ID secEnd = via->GetSecondaryDrillEndLayer();
1249
1250 // Calculate where the backdrill ends and plug should start
1251 const float secEndZ = m_boardAdapter.GetLayerBottomZPos( secEnd );
1252
1253 float plugZTop, plugZBot;
1254
1255 if( secStart == F_Cu )
1256 {
1257 // Backdrill from top: plug goes from below backdrill end to via bottom
1258 plugZTop = secEndZ;
1259 plugZBot = viaZBot;
1260 }
1261 else
1262 {
1263 // Backdrill from bottom: plug goes from via top to above backdrill end
1264 plugZTop = viaZTop;
1265 plugZBot = secEndZ;
1266 }
1267
1268 if( plugZTop > plugZBot )
1269 {
1270 // Create a ring from holeOuterRadius to backdrillRadius
1271 RING_2D* ring = new RING_2D( center, holeOuterRadius, backdrillRadius, *via );
1273
1274 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, plugZBot, plugZTop );
1275 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1276 objPtr->SetColor( boardColor );
1277 m_objectContainer.Add( objPtr );
1278 }
1279 }
1280 }
1281
1282 // Handle front post-machining plugs
1283 const auto frontMode = via->GetFrontPostMachining();
1284
1285 if( frontMode.has_value()
1287 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
1288 {
1289 const float frontRadius = via->GetFrontPostMachiningSize() * 0.5f * unitScale;
1290 const float frontDepth = via->GetFrontPostMachiningDepth() * unitScale;
1291
1292 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1293 {
1294 // Plug goes from bottom of post-machining to bottom of via
1295 const float pmBottomZ = viaZTop - frontDepth;
1296 const float plugZBot = viaZBot;
1297
1298 if( pmBottomZ > plugZBot )
1299 {
1300 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1301 {
1302 // For countersink, use a frustum (truncated cone)
1303 EDA_ANGLE angle( via->GetFrontPostMachiningAngle(), TENTHS_OF_A_DEGREE_T );
1304 float angleRad = angle.AsRadians();
1305 if( angleRad < 0.01f )
1306 angleRad = 0.01f;
1307
1308 float radialDiff = frontRadius - holeOuterRadius;
1309 float innerHeight = radialDiff / tanf( angleRad );
1310 float totalHeight = pmBottomZ - plugZBot;
1311
1312 if( innerHeight > totalHeight )
1313 innerHeight = totalHeight;
1314
1315 float zInnerTop = plugZBot + innerHeight;
1316
1317 // Create frustum from holeOuterRadius at zInnerTop to frontRadius at pmBottomZ
1318 TRUNCATED_CONE* frustum = new TRUNCATED_CONE( center, zInnerTop, pmBottomZ,
1319 holeOuterRadius, frontRadius );
1320 frustum->SetMaterial( &m_materials.m_EpoxyBoard );
1321 frustum->SetColor( boardColor );
1322 m_objectContainer.Add( frustum );
1323
1324 // If there's a cylindrical portion below the cone
1325 if( zInnerTop > plugZBot )
1326 {
1327 RING_2D* ring = new RING_2D( center, holeOuterRadius, frontRadius, *via );
1329
1330 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, plugZBot, zInnerTop );
1331 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1332 objPtr->SetColor( boardColor );
1333 m_objectContainer.Add( objPtr );
1334 }
1335 }
1336 else
1337 {
1338 RING_2D* ring = new RING_2D( center, holeOuterRadius, frontRadius, *via );
1340
1341 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, plugZBot, pmBottomZ );
1342 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1343 objPtr->SetColor( boardColor );
1344 m_objectContainer.Add( objPtr );
1345 }
1346 }
1347 }
1348 }
1349
1350 // Handle back post-machining plugs
1351 const auto backMode = via->GetBackPostMachining();
1352
1353 if( backMode.has_value()
1355 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
1356 {
1357 const float backRadius = via->GetBackPostMachiningSize() * 0.5f * unitScale;
1358 const float backDepth = via->GetBackPostMachiningDepth() * unitScale;
1359
1360 if( backRadius > holeOuterRadius && backDepth > 0 )
1361 {
1362 // Plug goes from top of via to top of post-machining
1363 const float plugZTop = viaZTop;
1364 const float pmTopZ = viaZBot + backDepth;
1365
1366 if( plugZTop > pmTopZ )
1367 {
1368 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1369 {
1370 // For countersink, use a frustum (truncated cone)
1371 EDA_ANGLE angle( via->GetBackPostMachiningAngle(), TENTHS_OF_A_DEGREE_T );
1372 float angleRad = angle.AsRadians();
1373 if( angleRad < 0.01f )
1374 angleRad = 0.01f;
1375
1376 float radialDiff = backRadius - holeOuterRadius;
1377 float innerHeight = radialDiff / tanf( angleRad );
1378 float totalHeight = plugZTop - pmTopZ;
1379
1380 if( innerHeight > totalHeight )
1381 innerHeight = totalHeight;
1382
1383 float zInnerBot = plugZTop - innerHeight;
1384
1385 // Create frustum from holeOuterRadius at zInnerBot to backRadius at pmTopZ
1386 TRUNCATED_CONE* frustum = new TRUNCATED_CONE( center, pmTopZ, zInnerBot,
1387 backRadius, holeOuterRadius );
1388 frustum->SetMaterial( &m_materials.m_EpoxyBoard );
1389 frustum->SetColor( boardColor );
1390 m_objectContainer.Add( frustum );
1391
1392 // If there's a cylindrical portion above the cone
1393 if( zInnerBot < plugZTop )
1394 {
1395 RING_2D* ring = new RING_2D( center, holeOuterRadius, backRadius, *via );
1397
1398 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, zInnerBot, plugZTop );
1399 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1400 objPtr->SetColor( boardColor );
1401 m_objectContainer.Add( objPtr );
1402 }
1403 }
1404 else
1405 {
1406 RING_2D* ring = new RING_2D( center, holeOuterRadius, backRadius, *via );
1408
1409 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, pmTopZ, plugZTop );
1410 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1411 objPtr->SetColor( boardColor );
1412 m_objectContainer.Add( objPtr );
1413 }
1414 }
1415 }
1416 }
1417 }
1418
1419 // Process pads for post-machining plugs
1420 for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1421 {
1422 for( const PAD* pad : footprint->Pads() )
1423 {
1424 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1425 continue;
1426
1427 if( !pad->HasHole() )
1428 continue;
1429
1430 if( pad->GetDrillShape() != PAD_DRILL_SHAPE::CIRCLE )
1431 continue;
1432
1433 const SFVEC2F padCenter( pad->GetPosition().x * unitScale,
1434 -pad->GetPosition().y * unitScale );
1435 const float holeInnerRadius = pad->GetDrillSize().x * 0.5f * unitScale;
1436 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1437
1438 const float padZTop = boardZTop;
1439 const float padZBot = boardZBot;
1440
1441 // Handle front post-machining plugs for pads
1442 const auto frontMode = pad->GetFrontPostMachining();
1443
1444 if( frontMode.has_value()
1446 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
1447 {
1448 const float frontRadius = pad->GetFrontPostMachiningSize() * 0.5f * unitScale;
1449 const float frontDepth = pad->GetFrontPostMachiningDepth() * unitScale;
1450
1451 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1452 {
1453 const float pmBottomZ = padZTop - frontDepth;
1454 const float plugZBot = padZBot;
1455
1456 if( pmBottomZ > plugZBot )
1457 {
1458 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1459 {
1460 // For countersink, use a frustum (truncated cone)
1461 EDA_ANGLE angle( pad->GetFrontPostMachiningAngle(), TENTHS_OF_A_DEGREE_T );
1462 float angleRad = angle.AsRadians();
1463 if( angleRad < 0.01f )
1464 angleRad = 0.01f;
1465
1466 float radialDiff = frontRadius - holeOuterRadius;
1467 float innerHeight = radialDiff / tanf( angleRad );
1468 float totalHeight = pmBottomZ - plugZBot;
1469
1470 if( innerHeight > totalHeight )
1471 innerHeight = totalHeight;
1472
1473 float zInnerTop = plugZBot + innerHeight;
1474
1475 // Create frustum from holeOuterRadius at zInnerTop to frontRadius at pmBottomZ
1476 TRUNCATED_CONE* frustum = new TRUNCATED_CONE( padCenter, zInnerTop, pmBottomZ,
1477 holeOuterRadius, frontRadius );
1478 frustum->SetMaterial( &m_materials.m_EpoxyBoard );
1479 frustum->SetColor( boardColor );
1480 m_objectContainer.Add( frustum );
1481
1482 // If there's a cylindrical portion below the cone
1483 if( zInnerTop > plugZBot )
1484 {
1485 RING_2D* ring = new RING_2D( padCenter, holeOuterRadius, frontRadius, *pad );
1487
1488 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, plugZBot, zInnerTop );
1489 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1490 objPtr->SetColor( boardColor );
1491 m_objectContainer.Add( objPtr );
1492 }
1493 }
1494 else
1495 {
1496 RING_2D* ring = new RING_2D( padCenter, holeOuterRadius, frontRadius, *pad );
1498
1499 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, plugZBot, pmBottomZ );
1500 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1501 objPtr->SetColor( boardColor );
1502 m_objectContainer.Add( objPtr );
1503 }
1504 }
1505 }
1506 }
1507
1508 // Handle back post-machining plugs for pads
1509 const auto backMode = pad->GetBackPostMachining();
1510
1511 if( backMode.has_value()
1513 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
1514 {
1515 const float backRadius = pad->GetBackPostMachiningSize() * 0.5f * unitScale;
1516 const float backDepth = pad->GetBackPostMachiningDepth() * unitScale;
1517
1518 if( backRadius > holeOuterRadius && backDepth > 0 )
1519 {
1520 const float plugZTop = padZTop;
1521 const float pmTopZ = padZBot + backDepth;
1522
1523 if( plugZTop > pmTopZ )
1524 {
1525 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1526 {
1527 // For countersink, use a frustum (truncated cone)
1528 EDA_ANGLE angle( pad->GetBackPostMachiningAngle(), TENTHS_OF_A_DEGREE_T );
1529 float angleRad = angle.AsRadians();
1530 if( angleRad < 0.01f )
1531 angleRad = 0.01f;
1532
1533 float radialDiff = backRadius - holeOuterRadius;
1534 float innerHeight = radialDiff / tanf( angleRad );
1535 float totalHeight = plugZTop - pmTopZ;
1536
1537 if( innerHeight > totalHeight )
1538 innerHeight = totalHeight;
1539
1540 float zInnerBot = plugZTop - innerHeight;
1541
1542 // Create frustum from holeOuterRadius at zInnerBot to backRadius at pmTopZ
1543 TRUNCATED_CONE* frustum = new TRUNCATED_CONE( padCenter, pmTopZ, zInnerBot,
1544 backRadius, holeOuterRadius );
1545 frustum->SetMaterial( &m_materials.m_EpoxyBoard );
1546 frustum->SetColor( boardColor );
1547 m_objectContainer.Add( frustum );
1548
1549 // If there's a cylindrical portion above the cone
1550 if( zInnerBot < plugZTop )
1551 {
1552 RING_2D* ring = new RING_2D( padCenter, holeOuterRadius, backRadius, *pad );
1554
1555 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, zInnerBot, plugZTop );
1556 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1557 objPtr->SetColor( boardColor );
1558 m_objectContainer.Add( objPtr );
1559 }
1560 }
1561 else
1562 {
1563 RING_2D* ring = new RING_2D( padCenter, holeOuterRadius, backRadius, *pad );
1565
1566 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, pmTopZ, plugZTop );
1567 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
1568 objPtr->SetColor( boardColor );
1569 m_objectContainer.Add( objPtr );
1570 }
1571 }
1572 }
1573 }
1574 }
1575 }
1576}
1577
1578
1580{
1581 if( !m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
1582 return;
1583
1584 PCB_LAYER_ID top_layer, bottom_layer;
1585 int radiusBUI = ( aVia->GetDrillValue() / 2 );
1586
1587 aVia->LayerPair( &top_layer, &bottom_layer );
1588
1589 float frontDepth = 0.0f;
1590 float backDepth = 0.0f;
1591
1593 frontDepth = aVia->Padstack().FrontPostMachining().depth * m_boardAdapter.BiuTo3dUnits();
1594
1596 backDepth = aVia->Padstack().BackPostMachining().depth * m_boardAdapter.BiuTo3dUnits();
1597
1598 float topZ = m_boardAdapter.GetLayerBottomZPos( top_layer )
1599 + m_boardAdapter.GetFrontCopperThickness() - frontDepth;
1600
1601 float botZ = m_boardAdapter.GetLayerBottomZPos( bottom_layer )
1602 - m_boardAdapter.GetBackCopperThickness() + backDepth;
1603
1604 const float unitScale = m_boardAdapter.BiuTo3dUnits();
1605 const SFVEC2F center = SFVEC2F( aVia->GetStart().x * unitScale, -aVia->GetStart().y * unitScale );
1606
1607 RING_2D* ring = new RING_2D( center, radiusBUI * unitScale,
1608 ( radiusBUI + m_boardAdapter.GetHolePlatingThickness() ) * unitScale, *aVia );
1609
1611
1612 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, topZ, botZ );
1613
1614 objPtr->SetMaterial( &m_materials.m_Copper );
1615 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_CopperColor ) );
1616
1617 m_objectContainer.Add( objPtr );
1618
1619 const float holeInnerRadius = radiusBUI * unitScale;
1620 const float frontSurface = topZ + frontDepth;
1621 const float backSurface = botZ - backDepth;
1622
1623 const PAD_DRILL_POST_MACHINING_MODE frontMode =
1625 const float frontRadius = 0.5f * aVia->GetFrontPostMachiningSize() * unitScale;
1626
1627 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1628 {
1630 {
1631 addCounterborePlating( *aVia, center, frontRadius, frontDepth, frontSurface, true );
1632 }
1633 else if( frontMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1634 {
1635 addCountersinkPlating( center, frontRadius, holeInnerRadius, frontSurface, frontDepth,
1636 true );
1637 }
1638 }
1639
1640 const PAD_DRILL_POST_MACHINING_MODE backMode =
1642 const float backRadius = 0.5f * aVia->GetBackPostMachiningSize() * unitScale;
1643
1644 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1645 {
1647 {
1648 addCounterborePlating( *aVia, center, backRadius, backDepth, backSurface, false );
1649 }
1650 else if( backMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1651 {
1652 addCountersinkPlating( center, backRadius, holeInnerRadius, backSurface, backDepth,
1653 false );
1654 }
1655 }
1656}
1657
1658
1660{
1661 if( !m_boardAdapter.m_Cfg->m_Render.show_plated_barrels )
1662 return;
1663
1664 const OBJECT_2D* object2d_A = nullptr;
1665
1666 SFVEC3F objColor = m_boardAdapter.m_CopperColor;
1667 const VECTOR2I drillsize = aPad->GetDrillSize();
1668 const bool hasHole = drillsize.x && drillsize.y;
1669 const float unitScale = m_boardAdapter.BiuTo3dUnits();
1670 const bool isRoundHole = drillsize.x == drillsize.y;
1671 SFVEC2F holeCenter = SFVEC2F( 0.0f, 0.0f );
1672 float holeInnerRadius = 0.0f;
1673
1674 if( !hasHole )
1675 return;
1676
1677 CONST_LIST_OBJECT2D antiOutlineIntersectionList;
1678
1679 float frontDepth = 0.0f;
1680 float backDepth = 0.0f;
1681
1683 frontDepth = aPad->GetFrontPostMachiningDepth() * m_boardAdapter.BiuTo3dUnits();
1684
1686 backDepth = aPad->GetBackPostMachiningDepth() * m_boardAdapter.BiuTo3dUnits();
1687
1688 const float topZ = m_boardAdapter.GetLayerBottomZPos( F_Cu )
1689 + m_boardAdapter.GetFrontCopperThickness() * 0.99f - frontDepth;
1690
1691 const float botZ = m_boardAdapter.GetLayerBottomZPos( B_Cu )
1692 - m_boardAdapter.GetBackCopperThickness() * 0.99f + backDepth;
1693
1694 if( isRoundHole ) // usual round hole
1695 {
1696 holeCenter = SFVEC2F( aPad->GetPosition().x * unitScale,
1697 -aPad->GetPosition().y * unitScale );
1698
1699 int innerRadius = drillsize.x / 2;
1700 int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThickness();
1701 holeInnerRadius = innerRadius * unitScale;
1702
1703 RING_2D* ring = new RING_2D( holeCenter, innerRadius * unitScale,
1704 outerRadius * unitScale, *aPad );
1705
1707
1708 object2d_A = ring;
1709
1710 // If the object (ring) is intersected by an antioutline board,
1711 // it will use instead a CSG of two circles.
1712 if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1713 {
1714 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
1715 antiOutlineIntersectionList );
1716 }
1717
1718 if( !antiOutlineIntersectionList.empty() )
1719 {
1720 FILLED_CIRCLE_2D* innerCircle = new FILLED_CIRCLE_2D(
1721 holeCenter, innerRadius * unitScale, *aPad );
1722
1723 FILLED_CIRCLE_2D* outterCircle = new FILLED_CIRCLE_2D(
1724 holeCenter, outerRadius * unitScale, *aPad );
1725 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1726 object2d_B->push_back( innerCircle );
1727
1728 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( outterCircle, object2d_B, CSGITEM_FULL,
1729 *aPad );
1730
1731 m_containerWithObjectsToDelete.Add( itemCSG2d );
1732 m_containerWithObjectsToDelete.Add( innerCircle );
1733 m_containerWithObjectsToDelete.Add( outterCircle );
1734
1735 object2d_A = itemCSG2d;
1736 }
1737 }
1738 else // Oblong hole
1739 {
1740 VECTOR2I ends_offset;
1741 int width;
1742
1743 if( drillsize.x > drillsize.y ) // Horizontal oval
1744 {
1745 ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
1746 width = drillsize.y;
1747 }
1748 else // Vertical oval
1749 {
1750 ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
1751 width = drillsize.x;
1752 }
1753
1754 RotatePoint( ends_offset, aPad->GetOrientation() );
1755
1756 VECTOR2I start = VECTOR2I( aPad->GetPosition() ) + ends_offset;
1757 VECTOR2I end = VECTOR2I( aPad->GetPosition() ) - ends_offset;
1758
1759 ROUND_SEGMENT_2D* innerSeg =
1760 new ROUND_SEGMENT_2D( SFVEC2F( start.x * unitScale,
1761 -start.y * unitScale ),
1762 SFVEC2F( end.x * unitScale,
1763 -end.y * unitScale ),
1764 width * unitScale, *aPad );
1765
1766 ROUND_SEGMENT_2D* outerSeg =
1767 new ROUND_SEGMENT_2D( SFVEC2F( start.x * unitScale,
1768 -start.y * unitScale ),
1769 SFVEC2F( end.x * unitScale,
1770 -end.y * unitScale ),
1771 ( width + m_boardAdapter.GetHolePlatingThickness() * 2 )
1772 * unitScale, *aPad );
1773
1774 // NOTE: the round segment width is the "diameter", so we double the thickness
1775 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1776 object2d_B->push_back( innerSeg );
1777
1778 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( outerSeg, object2d_B, CSGITEM_FULL, *aPad );
1779
1780 m_containerWithObjectsToDelete.Add( itemCSG2d );
1781 m_containerWithObjectsToDelete.Add( innerSeg );
1782 m_containerWithObjectsToDelete.Add( outerSeg );
1783
1784 object2d_A = itemCSG2d;
1785
1786 if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1787 {
1788 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
1789 antiOutlineIntersectionList );
1790 }
1791 }
1792
1793 if( object2d_A )
1794 {
1795 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1796
1797 // Check if there are any other THT that intersects this hole
1798 // It will use the non inflated holes
1799 if( !m_boardAdapter.GetTH_IDs().GetList().empty() )
1800 {
1801 CONST_LIST_OBJECT2D intersecting;
1802
1803 m_boardAdapter.GetTH_IDs().GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
1804
1805 for( const OBJECT_2D* hole2d : intersecting )
1806 {
1807 if( object2d_A->Intersects( hole2d->GetBBox() ) )
1808 object2d_B->push_back( hole2d );
1809 }
1810 }
1811
1812 for( const OBJECT_2D* obj : antiOutlineIntersectionList )
1813 object2d_B->push_back( obj );
1814
1815 if( object2d_B->empty() )
1816 {
1817 delete object2d_B;
1818 object2d_B = CSGITEM_EMPTY;
1819 }
1820
1821 if( object2d_B == CSGITEM_EMPTY )
1822 {
1823 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, topZ, botZ );
1824
1825 objPtr->SetMaterial( &m_materials.m_Copper );
1826 objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1827 m_objectContainer.Add( objPtr );
1828 }
1829 else
1830 {
1831 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, CSGITEM_FULL,
1832 *aPad );
1833
1834 m_containerWithObjectsToDelete.Add( itemCSG2d );
1835
1836 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, topZ, botZ );
1837
1838 objPtr->SetMaterial( &m_materials.m_Copper );
1839 objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1840
1841 m_objectContainer.Add( objPtr );
1842 }
1843 }
1844
1845 if( object2d_A && isRoundHole )
1846 {
1847 const float frontSurface = topZ + frontDepth;
1848 const float backSurface = botZ - backDepth;
1849
1850 const PAD_DRILL_POST_MACHINING_MODE frontMode =
1852 const float frontRadius = 0.5f * aPad->GetFrontPostMachiningSize() * unitScale;
1853
1854 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1855 {
1857 {
1858 addCounterborePlating( *aPad, holeCenter, frontRadius, frontDepth, frontSurface,
1859 true );
1860 }
1861 else if( frontMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1862 {
1863 addCountersinkPlating( holeCenter, frontRadius, holeInnerRadius, frontSurface,
1864 frontDepth, true );
1865 }
1866 }
1867
1868 const PAD_DRILL_POST_MACHINING_MODE backMode =
1870 const float backRadius = 0.5f * aPad->GetBackPostMachiningSize() * unitScale;
1871
1872 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1873 {
1875 {
1876 addCounterborePlating( *aPad, holeCenter, backRadius, backDepth, backSurface,
1877 false );
1878 }
1879 else if( backMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
1880 {
1881 addCountersinkPlating( holeCenter, backRadius, holeInnerRadius, backSurface,
1882 backDepth, false );
1883 }
1884 }
1885 }
1886}
1887
1888
1890{
1891 if( !m_boardAdapter.GetBoard() )
1892 return;
1893
1894 // Insert plated vertical holes inside the board
1895
1896 // Insert vias holes (vertical cylinders)
1897 for( PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
1898 {
1899 if( track->Type() == PCB_VIA_T )
1900 {
1901 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1902 insertHole( via );
1903 }
1904 }
1905
1906 // Insert pads holes (vertical cylinders)
1907 for( FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1908 {
1909 for( PAD* pad : footprint->Pads() )
1910 {
1911 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
1912 insertHole( pad );
1913 }
1914 }
1915}
1916
1917
1919 const glm::mat4& aFpMatrix, bool aHasExtrudedBody )
1920{
1921 if( aHasExtrudedBody )
1922 return;
1923
1924 BOX2I localBox = CalcPlaceholderLocalBox( aFootprint );
1925
1926 float bboxW = std::abs( localBox.GetWidth() ) / pcbIUScale.IU_PER_MM * 0.9f;
1927 float bboxH = std::abs( localBox.GetHeight() ) / pcbIUScale.IU_PER_MM * 0.9f;
1928 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1929
1930 VECTOR2I localCenter = localBox.GetCenter();
1931 float offsetX = localCenter.x / pcbIUScale.IU_PER_MM;
1932 float offsetY = -localCenter.y / pcbIUScale.IU_PER_MM;
1933
1934 if( aFootprint->IsFlipped() )
1935 offsetY = -offsetY;
1936
1937 SFVEC3F boxMin( offsetX - bboxW * 0.5f, offsetY - bboxH * 0.5f, 0.0f );
1938 SFVEC3F boxMax( offsetX + bboxW * 0.5f, offsetY + bboxH * 0.5f, scaleZ );
1939
1940 BBOX_3D worldBBox;
1941 worldBBox.Reset();
1942
1943 for( int i = 0; i < 8; ++i )
1944 {
1945 SFVEC3F corner( ( i & 1 ) ? boxMax.x : boxMin.x, ( i & 2 ) ? boxMax.y : boxMin.y,
1946 ( i & 4 ) ? boxMax.z : boxMin.z );
1947
1948 glm::vec4 transformed = aFpMatrix * glm::vec4( corner, 1.0f );
1949 worldBBox.Union( SFVEC3F( transformed ) );
1950 }
1951
1952 DUMMY_BLOCK* placeholder = new DUMMY_BLOCK( worldBBox );
1953 placeholder->SetBoardItem( const_cast<FOOTPRINT*>( aFootprint ) );
1954 placeholder->SetMaterial( &m_materials.m_EpoxyBoard );
1955 placeholder->SetColor( SFVEC3F( 1.0f, 0.5f, 0.0f ) );
1956
1957 aDstContainer.Add( placeholder );
1958}
1959
1960
1961static size_t addOutlineToRaytracerObjects( CONTAINER_2D& aObjContainer, const SHAPE_POLY_SET& aOutline, float aBiuTo3d,
1962 const BOARD_ITEM& aBoardItem )
1963{
1964 size_t added = 0;
1965
1966 for( int oi = 0; oi < aOutline.OutlineCount(); oi++ )
1967 {
1968 const SHAPE_LINE_CHAIN& chain = aOutline.COutline( oi );
1969
1970 if( chain.PointCount() < 3 )
1971 continue;
1972
1973 // Convert points to 3D-scaled coordinates
1974 SEGMENTS_WIDTH_NORMALS segNormals;
1975 SFVEC2F prevPt;
1976
1977 for( int i = 0; i < chain.PointCount(); i++ )
1978 {
1979 const VECTOR2I& a = chain.CPoint( i );
1980 SFVEC2F pt( (float) a.x * aBiuTo3d, (float) ( -a.y ) * aBiuTo3d );
1981
1982 if( ( i == 0 ) || ( fabs( prevPt.x - pt.x ) > FLT_EPSILON ) || ( fabs( prevPt.y - pt.y ) > FLT_EPSILON ) )
1983 {
1984 prevPt = pt;
1985
1987 sn.m_Start = pt;
1988 segNormals.push_back( sn );
1989 }
1990 }
1991
1992 // Build side-wall
1993 if( segNormals.size() >= 3 )
1994 {
1995 std::vector<SFVEC2F> tmpNormals( segNormals.size() );
1996 unsigned int j = segNormals.size() - 1;
1997
1998 for( unsigned int i = 0; i < segNormals.size(); j = i++ )
1999 {
2000 SFVEC2F slope = segNormals[j].m_Start - segNormals[i].m_Start;
2001 segNormals[i].m_Precalc_slope = slope;
2002 tmpNormals[i] = glm::normalize( SFVEC2F( slope.y, -slope.x ) );
2003 }
2004
2005 j = segNormals.size() - 1;
2006
2007 for( unsigned int i = 0; i < segNormals.size(); j = i++ )
2008 {
2009 const SFVEC2F& nBefore = tmpNormals[j];
2010 const SFVEC2F& nCur = tmpNormals[i];
2011 const SFVEC2F& nAfter = tmpNormals[( i + 1 ) % segNormals.size()];
2012
2013 float dotBefore = glm::dot( nBefore, nCur );
2014 float dotAfter = glm::dot( nAfter, nCur );
2015
2016 segNormals[i].m_Normals.m_Start =
2017 ( dotBefore < 0.7f ) ? nCur : glm::normalize( nBefore * dotBefore + nCur );
2018 segNormals[i].m_Normals.m_End = ( dotAfter < 0.7f ) ? nCur : glm::normalize( nAfter * dotAfter + nCur );
2019 }
2020
2021 SEGMENTS capSegments( segNormals.size() );
2022
2023 for( unsigned int i = 0; i < segNormals.size(); i++ )
2024 capSegments[i].m_Start = segNormals[i].m_Start;
2025
2026 j = capSegments.size() - 1;
2027
2028 for( unsigned int i = 0; i < capSegments.size(); j = i++ )
2029 {
2030 capSegments[i].m_inv_JY_minus_IY = 1.0f / ( capSegments[j].m_Start.y - capSegments[i].m_Start.y );
2031 capSegments[i].m_JX_minus_IX = capSegments[j].m_Start.x - capSegments[i].m_Start.x;
2032 }
2033
2034 OUTERS_AND_HOLES outersAndHoles;
2035 outersAndHoles.m_Outers.push_back( capSegments );
2036
2037 aObjContainer.Add( new POLYGON_2D( segNormals, outersAndHoles, aBoardItem ) );
2038 added++;
2039 }
2040 }
2041
2042 // top/bottom caps
2043 size_t prevSize = aObjContainer.GetList().size();
2044 ConvertPolygonToTriangles( aOutline, aObjContainer, aBiuTo3d, aBoardItem );
2045 added += aObjContainer.GetList().size() - prevSize;
2046
2047 return added;
2048}
2049
2050
2052{
2053 SHAPE_POLY_SET outline;
2054
2055 if( !GetExtrusionOutline( aFootprint, outline ) )
2056 return false;
2057
2058 if( outline.OutlineCount() == 0 )
2059 return false;
2060
2061 outline.Simplify();
2062
2063 const EXTRUDED_3D_BODY* body = aFootprint->GetExtrudedBody();
2064 const float biuTo3d = m_boardAdapter.BiuTo3dUnits();
2065
2066 VECTOR2I fpPos = aFootprint->GetPosition();
2067 ApplyExtrusionTransform( outline, body, fpPos );
2068
2069 bool isBack = aFootprint->IsFlipped();
2070 float boardSurfaceZ = m_boardAdapter.GetFootprintZPos( isBack );
2071 float standoff3d = body->m_standoff * biuTo3d;
2072 float bodyThickness = ( body->m_height - body->m_standoff ) * biuTo3d * body->m_scale.z;
2073 float zOffset3d = pcbIUScale.mmToIU( body->m_offset.z ) * biuTo3d;
2074
2075 float zBot, zTop;
2076
2077 if( !isBack )
2078 {
2079 zBot = boardSurfaceZ + standoff3d + zOffset3d;
2080 zTop = zBot + bodyThickness;
2081 }
2082 else
2083 {
2084 zTop = boardSurfaceZ - standoff3d - zOffset3d;
2085 zBot = zTop - bodyThickness;
2086 }
2087
2088 KIGFX::COLOR4D c = body->m_color;
2089
2092
2093 SFVEC3F objColor = ConvertSRGBToLinear( SFVEC3F( c.r, c.g, c.b ) );
2094
2095 // Build body 2D objects (side walls + caps)
2096 outline.Fracture();
2097
2098 const LIST_OBJECT2D& objList = m_containerWithObjectsToDelete.GetList();
2099 size_t prevCount = objList.size();
2100
2101 addOutlineToRaytracerObjects( m_containerWithObjectsToDelete, outline, biuTo3d, *aFootprint );
2102
2103 EXTRUSION_MATERIAL_PROPS props = GetMaterialProps( body->m_material, objColor );
2104
2105 m_extrusionMaterials.push_back( std::make_unique<BLINN_PHONG_MATERIAL>(
2106 props.m_Ambient, SFVEC3F( 0.0f ), props.m_Specular, props.m_Shininess, 0.0f, 0.0f ) );
2107
2108 const MATERIAL* bodyMaterial = m_extrusionMaterials.back().get();
2109
2110 auto it = objList.begin();
2111 std::advance( it, prevCount );
2112
2113 for( ; it != objList.end(); ++it )
2114 {
2115 LAYER_ITEM* layerItem = new LAYER_ITEM( *it, zBot, zTop );
2116 layerItem->SetBoardItem( const_cast<FOOTPRINT*>( aFootprint ) );
2117 layerItem->SetMaterial( bodyMaterial );
2118 layerItem->SetColor( objColor );
2119 aDstContainer.Add( layerItem );
2120 }
2121
2122 // Create metallic pin extrusions for THT pads (from opposite board side to standoff height)
2123 if( standoff3d > 0.0f )
2124 {
2125 SHAPE_POLY_SET pinPoly;
2126
2127 if( GetExtrusionPinOutline( aFootprint, pinPoly ) )
2128 {
2129 ApplyExtrusionTransform( pinPoly, body, fpPos );
2130
2131 float oppositeSurfaceZ = m_boardAdapter.GetFootprintZPos( !isBack );
2132 float protrusion = 1.0f * pcbIUScale.IU_PER_MM * biuTo3d;
2133 float pinZBot, pinZTop;
2134
2135 if( !isBack )
2136 {
2137 pinZBot = oppositeSurfaceZ - protrusion;
2138 pinZTop = boardSurfaceZ + standoff3d;
2139 }
2140 else
2141 {
2142 pinZTop = oppositeSurfaceZ + protrusion;
2143 pinZBot = boardSurfaceZ - standoff3d;
2144 }
2145
2146 SFVEC3F metalColor = ConvertSRGBToLinear( SFVEC3F( 0.75f, 0.75f, 0.75f ) );
2147
2148 pinPoly.Fracture();
2149
2150 size_t prevPinCount = objList.size();
2151
2152 addOutlineToRaytracerObjects( m_containerWithObjectsToDelete, pinPoly, biuTo3d, *aFootprint );
2153
2154 // Wrap pin objects with material and Z extents
2155 auto pinIt = objList.begin();
2156 std::advance( pinIt, prevPinCount );
2157
2158 for( ; pinIt != objList.end(); ++pinIt )
2159 {
2160 LAYER_ITEM* layerItem = new LAYER_ITEM( *pinIt, pinZBot, pinZTop );
2161 layerItem->SetBoardItem( const_cast<FOOTPRINT*>( aFootprint ) );
2162 layerItem->SetMaterial( &m_materials.m_Copper );
2163 layerItem->SetColor( metalColor );
2164 aDstContainer.Add( layerItem );
2165 }
2166 }
2167 }
2168
2169 return true;
2170}
2171
2172
2174 bool aSkipMaterialInformation )
2175{
2176 if( !m_boardAdapter.GetBoard() )
2177 return;
2178
2179 if( !m_boardAdapter.m_IsPreviewer
2180 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
2181 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
2182 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
2183 {
2184 return;
2185 }
2186
2187 // Go for all footprints
2188 for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
2189 {
2190 bool hasModels = !fp->Models().empty();
2191 bool showMissing = m_boardAdapter.m_Cfg->m_Render.show_missing_models;
2192
2193 // Placeholder is suppressed when an extrusion was built.
2194 bool hasExtrudedBody = false;
2195
2196 if( fp->HasExtrudedBody() && fp->GetExtrudedBody()->m_show && m_boardAdapter.IsFootprintShown( fp ) )
2197 hasExtrudedBody = addExtrudedBodyToRaytracer( aDstContainer, fp );
2198
2199 if( ( hasModels || showMissing ) && m_boardAdapter.IsFootprintShown( fp ) )
2200 {
2201 double zpos = m_boardAdapter.GetFootprintZPos( fp->IsFlipped() );
2202
2203 VECTOR2I pos = fp->GetPosition();
2204
2205 glm::mat4 fpMatrix = glm::mat4( 1.0f );
2206
2207 fpMatrix = glm::translate( fpMatrix,
2208 SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
2209 -pos.y * m_boardAdapter.BiuTo3dUnits(),
2210 zpos ) );
2211
2212 if( !fp->GetOrientation().IsZero() )
2213 {
2214 fpMatrix = glm::rotate( fpMatrix, (float) fp->GetOrientation().AsRadians(),
2215 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2216 }
2217
2218 if( fp->IsFlipped() )
2219 {
2220 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2221
2222 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2223 }
2224
2225 const double modelunit_to_3d_units_factor =
2226 m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
2227
2228 fpMatrix = glm::scale(
2229 fpMatrix, SFVEC3F( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
2230 modelunit_to_3d_units_factor ) );
2231
2232 // Get the list of model files for this model
2233 S3D_CACHE* cacheMgr = m_boardAdapter.Get3dCacheManager();
2234
2235 wxString libraryName = fp->GetFPID().GetLibNickname();
2236
2237 wxString footprintBasePath = wxEmptyString;
2238
2239 if( m_boardAdapter.GetBoard()->GetProject() )
2240 {
2241 try
2242 {
2243 // FindRow() can throw an exception
2244 std::optional<LIBRARY_TABLE_ROW*> fpRow =
2245 PROJECT_PCB::FootprintLibAdapter( m_boardAdapter.GetBoard()->GetProject() )
2246 ->GetRow( libraryName );
2247
2248 if( fpRow )
2249 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *fpRow, true );
2250 }
2251 catch( ... )
2252 {
2253 // Do nothing if the libraryName is not found in lib table
2254 }
2255 }
2256
2257 for( FP_3DMODEL& model : fp->Models() )
2258 {
2259 if( !model.m_Show || model.m_Filename.empty() )
2260 continue;
2261
2262 // get it from cache
2263 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
2264 embeddedFilesStack.push_back( fp->GetEmbeddedFiles() );
2265 embeddedFilesStack.push_back( m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
2266
2267 const S3DMODEL* modelPtr = cacheMgr->GetModel( model.m_Filename, footprintBasePath,
2268 std::move( embeddedFilesStack ) );
2269
2270 // only add it if the return is not NULL.
2271 if( modelPtr )
2272 {
2273 glm::mat4 modelMatrix = fpMatrix;
2274
2275 modelMatrix = glm::translate( modelMatrix,
2276 SFVEC3F( model.m_Offset.x, model.m_Offset.y, model.m_Offset.z ) );
2277
2278 modelMatrix = glm::rotate( modelMatrix,
2279 (float) -( model.m_Rotation.z / 180.0f ) * glm::pi<float>(),
2280 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2281
2282 modelMatrix = glm::rotate( modelMatrix,
2283 (float) -( model.m_Rotation.y / 180.0f ) * glm::pi<float>(),
2284 SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2285
2286 modelMatrix = glm::rotate( modelMatrix,
2287 (float) -( model.m_Rotation.x / 180.0f ) * glm::pi<float>(),
2288 SFVEC3F( 1.0f, 0.0f, 0.0f ) );
2289
2290 modelMatrix = glm::scale( modelMatrix,
2291 SFVEC3F( model.m_Scale.x, model.m_Scale.y, model.m_Scale.z ) );
2292
2293 addModels( aDstContainer, modelPtr, modelMatrix, (float) model.m_Opacity,
2294 aSkipMaterialInformation, fp );
2295 }
2296 else if( showMissing )
2297 {
2298 addPlaceholderToRaytracer( aDstContainer, fp, fpMatrix, hasExtrudedBody );
2299 }
2300 }
2301
2302 // Footprint with no models assigned at all
2303 if( !hasModels && showMissing )
2304 {
2305 addPlaceholderToRaytracer( aDstContainer, fp, fpMatrix, hasExtrudedBody );
2306 }
2307 }
2308 }
2309}
2310
2311
2313{
2314 MODEL_MATERIALS* materialVector;
2315
2316 // Try find if the materials already exists in the map list
2317 if( m_modelMaterialMap.find( a3DModel ) != m_modelMaterialMap.end() )
2318 {
2319 // Found it, so get the pointer
2320 materialVector = &m_modelMaterialMap[a3DModel];
2321 }
2322 else
2323 {
2324 // Materials was not found in the map, so it will create a new for
2325 // this model.
2326
2327 m_modelMaterialMap[a3DModel] = MODEL_MATERIALS();
2328 materialVector = &m_modelMaterialMap[a3DModel];
2329
2330 materialVector->resize( a3DModel->m_MaterialsSize );
2331
2332 for( unsigned int imat = 0; imat < a3DModel->m_MaterialsSize; ++imat )
2333 {
2334 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::NORMAL )
2335 {
2336 const SMATERIAL& material = a3DModel->m_Materials[imat];
2337
2338 // http://www.fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJtaW4oc3FydCh4LTAuMzUpKjAuNDAtMC4wNSwxLjApIiwiY29sb3IiOiIjMDAwMDAwIn0seyJ0eXBlIjoxMDAwLCJ3aW5kb3ciOlsiMC4wNzA3NzM2NzMyMzY1OTAxMiIsIjEuNTY5NTcxNjI5MjI1NDY5OCIsIi0wLjI3NDYzNTMyMTc1OTkyOTMiLCIwLjY0NzcwMTg4MTkyNTUzNjIiXSwic2l6ZSI6WzY0NCwzOTRdfV0-
2339
2340 float reflectionFactor = 0.0f;
2341
2342 if( ( material.m_Shininess - 0.35f ) > FLT_EPSILON )
2343 {
2344 reflectionFactor = glm::clamp(
2345 glm::sqrt( ( material.m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
2346 0.5f );
2347 }
2348
2349 BLINN_PHONG_MATERIAL& blinnMaterial = ( *materialVector )[imat];
2350
2351 blinnMaterial = BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( material.m_Ambient ),
2352 ConvertSRGBToLinear( material.m_Emissive ),
2353 ConvertSRGBToLinear( material.m_Specular ), material.m_Shininess * 180.0f,
2354 material.m_Transparency, reflectionFactor );
2355
2356 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
2357 {
2358 // Guess material type and apply a normal perturbator
2359 if( ( RGBtoGray( material.m_Diffuse ) < 0.3f )
2360 && ( material.m_Shininess < 0.36f )
2361 && ( material.m_Transparency == 0.0f )
2362 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) < 0.15f )
2363 && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
2364 < 0.15f )
2365 && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
2366 < 0.15f ) ) )
2367 {
2368 // This may be a black plastic..
2369 blinnMaterial.SetGenerator( &m_plasticMaterial );
2370 }
2371 else
2372 {
2373 if( ( RGBtoGray( material.m_Diffuse ) > 0.3f )
2374 && ( material.m_Shininess < 0.30f )
2375 && ( material.m_Transparency == 0.0f )
2376 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) > 0.25f )
2377 || ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g ) > 0.25f )
2378 || ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
2379 > 0.25f ) ) )
2380 {
2381 // This may be a color plastic ...
2382 blinnMaterial.SetGenerator( &m_shinyPlasticMaterial );
2383 }
2384 else
2385 {
2386 if( ( RGBtoGray( material.m_Diffuse ) > 0.6f )
2387 && ( material.m_Shininess > 0.35f )
2388 && ( material.m_Transparency == 0.0f )
2389 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g )
2390 < 0.40f )
2391 && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
2392 < 0.40f )
2393 && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
2394 < 0.40f ) ) )
2395 {
2396 // This may be a brushed metal
2397 blinnMaterial.SetGenerator( &m_brushedMetalMaterial );
2398 }
2399 }
2400 }
2401 }
2402 }
2403 else
2404 {
2405 ( *materialVector )[imat] = BLINN_PHONG_MATERIAL(
2406 SFVEC3F( 0.2f ), SFVEC3F( 0.0f ), SFVEC3F( 0.0f ), 0.0f, 0.0f, 0.0f );
2407 }
2408 }
2409 }
2410
2411 return materialVector;
2412}
2413
2414
2415void RENDER_3D_RAYTRACE_BASE::addModels( CONTAINER_3D& aDstContainer, const S3DMODEL* a3DModel,
2416 const glm::mat4& aModelMatrix, float aFPOpacity,
2417 bool aSkipMaterialInformation, BOARD_ITEM* aBoardItem )
2418{
2419 // Validate a3DModel pointers
2420 wxASSERT( a3DModel != nullptr );
2421
2422 if( a3DModel == nullptr )
2423 return;
2424
2425 wxASSERT( a3DModel->m_Materials != nullptr );
2426 wxASSERT( a3DModel->m_Meshes != nullptr );
2427 wxASSERT( a3DModel->m_MaterialsSize > 0 );
2428 wxASSERT( a3DModel->m_MeshesSize > 0 );
2429
2430 if( aFPOpacity > 1.0f )
2431 aFPOpacity = 1.0f;
2432
2433 if( aFPOpacity < 0.0f )
2434 aFPOpacity = 0.0f;
2435
2436 if( ( a3DModel->m_Materials != nullptr ) && ( a3DModel->m_Meshes != nullptr )
2437 && ( a3DModel->m_MaterialsSize > 0 ) && ( a3DModel->m_MeshesSize > 0 ) )
2438 {
2439 MODEL_MATERIALS* materialVector = nullptr;
2440
2441 if( !aSkipMaterialInformation )
2442 {
2443 materialVector = getModelMaterial( a3DModel );
2444 }
2445
2446 const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
2447
2448 for( unsigned int mesh_i = 0; mesh_i < a3DModel->m_MeshesSize; ++mesh_i )
2449 {
2450 const SMESH& mesh = a3DModel->m_Meshes[mesh_i];
2451
2452 // Validate the mesh pointers
2453 wxASSERT( mesh.m_Positions != nullptr );
2454 wxASSERT( mesh.m_FaceIdx != nullptr );
2455 wxASSERT( mesh.m_Normals != nullptr );
2456 wxASSERT( mesh.m_FaceIdxSize > 0 );
2457 wxASSERT( ( mesh.m_FaceIdxSize % 3 ) == 0 );
2458
2459
2460 if( ( mesh.m_Positions != nullptr ) && ( mesh.m_Normals != nullptr )
2461 && ( mesh.m_FaceIdx != nullptr ) && ( mesh.m_FaceIdxSize > 0 )
2462 && ( mesh.m_VertexSize > 0 ) && ( ( mesh.m_FaceIdxSize % 3 ) == 0 )
2463 && ( mesh.m_MaterialIdx < a3DModel->m_MaterialsSize ) )
2464 {
2465 float fpTransparency;
2466 const BLINN_PHONG_MATERIAL* blinn_material;
2467
2468 if( !aSkipMaterialInformation )
2469 {
2470 blinn_material = &( *materialVector )[mesh.m_MaterialIdx];
2471
2472 fpTransparency =
2473 1.0f - ( ( 1.0f - blinn_material->GetTransparency() ) * aFPOpacity );
2474 }
2475
2476 // Add all face triangles
2477 for( unsigned int faceIdx = 0; faceIdx < mesh.m_FaceIdxSize; faceIdx += 3 )
2478 {
2479 const unsigned int idx0 = mesh.m_FaceIdx[faceIdx + 0];
2480 const unsigned int idx1 = mesh.m_FaceIdx[faceIdx + 1];
2481 const unsigned int idx2 = mesh.m_FaceIdx[faceIdx + 2];
2482
2483 wxASSERT( idx0 < mesh.m_VertexSize );
2484 wxASSERT( idx1 < mesh.m_VertexSize );
2485 wxASSERT( idx2 < mesh.m_VertexSize );
2486
2487 if( ( idx0 < mesh.m_VertexSize ) && ( idx1 < mesh.m_VertexSize )
2488 && ( idx2 < mesh.m_VertexSize ) )
2489 {
2490 const SFVEC3F& v0 = mesh.m_Positions[idx0];
2491 const SFVEC3F& v1 = mesh.m_Positions[idx1];
2492 const SFVEC3F& v2 = mesh.m_Positions[idx2];
2493
2494 const SFVEC3F& n0 = mesh.m_Normals[idx0];
2495 const SFVEC3F& n1 = mesh.m_Normals[idx1];
2496 const SFVEC3F& n2 = mesh.m_Normals[idx2];
2497
2498 // Transform vertex with the model matrix
2499 const SFVEC3F vt0 = SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
2500 const SFVEC3F vt1 = SFVEC3F( aModelMatrix * glm::vec4( v1, 1.0f ) );
2501 const SFVEC3F vt2 = SFVEC3F( aModelMatrix * glm::vec4( v2, 1.0f ) );
2502
2503 const SFVEC3F nt0 = glm::normalize( SFVEC3F( normalMatrix * n0 ) );
2504 const SFVEC3F nt1 = glm::normalize( SFVEC3F( normalMatrix * n1 ) );
2505 const SFVEC3F nt2 = glm::normalize( SFVEC3F( normalMatrix * n2 ) );
2506
2507 TRIANGLE* newTriangle = new TRIANGLE( vt0, vt2, vt1, nt0, nt2, nt1 );
2508
2509 newTriangle->SetBoardItem( aBoardItem );
2510
2511 aDstContainer.Add( newTriangle );
2512
2513 if( !aSkipMaterialInformation )
2514 {
2515 newTriangle->SetMaterial( blinn_material );
2516 newTriangle->SetModelTransparency( fpTransparency );
2517
2518 if( mesh.m_Color == nullptr )
2519 {
2520 const SFVEC3F diffuseColor =
2521 a3DModel->m_Materials[mesh.m_MaterialIdx].m_Diffuse;
2522
2523 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::CAD_MODE )
2524 newTriangle->SetColor( ConvertSRGBToLinear(
2525 MaterialDiffuseToColorCAD( diffuseColor ) ) );
2526 else
2527 newTriangle->SetColor( ConvertSRGBToLinear( diffuseColor ) );
2528 }
2529 else
2530 {
2531 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::CAD_MODE )
2532 {
2533 newTriangle->SetColor(
2535 mesh.m_Color[idx0] ) ),
2537 mesh.m_Color[idx1] ) ),
2539 mesh.m_Color[idx2] ) ) );
2540 }
2541 else
2542 {
2543 newTriangle->SetColor(
2544 ConvertSRGBToLinear( mesh.m_Color[idx0] ),
2545 ConvertSRGBToLinear( mesh.m_Color[idx1] ),
2546 ConvertSRGBToLinear( mesh.m_Color[idx2] ) );
2547 }
2548 }
2549 }
2550 }
2551 }
2552 }
2553 }
2554 }
2555}
@ NORMAL
Use all material properties from model file.
Definition 3d_enums.h:72
@ CAD_MODE
Use a gray shading based on diffuse material.
Definition 3d_enums.h:74
Defines math related functions.
float NextFloatDown(float v)
float NextFloatUp(float v)
Defines math related functions.
float RGBtoGray(const SFVEC3F &aColor)
Definition 3d_math.h:140
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
Definition 3d_math.h:147
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
Definition 3d_math.h:43
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
EXTRUSION_MATERIAL_PROPS GetMaterialProps(EXTRUSION_MATERIAL aMaterial, const SFVEC3F &aDiffuse)
bool GetExtrusionPinOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly)
Get the pin outline polygons for extruded THT pin rendering.
bool GetExtrusionOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aOutline, PCB_LAYER_ID aLayerOverride)
Get the extrusion outline polygon for a footprint in board coordinates.
BOX2I CalcPlaceholderLocalBox(const FOOTPRINT *aFootprint)
Calculate a local space bounding box for a placeholder 3D model.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
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.
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
This BVH implementation is based on the source code implementation from the book "Physically Based Re...
Blinn Phong based material https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model.
Definition material.h:379
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
Procedural generation of the shiny brushed metal.
Definition material.h:195
void GetIntersectingObjects(const BBOX_2D &aBBox, CONST_LIST_OBJECT2D &aOutList) const override
Get a list of objects that intersects a bounding box.
static const float DEFAULT_MAX_ZOOM
Definition camera.h:106
void Add(OBJECT_2D *aObject)
const LIST_OBJECT2D & GetList() const
void Add(OBJECT_3D *aObject)
Procedural generation of the copper normals.
Definition material.h:76
A vertical cylinder.
Definition cylinder_3d.h:38
void SetColor(SFVEC3F aObjColor)
Definition cylinder_3d.h:48
A light source based only on a directional vector.
Definition light.h:116
A dummy block is used to fill the polygons.
void SetColor(SFVEC3F aObjColor)
double AsRadians() const
Definition eda_angle.h:120
KIGFX::COLOR4D m_color
Definition footprint.h:110
VECTOR3D m_offset
Definition footprint.h:116
static KIGFX::COLOR4D GetDefaultColor(EXTRUSION_MATERIAL aMaterial)
Definition footprint.h:118
VECTOR3D m_scale
Definition footprint.h:114
EXTRUSION_MATERIAL m_material
Definition footprint.h:111
const EXTRUDED_3D_BODY * GetExtrudedBody() const
Definition footprint.h:398
bool IsFlipped() const
Definition footprint.h:602
VECTOR2I GetPosition() const override
Definition footprint.h:405
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
double r
Red component.
Definition color4d.h:393
double g
Green component.
Definition color4d.h:394
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
double b
Blue component.
Definition color4d.h:395
Make solid geometry for objects on layers.
void SetColor(SFVEC3F aObjColor)
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
A base light class to derive to implement other light classes.
Definition light.h:41
Base material class that can be used to derive other material implementations.
Definition material.h:240
static void SetDefaultReflectionRayCount(unsigned int aCount)
Definition material.h:247
static void SetDefaultRefractionRayCount(unsigned int aCount)
Definition material.h:242
static void SetDefaultRefractionRecursionCount(unsigned int aCount)
Definition material.h:252
void SetGenerator(const MATERIAL_GENERATOR *aGenerator)
Definition material.h:328
float GetTransparency() const
Definition material.h:273
static void SetDefaultReflectionRecursionCount(unsigned int aCount)
Definition material.h:257
static OBJECT_2D_STATS & Instance()
Definition object_2d.h:137
void ResetStats()
Definition object_2d.h:122
virtual bool Intersects(const BBOX_2D &aBBox) const =0
a.Intersects(b) ⇔ !a.Disjoint(b) ⇔ !(a ∩ b = ∅)
const BBOX_2D & GetBBox() const
Definition object_2d.h:103
const BOARD_ITEM & GetBoardItem() const
Definition object_2d.h:66
OBJECT_2D_TYPE GetObjectType() const
Definition object_2d.h:107
static OBJECT_3D_STATS & Instance()
Definition object_3d.h:132
void ResetStats()
Definition object_3d.h:115
void SetMaterial(const MATERIAL *aMaterial)
Definition object_3d.h:58
void SetModelTransparency(float aModelTransparency)
Definition object_3d.h:66
void SetBoardItem(BOARD_ITEM *aBoardItem)
Definition object_3d.h:55
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:360
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:363
Definition pad.h:55
int GetBackPostMachiningSize() const
Definition pad.h:478
const VECTOR2I & GetDrillSize() const
Definition pad.h:317
VECTOR2I GetPosition() const override
Definition pad.h:209
int GetFrontPostMachiningSize() const
Definition pad.h:458
int GetFrontPostMachiningDepth() const
Definition pad.h:460
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
Definition pad.h:445
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:420
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetBackPostMachining() const
Definition pad.h:465
int GetBackPostMachiningDepth() const
Definition pad.h:480
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
int GetFrontPostMachiningSize() const
Definition pcb_track.h:693
const PADSTACK & Padstack() const
Definition pcb_track.h:406
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
Definition pcb_track.h:680
int GetBackPostMachiningSize() const
Definition pcb_track.h:713
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetBackPostMachining() const
Definition pcb_track.h:700
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
Procedural generation of the plastic normals.
Definition material.h:146
Procedural generation of the shiny plastic normals.
Definition material.h:170
Point light source based on http://ogldev.atspace.co.uk/www/tutorial20/tutorial20....
Definition light.h:71
Represent a sub polygon block.
Definition polygon_2d.h:94
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
SILK_SCREEN_NORMAL m_silkScreenMaterial
struct RENDER_3D_RAYTRACE_BASE::@013206213056006125230376122042346155134272177300 m_materials
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
void addCountersinkPlating(const SFVEC2F &aCenter, float aTopInnerRadius, float aBottomInnerRadius, float aSurfaceZ, float aDepth, bool aIsFront)
void addPlaceholderToRaytracer(CONTAINER_3D &aDstContainer, const FOOTPRINT *aFootprint, const glm::mat4 &aFpMatrix, bool aHasExtrudedBody=false)
std::vector< std::unique_ptr< BLINN_PHONG_MATERIAL > > m_extrusionMaterials
void load3DModels(CONTAINER_3D &aDstContainer, bool aSkipMaterialInformation)
void insertHole(const PCB_VIA *aVia)
BRUSHED_METAL_NORMAL m_brushedMetalMaterial
static constexpr float MIN_DISTANCE_IU
PLATED_COPPER_NORMAL m_platedCopperMaterial
void createItemsFromContainer(const BVH_CONTAINER_2D *aContainer2d, PCB_LAYER_ID aLayer_id, const MATERIAL *aMaterialLayer, const SFVEC3F &aLayerColor, float aLayerZOffset)
PLASTIC_SHINE_NORMAL m_shinyPlasticMaterial
bool addExtrudedBodyToRaytracer(CONTAINER_3D &aDstContainer, const FOOTPRINT *aFootprint)
void addCounterborePlating(const BOARD_ITEM &aSource, const SFVEC2F &aCenter, float aInnerRadius, float aDepth, float aSurfaceZ, bool aIsFront)
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
CONTAINER_2D m_containerWithObjectsToDelete
Store the list of created objects special for RT that will be clear in the end.
MODEL_MATERIALS * getModelMaterial(const S3DMODEL *a3DModel)
SOLDER_MASK_NORMAL m_solderMaskMaterial
void addModels(CONTAINER_3D &aDstContainer, const S3DMODEL *a3DModel, const glm::mat4 &aModelMatrix, float aFPOpacity, bool aSkipMaterialInformation, BOARD_ITEM *aBoardItem)
MAP_MODEL_MATERIALS m_modelMaterialMap
Stores materials of the 3D models.
void createObject(CONTAINER_3D &aDstContainer, const OBJECT_2D *aObject2D, float aZMin, float aZMax, const MATERIAL *aMaterial, const SFVEC3F &aObjColor)
Create one or more 3D objects form a 2D object and Z positions.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:75
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:104
void SetColor(SFVEC3F aObjColor)
Cache for storing the 3D shapes.
Definition 3d_cache.h:57
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:583
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Procedural generation of the solder mask.
Definition material.h:126
A triangle object.
Definition triangle_3d.h:43
void SetColor(const SFVEC3F &aColor)
A vertical truncated cone with different radii at top and bottom.
Definition frustum_3d.h:39
void SetColor(SFVEC3F aObjColor)
Definition frustum_3d.h:51
A plane that is parallel to XY plane.
Definition plane_3d.h:38
void SetColor(SFVEC3F aObjColor)
Definition plane_3d.h:49
std::list< OBJECT_2D * > LIST_OBJECT2D
std::list< const OBJECT_2D * > CONST_LIST_OBJECT2D
#define _(s)
#define UNITS3D_TO_UNITSPCB
Implements a model viewer canvas.
Declaration of the eda_3d_viewer class.
@ TENTHS_OF_A_DEGREE_T
Definition eda_angle.h:30
A truncated cone for raytracing, used for countersink visualization.
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
Definition layer_id.cpp:337
@ LAYER_3D_USER_1
Definition layer_ids.h:569
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:562
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:561
@ LAYER_3D_BOARD
Definition layer_ids.h:556
@ LAYER_3D_USER_45
Definition layer_ids.h:613
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_Adhes
Definition layer_ids.h:103
@ Dwgs_User
Definition layer_ids.h:107
@ F_Paste
Definition layer_ids.h:104
@ Cmts_User
Definition layer_ids.h:108
@ F_Adhes
Definition layer_ids.h:102
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ Eco1_User
Definition layer_ids.h:109
@ F_Mask
Definition layer_ids.h:97
@ B_Paste
Definition layer_ids.h:105
@ F_Fab
Definition layer_ids.h:119
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ Eco2_User
Definition layer_ids.h:110
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
#define CSGITEM_EMPTY
#define CSGITEM_FULL
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
PAD_DRILL_POST_MACHINING_MODE
Definition padstack.h:76
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
static wxColor copperColor(220, 180, 30)
void ConvertPolygonToBlocks(const SHAPE_POLY_SET &aMainPath, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, float aDivFactor, const BOARD_ITEM &aBoardItem, int aPolyIndex)
Use a polygon in the format of the ClipperLib::Path and process it and create multiple 2d objects (PO...
std::vector< SEGMENT_WITH_NORMALS > SEGMENTS_WIDTH_NORMALS
List used to test ray2d intersections.
Definition polygon_2d.h:69
std::vector< POLYSEGMENT > SEGMENTS
Definition polygon_2d.h:61
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
void buildBoardBoundingBoxPoly(const BOARD *aBoard, SHAPE_POLY_SET &aOutline)
Get the complete bounding box of the board (including all items).
static size_t addOutlineToRaytracerObjects(CONTAINER_2D &aObjContainer, const SHAPE_POLY_SET &aOutline, float aBiuTo3d, const BOARD_ITEM &aBoardItem)
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Perform an interpolation step to easy control the transparency based on the gray color value and tran...
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Attempt to control the transparency based on the gray value of the color.
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
std::vector< BLINN_PHONG_MATERIAL > MODEL_MATERIALS
Vector of materials.
const SFVEC2F & Min() const
Definition bbox_2d.h:175
const SFVEC2F & Max() const
Definition bbox_2d.h:180
Manage a bounding box defined by two SFVEC3F min max points.
Definition bbox_3d.h:43
void Union(const SFVEC3F &aPoint)
Recalculate the bounding box adding a point.
Definition bbox_3d.cpp:102
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition bbox_3d.cpp:132
const SFVEC3F & Min() const
Return the minimum vertex pointer.
Definition bbox_3d.h:192
const SFVEC3F & Max() const
Return the maximum vertex pointer.
Definition bbox_3d.h:199
void Reset()
Reset the bounding box to zero and de-initialize it.
Definition bbox_3d.cpp:95
bool IsInitialized() const
Check if this bounding box is already initialized.
Definition bbox_3d.cpp:88
void Scale(float aScale)
Scales a bounding box by its center.
Definition bbox_3d.cpp:182
Handle a subset of a polygon.
Definition polygon_2d.h:79
std::vector< SEGMENTS > m_Outers
Definition polygon_2d.h:80
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:281
Store the a model based on meshes and materials.
Definition c3dmodel.h:95
SMATERIAL * m_Materials
The materials list of this model.
Definition c3dmodel.h:100
unsigned int m_MeshesSize
Number of meshes in the array.
Definition c3dmodel.h:96
SMESH * m_Meshes
The meshes list of this model.
Definition c3dmodel.h:97
unsigned int m_MaterialsSize
Number of materials in the material array.
Definition c3dmodel.h:99
float m_Shininess
Definition c3dmodel.h:43
SFVEC3F m_Specular
Definition c3dmodel.h:42
SFVEC3F m_Ambient
Definition c3dmodel.h:39
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
Definition c3dmodel.h:44
SFVEC3F m_Emissive
Definition c3dmodel.h:41
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Definition c3dmodel.h:40
Per-vertex normal/color/texcoors structure.
Definition c3dmodel.h:81
unsigned int * m_FaceIdx
Triangle Face Indexes.
Definition c3dmodel.h:88
SFVEC3F * m_Normals
Vertex normals array.
Definition c3dmodel.h:84
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
Definition c3dmodel.h:89
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition c3dmodel.h:82
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
Definition c3dmodel.h:87
SFVEC3F * m_Color
Vertex color array, can be NULL.
Definition c3dmodel.h:86
SFVEC3F * m_Positions
Vertex position array.
Definition c3dmodel.h:83
KIBIS_MODEL * model
VECTOR3I v1(5, 5, 5)
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
VECTOR2I v2(1, 0)
VECTOR2I v4(1, 1)
VECTOR2I v5(-70, -70)
VECTOR2I v3(-2, 1)
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
Implement a triangle ray intersection based on article http://www.flipcode.com/archives/Raytracing_To...
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
glm::vec2 SFVEC2F
Definition xv3d_types.h:42
glm::vec3 SFVEC3F
Definition xv3d_types.h:44