mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
Recommendation is to avoid using the year nomenclature as this information is already encoded in the git repo. Avoids needing to repeatly update. Also updates AUTHORS.txt from current repo with contributor names
1021 lines
40 KiB
C++
1021 lines
40 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2015-2023 Mario Luzeiro <mrluzeiro@ua.pt>
|
|
* Copyright (C) 2023 CERN
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <gal/3d/camera.h>
|
|
#include "board_adapter.h"
|
|
#include <board_design_settings.h>
|
|
#include <board_stackup_manager/board_stackup.h>
|
|
#include <board_stackup_manager/stackup_predefined_prms.h>
|
|
#include <3d_rendering/raytracing/shapes2D/polygon_2d.h>
|
|
#include <board.h>
|
|
#include <dialogs/dialog_color_picker.h>
|
|
#include <layer_range.h>
|
|
#include <3d_math.h>
|
|
#include "3d_fastmath.h"
|
|
#include <geometry/geometry_utils.h>
|
|
#include <lset.h>
|
|
#include <pgm_base.h>
|
|
#include <settings/settings_manager.h>
|
|
#include <wx/log.h>
|
|
#include <pcbnew_settings.h>
|
|
#include <advanced_config.h>
|
|
|
|
|
|
#define DEFAULT_BOARD_THICKNESS pcbIUScale.mmToIU( 1.6 )
|
|
#define DEFAULT_COPPER_THICKNESS pcbIUScale.mmToIU( 0.035 ) // for 35 um
|
|
// The solder mask layer (and silkscreen) thickness
|
|
#define DEFAULT_TECH_LAYER_THICKNESS pcbIUScale.mmToIU( 0.025 )
|
|
// The solder paste thickness is chosen bigger than the solder mask layer
|
|
// to be sure is covers the mask when overlapping.
|
|
#define SOLDERPASTE_LAYER_THICKNESS pcbIUScale.mmToIU( 0.04 )
|
|
|
|
|
|
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_SilkColors;
|
|
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_MaskColors;
|
|
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_PasteColors;
|
|
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_FinishColors;
|
|
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_BoardColors;
|
|
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundTop;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundBot;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSilkscreen;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderMask;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderPaste;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSurfaceFinish;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBoardBody;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultComments;
|
|
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultECOs;
|
|
|
|
// To be used in Raytracing render to create bevels on layer items
|
|
float g_BevelThickness3DU = 0.0f;
|
|
|
|
static bool g_ColorsLoaded = false;
|
|
|
|
/**
|
|
* Trace mask used to enable or disable the trace output of this class.
|
|
* The debug output can be turned on by setting the WXTRACE environment variable to
|
|
* "KI_TRACE_EDA_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
|
|
* more information.
|
|
*
|
|
* @ingroup trace_env_vars
|
|
*/
|
|
const wxChar *BOARD_ADAPTER::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
|
|
|
|
|
|
BOARD_ADAPTER::BOARD_ADAPTER() :
|
|
m_Cfg( nullptr ),
|
|
m_IsBoardView( true ),
|
|
m_MousewheelPanning( true ),
|
|
m_IsPreviewer( false ),
|
|
m_board( nullptr ),
|
|
m_3dModelManager( nullptr ),
|
|
m_colors( nullptr ),
|
|
m_layerZcoordTop(),
|
|
m_layerZcoordBottom()
|
|
{
|
|
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::BOARD_ADAPTER" ) );
|
|
|
|
m_boardPos = VECTOR2I();
|
|
m_boardSize = VECTOR2I();
|
|
m_boardCenter = SFVEC3F( 0.0f );
|
|
|
|
m_boardBoundingBox.Reset();
|
|
|
|
m_TH_IDs.Clear();
|
|
m_TH_ODs.Clear();
|
|
m_viaAnnuli.Clear();
|
|
|
|
m_copperLayersCount = 2;
|
|
|
|
m_biuTo3Dunits = 1.0;
|
|
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
|
|
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
|
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
|
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
|
|
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
|
|
|
|
m_trackCount = 0;
|
|
m_viaCount = 0;
|
|
m_averageViaHoleDiameter = 0.0f;
|
|
m_holeCount = 0;
|
|
m_averageHoleDiameter = 0.0f;
|
|
m_averageTrackWidth = 0.0f;
|
|
|
|
m_BgColorBot = SFVEC4F( 0.4, 0.4, 0.5, 1.0 );
|
|
m_BgColorTop = SFVEC4F( 0.8, 0.8, 0.9, 1.0 );
|
|
m_BoardBodyColor = SFVEC4F( 0.4, 0.4, 0.5, 0.9 );
|
|
m_SolderMaskColorTop = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
|
|
m_SolderMaskColorBot = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
|
|
m_SolderPasteColor = SFVEC4F( 0.4, 0.4, 0.4, 1.0 );
|
|
m_SilkScreenColorTop = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
|
|
m_SilkScreenColorBot = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
|
|
m_CopperColor = SFVEC4F( 0.75, 0.61, 0.23, 1.0 );
|
|
m_UserDrawingsColor = SFVEC4F( 0.85, 0.85, 0.85, 1.0 );
|
|
m_UserCommentsColor = SFVEC4F( 0.85, 0.85, 0.85, 1.0 );
|
|
m_ECO1Color = SFVEC4F( 0.70, 0.10, 0.10, 1.0 );
|
|
m_ECO2Color = SFVEC4F( 0.70, 0.10, 0.10, 1.0 );
|
|
|
|
m_platedPadsFront = nullptr;
|
|
m_platedPadsBack = nullptr;
|
|
m_offboardPadsFront = nullptr;
|
|
m_offboardPadsBack = nullptr;
|
|
|
|
m_frontPlatedPadAndGraphicPolys = nullptr;
|
|
m_backPlatedPadAndGraphicPolys = nullptr;
|
|
m_frontPlatedCopperPolys = nullptr;
|
|
m_backPlatedCopperPolys = nullptr;
|
|
|
|
ReloadColorSettings();
|
|
|
|
if( !g_ColorsLoaded )
|
|
{
|
|
#define ADD_COLOR( list, r, g, b, a, name ) \
|
|
list.emplace_back( r/255.0, g/255.0, b/255.0, a, name )
|
|
|
|
ADD_COLOR( g_SilkColors, 245, 245, 245, 1.0, NotSpecifiedPrm() ); // White
|
|
ADD_COLOR( g_SilkColors, 20, 51, 36, 1.0, wxT( "Green" ) );
|
|
ADD_COLOR( g_SilkColors, 181, 19, 21, 1.0, wxT( "Red" ) );
|
|
ADD_COLOR( g_SilkColors, 2, 59, 162, 1.0, wxT( "Blue" ) );
|
|
ADD_COLOR( g_SilkColors, 11, 11, 11, 1.0, wxT( "Black" ) );
|
|
ADD_COLOR( g_SilkColors, 245, 245, 245, 1.0, wxT( "White" ) );
|
|
ADD_COLOR( g_SilkColors, 32, 2, 53, 1.0, wxT( "Purple" ) );
|
|
ADD_COLOR( g_SilkColors, 194, 195, 0, 1.0, wxT( "Yellow" ) );
|
|
|
|
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, NotSpecifiedPrm() ); // Green
|
|
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, wxT( "Green" ) );
|
|
ADD_COLOR( g_MaskColors, 91, 168, 12, 0.83, wxT( "Light Green" ) );
|
|
ADD_COLOR( g_MaskColors, 13, 104, 11, 0.83, wxT( "Saturated Green" ) );
|
|
ADD_COLOR( g_MaskColors, 181, 19, 21, 0.83, wxT( "Red" ) );
|
|
ADD_COLOR( g_MaskColors, 210, 40, 14, 0.83, wxT( "Light Red" ) );
|
|
ADD_COLOR( g_MaskColors, 239, 53, 41, 0.83, wxT( "Red/Orange" ) );
|
|
ADD_COLOR( g_MaskColors, 2, 59, 162, 0.83, wxT( "Blue" ) );
|
|
ADD_COLOR( g_MaskColors, 54, 79, 116, 0.83, wxT( "Light Blue 1" ) );
|
|
ADD_COLOR( g_MaskColors, 61, 85, 130, 0.83, wxT( "Light Blue 2" ) );
|
|
ADD_COLOR( g_MaskColors, 21, 70, 80, 0.83, wxT( "Green/Blue" ) );
|
|
ADD_COLOR( g_MaskColors, 11, 11, 11, 0.83, wxT( "Black" ) );
|
|
ADD_COLOR( g_MaskColors, 245, 245, 245, 0.83, wxT( "White" ) );
|
|
ADD_COLOR( g_MaskColors, 32, 2, 53, 0.83, wxT( "Purple" ) );
|
|
ADD_COLOR( g_MaskColors, 119, 31, 91, 0.83, wxT( "Light Purple" ) );
|
|
ADD_COLOR( g_MaskColors, 194, 195, 0, 0.83, wxT( "Yellow" ) );
|
|
|
|
ADD_COLOR( g_PasteColors, 128, 128, 128, 1.0, wxT( "Grey" ) );
|
|
ADD_COLOR( g_PasteColors, 90, 90, 90, 1.0, wxT( "Dark Grey" ) );
|
|
ADD_COLOR( g_PasteColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
|
|
|
|
ADD_COLOR( g_FinishColors, 184, 115, 50, 1.0, wxT( "Copper" ) );
|
|
ADD_COLOR( g_FinishColors, 178, 156, 0, 1.0, wxT( "Gold" ) );
|
|
ADD_COLOR( g_FinishColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
|
|
ADD_COLOR( g_FinishColors, 160, 160, 160, 1.0, wxT( "Tin" ) );
|
|
|
|
ADD_COLOR( g_BoardColors, 51, 43, 22, 0.83, wxT( "FR4 natural, dark" ) );
|
|
ADD_COLOR( g_BoardColors, 109, 116, 75, 0.83, wxT( "FR4 natural" ) );
|
|
ADD_COLOR( g_BoardColors, 252, 252, 250, 0.90, wxT( "PTFE natural" ) );
|
|
ADD_COLOR( g_BoardColors, 205, 130, 0, 0.68, wxT( "Polyimide" ) );
|
|
ADD_COLOR( g_BoardColors, 92, 17, 6, 0.90, wxT( "Phenolic natural" ) );
|
|
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 1" ) );
|
|
ADD_COLOR( g_BoardColors, 160, 123, 54, 0.83, wxT( "Brown 2" ) );
|
|
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 3" ) );
|
|
ADD_COLOR( g_BoardColors, 213, 213, 213, 1.0, wxT( "Aluminum" ) );
|
|
|
|
g_DefaultBackgroundTop = COLOR4D( 0.80, 0.80, 0.90, 1.0 );
|
|
g_DefaultBackgroundBot = COLOR4D( 0.40, 0.40, 0.50, 1.0 );
|
|
|
|
g_DefaultSilkscreen = COLOR4D( 0.94, 0.94, 0.94, 1.0 );
|
|
g_DefaultSolderMask = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
|
|
g_DefaultSolderPaste = COLOR4D( 0.50, 0.50, 0.50, 1.0 );
|
|
g_DefaultSurfaceFinish = COLOR4D( 0.75, 0.61, 0.23, 1.0 );
|
|
g_DefaultBoardBody = COLOR4D( 0.43, 0.45, 0.30, 0.90 );
|
|
|
|
g_DefaultComments = COLOR4D( 0.85, 0.85, 0.85, 1.0 );
|
|
g_DefaultECOs = COLOR4D( 0.70, 0.10, 0.10, 1.0 );
|
|
|
|
g_ColorsLoaded = true;
|
|
}
|
|
#undef ADD_COLOR
|
|
}
|
|
|
|
|
|
BOARD_ADAPTER::~BOARD_ADAPTER()
|
|
{
|
|
destroyLayers();
|
|
}
|
|
|
|
|
|
void BOARD_ADAPTER::ReloadColorSettings() noexcept
|
|
{
|
|
wxCHECK( PgmOrNull(), /* void */ );
|
|
|
|
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
|
|
PCBNEW_SETTINGS* cfg = mgr.GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
|
|
|
|
if( cfg )
|
|
{
|
|
m_colors = Pgm().GetSettingsManager().GetColorSettings( cfg->m_ColorTheme );
|
|
GetBoardEditorCopperLayerColors( cfg );
|
|
}
|
|
}
|
|
|
|
|
|
bool BOARD_ADAPTER::Is3dLayerEnabled( PCB_LAYER_ID aLayer,
|
|
const std::bitset<LAYER_3D_END>& aVisibilityFlags ) const
|
|
{
|
|
wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
|
|
|
|
if( m_board && !m_board->IsLayerEnabled( aLayer ) )
|
|
return false;
|
|
|
|
switch( aLayer )
|
|
{
|
|
case B_Cu: return aVisibilityFlags.test( LAYER_3D_COPPER_BOTTOM );
|
|
case F_Cu: return aVisibilityFlags.test( LAYER_3D_COPPER_TOP );
|
|
case B_Adhes: return aVisibilityFlags.test( LAYER_3D_ADHESIVE );
|
|
case F_Adhes: return aVisibilityFlags.test( LAYER_3D_ADHESIVE );
|
|
case B_Paste: return aVisibilityFlags.test( LAYER_3D_SOLDERPASTE );
|
|
case F_Paste: return aVisibilityFlags.test( LAYER_3D_SOLDERPASTE );
|
|
case B_SilkS: return aVisibilityFlags.test( LAYER_3D_SILKSCREEN_BOTTOM );
|
|
case F_SilkS: return aVisibilityFlags.test( LAYER_3D_SILKSCREEN_TOP );
|
|
case B_Mask: return aVisibilityFlags.test( LAYER_3D_SOLDERMASK_BOTTOM );
|
|
case F_Mask: return aVisibilityFlags.test( LAYER_3D_SOLDERMASK_TOP );
|
|
case Dwgs_User: return aVisibilityFlags.test( LAYER_3D_USER_DRAWINGS );
|
|
case Cmts_User: return aVisibilityFlags.test( LAYER_3D_USER_COMMENTS );
|
|
case Eco1_User: return aVisibilityFlags.test( LAYER_3D_USER_ECO1 );
|
|
case Eco2_User: return aVisibilityFlags.test( LAYER_3D_USER_ECO2 );
|
|
default: return m_board && m_board->IsLayerVisible( aLayer );
|
|
}
|
|
}
|
|
|
|
|
|
bool BOARD_ADAPTER::IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const
|
|
{
|
|
if( m_IsPreviewer ) // In panel Preview, footprints are always shown, of course
|
|
return true;
|
|
|
|
if( aFPAttributes & FP_EXCLUDE_FROM_POS_FILES )
|
|
{
|
|
if( !m_Cfg->m_Render.show_footprints_not_in_posfile )
|
|
return false;
|
|
}
|
|
|
|
if( aFPAttributes & FP_DNP )
|
|
{
|
|
if( !m_Cfg->m_Render.show_footprints_dnp )
|
|
return false;
|
|
}
|
|
|
|
if( aFPAttributes & FP_SMD )
|
|
return m_Cfg->m_Render.show_footprints_insert;
|
|
|
|
if( aFPAttributes & FP_THROUGH_HOLE )
|
|
return m_Cfg->m_Render.show_footprints_normal;
|
|
|
|
return m_Cfg->m_Render.show_footprints_virtual;
|
|
}
|
|
|
|
|
|
int BOARD_ADAPTER::GetHolePlatingThickness() const noexcept
|
|
{
|
|
return m_board ? m_board->GetDesignSettings().GetHolePlatingThickness()
|
|
: DEFAULT_COPPER_THICKNESS;
|
|
}
|
|
|
|
|
|
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( float aDiameter3DU ) const
|
|
{
|
|
wxASSERT( aDiameter3DU > 0.0f );
|
|
|
|
return GetCircleSegmentCount( (int)( aDiameter3DU / m_biuTo3Dunits ) );
|
|
}
|
|
|
|
|
|
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( int aDiameterBIU ) const
|
|
{
|
|
wxASSERT( aDiameterBIU > 0 );
|
|
|
|
return GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, FULL_CIRCLE );
|
|
}
|
|
|
|
|
|
void BOARD_ADAPTER::InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
|
|
{
|
|
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::InitSettings" ) );
|
|
|
|
if( aStatusReporter )
|
|
aStatusReporter->Report( _( "Build board outline" ) );
|
|
|
|
wxString msg;
|
|
|
|
const bool haveOutline = createBoardPolygon( &msg );
|
|
|
|
if( aWarningReporter )
|
|
{
|
|
if( !haveOutline )
|
|
aWarningReporter->Report( msg, RPT_SEVERITY_WARNING );
|
|
else
|
|
aWarningReporter->Report( wxEmptyString );
|
|
}
|
|
|
|
BOX2I bbbox;
|
|
|
|
if( m_board )
|
|
bbbox = m_board->ComputeBoundingBox( !m_board->IsFootprintHolder() && haveOutline );
|
|
|
|
// Gives a non null size to avoid issues in zoom / scale calculations
|
|
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
|
|
bbbox.Inflate( pcbIUScale.mmToIU( 10 ) );
|
|
|
|
m_boardSize = bbbox.GetSize();
|
|
m_boardPos = bbbox.Centre();
|
|
|
|
wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
|
|
|
|
m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
|
|
|
|
m_copperLayersCount = m_board ? m_board->GetCopperLayerCount() : 2;
|
|
|
|
// Ensure the board has 2 sides for 3D views, because it is hard to find
|
|
// a *really* single side board in the true life...
|
|
if( m_copperLayersCount < 2 )
|
|
m_copperLayersCount = 2;
|
|
|
|
// Calculate the conversion to apply to all positions.
|
|
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
|
|
|
|
// Hack to keep "home" zoom from being too small.
|
|
if( !m_board || !m_board->IsFootprintHolder() )
|
|
m_biuTo3Dunits *= 1.6f;
|
|
|
|
ReloadColorSettings();
|
|
|
|
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
|
|
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
|
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
|
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
|
|
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
|
|
|
|
g_BevelThickness3DU = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_3DRT_BevelHeight_um / 1000.0 ) * m_biuTo3Dunits;
|
|
|
|
if( m_board )
|
|
{
|
|
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
|
|
|
if( bds.GetStackupDescriptor().GetCount() )
|
|
{
|
|
int thickness = 0;
|
|
|
|
for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
|
|
{
|
|
switch( item->GetType() )
|
|
{
|
|
case BS_ITEM_TYPE_DIELECTRIC:
|
|
for( int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
|
|
thickness += item->GetThickness( sublayer );
|
|
break;
|
|
|
|
case BS_ITEM_TYPE_COPPER:
|
|
{
|
|
// The copper thickness must be > 0 to avoid draw issues (divide by 0 for instance)
|
|
// We use a minimal arbitrary value = 1 micrometer here:
|
|
int copper_thickness = std::max( item->GetThickness(), pcbIUScale.mmToIU( 0.001 ) );
|
|
|
|
if( item->GetBrdLayerId() == F_Cu )
|
|
m_frontCopperThickness3DU = copper_thickness * m_biuTo3Dunits;
|
|
else if( item->GetBrdLayerId() == B_Cu )
|
|
m_backCopperThickness3DU = copper_thickness * m_biuTo3Dunits;
|
|
else if( item->IsEnabled() )
|
|
thickness += copper_thickness;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_boardBodyThickness3DU = thickness * m_biuTo3Dunits;
|
|
}
|
|
}
|
|
|
|
// Init Z position of each layer
|
|
// calculate z position for each copper layer
|
|
// Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = B_Cu)
|
|
// Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = F_Cu)
|
|
|
|
// ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
|
|
// | | Top = Bottom + m_copperThickness
|
|
// |__________________________________|
|
|
// == == == == <- Bottom = -m_epoxyThickness / 2.0,
|
|
// Top = Bottom - m_copperThickness
|
|
|
|
// Generate the Z position of copper layers
|
|
// A copper layer Z position has 2 values: its top Z position and its bottom Z position
|
|
for( auto layer_id : LAYER_RANGE( F_Cu, B_Cu, m_copperLayersCount ) )
|
|
{
|
|
// This approximates internal layer positions (because we're treating all the dielectric
|
|
// layers as having the same thickness). But we don't render them anyway so it doesn't
|
|
// really matter.
|
|
int layer_pos; // the position of the copper layer from board top to bottom
|
|
|
|
switch( layer_id )
|
|
{
|
|
case F_Cu: layer_pos = 0; break;
|
|
case B_Cu: layer_pos = m_copperLayersCount - 1; break;
|
|
default: layer_pos = ( layer_id - B_Cu )/2; break;
|
|
};
|
|
|
|
m_layerZcoordBottom[layer_id] = m_boardBodyThickness3DU / 2.0
|
|
- ( m_boardBodyThickness3DU * layer_pos
|
|
/ ( m_copperLayersCount - 1 ) );
|
|
|
|
if( layer_pos < (m_copperLayersCount / 2) )
|
|
m_layerZcoordTop[layer_id] = m_layerZcoordBottom[layer_id] + m_frontCopperThickness3DU;
|
|
else
|
|
m_layerZcoordTop[layer_id] = m_layerZcoordBottom[layer_id] - m_backCopperThickness3DU;
|
|
}
|
|
|
|
#define layerThicknessMargin 1.1
|
|
const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
|
|
|
|
// This is the top of the copper layer thickness.
|
|
const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
|
|
const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
|
|
|
|
// Fill not copper layers zpos with a dummy position
|
|
// (m_layerZcoordTop[B_Cu]with a small margin)
|
|
// Some important layer position will be set later
|
|
for( int layer_id = 0; layer_id < PCB_LAYER_ID_COUNT; layer_id++ )
|
|
{
|
|
if( IsCopperLayer( (PCB_LAYER_ID)layer_id ) )
|
|
continue;
|
|
|
|
m_layerZcoordBottom[(PCB_LAYER_ID)layer_id] = zpos_copperTop_back - 2.0f * zpos_offset;
|
|
m_layerZcoordTop[(PCB_LAYER_ID)layer_id] = m_layerZcoordBottom[(PCB_LAYER_ID)layer_id] - m_backCopperThickness3DU;
|
|
}
|
|
|
|
// calculate z position for each technical layer
|
|
// Solder mask and Solder paste have the same Z position
|
|
for( PCB_LAYER_ID layer_id : { B_Adhes, B_Mask, B_Paste, F_Adhes, F_Mask, F_Paste, B_SilkS, F_SilkS } )
|
|
{
|
|
float zposTop = 0.0;
|
|
float zposBottom = 0.0;
|
|
|
|
switch( layer_id )
|
|
{
|
|
case B_Adhes:
|
|
zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
|
|
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
case F_Adhes:
|
|
zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
|
|
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
case B_Mask:
|
|
zposBottom = zpos_copperTop_back;
|
|
zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
case B_Paste:
|
|
zposBottom = zpos_copperTop_back;
|
|
zposTop = zpos_copperTop_back - m_solderPasteLayerThickness3DU;
|
|
break;
|
|
|
|
case F_Mask:
|
|
zposBottom = zpos_copperTop_front;
|
|
zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
case F_Paste:
|
|
zposBottom = zpos_copperTop_front;
|
|
zposTop = zpos_copperTop_front + m_solderPasteLayerThickness3DU;
|
|
break;
|
|
|
|
case B_SilkS:
|
|
zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
|
|
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
case F_SilkS:
|
|
zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
|
|
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
m_layerZcoordTop[layer_id] = zposTop;
|
|
m_layerZcoordBottom[layer_id] = zposBottom;
|
|
}
|
|
|
|
m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits, m_boardPos.y * m_biuTo3Dunits, 0.0f );
|
|
|
|
SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits, m_boardSize.y * m_biuTo3Dunits,
|
|
0.0f );
|
|
boardSize /= 2.0f;
|
|
|
|
SFVEC3F boardMin = ( m_boardCenter - boardSize );
|
|
SFVEC3F boardMax = ( m_boardCenter + boardSize );
|
|
|
|
boardMin.z = m_layerZcoordTop[B_Adhes];
|
|
boardMax.z = m_layerZcoordTop[F_Adhes];
|
|
|
|
m_boardBoundingBox = BBOX_3D( boardMin, boardMax );
|
|
|
|
#ifdef PRINT_STATISTICS_3D_VIEWER
|
|
int64_t stats_startCreateBoardPolyTime = GetRunningMicroSecs();
|
|
#endif
|
|
|
|
if( aStatusReporter )
|
|
aStatusReporter->Report( _( "Create layers" ) );
|
|
|
|
createLayers( aStatusReporter );
|
|
|
|
auto to_SFVEC4F =
|
|
[]( const COLOR4D& src )
|
|
{
|
|
return SFVEC4F( src.r, src.g, src.b, src.a );
|
|
};
|
|
|
|
std::map<int, COLOR4D> colors = GetLayerColors();
|
|
|
|
m_BgColorTop = to_SFVEC4F( colors[ LAYER_3D_BACKGROUND_TOP ] );
|
|
m_BgColorBot = to_SFVEC4F( colors[ LAYER_3D_BACKGROUND_BOTTOM ] );
|
|
m_SolderPasteColor = to_SFVEC4F( colors[ LAYER_3D_SOLDERPASTE ] );
|
|
m_SilkScreenColorBot = to_SFVEC4F( colors[ LAYER_3D_SILKSCREEN_BOTTOM ] );
|
|
m_SilkScreenColorTop = to_SFVEC4F( colors[ LAYER_3D_SILKSCREEN_TOP ] );
|
|
m_SolderMaskColorBot = to_SFVEC4F( colors[ LAYER_3D_SOLDERMASK_BOTTOM ] );
|
|
m_SolderMaskColorTop = to_SFVEC4F( colors[ LAYER_3D_SOLDERMASK_TOP ] );
|
|
m_CopperColor = to_SFVEC4F( colors[ LAYER_3D_COPPER_TOP ] );
|
|
m_BoardBodyColor = to_SFVEC4F( colors[ LAYER_3D_BOARD ] );
|
|
m_UserDrawingsColor = to_SFVEC4F( colors[ LAYER_3D_USER_DRAWINGS ] );
|
|
m_UserCommentsColor = to_SFVEC4F( colors[ LAYER_3D_USER_COMMENTS ] );
|
|
m_ECO1Color = to_SFVEC4F( colors[ LAYER_3D_USER_ECO1 ] );
|
|
m_ECO2Color = to_SFVEC4F( colors[ LAYER_3D_USER_ECO2 ] );
|
|
}
|
|
|
|
|
|
std::map<int, COLOR4D> BOARD_ADAPTER::GetDefaultColors() const
|
|
{
|
|
std::map<int, COLOR4D> colors;
|
|
|
|
colors[ LAYER_3D_BACKGROUND_TOP ] = BOARD_ADAPTER::g_DefaultBackgroundTop;
|
|
colors[ LAYER_3D_BACKGROUND_BOTTOM ] = BOARD_ADAPTER::g_DefaultBackgroundBot;
|
|
colors[ LAYER_3D_BOARD ] = BOARD_ADAPTER::g_DefaultBoardBody;
|
|
colors[ LAYER_3D_COPPER_TOP ] = BOARD_ADAPTER::g_DefaultSurfaceFinish;
|
|
colors[ LAYER_3D_COPPER_BOTTOM ] = BOARD_ADAPTER::g_DefaultSurfaceFinish;
|
|
colors[ LAYER_3D_SILKSCREEN_TOP ] = BOARD_ADAPTER::g_DefaultSilkscreen;
|
|
colors[ LAYER_3D_SILKSCREEN_BOTTOM ] = BOARD_ADAPTER::g_DefaultSilkscreen;
|
|
colors[ LAYER_3D_SOLDERMASK_TOP ] = BOARD_ADAPTER::g_DefaultSolderMask;
|
|
colors[ LAYER_3D_SOLDERMASK_BOTTOM ] = BOARD_ADAPTER::g_DefaultSolderMask;
|
|
colors[ LAYER_3D_SOLDERPASTE ] = BOARD_ADAPTER::g_DefaultSolderPaste;
|
|
colors[ LAYER_3D_USER_DRAWINGS ] = BOARD_ADAPTER::g_DefaultComments;
|
|
colors[ LAYER_3D_USER_COMMENTS ] = BOARD_ADAPTER::g_DefaultComments;
|
|
colors[ LAYER_3D_USER_ECO1 ] = BOARD_ADAPTER::g_DefaultECOs;
|
|
colors[ LAYER_3D_USER_ECO2 ] = BOARD_ADAPTER::g_DefaultECOs;
|
|
|
|
return colors;
|
|
}
|
|
|
|
|
|
void BOARD_ADAPTER::GetBoardEditorCopperLayerColors( PCBNEW_SETTINGS* aCfg )
|
|
{
|
|
m_BoardEditorColors.clear();
|
|
|
|
if( m_copperLayersCount <= 0 )
|
|
return;
|
|
|
|
COLOR_SETTINGS* settings = Pgm().GetSettingsManager().GetColorSettings( aCfg->m_ColorTheme );
|
|
|
|
LSET copperLayers = LSET::AllCuMask();
|
|
|
|
for( auto layer : LAYER_RANGE( F_Cu, B_Cu, m_copperLayersCount ) )
|
|
{
|
|
m_BoardEditorColors[ layer ] = settings->GetColor( layer );
|
|
}
|
|
}
|
|
|
|
|
|
std::map<int, COLOR4D> BOARD_ADAPTER::GetLayerColors() const
|
|
{
|
|
std::map<int, COLOR4D> colors;
|
|
|
|
if( LAYER_PRESET_3D* preset = m_Cfg->FindPreset( m_Cfg->m_CurrentPreset ) )
|
|
{
|
|
colors = preset->colors;
|
|
}
|
|
else
|
|
{
|
|
COLOR_SETTINGS* settings = Pgm().GetSettingsManager().GetColorSettings();
|
|
|
|
for( const auto& [ layer, defaultColor /* unused */ ] : GetDefaultColors() )
|
|
colors[ layer ] = settings->GetColor( layer );
|
|
}
|
|
|
|
if( m_Cfg->m_UseStackupColors && m_board )
|
|
{
|
|
const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
|
|
KIGFX::COLOR4D bodyColor( 0, 0, 0, 0 );
|
|
|
|
// Can't do a const KIGFX::COLOR4D& return type here because there are temporary variables
|
|
auto findColor =
|
|
[]( const wxString& aColorName, const CUSTOM_COLORS_LIST& aColorSet ) -> const KIGFX::COLOR4D
|
|
{
|
|
if( aColorName.StartsWith( wxT( "#" ) ) )
|
|
{
|
|
return KIGFX::COLOR4D( aColorName );
|
|
}
|
|
else
|
|
{
|
|
for( const CUSTOM_COLOR_ITEM& color : aColorSet )
|
|
{
|
|
if( color.m_ColorName == aColorName )
|
|
return color.m_Color;
|
|
}
|
|
}
|
|
|
|
return KIGFX::COLOR4D();
|
|
};
|
|
|
|
for( const BOARD_STACKUP_ITEM* stackupItem : stackup.GetList() )
|
|
{
|
|
wxString colorName = stackupItem->GetColor();
|
|
|
|
switch( stackupItem->GetType() )
|
|
{
|
|
case BS_ITEM_TYPE_SILKSCREEN:
|
|
if( stackupItem->GetBrdLayerId() == F_SilkS )
|
|
colors[ LAYER_3D_SILKSCREEN_TOP ] = findColor( colorName, g_SilkColors );
|
|
else
|
|
colors[ LAYER_3D_SILKSCREEN_BOTTOM ] = findColor( colorName, g_SilkColors );
|
|
|
|
break;
|
|
|
|
case BS_ITEM_TYPE_SOLDERMASK:
|
|
if( stackupItem->GetBrdLayerId() == F_Mask )
|
|
colors[ LAYER_3D_SOLDERMASK_TOP ] = findColor( colorName, g_MaskColors );
|
|
else
|
|
colors[ LAYER_3D_SOLDERMASK_BOTTOM ] = findColor( colorName, g_MaskColors );
|
|
|
|
break;
|
|
|
|
case BS_ITEM_TYPE_DIELECTRIC:
|
|
{
|
|
KIGFX::COLOR4D layerColor = findColor( colorName, g_BoardColors );
|
|
|
|
if( bodyColor == COLOR4D( 0, 0, 0, 0 ) )
|
|
bodyColor = layerColor;
|
|
else
|
|
bodyColor = bodyColor.Mix( layerColor, 1.0 - layerColor.a );
|
|
|
|
bodyColor.a += ( 1.0 - bodyColor.a ) * layerColor.a / 2;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( bodyColor != COLOR4D( 0, 0, 0, 0 ) )
|
|
colors[ LAYER_3D_BOARD ] = bodyColor;
|
|
|
|
const wxString& finishName = stackup.m_FinishType;
|
|
|
|
if( finishName.EndsWith( wxT( "OSP" ) ) )
|
|
{
|
|
colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Copper" ), g_FinishColors );
|
|
}
|
|
else if( finishName.EndsWith( wxT( "IG" ) )
|
|
|| finishName.EndsWith( wxT( "gold" ) ) )
|
|
{
|
|
colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Gold" ), g_FinishColors );
|
|
}
|
|
else if( finishName.StartsWith( wxT( "HAL" ) )
|
|
|| finishName.StartsWith( wxT( "HASL" ) )
|
|
|| finishName.EndsWith( wxT( "tin" ) )
|
|
|| finishName.EndsWith( wxT( "nickel" ) ) )
|
|
{
|
|
colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Tin" ), g_FinishColors );
|
|
}
|
|
else if( finishName.EndsWith( wxT( "silver" ) ) )
|
|
{
|
|
colors[ LAYER_3D_COPPER_TOP ] = findColor( wxT( "Silver" ), g_FinishColors );
|
|
}
|
|
}
|
|
|
|
colors[ LAYER_3D_COPPER_BOTTOM ] = colors[ LAYER_3D_COPPER_TOP ];
|
|
|
|
for( const auto& [layer, val] : m_ColorOverrides )
|
|
colors[layer] = val;
|
|
|
|
return colors;
|
|
}
|
|
|
|
|
|
void BOARD_ADAPTER::SetLayerColors( const std::map<int, COLOR4D>& aColors )
|
|
{
|
|
COLOR_SETTINGS* settings = Pgm().GetSettingsManager().GetColorSettings();
|
|
|
|
for( const auto& [ layer, color ] : aColors )
|
|
settings->SetColor( layer, color );
|
|
|
|
Pgm().GetSettingsManager().SaveColorSettings( settings, "3d_viewer" );
|
|
}
|
|
|
|
|
|
void BOARD_ADAPTER::SetVisibleLayers( const std::bitset<LAYER_3D_END>& aLayers )
|
|
{
|
|
m_Cfg->m_Render.show_board_body = aLayers.test( LAYER_3D_BOARD );
|
|
m_Cfg->m_Render.show_copper_top = aLayers.test( LAYER_3D_COPPER_TOP );
|
|
m_Cfg->m_Render.show_copper_bottom = aLayers.test( LAYER_3D_COPPER_BOTTOM );
|
|
m_Cfg->m_Render.show_silkscreen_top = aLayers.test( LAYER_3D_SILKSCREEN_TOP );
|
|
m_Cfg->m_Render.show_silkscreen_bottom = aLayers.test( LAYER_3D_SILKSCREEN_BOTTOM );
|
|
m_Cfg->m_Render.show_soldermask_top = aLayers.test( LAYER_3D_SOLDERMASK_TOP );
|
|
m_Cfg->m_Render.show_soldermask_bottom = aLayers.test( LAYER_3D_SOLDERMASK_BOTTOM );
|
|
m_Cfg->m_Render.show_solderpaste = aLayers.test( LAYER_3D_SOLDERPASTE );
|
|
m_Cfg->m_Render.show_adhesive = aLayers.test( LAYER_3D_ADHESIVE );
|
|
m_Cfg->m_Render.show_comments = aLayers.test( LAYER_3D_USER_COMMENTS );
|
|
m_Cfg->m_Render.show_drawings = aLayers.test( LAYER_3D_USER_DRAWINGS );
|
|
m_Cfg->m_Render.show_eco1 = aLayers.test( LAYER_3D_USER_ECO1 );
|
|
m_Cfg->m_Render.show_eco2 = aLayers.test( LAYER_3D_USER_ECO2 );
|
|
|
|
m_Cfg->m_Render.show_footprints_normal = aLayers.test( LAYER_3D_TH_MODELS );
|
|
m_Cfg->m_Render.show_footprints_insert = aLayers.test( LAYER_3D_SMD_MODELS );
|
|
m_Cfg->m_Render.show_footprints_virtual = aLayers.test( LAYER_3D_VIRTUAL_MODELS );
|
|
m_Cfg->m_Render.show_footprints_not_in_posfile = aLayers.test( LAYER_3D_MODELS_NOT_IN_POS );
|
|
m_Cfg->m_Render.show_footprints_dnp = aLayers.test( LAYER_3D_MODELS_MARKED_DNP );
|
|
|
|
m_Cfg->m_Render.show_fp_references = aLayers.test( LAYER_FP_REFERENCES );
|
|
m_Cfg->m_Render.show_fp_values = aLayers.test( LAYER_FP_VALUES );
|
|
m_Cfg->m_Render.show_fp_text = aLayers.test( LAYER_FP_TEXT );
|
|
|
|
m_Cfg->m_Render.show_model_bbox = aLayers.test( LAYER_3D_BOUNDING_BOXES );
|
|
m_Cfg->m_Render.show_off_board_silk = aLayers.test( LAYER_3D_OFF_BOARD_SILK );
|
|
m_Cfg->m_Render.show_axis = aLayers.test( LAYER_3D_AXES );
|
|
}
|
|
|
|
|
|
std::bitset<LAYER_3D_END> BOARD_ADAPTER::GetVisibleLayers() const
|
|
{
|
|
std::bitset<LAYER_3D_END> ret;
|
|
|
|
ret.set( LAYER_3D_BOARD, m_Cfg->m_Render.show_board_body );
|
|
ret.set( LAYER_3D_COPPER_TOP, m_Cfg->m_Render.show_copper_top );
|
|
ret.set( LAYER_3D_COPPER_BOTTOM, m_Cfg->m_Render.show_copper_bottom );
|
|
ret.set( LAYER_3D_SILKSCREEN_TOP, m_Cfg->m_Render.show_silkscreen_top );
|
|
ret.set( LAYER_3D_SILKSCREEN_BOTTOM, m_Cfg->m_Render.show_silkscreen_bottom );
|
|
ret.set( LAYER_3D_SOLDERMASK_TOP, m_Cfg->m_Render.show_soldermask_top );
|
|
ret.set( LAYER_3D_SOLDERMASK_BOTTOM, m_Cfg->m_Render.show_soldermask_bottom );
|
|
ret.set( LAYER_3D_SOLDERPASTE, m_Cfg->m_Render.show_solderpaste );
|
|
ret.set( LAYER_3D_ADHESIVE, m_Cfg->m_Render.show_adhesive );
|
|
ret.set( LAYER_3D_USER_COMMENTS, m_Cfg->m_Render.show_comments );
|
|
ret.set( LAYER_3D_USER_DRAWINGS, m_Cfg->m_Render.show_drawings );
|
|
ret.set( LAYER_3D_USER_ECO1, m_Cfg->m_Render.show_eco1 );
|
|
ret.set( LAYER_3D_USER_ECO2, m_Cfg->m_Render.show_eco2 );
|
|
|
|
ret.set( LAYER_FP_REFERENCES, m_Cfg->m_Render.show_fp_references );
|
|
ret.set( LAYER_FP_VALUES, m_Cfg->m_Render.show_fp_values );
|
|
ret.set( LAYER_FP_TEXT, m_Cfg->m_Render.show_fp_text );
|
|
|
|
ret.set( LAYER_3D_TH_MODELS, m_Cfg->m_Render.show_footprints_normal );
|
|
ret.set( LAYER_3D_SMD_MODELS, m_Cfg->m_Render.show_footprints_insert );
|
|
ret.set( LAYER_3D_VIRTUAL_MODELS, m_Cfg->m_Render.show_footprints_virtual );
|
|
ret.set( LAYER_3D_MODELS_NOT_IN_POS, m_Cfg->m_Render.show_footprints_not_in_posfile );
|
|
ret.set( LAYER_3D_MODELS_MARKED_DNP, m_Cfg->m_Render.show_footprints_dnp );
|
|
|
|
ret.set( LAYER_3D_BOUNDING_BOXES, m_Cfg->m_Render.show_model_bbox );
|
|
ret.set( LAYER_3D_OFF_BOARD_SILK, m_Cfg->m_Render.show_off_board_silk );
|
|
ret.set( LAYER_3D_AXES, m_Cfg->m_Render.show_axis );
|
|
|
|
if( m_Cfg->m_CurrentPreset == FOLLOW_PCB )
|
|
{
|
|
if( !m_board )
|
|
return ret;
|
|
|
|
ret.set( LAYER_3D_BOARD, true );
|
|
ret.set( LAYER_3D_COPPER_TOP, m_board->IsLayerVisible( F_Cu ) );
|
|
ret.set( LAYER_3D_COPPER_BOTTOM, m_board->IsLayerVisible( B_Cu ) );
|
|
ret.set( LAYER_3D_SILKSCREEN_TOP, m_board->IsLayerVisible( F_SilkS ) );
|
|
ret.set( LAYER_3D_SILKSCREEN_BOTTOM, m_board->IsLayerVisible( B_SilkS ) );
|
|
ret.set( LAYER_3D_SOLDERMASK_TOP, m_board->IsLayerVisible( F_Mask ) );
|
|
ret.set( LAYER_3D_SOLDERMASK_BOTTOM, m_board->IsLayerVisible( B_Mask ) );
|
|
ret.set( LAYER_3D_SOLDERPASTE, m_board->IsLayerVisible( F_Paste ) );
|
|
ret.set( LAYER_3D_ADHESIVE, m_board->IsLayerVisible( F_Adhes ) );
|
|
ret.set( LAYER_3D_USER_COMMENTS, m_board->IsLayerVisible( Cmts_User ) );
|
|
ret.set( LAYER_3D_USER_DRAWINGS, m_board->IsLayerVisible( Dwgs_User ) );
|
|
ret.set( LAYER_3D_USER_ECO1, m_board->IsLayerVisible( Eco1_User ) );
|
|
ret.set( LAYER_3D_USER_ECO2, m_board->IsLayerVisible( Eco2_User ) );
|
|
|
|
for( GAL_LAYER_ID layer : { LAYER_FP_REFERENCES, LAYER_FP_VALUES, LAYER_FP_TEXT } )
|
|
ret.set( layer, m_board->IsElementVisible( layer ) );
|
|
}
|
|
else if( m_Cfg->m_CurrentPreset == FOLLOW_PLOT_SETTINGS )
|
|
{
|
|
if( !m_board )
|
|
return ret;
|
|
|
|
const PCB_PLOT_PARAMS& plotParams = m_board->GetPlotOptions();
|
|
LSET layers = plotParams.GetLayerSelection() | plotParams.GetPlotOnAllLayersSelection();
|
|
|
|
ret.set( LAYER_3D_BOARD, true );
|
|
ret.set( LAYER_3D_COPPER_TOP, layers.test( F_Cu ) );
|
|
ret.set( LAYER_3D_COPPER_BOTTOM, layers.test( B_Cu ) );
|
|
ret.set( LAYER_3D_SILKSCREEN_TOP, layers.test( F_SilkS ) );
|
|
ret.set( LAYER_3D_SILKSCREEN_BOTTOM, layers.test( B_SilkS ) );
|
|
ret.set( LAYER_3D_SOLDERMASK_TOP, layers.test( F_Mask ) );
|
|
ret.set( LAYER_3D_SOLDERMASK_BOTTOM, layers.test( B_Mask ) );
|
|
ret.set( LAYER_3D_SOLDERPASTE, layers.test( F_Paste ) );
|
|
ret.set( LAYER_3D_ADHESIVE, layers.test( F_Adhes ) );
|
|
ret.set( LAYER_3D_USER_COMMENTS, layers.test( Cmts_User ) );
|
|
ret.set( LAYER_3D_USER_DRAWINGS, layers.test( Dwgs_User ) );
|
|
ret.set( LAYER_3D_USER_ECO1, layers.test( Eco1_User ) );
|
|
ret.set( LAYER_3D_USER_ECO2, layers.test( Eco2_User ) );
|
|
|
|
ret.set( LAYER_FP_REFERENCES, plotParams.GetPlotReference() );
|
|
ret.set( LAYER_FP_VALUES, plotParams.GetPlotValue() );
|
|
ret.set( LAYER_FP_TEXT, plotParams.GetPlotFPText() );
|
|
}
|
|
else if( LAYER_PRESET_3D* preset = m_Cfg->FindPreset( m_Cfg->m_CurrentPreset ) )
|
|
{
|
|
ret = preset->layers;
|
|
}
|
|
else
|
|
{
|
|
ret.set( LAYER_3D_BOARD, m_Cfg->m_Render.show_board_body );
|
|
ret.set( LAYER_3D_COPPER_TOP, m_Cfg->m_Render.show_copper_top );
|
|
ret.set( LAYER_3D_COPPER_BOTTOM, m_Cfg->m_Render.show_copper_bottom );
|
|
ret.set( LAYER_3D_SILKSCREEN_TOP, m_Cfg->m_Render.show_silkscreen_top );
|
|
ret.set( LAYER_3D_SILKSCREEN_BOTTOM, m_Cfg->m_Render.show_silkscreen_bottom );
|
|
ret.set( LAYER_3D_SOLDERMASK_TOP, m_Cfg->m_Render.show_soldermask_top );
|
|
ret.set( LAYER_3D_SOLDERMASK_BOTTOM, m_Cfg->m_Render.show_soldermask_bottom );
|
|
ret.set( LAYER_3D_SOLDERPASTE, m_Cfg->m_Render.show_solderpaste );
|
|
ret.set( LAYER_3D_ADHESIVE, m_Cfg->m_Render.show_adhesive );
|
|
ret.set( LAYER_3D_USER_COMMENTS, m_Cfg->m_Render.show_comments );
|
|
ret.set( LAYER_3D_USER_DRAWINGS, m_Cfg->m_Render.show_drawings );
|
|
ret.set( LAYER_3D_USER_ECO1, m_Cfg->m_Render.show_eco1 );
|
|
ret.set( LAYER_3D_USER_ECO2, m_Cfg->m_Render.show_eco2 );
|
|
|
|
ret.set( LAYER_FP_REFERENCES, m_Cfg->m_Render.show_fp_references );
|
|
ret.set( LAYER_FP_VALUES, m_Cfg->m_Render.show_fp_values );
|
|
ret.set( LAYER_FP_TEXT, m_Cfg->m_Render.show_fp_text );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
std::bitset<LAYER_3D_END> BOARD_ADAPTER::GetDefaultVisibleLayers() const
|
|
{
|
|
std::bitset<LAYER_3D_END> ret;
|
|
|
|
ret.set( LAYER_3D_BOARD, true );
|
|
ret.set( LAYER_3D_COPPER_TOP, true );
|
|
ret.set( LAYER_3D_COPPER_BOTTOM, true );
|
|
ret.set( LAYER_3D_SILKSCREEN_TOP, true );
|
|
ret.set( LAYER_3D_SILKSCREEN_BOTTOM, true );
|
|
ret.set( LAYER_3D_SOLDERMASK_TOP, true );
|
|
ret.set( LAYER_3D_SOLDERMASK_BOTTOM, true );
|
|
ret.set( LAYER_3D_SOLDERPASTE, true );
|
|
ret.set( LAYER_3D_ADHESIVE, true );
|
|
ret.set( LAYER_3D_USER_COMMENTS, false );
|
|
ret.set( LAYER_3D_USER_DRAWINGS, false );
|
|
ret.set( LAYER_3D_USER_ECO1, false );
|
|
ret.set( LAYER_3D_USER_ECO2, false );
|
|
|
|
ret.set( LAYER_FP_REFERENCES, true );
|
|
ret.set( LAYER_FP_VALUES, true );
|
|
ret.set( LAYER_FP_TEXT, true );
|
|
|
|
ret.set( LAYER_3D_TH_MODELS, true );
|
|
ret.set( LAYER_3D_SMD_MODELS, true );
|
|
ret.set( LAYER_3D_VIRTUAL_MODELS, true );
|
|
ret.set( LAYER_3D_MODELS_NOT_IN_POS, false );
|
|
ret.set( LAYER_3D_MODELS_MARKED_DNP, false );
|
|
|
|
ret.set( LAYER_3D_BOUNDING_BOXES, false );
|
|
ret.set( LAYER_3D_OFF_BOARD_SILK, false );
|
|
ret.set( LAYER_3D_AXES, true );
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
|
|
{
|
|
m_board_poly.RemoveAllContours();
|
|
|
|
if( !m_board )
|
|
return false;
|
|
|
|
bool success;
|
|
|
|
if( m_board->IsFootprintHolder() )
|
|
{
|
|
if( !m_board->GetFirstFootprint() )
|
|
{
|
|
if( aErrorMsg )
|
|
*aErrorMsg = _( "No footprint loaded." );
|
|
|
|
return false;
|
|
}
|
|
|
|
// max dist from one endPt to next startPt
|
|
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
|
|
|
|
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
|
|
m_board->GetDesignSettings().m_MaxError,
|
|
chainingEpsilon );
|
|
m_board_poly.Simplify();
|
|
|
|
if( !success && aErrorMsg )
|
|
{
|
|
*aErrorMsg = _( "Footprint outline is missing or malformed. Run Footprint Checker for "
|
|
"a full analysis." );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
success = m_board->GetBoardPolygonOutlines( m_board_poly, nullptr, false, true );
|
|
|
|
if( !success && aErrorMsg )
|
|
*aErrorMsg = _( "Board outline is missing or malformed. Run DRC for a full analysis." );
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
float BOARD_ADAPTER::GetFootprintZPos( bool aIsFlipped ) const
|
|
{
|
|
if( aIsFlipped )
|
|
{
|
|
if( auto it = m_layerZcoordBottom.find( B_Paste ); it != m_layerZcoordBottom.end() )
|
|
return it->second;
|
|
}
|
|
else
|
|
{
|
|
if( auto it = m_layerZcoordTop.find( F_Paste ); it != m_layerZcoordTop.end() )
|
|
return it->second;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
SFVEC4F BOARD_ADAPTER::GetLayerColor( PCB_LAYER_ID aLayerId ) const
|
|
{
|
|
wxASSERT( aLayerId < PCB_LAYER_ID_COUNT );
|
|
|
|
const COLOR4D color = m_colors->GetColor( aLayerId );
|
|
|
|
return SFVEC4F( color.r, color.g, color.b, color.a );
|
|
}
|
|
|
|
|
|
SFVEC4F BOARD_ADAPTER::GetItemColor( int aItemId ) const
|
|
{
|
|
return GetColor( m_colors->GetColor( aItemId ) );
|
|
}
|
|
|
|
|
|
SFVEC4F BOARD_ADAPTER::GetColor( const COLOR4D& aColor ) const
|
|
{
|
|
return SFVEC4F( aColor.r, aColor.g, aColor.b, aColor.a );
|
|
}
|
|
|
|
|
|
SFVEC2F BOARD_ADAPTER::GetSphericalCoord( int i ) const
|
|
{
|
|
SFVEC2F sphericalCoord =
|
|
SFVEC2F( ( m_Cfg->m_Render.raytrace_lightElevation[i] + 90.0f ) / 180.0f,
|
|
m_Cfg->m_Render.raytrace_lightAzimuth[i] / 180.0f );
|
|
|
|
sphericalCoord.x = glm::clamp( sphericalCoord.x, 0.0f, 1.0f );
|
|
sphericalCoord.y = glm::clamp( sphericalCoord.y, 0.0f, 2.0f );
|
|
|
|
return sphericalCoord;
|
|
}
|