ADDED: --net-filter option to STEP/BREP export CLI.

This commit is contained in:
Alex Shvartzkop 2024-04-24 18:28:44 +03:00
parent 33869dbb61
commit 5f81e01f43
8 changed files with 77 additions and 9 deletions

View File

@ -56,6 +56,7 @@ public:
bool m_includeDNP;
bool m_substModels;
bool m_optimizeStep;
wxString m_netFilter;
wxString m_filename;
wxString m_outputFile;
double m_xOrigin;

View File

@ -44,6 +44,7 @@
#define ARG_INCLUDE_INNER_COPPER "--include-inner-copper"
#define ARG_FUSE_SHAPES "--fuse-shapes"
#define ARG_NO_OPTIMIZE_STEP "--no-optimize-step"
#define ARG_NET_FILTER "--net-filter"
#define ARG_FORMAT "--format"
#define ARG_VRML_UNITS "--units"
#define ARG_VRML_MODELS_DIR "--models-dir"
@ -135,6 +136,11 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string& aNa
.help( UTF8STDSTR(
_( "Minimum distance between points to treat them as separate ones" ) ) )
.metavar( "MIN_DIST" );
m_argParser.add_argument( ARG_NET_FILTER )
.default_value( std::string() )
.help( UTF8STDSTR( _(
"Only include copper items belonging to nets matching this wildcard" ) ) );
}
if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP )
@ -187,6 +193,7 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
step->m_exportInnerCopper = m_argParser.get<bool>( ARG_INCLUDE_INNER_COPPER );
step->m_fuseShapes = m_argParser.get<bool>( ARG_FUSE_SHAPES );
step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
step->m_netFilter = From_UTF8( m_argParser.get<std::string>( ARG_NET_FILTER ).c_str() );
}
if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP )

View File

@ -508,6 +508,8 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
if( m_fuseShapes )
cmdK2S.Append( wxT( " --fuse-shapes" ) );
// TODO: --net-filter
// Note: for some reason, using \" to insert a quote in a format string, under MacOS
// wxString::Format does not work. So use a %c format in string
int quote = '\'';

View File

