32#include <wx/filename.h> 
   34#include <wx/sstream.h> 
   35#include <wx/stdpaths.h> 
   38#include <wx/zstream.h> 
   39#include <wx/wfstream.h> 
   40#include <wx/zipstrm.h> 
   41#include <wx/stdstream.h> 
   44#include <decompress.hpp> 
   69#include <IGESCAFControl_Reader.hxx> 
   70#include <IGESCAFControl_Writer.hxx> 
   71#include <IGESControl_Controller.hxx> 
   72#include <IGESData_GlobalSection.hxx> 
   73#include <IGESData_IGESModel.hxx> 
   74#include <Interface_Static.hxx> 
   75#include <Quantity_Color.hxx> 
   76#include <STEPCAFControl_Reader.hxx> 
   77#include <STEPCAFControl_Writer.hxx> 
   78#include <APIHeaderSection_MakeHeader.hxx> 
   79#include <Standard_Failure.hxx> 
   80#include <Standard_Handle.hxx> 
   81#include <Standard_Version.hxx> 
   82#include <TCollection_ExtendedString.hxx> 
   83#include <TDocStd_Document.hxx> 
   84#include <TDocStd_XLinkTool.hxx> 
   85#include <TDataStd_Name.hxx> 
   86#include <TDataStd_TreeNode.hxx> 
   87#include <TDF_LabelSequence.hxx> 
   88#include <TDF_Tool.hxx> 
   89#include <TopExp_Explorer.hxx> 
   91#include <XCAFApp_Application.hxx> 
   93#include <XCAFDoc_DocumentTool.hxx> 
   94#include <XCAFDoc_ColorTool.hxx> 
   95#include <XCAFDoc_ShapeTool.hxx> 
   96#include <XCAFDoc_VisMaterialTool.hxx> 
   97#include <XCAFDoc_Area.hxx> 
   98#include <XCAFDoc_Centroid.hxx> 
   99#include <XCAFDoc_Location.hxx> 
  100#include <XCAFDoc_Volume.hxx> 
  103#include "KI_XCAFDoc_AssemblyGraph.hxx" 
  105#include <BRep_Tool.hxx> 
  106#include <BRepMesh_IncrementalMesh.hxx> 
  107#include <BRepBuilderAPI_GTransform.hxx> 
  108#include <BRepBuilderAPI_MakeEdge.hxx> 
  109#include <BRepBuilderAPI_MakeWire.hxx> 
  110#include <BRepBuilderAPI_MakeFace.hxx> 
  111#include <BRepExtrema_DistShapeShape.hxx> 
  112#include <BRepPrimAPI_MakePrism.hxx> 
  113#include <BRepTools.hxx> 
  114#include <BRepLib_MakeWire.hxx> 
  115#include <BRepAdaptor_Surface.hxx> 
  116#include <BRepAlgoAPI_Check.hxx> 
  117#include <BRepAlgoAPI_Cut.hxx> 
  118#include <BRepAlgoAPI_Fuse.hxx> 
  119#include <ShapeUpgrade_UnifySameDomain.hxx> 
  121#include <BRepBndLib.hxx> 
  122#include <Bnd_BoundSortBox.hxx> 
  123#include <GProp_GProps.hxx> 
  124#include <BRepGProp.hxx> 
  126#include <Geom_Curve.hxx> 
  127#include <Geom_TrimmedCurve.hxx> 
  132#include <GC_MakeArcOfCircle.hxx> 
  133#include <GC_MakeCircle.hxx> 
  135#include <RWGltf_CafWriter.hxx> 
  136#include <StlAPI_Writer.hxx> 
  138#if OCC_VERSION_HEX >= 0x070700 
  139#include <VrmlAPI_CafReader.hxx> 
  140#include <RWPly_CafWriter.hxx> 
  168    wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
 
  170    if( !lfile.FileExists() )
 
  173    wxString ext = lfile.GetExt().Lower();
 
  175    if( ext == wxT( 
"wrl" ) )
 
  178    if( ext == wxT( 
"wrz" ) )
 
  181    if( ext == wxT( 
"idf" ) )
 
  184    if( ext == wxT( 
"emn" ) )
 
  187    if( ext == wxT( 
"stpz" ) || ext == wxT( 
"gz" ) )
 
  201    const int max_line_count = 3;
 
  203    for( 
int ii = 0; ii < max_line_count; ii++ )
 
  205        memset( iline, 0, 82 );
 
  206        ifile.getline( iline, 82 );
 
  212        if( !strncmp( iline, 
"ISO-10303-21;", 13 ) )
 
  218        std::string fstr = iline;
 
  222        if( fstr.find( 
"urn:oid:1.0.10303." ) != std::string::npos )
 
  231        if( iline[72] == 
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
 
  238        if( strncmp( iline, 
"/*", 2 ) != 0 )    
 
 
  256    double   bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
 
  257    double   cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
 
  258    double   det = -b.
x * d.
y + d.
x * b.
y;
 
  262    center.x = ( -bc * d.
y - cd * b.
y ) * det;
 
  263    center.y = ( b.
x * cd + d.
x * bc ) * det;
 
 
  270#define APPROX_DBG( stmt ) 
  278    static const double c_radiusDeviation = 1000.0;
 
  279    static const double c_arcCenterDeviation = 1000.0;
 
  280    static const double c_relLengthDeviation = 0.8;
 
  281    static const int    c_last_none = -1000; 
 
  283    static const double c_smallSize = 
pcbIUScale.mmToIU( 0.1 );
 
  284    static const double c_circleCloseGap = 
pcbIUScale.mmToIU( 1.0 );
 
  301        int last = c_last_none;
 
  307        APPROX_DBG( std::cout << i << 
" " << aSrc.
CPoint( i ) << 
" " << ( i - 3 ) << 
" " 
  309                              << ( i - 1 ) << 
" " << 
VECTOR2I( p2 ) << std::endl );
 
  314        bool defective = 
false;
 
  320        defective |= 
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
 
  328            double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
 
  329            defective |= 
std::abs( a_diff ) < 0.1;
 
  332            double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
 
  333            defective |= 
std::abs( a_diff ) >= maxAngleDiff;
 
  344            for( 
int j = i; j <= jEndIdx; j++ )
 
  349                double    rad_test = ( p_test - 
center ).EuclideanNorm();
 
  350                double    d_tl = ( p_test - p_prev ).EuclideanNorm();
 
  354                                      << int64_t( rad_test ) << 
" ref " << int64_t( 
radius )
 
  357                if( rad_dev > c_radiusDeviation )
 
  360                                          << 
" Radius deviation too large: " << int64_t( rad_dev )
 
  361                                          << 
" > " << c_radiusDeviation << std::endl );
 
  366                double maxAngleDiff =
 
  367                        std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
 
  369                double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
 
  370                if( 
std::abs( a_diff_test ) >= maxAngleDiff )
 
  372                    APPROX_DBG( std::cout << 
"  " << j << 
" Angles differ too much " << a_diff_test
 
  377                if( 
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
 
  379                    APPROX_DBG( std::cout << 
"  " << j << 
" Lengths differ too much " << d_tl
 
  380                                          << 
"; " << d01 << std::endl );
 
  390        if( last != c_last_none )
 
  399                int toRemove = last - ( aSrc.
PointCount() - 3 );
 
  429                APPROX_DBG( std::cout << 
" Self-intersection check failed" << std::endl );
 
  433        if( last == c_last_none )
 
  450    if( iarc0 != -1 && iarc1 != -1 )
 
  452        APPROX_DBG( std::cout << 
"Final arcs " << iarc0 << 
" " << iarc1 << std::endl );
 
  462            if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
 
  480            if( 
std::abs( ar0 - ar1 ) <= c_radiusDeviation
 
  481                && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
 
 
  499    TDF_LabelSequence theLabels;
 
  500    aShapeTool->GetFreeShapes( theLabels );
 
  504    if( theLabels.Length() == 1 )
 
  505        return aShapeTool->GetShape( theLabels.Value( 1 ) );
 
  507    TopoDS_Compound aCompound;
 
  508    BRep_Builder    aBuilder;
 
  509    aBuilder.MakeCompound( aCompound );
 
  511    for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
 
  513        TopoDS_Shape aFreeShape;
 
  515        if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
 
  518        aBuilder.Add( aCompound, aFreeShape );
 
  521    if( aCompound.NbChildren() > 0 )
 
 
  530static Standard_Boolean 
rescaleShapes( 
const TDF_Label& theLabel, 
const gp_XYZ& aScale )
 
  532    if( theLabel.IsNull() )
 
  534        Message::SendFail( 
"Null label." );
 
  535        return Standard_False;
 
  538    if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
 
  539        || Abs( aScale.Z() ) <= gp::Resolution() )
 
  541        Message::SendFail( 
"Scale factor is too small." );
 
  542        return Standard_False;
 
  545    Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
 
  547    if( aShapeTool.IsNull() )
 
  549        Message::SendFail( 
"Couldn't find XCAFDoc_ShapeTool attribute." );
 
  550        return Standard_False;
 
  553    Handle( KI_XCAFDoc_AssemblyGraph ) aG = 
new KI_XCAFDoc_AssemblyGraph( theLabel );
 
  557        Message::SendFail( 
"Couldn't create assembly graph." );
 
  558        return Standard_False;
 
  561    Standard_Boolean anIsDone = Standard_True;
 
  565    aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
 
  567                                     0, 0, aScale.Z() ) );
 
  570    BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
 
  572    for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
 
  574        const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
 
  576        if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
 
  577            && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
 
  582        const TDF_Label& aLabel = aG->GetNode( idx );
 
  584        if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
 
  586            const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
 
  587            aBRepTrsf.Perform( aShape, Standard_True );
 
  588            if( !aBRepTrsf.IsDone() )
 
  590                Standard_SStream        aSS;
 
  591                TCollection_AsciiString anEntry;
 
  592                TDF_Tool::Entry( aLabel, anEntry );
 
  593                aSS << 
