KiCad PCB EDA Suite
Loading...
Searching...
No Matches
board_adapter.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-2023 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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "board_adapter.h"
23
24#include <wx/log.h>
25
26#include <gal/3d/camera.h>
31#include <board.h>
33#include <footprint.h>
35#include <layer_range.h>
36#include <project_pcb.h>
37#include <3d_math.h>
39#include <layer_ids.h>
40#include <layer_range.h>
41#include <lset.h>
42#include <pgm_base.h>
45#include <pcb_track.h>
46#include <pcbnew_settings.h>
47#include <advanced_config.h>
48
49
50#define DEFAULT_BOARD_THICKNESS pcbIUScale.mmToIU( 1.6 )
51#define DEFAULT_COPPER_THICKNESS pcbIUScale.mmToIU( 0.035 ) // for 35 um
52// The solder mask layer (and silkscreen) thickness
53#define DEFAULT_TECH_LAYER_THICKNESS pcbIUScale.mmToIU( 0.025 )
54// The solder paste thickness is chosen bigger than the solder mask layer
55// to be sure is covers the mask when overlapping.
56#define SOLDERPASTE_LAYER_THICKNESS pcbIUScale.mmToIU( 0.04 )
57
58
59std::vector<CUSTOM_COLOR_ITEM> BOARD_ADAPTER::g_SilkColors;
60std::vector<CUSTOM_COLOR_ITEM> BOARD_ADAPTER::g_MaskColors;
61std::vector<CUSTOM_COLOR_ITEM> BOARD_ADAPTER::g_PasteColors;
62std::vector<CUSTOM_COLOR_ITEM> BOARD_ADAPTER::g_FinishColors;
63std::vector<CUSTOM_COLOR_ITEM> BOARD_ADAPTER::g_BoardColors;
64
77
78// To be used in Raytracing render to create bevels on layer items
80
81static bool g_ColorsLoaded = false;
82
91const wxChar *BOARD_ADAPTER::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
92
93
95 m_Cfg( nullptr ),
96 m_IsBoardView( true ),
97 m_MousewheelPanning( true ),
98 m_IsPreviewer( false ),
99 m_board( nullptr ),
100 m_3dModelManager( nullptr ),
103{
104 wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::BOARD_ADAPTER" ) );
105
108 m_boardCenter = SFVEC3F( 0.0f );
109
110 m_boardBoundingBox.Reset();
111
112 m_TH_IDs.Clear();
113 m_TH_ODs.Clear();
114 m_viaAnnuli.Clear();
115
117
118 m_biuTo3Dunits = 1.0;
126
127 m_trackCount = 0;
128 m_viaCount = 0;
130 m_holeCount = 0;
132 m_averageTrackWidth = 0.0f;
133
134 m_BgColorBot = SFVEC4F( 0.4, 0.4, 0.5, 1.0 );
135 m_BgColorTop = SFVEC4F( 0.8, 0.8, 0.9, 1.0 );
136 m_BoardBodyColor = SFVEC4F( 0.4, 0.4, 0.5, 0.9 );
137 m_SolderMaskColorTop = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
138 m_SolderMaskColorBot = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
139 m_SolderPasteColor = SFVEC4F( 0.4, 0.4, 0.4, 1.0 );
140 m_SilkScreenColorTop = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
141 m_SilkScreenColorBot = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
142 m_CopperColor = SFVEC4F( 0.75, 0.61, 0.23, 1.0 );
143 m_UserDrawingsColor = SFVEC4F( 0.85, 0.85, 0.85, 1.0 );
144 m_UserCommentsColor = SFVEC4F( 0.85, 0.85, 0.85, 1.0 );
145 m_ECO1Color = SFVEC4F( 0.70, 0.10, 0.10, 1.0 );
146 m_ECO2Color = SFVEC4F( 0.70, 0.10, 0.10, 1.0 );
147 m_FFabColor = SFVEC4F( 0.60, 0.60, 0.60, 1.0 );
148 m_BFabColor = SFVEC4F( 0.60, 0.60, 0.60, 1.0 );
149 // Based on default board colourscheme for F.CrtYd and B.CrtYd
150 m_FCourtyardColor = SFVEC4F( 1.000, 0.149, 0.886, 1.0 );
151 m_BCourtyardColor = SFVEC4F( 1.000, 0.149, 0.886, 1.0 );
152
153 for( int ii = 0; ii < 45; ++ii )
154 m_UserDefinedLayerColor[ii] = SFVEC4F( 0.70, 0.10, 0.10, 1.0 );
155
156 m_platedPadsFront = nullptr;
157 m_platedPadsBack = nullptr;
158 m_offboardPadsFront = nullptr;
159 m_offboardPadsBack = nullptr;
160
161 m_frontPlatedCopperPolys = nullptr;
162 m_backPlatedCopperPolys = nullptr;
163
165
166 if( !g_ColorsLoaded )
167 {
168#define ADD_COLOR( list, r, g, b, a, name ) \
169 list.emplace_back( r/255.0, g/255.0, b/255.0, a, name )
170
171 ADD_COLOR( g_SilkColors, 245, 245, 245, 1.0, NotSpecifiedPrm() ); // White
172 ADD_COLOR( g_SilkColors, 20, 51, 36, 1.0, wxT( "Green" ) );
173 ADD_COLOR( g_SilkColors, 181, 19, 21, 1.0, wxT( "Red" ) );
174 ADD_COLOR( g_SilkColors, 2, 59, 162, 1.0, wxT( "Blue" ) );
175 ADD_COLOR( g_SilkColors, 11, 11, 11, 1.0, wxT( "Black" ) );
176 ADD_COLOR( g_SilkColors, 245, 245, 245, 1.0, wxT( "White" ) );
177 ADD_COLOR( g_SilkColors, 32, 2, 53, 1.0, wxT( "Purple" ) );
178 ADD_COLOR( g_SilkColors, 194, 195, 0, 1.0, wxT( "Yellow" ) );
179
180 ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, NotSpecifiedPrm() ); // Green
181 ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, wxT( "Green" ) );
182 ADD_COLOR( g_MaskColors, 91, 168, 12, 0.83, wxT( "Light Green" ) );
183 ADD_COLOR( g_MaskColors, 13, 104, 11, 0.83, wxT( "Saturated Green" ) );
184 ADD_COLOR( g_MaskColors, 181, 19, 21, 0.83, wxT( "Red" ) );
185 ADD_COLOR( g_MaskColors, 210, 40, 14, 0.83, wxT( "Light Red" ) );
186 ADD_COLOR( g_MaskColors, 239, 53, 41, 0.83, wxT( "Red/Orange" ) );
187 ADD_COLOR( g_MaskColors, 2, 59, 162, 0.83, wxT( "Blue" ) );
188 ADD_COLOR( g_MaskColors, 54, 79, 116, 0.83, wxT( "Light Blue 1" ) );
189 ADD_COLOR( g_MaskColors, 61, 85, 130, 0.83, wxT( "Light Blue 2" ) );
190 ADD_COLOR( g_MaskColors, 21, 70, 80, 0.83, wxT( "Green/Blue" ) );
191 ADD_COLOR( g_MaskColors, 11, 11, 11, 0.83, wxT( "Black" ) );
192 ADD_COLOR( g_MaskColors, 245, 245, 245, 0.83, wxT( "White" ) );
193 ADD_COLOR( g_MaskColors, 32, 2, 53, 0.83, wxT( "Purple" ) );
194 ADD_COLOR( g_MaskColors, 119, 31, 91, 0.83, wxT( "Light Purple" ) );
195 ADD_COLOR( g_MaskColors, 194, 195, 0, 0.83, wxT( "Yellow" ) );
196
197 ADD_COLOR( g_PasteColors, 128, 128, 128, 1.0, wxT( "Grey" ) );
198 ADD_COLOR( g_PasteColors, 90, 90, 90, 1.0, wxT( "Dark Grey" ) );
199 ADD_COLOR( g_PasteColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
200
201 ADD_COLOR( g_FinishColors, 184, 115, 50, 1.0, wxT( "Copper" ) );
202 ADD_COLOR( g_FinishColors, 178, 156, 0, 1.0, wxT( "Gold" ) );
203 ADD_COLOR( g_FinishColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
204 ADD_COLOR( g_FinishColors, 160, 160, 160, 1.0, wxT( "Tin" ) );
205
206 ADD_COLOR( g_BoardColors, 51, 43, 22, 0.83, wxT( "FR4 natural, dark" ) );
207 ADD_COLOR( g_BoardColors, 109, 116, 75, 0.83, wxT( "FR4 natural" ) );
208 ADD_COLOR( g_BoardColors, 252, 252, 250, 0.90, wxT( "PTFE natural" ) );
209 ADD_COLOR( g_BoardColors, 205, 130, 0, 0.68, wxT( "Polyimide" ) );
210 ADD_COLOR( g_BoardColors, 92, 17, 6, 0.90, wxT( "Phenolic natural" ) );
211 ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 1" ) );
212 ADD_COLOR( g_BoardColors, 160, 123, 54, 0.83, wxT( "Brown 2" ) );
213 ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 3" ) );
214 ADD_COLOR( g_BoardColors, 213, 213, 213, 1.0, wxT( "Aluminum" ) );
215
216 g_DefaultBackgroundTop = COLOR4D( 0.80, 0.80, 0.90, 1.0 );
217 g_DefaultBackgroundBot = COLOR4D( 0.40, 0.40, 0.50, 1.0 );
218
219 g_DefaultSilkscreen = COLOR4D( 0.94, 0.94, 0.94, 1.0 );
220 g_DefaultSolderMask = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
221 g_DefaultSolderPaste = COLOR4D( 0.50, 0.50, 0.50, 1.0 );
222 g_DefaultAdhesive = COLOR4D( 0.70, 0.11, 0.17, 1.0 );
223 g_DefaultSurfaceFinish = COLOR4D( 0.75, 0.61, 0.23, 1.0 );
224 g_DefaultBoardBody = COLOR4D( 0.43, 0.45, 0.30, 0.90 );
225
226 g_DefaultComments = COLOR4D( 0.85, 0.85, 0.85, 1.0 );
227 g_DefaultECOs = COLOR4D( 0.70, 0.10, 0.10, 1.0 );
228
229 g_DefaultFabColor = COLOR4D( 0.60, 0.60, 0.60, 1.0 );
230 g_DefaultCourtyardColor = COLOR4D( 1.000, 0.149, 0.886, 1.0 );
231
232 g_ColorsLoaded = true;
233 }
234#undef ADD_COLOR
235}
236
237
242
243
245{
248
249 for( int layer = F_Cu; layer < PCB_LAYER_ID_COUNT; ++layer )
250 m_BoardEditorColors[ layer ] = cs->GetColor( layer );
251}
252
253
255 const std::bitset<LAYER_3D_END>& aVisibilityFlags ) const
256{
257 wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
258
259 if( m_board && !m_board->IsLayerEnabled( aLayer ) )
260 return false;
261
262 switch( aLayer )
263 {
264 case B_Cu: return aVisibilityFlags.test( LAYER_3D_COPPER_BOTTOM );
265 case F_Cu: return aVisibilityFlags.test( LAYER_3D_COPPER_TOP );
266 case B_Adhes: return aVisibilityFlags.test( LAYER_3D_ADHESIVE );
267 case F_Adhes: return aVisibilityFlags.test( LAYER_3D_ADHESIVE );
268 case B_Paste: return aVisibilityFlags.test( LAYER_3D_SOLDERPASTE );
269 case F_Paste: return aVisibilityFlags.test( LAYER_3D_SOLDERPASTE );
270 case B_SilkS: return aVisibilityFlags.test( LAYER_3D_SILKSCREEN_BOTTOM );
271 case F_SilkS: return aVisibilityFlags.test( LAYER_3D_SILKSCREEN_TOP );
272 case B_Mask: return aVisibilityFlags.test( LAYER_3D_SOLDERMASK_BOTTOM );
273 case F_Mask: return aVisibilityFlags.test( LAYER_3D_SOLDERMASK_TOP );
274 case Dwgs_User: return aVisibilityFlags.test( LAYER_3D_USER_DRAWINGS );
275 case Cmts_User: return aVisibilityFlags.test( LAYER_3D_USER_COMMENTS );
276 case Eco1_User: return aVisibilityFlags.test( LAYER_3D_USER_ECO1 );
277 case Eco2_User: return aVisibilityFlags.test( LAYER_3D_USER_ECO2 );
278 case F_Fab: return aVisibilityFlags.test( LAYER_3D_F_FAB );
279 case B_Fab: return aVisibilityFlags.test( LAYER_3D_B_FAB );
280 case F_CrtYd: return aVisibilityFlags.test( LAYER_3D_F_COURTYARD );
281 case B_CrtYd: return aVisibilityFlags.test( LAYER_3D_B_COURTYARD );
282 default:
283 {
284 int layer3D = MapPCBLayerTo3DLayer( aLayer );
285
286 if( layer3D != UNDEFINED_LAYER )
287 return aVisibilityFlags.test( layer3D );
288
289 return m_board && m_board->IsLayerVisible( aLayer );
290 }
291 }
292}
293
294
295bool BOARD_ADAPTER::IsFootprintShown( const FOOTPRINT* aFootprint ) const
296{
297 if( m_IsPreviewer ) // In panel Preview, footprints are always shown, of course
298 return true;
299
300 if( !aFootprint )
301 return false;
302
303 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
304 const bool excludedFromPos = aFootprint->GetExcludedFromPosFilesForVariant( variantName );
305 const bool dnp = aFootprint->GetDNPForVariant( variantName );
306 const auto attributes = static_cast<FOOTPRINT_ATTR_T>( aFootprint->GetAttributes() );
307
308 if( excludedFromPos )
309 {
310 if( !m_Cfg->m_Render.show_footprints_not_in_posfile )
311 return false;
312 }
313
314 if( dnp )
315 {
316 if( !m_Cfg->m_Render.show_footprints_dnp )
317 return false;
318 }
319
320 if( attributes & FP_SMD )
321 return m_Cfg->m_Render.show_footprints_insert;
322
323 if( attributes & FP_THROUGH_HOLE )
324 return m_Cfg->m_Render.show_footprints_normal;
325
326 return m_Cfg->m_Render.show_footprints_virtual;
327}
328
329
330wxString BOARD_ADAPTER::GetFootprintLibraryPath( const FOOTPRINT* aFootprint ) const
331{
332 if( !aFootprint )
333 return wxEmptyString;
334
335 const wxString libraryName = aFootprint->GetFPID().GetLibNickname();
336
337 if( libraryName.empty() )
338 return wxEmptyString;
339
340 PROJECT* project = m_board ? m_board->GetProject() : nullptr;
341
342 // Footprint-editor boards have no project, so fall back to the 3D cache.
343 if( !project && m_3dModelManager )
344 project = m_3dModelManager->GetProject();
345
346 if( !project )
347 return wxEmptyString;
348
349 try
350 {
352
353 if( !adapter )
354 return wxEmptyString;
355
356 // GetRow() can throw an exception
357 std::optional<LIBRARY_TABLE_ROW*> fpRow = adapter->GetRow( libraryName );
358
359 if( fpRow )
360 return LIBRARY_MANAGER::GetFullURI( *fpRow, true );
361 }
362 catch( ... )
363 {
364 // Do nothing if the libraryName is not found in lib table
365 }
366
367 return wxEmptyString;
368}
369
370
372{
373 return m_board ? m_board->GetDesignSettings().GetHolePlatingThickness()
375}
376
377
378unsigned int BOARD_ADAPTER::GetCircleSegmentCount( float aDiameter3DU ) const
379{
380 wxASSERT( aDiameter3DU > 0.0f );
381
382 return GetCircleSegmentCount( (int)( aDiameter3DU / m_biuTo3Dunits ) );
383}
384
385
386unsigned int BOARD_ADAPTER::GetCircleSegmentCount( int aDiameterBIU ) const
387{
388 wxASSERT( aDiameterBIU > 0 );
389
390 return GetArcToSegmentCount( aDiameterBIU / 2, m_board->GetDesignSettings().m_MaxError, FULL_CIRCLE );
391}
392
393
394void BOARD_ADAPTER::InitSettings( std::shared_ptr<REPORTER> aStatusReporter,
395 std::shared_ptr<REPORTER> aWarningReporter )
396{
397 wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::InitSettings" ) );
398
399 if( aStatusReporter )
400 aStatusReporter->Report( _( "Build board outline" ) );
401
402 wxString msg;
403
404 const bool haveOutline = createBoardPolygon( &msg );
405
406 if( aWarningReporter )
407 {
408 if( !haveOutline )
409 aWarningReporter->Report( msg, RPT_SEVERITY_WARNING );
410 else
411 aWarningReporter->Report( wxEmptyString );
412 }
413
414 BOX2I bbbox;
415
416 if( m_board )
417 bbbox = m_board->ComputeBoundingBox( !m_board->IsFootprintHolder() && haveOutline, true );
418
419 // Gives a non null size to avoid issues in zoom / scale calculations
420 if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
421 bbbox.Inflate( pcbIUScale.mmToIU( 10 ) );
422
423 m_boardSize = bbbox.GetSize();
424 m_boardPos = bbbox.Centre();
425
426 wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
427
428 m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
429
430 m_copperLayersCount = m_board ? m_board->GetCopperLayerCount() : 2;
431
432 // Ensure the board has 2 sides for 3D views, because it is hard to find
433 // a *really* single side board in the true life...
434 if( m_copperLayersCount < 2 )
436
437 // Calculate the conversion to apply to all positions.
439
440 // Hack to keep "home" zoom from being too small.
441 if( !m_board || !m_board->IsFootprintHolder() )
442 m_biuTo3Dunits *= 1.6f;
443
445
453
454 g_BevelThickness3DU = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_3DRT_BevelHeight_um / 1000.0 )
456
457 if( m_board )
458 {
459 const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
460
461 if( bds.GetStackupDescriptor().GetCount() )
462 {
463 int body_thickness = 0;
464
465 for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
466 {
467 switch( item->GetType() )
468 {
470 for( int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
471 body_thickness += item->GetThickness( sublayer );
472
473 break;
474
476 {
477 // The copper thickness must be > 0 to avoid draw issues (divide by 0 for
478 // instance). We use a minimal arbitrary value = 1 micrometer here:
479 int copper_thickness = std::max( item->GetThickness(), pcbIUScale.mmToIU( 0.001 ) );
480
481 if( item->GetBrdLayerId() == F_Cu )
482 m_frontCopperThickness3DU = copper_thickness * m_biuTo3Dunits;
483 else if( item->GetBrdLayerId() == B_Cu )
484 m_backCopperThickness3DU = copper_thickness * m_biuTo3Dunits;
485 else if( item->IsEnabled() )
486 body_thickness += copper_thickness;
487
488 break;
489 }
490
492 {
493 // The mask thickness must be > 0 to avoid draw issues (divide by 0 for
494 // instance). We use a minimal arbitrary value = 1 micrometer here:
495 int mask_thickness = std::max( item->GetThickness(), pcbIUScale.mmToIU( 0.001 ) );
496
497 if( item->GetBrdLayerId() == F_Mask )
498 m_frontMaskThickness3DU = mask_thickness * m_biuTo3Dunits;
499 else if( item->GetBrdLayerId() == B_Mask )
500 m_backMaskThickness3DU = mask_thickness * m_biuTo3Dunits;
501 }
502
503 default:
504 break;
505 }
506 }
507
508 m_boardBodyThickness3DU = body_thickness * m_biuTo3Dunits;
509 }
510 }
511
512 // Init Z position of each layer
513 // calculate z position for each copper layer
514 // Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer)
515 // (layer id = B_Cu)
516 // Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer)
517 // (layer id = F_Cu)
518
519 // ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
520 // | | Top = Bottom + m_copperThickness
521 // |__________________________________|
522 // == == == == <- Bottom = -m_epoxyThickness / 2.0,
523 // Top = Bottom - m_copperThickness
524
525 // Generate the Z position of copper layers
526 // A copper layer Z position has 2 values: its top Z position and its bottom Z position
527 for( auto layer_id : LAYER_RANGE( F_Cu, B_Cu, m_copperLayersCount ) )
528 {
529 // This approximates internal layer positions (because we're treating all the dielectric
530 // layers as having the same thickness). But we don't render them anyway so it doesn't
531 // really matter.
532 int layer_pos; // the position of the copper layer from board top to bottom
533
534 switch( layer_id )
535 {
536 case F_Cu: layer_pos = 0; break;
537 case B_Cu: layer_pos = m_copperLayersCount - 1; break;
538 default: layer_pos = ( layer_id - B_Cu )/2; break;
539 };
540
542 - ( m_boardBodyThickness3DU * layer_pos / ( m_copperLayersCount - 1 ) );
543
544 if( layer_pos < (m_copperLayersCount / 2) )
546 else
548 }
549
550 #define layerThicknessMargin 1.1
551 const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
552
553 // This is the top of the copper layer thickness.
554 const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
555 const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
556
557 // Fill not copper layers zpos
558 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; layer++ )
559 {
560 PCB_LAYER_ID layer_id = ToLAYER_ID( layer );
561
562 if( IsCopperLayer( layer_id ) )
563 continue;
564
565 float zposBottom;
566 float zposTop;
567
568 switch( layer_id )
569 {
570 case B_Mask:
571 zposBottom = zpos_copperTop_back;
572 zposTop = zpos_copperTop_back - m_backMaskThickness3DU;
573 break;
574
575 case B_Paste:
576 zposBottom = zpos_copperTop_back;
577 zposTop = zpos_copperTop_back - m_solderPasteLayerThickness3DU;
578 break;
579
580 case F_Mask:
581 zposBottom = zpos_copperTop_front;
582 zposTop = zpos_copperTop_front + m_frontMaskThickness3DU;
583 break;
584
585 case F_Paste:
586 zposBottom = zpos_copperTop_front;
587 zposTop = zpos_copperTop_front + m_solderPasteLayerThickness3DU;
588 break;
589
590 case B_SilkS:
591 zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
592 zposTop = zposBottom - m_nonCopperLayerThickness3DU;
593 break;
594
595 case F_SilkS:
596 zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
597 zposTop = zposBottom + m_nonCopperLayerThickness3DU;
598 break;
599
600 default:
601 if( m_board->IsBackLayer( layer_id ) )
602 {
603 zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
604 zposTop = zposBottom - m_nonCopperLayerThickness3DU;
605 }
606 else
607 {
608 zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
609 zposTop = zposBottom + m_nonCopperLayerThickness3DU;
610 }
611 break;
612 }
613
614 m_layerZcoordTop[layer_id] = zposTop;
615 m_layerZcoordBottom[layer_id] = zposBottom;
616 }
617
619
621 boardSize /= 2.0f;
622
623 SFVEC3F boardMin = ( m_boardCenter - boardSize );
624 SFVEC3F boardMax = ( m_boardCenter + boardSize );
625
626 boardMin.z = m_layerZcoordTop[B_Adhes];
627 boardMax.z = m_layerZcoordTop[F_Adhes];
628
629 m_boardBoundingBox = BBOX_3D( boardMin, boardMax );
630}
631
632
633void BOARD_ADAPTER::CreateLayers( std::shared_ptr<REPORTER> aStatusReporter, std::stop_token aStop )
634{
635#ifdef PRINT_STATISTICS_3D_VIEWER
636 int64_t stats_startCreateBoardPolyTime = GetRunningMicroSecs();
637#endif
638
639 if( aStatusReporter )
640 aStatusReporter->Report( _( "Create layers" ) );
641
642 createLayers( aStatusReporter, aStop );
643
644 auto to_SFVEC4F =
645 []( const COLOR4D& src )
646 {
647 return SFVEC4F( src.r, src.g, src.b, src.a );
648 };
649
650 std::map<int, COLOR4D> colors = GetLayerColors();
651
652 m_BgColorTop = to_SFVEC4F( colors[ LAYER_3D_BACKGROUND_TOP ] );
653 m_BgColorBot = to_SFVEC4F( colors[ LAYER_3D_BACKGROUND_BOTTOM ] );
654 m_SolderPasteColor = to_SFVEC4F( colors[ LAYER_3D_SOLDERPASTE ] );
655 m_AdhesiveColor = to_SFVEC4F( colors[ LAYER_3D_ADHESIVE ] );
656 m_SilkScreenColorBot = to_SFVEC4F( colors[ LAYER_3D_SILKSCREEN_BOTTOM ] );
657 m_SilkScreenColorTop = to_SFVEC4F( colors[ LAYER_3D_SILKSCREEN_TOP ] );
658 m_SolderMaskColorBot = to_SFVEC4F( colors[ LAYER_3D_SOLDERMASK_BOTTOM ] );
659 m_SolderMaskColorTop = to_SFVEC4F( colors[ LAYER_3D_SOLDERMASK_TOP ] );
660 m_CopperColor = to_SFVEC4F( colors[ LAYER_3D_COPPER_TOP ] );
661 m_BoardBodyColor = to_SFVEC4F( colors[ LAYER_3D_BOARD ] );
662 m_UserDrawingsColor = to_SFVEC4F( colors[ LAYER_3D_USER_DRAWINGS ] );
663 m_UserCommentsColor = to_SFVEC4F( colors[ LAYER_3D_USER_COMMENTS ] );
664 m_ECO1Color = to_SFVEC4F( colors[ LAYER_3D_USER_ECO1 ] );
665 m_ECO2Color = to_SFVEC4F( colors[ LAYER_3D_USER_ECO2 ] );
666 m_FFabColor = to_SFVEC4F( colors[ LAYER_3D_F_FAB ] );
667 m_BFabColor = to_SFVEC4F( colors[ LAYER_3D_B_FAB ] );
668 m_FCourtyardColor = to_SFVEC4F( colors[ LAYER_3D_F_COURTYARD ] );
669 m_BCourtyardColor = to_SFVEC4F( colors[ LAYER_3D_B_COURTYARD ] );
670
671 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
672 m_UserDefinedLayerColor[ layer - LAYER_3D_USER_1 ] = to_SFVEC4F( colors[ layer ] );
673}
674
675
676std::map<int, COLOR4D> BOARD_ADAPTER::GetDefaultColors() const
677{
678 std::map<int, COLOR4D> colors;
679
699
701
702 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
703 colors[ layer ] = settings->GetColor( layer );
704
705 return colors;
706}
707
708
709std::map<int, COLOR4D> BOARD_ADAPTER::GetLayerColors() const
710{
711 std::map<int, COLOR4D> colors;
712
713 if( LAYER_PRESET_3D* preset = m_Cfg->FindPreset( m_Cfg->m_CurrentPreset ) )
714 {
715 colors = preset->colors;
716 }
717 else
718 {
720
721 for( const auto& [ layer, defaultColor /* unused */ ] : GetDefaultColors() )
722 colors[ layer ] = settings->GetColor( layer );
723 }
724
725 if( m_Cfg->m_UseStackupColors && m_board )
726 {
727 const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
728 KIGFX::COLOR4D bodyColor( 0, 0, 0, 0 );
729
730 // Can't do a const KIGFX::COLOR4D& return type here because there are temporary variables
731 auto findColor =
732 []( const wxString& aName, const std::vector<CUSTOM_COLOR_ITEM>& aColorSet ) -> const KIGFX::COLOR4D
733 {
734 if( aName.StartsWith( wxT( "#" ) ) )
735 {
736 return KIGFX::COLOR4D( aName );
737 }
738 else
739 {
740 for( const CUSTOM_COLOR_ITEM& color : aColorSet )
741 {
742 if( color.m_ColorName == aName )
743 return color.m_Color;
744 }
745 }
746
747 return KIGFX::COLOR4D();
748 };
749
750 for( const BOARD_STACKUP_ITEM* stackupItem : stackup.GetList() )
751 {
752 wxString colorName = stackupItem->GetColor();
753
754 switch( stackupItem->GetType() )
755 {
757 if( stackupItem->GetBrdLayerId() == F_SilkS )
758 colors[ LAYER_3D_SILKSCREEN_TOP ] = findColor( colorName, g_SilkColors );
759 else
760 colors[ LAYER_3D_SILKSCREEN_BOTTOM ] = findColor( colorName, g_SilkColors );
761
762 break;
763
765 if( stackupItem->GetBrdLayerId() == F_Mask )
766 colors[ LAYER_3D_SOLDERMASK_TOP ] = findColor( colorName, g_MaskColors );
767 else
768 colors[ LAYER_3D_SOLDERMASK_BOTTOM ] = findColor( colorName, g_MaskColors );
769
770 break;
771
773 {
774 KIGFX::COLOR4D layerColor = findColor( colorName, g_BoardColors );
775
776 if( bodyColor == COLOR4D( 0, 0, 0, 0 ) )
777 bodyColor = layerColor;
778 else
779 bodyColor = bodyColor.Mix( layerColor, 1.0 - layerColor.a );
780
781 bodyColor.a += ( 1.0 - bodyColor.a ) * layerColor.a / 2;
782 break;
783 }
784
785 default:
786 break;
787 }
788 }
789
790 if( bodyColor != COLOR4D( 0, 0, 0, 0 ) )
791 colors[ LAYER_3D_BOARD ] = bodyColor;
792
793 const wxString& finishName = stackup.m_FinishType;
794
795 if( finishName.EndsWith( wxT( "OSP" ) ) )
796 {
797 colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Copper" ), g_FinishColors );
798 }
799 else if( finishName.EndsWith( wxT( "IG" ) )
800 || finishName.EndsWith( wxT( "gold" ) ) )
801 {
802 colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Gold" ), g_FinishColors );
803 }
804 else if( finishName.StartsWith( wxT( "HAL" ) )
805 || finishName.StartsWith( wxT( "HASL" ) )
806 || finishName.EndsWith( wxT( "tin" ) )
807 || finishName.EndsWith( wxT( "nickel" ) ) )
808 {
809 colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Tin" ), g_FinishColors );
810 }
811 else if( finishName.EndsWith( wxT( "silver" ) ) )
812 {
813 colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Silver" ), g_FinishColors );
814 }
815 }
816
817 colors[ LAYER_3D_COPPER_BOTTOM ] = colors[ LAYER_3D_COPPER_TOP ];
818
819 for( const auto& [layer, val] : m_ColorOverrides )
820 colors[layer] = val;
821
822 return colors;
823}
824
825
826void BOARD_ADAPTER::SetLayerColors( const std::map<int, COLOR4D>& aColors )
827{
829
830 for( const auto& [ layer, color ] : aColors )
831 {
832 settings->SetColor( layer, color );
833
834 if( layer >= LAYER_3D_USER_1 && layer <= LAYER_3D_USER_45 )
836 }
837
838 Pgm().GetSettingsManager().SaveColorSettings( settings, "3d_viewer" );
839}
840
841
842void BOARD_ADAPTER::SetVisibleLayers( const std::bitset<LAYER_3D_END>& aLayers )
843{
844 m_Cfg->m_Render.show_board_body = aLayers.test( LAYER_3D_BOARD );
845 m_Cfg->m_Render.show_plated_barrels = aLayers.test( LAYER_3D_PLATED_BARRELS );
846 m_Cfg->m_Render.show_copper_top = aLayers.test( LAYER_3D_COPPER_TOP );
847 m_Cfg->m_Render.show_copper_bottom = aLayers.test( LAYER_3D_COPPER_BOTTOM );
848
849 for( int layer = LAYER_3D_COPPER_INNER_1; layer <= LAYER_3D_COPPER_INNER_30; ++layer )
850 m_Cfg->m_Render.show_copper_inner[layer - LAYER_3D_COPPER_INNER_1] = aLayers.test( layer );
851
852 m_Cfg->m_Render.show_silkscreen_top = aLayers.test( LAYER_3D_SILKSCREEN_TOP );
853 m_Cfg->m_Render.show_silkscreen_bottom = aLayers.test( LAYER_3D_SILKSCREEN_BOTTOM );
854 m_Cfg->m_Render.show_soldermask_top = aLayers.test( LAYER_3D_SOLDERMASK_TOP );
855 m_Cfg->m_Render.show_soldermask_bottom = aLayers.test( LAYER_3D_SOLDERMASK_BOTTOM );
856 m_Cfg->m_Render.show_solderpaste = aLayers.test( LAYER_3D_SOLDERPASTE );
857 m_Cfg->m_Render.show_adhesive = aLayers.test( LAYER_3D_ADHESIVE );
858 m_Cfg->m_Render.show_comments = aLayers.test( LAYER_3D_USER_COMMENTS );
859 m_Cfg->m_Render.show_drawings = aLayers.test( LAYER_3D_USER_DRAWINGS );
860 m_Cfg->m_Render.show_eco1 = aLayers.test( LAYER_3D_USER_ECO1 );
861 m_Cfg->m_Render.show_eco2 = aLayers.test( LAYER_3D_USER_ECO2 );
862 m_Cfg->m_Render.show_f_fab = aLayers.test( LAYER_3D_F_FAB );
863 m_Cfg->m_Render.show_b_fab = aLayers.test( LAYER_3D_B_FAB );
864 m_Cfg->m_Render.show_f_courtyard = aLayers.test( LAYER_3D_F_COURTYARD );
865 m_Cfg->m_Render.show_b_courtyard = aLayers.test( LAYER_3D_B_COURTYARD );
866
867 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
868 m_Cfg->m_Render.show_user[ layer - LAYER_3D_USER_1 ] = aLayers.test( layer );
869
870 m_Cfg->m_Render.show_footprints_normal = aLayers.test( LAYER_3D_TH_MODELS );
871 m_Cfg->m_Render.show_footprints_insert = aLayers.test( LAYER_3D_SMD_MODELS );
872 m_Cfg->m_Render.show_footprints_virtual = aLayers.test( LAYER_3D_VIRTUAL_MODELS );
873 m_Cfg->m_Render.show_footprints_not_in_posfile = aLayers.test( LAYER_3D_MODELS_NOT_IN_POS );
874 m_Cfg->m_Render.show_footprints_dnp = aLayers.test( LAYER_3D_MODELS_MARKED_DNP );
875
876 m_Cfg->m_Render.show_fp_references = aLayers.test( LAYER_FP_REFERENCES );
877 m_Cfg->m_Render.show_fp_values = aLayers.test( LAYER_FP_VALUES );
878 m_Cfg->m_Render.show_fp_text = aLayers.test( LAYER_FP_TEXT );
879
880 m_Cfg->m_Render.show_model_bbox = aLayers.test( LAYER_3D_BOUNDING_BOXES );
881 m_Cfg->m_Render.show_off_board_silk = aLayers.test( LAYER_3D_OFF_BOARD_SILK );
882 m_Cfg->m_Render.show_navigator = aLayers.test( LAYER_3D_NAVIGATOR );
883}
884
885
886std::bitset<LAYER_3D_END> BOARD_ADAPTER::GetVisibleLayers() const
887{
889 return *m_visibilityOverride;
890
891 std::bitset<LAYER_3D_END> ret;
892
893 if( m_IsPreviewer )
894 {
895 // The preview has one board-body button and no layer controls, so it cannot follow
896 // the per-layer flags the 3D viewer's appearance panel writes: a mask switched off
897 // there would leave the preview showing bare substrate with no way back.
898 if( m_Cfg->m_Preview.show_board_body )
899 {
900 ret.set( LAYER_3D_BOARD, true );
901 ret.set( LAYER_3D_SOLDERMASK_TOP, true );
902 ret.set( LAYER_3D_SOLDERMASK_BOTTOM, true );
903 ret.set( LAYER_3D_SOLDERPASTE, true );
904 ret.set( LAYER_3D_ADHESIVE, m_Cfg->m_Render.show_adhesive );
905 }
906
907 ret.set( LAYER_3D_PLATED_BARRELS, true );
908
910 ret.set( MapPCBLayerTo3DLayer( layer ), true );
911
912 ret.set( LAYER_3D_SILKSCREEN_TOP, true );
913 ret.set( LAYER_3D_SILKSCREEN_BOTTOM, true );
914 ret.set( LAYER_3D_USER_COMMENTS, true );
915 ret.set( LAYER_3D_USER_DRAWINGS, true );
916 ret.set( LAYER_3D_USER_ECO1, true );
917 ret.set( LAYER_3D_USER_ECO2, true );
918 ret.set( LAYER_3D_F_FAB, true );
919 ret.set( LAYER_3D_B_FAB, true );
920 ret.set( LAYER_3D_F_COURTYARD, true );
921 ret.set( LAYER_3D_B_COURTYARD, true );
922
923 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
924 ret.set( layer, true );
925
926 ret.set( LAYER_FP_REFERENCES, true );
927 ret.set( LAYER_FP_VALUES, true );
928 ret.set( LAYER_FP_TEXT, true );
929
930 ret.set( LAYER_3D_TH_MODELS, true );
931 ret.set( LAYER_3D_SMD_MODELS, true );
932 ret.set( LAYER_3D_VIRTUAL_MODELS, true );
933 ret.set( LAYER_3D_MODELS_NOT_IN_POS, true );
934 ret.set( LAYER_3D_MODELS_MARKED_DNP, true );
935
936 ret.set( LAYER_3D_BOUNDING_BOXES, m_Cfg->m_Render.show_model_bbox );
937 ret.set( LAYER_3D_OFF_BOARD_SILK, m_Cfg->m_Render.show_off_board_silk );
938 ret.set( LAYER_3D_NAVIGATOR, m_Cfg->m_Render.show_navigator );
939
940 return ret;
941 }
942
943 ret.set( LAYER_3D_BOARD, m_Cfg->m_Render.show_board_body );
944 ret.set( LAYER_3D_PLATED_BARRELS, m_Cfg->m_Render.show_plated_barrels );
945 ret.set( LAYER_3D_COPPER_TOP, m_Cfg->m_Render.show_copper_top );
946 ret.set( LAYER_3D_COPPER_BOTTOM, m_Cfg->m_Render.show_copper_bottom );
947
948 for( int layer = LAYER_3D_COPPER_INNER_1; layer <= LAYER_3D_COPPER_INNER_30; ++layer )
949 ret.set( layer, m_Cfg->m_Render.show_copper_inner[layer - LAYER_3D_COPPER_INNER_1] );
950
951 ret.set( LAYER_3D_SILKSCREEN_TOP, m_Cfg->m_Render.show_silkscreen_top );
952 ret.set( LAYER_3D_SILKSCREEN_BOTTOM, m_Cfg->m_Render.show_silkscreen_bottom );
953 ret.set( LAYER_3D_SOLDERMASK_TOP, m_Cfg->m_Render.show_soldermask_top );
954 ret.set( LAYER_3D_SOLDERMASK_BOTTOM, m_Cfg->m_Render.show_soldermask_bottom );
955 ret.set( LAYER_3D_SOLDERPASTE, m_Cfg->m_Render.show_solderpaste );
956 ret.set( LAYER_3D_ADHESIVE, m_Cfg->m_Render.show_adhesive );
957 ret.set( LAYER_3D_USER_COMMENTS, m_Cfg->m_Render.show_comments );
958 ret.set( LAYER_3D_USER_DRAWINGS, m_Cfg->m_Render.show_drawings );
959 ret.set( LAYER_3D_USER_ECO1, m_Cfg->m_Render.show_eco1 );
960 ret.set( LAYER_3D_USER_ECO2, m_Cfg->m_Render.show_eco2 );
961 ret.set( LAYER_3D_F_FAB, m_Cfg->m_Render.show_f_fab );
962 ret.set( LAYER_3D_B_FAB, m_Cfg->m_Render.show_b_fab );
963 ret.set( LAYER_3D_F_COURTYARD, m_Cfg->m_Render.show_f_courtyard );
964 ret.set( LAYER_3D_B_COURTYARD, m_Cfg->m_Render.show_b_courtyard );
965
966 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
967 ret.set( layer, m_Cfg->m_Render.show_user[ layer - LAYER_3D_USER_1 ] );
968
969 ret.set( LAYER_FP_REFERENCES, m_Cfg->m_Render.show_fp_references );
970 ret.set( LAYER_FP_VALUES, m_Cfg->m_Render.show_fp_values );
971 ret.set( LAYER_FP_TEXT, m_Cfg->m_Render.show_fp_text );
972
973 ret.set( LAYER_3D_TH_MODELS, m_Cfg->m_Render.show_footprints_normal );
974 ret.set( LAYER_3D_SMD_MODELS, m_Cfg->m_Render.show_footprints_insert );
975 ret.set( LAYER_3D_VIRTUAL_MODELS, m_Cfg->m_Render.show_footprints_virtual );
976 ret.set( LAYER_3D_MODELS_NOT_IN_POS, m_Cfg->m_Render.show_footprints_not_in_posfile );
977 ret.set( LAYER_3D_MODELS_MARKED_DNP, m_Cfg->m_Render.show_footprints_dnp );
978
979 ret.set( LAYER_3D_BOUNDING_BOXES, m_Cfg->m_Render.show_model_bbox );
980 ret.set( LAYER_3D_OFF_BOARD_SILK, m_Cfg->m_Render.show_off_board_silk );
981 ret.set( LAYER_3D_NAVIGATOR, m_Cfg->m_Render.show_navigator );
982
983 if( m_Cfg->m_CurrentPreset == FOLLOW_PCB )
984 {
985 if( !m_board )
986 return ret;
987
988 ret.set( LAYER_3D_BOARD, true );
989
991 ret.set( MapPCBLayerTo3DLayer( layer ), m_board->IsLayerVisible( layer ) );
992
993 ret.set( LAYER_3D_SILKSCREEN_TOP, m_board->IsLayerVisible( F_SilkS ) );
994 ret.set( LAYER_3D_SILKSCREEN_BOTTOM, m_board->IsLayerVisible( B_SilkS ) );
995 ret.set( LAYER_3D_SOLDERMASK_TOP, m_board->IsLayerVisible( F_Mask ) );
996 ret.set( LAYER_3D_SOLDERMASK_BOTTOM, m_board->IsLayerVisible( B_Mask ) );
997 ret.set( LAYER_3D_SOLDERPASTE, m_board->IsLayerVisible( F_Paste ) );
998 ret.set( LAYER_3D_ADHESIVE, m_board->IsLayerVisible( F_Adhes ) );
999 ret.set( LAYER_3D_USER_COMMENTS, m_board->IsLayerVisible( Cmts_User ) );
1000 ret.set( LAYER_3D_USER_DRAWINGS, m_board->IsLayerVisible( Dwgs_User ) );
1001 ret.set( LAYER_3D_USER_ECO1, m_board->IsLayerVisible( Eco1_User ) );
1002 ret.set( LAYER_3D_USER_ECO2, m_board->IsLayerVisible( Eco2_User ) );
1003 ret.set( LAYER_3D_F_FAB, m_board->IsLayerVisible( F_Fab ) );
1004 ret.set( LAYER_3D_B_FAB, m_board->IsLayerVisible( B_Fab ) );
1005 ret.set( LAYER_3D_F_COURTYARD, m_board->IsLayerVisible( F_CrtYd ) );
1006 ret.set( LAYER_3D_B_COURTYARD, m_board->IsLayerVisible( B_CrtYd ) );
1007
1009 ret.set( layer, m_board->IsElementVisible( layer ) );
1010 }
1011 else if( m_Cfg->m_CurrentPreset == FOLLOW_PLOT_SETTINGS )
1012 {
1013 if( !m_board )
1014 return ret;
1015
1016 const PCB_PLOT_PARAMS& plotParams = m_board->GetPlotOptions();
1017 LSET layers = plotParams.GetLayerSelection();
1018
1019 for( PCB_LAYER_ID commonLayer : plotParams.GetPlotOnAllLayersSequence() )
1020 layers.set( commonLayer );
1021
1022 ret.set( LAYER_3D_BOARD, true );
1023
1025 ret.set( MapPCBLayerTo3DLayer( layer ), layers.test( layer ) );
1026
1027 ret.set( LAYER_3D_SILKSCREEN_TOP, layers.test( F_SilkS ) );
1028 ret.set( LAYER_3D_SILKSCREEN_BOTTOM, layers.test( B_SilkS ) );
1029 ret.set( LAYER_3D_SOLDERMASK_TOP, layers.test( F_Mask ) );
1030 ret.set( LAYER_3D_SOLDERMASK_BOTTOM, layers.test( B_Mask ) );
1031 ret.set( LAYER_3D_SOLDERPASTE, layers.test( F_Paste ) );
1032 ret.set( LAYER_3D_ADHESIVE, layers.test( F_Adhes ) );
1033 ret.set( LAYER_3D_USER_COMMENTS, layers.test( Cmts_User ) );
1034 ret.set( LAYER_3D_USER_DRAWINGS, layers.test( Dwgs_User ) );
1035 ret.set( LAYER_3D_USER_ECO1, layers.test( Eco1_User ) );
1036 ret.set( LAYER_3D_USER_ECO2, layers.test( Eco2_User ) );
1037 ret.set( LAYER_3D_F_FAB, layers.test( F_Fab ) );
1038 ret.set( LAYER_3D_B_FAB, layers.test( B_Fab ) );
1039 ret.set( LAYER_3D_F_COURTYARD, layers.test( F_CrtYd ) );
1040 ret.set( LAYER_3D_B_COURTYARD, layers.test( B_CrtYd ) );
1041
1042 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
1043 ret.set( layer, layers.test( Map3DLayerToPCBLayer( layer ) ) );
1044
1045 ret.set( LAYER_FP_REFERENCES, plotParams.GetPlotReference() );
1046 ret.set( LAYER_FP_VALUES, plotParams.GetPlotValue() );
1047 ret.set( LAYER_FP_TEXT, plotParams.GetPlotFPText() );
1048 }
1049 else if( LAYER_PRESET_3D* preset = m_Cfg->FindPreset( m_Cfg->m_CurrentPreset ) )
1050 {
1051 ret = preset->layers;
1052 }
1053
1054 return ret;
1055}
1056
1057
1058std::bitset<LAYER_3D_END> BOARD_ADAPTER::GetDefaultVisibleLayers() const
1059{
1060 std::bitset<LAYER_3D_END> ret;
1061
1062 ret.set( LAYER_3D_BOARD, true );
1063 ret.set( LAYER_3D_PLATED_BARRELS, true );
1064 ret.set( LAYER_3D_COPPER_TOP, true );
1065 ret.set( LAYER_3D_COPPER_BOTTOM, true );
1066
1067 for( int layer = LAYER_3D_COPPER_INNER_1; layer <= LAYER_3D_COPPER_INNER_30; ++layer )
1068 ret.set( layer, true );
1069
1070 ret.set( LAYER_3D_SILKSCREEN_TOP, true );
1071 ret.set( LAYER_3D_SILKSCREEN_BOTTOM, true );
1072 ret.set( LAYER_3D_SOLDERMASK_TOP, true );
1073 ret.set( LAYER_3D_SOLDERMASK_BOTTOM, true );
1074 ret.set( LAYER_3D_SOLDERPASTE, true );
1075 ret.set( LAYER_3D_ADHESIVE, true );
1076 ret.set( LAYER_3D_USER_COMMENTS, false );
1077 ret.set( LAYER_3D_USER_DRAWINGS, false );
1078 ret.set( LAYER_3D_USER_ECO1, false );
1079 ret.set( LAYER_3D_USER_ECO2, false );
1080 ret.set( LAYER_3D_F_FAB, false );
1081 ret.set( LAYER_3D_B_FAB, false );
1082 ret.set( LAYER_3D_F_COURTYARD, false );
1083 ret.set( LAYER_3D_B_COURTYARD, false );
1084
1085 for( int layer = LAYER_3D_USER_1; layer <= LAYER_3D_USER_45; ++layer )
1086 ret.set( layer, false );
1087
1088 ret.set( LAYER_FP_REFERENCES, true );
1089 ret.set( LAYER_FP_VALUES, true );
1090 ret.set( LAYER_FP_TEXT, true );
1091
1092 ret.set( LAYER_3D_TH_MODELS, true );
1093 ret.set( LAYER_3D_SMD_MODELS, true );
1094 ret.set( LAYER_3D_VIRTUAL_MODELS, true );
1095 ret.set( LAYER_3D_MODELS_NOT_IN_POS, false );
1096 ret.set( LAYER_3D_MODELS_MARKED_DNP, false );
1097
1098 ret.set( LAYER_3D_BOUNDING_BOXES, false );
1099 ret.set( LAYER_3D_OFF_BOARD_SILK, false );
1100 ret.set( LAYER_3D_NAVIGATOR, true );
1101
1102 return ret;
1103}
1104
1105
1107{
1108 return m_Cfg->m_Render.use_board_editor_copper_colors && !m_board->IsFootprintHolder();
1109}
1110
1111
1112bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
1113{
1114 m_board_poly.RemoveAllContours();
1115
1116 if( !m_board )
1117 return false;
1118
1119 bool success;
1120
1121 if( m_board->IsFootprintHolder() )
1122 {
1123 if( !m_board->GetFirstFootprint() )
1124 {
1125 if( aErrorMsg )
1126 *aErrorMsg = _( "No footprint loaded." );
1127
1128 return false;
1129 }
1130
1131 // max dist from one endPt to next startPt
1132 int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
1133
1135 m_board->GetDesignSettings().m_MaxError,
1136 chainingEpsilon );
1137 m_board_poly.Simplify();
1138
1139 if( !success && aErrorMsg )
1140 {
1141 *aErrorMsg = _( "Footprint outline is missing or malformed. Run Footprint Checker for "
1142 "a full analysis." );
1143 }
1144 }
1145 else
1146 {
1147 success = m_board->GetBoardPolygonOutlines( m_board_poly, true, nullptr, false, true );
1148
1149 if( !success && aErrorMsg )
1150 *aErrorMsg = _( "Board outline is missing or malformed. Run DRC for a full analysis." );
1151 }
1152
1153 return success;
1154}
1155
1156
1157float BOARD_ADAPTER::GetFootprintZPos( bool aIsFlipped ) const
1158{
1159 if( aIsFlipped )
1160 {
1161 if( auto it = m_layerZcoordBottom.find( B_Paste ); it != m_layerZcoordBottom.end() )
1162 return it->second;
1163 }
1164 else
1165 {
1166 if( auto it = m_layerZcoordTop.find( F_Paste ); it != m_layerZcoordTop.end() )
1167 return it->second;
1168 }
1169
1170 return 0.0;
1171}
1172
1173
1174glm::mat4 BOARD_ADAPTER::GetFootprintMatrix( const FOOTPRINT& aFootprint ) const
1175{
1176 const VECTOR2I pos = aFootprint.GetPosition();
1177 glm::mat4 matrix( 1.0f );
1178
1179 matrix = glm::translate( matrix, SFVEC3F( pos.x * BiuTo3dUnits(), -pos.y * BiuTo3dUnits(),
1180 GetFootprintZPos( aFootprint.IsFlipped() ) ) );
1181
1182 if( !aFootprint.GetOrientation().IsZero() )
1183 {
1184 matrix = glm::rotate( matrix, (float) aFootprint.GetOrientation().AsRadians(),
1185 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1186 }
1187
1188 if( aFootprint.IsFlipped() )
1189 {
1190 matrix = glm::rotate( matrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1191 matrix = glm::rotate( matrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1192 }
1193
1194 return glm::scale( matrix, SFVEC3F( BiuTo3dUnits() * pcbIUScale.IU_PER_MM ) );
1195}
1196
1197
1199{
1200 if( aLayerId >= LAYER_3D_USER_1 && aLayerId <= LAYER_3D_USER_45 )
1201 aLayerId = Map3DLayerToPCBLayer( aLayerId );
1202
1203 wxASSERT( aLayerId < PCB_LAYER_ID_COUNT );
1204
1205 return GetColor( m_BoardEditorColors.at( aLayerId ) );
1206}
1207
1208
1210{
1211 return SFVEC4F( aColor.r, aColor.g, aColor.b, aColor.a );
1212}
1213
1214
1216{
1217 SFVEC2F sphericalCoord = SFVEC2F( ( m_Cfg->m_Render.raytrace_lightElevation[i] + 90.0f ) / 180.0f,
1218 m_Cfg->m_Render.raytrace_lightAzimuth[i] / 180.0f );
1219
1220 sphericalCoord.x = glm::clamp( sphericalCoord.x, 0.0f, 1.0f );
1221 sphericalCoord.y = glm::clamp( sphericalCoord.y, 0.0f, 2.0f );
1222
1223 return sphericalCoord;
1224}
Defines math related functions.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
#define SOLDERPASTE_LAYER_THICKNESS
#define ADD_COLOR(list, r, g, b, a, name)
float g_BevelThickness3DU
#define DEFAULT_TECH_LAYER_THICKNESS
#define DEFAULT_BOARD_THICKNESS
#define layerThicknessMargin
static bool g_ColorsLoaded
#define DEFAULT_COPPER_THICKNESS
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
@ BS_ITEM_TYPE_COPPER
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
Define an abstract camera.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
wxString m_ColorTheme
Active color theme name.
BASE_SET & set(size_t pos)
Definition base_set.h:126
std::map< int, COLOR4D > m_BoardEditorColors
list of colors used by the board editor
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
BVH_CONTAINER_2D * m_offboardPadsBack
SFVEC4F m_BgColorTop
background top color
SFVEC4F m_ECO2Color
void SetVisibleLayers(const std::bitset< LAYER_3D_END > &aLayers)
static std::vector< CUSTOM_COLOR_ITEM > g_PasteColors
float m_solderPasteLayerThickness3DU
SFVEC4F GetLayerColor(int aLayerId) const
Get the technical color of a layer.
std::map< PCB_LAYER_ID, float > m_layerZcoordBottom
Bottom (Start) Z pos of each layer.
void CreateLayers(std::shared_ptr< REPORTER > aStatusReporter, std::stop_token aStop=std::stop_token())
Creates the layers for the board, should be called after InitSettings.
S3D_CACHE * m_3dModelManager
VECTOR2I m_boardPos
Board center position in board internal units.
float m_backCopperThickness3DU
bool GetUseBoardEditorCopperLayerColors() const
static KIGFX::COLOR4D g_DefaultComments
SFVEC4F m_SolderPasteColor
BBOX_3D m_boardBoundingBox
3D bounding box of the board in 3D units.
void createLayers(std::shared_ptr< REPORTER > aStatusReporter, std::stop_token aStop)
static KIGFX::COLOR4D g_DefaultBoardBody
SFVEC4F m_UserDefinedLayerColor[45]
static KIGFX::COLOR4D g_DefaultAdhesive
unsigned int m_viaCount
static KIGFX::COLOR4D g_DefaultFabColor
static KIGFX::COLOR4D g_DefaultSolderMask
std::map< int, COLOR4D > GetLayerColors() const
Build a color list which is used to store colors layers.
static std::vector< CUSTOM_COLOR_ITEM > g_BoardColors
std::optional< std::bitset< LAYER_3D_END > > m_visibilityOverride
static std::vector< CUSTOM_COLOR_ITEM > g_MaskColors
static std::vector< CUSTOM_COLOR_ITEM > g_SilkColors
SHAPE_POLY_SET * m_frontPlatedCopperPolys
BVH_CONTAINER_2D m_TH_ODs
List of PTH outer diameters.
float m_frontMaskThickness3DU
unsigned int m_trackCount
float m_averageTrackWidth
SHAPE_POLY_SET m_board_poly
Board outline polygon.
std::bitset< LAYER_3D_END > GetVisibleLayers() const
SFVEC4F m_SolderMaskColorBot
bool m_IsPreviewer
true if we're in a 3D preview panel, false for the standard 3D viewer
int GetHolePlatingThickness() const noexcept
Get the hole plating thickness (NB: in BOARD UNITS!).
static KIGFX::COLOR4D g_DefaultECOs
SFVEC4F m_SolderMaskColorTop
SFVEC4F GetColor(const COLOR4D &aColor) const
BVH_CONTAINER_2D * m_offboardPadsFront
float m_averageViaHoleDiameter
static KIGFX::COLOR4D g_DefaultBackgroundTop
glm::mat4 GetFootprintMatrix(const FOOTPRINT &aFootprint) const
Build the transform from footprint-local model units to 3D world units.
SFVEC4F m_FFabColor
float m_averageHoleDiameter
static KIGFX::COLOR4D g_DefaultSurfaceFinish
SFVEC4F m_CopperColor
void ReloadColorSettings() noexcept
static std::vector< CUSTOM_COLOR_ITEM > g_FinishColors
SFVEC2F GetSphericalCoord(int i) const
BVH_CONTAINER_2D * m_platedPadsBack
std::bitset< LAYER_3D_END > GetDefaultVisibleLayers() const
SFVEC4F m_BCourtyardColor
void InitSettings(std::shared_ptr< REPORTER > aStatusReporter, std::shared_ptr< REPORTER > aWarningReporter)
Function to be called by the render when it need to reload the settings for the board.
std::map< PCB_LAYER_ID, float > m_layerZcoordTop
Top (End) Z pos of each layer in 3D units.
float GetFootprintZPos(bool aIsFlipped) const
Get the position of the footprint in 3d integer units considering if it is flipped or not.
float m_frontCopperThickness3DU
float m_backMaskThickness3DU
SFVEC4F m_AdhesiveColor
static KIGFX::COLOR4D g_DefaultSolderPaste
wxString GetFootprintLibraryPath(const FOOTPRINT *aFootprint) const
Return the directory of aFootprint's library.
float m_boardBodyThickness3DU
VECTOR2I m_boardSize
Board size in board internal units.
SHAPE_POLY_SET * m_backPlatedCopperPolys
void SetLayerColors(const std::map< int, COLOR4D > &aColors)
EDA_3D_VIEWER_SETTINGS * m_Cfg
std::map< int, COLOR4D > m_ColorOverrides
allows to override color scheme colors
SFVEC4F m_SilkScreenColorTop
SFVEC4F m_SilkScreenColorBot
bool IsFootprintShown(const FOOTPRINT *aFootprint) const
Test if footprint should be displayed in relation to attributes and the flags.
unsigned int GetCircleSegmentCount(float aDiameter3DU) const
SFVEC4F m_FCourtyardColor
static KIGFX::COLOR4D g_DefaultCourtyardColor
SFVEC4F m_BFabColor
float m_nonCopperLayerThickness3DU
unsigned int m_holeCount
BVH_CONTAINER_2D m_viaAnnuli
List of via annular rings.
SFVEC4F m_BoardBodyColor
bool createBoardPolygon(wxString *aErrorMsg)
Create the board outline polygon.
unsigned int m_copperLayersCount
std::map< int, COLOR4D > GetDefaultColors() const
BVH_CONTAINER_2D m_TH_IDs
List of PTH inner diameters.
SFVEC4F m_UserCommentsColor
static KIGFX::COLOR4D g_DefaultSilkscreen
BVH_CONTAINER_2D * m_platedPadsFront
SFVEC3F m_boardCenter
3D center position of the board in 3D units.
static KIGFX::COLOR4D g_DefaultBackgroundBot
bool Is3dLayerEnabled(PCB_LAYER_ID aLayer, const std::bitset< LAYER_3D_END > &aVisibilityFlags) const
Check if a layer is enabled.
SFVEC4F m_ECO1Color
SFVEC4F m_UserDrawingsColor
double m_biuTo3Dunits
Scale factor to convert board internal units.
SFVEC4F m_BgColorBot
background bottom color
Container for design settings for a BOARD object.
BOARD_STACKUP & GetStackupDescriptor()
Manage one layer needed to make a physical board.
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int GetCount() const
wxString m_FinishType
The name of external copper finish.
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr const SizeVec & GetSize() const
Definition box2.h:203
Color settings are a bit different than most of the settings objects in that there can be more than o...
void SetColor(int aLayer, const COLOR4D &aColor)
COLOR4D GetColor(int aLayer) const
bool IsZero() const
Definition eda_angle.h:135
double AsRadians() const
Definition eda_angle.h:119
An interface to the global shared library manager that is schematic-specific and linked to one projec...
EDA_ANGLE GetOrientation() const
Definition footprint.h:382
int GetAttributes() const
Definition footprint.h:509
bool IsFlipped() const
Definition footprint.h:620
const LIB_ID & GetFPID() const
Definition footprint.h:417
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
bool GetExcludedFromPosFilesForVariant(const wxString &aVariantName) const
Get the exclude-from-position-files status for a specific variant.
VECTOR2I GetPosition() const override
Definition footprint.h:379
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:391
double g
Green component.
Definition color4d.h:392
double a
Alpha component.
Definition color4d.h:394
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Definition color4d.h:293
double b
Blue component.
Definition color4d.h:393
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...
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Parameters and options when plotting/printing a board.
LSEQ GetPlotOnAllLayersSequence() const
LSET GetLayerSelection() const
bool GetPlotReference() const
bool GetPlotValue() const
bool GetPlotFPText() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:63
void SaveColorSettings(COLOR_SETTINGS *aSettings, const std::string &aNamespace="")
Safely save a COLOR_SETTINGS to disk, preserving any changes outside the given namespace.
bool BuildFootprintPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, OUTLINE_ERROR_HANDLER *aErrorHandler)
Extract a board outline for a footprint view.
#define _(s)
#define FOLLOW_PLOT_SETTINGS
#define FOLLOW_PCB
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:446
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition footprint.h:85
@ FP_SMD
Definition footprint.h:87
@ FP_THROUGH_HOLE
Definition footprint.h:86
a few functions useful in geometry calculations.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
PCB_LAYER_ID Map3DLayerToPCBLayer(int aLayer)
Definition layer_id.cpp:279
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
Definition layer_id.cpp:354
@ LAYER_3D_COPPER_INNER_30
Definition layer_ids.h:684
@ LAYER_3D_USER_1
Definition layer_ids.h:599
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:588
@ LAYER_3D_NAVIGATOR
Definition layer_ids.h:649
@ LAYER_3D_BOUNDING_BOXES
Definition layer_ids.h:650
@ LAYER_3D_ADHESIVE
Definition layer_ids.h:590
@ LAYER_3D_SMD_MODELS
Definition layer_ids.h:645
@ LAYER_3D_BACKGROUND_TOP
Definition layer_ids.h:581
@ LAYER_3D_USER_COMMENTS
Definition layer_ids.h:591
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:587
@ LAYER_3D_BOARD
Definition layer_ids.h:582
@ LAYER_3D_PLATED_BARRELS
Definition layer_ids.h:652
@ LAYER_3D_USER_ECO1
Definition layer_ids.h:593
@ LAYER_3D_COPPER_INNER_1
Definition layer_ids.h:655
@ LAYER_3D_USER_ECO2
Definition layer_ids.h:594
@ LAYER_3D_TH_MODELS
Definition layer_ids.h:644
@ LAYER_3D_B_FAB
Definition layer_ids.h:596
@ LAYER_3D_SILKSCREEN_TOP
Definition layer_ids.h:586
@ LAYER_3D_B_COURTYARD
Definition layer_ids.h:598
@ LAYER_3D_VIRTUAL_MODELS
Definition layer_ids.h:646
@ LAYER_3D_MODELS_MARKED_DNP
Definition layer_ids.h:648
@ LAYER_3D_COPPER_TOP
Definition layer_ids.h:583
@ LAYER_3D_SOLDERPASTE
Definition layer_ids.h:589
@ LAYER_3D_OFF_BOARD_SILK
Definition layer_ids.h:651
@ LAYER_3D_MODELS_NOT_IN_POS
Definition layer_ids.h:647
@ LAYER_3D_USER_45
Definition layer_ids.h:643
@ LAYER_3D_USER_DRAWINGS
Definition layer_ids.h:592
@ LAYER_3D_COPPER_BOTTOM
Definition layer_ids.h:584
@ LAYER_3D_BACKGROUND_BOTTOM
Definition layer_ids.h:580
@ LAYER_3D_SILKSCREEN_BOTTOM
Definition layer_ids.h:585
@ LAYER_3D_F_COURTYARD
Definition layer_ids.h:597
@ LAYER_3D_F_FAB
Definition layer_ids.h:595
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
GAL_LAYER_ID
GAL layers are "virtual" layers, i.e.
Definition layer_ids.h:224
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition layer_ids.h:262
@ LAYER_FP_TEXT
Definition layer_ids.h:236
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition layer_ids.h:259
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_CrtYd
Definition layer_ids.h:112
@ B_Adhes
Definition layer_ids.h:99
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ Cmts_User
Definition layer_ids.h:104
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_Fab
Definition layer_ids.h:115
@ F_SilkS
Definition layer_ids.h:96
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Eco2_User
Definition layer_ids.h:106
@ B_SilkS
Definition layer_ids.h:97
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
@ RPT_SEVERITY_WARNING
#define DEFAULT_THEME
COLOR_SETTINGS * GetColorSettings(const wxString &aName)
T * GetAppSettings(const char *aFilename)
wxString NotSpecifiedPrm()
Manage a bounding box defined by two SFVEC3F min max points.
Definition bbox_3d.h:39
A class to handle a custom color (predefined color) for the color picker dialog.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
glm::vec2 SFVEC2F
Definition xv3d_types.h:38
glm::vec3 SFVEC3F
Definition xv3d_types.h:40
glm::vec4 SFVEC4F
Definition xv3d_types.h:42