diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp index 7e1354fd20..151282ee82 100644 --- a/pcbnew/exporters/step/exporter_step.cpp +++ b/pcbnew/exporters/step/exporter_step.cpp @@ -121,6 +121,7 @@ EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams m_boardThickness( DEFAULT_BOARD_THICKNESS_MM ) { m_solderMaskColor = COLOR4D( 0.08, 0.20, 0.14, 0.83 ); + m_copperColor = COLOR4D( 0.7, 0.61, 0.0, 1.0 ); m_resolver = std::make_unique(); m_resolver->Set3DConfigDir( wxT( "" ) ); @@ -135,7 +136,7 @@ EXPORTER_STEP::~EXPORTER_STEP() } -bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ) +bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin ) { bool hasdata = false; @@ -152,6 +153,20 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ) } } + // Build 3D shapes of the footprint graphic items on external layers: + if( ExportTracksAndVias() ) + { + int maxError = m_board->GetDesignSettings().m_MaxError; + aFootprint->TransformFPShapesToPolySet( m_top_copper_shapes, F_Cu, 0, maxError, ERROR_INSIDE, + false, /* include text */ + true, /* include shapes */ + false /* include private items */ ); + aFootprint->TransformFPShapesToPolySet( m_bottom_copper_shapes, B_Cu, 0, maxError, ERROR_INSIDE, + false, /* include text */ + true, /* include shapes */ + false /* include private items */ ); + } + if( ( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) && !m_params.m_includeExcludedBom ) { return hasdata; @@ -241,7 +256,7 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ) } -bool EXPORTER_STEP::composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin ) +bool EXPORTER_STEP::buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin ) { if( aTrack->Type() == PCB_VIA_T ) { @@ -268,15 +283,18 @@ bool EXPORTER_STEP::composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin ) SHAPE_POLY_SET copper_shapes; int maxError = m_board->GetDesignSettings().m_MaxError; - aTrack->TransformShapeToPolygon( copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE ); + if( pcblayer == F_Cu ) + aTrack->TransformShapeToPolygon( m_top_copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE ); + else + aTrack->TransformShapeToPolygon( m_bottom_copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE ); - m_pcbModel->AddCopperPolygonShapes( &copper_shapes, pcblayer == F_Cu, aOrigin ); + //m_pcbModel->AddCopperPolygonShapes( &copper_shapes, pcblayer == F_Cu, aOrigin ); return true; } -bool EXPORTER_STEP::composePCB() +bool EXPORTER_STEP::buildBoard3DShapes() { if( m_pcbModel ) return true; @@ -303,6 +321,7 @@ bool EXPORTER_STEP::composePCB() // TODO: Handle when top & bottom soldermask colours are different... m_pcbModel->SetBoardColor( m_solderMaskColor.r, m_solderMaskColor.g, m_solderMaskColor.b ); + m_pcbModel->SetCopperColor( m_copperColor.r, m_copperColor.g, m_copperColor.b ); m_pcbModel->SetPCBThickness( m_boardThickness ); @@ -320,14 +339,20 @@ bool EXPORTER_STEP::composePCB() // For copper layers, only pads and tracks are added, because adding everything on copper // generate unreasonable file sizes and take a unreasonable calculation time. for( FOOTPRINT* fp : m_board->Footprints() ) - composePCB( fp, origin ); + buildFootprint3DShapes( fp, origin ); if( ExportTracksAndVias() ) { for( PCB_TRACK* track : m_board->Tracks() ) - composePCB( track, origin ); + buildTrack3DShape( track, origin ); } + m_top_copper_shapes.Fracture( SHAPE_POLY_SET::PM_FAST ); + m_bottom_copper_shapes.Fracture( SHAPE_POLY_SET::PM_FAST ); + + m_pcbModel->AddCopperPolygonShapes( &m_top_copper_shapes, true, origin ); + m_pcbModel->AddCopperPolygonShapes( &m_bottom_copper_shapes, false, origin ); + ReportMessage( wxT( "Create PCB solid model\n" ) ); wxString msg; @@ -344,7 +369,7 @@ bool EXPORTER_STEP::composePCB() } -void EXPORTER_STEP::determinePcbThickness() +void EXPORTER_STEP::calculatePcbThickness() { m_boardThickness = DEFAULT_BOARD_THICKNESS_MM; @@ -389,7 +414,7 @@ bool EXPORTER_STEP::Export() Message::DefaultMessenger()->AddPrinter( new KiCadPrinter( this ) ); ReportMessage( _( "Determining PCB data\n" ) ); - determinePcbThickness(); + calculatePcbThickness(); wxString msg; msg.Printf( _( "Board Thickness from stackup: %.3f mm\n" ), m_boardThickness ); ReportMessage( msg ); @@ -398,7 +423,7 @@ bool EXPORTER_STEP::Export() { ReportMessage( _( "Build STEP data\n" ) ); - if( !composePCB() ) + if( !buildBoard3DShapes() ) { ReportMessage( _( "\n** Error building STEP board model. Export aborted. **\n" ) ); return false; diff --git a/pcbnew/exporters/step/exporter_step.h b/pcbnew/exporters/step/exporter_step.h index eb49e83939..17a3a45583 100644 --- a/pcbnew/exporters/step/exporter_step.h +++ b/pcbnew/exporters/step/exporter_step.h @@ -87,10 +87,10 @@ public: bool ExportTracksAndVias() { return m_params.m_exportTracks; } private: - bool composePCB(); - bool composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ); - bool composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin ); - void determinePcbThickness(); + bool buildBoard3DShapes(); + bool buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin ); + bool buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin ); + void calculatePcbThickness(); EXPORTER_STEP_PARAMS m_params; std::unique_ptr m_resolver; @@ -107,7 +107,11 @@ private: double m_boardThickness; + SHAPE_POLY_SET m_top_copper_shapes; + SHAPE_POLY_SET m_bottom_copper_shapes; + KIGFX::COLOR4D m_solderMaskColor; + KIGFX::COLOR4D m_copperColor; }; #endif \ No newline at end of file diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp index f61b954a08..8d05272f24 100644 --- a/pcbnew/exporters/step/step_pcb_model.cpp +++ b/pcbnew/exporters/step/step_pcb_model.cpp @@ -178,7 +178,7 @@ STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName ) { m_app = XCAFApp_Application::GetApplication(); m_app->NewDocument( "MDTV-XCAF", m_doc ); - m_assy = XCAFDoc_DocumentTool::ShapeTool ( m_doc->Main() ); + m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() ); m_assy_label = m_assy->NewShape(); m_hasPCB = false; m_components = 0; @@ -277,16 +277,19 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin ) return false; VECTOR2I pos = aPad->GetPosition(); - double holeZsize = m_boardThickness + ( m_copperThickness * 2 ); + const double margin = 0.01; // a small margin on the Z axix to be sure the hole + // is bigget than the board with copper + // must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS + double holeZsize = m_boardThickness + ( m_copperThickness * 2 ) + ( margin * 2 ); if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) { TopoDS_Shape s = - BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize * 2.0 ).Shape(); + BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize ).Shape(); gp_Trsf shift; shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( pos.x - aOrigin.x ), -pcbIUScale.IUTomm( pos.y - aOrigin.y ), - -holeZsize * 0.5 ) ); + -m_copperThickness - margin ) ); BRepBuilderAPI_Transform hole( s, shift ); m_cutouts.push_back( hole.Shape() ); return true; @@ -304,7 +307,7 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin ) if( holeOutlines.OutlineCount() > 0 ) { - if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize*2, -holeZsize * 0.5, aOrigin ) ) + if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize, -m_copperThickness - margin, aOrigin ) ) { m_cutouts.push_back( hole ); } @@ -392,6 +395,14 @@ void STEP_PCB_MODEL::SetBoardColor( double r, double g, double b ) } +void STEP_PCB_MODEL::SetCopperColor( double r, double g, double b ) +{ + m_copperColor[0] = r; + m_copperColor[1] = g; + m_copperColor[2] = b; +} + + void STEP_PCB_MODEL::OCCSetMergeMaxDistance( double aDistance ) { // Ensure a minimal value (in mm) @@ -562,7 +573,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin ) for( TopoDS_Shape& hole : m_cutouts ) holelist.Append( hole ); - // Remove holes for each board (usually there is only one board + // Remove holes for each board (usually there is only one board) int cnt = 0; for( TopoDS_Shape& board: m_board_outlines ) { @@ -605,18 +616,18 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin ) // identically named assemblies. So we want to avoid having the PCB be generally defaulted // to "Component" or "Assembly". - // color the PCB + // Init colors for the board body and the copper items (if any) Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() ); - Quantity_Color board_color( m_boardColor[0], m_boardColor[1], m_boardColor[2], Quantity_TOC_RGB ); - Quantity_Color copper_color( 0.7, 0.61, 0.0, Quantity_TOC_RGB ); + Quantity_Color board_color( m_boardColor[0], m_boardColor[1], m_boardColor[2], + Quantity_TOC_RGB ); + Quantity_Color copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], + Quantity_TOC_RGB ); int pcbIdx = 1; int copper_objects_cnt = 0; for( TDF_Label& pcb_label : m_pcb_labels ) { - colorTool->SetColor( pcb_label, board_color, XCAFDoc_ColorSurf ); - Handle( TDataStd_TreeNode ) node; if( pcb_label.FindAttribute( XCAFDoc::ShapeRefGUID(), node ) ) @@ -628,10 +639,17 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin ) { wxString pcbName; - if( m_pcb_labels.size() == 1 ) - pcbName = wxT( "PCB" ); + if( copper_objects_cnt < copper_item_count ) + { + pcbName = wxString::Format( wxT( "Copper_Item%d" ), copper_objects_cnt+1 ); + } else - pcbName = wxString::Format( wxT( "PCB%d" ), pcbIdx++ ); + { + if( m_pcb_labels.size() == 1 ) + pcbName = wxT( "PCB" ); + else + pcbName = wxString::Format( wxT( "PCB%d" ), pcbIdx++ ); + } std::string pcbNameStdString( pcbName.ToUTF8() ); TCollection_ExtendedString partname( pcbNameStdString.c_str() ); @@ -641,10 +659,11 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin ) // color the PCB TopExp_Explorer topex; - topex.Init( m_assy->GetShape( pcb_label ), TopAbs_SOLID ); + topex.Init( m_assy->GetShape( pcb_label ), TopAbs_COMPOUND /*TopAbs_SOLID*/ ); while( topex.More() ) { + // First objects are copper objects, last(s) is the board body if( copper_objects_cnt < copper_item_count ) colorTool->SetColor( topex.Current(), copper_color, XCAFDoc_ColorSurf ); else diff --git a/pcbnew/exporters/step/step_pcb_model.h b/pcbnew/exporters/step/step_pcb_model.h index d7db3c1742..0c6db1594b 100644 --- a/pcbnew/exporters/step/step_pcb_model.h +++ b/pcbnew/exporters/step/step_pcb_model.h @@ -44,9 +44,9 @@ /** * Default distance between points to treat them as separate ones (mm) - * 0.001 mm is a reasonable value. A too large value creates issues by + * 0.001 mm or less is a reasonable value. A too large value creates issues by * merging points that should be different. - * Remember we are a 3D space, so a thin line can be broken if 2 points + * Remember we are a 3D space, so a thin shape can be broken if 2 points * are merged (in X, Y, Z coords) when they should not. * round shapes converted to polygon can also be not good with a to large value */ @@ -56,9 +56,11 @@ static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS = 0.001; static constexpr double BOARD_THICKNESS_DEFAULT_MM = 1.6; // minimum PCB thickness in mm (10 microns assumes a very thin polyimide film) +// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS static constexpr double BOARD_THICKNESS_MIN_MM = 0.01; // default copper thickness in mm +// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS static constexpr double COPPER_THICKNESS_DEFAULT_MM = 0.035; // Max error to approximate an arc by segments (in mm) @@ -92,6 +94,7 @@ public: VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels = true ); void SetBoardColor( double r, double g, double b ); + void SetCopperColor( 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 @@ -166,7 +169,8 @@ 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_boardColor[3]; // board body, RGB values + double m_copperColor[3]; // copper, RGB values double m_boardThickness; // PCB thickness, mm double m_copperThickness; // copper thickness, mm