From 67debb8257d3dfd3de951e2d0e0babef41ff4e2d Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 3 May 2025 18:24:51 +0100 Subject: [PATCH] Move STEP exporter error reporting to REPORTER interface. Fixes https://gitlab.com/kicad/code/kicad/-/issues/20738 (cherry picked from commit e69c80f09d05442d66eb7f2f49c9c6e3cc276902) --- kicad/jobs_runner.cpp | 17 +- pcbnew/exporters/step/exporter_step.cpp | 158 +++--- pcbnew/exporters/step/exporter_step.h | 11 +- pcbnew/exporters/step/step_pcb_model.cpp | 684 ++++++++++++----------- pcbnew/exporters/step/step_pcb_model.h | 4 +- pcbnew/pcbnew_jobs_handler.cpp | 2 +- 6 files changed, 459 insertions(+), 417 deletions(-) diff --git a/kicad/jobs_runner.cpp b/kicad/jobs_runner.cpp index 672dde677b..53de7d20b3 100644 --- a/kicad/jobs_runner.cpp +++ b/kicad/jobs_runner.cpp @@ -42,9 +42,7 @@ JOBS_RUNNER::JOBS_RUNNER( KIWAY* aKiway, JOBSET* aJobsFile, PROJECT* aProject, m_project( aProject ) { if( !m_reporter ) - { m_reporter = &NULL_REPORTER::GetInstance(); - } } @@ -62,7 +60,6 @@ bool JOBS_RUNNER::RunJobsAllDestinations( bool aBail ) int JOBS_RUNNER::runSpecialExecute( const JOBSET_JOB* aJob, PROJECT* aProject ) { JOB_SPECIAL_EXECUTE* specialJob = static_cast( aJob->m_job.get() ); - wxString cmd = ExpandEnvVarSubstitutions( specialJob->m_command, m_project ); // static cast required because wx uses `long` which is 64-bit on Linux but 32-bit on Windows @@ -85,18 +82,16 @@ int JOBS_RUNNER::runSpecialExecute( const JOBSET_JOB* aJob, PROJECT* aProject ) if( !procOutput.IsOk() ) return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; - wxInputStream* inputStream = process.GetInputStream(); + wxInputStream* inputStream = process.GetInputStream(); + if( inputStream ) - { inputStream->Read( procOutput ); - } + procOutput.Close(); } if( specialJob->m_ignoreExitcode ) - { return CLI::EXIT_CODES::OK; - } return result; } @@ -152,6 +147,9 @@ public: { wxString text( aText ); + if( aSeverity == RPT_SEVERITY_DEBUG && !m_includeDebug ) + return *this; + if( aSeverity == RPT_SEVERITY_ACTION ) text.Replace( m_tempDirPath, wxEmptyString ); @@ -160,6 +158,7 @@ public: private: wxString m_tempDirPath; + bool m_includeDebug; }; @@ -215,7 +214,7 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool { msg += wxT( "|--------------------------------\n" ); msg += wxT( "| " ); - msg += wxString::Format( "Performing jobs for output %s", aDestination->m_id ); + msg += wxString::Format( wxT( "Performing jobs for output %s" ), aDestination->m_id ); msg += wxT( "\n" ); msg += wxT( "|--------------------------------\n" ); diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp index 65c874a67e..46e7f3ba43 100644 --- a/pcbnew/exporters/step/exporter_step.cpp +++ b/pcbnew/exporters/step/exporter_step.cpp @@ -40,6 +40,7 @@ #include "step_pcb_model.h" #include +#include #include #include #include @@ -63,16 +64,12 @@ #endif -void ReportMessage( const wxString& aMessage ) -{ - wxPrintf( aMessage ); - fflush( stdout ); // Force immediate printing (needed on mingw) -} - -class KiCadPrinter : public Message_Printer +class KICAD_PRINTER : public Message_Printer { public: - KiCadPrinter( EXPORTER_STEP* aConverter ) : m_converter( aConverter ) {} + KICAD_PRINTER( REPORTER* aReporter ) : + m_reporter( aReporter ) + {} protected: #if OCC_VERSION_HEX < OCC_VERSION_MIN @@ -88,44 +85,45 @@ protected: const Standard_Boolean theToPutEol ) const override #else virtual void send( const TCollection_AsciiString& theString, - const Message_Gravity theGravity ) const override + const Message_Gravity theGravity ) const override #endif { - if( theGravity >= Message_Warning - || ( wxLog::IsAllowedTraceMask( traceKiCad2Step ) && theGravity == Message_Info ) ) - { - ReportMessage( theString.ToCString() ); + wxString msg( theString.ToCString() ); #if OCC_VERSION_HEX < OCC_VERSION_MIN - if( theToPutEol ) - ReportMessage( wxT( "\n" ) ); + if( theToPutEol ) + msg += wxT( "\n" ); #else - ReportMessage( wxT( "\n" ) ); + msg += wxT( "\n" ); #endif - } - if( theGravity == Message_Warning ) - m_converter->SetWarn(); - - if( theGravity >= Message_Alarm ) - m_converter->SetError(); - - if( theGravity == Message_Fail ) - m_converter->SetFail(); + m_reporter->Report( msg, getSeverity( theGravity ) ); } private: - EXPORTER_STEP* m_converter; + SEVERITY getSeverity( const Message_Gravity theGravity ) const + { + switch( theGravity ) + { + case Message_Trace: return RPT_SEVERITY_DEBUG; + case Message_Info: return RPT_SEVERITY_DEBUG; + case Message_Warning: return RPT_SEVERITY_WARNING; + case Message_Alarm: return RPT_SEVERITY_ERROR; + case Message_Fail: return RPT_SEVERITY_ERROR; + } + } + +private: + REPORTER* m_reporter; }; -EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams ) : - m_params( aParams ), - m_error( false ), - m_fail( false ), - m_warn( false ), - m_board( aBoard ), - m_pcbModel( nullptr ) +EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams, + REPORTER* aReporter ) : + m_params( aParams ), + m_reporter( aReporter ), + m_board( aBoard ), + m_pcbModel( nullptr ) { m_copperColor = COLOR4D( 0.7, 0.61, 0.0, 1.0 ); @@ -369,9 +367,11 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri if( mname.empty() ) mname = fp_model.m_Filename; - ReportMessage( wxString::Format( wxT( "Could not add 3D model to %s.\n" - "File not found: %s\n" ), - aFootprint->GetReference(), mname ) ); + m_reporter->Report( wxString::Format( _( "Could not add 3D model for %s.\n" + "File not found: %s\n" ), + aFootprint->GetReference(), + mname ), + RPT_SEVERITY_ERROR ); continue; } @@ -397,9 +397,11 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri } catch( const Standard_Failure& e ) { - ReportMessage( wxString::Format( wxT( "Could not add 3D model to %s.\n" - "OpenCASCADE error: %s\n" ), - aFootprint->GetReference(), e.GetMessageString() ) ); + m_reporter->Report( wxString::Format( _( "Could not add 3D model for %s.\n" + "OpenCASCADE error: %s\n" ), + aFootprint->GetReference(), + e.GetMessageString() ), + RPT_SEVERITY_ERROR ); } } @@ -699,7 +701,7 @@ bool EXPORTER_STEP::buildBoard3DShapes() else origin = m_params.m_Origin; - m_pcbModel = std::make_unique( m_pcbBaseName ); + m_pcbModel = std::make_unique( m_pcbBaseName, m_reporter ); initOutputVariant(); @@ -785,15 +787,15 @@ bool EXPORTER_STEP::buildBoard3DShapes() } } - ReportMessage( wxT( "Create PCB solid model\n" ) ); + m_reporter->Report( wxT( "Create PCB solid model.\n" ), RPT_SEVERITY_DEBUG ); - wxString msg; - msg.Printf( wxT( "Board outline: find %d initial points\n" ), pcbOutlines.FullPointCount() ); - ReportMessage( msg ); + m_reporter->Report( wxString::Format( wxT( "Board outline: found %d initial points.\n" ), + pcbOutlines.FullPointCount() ), + RPT_SEVERITY_DEBUG ); if( !m_pcbModel->CreatePCB( pcbOutlines, origin, m_params.m_ExportBoardBody ) ) { - ReportMessage( wxT( "could not create PCB solid model\n" ) ); + m_reporter->Report( _( "Could not create PCB solid model.\n" ), RPT_SEVERITY_ERROR ); return false; } @@ -808,9 +810,9 @@ bool EXPORTER_STEP::Export() // setup opencascade message log Message::DefaultMessenger()->RemovePrinters( STANDARD_TYPE( Message_PrinterOStream ) ); - Message::DefaultMessenger()->AddPrinter( new KiCadPrinter( this ) ); + Message::DefaultMessenger()->AddPrinter( new KICAD_PRINTER( m_reporter ) ); - ReportMessage( _( "Determining PCB data\n" ) ); + m_reporter->Report( wxT( "Determining PCB data.\n" ), RPT_SEVERITY_DEBUG ); if( m_params.m_OutputFile.IsEmpty() ) { @@ -842,15 +844,19 @@ bool EXPORTER_STEP::Export() try { - ReportMessage( wxString::Format( _( "Build %s data\n" ), m_params.GetFormatName() ) ); + m_reporter->Report( wxString::Format( wxT( "Build %s data.\n" ), m_params.GetFormatName() ), + RPT_SEVERITY_DEBUG ); if( !buildBoard3DShapes() ) { - ReportMessage( _( "\n** Error building STEP board model. Export aborted. **\n" ) ); + m_reporter->Report( _( "\n" + "** Error building STEP board model. Export aborted. **\n" ), + RPT_SEVERITY_ERROR ); return false; } - ReportMessage( wxString::Format( _( "Writing %s file\n" ), m_params.GetFormatName() ) ); + m_reporter->Report( wxString::Format( wxT( "Writing %s file.\n" ), m_params.GetFormatName() ), + RPT_SEVERITY_DEBUG ); bool success = true; if( m_params.m_Format == EXPORTER_STEP_PARAMS::FORMAT::STEP ) @@ -868,52 +874,44 @@ bool EXPORTER_STEP::Export() if( !success ) { - ReportMessage( wxString::Format( _( "\n** Error writing %s file. **\n" ), - m_params.GetFormatName() ) ); + m_reporter->Report( wxString::Format( _( "\n" + "** Error writing %s file. **\n" ), + m_params.GetFormatName() ), + RPT_SEVERITY_ERROR ); return false; } else { - ReportMessage( wxString::Format( _( "%s file '%s' created.\n" ), - m_params.GetFormatName(), m_outputFile ) ); + m_reporter->Report( wxString::Format( wxT( "%s file '%s' created.\n" ), + m_params.GetFormatName(), + m_outputFile ), + RPT_SEVERITY_ACTION ); } } catch( const Standard_Failure& e ) { - ReportMessage( e.GetMessageString() ); - ReportMessage( wxString::Format( _( "\n** Error exporting %s file. Export aborted. **\n" ), - m_params.GetFormatName() ) ); + m_reporter->Report( e.GetMessageString(), RPT_SEVERITY_ERROR ); + m_reporter->Report( wxString::Format( _( "\n" + "** Error exporting %s file. Export aborted. **\n" ), + m_params.GetFormatName() ), + RPT_SEVERITY_ERROR ); return false; } catch( ... ) { - ReportMessage( wxString::Format( _( "\n** Error exporting %s file. Export aborted. **\n" ), - m_params.GetFormatName() ) ); + m_reporter->Report( wxString::Format( _( "\n" + "** Error exporting %s file. Export aborted. **\n" ), + m_params.GetFormatName() ), + RPT_SEVERITY_ERROR ); return false; } - if( m_fail || m_error ) - { - wxString msg; - - if( m_fail ) - { - msg = wxString::Format( _( "Unable to create %s file.\n" - "Check that the board has a valid outline and models." ), - m_params.GetFormatName() ); - } - else if( m_error || m_warn ) - { - msg = wxString::Format( _( "%s file has been created, but there are warnings." ), - m_params.GetFormatName() ); - } - - ReportMessage( msg ); - } - // Display calculation time in seconds double calculation_time = (double)( GetRunningMicroSecs() - stats_startExportTime) / 1e6; - ReportMessage( wxString::Format( _( "\nExport time %.3f s\n" ), calculation_time ) ); + m_reporter->Report( wxString::Format( _( "\n" + "Export time %.3f s\n" ), + calculation_time ), + RPT_SEVERITY_INFO ); - return true; + return !m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ); } diff --git a/pcbnew/exporters/step/exporter_step.h b/pcbnew/exporters/step/exporter_step.h index c5ec2a0d08..0afbc5d0c7 100644 --- a/pcbnew/exporters/step/exporter_step.h +++ b/pcbnew/exporters/step/exporter_step.h @@ -31,6 +31,7 @@ #include // For EXPORTER_STEP_PARAMS #include #include +#include class PCBMODEL; @@ -45,17 +46,13 @@ class STEP_PCB_MODEL; class EXPORTER_STEP { public: - EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams ); + EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams, REPORTER* aReporter ); ~EXPORTER_STEP(); bool Export(); wxString m_outputFile; - void SetError() { m_error = true; } - void SetFail() { m_fail = true; } - void SetWarn() { m_warn = true; } - private: bool buildBoard3DShapes(); bool buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin ); @@ -68,9 +65,7 @@ private: std::unique_ptr m_resolver; private: - bool m_error; - bool m_fail; - bool m_warn; + REPORTER* m_reporter; BOARD* m_board; std::unique_ptr m_pcbModel; diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp index 221d06289f..104446e53a 100644 --- a/pcbnew/exporters/step/step_pcb_model.cpp +++ b/pcbnew/exporters/step/step_pcb_model.cpp @@ -30,10 +30,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -48,6 +50,7 @@ #include #include #include +#include #include "step_pcb_model.h" #include "streamwrapper.h" @@ -152,14 +155,7 @@ MODEL3D_FORMAT_TYPE fileType( const char* aFileName ) wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) ); if( !lfile.FileExists() ) - { - wxString msg; - msg.Printf( wxT( " * fileType(): no such file: %s\n" ), - wxString::FromUTF8Unchecked( aFileName ) ); - - ReportMessage( msg ); return FMT_NONE; - } wxString ext = lfile.GetExt().Lower(); @@ -623,7 +619,7 @@ static Standard_Boolean rescaleShapes( const TDF_Label& theLabel, const gp_XYZ& } -static bool fuseShapes( auto& aInputShapes, TopoDS_Shape& aOutShape ) +static bool fuseShapes( auto& aInputShapes, TopoDS_Shape& aOutShape, REPORTER* aReporter ) { BRepAlgoAPI_Fuse mkFuse; TopTools_ListOfShape shapeArguments, shapeTools; @@ -647,21 +643,27 @@ static bool fuseShapes( auto& aInputShapes, TopoDS_Shape& aOutShape ) if( mkFuse.HasErrors() || mkFuse.HasWarnings() ) { - ReportMessage( _( "** Got problems while fusing shapes **\n" ) ); + aReporter->Report( _( "** Got problems while fusing shapes **\n" ), RPT_SEVERITY_ERROR ); if( mkFuse.HasErrors() ) { - ReportMessage( _( "Errors:\n" ) ); - mkFuse.DumpErrors( std::cout ); + wxString msg = _( "Errors:\n" ); + wxStringOutputStream os_stream( &msg ); + wxStdOutputStream out( os_stream ); + + mkFuse.DumpErrors( out ); + aReporter->Report( msg, RPT_SEVERITY_ERROR ); } if( mkFuse.HasWarnings() ) { - ReportMessage( _( "Warnings:\n" ) ); - mkFuse.DumpWarnings( std::cout ); - } + wxString msg = _( "Warnings:\n" ); + wxStringOutputStream os_stream( &msg ); + wxStdOutputStream out( os_stream ); - std::cout << "\n"; + mkFuse.DumpWarnings( out ); + aReporter->Report( msg, RPT_SEVERITY_WARNING ); + } } if( mkFuse.IsDone() ) @@ -676,7 +678,8 @@ static bool fuseShapes( auto& aInputShapes, TopoDS_Shape& aOutShape ) if( unifiedShapes.IsNull() ) { - ReportMessage( _( "** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) ); + aReporter->Report( _( "** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ), + RPT_SEVERITY_ERROR ); } else { @@ -703,14 +706,15 @@ static TopoDS_Compound makeCompound( const auto& aInputShapes ) // Try to fuse shapes. If that fails, just add them to a compound -static TopoDS_Shape fuseShapesOrCompound( const TopTools_ListOfShape& aInputShapes ) +static TopoDS_Shape fuseShapesOrCompound( const TopTools_ListOfShape& aInputShapes, + REPORTER* aReporter ) { TopoDS_Shape outShape; if( aInputShapes.Size() == 1 ) return aInputShapes.First(); - if( fuseShapes( aInputShapes, outShape ) ) + if( fuseShapes( aInputShapes, outShape, aReporter ) ) return outShape; return makeCompound( aInputShapes ); @@ -757,7 +761,8 @@ static Standard_Boolean prefixNames( const TDF_Label& aLabel, } -STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName ) +STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName, REPORTER* aReporter ) : + m_reporter( aReporter ) { m_app = XCAFApp_Application::GetApplication(); m_app->NewDocument( "MDTV-XCAF", m_doc ); @@ -890,7 +895,7 @@ bool STEP_PCB_MODEL::AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin, bool } if( !success ) // Error - ReportMessage( wxT( "OCC error adding pad/via polygon.\n" ) ); + m_reporter->Report( _( "OCC error adding pad/via polygon.\n" ), RPT_SEVERITY_ERROR ); if( !padShapes.empty() ) { @@ -902,8 +907,7 @@ bool STEP_PCB_MODEL::AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin, bool for( const TopoDS_Shape& shape : padShapes ) padShapesList.Append( shape ); - m_board_copper_pads[aPad->GetNetname()].push_back( - fuseShapesOrCompound( padShapesList ) ); + m_board_copper_pads[aPad->GetNetname()].push_back( fuseShapesOrCompound( padShapesList, m_reporter ) ); } else { @@ -1136,9 +1140,10 @@ bool STEP_PCB_MODEL::AddPolygonShapes( const SHAPE_POLY_SET* aPolyShapes, PCB_LA if( !MakeShapes( targetVec, *aPolyShapes, m_simplifyShapes, thickness, z_pos, aOrigin ) ) { - ReportMessage( - wxString::Format( wxT( "Could not add shape (%d points) to copper layer on %s.\n" ), - aPolyShapes->FullPointCount(), LayerName( aLayer ) ) ); + m_reporter->Report( wxString::Format( _( "Could not add shape (%d points) to copper layer %s.\n" ), + aPolyShapes->FullPointCount(), + LayerName( aLayer ) ), + RPT_SEVERITY_ERROR ); success = false; } @@ -1153,12 +1158,13 @@ bool STEP_PCB_MODEL::AddComponent( const std::string& aFileNameUTF8, const std:: { if( aFileNameUTF8.empty() ) { - ReportMessage( wxString::Format( wxT( "No model defined for component %s.\n" ), aRefDes ) ); + m_reporter->Report( wxString::Format( _( "No model defined for %s.\n" ), aRefDes ), + RPT_SEVERITY_WARNING ); return false; } wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) ); - ReportMessage( wxString::Format( wxT( "Adding component %s.\n" ), aRefDes ) ); + m_reporter->Report( wxString::Format( wxT( "Adding component %s.\n" ), aRefDes ), RPT_SEVERITY_DEBUG ); // first retrieve a label TDF_Label lmodel; @@ -1167,10 +1173,9 @@ bool STEP_PCB_MODEL::AddComponent( const std::string& aFileNameUTF8, const std:: if( !getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) ) { if( errorMessage.IsEmpty() ) - ReportMessage( wxString::Format( wxT( "No model for filename '%s'.\n" ), fileName ) ); - else - ReportMessage( errorMessage ); + errorMessage.Printf( _( "No model for filename '%s'.\n" ), fileName ); + m_reporter->Report( errorMessage, RPT_SEVERITY_ERROR ); return false; } @@ -1179,8 +1184,8 @@ bool STEP_PCB_MODEL::AddComponent( const std::string& aFileNameUTF8, const std:: if( !getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) ) { - ReportMessage( - wxString::Format( wxT( "No location data for filename '%s'.\n" ), fileName ) ); + m_reporter->Report( wxString::Format( _( "No location data for filename '%s'.\n" ), fileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -1189,8 +1194,8 @@ bool STEP_PCB_MODEL::AddComponent( const std::string& aFileNameUTF8, const std:: if( llabel.IsNull() ) { - ReportMessage( wxString::Format( wxT( "Could not add component with filename '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( _( "Could not add component with filename '%s'.\n" ), fileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -1359,8 +1364,9 @@ bool STEP_PCB_MODEL::MakeShapeAsThickSegment( TopoDS_Shape& aShape, } catch( const Standard_Failure& e ) { - ReportMessage( wxString::Format( wxT( "build shape segment: OCC exception: %s\n" ), - e.GetMessageString() ) ); + m_reporter->Report( wxString::Format( _( "OCC exception building shape segment: %s\n" ), + e.GetMessageString() ), + RPT_SEVERITY_ERROR ); return false; } @@ -1373,8 +1379,9 @@ bool STEP_PCB_MODEL::MakeShapeAsThickSegment( TopoDS_Shape& aShape, } catch( const Standard_Failure& e ) { - ReportMessage( wxString::Format( wxT( "MakeShapeThickSegment: OCC exception: %s\n" ), - e.GetMessageString() ) ); + m_reporter->Report( wxString::Format( _( "OCC exception building face: %s\n" ), + e.GetMessageString() ), + RPT_SEVERITY_ERROR ); return false; } @@ -1384,7 +1391,8 @@ bool STEP_PCB_MODEL::MakeShapeAsThickSegment( TopoDS_Shape& aShape, if( aShape.IsNull() ) { - ReportMessage( wxT( "failed to create a prismatic shape\n" ) ); + m_reporter->Report( _( "Failed to create a prismatic shape\n" ), + RPT_SEVERITY_ERROR ); return false; } } @@ -1412,7 +1420,8 @@ static wxString formatBBox( const BOX2I& aBBox ) static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN& aChain, - double aMergeOCCMaxDist, double aZposition, const VECTOR2D& aOrigin ) + double aMergeOCCMaxDist, double aZposition, const VECTOR2D& aOrigin, + REPORTER* aReporter ) { auto toPoint = [&]( const VECTOR2D& aKiCoords ) -> gp_Pnt { @@ -1430,13 +1439,15 @@ static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN gp_Pnt start = toPoint( aPt0 ); gp_Pnt end = toPoint( aPt1 ); - BRepBuilderAPI_MakeEdge mkEdge( start, end ); + BRepBuilderAPI_MakeEdge mkEdge( start, end ); if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() ) { - ReportMessage( wxString::Format( wxT( "failed to make segment edge at (%d " - "%d) -> (%d %d), skipping\n" ), - aPt0.x, aPt0.y, aPt1.x, aPt1.y ) ); + aReporter->Report( wxString::Format( _( "Failed to make segment edge (%d %d) -> (%d %d), " + "skipping\n" ), + aPt0.x, aPt0.y, + aPt1.x, aPt1.y ), + RPT_SEVERITY_ERROR ); } else { @@ -1444,9 +1455,10 @@ static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN if( aMkWire.Error() != BRepLib_WireDone ) { - ReportMessage( wxString::Format( wxT( "failed to add segment edge " - "at (%d %d) -> (%d %d)\n" ), - aPt0.x, aPt0.y, aPt1.x, aPt1.y ) ); + aReporter->Report( wxString::Format( _( "Failed to add segment edge (%d %d) -> (%d %d)\n" ), + aPt0.x, aPt0.y, + aPt1.x, aPt1.y ), + RPT_SEVERITY_ERROR ); return false; } } @@ -1469,8 +1481,7 @@ static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN else { curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ), - toPoint( aArc.GetP1() ) ) - .Value(); + toPoint( aArc.GetP1() ) ).Value(); } if( curve.IsNull() ) @@ -1480,11 +1491,13 @@ static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN if( !aMkWire.IsDone() ) { - ReportMessage( wxString::Format( - wxT( "failed to add arc curve from (%d %d), arc p0 " - "(%d %d), mid (%d %d), p1 (%d %d)\n" ), - aPt0.x, aPt0.y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x, - aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) ); + aReporter->Report( wxString::Format( _( "Failed to add arc curve from (%d %d), arc p0 " + "(%d %d), mid (%d %d), p1 (%d %d)\n" ), + aPt0.x, aPt0.y, + aArc.GetP0().x, aArc.GetP0().y, + aArc.GetArcMid().x, aArc.GetArcMid().y, + aArc.GetP1().x, aArc.GetP1().y ), + RPT_SEVERITY_ERROR ); return false; } @@ -1554,17 +1567,19 @@ static bool makeWireFromChain( BRepLib_MakeWire& aMkWire, const SHAPE_LINE_CHAIN if( lastPt != firstPt && !addSegment( lastPt, firstPt ) ) { - ReportMessage( - wxString::Format( wxT( "** Failed to close wire at %d, %d -> %d, %d **\n" ), - lastPt.x, lastPt.y, firstPt.x, firstPt.y ) ); + aReporter->Report( wxString::Format( _( "Failed to close wire at %d, %d -> %d, %d **\n" ), + lastPt.x, lastPt.y, + firstPt.x, firstPt.y ), + RPT_SEVERITY_ERROR ); return false; } } catch( const Standard_Failure& e ) { - ReportMessage( wxString::Format( wxT( "makeWireFromChain: OCC exception: %s\n" ), - e.GetMessageString() ) ); + aReporter->Report( wxString::Format( _( "OCC exception creating wire: %s\n" ), + e.GetMessageString() ), + RPT_SEVERITY_ERROR ); return false; } @@ -1601,11 +1616,11 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE // TODO: this is not accurate because it doesn't check arcs. /*if( approximated.IsSelfIntersecting() ) { - ReportMessage( wxString::Format( _( "\nApproximated polygon self-intersection check " - "failed\n" ) ) ); - - ReportMessage( wxString::Format( _( "z: %g; bounding box: %s\n" ), aZposition, - formatBBox( workingPoly.BBox() ) ) ); + m_reporter->Report( wxString::Format( _( "Approximated polygon self-intersection check failed\n" + "z: %g; bounding box: %s\n" ) ), + aZposition, + formatBBox( workingPoly.BBox() ) ), + RPT_SEVERITY_ERROR ); } else { @@ -1635,7 +1650,7 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE TopoDS_Wire wire; BRepLib_MakeWire mkWire; - makeWireFromChain( mkWire, aContour, m_mergeOCCMaxDist, aZposition, aOrigin ); + makeWireFromChain( mkWire, aContour, m_mergeOCCMaxDist, aZposition, aOrigin, m_reporter ); if( mkWire.IsDone() ) { @@ -1643,13 +1658,12 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE } else { - ReportMessage( - wxString::Format( _( "Wire not done (contour points %d): OCC error %d\n" ), - static_cast( aContour.PointCount() ), - static_cast( mkWire.Error() ) ) ); - - ReportMessage( wxString::Format( _( "z: %g; bounding box: %s\n" ), aZposition, - formatBBox( aContour.BBox() ) ) ); + m_reporter->Report( wxString::Format( _( "Wire not done (contour points %d): OCC error %d\n" + "z: %g; bounding box: %s\n" ), + static_cast( aContour.PointCount() ), + static_cast( mkWire.Error() ), + formatBBox( aContour.BBox() ) ), + RPT_SEVERITY_ERROR ); } if( !wire.IsNull() ) @@ -1658,12 +1672,11 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE if( !check.IsValid() ) { - ReportMessage( wxString::Format( _( "\nWire self-interference check " - "failed\n" ) ) ); - - ReportMessage( wxString::Format( _( "z: %g; bounding box: %s\n" ), aZposition, - formatBBox( aContour.BBox() ) ) ); - + m_reporter->Report( wxString::Format( _( "Wire self-interference check failed\n" + "z: %g; bounding box: %s\n" ), + aZposition, + formatBBox( aContour.BBox() ) ), + RPT_SEVERITY_ERROR ); wire.Nullify(); } } @@ -1681,7 +1694,8 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE if( aConvertToArcs && wire.IsNull() ) { - ReportMessage( wxString::Format( _( "Using non-simplified polygon.\n" ) ) ); + m_reporter->Report( wxString::Format( _( "Using non-simplified polygon.\n" ) ), + RPT_SEVERITY_DEBUG ); // Fall back to original shape wire = tryMakeWire( fallbackPoly.CPolygon( polyId )[contId] ); @@ -1698,12 +1712,11 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE } else { - ReportMessage( wxString::Format( wxT( "\n** Outline skipped **\n" ) ) ); - - ReportMessage( wxString::Format( wxT( "z: %g; bounding box: %s\n" ), - aZposition, - formatBBox( polygon[contId].BBox() ) ) ); - + m_reporter->Report( wxString::Format( wxT( "** Outline skipped **\n" + "z: %g; bounding box: %s\n" ), + aZposition, + formatBBox( polygon[contId].BBox() ) ), + RPT_SEVERITY_DEBUG ); break; } } @@ -1718,19 +1731,20 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE } else { - ReportMessage( wxString::Format( wxT( "\n** Hole skipped **\n" ) ) ); - - ReportMessage( wxString::Format( wxT( "z: %g; bounding box: %s\n" ), - aZposition, - formatBBox( polygon[contId].BBox() ) ) ); + m_reporter->Report( wxString::Format( wxT( "** Hole skipped **\n" + "z: %g; bounding box: %s\n" ), + aZposition, + formatBBox( polygon[contId].BBox() ) ), + RPT_SEVERITY_DEBUG ); } } } catch( const Standard_Failure& e ) { - ReportMessage( - wxString::Format( wxT( "MakeShapes (contour %d): OCC exception: %s\n" ), - static_cast( contId ), e.GetMessageString() ) ); + m_reporter->Report( wxString::Format( _( "OCC exception creating contour %d: %s\n" ), + static_cast( contId ), + e.GetMessageString() ), + RPT_SEVERITY_ERROR ); return false; } } @@ -1746,7 +1760,7 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE if( prism.IsNull() ) { - ReportMessage( _( "Failed to create a prismatic shape\n" ) ); + m_reporter->Report( _( "Failed to create a prismatic shape\n" ), RPT_SEVERITY_ERROR ); return false; } } @@ -1757,7 +1771,7 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector& aShapes, const SHAPE } else { - ReportMessage( wxString::Format( _( "** Face skipped **\n" ) ) ); + m_reporter->Report( _( "** Face skipped **\n" ), RPT_SEVERITY_DEBUG ); } } @@ -1823,14 +1837,15 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool thread_pool& tp = GetKiCadThreadPool(); - Handle( XCAFDoc_VisMaterialTool ) visMatTool = - XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() ); + Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() ); m_hasPCB = true; // whether or not operations fail we note that CreatePCB has been invoked // Support for more than one main outline (more than one board) - ReportMessage( wxString::Format( wxT( "Build board outlines (%d outlines) with %d points.\n" ), - aOutline.OutlineCount(), aOutline.FullPointCount() ) ); + m_reporter->Report( wxString::Format( wxT( "Build board outlines (%d outlines) with %d points.\n" ), + aOutline.OutlineCount(), + aOutline.FullPointCount() ), + RPT_SEVERITY_DEBUG ); double boardThickness; double boardZPos; @@ -1846,8 +1861,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool if( !MakeShapes( m_board_outlines, aOutline, false, boardThickness, boardZPos, aOrigin ) ) { // Error - ReportMessage( wxString::Format( - wxT( "OCC error creating main outline.\n" ) ) ); + m_reporter->Report( _( "OCC error creating main outline.\n" ), RPT_SEVERITY_ERROR ); } #else // Workaround for bug #17446 Holes are missing from STEP export with circular PCB outline @@ -1864,7 +1878,8 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool if( !MakeShapes( m_board_outlines, polyset, false, boardThickness, boardZPos, aOrigin ) ) { - ReportMessage( wxT( "OCC error creating main outline.\n" ) ); + m_reporter->Report( _( "OCC error creating main outline.\n" ), + RPT_SEVERITY_ERROR ); } } else // Hole inside the main outline @@ -1872,7 +1887,8 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool if( !MakeShapes( m_boardCutouts, polyset, false, boardThickness, boardZPos, aOrigin ) ) { - ReportMessage( wxT( "OCC error creating hole in main outline.\n" ) ); + m_reporter->Report( _( "OCC error creating hole in main outline.\n" ), + RPT_SEVERITY_ERROR ); } } } @@ -1886,8 +1902,9 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool BRepBndLib::Add( brdShape, brdBndBox ); // subtract cutouts (if any) - ReportMessage( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ), - (int) ( m_boardCutouts.size() + m_copperCutouts.size() ) ) ); + m_reporter->Report( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ), + (int) ( m_boardCutouts.size() + m_copperCutouts.size() ) ), + RPT_SEVERITY_DEBUG ); auto buildBSB = [&brdBndBox]( std::vector& input, Bnd_BoundSortBox& bsbHoles ) { @@ -1909,80 +1926,89 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool }; auto subtractShapesMap = - [&tp]( const wxString& aWhat, std::map>& aShapesMap, - std::vector& aHolesList, Bnd_BoundSortBox& aBSBHoles ) - { - ReportMessage( wxString::Format( _( "Subtracting holes for %s\n" ), aWhat ) ); - - for( auto& [netname, vec] : aShapesMap ) - { - std::mutex mutex; - - auto subtractLoopFn = [&]( const int a, const int b ) + [&tp, this]( const wxString& aWhat, std::map>& aShapesMap, + std::vector& aHolesList, Bnd_BoundSortBox& aBSBHoles ) { - for( int shapeId = a; shapeId < b; shapeId++ ) + m_reporter->Report( wxString::Format( _( "Subtracting holes for %s\n" ), aWhat ), + RPT_SEVERITY_DEBUG ); + + for( auto& [netname, vec] : aShapesMap ) { - TopoDS_Shape& shape = vec[shapeId]; - - Bnd_Box shapeBbox; - BRepBndLib::Add( shape, shapeBbox ); - - TopTools_ListOfShape holelist; + std::mutex mutex; + auto subtractLoopFn = [&]( const int a, const int b ) { - std::unique_lock lock( mutex ); - - const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox ); - - for( const Standard_Integer& index : indices ) - holelist.Append( aHolesList[index] ); - } - - if( holelist.IsEmpty() ) - continue; - - TopTools_ListOfShape cutArgs; - cutArgs.Append( shape ); - - BRepAlgoAPI_Cut cut; - - cut.SetRunParallel( true ); - cut.SetToFillHistory( false ); - - cut.SetArguments( cutArgs ); - cut.SetTools( holelist ); - cut.Build(); - - if( cut.HasErrors() || cut.HasWarnings() ) - { - ReportMessage( wxString::Format( _( "\n** Got problems while cutting " - "%s net '%s' **\n" ), - aWhat, UnescapeString( netname ) ) ); - shapeBbox.Dump(); - - if( cut.HasErrors() ) + for( int shapeId = a; shapeId < b; shapeId++ ) { - ReportMessage( _( "Errors:\n" ) ); - cut.DumpErrors( std::cout ); + TopoDS_Shape& shape = vec[shapeId]; + + Bnd_Box shapeBbox; + BRepBndLib::Add( shape, shapeBbox ); + + TopTools_ListOfShape holelist; + + { + std::unique_lock lock( mutex ); + + const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox ); + + for( const Standard_Integer& index : indices ) + holelist.Append( aHolesList[index] ); + } + + if( holelist.IsEmpty() ) + continue; + + TopTools_ListOfShape cutArgs; + cutArgs.Append( shape ); + + BRepAlgoAPI_Cut cut; + + cut.SetRunParallel( true ); + cut.SetToFillHistory( false ); + + cut.SetArguments( cutArgs ); + cut.SetTools( holelist ); + cut.Build(); + + if( cut.HasErrors() || cut.HasWarnings() ) + { + m_reporter->Report( wxString::Format( _( "** Got problems while cutting " + "%s net '%s' **\n" ), + aWhat, + UnescapeString( netname ) ), + RPT_SEVERITY_ERROR ); + shapeBbox.Dump(); + + if( cut.HasErrors() ) + { + wxString msg = _( "Errors:\n" ); + wxStringOutputStream os_stream( &msg ); + wxStdOutputStream out( os_stream ); + + cut.DumpErrors( out ); + m_reporter->Report( msg, RPT_SEVERITY_ERROR ); + } + + if( cut.HasWarnings() ) + { + wxString msg = _( "Warnings:\n" ); + wxStringOutputStream os_stream( &msg ); + wxStdOutputStream out( os_stream ); + + cut.DumpWarnings( out ); + m_reporter->Report( msg, RPT_SEVERITY_WARNING ); + } + } + + shape = cut.Shape(); } + }; - if( cut.HasWarnings() ) - { - ReportMessage( _( "Warnings:\n" ) ); - cut.DumpWarnings( std::cout ); - } - - std::cout << "\n"; - } - - shape = cut.Shape(); + tp.parallelize_loop( vec.size(), subtractLoopFn ).wait(); } }; - tp.parallelize_loop( vec.size(), subtractLoopFn ).wait(); - } - }; - auto subtractShapes = [subtractShapesMap]( const wxString& aWhat, std::vector& aShapesList, std::vector& aHolesList, @@ -2032,7 +2058,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool for( const auto& [netname, shapes] : m_board_copper_vias ) addShapes( netname, shapes ); - ReportMessage( "Fusing shapes\n" ); + m_reporter->Report( wxT( "Fusing shapes\n" ), RPT_SEVERITY_DEBUG ); // Do fusing in parallel std::mutex mutex; @@ -2040,7 +2066,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool auto fuseLoopFn = [&]( const wxString& aNetname ) { auto& toFuse = shapesToFuseMap[aNetname]; - TopoDS_Shape fusedShape = fuseShapesOrCompound( toFuse ); + TopoDS_Shape fusedShape = fuseShapesOrCompound( toFuse, m_reporter ); if( !fusedShape.IsNull() ) { @@ -2063,7 +2089,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool } // push the board to the data structure - ReportMessage( wxT( "\nGenerate board full shape.\n" ) ); + m_reporter->Report( wxT( "Generate board full shape.\n" ), RPT_SEVERITY_DEBUG ); // AddComponent adds a label that has a reference (not a parent/child relation) to the real // label. We need to extract that real label to name it for the STEP output cleanly @@ -2074,104 +2100,106 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool // aCompoundNets will place all geometry within a net into one compound. // aCompoundAll will place all geometry into one compound. - auto pushToAssemblyMap = [&]( const std::map>& aShapesMap, - const TDF_Label& aVisMatLabel, const wxString& aShapeName, - bool aCompoundNets, bool aCompoundAll ) - { - std::map> shapesMap; - - if( aCompoundAll ) - { - std::vector allShapes; - - for( const auto& [netname, shapesList] : aShapesMap ) - allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() ); - - if( !allShapes.empty() ) - shapesMap[wxEmptyString].emplace_back( makeCompound( allShapes ) ); - } - else - { - shapesMap = aShapesMap; - } - - for( const auto& [netname, shapesList] : shapesMap ) - { - std::vector newList; - - if( aCompoundNets ) - newList.emplace_back( makeCompound( shapesList ) ); - else - newList = shapesList; - - int i = 1; - for( TopoDS_Shape& shape : newList ) + auto pushToAssemblyMap = + [&]( const std::map>& aShapesMap, + const TDF_Label& aVisMatLabel, const wxString& aShapeName, bool aCompoundNets, + bool aCompoundAll ) { - Handle( TDataStd_TreeNode ) node; + std::map> shapesMap; - // Dont expand the component or else coloring it gets hard - TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape, false ); - m_pcb_labels.push_back( lbl ); - - if( m_pcb_labels.back().IsNull() ) - return; - - lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node ); - TDF_Label shpLbl = node->Father()->Label(); - if( !shpLbl.IsNull() ) + if( aCompoundAll ) { - if( visMatTool && !aVisMatLabel.IsNull() ) - visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel ); + std::vector allShapes; - wxString shapeName; + for( const auto& [netname, shapesList] : aShapesMap ) + allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() ); - shapeName << m_pcbName; - shapeName << '_'; - shapeName << aShapeName; - - if( !netname.empty() ) - { - shapeName << '_'; - shapeName << netname; - } - - if( newList.size() > 1 ) - { - shapeName << '_'; - shapeName << i; - } - - TCollection_ExtendedString partname( shapeName.ToUTF8().data() ); - TDataStd_Name::Set( shpLbl, partname ); + if( !allShapes.empty() ) + shapesMap[wxEmptyString].emplace_back( makeCompound( allShapes ) ); + } + else + { + shapesMap = aShapesMap; } - i++; - } - } - }; + for( const auto& [netname, shapesList] : shapesMap ) + { + std::vector newList; - auto pushToAssembly = [&]( const std::vector& aShapesList, - const TDF_Label& aVisMatLabel, const wxString& aShapeName, - bool aCompound ) - { - const std::map> shapesMap{ { wxEmptyString, - aShapesList } }; + if( aCompoundNets ) + newList.emplace_back( makeCompound( shapesList ) ); + else + newList = shapesList; - pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound ); - }; + int i = 1; - auto makeMaterial = [&]( const TCollection_AsciiString& aName, - const Quantity_ColorRGBA& aBaseColor, double aMetallic, - double aRoughness ) -> TDF_Label - { - Handle( XCAFDoc_VisMaterial ) vismat = new XCAFDoc_VisMaterial; - XCAFDoc_VisMaterialPBR pbr; - pbr.BaseColor = aBaseColor; - pbr.Metallic = aMetallic; - pbr.Roughness = aRoughness; - vismat->SetPbrMaterial( pbr ); - return visMatTool->AddMaterial( vismat, aName ); - }; + for( TopoDS_Shape& shape : newList ) + { + Handle( TDataStd_TreeNode ) node; + + // Dont expand the component or else coloring it gets hard + TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape, false ); + m_pcb_labels.push_back( lbl ); + + if( m_pcb_labels.back().IsNull() ) + return; + + lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node ); + TDF_Label shpLbl = node->Father()->Label(); + + if( !shpLbl.IsNull() ) + { + if( visMatTool && !aVisMatLabel.IsNull() ) + visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel ); + + wxString shapeName; + + shapeName << m_pcbName; + shapeName << '_'; + shapeName << aShapeName; + + if( !netname.empty() ) + { + shapeName << '_'; + shapeName << netname; + } + + if( newList.size() > 1 ) + { + shapeName << '_'; + shapeName << i; + } + + TCollection_ExtendedString partname( shapeName.ToUTF8().data() ); + TDataStd_Name::Set( shpLbl, partname ); + } + + i++; + } + } + }; + + auto pushToAssembly = + [&]( const std::vector& aShapesList, const TDF_Label& aVisMatLabel, + const wxString& aShapeName, bool aCompound ) + { + const std::map> shapesMap{ { wxEmptyString, aShapesList } }; + + pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound ); + }; + + auto makeMaterial = + [&]( const TCollection_AsciiString& aName, const Quantity_ColorRGBA& aBaseColor, + double aMetallic, double aRoughness ) -> TDF_Label + { + Handle( XCAFDoc_VisMaterial ) vismat = new XCAFDoc_VisMaterial; + XCAFDoc_VisMaterialPBR pbr; + pbr.BaseColor = aBaseColor; + pbr.Metallic = aMetallic; + pbr.Roughness = aRoughness; + vismat->SetPbrMaterial( pbr ); + return visMatTool->AddMaterial( vismat, aName ); + }; // Init colors for the board items Quantity_ColorRGBA copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], 1.0 ); @@ -2238,9 +2266,9 @@ bool STEP_PCB_MODEL::WriteIGES( const wxString& aFileName ) { if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -2254,10 +2282,8 @@ bool STEP_PCB_MODEL::WriteIGES( const wxString& aFileName ) IGESData_GlobalSection header = writer.Model()->GlobalSection(); header.SetFileName( new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) ); header.SetSendName( new TCollection_HAsciiString( "KiCad electronic assembly" ) ); - header.SetAuthorName( - new TCollection_HAsciiString( Interface_Static::CVal( "write.iges.header.author" ) ) ); - header.SetCompanyName( - new TCollection_HAsciiString( Interface_Static::CVal( "write.iges.header.company" ) ) ); + header.SetAuthorName( new TCollection_HAsciiString( Interface_Static::CVal( "write.iges.header.author" ) ) ); + header.SetCompanyName( new TCollection_HAsciiString( Interface_Static::CVal( "write.iges.header.company" ) ) ); writer.Model()->SetGlobalSection( header ); if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) ) @@ -2272,9 +2298,9 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName, bool aOptimize ) { if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -2292,12 +2318,18 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName, bool aOptimize ) // target is still better than "open cascade step translter v..." // UTF8 should be ok from ISO 10303-21:2016, but... older stuff? use boring ascii if( !Interface_Static::SetCVal( "write.step.product.name", fn.GetName().ToAscii() ) ) - ReportMessage( wxT( "Failed to set step product name, but will attempt to continue." ) ); + { + m_reporter->Report( _( "Failed to set STEP product name, but will attempt to continue." ), + RPT_SEVERITY_WARNING ); + } // Setting write.surfacecurve.mode to 0 reduces file size and write/read times. // But there are reports that this mode might be less compatible in some cases. if( !Interface_Static::SetIVal( "write.surfacecurve.mode", aOptimize ? 0 : 1 ) ) - ReportMessage( wxT( "Failed to set surface curve mode, but will attempt to continue." ) ); + { + m_reporter->Report( _( "Failed to set surface curve mode, but will attempt to continue." ), + RPT_SEVERITY_WARNING ); + } if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) ) return false; @@ -2336,9 +2368,10 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName, bool aOptimize ) if( !wxRenameFile( tmpfname, fn.GetFullName(), true ) ) { - ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ), - tmpfname, - fn.GetFullName() ) ); + m_reporter->Report( wxString::Format( _( "Cannot rename temporary file '%s' to '%s'.\n" ), + tmpfname, + fn.GetFullName() ), + RPT_SEVERITY_ERROR ); success = false; } } @@ -2353,9 +2386,9 @@ bool STEP_PCB_MODEL::WriteBREP( const wxString& aFileName ) { if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -2391,7 +2424,8 @@ bool STEP_PCB_MODEL::WriteXAO( const wxString& aFileName ) if( !ffStream.IsOk() ) { - ReportMessage( wxString::Format( "Could not open file '%s'", fn.GetFullPath() ) ); + m_reporter->Report( wxString::Format( "Could not open file '%s'", fn.GetFullPath() ), + RPT_SEVERITY_ERROR ); return false; } @@ -2515,8 +2549,8 @@ bool STEP_PCB_MODEL::WriteXAO( const wxString& aFileName ) int groupNumber = 1; - ReportMessage( "Pad definitions:\n" ); - ReportMessage( "Number\tName\tArea (m^2)\n" ); + m_reporter->Report( wxT( "Pad definitions:\n" ), RPT_SEVERITY_DEBUG ); + m_reporter->Report( wxT( "Number\tName\tArea (m^2)\n" ), RPT_SEVERITY_DEBUG ); for( int dim = 0; dim <= 3; dim++ ) { @@ -2540,19 +2574,23 @@ bool STEP_PCB_MODEL::WriteXAO( const wxString& aFileName ) // file << "\" tag=\"" << g.first; //#endif file << "\" count=\"" << g.second.size() << "\">" << std::endl; + for( auto index : g.second ) - { file << " " << std::endl; - } + file << " " << std::endl; - ReportMessage( wxString::Format( "%d\t%s\t%g\n", groupNumber, name, groupAreas[name] ) ); + m_reporter->Report( wxString::Format( "%d\t%s\t%g\n", + groupNumber, + name, + groupAreas[name] ), + RPT_SEVERITY_DEBUG ); groupNumber++; } } - ReportMessage( "\n" ); + m_reporter->Report( wxT( "\n" ), RPT_SEVERITY_DEBUG ); file << " " << std::endl; file << " " << std::endl; @@ -2589,8 +2627,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a case FMT_IGES: if( !readIGES( doc, aFileNameUTF8.c_str() ) ) { - ReportMessage( wxString::Format( wxT( "readIGES() failed on filename '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( wxT( "readIGES() failed on filename '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } break; @@ -2598,8 +2637,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a case FMT_STEP: if( !readSTEP( doc, aFileNameUTF8.c_str() ) ) { - ReportMessage( wxString::Format( wxT( "readSTEP() failed on filename '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( wxT( "readSTEP() failed on filename '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } break; @@ -2617,8 +2657,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a if( size == wxInvalidOffset ) { - ReportMessage( wxString::Format( wxT( "getModelLabel() failed on filename '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( wxT( "getModelLabel() failed on filename '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -2641,8 +2682,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a } catch( ... ) { - ReportMessage( wxString::Format( wxT( "failed to decompress '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( wxT( "failed to decompress '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); } if( expanded.empty() ) @@ -2669,8 +2711,7 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a if( success ) { std::string altFileNameUTF8 = TO_UTF8( outFile.GetFullPath() ); - success = - getModelLabel( altFileNameUTF8, VECTOR3D( 1.0, 1.0, 1.0 ), aLabel, false ); + success = getModelLabel( altFileNameUTF8, VECTOR3D( 1.0, 1.0, 1.0 ), aLabel, false ); } return success; @@ -2758,8 +2799,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a } else { - ReportMessage( wxString::Format( wxT( "readVRML() failed on filename '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( wxT( "readVRML() failed on filename '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } } @@ -2777,8 +2819,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a // TODO: implement IDF and EMN converters default: - ReportMessage( wxString::Format( wxT( "Cannot identify actual file type for '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( _( "Cannot identify actual file type for '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -2786,8 +2829,9 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a if( aLabel.IsNull() ) { - ReportMessage( wxString::Format( wxT( "Could not transfer model data from file '%s'.\n" ), - fileName ) ); + m_reporter->Report( wxString::Format( _( "Could not transfer model data from file '%s'.\n" ), + fileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -3028,7 +3072,7 @@ bool STEP_PCB_MODEL::performMeshing( Handle( XCAFDoc_ShapeTool ) & aShapeTool ) TDF_LabelSequence freeShapes; aShapeTool->GetFreeShapes( freeShapes ); - ReportMessage( wxT( "Meshing model\n" ) ); + m_reporter->Report( wxT( "Meshing model\n" ), RPT_SEVERITY_DEBUG ); // GLTF is a mesh format, we have to trigger opencascade to mesh the shapes we composited into the asesmbly // To mesh models, lets just grab the free shape root and execute on them @@ -3055,9 +3099,9 @@ bool STEP_PCB_MODEL::WriteGLTF( const wxString& aFileName ) { if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -3106,8 +3150,10 @@ bool STEP_PCB_MODEL::WriteGLTF( const wxString& aFileName ) if( !wxRenameFile( tmpGltfname, fn.GetFullName(), true ) ) { - ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ), - tmpGltfname, fn.GetFullName() ) ); + m_reporter->Report( wxString::Format( _( "Cannot rename temporary file '%s' to '%s'.\n" ), + tmpGltfname, + fn.GetFullName() ), + RPT_SEVERITY_ERROR ); success = false; } } @@ -3127,9 +3173,9 @@ bool STEP_PCB_MODEL::WritePLY( const wxString& aFileName ) if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -3177,8 +3223,10 @@ bool STEP_PCB_MODEL::WritePLY( const wxString& aFileName ) if( !wxRenameFile( tmpFname, fn.GetFullName(), true ) ) { - ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ), - tmpFname, fn.GetFullName() ) ); + m_reporter->Report( wxString::Format( _( "Cannot rename temporary file '%s' to '%s'.\n" ), + tmpFname, + fn.GetFullName() ), + RPT_SEVERITY_ERROR ); success = false; } } @@ -3194,9 +3242,9 @@ bool STEP_PCB_MODEL::WriteSTL( const wxString& aFileName ) { if( !isBoardOutlineValid() ) { - ReportMessage( wxString::Format( wxT( "No valid PCB assembly; cannot create output file " - "'%s'.\n" ), - aFileName ) ); + m_reporter->Report( wxString::Format( _( "No valid PCB assembly; cannot create output file '%s'.\n" ), + aFileName ), + RPT_SEVERITY_ERROR ); return false; } @@ -3224,8 +3272,10 @@ bool STEP_PCB_MODEL::WriteSTL( const wxString& aFileName ) if( !wxRenameFile( tmpFname, fn.GetFullName(), true ) ) { - ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ), - tmpFname, fn.GetFullName() ) ); + m_reporter->Report( wxString::Format( _( "Cannot rename temporary file '%s' to '%s'.\n" ), + tmpFname, + fn.GetFullName() ), + RPT_SEVERITY_ERROR ); success = false; } } diff --git a/pcbnew/exporters/step/step_pcb_model.h b/pcbnew/exporters/step/step_pcb_model.h index 0dac1d0a98..e2f2a86218 100644 --- a/pcbnew/exporters/step/step_pcb_model.h +++ b/pcbnew/exporters/step/step_pcb_model.h @@ -73,7 +73,6 @@ class XCAFDoc_ShapeTool; typedef std::pair< std::string, TDF_Label > MODEL_DATUM; typedef std::map< std::string, TDF_Label > MODEL_MAP; -extern void ReportMessage( const wxString& aMessage ); enum class OUTPUT_FORMAT { @@ -90,7 +89,7 @@ enum class OUTPUT_FORMAT class STEP_PCB_MODEL { public: - STEP_PCB_MODEL( const wxString& aPcbName ); + STEP_PCB_MODEL( const wxString& aPcbName, REPORTER* aReporter ); virtual ~STEP_PCB_MODEL(); // Update m_outFmt to aVariant, giving the output format variant @@ -288,6 +287,7 @@ private: /// The current output format for created file OUTPUT_FORMAT m_outFmt; + REPORTER* m_reporter; }; #endif // OCE_VIS_OCE_UTILS_H diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index 15470d40b4..b9ba49b95f 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -515,7 +515,7 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob ) return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here } - EXPORTER_STEP stepExporter( brd, params ); + EXPORTER_STEP stepExporter( brd, params, m_reporter ); stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() ); if( !stepExporter.Export() )