"Shape " << anEntry << 
" is not scaled!";
 
  594                Message::SendFail( aSS.str().c_str() );
 
  595                anIsDone = Standard_False;
 
  596                return Standard_False;
 
  598            TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
 
  599            aShapeTool->SetShape( aLabel, aScaledShape );
 
  602            TDF_LabelSequence aSubshapes;
 
  603            aShapeTool->GetSubShapes( aLabel, aSubshapes );
 
  604            for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
 
  606                const TDF_Label&   aLSs = anItSs.Value();
 
  607                const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
 
  608                const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
 
  609                aShapeTool->SetShape( aLSs, aSs1 );
 
  613            aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
 
  614            aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
 
  615            aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
 
  617        else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
 
  619            TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
 
  620            gp_Trsf         aTrsf = aLoc.Transformation();
 
  621            aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
 
  622            XCAFDoc_Location::Set( aLabel, aTrsf );
 
  628        return Standard_False;
 
  631    aShapeTool->UpdateAssemblies();
 
 
  639    BRepAlgoAPI_Fuse     mkFuse;
 
  640    TopTools_ListOfShape shapeArguments, shapeTools;
 
  642    for( TopoDS_Shape& sh : aInputShapes )
 
  647        if( shapeArguments.IsEmpty() )
 
  648            shapeArguments.Append( sh );
 
  650            shapeTools.Append( sh );
 
  653    mkFuse.SetRunParallel( 
true );
 
  654    mkFuse.SetToFillHistory( 
false );
 
  655    mkFuse.SetArguments( shapeArguments );
 
  656    mkFuse.SetTools( shapeTools );
 
  659    if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
 
  663        if( mkFuse.HasErrors() )
 
  665            wxString             msg = 
_( 
"Errors:\n" );
 
  666            wxStringOutputStream os_stream( &msg );
 
  667            wxStdOutputStream    out( os_stream );
 
  669            mkFuse.DumpErrors( out );
 
  673        if( mkFuse.HasWarnings() )
 
  675            wxString             msg = 
_( 
"Warnings:\n" );
 
  676            wxStringOutputStream os_stream( &msg );
 
  677            wxStdOutputStream    out( os_stream );
 
  679            mkFuse.DumpWarnings( out );
 
  684    if( mkFuse.IsDone() )
 
  686        TopoDS_Shape fusedShape = mkFuse.Shape();
 
  688        ShapeUpgrade_UnifySameDomain unify( fusedShape, 
true, 
true, 
false );
 
  689        unify.History() = 
nullptr;
 
  692        TopoDS_Shape unifiedShapes = unify.Shape();
 
  694        if( unifiedShapes.IsNull() )
 
  696            aReporter->
Report( 
_( 
"** ShapeUpgrade_UnifySameDomain produced a null shape **" ),
 
  701            aOutShape = unifiedShapes;
 
 
  712    TopoDS_Compound compound;
 
  713    BRep_Builder    builder;
 
  714    builder.MakeCompound( compound );
 
  716    for( 
const TopoDS_Shape& shape : aInputShapes )
 
  717        builder.Add( compound, shape );
 
 
  727    TopoDS_Shape outShape;
 
  729    if( aInputShapes.Size() == 1 )
 
  730        return aInputShapes.First();
 
  732    if( 
fuseShapes( aInputShapes, outShape, aReporter ) )
 
 
  741                                     const TCollection_ExtendedString& aPrefix )
 
  743    Handle( KI_XCAFDoc_AssemblyGraph ) aG = 
new KI_XCAFDoc_AssemblyGraph( aLabel );
 
  747        Message::SendFail( 
"Couldn't create assembly graph." );
 
  748        return Standard_False;
 
  751    Standard_Boolean anIsDone = Standard_True;
 
  753    for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
 
  755        const TDF_Label& lbl = aG->GetNode( idx );
 
  756        Handle( TDataStd_Name ) nameHandle;
 
  758        if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
 
  760            TCollection_ExtendedString 
name;
 
  764            name += nameHandle->Get();
 
  767            TDataStd_Name::Set( lbl, 
name );
 
  771            TDataStd_Name::Set( lbl, aPrefix );
 
 
  782    m_app = XCAFApp_Application::GetApplication();
 
  783    m_app->NewDocument( 
"MDTV-XCAF", m_doc );
 
  784    m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
 
 
  801    if( m_doc->CanClose() == CDM_CCS_OK )
 
 
  809    const double              c_padExtraThickness = 0.005;
 
  811    std::vector<TopoDS_Shape> padShapes;
 
  825        double Zpos, thickness;
 
  831            if( pcb_layer == 
F_Cu )
 
  832                thickness += c_padExtraThickness;
 
  833            else if( pcb_layer == 
B_Cu )
 
  834                thickness -= c_padExtraThickness;
 
  837        TopoDS_Shape testShape;
 
  851        if( testShape.IsNull() )
 
  853            std::vector<TopoDS_Shape> testShapes;
 
  857            if( testShapes.size() > 0 )
 
  858                testShape = testShapes.front();
 
  861        if( !aVia && !testShape.IsNull() )
 
  863            if( pcb_layer == 
F_Cu || pcb_layer == 
B_Cu )
 
  869                if( pcb_layer == 
F_Cu )
 
  871                else if( pcb_layer == 
B_Cu )
 
  887        double f_pos, f_thickness;
 
  888        double b_pos, b_thickness;
 
  895            f_thickness += c_padExtraThickness;
 
  896            b_thickness -= c_padExtraThickness;
 
  899        double top = std::max( f_pos, f_pos + f_thickness );
 
  900        double bottom = std::min( b_pos, b_pos + b_thickness );
 
  901        double hole_height = top - bottom;
 
  903        TopoDS_Shape plating;
 
  911                                         hole_height, bottom, aOrigin ) )
 
  913                padShapes.push_back( plating );
 
  927            if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )  
 
  944                padShapes.push_back( plating );
 
  956    if( !padShapes.empty() )
 
  961            TopTools_ListOfShape padShapesList;
 
  963            for( 
const TopoDS_Shape& shape : padShapes )
 
  964                padShapesList.Append( shape );
 
  970            for( 
const TopoDS_Shape& shape : padShapes )
 
 
  981                              const VECTOR2D& aOrigin, 
bool aCutCopper, 
bool aCutBody )
 
  983    double margin = 0.001; 
 
  991    double f_pos, f_thickness;
 
  992    double b_pos, b_thickness;
 
  995    double top = std::max( f_pos, f_pos + f_thickness );
 
  996    double bottom = std::min( b_pos, b_pos + b_thickness );
 
  998    double holeZsize = ( top - bottom ) + ( margin * 2 );
 
 1000    double boardDrill = aShape.
GetWidth();
 
 1001    double copperDrill = boardDrill - aPlatingThickness * 2;
 
 1003    TopoDS_Shape copperHole, boardHole;
 
 1008                                     holeZsize, bottom - margin, aOrigin ) )
 
 1021                                     holeZsize, bottom - margin, aOrigin ) )
 
 
 1037                                const wxString& aNetname )
 
 1039    double f_pos, f_thickness;
 
 1040    double b_pos, b_thickness;
 
 1043    double top = std::max( f_pos, f_pos + f_thickness );
 
 1044    double bottom = std::min( b_pos, b_pos + b_thickness );
 
 1046    TopoDS_Shape plating;
 
 1049                                  ( top - bottom ), bottom, aOrigin ) )
 
 
 1064                                         double& aThickness )
 
 1067    static const double c_silkscreenAboveCopper = 0.04;
 
 1068    static const double c_soldermaskAboveCopper = 0.015;
 
 1076        double f_pos, f_thickness;
 
 1078        double top = std::max( f_pos, f_pos + f_thickness );
 
 1081            aZPos = top + c_silkscreenAboveCopper;
 
 1083            aZPos = top + c_soldermaskAboveCopper;
 
 1089        double b_pos, b_thickness;
 
 1091        double bottom = std::min( b_pos, b_pos + b_thickness );
 
 1094            aZPos = bottom - c_silkscreenAboveCopper;
 
 1096            aZPos = bottom - c_soldermaskAboveCopper;
 
 
 1104                                               double& aThickness )
 
 1108    bool wasPrepreg = 
false;
 
 1110    const std::vector<BOARD_STACKUP_ITEM*>& materials = 
