Add board stackup parsing to Kicad2Step.

Fixes https://gitlab.com/kicad/code/kicad/issues/11565

(cherry picked from commit e85105a907)
This commit is contained in:
Jeff Young 2022-05-09 21:02:33 +01:00
parent aac4f30b7d
commit 68d9b3cbf7
4 changed files with 189 additions and 27 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* 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( wxEmptyString );
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<KICADCURVE> poly = std::make_unique<KICADCURVE>();
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" ) );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* 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 <wx/string.h>
#include <wx/colour.h>
#include <string>
#include <vector>
#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<KICADFOOTPRINT*> m_footprints;
std::vector<KICADCURVE*> m_curves;
wxString m_pcbName;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* 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();
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* 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<KICADCURVE>::iterator m_mincurve; // iterator to the leftmost curve