@ -24,6 +24,7 @@
*/
#include "exporter_step.h"
#include <advanced_config.h>
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
@ -172,7 +173,8 @@ EXPORTER_STEP::~EXPORTER_STEP()
bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
{
bool hasdata = false;
bool hasdata = false;
std::vector<PAD*> padsMatchingNetFilter;
// Dump the pad holes into the PCB
for( PAD* pad : aFootprint->Pads() )
@ -180,11 +182,16 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri
if( m_pcbModel->AddPadHole( pad, aOrigin ) )
hasdata = true;
if( !m_params.m_netFilter.IsEmpty() && !pad->GetNetname().Matches( m_params.m_netFilter ) )
continue;
if( m_params.m_exportTracksVias )
{
if( m_pcbModel->AddPadShape( pad, aOrigin ) )
hasdata = true;
}
padsMatchingNetFilter.push_back( pad );
}
// Build 3D shapes of the footprint graphic items on external layers:
@ -192,13 +199,42 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri
{
int maxError = m_board->GetDesignSettings().m_MaxError;
for( PCB_LAYER_ID pcblayer : aFootprint->GetLayerSet().CuStack() )
for( PCB_LAYER_ID pcblayer : LSET( aFootprint->GetLayerSet() & LSET::AllCuMask() ).Seq() )
{
aFootprint->TransformFPShapesToPolySet( m_poly_copper_shapes[pcblayer], pcblayer, 0,
maxError, ERROR_INSIDE,
SHAPE_POLY_SET buffer;
aFootprint->TransformFPShapesToPolySet( buffer, pcblayer, 0, maxError, ERROR_INSIDE,
false, /* include text */
true, /* include shapes */
false /* include private items */ );
if( m_params.m_netFilter.IsEmpty() )
{
m_poly_copper_shapes[pcblayer].Append( buffer );
}
else
{
// Only add shapes colliding with any matching pads
for( const SHAPE_POLY_SET::POLYGON& poly : buffer.CPolygons() )
{
bool connectsToPad = false;
for( PAD* pad : padsMatchingNetFilter )
{
if( !pad->IsOnLayer( pcblayer ) )
continue;
std::shared_ptr<SHAPE_POLY_SET> padPoly = pad->GetEffectivePolygon();
SHAPE_POLY_SET gfxPoly( poly );
if( padPoly->Collide( &gfxPoly ) )
{
m_poly_copper_shapes[pcblayer].Append( gfxPoly );
break;
}
}
}
}
}
}
@ -301,6 +337,9 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri
bool EXPORTER_STEP::buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin )
{
if( !m_params.m_netFilter.IsEmpty() && !aTrack->GetNetname().Matches( m_params.m_netFilter ) )
return true;
if( aTrack->Type() == PCB_VIA_T )
{
return m_pcbModel->AddViaShape( static_cast<const PCB_VIA*>( aTrack ), aOrigin );
@ -329,12 +368,18 @@ void EXPORTER_STEP::buildZones3DShape( VECTOR2D aOrigin )
{
for( ZONE* zone : m_board->Zones() )
{
if( !m_params.m_netFilter.IsEmpty() && !zone->GetNetname().Matches( m_params.m_netFilter ) )
continue;
for( PCB_LAYER_ID layer : zone->GetLayerSet().CuStack() )
{
SHAPE_POLY_SET copper_shape;
zone->TransformSolidAreasShapesToPolygon( layer, copper_shape );
copper_shape.Unfracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
copper_shape.SimplifyOutlines(
ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel );
m_pcbModel->AddCopperPolygonShapes( &copper_shape, layer, aOrigin, false );
}
}
@ -348,6 +393,9 @@ bool EXPORTER_STEP::buildGraphic3DShape( BOARD_ITEM* aItem, VECTOR2D aOrigin )
if( !graphic )
return false;
if( !m_params.m_netFilter.IsEmpty() && !graphic->GetNetname().Matches( m_params.m_netFilter ) )
return true;
PCB_LAYER_ID pcblayer = graphic->GetLayer();
if( !IsCopperLayer( pcblayer ) )
@ -405,6 +453,7 @@ bool EXPORTER_STEP::buildBoard3DShapes()
m_pcbModel->SetStackup( m_board->GetDesignSettings().GetStackupDescriptor() );
m_pcbModel->SetEnabledLayers( layersToExport );
m_pcbModel->SetFuseShapes( m_params.m_fuseShapes );
m_pcbModel->SetNetFilter( m_params.m_netFilter );
// Note: m_params.m_BoardOutlinesChainingEpsilon is used only to build the board outlines,
// not to set OCC chaining epsilon (much smaller)

View File

@ -73,6 +73,7 @@ public:
};
wxString m_outputFile;
wxString m_netFilter;
VECTOR2D m_origin;

View File

@ -108,7 +108,6 @@
#include <RWGltf_CafWriter.hxx>
#include <macros.h>
#include <advanced_config.h>
static constexpr double USER_PREC = 1e-4;
static constexpr double USER_ANGLE_PREC = 1e-6;
@ -510,7 +509,7 @@ bool STEP_PCB_MODEL::AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin )
{
TopoDS_Shape fusedShape = mkFuse.Shape();
ShapeUpgrade_UnifySameDomain unify( fusedShape, false, true, false );
ShapeUpgrade_UnifySameDomain unify( fusedShape, true, true, false );
unify.History() = nullptr;
unify.Build();
@ -821,6 +820,12 @@ void STEP_PCB_MODEL::SetStackup( const BOARD_STACKUP& aStackup )
}
void STEP_PCB_MODEL::SetNetFilter( const wxString& aFilter )
{
m_netFilter = aFilter;
}
void STEP_PCB_MODEL::SetBoardColor( double r, double g, double b )
{
m_boardColor[0] = r;
@ -1055,7 +1060,6 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector<TopoDS_Shape>& aShapes, const SHAPE
{
SHAPE_POLY_SET simplified = aPolySet;
simplified.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
simplified.SimplifyOutlines( ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel );
auto toPoint = [&]( const VECTOR2D& aKiCoords ) -> gp_Pnt
{
@ -1637,11 +1641,11 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool
if( mkFuse.IsDone() )
{
ReportMessage( wxT( "Removing extra faces\n" ) );
ReportMessage( wxT( "Removing extra edges/faces\n" ) );
TopoDS_Shape fusedShape = mkFuse.Shape();
ShapeUpgrade_UnifySameDomain unify( fusedShape, false, true, false );
ShapeUpgrade_UnifySameDomain unify( fusedShape, true, true, false );
unify.History() = nullptr;
unify.Build();

View File

@ -111,6 +111,8 @@ public:
void SetStackup( const BOARD_STACKUP& aStackup );
void SetNetFilter( const wxString& aFilter );
// Set the max distance (in mm) to consider 2 points have the same coordinates
// and can be merged
void OCCSetMergeMaxDistance( double aDistance = OCC_MAX_DISTANCE_TO_MERGE_POINTS );
@ -239,6 +241,7 @@ private:
double m_copperColor[3]; // copper, RGB values
BOARD_STACKUP m_stackup; // board stackup
LSET m_enabledLayers; // a set of layers enabled for export
wxString m_netFilter; // remove nets not matching this wildcard
double m_minx; // leftmost curve point
double m_mergeOCCMaxDist; // minimum distance (mm) below which two

View File

@ -206,6 +206,7 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
params.m_useGridOrigin = aStepJob->m_useGridOrigin;
params.m_boardOnly = aStepJob->m_boardOnly;
params.m_optimizeStep = aStepJob->m_optimizeStep;
params.m_netFilter = aStepJob->m_netFilter;
switch( aStepJob->m_format )
{