From e85105a907141e80c4c782ea74defc4bd4a3d1b0 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 9 May 2022 21:02:33 +0100 Subject: [PATCH] Add board stackup parsing to Kicad2Step. Fixes https://gitlab.com/kicad/code/kicad/issues/11565 --- utils/kicad2step/pcb/kicadpcb.cpp | 179 ++++++++++++++++++++++++++--- utils/kicad2step/pcb/kicadpcb.h | 10 +- utils/kicad2step/pcb/oce_utils.cpp | 19 ++- utils/kicad2step/pcb/oce_utils.h | 8 +- 4 files changed, 189 insertions(+), 27 deletions(-) diff --git a/utils/kicad2step/pcb/kicadpcb.cpp b/utils/kicad2step/pcb/kicadpcb.cpp index c438a0cc36..120015f486 100644 --- a/utils/kicad2step/pcb/kicadpcb.cpp +++ b/utils/kicad2step/pcb/kicadpcb.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo - * Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2020-2022 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 @@ -43,6 +43,13 @@ KICADPCB::KICADPCB( const wxString& aPcbName ) { m_resolver.Set3DConfigDir( wxT( "" ) ); + + m_topSolderMask = wxColour( 15, 102, 15 ); + m_bottomSolderMask = wxColour( 15, 102, 15 ); + m_topSilk = wxColour( 240, 240, 240 ); + m_bottomSilk = wxColour( 240, 240, 240 ); + m_copperFinish = wxColour( 191, 155, 58 ); + m_thickness = 1.6; m_pcb_model = nullptr; m_minDistance = MIN_DISTANCE; @@ -124,9 +131,7 @@ bool KICADPCB::ReadFile( const wxString& aFileName ) bool KICADPCB::WriteSTEP( const wxString& aFileName ) { if( m_pcb_model ) - { return m_pcb_model->WriteSTEP( aFileName ); - } return false; } @@ -136,9 +141,7 @@ bool KICADPCB::WriteSTEP( const wxString& aFileName ) bool KICADPCB::WriteIGES( const wxString& aFileName ) { if( m_pcb_model ) - { return m_pcb_model->WriteIGES( aFileName ); - } return false; } @@ -250,6 +253,7 @@ bool KICADPCB::parseLayers( SEXPR::SEXPR* data ) child->GetLineNumber() ) ); return false; } + std::string ref; if( child->GetChild( 1 )->IsSymbol() ) @@ -264,6 +268,146 @@ bool KICADPCB::parseLayers( SEXPR::SEXPR* data ) } +bool KICADPCB::parseStackupLayer( SEXPR::SEXPR* data ) +{ + if( data->IsList() && data->GetNumberOfChildren() >= 3 ) + { + size_t nc = data->GetNumberOfChildren(); + SEXPR::SEXPR* child = NULL; + std::string ref; + std::string value; + + for( size_t i = 1; i < nc; ++i ) + { + child = data->GetChild( i ); + + if( child->IsList() && child->GetChild( 0 )->GetSymbol() == "type" ) + { + if( child->GetChild( 1 )->IsSymbol() ) + ref = child->GetChild( 1 )->GetSymbol(); + else + ref = child->GetChild( 1 )->GetString(); + } + else if( child->IsList() && child->GetChild( 0 )->GetSymbol() == "color" ) + { + if( child->GetChild( 1 )->IsSymbol() ) + value = child->GetChild( 1 )->GetSymbol(); + else + value = child->GetChild( 1 )->GetString(); + } + } + + if( !value.empty() ) + { + wxString colorName( value ); + wxColour color; + + if( colorName.StartsWith( wxT( "#" ) ) ) + color = wxColour( colorName.Left( 7 ) /* drop alpha component */ ); + else if( colorName == wxT( "Green" ) ) + color = wxColour( 20, 51, 36 ); + else if( colorName == wxT( "Light Green" ) ) + color = wxColour( 91, 168, 12); + else if( colorName == wxT( "Saturated Green" ) ) + color = wxColour( 13, 104, 11 ); + else if( colorName == wxT( "Red" ) ) + color = wxColour( 181, 19, 21 ); + else if( colorName == wxT( "Light Red" ) ) + color = wxColour( 210, 40, 14 ); + else if( colorName == wxT( "Red/Orange" ) ) + color = wxColour( 239, 53, 41 ); + else if( colorName == wxT( "Blue" ) ) + color = wxColour( 2, 59, 162 ); + else if( colorName == wxT( "Light Blue 1" ) ) + color = wxColour( 54, 79, 116 ); + else if( colorName == wxT( "Light Blue 2" ) ) + color = wxColour( 61, 85, 130 ); + else if( colorName == wxT( "Green/Blue" ) ) + color = wxColour( 21, 70, 80 ); + else if( colorName == wxT( "Black" ) ) + color = wxColour( 11, 11, 11 ); + else if( colorName == wxT( "White" ) ) + color = wxColour( 245, 245, 245 ); + else if( colorName == wxT( "Purple" ) ) + color = wxColour( 32, 2, 53 ); + else if( colorName == wxT( "Light Purple" ) ) + color = wxColour( 119, 31, 91 ); + else if( colorName == wxT( "Yellow" ) ) + color = wxColour( 194, 195, 0 ); + + if( ref == "Top Silk Screen" ) + m_topSilk = color; + else if( ref == "Top Solder Mask" ) + m_topSolderMask = color; + else if( ref == "Bottom Silk Screen" ) + m_bottomSilk = color; + else if( ref == "Bottom Solder Mask" ) + m_bottomSolderMask = color; + } + } + + return true; +} + + +bool KICADPCB::parseStackup( SEXPR::SEXPR* data ) +{ + size_t nc = data->GetNumberOfChildren(); + SEXPR::SEXPR* child = NULL; + + for( size_t i = 1; i < nc; ++i ) + { + child = data->GetChild( i ); + + if( !child->IsList() ) + { + ReportMessage( wxString::Format( wxT( "corrupt PCB file (line %d)\n" ), + child->GetLineNumber() ) ); + return false; + } + + std::string ref; + + if( child->GetChild( 0 )->GetSymbol() == "layer" ) + { + parseStackupLayer( child ); + } + else if( child->GetChild( 0 )->GetSymbol() == "copper_finish" ) + { + if( child->GetChild( 1 )->IsSymbol() ) + ref = child->GetChild( 1 )->GetSymbol(); + else + ref = child->GetChild( 1 )->GetString(); + + wxString finishName( ref ); + + if( finishName.EndsWith( wxT( "OSP" ) ) ) + { + m_copperFinish = wxColour( 184, 115, 50 ); + } + else if( finishName.EndsWith( wxT( "IG" ) ) + || finishName.EndsWith( wxT( "gold" ) ) ) + { + m_copperFinish = wxColour( 178, 156, 0 ); + } + else if( finishName.StartsWith( wxT( "HAL" ) ) + || finishName.StartsWith( wxT( "HASL" ) ) + || finishName.EndsWith( wxT( "tin" ) ) + || finishName.EndsWith( wxT( "nickel" ) ) ) + { + m_copperFinish = wxColour( 160, 160, 160 ); + } + else if( finishName.EndsWith( wxT( "silver" ) ) ) + { + m_copperFinish = wxColour( 213, 213, 213 ); + } + } + } + + return true; +} + + int KICADPCB::GetLayerId( std::string& aLayerName ) { int lid = -1; @@ -323,7 +467,10 @@ bool KICADPCB::parseSetup( SEXPR::SEXPR* data ) m_drillOrigin.y = child->GetChild( 2 )->GetDouble(); m_hasDrillOrigin = true; } - + else if( child->GetChild( 0 )->GetSymbol() == "stackup" ) + { + parseStackup( child ); + } } return true; @@ -389,15 +536,11 @@ bool KICADPCB::parsePolygon( SEXPR::SEXPR* data ) std::unique_ptr poly = std::make_unique(); if( !poly->Read( data, CURVE_POLYGON ) ) - { return false; - } // reject any curves not on the Edge.Cuts layer if( poly->GetLayer() != LAYER_EDGE ) - { return true; - } auto pts = poly->m_poly; @@ -460,23 +603,23 @@ bool KICADPCB::ComposePCB( bool aComposeVirtual, bool aSubstituteModels ) // Determine the coordinate system reference: // Precedence of reference point is Drill Origin > Grid Origin > User Offset if( m_useDrillOrigin && m_hasDrillOrigin ) - { origin = m_drillOrigin; - } else if( m_useGridOrigin && m_hasDrillOrigin ) - { origin = m_gridOrigin; - } else - { origin = m_origin; - } m_pcb_model = new PCBMODEL( m_pcbName ); + + // TODO: Handle when top & bottom soldermask colours are different... + m_pcb_model->SetBoardColor( m_topSolderMask.Red() / 255.0, + m_topSolderMask.Green() / 255.0, + m_topSolderMask.Blue() / 255.0 ); + m_pcb_model->SetPCBThickness( m_thickness ); m_pcb_model->SetMinDistance( m_minDistance ); - for( auto i : m_curves ) + for( KICADCURVE* i : m_curves ) { if( CURVE_NONE == i->m_form || LAYER_EDGE != i->m_layer ) continue; @@ -501,7 +644,7 @@ bool KICADPCB::ComposePCB( bool aComposeVirtual, bool aSubstituteModels ) m_pcb_model->AddOutlineSegment( &lcurve ); } - for( auto i : m_footprints ) + for( KICADFOOTPRINT* i : m_footprints ) i->ComposePCB( m_pcb_model, &m_resolver, origin, aComposeVirtual, aSubstituteModels ); ReportMessage( wxT( "Create PCB solid model\n" ) ); diff --git a/utils/kicad2step/pcb/kicadpcb.h b/utils/kicad2step/pcb/kicadpcb.h index 3f41b20ace..08669b6dba 100644 --- a/utils/kicad2step/pcb/kicadpcb.h +++ b/utils/kicad2step/pcb/kicadpcb.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2022 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 @@ -31,6 +31,7 @@ #define KICADPCB_H #include +#include #include #include #include "3d_resolver.h" @@ -92,6 +93,8 @@ private: bool parsePCB( SEXPR::SEXPR* data ); bool parseGeneral( SEXPR::SEXPR* data ); bool parseSetup( SEXPR::SEXPR* data ); + bool parseStackup( SEXPR::SEXPR* data ); + bool parseStackupLayer( SEXPR::SEXPR* data ); bool parseLayers( SEXPR::SEXPR* data ); bool parseModule( SEXPR::SEXPR* data ); bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType ); @@ -118,6 +121,11 @@ private: // PCB parameters/entities double m_thickness; + wxColour m_topSolderMask; + wxColour m_bottomSolderMask; // Not currently used. + wxColour m_topSilk; // Not currently used. + wxColour m_bottomSilk; // Not currently used. + wxColour m_copperFinish; // Not currently used. std::vector m_footprints; std::vector m_curves; wxString m_pcbName; diff --git a/utils/kicad2step/pcb/oce_utils.cpp b/utils/kicad2step/pcb/oce_utils.cpp index 6047d526c8..1e6cff9ced 100644 --- a/utils/kicad2step/pcb/oce_utils.cpp +++ b/utils/kicad2step/pcb/oce_utils.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2022 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 @@ -673,6 +673,14 @@ void PCBMODEL::SetPCBThickness( double aThickness ) } +void PCBMODEL::SetBoardColor( double r, double g, double b ) +{ + m_boardColor[0] = r; + m_boardColor[1] = g; + m_boardColor[2] = b; +} + + void PCBMODEL::SetMinDistance( double aDistance ) { // m_minDistance2 keeps a squared distance value @@ -889,16 +897,17 @@ bool PCBMODEL::CreatePCB() // color the PCB - Handle( XCAFDoc_ColorTool ) color = XCAFDoc_DocumentTool::ColorTool( m_doc->Main () ); - Quantity_Color pcb_green( 0.06, 0.4, 0.06, Quantity_TOC_RGB ); - color->SetColor( m_pcb_label, pcb_green, XCAFDoc_ColorSurf ); + Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main () ); + Quantity_Color color( m_boardColor[0], m_boardColor[1], m_boardColor[2], Quantity_TOC_RGB ); + + colorTool->SetColor( m_pcb_label, color, XCAFDoc_ColorSurf ); TopExp_Explorer topex; topex.Init( m_assy->GetShape( m_pcb_label ), TopAbs_SOLID ); while( topex.More() ) { - color->SetColor( topex.Current(), pcb_green, XCAFDoc_ColorSurf ); + colorTool->SetColor( topex.Current(), color, XCAFDoc_ColorSurf ); topex.Next(); } diff --git a/utils/kicad2step/pcb/oce_utils.h b/utils/kicad2step/pcb/oce_utils.h index d76a36639f..027ddd5cfd 100644 --- a/utils/kicad2step/pcb/oce_utils.h +++ b/utils/kicad2step/pcb/oce_utils.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2022 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 @@ -101,6 +101,8 @@ public: TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale, bool aSubstituteModels = true ); + void SetBoardColor( double r, double g, double b ); + // set the thickness of the PCB (mm); the top of the PCB shall be at Z = aThickness // aThickness < 0.0 == use default thickness // aThickness <= THICKNESS_MIN == use THICKNESS_MIN @@ -156,10 +158,10 @@ private: int m_components; // number of successfully loaded components; double m_precision; // model (length unit) numeric precision double m_angleprec; // angle numeric precision + double m_boardColor[3];// RGB values double m_thickness; // PCB thickness, mm - // minimum X value in curves (leftmost curve feature). - double m_minx; + double m_minx; // leftmost curve point double m_minDistance2; // minimum squared distance between items (mm) std::list::iterator m_mincurve; // iterator to the leftmost curve