m_stackup.GetList();
 
 1113    for( 
auto it = materials.rbegin(); it != materials.rend(); ++it )
 
 1119            if( aLayer == 
B_Cu )
 
 
 1164    double f_pos, f_thickness;
 
 1165    double b_pos, b_thickness;
 
 1168    double top = std::min( f_pos, f_pos + f_thickness );
 
 1169    double bottom = std::max( b_pos, b_pos + b_thickness );
 
 1171    aThickness = ( top - bottom );
 
 1174    wxASSERT( aZPos == 0.0 );
 
 
 1179                                       const VECTOR2D& aOrigin, 
const wxString& aNetname )
 
 1181    bool success = 
true;
 
 1189    double z_pos, thickness;
 
 1192    std::vector<TopoDS_Shape>* targetVec = 
nullptr;
 
 1200    else if( aLayer == 
F_Mask )
 
 1207        m_reporter->Report( wxString::Format( 
_( 
"Could not add shape (%d points) to copper layer %s." ),
 
 
 1220                             bool aBottom, 
const VECTOR2D& aPosition, 
double aRotation, 
const VECTOR3D& aOffset,
 
 1221                             const VECTOR3D& aOrientation, 
const VECTOR3D& aScale, 
bool aSubstituteModels )
 
 1223    if( aFileNameUTF8.empty() )
 
 1225        m_reporter->Report( wxString::Format( 
_( 
"No model defined for %s." ), aRefDes ),
 
 1230    wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
 
 1235    wxString  errorMessage;
 
 1237    if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
 
 1239        if( errorMessage.IsEmpty() )
 
 1240            errorMessage.Printf( 
_( 
"No model for filename '%s'." ), fileName );
 
 1247    TopLoc_Location toploc;
 
 1249    if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
 
 1251        m_reporter->Report( wxString::Format( 
_( 
"No location data for filename '%s'." ), fileName ),
 
 1257    TDF_Label llabel = m_assy->AddComponent( 
m_assy_label, lmodel, toploc );
 
 1259    if( llabel.IsNull() )
 
 1261        m_reporter->Report( wxString::Format( 
_( 
"Could not add component with filename '%s'." ), fileName ),
 
 1267    TCollection_ExtendedString refdes( aRefDes.c_str() );
 
 1268    TDataStd_Name::Set( llabel, refdes );
 
 
 1336                                              const VECTOR2D& aEndPoint, 
double aWidth, 
double aThickness,
 
 1337                                              double aZposition, 
const VECTOR2D& aOrigin )
 
 1344    double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
 
 1345    double h_width = aWidth/2.0;
 
 1347    coords[0] = 
VECTOR2D{ 0.0, h_width };
 
 1350    coords[1] = 
VECTOR2D{ len, h_width };
 
 1353    coords[2] = 
VECTOR2D{ len + h_width, 0.0 };
 
 1356    coords[3] = 
VECTOR2D{ len, -h_width };
 
 1359    coords[4] = 
VECTOR2D{ 0, -h_width };
 
 1362    coords[5] = 
VECTOR2D{ -h_width, 0.0 };
 
 1365    EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
 
 1367    for( 
int ii = 0; ii < 6; ii++ )
 
 1370        coords[ii] += aStartPoint;
 
 1375    gp_Pnt coords3D[ 6 ];
 
 1377    for( 
int ii = 0; ii < 6; ii++ )
 
 1379        coords3D[ii] = gp_Pnt( 
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
 
 1380                               -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
 
 1384    BRepBuilderAPI_MakeWire wire;
 
 1385    bool success = 
true;
 
 1397            Handle( Geom_Circle ) 
circle = GC_MakeCircle( coords3D[1], 
 
 1402            edge = BRepBuilderAPI_MakeEdge( 
circle );
 
 1407            edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
 
 1410            Handle( Geom_TrimmedCurve ) arcOfCircle =
 
 1411                    GC_MakeArcOfCircle( coords3D[1], 
 
 1415            edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
 
 1418            edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
 
 1421            Handle( Geom_TrimmedCurve ) arcOfCircle2 =
 
 1422                    GC_MakeArcOfCircle( coords3D[4], 
 
 1426            edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
 
 1430    catch( 
const Standard_Failure& e )
 
 1432        m_reporter->Report( wxString::Format( 
_( 
"OCC exception building shape segment: %s" ),
 
 1433                                              e.GetMessageString() ),
 
 1438    BRepBuilderAPI_MakeFace face;
 
 1442        gp_Pln plane( coords3D[0], gp::DZ() );
 
 1443        face = BRepBuilderAPI_MakeFace( plane, wire );
 
 1445    catch( 
const Standard_Failure& e )
 
 1447        m_reporter->Report( wxString::Format( 
_( 
"OCC exception building face: %s" ),
 
 1448                                              e.GetMessageString() ),
 
 1453    if( aThickness != 0.0 )
 
 1455        aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
 
 1457        if( aShape.IsNull() )
 
 1459            m_reporter->Report( 
_( 
"Failed to create a prismatic shape" ),
 
 
 1476                                        double aZposition, 
const VECTOR2D& aOrigin )
 
 1478    std::vector<TopoDS_Shape> testShapes;
 
 1481                               aHeight, aZposition, aOrigin );
 
 1483    if( testShapes.size() > 0 )
 
 1484        aShape = testShapes.front();
 
 
 1507                               double aMergeOCCMaxDist, 
double aZposition, 
const VECTOR2D& aOrigin,
 
 1511            [&]( 
const VECTOR2D& aKiCoords ) -> gp_Pnt
 
 1513                return gp_Pnt( 
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
 
 1514                               -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
 
 1524            gp_Pnt start = toPoint( aPt0 );
 
 1525            gp_Pnt 
end = toPoint( aPt1 );
 
 1527            BRepBuilderAPI_MakeEdge mkEdge( start, 
end );
 
 1529            if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
 
 1531                aReporter->
Report( wxString::Format( 
_( 
"Failed to make segment edge (%d %d) -> (%d %d), " 
 1539                aMkWire.Add( mkEdge.Edge() );
 
 1541                if( aMkWire.Error() != BRepLib_WireDone )
 
 1543                    aReporter->
Report( wxString::Format( 
_( 
"Failed to add segment edge (%d %d) -> (%d %d)" ),
 
 1557            Handle( Geom_Curve ) curve;
 
 1559            if( aArc.GetCentralAngle() == 
ANGLE_360 )
 
 1561                gp_Ax2 axis = gp::XOY();
 
 1562                axis.SetLocation( toPoint( aArc.GetCenter() ) );
 
 1564                curve = GC_MakeCircle( axis, 
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
 
 1568                curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
 
 1569                                            toPoint( aArc.GetP1() ) ).Value();
 
 1572            if( curve.IsNull() )
 
 1575            aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
 
 1577            if( !aMkWire.IsDone() )
 
 1579                aReporter->
Report( wxString::Format( 
_( 
"Failed to add arc curve from (%d %d), arc p0 " 
 1580                                                        "(%d %d), mid (%d %d), p1 (%d %d)" ),
 
 1582                                                     aArc.GetP0().x, aArc.GetP0().y,
 
 1583                                                     aArc.GetArcMid().x, aArc.GetArcMid().y,
 
 1584                                                     aArc.GetP1().x, aArc.GetP1().y ),
 
 1594        bool     isFirstShape = 
true;
 
 1607                    if( nextShape != -1 )
 
 1613                lastPt = aChain.
CPoint( i );
 
 1623                    firstPt = currentArc.
GetP0();
 
 1628                    lastPt = currentArc.
GetP0();
 
 1630                if( addArc( lastPt, currentArc ) )
 
 1631                    lastPt = currentArc.
GetP1();
 
 1650            isFirstShape = 
false;
 
 1653        if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
 
 1655            aReporter->
Report( wxString::Format( 
_( 
"Failed to close wire at %d, %d -> %d, %d **" ),
 
 1657                                                 firstPt.
x, firstPt.
y ),
 
 1663    catch( 
const Standard_Failure& e )
 
 1665        aReporter->
Report( wxString::Format( 
_( 
"OCC exception creating wire: %s" ),
 
 1666                                             e.GetMessageString() ),
 
 
 1676                                 bool aConvertToArcs, 
double aThickness, 
double aZposition,
 
 1684    if( aConvertToArcs )
 
 1688        for( 
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
 
 1692            for( 
size_t contId = 0; contId < polygon.size(); contId++ )
 
 1696        fallbackPoly = workingPoly;
 
 1697        workingPoly = approximated;
 
 1716    auto toPoint = [&]( 
const VECTOR2D& aKiCoords ) -> gp_Pnt
 
 1718        return gp_Pnt( 
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
 
 1719                       -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
 
 1723    gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
 
 1724                      std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
 
 1726    for( 
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
 
 1730        auto tryMakeWire = [
this, &aZposition,
 
 1731                            &aOrigin]( 
const SHAPE_LINE_CHAIN& aContour, 
bool aAllowRetry ) -> TopoDS_Wire
 
 1734            BRepLib_MakeWire mkWire;
 
 1738            if( mkWire.IsDone() )
 
 1740                wire = mkWire.Wire();
 
 1745                        wxString::Format( 
_( 
"Wire not done (contour points %d): OCC error %d\n" 
 1746                                             "z: %g; bounding box: %s" ),
 
 1747                                          static_cast<int>( aContour.PointCount() ),
 
 1748                                          static_cast<int>( mkWire.Error() ),
 
 1753            if( !wire.IsNull() )
 
 1755                BRepAlgoAPI_Check check( wire, 
false, 
true );
 
 1757                if( !check.IsValid() )
 
 1759                    m_reporter->Report( wxString::Format( 
_( 
"Wire self-interference check failed\n" 
 1760                                                             "z: %g; bounding box: %s" ),
 
 1772        BRepBuilderAPI_MakeFace mkFace;
 
 1774        for( 
size_t contId = 0; contId < polygon.size(); contId++ )
 
 1780                bool allow_retry = aConvertToArcs ? true : 
false;
 
 1782                TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
 
 1784                if( aConvertToArcs && wire.IsNull() )
 
 1786                    m_reporter->Report( wxString::Format( 
_( 
"Using non-simplified polygon." ) ),
 
 1790                    allow_retry = 
false;
 
 1791                    wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
 
 1796                    if( !wire.IsNull() )
 
 1798                        if( basePlane.Axis().Direction().Z() < 0 )
 
 1801                        mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
 
 1805                        m_reporter->Report( wxString::Format( wxT( 
"** Outline skipped **\n" 
 1806                                                                   "z: %g; bounding box: %s" ),
 
 1815                    if( !wire.IsNull() )
 
 1817                        if( basePlane.Axis().Direction().Z() > 0 )
 
 1824                        m_reporter->Report( wxString::Format( wxT( 
"** Hole skipped **\n" 
 1825                                                                   "z: %g; bounding box: %s" ),
 
 1832            catch( 
const Standard_Failure& e )
 
 1834                m_reporter->Report( wxString::Format( 
_( 
"OCC exception creating contour %d: %s" ),
 
 1835                                                      static_cast<int>( contId ),
 
 1836                                                      e.GetMessageString() ),
 
 1842        if( mkFace.IsDone() )
 
 1844            TopoDS_Shape faceShape = mkFace.Shape();
 
 1846            if( aThickness != 0.0 )
 
 1848                TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
 
 1849                aShapes.push_back( prism );
 
 1851                if( prism.IsNull() )
 
 1859                aShapes.push_back( faceShape );
 
 
 1875    { 
_HKI( 
"Green" ), wxColor( 20, 51, 36 ) },          
 
 1876    { 
_HKI( 
"Red" ), wxColor( 181, 19, 21 ) },           
 
 1877    { 
_HKI( 
"Blue" ), wxColor( 2, 59, 162 ) },           
 
 1878    { 
_HKI( 
"Purple" ), wxColor( 32, 2, 53 ) },          
 
 1879    { 
_HKI( 
"Black" ), wxColor( 11, 11, 11 ) },          
 
 1880    { 
_HKI( 
"White" ), wxColor( 245, 245, 245 ) },       
 
 1881    { 
_HKI( 
"Yellow" ), wxColor( 194, 195, 0 ) },        
 
 1882    { 
_HKI( 
"User defined" ), wxColor( 128, 128, 128 ) } 
 
 
 1892    if( aColorStr.StartsWith( wxT( 
"#" ) ) ) 
 
 1894        aColorOut = 
COLOR4D( aColorStr );
 
 1899        const std::vector<FAB_LAYER_COLOR>& colors =
 
 1906            if( fabColor.GetName() == aColorStr )
 
 1908                aColorOut = fabColor.GetColor( aType );
 
 
 1930    Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
 
 1935    m_reporter->Report( wxString::Format( wxT( 
"Build board outlines (%d outlines) with %d points." ),
 
 1940    double boardThickness;
 
 1960        for( 
size_t contId = 0; contId < polygon.size(); contId++ )
 
 1964            polyset.
Append( contour );
 
 1971                    m_reporter->Report( 
_( 
"OCC error creating main outline." ),
 
 1980                    m_reporter->Report( 
_( 
"OCC error creating hole in main outline." ),
 
 1992        BRepBndLib::Add( brdShape, brdBndBox );
 
 1995    m_reporter->Report( wxString::Format( wxT( 
"Build board cutouts and holes (%d hole(s))." ),
 
 2000            [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
 
 2004                Bnd_Box brdWithHolesBndBox = brdBndBox;
 
 2006                Handle( Bnd_HArray1OfBox ) holeBoxSet = 
new Bnd_HArray1OfBox( 0, input.size() - 1 );
 
 2008                for( 
size_t i = 0; i < input.size(); i++ )
 
 2011                    BRepBndLib::Add( input[i], bbox );
 
 2012                    brdWithHolesBndBox.Add( bbox );
 
 2013                    ( *holeBoxSet )[i] = bbox;
 
 2016                bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
 
 2019    auto subtractShapesMap =
 
 2020            [&
tp, 
this]( 
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
 
 2021                         std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
 
 2023                m_reporter->Report( wxString::Format( 
_( 
"Subtracting holes for %s" ), aWhat ),
 
 2026                for( 
auto& [netname, vec] : aShapesMap )
 
 2030                    auto subtractLoopFn = [&]( 
const int shapeId )
 
 2032                        TopoDS_Shape& shape = vec[shapeId];
 
 2035                        BRepBndLib::Add( shape, shapeBbox );
 
 2037                        TopTools_ListOfShape holelist;
 
 2040                            std::unique_lock lock( mutex );
 
 2042                            const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
 
 2044                            for( 
const Standard_Integer& index : indices )
 
 2045                                holelist.Append( aHolesList[index] );
 
 2048                        if( holelist.IsEmpty() )
 
 2051                        TopTools_ListOfShape cutArgs;
 
 2052                        cutArgs.Append( shape );
 
 2054                        BRepAlgoAPI_Cut 
cut;
 
 2056                        cut.SetRunParallel( 
true );
 
 2057                        cut.SetToFillHistory( 
false );
 
 2059                        cut.SetArguments( cutArgs );
 
 2060                        cut.SetTools( holelist );
 
 2063                        if( 
cut.HasErrors() || 
cut.HasWarnings() )
 
 2065                            m_reporter->Report( wxString::Format( 
_( 
"** Got problems while cutting " 
 2072                            if( 
cut.HasErrors() )
 
 2074                                wxString             msg = 
_( 
"Errors:\n" );
 
 2075                                wxStringOutputStream os_stream( &msg );
 
 2076                                wxStdOutputStream    out( os_stream );
 
 2078                                cut.DumpErrors( out );
 
 2082                            if( 
cut.HasWarnings() )
 
 2084                                wxString             msg = 
_( 
"Warnings:\n" );
 
 2085                                wxStringOutputStream os_stream( &msg );
 
 2086                                wxStdOutputStream    out( os_stream );
 
 2088                                cut.DumpWarnings( out );
 
 2093                        shape = 
cut.Shape();
 
 2096                    tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
 
 2100    auto subtractShapes =
 
 2101            [subtractShapesMap]( 
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
 
 2102                                 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
 
 2104                std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
 
 2106                subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
 
 2107                aShapesList = aShapesMap[wxEmptyString];
 
 2113        Bnd_BoundSortBox bsbHoles;
 
 2121        Bnd_BoundSortBox bsbHoles;
 
 2130        std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
 
 2132        auto addShapes = [&shapesToFuseMap]( 
const wxString&                  aNetname,
 
 2133                                             const std::vector<TopoDS_Shape>& aShapes )
 
 2135            for( 
const TopoDS_Shape& shape : aShapes )
 
 2136                shapesToFuseMap[aNetname].Append( shape );
 
 2140            addShapes( netname, shapes );
 
 2143            addShapes( netname, shapes );
 
 2146            addShapes( netname, shapes );
 
 2153        auto fuseLoopFn = [&]( 
const wxString& aNetname )
 
 2155            auto&        toFuse = shapesToFuseMap[aNetname];
 
 2158            if( !fusedShape.IsNull() )
 
 2160                std::unique_lock lock( mutex );
 
 2170        BS::multi_future<void> mf;
 
 2172        for( 
const auto& [netname, 
_] : shapesToFuseMap )
 
 2173            mf.push_back( 
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
 
 2190    auto pushToAssemblyMap =
 
 2191            [&]( 
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
 
 2192                 const TDF_Label& aVisMatLabel, 
const wxString& aShapeName, 
bool aCompoundNets,
 
 2193                 bool aCompoundAll, 
const wxString& aNiceName )
 
 2195                std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
 
 2199                    std::vector<TopoDS_Shape> allShapes;
 
 2201                    for( 
const auto& [netname, shapesList] : aShapesMap )
 
 2202                        allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
 
 2204                    if( !allShapes.empty() )
 
 2205                        shapesMap[wxEmptyString].emplace_back( 
makeCompound( allShapes ) );
 
 2209                    shapesMap = aShapesMap;
 
 2212                for( 
const auto& [netname, shapesList] : shapesMap )
 
 2214                    std::vector<TopoDS_Shape> newList;
 
 2219                        newList = shapesList;
 
 2223                    for( TopoDS_Shape& shape : newList )
 
 2225                        Handle( TDataStd_TreeNode ) node;
 
 2228                        TDF_Label lbl = m_assy->AddComponent( 
m_assy_label, shape, 
false );
 
 2235                        lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
 
 2236                        TDF_Label shpLbl = node->Father()->Label();
 
 2238                        if( !shpLbl.IsNull() )
 
 2240                            if( visMatTool && !aVisMatLabel.IsNull() )
 
 2241                                visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
 
 2247                            shapeName << aShapeName;
 
 2249                            if( !netname.empty() )
 
 2252                                shapeName << netname;
 
 2255                            if( newList.size() > 1 )
 
 2261                            TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
 
 2262                            TDataStd_Name::Set( shpLbl, partname );
 
 2270    auto pushToAssembly =
 
 2271            [&]( 
const std::vector<TopoDS_Shape>& aShapesList, 
const TDF_Label& aVisMatLabel,
 
 2272                 const wxString& aShapeName, 
bool aCompound, 
const wxString& aNiceName )
 
 2274                const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
 
 2276                pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
 
 2280            [&]( 
const TCollection_AsciiString& aName, 
const Quantity_ColorRGBA& aBaseColor,
 
 2281                 double aMetallic, 
double aRoughness ) -> TDF_Label
 
 2283                Handle( XCAFDoc_VisMaterial ) vismat = 
new XCAFDoc_VisMaterial;
 
 2284                XCAFDoc_VisMaterialPBR pbr;
 
 2285                pbr.BaseColor = aBaseColor;
 
 2286                pbr.Metallic = aMetallic;
 
 2287                pbr.Roughness = aRoughness;
 
 2288                vismat->SetPbrMaterial( pbr );
 
 2289                return visMatTool->AddMaterial( vismat, aName );
 
 2296    Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
 
 2297    Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
 
 2298    Quantity_ColorRGBA back_silk_color = front_silk_color;
 
 2299    Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
 
 2300    Quantity_ColorRGBA back_mask_color = front_mask_color;
 
 2310        if( item->GetBrdLayerId() == 
F_Mask || item->GetBrdLayerId() == 
B_Mask )
 
 2314            if( item->GetBrdLayerId() == 
F_Mask )
 
 2315                front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
 
 2317                back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
 
 2320        if( item->GetBrdLayerId() == 
F_SilkS )
 
 2321            front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
 
 2322        else if( item->GetBrdLayerId() == 
B_SilkS )
 
 2323            back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
 
 2326            board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
 
 2332        board_color = front_mask_color;
 
 2333        board_color.SetAlpha( 1.0 );
 
 2336    TDF_Label front_mask_mat = makeMaterial( 
"soldermask", front_mask_color, 0.0, 0.6 );
 
 2337    TDF_Label back_mask_mat = makeMaterial( 
"soldermask", back_mask_color, 0.0, 0.6 );
 
 2338    TDF_Label front_silk_mat = makeMaterial( 
"silkscreen", front_silk_color, 0.0, 0.9 );
 
 2339    TDF_Label back_silk_mat = makeMaterial( 
"silkscreen", back_silk_color, 0.0, 0.9 );
 
 2340    TDF_Label copper_mat = makeMaterial( 
"copper", copper_color, 1.0, 0.4 );
 
 2341    TDF_Label pad_mat = makeMaterial( 
"pad", pad_color, 1.0, 0.4 );
 
 2342    TDF_Label board_mat = makeMaterial( 
"board", board_color, 0.0, 0.8 );
 
 2344    pushToAssemblyMap( 
m_board_copper, copper_mat, 
"copper", 
true, 
true, 
"Copper" );
 
 2348    pushToAssembly( 
m_board_front_silk, front_silk_mat, 
"silkscreen", 
true, 
"Top Silkscreen" );
 
 2349    pushToAssembly( 
m_board_back_silk, back_silk_mat, 
"silkscreen", 
true, 
"Bottom Silkscreen" );
 
 2350    pushToAssembly( 
m_board_front_mask, front_mask_mat, 
"soldermask", 
true, 
"Top Soldermask" );
 
 2351    pushToAssembly( 
m_board_back_mask, back_mask_mat, 
"soldermask", 
true, 
"Bottom Soldermask" );
 
 2353    if( aPushBoardBody )
 
 2356#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 ) 
 2357    m_assy->UpdateAssemblies();
 
 
 2366bool STEP_PCB_MODEL::WriteIGES( 
const wxString& aFileName )
 
 2370        m_reporter->
Report( wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'." ),
 
 2378    wxFileName fn( aFileName );
 
 2379    IGESControl_Controller::Init();
 
 2380    IGESCAFControl_Writer writer;
 
 2381    writer.SetColorMode( Standard_True );
 
 2382    writer.SetNameMode( Standard_True );
 
 2383    IGESData_GlobalSection header = writer.Model()->GlobalSection();
 
 2384    header.SetFileName( 
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
 
 2385    header.SetSendName( 
new TCollection_HAsciiString( 
"KiCad electronic assembly" ) );
 
 2386    header.SetAuthorName( 
new TCollection_HAsciiString( Interface_Static::CVal( 
"write.iges.header.author" ) ) );
 
 2387    header.SetCompanyName( 
new TCollection_HAsciiString( Interface_Static::CVal( 
"write.iges.header.company" ) ) );
 
 2388    writer.Model()->SetGlobalSection( header );
 
 2390    if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
 
 2399    wxFileInputStream  input( inputFile );
 
 2400    wxFileOutputStream output( outputFile );
 
 2404        m_reporter->Report( wxString::Format( 
_( 
"Cannot create input stream '%s'.\n" ), inputFile ) );
 
 2408    if( !output.IsOk() )
 
 2410        m_reporter->Report( wxString::Format( 
_( 
"Cannot create output stream '%s'.\n" ), outputFile ) );
 
 2414    wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
 
 2416    if( !zlibStream.IsOk() )
 
 2418        m_reporter->Report( 
_( 
"Impossible create compress stream" ) );
 
 2422    input.Read( zlibStream );
 
 2424    if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
 
 2426        m_reporter->Report( 
_( 
"Compress read or write error" ) );
 
 
 2440        m_reporter->Report( wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'." ),
 
 2448    wxFileName fn( aFileName );
 
 2450    STEPCAFControl_Writer writer;
 
 2451    writer.SetColorMode( Standard_True );
 
 2452    writer.SetNameMode( Standard_True );
 
 2459    if( !Interface_Static::SetCVal( 
"write.step.product.name", fn.GetName().ToAscii() ) )
 
 2461        m_reporter->Report( 
_( 
"Failed to set STEP product name, but will attempt to continue." ),
 
 2467    if( !Interface_Static::SetIVal( 
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
 
 2469        m_reporter->Report( 
_( 
"Failed to set surface curve mode, but will attempt to continue." ),
 
 2473    if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
 
 2476    APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
 
 2480    hdr.SetName( 
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
 
 2483    hdr.SetAuthorValue( 1, 
new TCollection_HAsciiString( 
"Pcbnew" ) );
 
 2484    hdr.SetOrganizationValue( 1, 
new TCollection_HAsciiString( 
"Kicad" ) );
 
 2485    hdr.SetOriginatingSystem( 
new TCollection_HAsciiString( 
"KiCad to STEP converter" ) );
 
 2486    hdr.SetDescriptionValue( 1, 
new TCollection_HAsciiString( 
"KiCad electronic assembly" ) );
 
 2488    bool success = 
true;
 
 2491    wxString currCWD = wxGetCwd();
 
 2492    wxString workCWD = fn.GetPath();
 
 2494    if( !workCWD.IsEmpty() )
 
 2495        wxSetWorkingDirectory( workCWD );
 
 2497    wxString tmpfname( 
"$tempfile$.step" );
 
 2499    if( Standard_False == writer.Write( tmpfname.c_str() ) )
 
 2502    if( compress && success )
 
 2504        wxString srcTmp( tmpfname );
 
 2505        wxString dstTmp( 
"$tempfile$.stpz" );
 
 2508        wxRemoveFile( srcTmp );
 
 2519        if( !wxRenameFile( tmpfname, fn.GetFullName(), 
true ) )
 
 2521            m_reporter->Report( wxString::Format( 
_( 
"Cannot rename temporary file '%s' to '%s'." ),
 
 2529    wxSetWorkingDirectory( currCWD );
 
 
 2539        m_reporter->Report( wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'." ),
 
 2548    Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
 
 2553    wxFileName fn( aFileName );
 
 2555    wxFFileOutputStream ffStream( fn.GetFullPath() );
 
 2556    wxStdOutputStream   stdStream( ffStream );
 
 2558#if OCC_VERSION_HEX >= 0x070600 
 2559    BRepTools::Write( shape, stdStream, 
false, 
false, TopTools_FormatVersion_VERSION_1 );
 
 2561    BRepTools::Write( shape, stdStream );
 
 
 2570    wxFileName fn( aFileName );
 
 2572    wxFFileOutputStream ffStream( fn.GetFullPath() );
 
 2573    wxStdOutputStream   file( ffStream );
 
 2575    if( !ffStream.IsOk() )
 
 2577        m_reporter->Report( wxString::Format( 
"Could not open file '%s'", fn.GetFullPath() ),
 
 2585    Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
 
 2590    std::map<wxString, std::vector<int>> groups[4];
 
 2591    std::map<wxString, double>           groupAreas;
 
 2592    TopExp_Explorer                      exp;
 
 2595    for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
 
 2597        TopoDS_Shape subShape = exp.Current();
 
 2600        BRepBndLib::Add( subShape, bbox );
 
 2604            for( 
const auto& pair : pairs )
 
 2606                const auto& [point, padTestShape] = pair;
 
 2608                if( bbox.IsOut( point ) )
 
 2611                BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
 
 2613                if( surface.GetType() != GeomAbs_Plane )
 
 2616                BRepExtrema_DistShapeShape dist( padTestShape, subShape );
 
 2619                if( !dist.IsDone() )
 
 2622                if( dist.Value() < Precision::Approximation() )
 
 2625                    groups[2][padKey].push_back( faceIndex );
 
 2627                    GProp_GProps system;
 
 2628                    BRepGProp::SurfaceProperties( subShape, system );
 
 2630                    double surfaceArea = system.Mass() / 1e6; 
 
 2631                    groupAreas[padKey] += surfaceArea;
 
 2640    file << 
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
 
 2641    file << 
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
 
 2642    file << 
"  <geometry name=\"" << fn.GetName() << 
"\">" << std::endl;
 
 2643    file << 
"    <shape format=\"BREP\"><![CDATA[";
 
 2644#if OCC_VERSION_HEX < 0x070600 
 2645    BRepTools::Write( shape, file );
 
 2647    BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
 
 2649    file << 
"]]></shape>" << std::endl;
 
 2650    file << 
"    <topology>" << std::endl;
 
 2652    TopTools_IndexedMapOfShape mainMap;
 
 2653    TopExp::MapShapes( shape, mainMap );
 
 2654    std::set<int> topo[4];
 
 2656    static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
 
 2659    static const std::string c_dimLabel[] = { 
"vertex", 
"edge", 
"face", 
"solid" };
 
 2660    static const std::string c_dimLabels[] = { 
"vertices", 
"edges", 
"faces", 
"solids" };
 
 2662    for( 
int dim = 0; dim < 4; dim++ )
 
 2664        for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
 
 2666            TopoDS_Shape subShape = exp.Current();
 
 2667            int          idx = mainMap.FindIndex( subShape );
 
 2669            if( idx && !topo[dim].count( idx ) )
 
 2670                topo[dim].insert( idx );
 
 2674    for( 
int dim = 0; dim <= 3; dim++ )
 
 2676        std::string labels = c_dimLabels[dim];
 
 2677        std::string label = c_dimLabel[dim];
 
 2679        file << 
"      <" << labels << 
" count=\"" << topo[dim].size() << 
"\">" << std::endl;
 
 2682        for( 
auto p : topo[dim] )
 
 2684            std::string 
name( 
"" );
 
 2685            file << 
"        <" << label << 
" index=\"" << index << 
"\" " 
 2686                 << 
"name=\"" << 
name << 
"\" " 
 2687                 << 
"reference=\"" << p << 
"\"/>" << std::endl;
 
 2691        file << 
"      </" << labels << 
">" << std::endl;
 
 2694    file << 
"    </topology>" << std::endl;
 
 2695    file << 
"  </geometry>" << std::endl;
 
 2696    file << 
"  <groups count=\"" 
 2697         << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() << 
"\">" 
 2700    int groupNumber = 1;
 
 2705    for( 
int dim = 0; dim <= 3; dim++ )
 
 2707        std::string label = c_dimLabel[dim];
 
 2709        for( 
auto g : groups[dim] )
 
 2712            wxString 
name = g.first;
 
 2716                std::ostringstream gs;
 
 2717                gs << 
"G_" << dim << 
"D_" << g.first;
 
 2720            file << 
"    <group name=\"" << 
name << 
"\" dimension=\"" << label;
 
 2726            file << 
"\" count=\"" << g.second.size() << 
"\">" << std::endl;
 
 2728            for( 
auto index : g.second )
 
 2729                file << 
"      <element index=\"" << index << 
"\"/>" << std::endl;
 
 2731            file << 
"    </group>" << std::endl;
 
 2733            m_reporter->Report( wxString::Format( 
"%d\t%s\t%g",
 
 2745    file << 
"  </groups>" << std::endl;
 
 2746    file << 
"  <fields count=\"0\"/>" << std::endl;
 
 2747    file << 
"</XAO>" << std::endl;
 
 
 2754                                    bool aSubstituteModels, wxString* aErrorMessage )
 
 2756    std::string model_key = aFileNameUTF8 + 
"_" + std::to_string( aScale.
x )
 
 2757                            + 
"_" + std::to_string( aScale.
y ) + 
"_" + std::to_string( aScale.
z );
 
 2759    MODEL_MAP::const_iterator mm = 
m_models.find( model_key );
 
 2763        aLabel = mm->second;
 
 2769    Handle( TDocStd_Document )  doc;
 
 2770    m_app->NewDocument( 
"MDTV-XCAF", doc );
 
 2772    wxString            fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
 
 2775    wxFileName                 modelFile( fileName );
 
 2776    std::string                pname( modelFile.GetName().ToUTF8() );
 
 2777    TCollection_ExtendedString partname( pname.c_str() );
 
 2782        if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
 
 2784            m_reporter->Report( wxString::Format( wxT( 
"readIGES() failed on filename '%s'." ),
 
 2792        if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
 
 2794            m_reporter->Report( wxString::Format( wxT( 
"readSTEP() failed on filename '%s'." ),
 
 2805        wxFFileInputStream ifile( fileName );
 
 2806        wxFileName         outFile( fileName );
 
 2808        outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
 
 2809        outFile.SetExt( wxT( 
"step" ) );
 
 2810        wxFileOffset size = ifile.GetLength();
 
 2812        if( size == wxInvalidOffset )
 
 2814            m_reporter->Report( wxString::Format( wxT( 
"getModelLabel() failed on filename '%s'." ),
 
 2821            bool                success = 
false;
 
 2822            wxFFileOutputStream ofile( outFile.GetFullPath() );
 
 2827            char* buffer = 
new char[size];
 
 2829            ifile.Read( buffer, size );
 
 2830            std::string expanded;
 
 2834                expanded = gzip::decompress( buffer, size );
 
 2839                m_reporter->Report( wxString::Format( wxT( 
"failed to decompress '%s'." ),
 
 2844            if( expanded.empty() )
 
 2848                wxZipInputStream            izipfile( ifile );
 
 2849                std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
 
 2851                if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
 
 2853                    izipfile.Read( ofile );
 
 2859                ofile.Write( expanded.data(), expanded.size() );
 
 2867                std::string altFileNameUTF8 = 
TO_UTF8( outFile.GetFullPath() );
 
 2887        if( aSubstituteModels )
 
 2889            wxFileName wrlName( fileName );
 
 2891            wxString basePath = wrlName.GetPath();
 
 2892            wxString baseName = wrlName.GetName();
 
 2900            alts.Add( wxT( 
"stp" ) );
 
 2901            alts.Add( wxT( 
"step" ) );
 
 2902            alts.Add( wxT( 
"STP" ) );
 
 2903            alts.Add( wxT( 
"STEP" ) );
 
 2904            alts.Add( wxT( 
"Stp" ) );
 
 2905            alts.Add( wxT( 
"Step" ) );
 
 2906            alts.Add( wxT( 
"stpz" ) );
 
 2907            alts.Add( wxT( 
"stpZ" ) );
 
 2908            alts.Add( wxT( 
"STPZ" ) );
 
 2909            alts.Add( wxT( 
"step.gz" ) );
 
 2910            alts.Add( wxT( 
"stp.gz" ) );
 
 2913            alts.Add( wxT( 
"iges" ) );
 
 2914            alts.Add( wxT( 
"IGES" ) );
 
 2915            alts.Add( wxT( 
"igs" ) );
 
 2916            alts.Add( wxT( 
"IGS" ) );
 
 2920            for( 
const auto& alt : alts )
 
 2922                wxFileName altFile( basePath, baseName + wxT( 
"." ) + alt );
 
 2924                if( altFile.IsOk() && altFile.FileExists() )
 
 2926                    std::string altFileNameUTF8 = 
TO_UTF8( altFile.GetFullPath() );
 
 2949            if( 
readVRML( doc, aFileNameUTF8.c_str() ) )
 
 2951                Handle( XCAFDoc_ShapeTool ) shapeTool = XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
 
 2957                m_reporter->Report( wxString::Format( wxT( 
"readVRML() failed on filename '%s'." ), fileName ),
 
 2965                aErrorMessage->Printf( 
_( 
"Cannot use VRML models when exporting to non-mesh formats." ) );
 
 2975        m_reporter->Report( wxString::Format( 
_( 
"Cannot identify actual file type for '%s'." ),
 
 2983    if( aLabel.IsNull() )
 
 2985        m_reporter->Report( wxString::Format( 
_( 
"Could not transfer model data from file '%s'." ),
 
 2993    TDataStd_Name::Set( aLabel, partname );
 
 
 3003                                       TopLoc_Location& aLocation )
 
 3017    lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
 
 3023    double boardThickness;
 
 3026    double top = std::max( boardZPos, boardZPos + boardThickness );
 
 3027    double bottom = std::min( boardZPos, boardZPos + boardThickness );
 
 3032    double f_pos, f_thickness;
 
 3036    bottom += f_thickness;      
 
 3043        lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
 
 3044        lPos.Multiply( lRot );
 
 3045        lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), 
M_PI );
 
 3046        lPos.Multiply( lRot );
 
 3051        lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
 
 3052        lPos.Multiply( lRot );
 
 3056    lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
 
 3057    lPos.Multiply( lOff );
 
 3060    lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
 
 3061    lPos.Multiply( lOrient );
 
 3062    lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
 
 3063    lPos.Multiply( lOrient );
 
 3064    lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
 
 3065    lPos.Multiply( lOrient );
 
 3067    aLocation = TopLoc_Location( lPos );
 
 
 3074    IGESControl_Controller::Init();
 
 3075    IGESCAFControl_Reader reader;
 
 3076    IFSelect_ReturnStatus stat  = reader.ReadFile( fname );
 
 3078    if( stat != IFSelect_RetDone )
 
 3082    if( !Interface_Static::SetIVal( 
"read.precision.mode", 1 ) )
 
 3086    if( !Interface_Static::SetRVal( 
"read.precision.val", 
USER_PREC ) )
 
 3090    reader.SetColorMode( 
true );  
 
 3091    reader.SetNameMode( 
false );  
 
 3092    reader.SetLayerMode( 
false ); 
 
 3094    if( !reader.Transfer( doc ) )
 
 3096        if( doc->CanClose() == CDM_CCS_OK )
 
 3103    if( reader.NbShapes() < 1 )
 
 3105        if( doc->CanClose() == CDM_CCS_OK )
 
 
 3117    STEPCAFControl_Reader reader;
 
 3118    IFSelect_ReturnStatus stat  = reader.ReadFile( fname );
 
 3120    if( stat != IFSelect_RetDone )
 
 3124    if( !Interface_Static::SetIVal( 
"read.precision.mode", 1 ) )
 
 3128    if( !Interface_Static::SetRVal( 
"read.precision.val", 
USER_PREC ) )
 
 3132    reader.SetColorMode( 
true );  
 
 3133    reader.SetNameMode( 
true );  
 
 3134    reader.SetLayerMode( 
false ); 
 
 3136    if( !reader.Transfer( doc ) )
 
 3138        if( doc->CanClose() == CDM_CCS_OK )
 
 3145    if( reader.NbRootsForTransfer() < 1 )
 
 3147        if( doc->CanClose() == CDM_CCS_OK )
 
 
 3159#if OCC_VERSION_HEX >= 0x070700 
 3160    VrmlAPI_CafReader                reader;
 
 3161    RWMesh_CoordinateSystemConverter conv;
 
 3162    conv.SetInputLengthUnit( 2.54 );
 
 3163    reader.SetCoordinateSystemConverter( conv );
 
 3164    reader.SetDocument( doc );
 
 3166    if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
 
 
 3181    Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
 
 3184    TDF_LabelSequence frshapes;
 
 3185    s_assy->GetFreeShapes( frshapes );
 
 3188    Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
 
 3191    TDF_Label d_targetLabel = d_assy->NewShape();
 
 3193    if( frshapes.Size() == 1 )
 
 3195        TDocStd_XLinkTool link;
 
 3196        link.Copy( d_targetLabel, frshapes.First() );
 
 3201        for( TDF_Label& s_shapeLabel : frshapes )
 
 3203            TDF_Label d_component = d_assy->NewShape();
 
 3205            TDocStd_XLinkTool link;
 
 3206            link.Copy( d_component, s_shapeLabel );
 
 3208            d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
 
 3212    if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
 
 3215    return d_targetLabel;
 
 
 3221    TDF_LabelSequence freeShapes;
 
 3222    aShapeTool->GetFreeShapes( freeShapes );
 
 3228    for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
 
 3230        TDF_Label    label = freeShapes.Value( i );
 
 3232        aShapeTool->GetShape( label, shape );
 
 3237        const Standard_Real      linearDeflection = 0.14;
 
 3238        const Standard_Real      angularDeflection = 
DEG2RAD( 30.0 );
 
 3239        BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
 
 
 3261    wxFileName fn( aFileName );
 
 3263    const char* tmpGltfname = 
"$tempfile$.glb";
 
 3264    RWGltf_CafWriter cafWriter( tmpGltfname, 
true );
 
 3266    cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
 
 3267    cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
 
 3268    cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
 
 3269            RWMesh_CoordinateSystem_Zup );
 
 3270#if OCC_VERSION_HEX >= 0x070700 
 3271    cafWriter.SetParallel( 
true );
 
 3273    TColStd_IndexedDataMapOfStringString metadata;
 
 3275    metadata.Add( TCollection_AsciiString( 
"pcb_name" ),
 
 3276                  TCollection_ExtendedString( fn.GetName().wc_str() ) );
 
 3277    metadata.Add( TCollection_AsciiString( 
"source_pcb_file" ),
 
 3278                  TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
 
 3279    metadata.Add( TCollection_AsciiString( 
"generator" ),
 
 3280                  TCollection_AsciiString( wxString::Format( wxS( 
"KiCad %s" ), 
GetSemanticVersion() ).ToAscii() ) );
 
 3281    metadata.Add( TCollection_AsciiString( 
"generated_at" ),
 
 3284    bool success = 
true;
 
 3287    wxString currCWD = wxGetCwd();
 
 3288    wxString workCWD = fn.GetPath();
 
 3290    if( !workCWD.IsEmpty() )
 
 3291        wxSetWorkingDirectory( workCWD );
 
 3293    success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
 
 3300        if( !wxRenameFile( tmpGltfname, fn.GetFullName(), 
true ) )
 
 3302            m_reporter->Report( wxString::Format( 
_( 
"Cannot rename temporary file '%s' to '%s'." ),
 
 3310    wxSetWorkingDirectory( currCWD );
 
 
 3318#if OCC_VERSION_HEX < 0x070700 
 3325        m_reporter->Report( wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'." ),
 
 3335    wxFileName fn( aFileName );
 
 3337    const char*     tmpFname = 
"$tempfile$.ply";
 
 3338    RWPly_CafWriter cafWriter( tmpFname );
 
 3340    cafWriter.SetFaceId( 
true ); 
 
 3341    cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
 
 3342    cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
 
 3344    TColStd_IndexedDataMapOfStringString metadata;
 
 3346    metadata.Add( TCollection_AsciiString( 
"pcb_name" ),
 
 3347                  TCollection_ExtendedString( fn.GetName().wc_str() ) );
 
 3348    metadata.Add( TCollection_AsciiString( 
"source_pcb_file" ),
 
 3349                  TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
 
 3350    metadata.Add( TCollection_AsciiString( 
"generator" ),
 
 3351                  TCollection_AsciiString( wxString::Format( wxS( 
"KiCad %s" ),
 
 3353    metadata.Add( TCollection_AsciiString( 
"generated_at" ),
 
 3356    bool success = 
true;
 
 3359    wxString currCWD = wxGetCwd();
 
 3360    wxString workCWD = fn.GetPath();
 
 3362    if( !workCWD.IsEmpty() )
 
 3363        wxSetWorkingDirectory( workCWD );
 
 3365    success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
 
 3372        if( !wxRenameFile( tmpFname, fn.GetFullName(), 
true ) )
 
 3374            m_reporter->Report( wxString::Format( 
_( 
"Cannot rename temporary file '%s' to '%s'." ),
 
 3382    wxSetWorkingDirectory( currCWD );
 
 
 3393        m_reporter->Report( wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'." ),
 
 3403    wxFileName fn( aFileName );
 
 3405    const char* tmpFname = 
"$tempfile$.stl";
 
 3408    wxString currCWD = wxGetCwd();
 
 3409    wxString workCWD = fn.GetPath();
 
 3411    if( !workCWD.IsEmpty() )
 
 3412        wxSetWorkingDirectory( workCWD );
 
 3414    bool success = StlAPI_Writer().Write( 
getOneShape( m_assy ), tmpFname );
 
 3421        if( !wxRenameFile( tmpFname, fn.GetFullName(), 
true ) )
 
 3423            m_reporter->Report( wxString::Format( 
_( 
"Cannot rename temporary file '%s' to '%s'." ),
 
 3431    wxSetWorkingDirectory( currCWD );
 
 
 3443                wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
 
 3452    wxFileName fn( aFileName );
 
 3454    const char* tmpFname = 
"$tempfile$.u3d";
 
 3457    wxString currCWD = wxGetCwd();
 
 3458    wxString workCWD = fn.GetPath();
 
 3460    if( !workCWD.IsEmpty() )
 
 3461        wxSetWorkingDirectory( workCWD );
 
 3464    bool success = writer.
Perform( m_doc );
 
 3470        if( !wxRenameFile( tmpFname, fn.GetFullName(), 
true ) )
 
 3472            m_reporter->Report( wxString::Format( wxT( 
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
 
 3479    wxSetWorkingDirectory( currCWD );
 
 
 3490                wxString::Format( 
_( 
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
 
 3499    wxFileName fn( aFileName );
 
 3501    wxFileName  u3dTmpfn = wxFileName::CreateTempFileName( 
"" );
 
 3502    wxFileName  pdfTmpfn = wxFileName::CreateTempFileName( 
"" );
 
 3504    U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
 
 3505    bool        success = writer.
Perform( m_doc );
 
 3508    std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
 
 3510    plotter->SetColorMode( 
true );
 
 3511    plotter->Set3DExport( 
true );
 
 3512    plotter->SetCreator( wxT( 
"Mark's awesome 3d exporter" ) );
 
 3514    plotter->SetRenderSettings( &renderSettings );
 
 3516    if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
 
 3518        m_reporter->Report( wxString::Format( wxT( 
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
 
 3524        plotter->StartPlot( 
"1", 
"3D Model" );
 
 3525        double fov_degrees = 16.5f;
 
 3530        std::vector<PDF_3D_VIEW> views;
 
 3535        std::vector<float> c2wMatrix =
 
 3539                .m_name = 
"Default",
 
 3540                .m_cameraMatrix = c2wMatrix,
 
 3541                .m_cameraCenter = (float) 
distance,
 
 3542                .m_fov = (
float) fov_degrees,
 
 3551                .m_cameraMatrix = c2wMatrix,
 
 3552                .m_cameraCenter = (float) 
distance,
 
 3553                .m_fov = (
float) fov_degrees,
 
 3562                .m_cameraMatrix = c2wMatrix,
 
 3563                .m_cameraCenter = (float) 
distance,
 
 3564                .m_fov = (
float) fov_degrees,
 
 3573                .m_cameraMatrix = c2wMatrix,
 
 3574                .m_cameraCenter = (float) 
distance,
 
 3575                .m_fov = (
float) fov_degrees,
 
 3578        plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
 
 3587        if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(), 
true ) )
 
 3589            m_reporter->Report(  wxString::Format( wxT( 
"Cannot rename temporary file '%s' to '%s'.\n" ),
 
 3590                                             pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
 
 3596    wxRemoveFile( u3dTmpfn.GetFullPath() );
 
 
constexpr EDA_IU_SCALE pcbIUScale
 
bool IsPrmSpecified(const wxString &aPrmValue)
 
@ BS_ITEM_TYPE_SILKSCREEN
 
@ BS_ITEM_TYPE_DIELECTRIC
 
@ BS_ITEM_TYPE_SOLDERMASK
 
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
 
wxString GetNetname() const
 
const wxString & GetShortNetname() const
 
FOOTPRINT * GetParentFootprint() const
 
Manage one layer needed to make a physical board.
 
wxString GetTypeName() const
 
int GetSublayersCount() const
 
PCB_LAYER_ID GetBrdLayerId() const
 
int GetThickness(int aDielectricSubLayer=0) const
 
BOARD_STACKUP_ITEM_TYPE GetType() const
 
Manage layers needed to make a physical board.
 
constexpr coord_type GetLeft() const
 
constexpr coord_type GetRight() const
 
constexpr coord_type GetTop() const
 
constexpr coord_type GetBottom() const
 
A color representation with 4 components: red, green, blue, alpha.
 
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
 
PCB specific render settings.
 
LSET is a set of PCB_LAYER_IDs.
 
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
 
PAD_PROP GetProperty() const
 
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
 
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
 
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
 
const VECTOR2I & GetDrillSize() const
 
PAD_ATTRIB GetAttribute() const
 
const wxString & GetNumber() const
 
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
 
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
 
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
 
A pure virtual class used to derive REPORTER objects from.
 
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
 
const VECTOR2I & GetArcMid() const
 
const VECTOR2I & GetP1() const
 
const VECTOR2I & GetP0() const
 
const VECTOR2I & GetCenter() const
 
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
 
const SHAPE_ARC & Arc(size_t aArc) const
 
bool IsClosed() const override
 
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
 
int PointCount() const
Return the number of points (vertices) in this line chain.
 
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
 
void Clear()
Remove all points from the line chain.
 
const std::optional< INTERSECTION > SelfIntersectingWithArcs() const
Check if the line chain is self-intersecting.
 
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
 
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
 
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
 
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
 
virtual size_t GetSegmentCount() const override
 
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
 
bool IsArcSegment(size_t aSegment) const
 
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
 
bool IsArcStart(size_t aIndex) const
 
Represent a set of closed polygons.
 
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
 
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
 
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
 
int FullPointCount() const
Return the number of points in the shape poly set.
 
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
 
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
 
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
 
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
 
int OutlineCount() const
Return the number of outlines in the set.
 
const POLYGON & CPolygon(int aIndex) const
 
const std::vector< POLYGON > & CPolygons() const
 
const SEG & GetSeg() const
 
int GetWidth() const override
 
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
 
OUTPUT_FORMAT m_outFmt
The current output format for created file.
 
void SetCopperColor(double r, double g, double b)
 
bool isBoardOutlineValid()
 
bool WritePLY(const wxString &aFileName)
 
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_vias
 
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_pads
 
bool WriteSTEP(const wxString &aFileName, bool aOptimize, bool compress)
 
std::vector< TopoDS_Shape > m_board_back_mask
 
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
 
std::vector< TopoDS_Shape > m_boardCutouts
 
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
 
bool CreatePCB(SHAPE_POLY_SET &aOutline, const VECTOR2D &aOrigin, bool aPushBoardBody)
 
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
 
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, const VECTOR3D &aScale)
 
bool getModelLocation(bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, TopLoc_Location &aLocation)
 
void SetFuseShapes(bool aValue)
 
bool WriteXAO(const wxString &aFileName)
 
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
 
std::vector< TDF_Label > m_pcb_labels
 
STEP_PCB_MODEL(const wxString &aPcbName, REPORTER *aReporter)
 
void getLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
 
std::vector< TopoDS_Shape > m_board_outlines
 
void SetSimplifyShapes(bool aValue)
 
bool WriteU3D(const wxString &aFileName)
 
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
 
void SetPadColor(double r, double g, double b)
 
void SetEnabledLayers(const LSET &aLayers)
 
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
 
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
 
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
 
std::vector< TopoDS_Shape > m_board_front_silk
 
Handle(XCAFApp_Application) m_app
 
bool WritePDF(const wxString &aFileName)
 
virtual ~STEP_PCB_MODEL()
 
std::vector< TopoDS_Shape > m_board_front_mask
 
bool WriteSTL(const wxString &aFileName)
 
void SetStackup(const BOARD_STACKUP &aStackup)
 
void SetNetFilter(const wxString &aFilter)
 
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
 
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
 
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
 
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
 
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
 
bool getModelLabel(const std::string &aFileNameUTF8, const VECTOR3D &aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
 
std::vector< TopoDS_Shape > m_copperCutouts
 
bool CompressSTEP(wxString &inputFile, wxString &outputFile)
 
std::vector< TopoDS_Shape > m_board_back_silk
 
void getCopperLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
 
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
 
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
 
bool AddComponent(const std::string &aFileName, const std::string &aRefDes, bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, const VECTOR3D &aScale, bool aSubstituteModels=true)
 
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
 
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
 
bool WriteBREP(const wxString &aFileName)
 
bool Perform(const Handle(TDocStd_Document) &aDocument)
 
const VECTOR3D & GetCenter() const
 
const Bnd_Box & GetMeshBoundingBox() const
 
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
 
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
 
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
 
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
 
static constexpr EDA_ANGLE ANGLE_360
 
Handle(KICAD3D_INFO) KICAD3D_INFO
 
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
 
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
 
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
 
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
 
PCB_LAYER_ID
A quick note on layer IDs:
 
This file contains miscellaneous commonly used macros and functions.
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
@ PTH
Plated through hole pad.
 
@ CASTELLATED
a pad with a castellated through hole
 
Plotting engines similar to ps (PostScript, Gerber, svg)
 
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
 
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
 
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
 
wxString NotSpecifiedPrm()
 
static TopoDS_Shape fuseShapesOrCompound(const TopTools_ListOfShape &aInputShapes, REPORTER *aReporter)
 
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
 
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
 
static Standard_Boolean prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
 
static Standard_Boolean rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
 
static constexpr double BOARD_OFFSET
 
static wxString formatBBox(const BOX2I &aBBox)
 
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
 
static TopoDS_Compound makeCompound(const auto &aInputShapes)
 
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
 
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
 
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
 
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
 
static constexpr double USER_ANGLE_PREC
 
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
 
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
 
std::pair< std::string, TDF_Label > MODEL_DATUM
 
#define CLOSE_STREAM(var)
 
#define OPEN_ISTREAM(var, name)
 
wxString UnescapeString(const wxString &aSource)
 
wxString GetISO8601CurrentDateTime()
 
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
 
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
 
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
 
BS::thread_pool< 0 > thread_pool
 
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
 
double DEG2RAD(double deg)
 
VECTOR2< int32_t > VECTOR2I
 
VECTOR2< double > VECTOR2D
 
VECTOR3< double > VECTOR3D