31#include <wx/filename.h>
33#include <wx/stdpaths.h>
34#include <wx/wfstream.h>
35#include <wx/zipstrm.h>
37#include <decompress.hpp>
45#include <IGESCAFControl_Reader.hxx>
46#include <IGESCAFControl_Writer.hxx>
47#include <IGESControl_Controller.hxx>
48#include <IGESData_GlobalSection.hxx>
49#include <IGESData_IGESModel.hxx>
50#include <Interface_Static.hxx>
51#include <Quantity_Color.hxx>
52#include <STEPCAFControl_Reader.hxx>
53#include <STEPCAFControl_Writer.hxx>
54#include <APIHeaderSection_MakeHeader.hxx>
55#include <Standard_Version.hxx>
56#include <TCollection_ExtendedString.hxx>
57#include <TDataStd_Name.hxx>
58#include <TDataStd_TreeNode.hxx>
59#include <TDF_LabelSequence.hxx>
60#include <TDF_ChildIterator.hxx>
61#include <TopExp_Explorer.hxx>
63#include <XCAFDoc_DocumentTool.hxx>
64#include <XCAFDoc_ColorTool.hxx>
66#include <BRep_Tool.hxx>
67#include <BRepMesh_IncrementalMesh.hxx>
68#include <BRepBuilderAPI.hxx>
69#include <BRepBuilderAPI_MakeEdge.hxx>
70#include <BRepBuilderAPI_Transform.hxx>
71#include <BRepBuilderAPI_GTransform.hxx>
72#include <BRepBuilderAPI_MakeFace.hxx>
73#include <BRepPrimAPI_MakePrism.hxx>
74#include <BRepPrimAPI_MakeCylinder.hxx>
75#include <BRepAlgoAPI_Cut.hxx>
78#include <TopoDS_Wire.hxx>
79#include <TopoDS_Face.hxx>
80#include <TopoDS_Compound.hxx>
81#include <TopoDS_Builder.hxx>
83#include <Standard_Failure.hxx>
89#include <Geom_BezierCurve.hxx>
125 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
127 if( !lfile.FileExists() )
130 msg.Printf( wxT(
" * fileType(): no such file: %s\n" ),
131 wxString::FromUTF8Unchecked( aFileName ) );
137 wxString ext = lfile.GetExt().Lower();
139 if( ext == wxT(
"wrl" ) )
142 if( ext == wxT(
"wrz" ) )
145 if( ext == wxT(
"idf" ) )
148 if( ext == wxT(
"emn" ) )
151 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
160 memset( iline, 0, 82 );
161 ifile.getline( iline, 82 );
167 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
170 std::string fstr = iline;
174 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
180 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
189 m_app = XCAFApp_Application::GetApplication();
190 m_app->NewDocument(
"MDTV-XCAF", m_doc );
191 m_assy = XCAFDoc_DocumentTool::ShapeTool ( m_doc->Main() );
227 BRepBuilderAPI_Transform hole( s, shift );
261 if( aFileNameUTF8.empty() )
267 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
285 TopLoc_Location toploc;
287 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
290 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
295 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
297 if( llabel.IsNull() )
305 TCollection_ExtendedString refdes( aRefDes.c_str() );
306 TDataStd_Name::Set( llabel, refdes );
314 if( aThickness < 0.0 )
338 BRepBuilderAPI::Precision( aDistance );
348 double aThickness,
const VECTOR2D& aOrigin )
350 if( !aShape.IsNull() )
356 BRepBuilderAPI_MakeWire wire;
363 for(
int j = 0; j < aChain.
PointCount(); j++ )
381 double seg_len =
std::abs( end.X() - start.X()) +
std::abs(start.Y() - end.Y() );
382 double min_len = 0.0001;
384 if( seg_len < min_len )
389 edge = BRepBuilderAPI_MakeEdge( start, end );
392 if( BRepBuilderAPI_WireDone != wire.Error() )
398 catch(
const Standard_Failure& e )
414 BRepBuilderAPI_MakeFace face;
418 face = BRepBuilderAPI_MakeFace( wire );
420 catch(
const Standard_Failure& e )
427 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
429 if( aShape.IsNull() )
431 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
452 std::vector<TopoDS_Shape> board_outlines;
454 for(
int cnt = 0; cnt < aOutline.
OutlineCount(); cnt++ )
461 TopoDS_Shape curr_brd;
467 wxT(
"OCC error adding main outline polygon %d with %d points.\n" ),
471 board_outlines.push_back( curr_brd );
480 for(
int ii = 0; ii < aOutline.
HoleCount( cnt ); ii++ )
498 TopTools_ListOfShape holelist;
501 holelist.Append( hole );
504 for( TopoDS_Shape& board: board_outlines )
507 TopTools_ListOfShape mainbrd;
509 mainbrd.Append( board );
511 Cut.SetArguments( mainbrd );
513 Cut.SetTools( holelist );
524 for( TopoDS_Shape& board: board_outlines )
540 Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
547 colorTool->SetColor( pcb_label,
color, XCAFDoc_ColorSurf );
549 Handle( TDataStd_TreeNode ) node;
551 if( pcb_label.FindAttribute( XCAFDoc::ShapeRefGUID(), node ) )
554 TDF_Label label = node->Father()->Label();
556 if( !label.IsNull() )
561 pcbName = wxT(
"PCB" );
565 std::string pcbNameStdString( pcbName.ToUTF8() );
566 TCollection_ExtendedString partname( pcbNameStdString.c_str() );
567 TDataStd_Name::Set( label, partname );
571 TopExp_Explorer topex;
573 topex.Init( m_assy->GetShape( pcb_label ), TopAbs_SOLID );
575 while( topex.More() )
577 colorTool->SetColor( topex.Current(),
color, XCAFDoc_ColorSurf );
582#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
583 m_assy->UpdateAssemblies();
592bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
602 wxFileName fn( aFileName );
604 IGESCAFControl_Writer writer;
605 writer.SetColorMode( Standard_True );
606 writer.SetNameMode( Standard_True );
607 IGESData_GlobalSection header = writer.Model()->GlobalSection();
608 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
609 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
610 header.SetAuthorName(
611 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
612 header.SetCompanyName(
613 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
614 writer.Model()->SetGlobalSection( header );
616 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
634 wxFileName fn( aFileName );
636 STEPCAFControl_Writer writer;
637 writer.SetColorMode( Standard_True );
638 writer.SetNameMode( Standard_True );
645 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
646 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
648 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
651 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
655 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
658 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
659 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
660 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
661 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
666 wxString currCWD = wxGetCwd();
667 wxString workCWD = fn.GetPath();
669 if( !workCWD.IsEmpty() )
670 wxSetWorkingDirectory( workCWD );
672 char tmpfname[] =
"$tempfile$.step";
674 if( Standard_False == writer.Write( tmpfname ) )
679 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
683 fn.GetFullName() ) );
688 wxSetWorkingDirectory( currCWD );
695 bool aSubstituteModels, wxString* aErrorMessage )
697 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
698 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
700 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
710 Handle( TDocStd_Document ) doc;
711 m_app->NewDocument(
"MDTV-XCAF", doc );
713 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
719 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
728 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
740 wxFFileInputStream ifile( fileName );
741 wxFileName outFile( fileName );
743 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
744 outFile.SetExt( wxT(
"step" ) );
745 wxFileOffset size = ifile.GetLength();
747 if( size == wxInvalidOffset )
755 bool success =
false;
756 wxFFileOutputStream ofile( outFile.GetFullPath() );
761 char* buffer =
new char[size];
763 ifile.Read( buffer, size );
764 std::string expanded;
768 expanded = gzip::decompress( buffer, size );
777 if( expanded.empty() )
781 wxZipInputStream izipfile( ifile );
782 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
784 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
786 izipfile.Read( ofile );
792 ofile.Write( expanded.data(), expanded.size() );
800 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
821 if( aSubstituteModels )
823 wxFileName wrlName( fileName );
825 wxString basePath = wrlName.GetPath();
826 wxString baseName = wrlName.GetName();
834 alts.Add( wxT(
"stp" ) );
835 alts.Add( wxT(
"step" ) );
836 alts.Add( wxT(
"STP" ) );
837 alts.Add( wxT(
"STEP" ) );
838 alts.Add( wxT(
"Stp" ) );
839 alts.Add( wxT(
"Step" ) );
840 alts.Add( wxT(
"stpz" ) );
841 alts.Add( wxT(
"stpZ" ) );
842 alts.Add( wxT(
"STPZ" ) );
843 alts.Add( wxT(
"step.gz" ) );
844 alts.Add( wxT(
"stp.gz" ) );
847 alts.Add( wxT(
"iges" ) );
848 alts.Add( wxT(
"IGES" ) );
849 alts.Add( wxT(
"igs" ) );
850 alts.Add( wxT(
"IGS" ) );
854 for(
const auto& alt : alts )
856 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
858 if( altFile.IsOk() && altFile.FileExists() )
860 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
881 aErrorMessage->Printf( wxT(
"Cannot add a VRML model to a STEP file.\n" ) );
896 if( aLabel.IsNull() )
905 wxFileName afile( fileName );
906 std::string pname( afile.GetName().ToUTF8() );
907 TCollection_ExtendedString partname( pname.c_str() );
908 TDataStd_Name::Set( aLabel, partname );
917 TopLoc_Location& aLocation )
931 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
940 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
941 lPos.Multiply( lRot );
942 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
943 lPos.Multiply( lRot );
948 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
949 lPos.Multiply( lRot );
953 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
954 lPos.Multiply( lOff );
957 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
959 lPos.Multiply( lOrient );
960 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
962 lPos.Multiply( lOrient );
963 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
965 lPos.Multiply( lOrient );
967 aLocation = TopLoc_Location( lPos );
975 IGESCAFControl_Reader reader;
976 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
978 if( stat != IFSelect_RetDone )
982 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
986 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
990 reader.SetColorMode(
true );
991 reader.SetNameMode(
false );
992 reader.SetLayerMode(
false );
994 if( !reader.Transfer( doc ) )
1001 if( reader.NbShapes() < 1 )
1013 STEPCAFControl_Reader reader;
1014 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
1016 if( stat != IFSelect_RetDone )
1020 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
1024 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
1028 reader.SetColorMode(
true );
1029 reader.SetNameMode(
false );
1030 reader.SetLayerMode(
false );
1032 if( !reader.Transfer( doc ) )
1039 if( reader.NbRootsForTransfer() < 1 )
1050 Handle( TDocStd_Document )& dest,
VECTOR3D aScale )
1053 gp_GTrsf scale_transform;
1054 scale_transform.SetVectorialPart( gp_Mat( aScale.
x, 0, 0,
1057 BRepBuilderAPI_GTransform brep( scale_transform );
1060 Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
1063 TDF_LabelSequence frshapes;
1064 s_assy->GetFreeShapes( frshapes );
1067 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool ( dest->Main() );
1070 TDF_Label component = d_assy->NewShape();
1072 int nshapes = frshapes.Length();
1074 Handle( XCAFDoc_ColorTool ) scolor = XCAFDoc_DocumentTool::ColorTool( source->Main() );
1075 Handle( XCAFDoc_ColorTool ) dcolor = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
1076 TopExp_Explorer dtop;
1077 TopExp_Explorer stop;
1079 while(
id <= nshapes )
1081 TopoDS_Shape shape = s_assy->GetShape( frshapes.Value(
id ) );
1083 if( !shape.IsNull() )
1085 TopoDS_Shape scaled_shape( shape );
1087 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
1089 brep.Perform( shape, Standard_False );
1093 scaled_shape = brep.Shape();
1097 ReportMessage( wxT(
" * transfertModel(): failed to scale model\n" ) );
1099 scaled_shape = shape;
1103 TDF_Label niulab = d_assy->AddComponent( component, scaled_shape, Standard_False );
1106 stop.Init( shape, TopAbs_FACE );
1107 dtop.Init( d_assy->GetShape( niulab ), TopAbs_FACE );
1109 while( stop.More() && dtop.More() )
1111 Quantity_Color face_color;
1116 if( s_assy->FindShape( stop.Current(), tl ) )
1118 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1119 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1120 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1122 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1125 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1126 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1127 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1129 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1137 stop.Init( shape, TopAbs_SOLID );
1138 dtop.Init( d_assy->GetShape( niulab ), TopAbs_SOLID, TopAbs_FACE );
1140 while( stop.More() && dtop.More() )
1142 Quantity_Color face_color;
1147 if( s_assy->FindShape( stop.Current(), tl ) )
1149 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1150 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1151 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1153 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorGen );
1156 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1157 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1158 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1160 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
constexpr EDA_IU_SCALE pcbIUScale
PAD_DRILL_SHAPE_T GetDrillShape() const
const VECTOR2I & GetDrillSize() const
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc) const
Build the corner list of the polygonal drill shape in the board coordinate system.
VECTOR2I GetPosition() const override
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
bool isBoardOutlineValid()
bool AddComponent(const std::string &aFileName, const std::string &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
bool AddPadHole(const PAD *aPad, const VECTOR2D &aOrigin)
std::vector< TDF_Label > m_pcb_labels
STEP_PCB_MODEL(const wxString &aPcbName)
bool readIGES(Handle(TDocStd_Document)&m_doc, const char *fname)
void SetBoardColor(double r, double g, double b)
void SetMinDistance(double aDistance)
bool CreatePCB(SHAPE_POLY_SET &aOutline, VECTOR2D aOrigin)
bool readSTEP(Handle(TDocStd_Document)&m_doc, const char *fname)
Handle(XCAFApp_Application) m_app
bool getModelLocation(bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, TopLoc_Location &aLocation)
virtual ~STEP_PCB_MODEL()
bool WriteSTEP(const wxString &aFileName)
bool getModelLabel(const std::string &aFileNameUTF8, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
std::vector< TopoDS_Shape > m_cutouts
bool MakeShape(TopoDS_Shape &aShape, const SHAPE_LINE_CHAIN &chain, double aThickness, const VECTOR2D &aOrigin)
void SetPCBThickness(double aThickness)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, VECTOR3D aScale)
void ReportMessage(const wxString &aMessage)
This file contains miscellaneous commonly used macros and functions.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
constexpr const char * errorMessage
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
static constexpr double BOARD_OFFSET
static constexpr double MIN_LENGTH2
static constexpr double THICKNESS_DEFAULT
FormatType fileType(const char *aFileName)
static constexpr double USER_ANGLE_PREC
static constexpr double THICKNESS_MIN
static constexpr double USER_PREC
std::pair< std::string, TDF_Label > MODEL_DATUM
static constexpr double STEPEXPORT_MIN_DISTANCE
< Default minimum distance between points to treat them as separate ones (mm)
static constexpr double STEPEXPORT_MIN_ACCEPTABLE_DISTANCE
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
constexpr double IUTomm(int iu) const
VECTOR3< double > VECTOR3D