31#include <wx/filename.h>
33#include <wx/stdpaths.h>
34#include <wx/wfstream.h>
35#include <wx/zipstrm.h>
37#include <decompress.hpp>
50#include <IGESCAFControl_Reader.hxx>
51#include <IGESCAFControl_Writer.hxx>
52#include <IGESControl_Controller.hxx>
53#include <IGESData_GlobalSection.hxx>
54#include <IGESData_IGESModel.hxx>
55#include <Interface_Static.hxx>
56#include <Quantity_Color.hxx>
57#include <STEPCAFControl_Reader.hxx>
58#include <STEPCAFControl_Writer.hxx>
59#include <APIHeaderSection_MakeHeader.hxx>
60#include <Standard_Version.hxx>
61#include <TCollection_ExtendedString.hxx>
62#include <TDataStd_Name.hxx>
63#include <TDataStd_TreeNode.hxx>
64#include <TDF_LabelSequence.hxx>
65#include <TDF_ChildIterator.hxx>
66#include <TopExp_Explorer.hxx>
68#include <XCAFDoc_DocumentTool.hxx>
69#include <XCAFDoc_ColorTool.hxx>
71#include <BRep_Tool.hxx>
72#include <BRepMesh_IncrementalMesh.hxx>
73#include <BRepBuilderAPI.hxx>
74#include <BRepBuilderAPI_MakeEdge.hxx>
75#include <BRepBuilderAPI_Transform.hxx>
76#include <BRepBuilderAPI_GTransform.hxx>
77#include <BRepBuilderAPI_MakeFace.hxx>
78#include <BRepPrimAPI_MakePrism.hxx>
79#include <BRepPrimAPI_MakeCylinder.hxx>
80#include <BRepAlgoAPI_Cut.hxx>
82#include <BRepBndLib.hxx>
83#include <Bnd_BoundSortBox.hxx>
86#include <TopoDS_Wire.hxx>
87#include <TopoDS_Face.hxx>
88#include <TopoDS_Compound.hxx>
89#include <TopoDS_Builder.hxx>
90#include <Standard_Failure.hxx>
92#include <Geom_Curve.hxx>
93#include <Geom_BezierCurve.hxx>
94#include <Geom_TrimmedCurve.hxx>
100#include <GC_MakeArcOfCircle.hxx>
101#include <GC_MakeCircle.hxx>
103#include <RWGltf_CafWriter.hxx>
129 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
131 if( !lfile.FileExists() )
134 msg.Printf( wxT(
" * fileType(): no such file: %s\n" ),
135 wxString::FromUTF8Unchecked( aFileName ) );
141 wxString ext = lfile.GetExt().Lower();
143 if( ext == wxT(
"wrl" ) )
146 if( ext == wxT(
"wrz" ) )
149 if( ext == wxT(
"idf" ) )
152 if( ext == wxT(
"emn" ) )
155 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
164 memset( iline, 0, 82 );
165 ifile.getline( iline, 82 );
171 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
174 std::string fstr = iline;
178 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
184 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
193 m_app = XCAFApp_Application::GetApplication();
194 m_app->NewDocument(
"MDTV-XCAF", m_doc );
195 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
212 if( m_doc->CanClose() == CDM_CCS_OK )
224 TopoDS_Shape curr_shape;
231 if( aPad->
GetShape() == PAD_SHAPE::CIRCLE )
233 curr_shape = BRepPrimAPI_MakeCylinder(
239 BRepBuilderAPI_Transform round_shape( curr_shape, shift );
249 if( pcb_layer ==
B_Cu )
256 TopoDS_Shape plating;
274 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
304 if( pcblayer !=
F_Cu && pcblayer !=
B_Cu )
312 zposition, aOrigin );
322 const VECTOR2D& aOrigin,
bool aTrack )
335 wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
336 aPolyShapes->
FullPointCount(), aOnTop ? wxT(
"top" ) : wxT(
"bottom" ) ) );
353 const double margin = 0.01;
361 double copperDrill = boardDrill - platingThickness * 2;
363 TopoDS_Shape copperHole, boardHole;
393 if( aFileNameUTF8.empty() )
395 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
399 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
400 ReportMessage( wxString::Format( wxT(
"Add component %s.\n" ), aRefDes ) );
404 wxString errorMessage;
406 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
408 if( errorMessage.IsEmpty() )
409 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
417 TopLoc_Location toploc;
419 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
422 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
427 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
429 if( llabel.IsNull() )
431 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
437 TCollection_ExtendedString refdes( aRefDes.c_str() );
438 TDataStd_Name::Set( llabel, refdes );
446 if( aThickness < 0.0 )
491 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
493 if( arcs.size() == 1 )
497 if( arc. GetP0() == arc.
GetP1() )
508 double aZposition,
const VECTOR2D& aOrigin )
510 if( !aShape.IsNull() )
516 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
519 TopoDS_Shape base_shape;
520 base_shape = BRepPrimAPI_MakeCylinder(
526 BRepBuilderAPI_Transform round_shape( base_shape, shift );
527 aShape = round_shape;
529 if( aShape.IsNull() )
531 ReportMessage( wxT(
"failed to create a cylinder vertical shape\n" ) );
541 double aWidth,
double aThickness,
542 double aZposition,
const VECTOR2D& aOrigin )
550 double h_width = aWidth/2.0;
552 coords[0] =
VECTOR2D{ 0.0, h_width };
555 coords[1] =
VECTOR2D{ len, h_width };
558 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
561 coords[3] =
VECTOR2D{ len, -h_width };
564 coords[4] =
VECTOR2D{ 0, -h_width };
567 coords[5] =
VECTOR2D{ -h_width, 0.0 };
570 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
572 for(
int ii = 0; ii < 6; ii++ )
575 coords[ii] += aStartPoint;
580 gp_Pnt coords3D[ 6 ];
582 for(
int ii = 0; ii < 6; ii++ )
589 BRepBuilderAPI_MakeWire wire;
602 Handle( Geom_Circle ) circle = GC_MakeCircle( coords3D[1],
607 edge = BRepBuilderAPI_MakeEdge( circle );
612 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
615 Handle( Geom_TrimmedCurve ) arcOfCircle =
616 GC_MakeArcOfCircle( coords3D[1],
620 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
623 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
626 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
627 GC_MakeArcOfCircle( coords3D[4],
631 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
635 catch(
const Standard_Failure& e )
637 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
638 e.GetMessageString() ) );
643 BRepBuilderAPI_MakeFace face;
647 gp_Pln plane( coords3D[0], gp::DZ() );
648 face = BRepBuilderAPI_MakeFace( plane, wire );
650 catch(
const Standard_Failure& e )
653 wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
654 e.GetMessageString() ) );
658 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
660 if( aShape.IsNull() )
662 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
671 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
676 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
684 auto makeWireFromChain = [&]( BRepLib_MakeWire& aMkWire,
694 gp_Pnt start = toPoint( aPt0 );
695 gp_Pnt end = toPoint( aPt1 );
699 double seg_len = std::hypot( end.X() - start.X(), end.Y() - start.Y() );
704 BRepBuilderAPI_MakeEdge mkEdge( start, end );
706 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
708 ReportMessage( wxString::Format( wxT(
"failed to make segment edge at (%d "
709 "%d) -> (%d %d), skipping\n" ),
710 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
714 aMkWire.Add( mkEdge.Edge() );
716 if( aMkWire.Error() != BRepLib_WireDone )
718 ReportMessage( wxString::Format( wxT(
"failed to add segment edge "
719 "at (%d %d) -> (%d %d)\n" ),
720 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
731 Handle( Geom_Curve ) curve;
733 if( aArc.GetCentralAngle() ==
ANGLE_360 )
735 gp_Ax2 axis = gp::XOY();
736 axis.SetLocation( toPoint( aArc.GetCenter() ) );
743 curve = GC_MakeArcOfCircle( toPoint( aPt0 ),
744 toPoint( aArc.GetArcMid() ),
745 toPoint( aArc.GetP1() ) )
752 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
754 if( !aMkWire.IsDone() )
757 wxT(
"failed to add arc curve from (%d %d), arc p0 "
758 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
759 aPt0.
x, aPt0.
y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x,
760 aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) );
769 bool isFirstShape =
true;
783 if( nextShape != -1 )
789 lastPt = aChain.
CPoint( i );
799 firstPt = currentArc.
GetP0();
804 lastPt = currentArc.
GetP0();
806 if( addArc( lastPt, currentArc ) )
807 lastPt = currentArc.
GetP1();
826 isFirstShape =
false;
829 if( lastPt != firstPt )
832 catch(
const Standard_Failure& e )
834 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
835 e.GetMessageString() ) );
842 BRepBuilderAPI_MakeFace mkFace;
844 for(
size_t contId = 0; contId < polygon.size(); contId++ )
847 BRepLib_MakeWire mkWire;
851 if( !makeWireFromChain( mkWire, contour ) )
854 wxASSERT( mkWire.IsDone() );
857 mkFace = BRepBuilderAPI_MakeFace( mkWire.Wire() );
859 mkFace.Add( mkWire );
861 catch(
const Standard_Failure& e )
864 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
865 contId, e.GetMessageString() ) );
870 if( mkFace.IsDone() )
872 TopoDS_Shape prism = BRepPrimAPI_MakePrism( mkFace, gp_Vec( 0, 0, aThickness ) );
873 aShapes.push_back( prism );
877 ReportMessage( wxT(
"Failed to create a prismatic shape\n" ) );
901 Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
906 ReportMessage( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
919 wxT(
"OCC error creating main outline.\n" ) ) );
925 for(
size_t contId = 0; contId < polygon.size(); contId++ )
929 polyset.
Append( contour );
934 ReportMessage( wxT(
"OCC error creating main outline.\n" ) );
939 ReportMessage( wxT(
"OCC error creating hole in main outline.\n" ) );
948 BRepBndLib::Add( brdShape, brdBndBox );
951 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
954 auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
958 Bnd_Box brdWithHolesBndBox = brdBndBox;
960 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
962 for(
size_t i = 0; i < input.size(); i++ )
965 BRepBndLib::Add( input[i], bbox );
966 brdWithHolesBndBox.Add( bbox );
967 ( *holeBoxSet )[i] = bbox;
970 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
973 auto subtractShapes = [](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
974 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
978 for( TopoDS_Shape& shape : aShapesList )
981 BRepBndLib::Add( shape, shapeBbox );
983 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
985 TopTools_ListOfShape holelist;
987 for(
const Standard_Integer& index : indices )
988 holelist.Append( aHolesList[index] );
991 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
997 (
int) aShapesList.size(), aWhat ) );
999 if( holelist.IsEmpty() )
1002 TopTools_ListOfShape cutArgs;
1003 cutArgs.Append( shape );
1005 BRepAlgoAPI_Cut
cut;
1008 cut.SetFuzzyValue( 0.0005 );
1009 cut.SetArguments( cutArgs );
1011 cut.SetTools( holelist );
1014 shape =
cut.Shape();
1020 Bnd_BoundSortBox bsbHoles;
1028 Bnd_BoundSortBox bsbHoles;
1039 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_Color aColor,
1040 const wxString& aShapeName )
1043 for( TopoDS_Shape& shape : aShapesList )
1045 Handle( TDataStd_TreeNode ) node;
1048 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
1054 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
1055 TDF_Label shpLbl = node->Father()->Label();
1056 if( !shpLbl.IsNull() )
1058 colorTool->SetColor( shpLbl, aColor, XCAFDoc_ColorSurf );
1061 if( aShapesList.size() > 1 )
1063 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
1067 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
1071 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
1072 TDataStd_Name::Set( shpLbl, partname );
1097#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
1098 m_assy->UpdateAssemblies();
1107bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
1111 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1117 wxFileName fn( aFileName );
1118 IGESControl_Controller::Init();
1119 IGESCAFControl_Writer writer;
1120 writer.SetColorMode( Standard_True );
1121 writer.SetNameMode( Standard_True );
1122 IGESData_GlobalSection header = writer.Model()->GlobalSection();
1123 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
1124 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
1125 header.SetAuthorName(
1126 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
1127 header.SetCompanyName(
1128 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
1129 writer.Model()->SetGlobalSection( header );
1131 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
1143 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1149 wxFileName fn( aFileName );
1151 STEPCAFControl_Writer writer;
1152 writer.SetColorMode( Standard_True );
1153 writer.SetNameMode( Standard_True );
1160 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
1161 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
1165 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
1166 ReportMessage( wxT(
"Failed to set surface curve mode, but will attempt to continue." ) );
1168 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
1171 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
1175 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
1178 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
1179 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
1180 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
1181 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
1183 bool success =
true;
1186 wxString currCWD = wxGetCwd();
1187 wxString workCWD = fn.GetPath();
1189 if( !workCWD.IsEmpty() )
1190 wxSetWorkingDirectory( workCWD );
1192 char tmpfname[] =
"$tempfile$.step";
1194 if( Standard_False == writer.Write( tmpfname ) )
1203 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
1205 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
1207 fn.GetFullName() ) );
1212 wxSetWorkingDirectory( currCWD );
1219 bool aSubstituteModels, wxString* aErrorMessage )
1221 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
1222 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
1224 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
1228 aLabel = mm->second;
1234 Handle( TDocStd_Document ) doc;
1235 m_app->NewDocument(
"MDTV-XCAF", doc );
1237 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1243 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
1245 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
1252 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
1254 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
1264 wxFFileInputStream ifile( fileName );
1265 wxFileName outFile( fileName );
1267 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
1268 outFile.SetExt( wxT(
"step" ) );
1269 wxFileOffset size = ifile.GetLength();
1271 if( size == wxInvalidOffset )
1273 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
1279 bool success =
false;
1280 wxFFileOutputStream ofile( outFile.GetFullPath() );
1285 char* buffer =
new char[size];
1287 ifile.Read( buffer, size );
1288 std::string expanded;
1292 expanded = gzip::decompress( buffer, size );
1297 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
1301 if( expanded.empty() )
1305 wxZipInputStream izipfile( ifile );
1306 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
1308 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
1310 izipfile.Read( ofile );
1316 ofile.Write( expanded.data(), expanded.size() );
1324 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
1345 if( aSubstituteModels )
1347 wxFileName wrlName( fileName );
1349 wxString basePath = wrlName.GetPath();
1350 wxString baseName = wrlName.GetName();
1358 alts.Add( wxT(
"stp" ) );
1359 alts.Add( wxT(
"step" ) );
1360 alts.Add( wxT(
"STP" ) );
1361 alts.Add( wxT(
"STEP" ) );
1362 alts.Add( wxT(
"Stp" ) );
1363 alts.Add( wxT(
"Step" ) );
1364 alts.Add( wxT(
"stpz" ) );
1365 alts.Add( wxT(
"stpZ" ) );
1366 alts.Add( wxT(
"STPZ" ) );
1367 alts.Add( wxT(
"step.gz" ) );
1368 alts.Add( wxT(
"stp.gz" ) );
1371 alts.Add( wxT(
"iges" ) );
1372 alts.Add( wxT(
"IGES" ) );
1373 alts.Add( wxT(
"igs" ) );
1374 alts.Add( wxT(
"IGS" ) );
1378 for(
const auto& alt : alts )
1380 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
1382 if( altFile.IsOk() && altFile.FileExists() )
1384 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
1405 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
1420 if( aLabel.IsNull() )
1422 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
1429 wxFileName afile( fileName );
1430 std::string pname( afile.GetName().ToUTF8() );
1431 TCollection_ExtendedString partname( pname.c_str() );
1432 TDataStd_Name::Set( aLabel, partname );
1441 TopLoc_Location& aLocation )
1455 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
1464 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
1465 lPos.Multiply( lRot );
1466 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
1467 lPos.Multiply( lRot );
1472 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
1473 lPos.Multiply( lRot );
1477 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
1478 lPos.Multiply( lOff );
1481 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
1483 lPos.Multiply( lOrient );
1484 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
1486 lPos.Multiply( lOrient );
1487 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
1489 lPos.Multiply( lOrient );
1491 aLocation = TopLoc_Location( lPos );
1498 IGESControl_Controller::Init();
1499 IGESCAFControl_Reader reader;
1500 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
1502 if( stat != IFSelect_RetDone )
1506 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
1510 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
1514 reader.SetColorMode(
true );
1515 reader.SetNameMode(
false );
1516 reader.SetLayerMode(
false );
1518 if( !reader.Transfer( doc ) )
1520 if( doc->CanClose() == CDM_CCS_OK )
1527 if( reader.NbShapes() < 1 )
1529 if( doc->CanClose() == CDM_CCS_OK )
1541 STEPCAFControl_Reader reader;
1542 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
1544 if( stat != IFSelect_RetDone )
1548 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
1552 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
1556 reader.SetColorMode(
true );
1557 reader.SetNameMode(
true );
1558 reader.SetLayerMode(
false );
1560 if( !reader.Transfer( doc ) )
1562 if( doc->CanClose() == CDM_CCS_OK )
1569 if( reader.NbRootsForTransfer() < 1 )
1571 if( doc->CanClose() == CDM_CCS_OK )
1582 Handle( TDocStd_Document )& dest,
VECTOR3D aScale )
1585 gp_GTrsf scale_transform;
1586 scale_transform.SetVectorialPart( gp_Mat( aScale.
x, 0, 0,
1589 BRepBuilderAPI_GTransform brep( scale_transform );
1592 Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
1595 TDF_LabelSequence frshapes;
1596 s_assy->GetFreeShapes( frshapes );
1599 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool ( dest->Main() );
1602 TDF_Label component = d_assy->NewShape();
1604 int nshapes = frshapes.Length();
1606 Handle( XCAFDoc_ColorTool ) scolor = XCAFDoc_DocumentTool::ColorTool( source->Main() );
1607 Handle( XCAFDoc_ColorTool ) dcolor = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
1608 TopExp_Explorer dtop;
1609 TopExp_Explorer stop;
1611 while(
id <= nshapes )
1613 const TDF_Label& s_shapeLabel = frshapes.Value(
id );
1614 TopoDS_Shape shape = s_assy->GetShape( s_shapeLabel );
1616 if( !shape.IsNull() )
1618 Handle( TDataStd_Name ) s_nameAttr;
1619 s_shapeLabel.FindAttribute( TDataStd_Name::GetID(), s_nameAttr );
1621 TCollection_ExtendedString s_labelName =
1622 s_nameAttr ? s_nameAttr->Get() : TCollection_ExtendedString();
1624 TopoDS_Shape scaled_shape( shape );
1626 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
1628 brep.Perform( shape, Standard_False );
1632 scaled_shape = brep.Shape();
1636 ReportMessage( wxT(
" * transfertModel(): failed to scale model\n" ) );
1638 scaled_shape = shape;
1642 TDF_Label d_shapeLabel = d_assy->AddShape( scaled_shape, Standard_False );
1644 if( s_labelName.Length() > 0 )
1645 TDataStd_Name::Set( d_shapeLabel, s_labelName );
1648 d_assy->AddComponent( component, d_shapeLabel, scaled_shape.Location() );
1651 stop.Init( shape, TopAbs_FACE );
1652 dtop.Init( d_assy->GetShape( niulab ), TopAbs_FACE );
1654 while( stop.More() && dtop.More() )
1656 Quantity_Color face_color;
1661 if( s_assy->FindShape( stop.Current(), tl ) )
1663 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1664 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1665 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1667 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1670 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1671 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1672 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1674 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1682 stop.Init( shape, TopAbs_SOLID );
1683 dtop.Init( d_assy->GetShape( niulab ), TopAbs_SOLID, TopAbs_FACE );
1685 while( stop.More() && dtop.More() )
1687 Quantity_Color face_color;
1692 if( s_assy->FindShape( stop.Current(), tl ) )
1694 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1695 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1696 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1698 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorGen );
1701 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1702 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1703 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1705 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1724 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1730 TDF_LabelSequence freeShapes;
1731 m_assy->GetFreeShapes( freeShapes );
1737 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
1739 TDF_Label label = freeShapes.Value( i );
1741 m_assy->GetShape( label, shape );
1746 const Standard_Real linearDeflection = 0.01;
1747 const Standard_Real angularDeflection = 0.5;
1748 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
1752 wxFileName fn( aFileName );
1754 const char* tmpGltfname =
"$tempfile$.glb";
1755 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
1757 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
1758 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
1759 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
1760 RWMesh_CoordinateSystem_Zup );
1761#if OCC_VERSION_HEX >= 0x070700
1762 cafWriter.SetParallel(
true );
1764 TColStd_IndexedDataMapOfStringString metadata;
1766 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
1767 TCollection_ExtendedString( fn.GetName().wc_str() ) );
1768 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
1769 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
1770 metadata.Add( TCollection_AsciiString(
"generator" ),
1771 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
1772 metadata.Add( TCollection_AsciiString(
"generated_at" ),
1775 bool success =
true;
1778 wxString currCWD = wxGetCwd();
1779 wxString workCWD = fn.GetPath();
1781 if( !workCWD.IsEmpty() )
1782 wxSetWorkingDirectory( workCWD );
1784 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
1791 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
1793 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
1794 tmpGltfname, fn.GetFullName() ) );
1799 wxSetWorkingDirectory( currCWD );
constexpr EDA_IU_SCALE pcbIUScale
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
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
VECTOR2I GetPosition() const override
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
PAD_SHAPE GetShape() const
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
const VECTOR2I & GetP1() const
VECTOR2I GetCenter() const
const VECTOR2I & GetP0() 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
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.
const std::vector< SHAPE_ARC > & CArcs() const
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
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)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
int OutlineCount() const
Return the number of outlines in the set.
const std::vector< POLYGON > & CPolygons() const
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, VECTOR2D aStartPoint, VECTOR2D aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_LINE_CHAIN containing only one 360 deg arc to a TopoDS_Shape ( vertical cylinder) it ...
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.
std::vector< TopoDS_Shape > m_boardCutouts
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin)
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
bool AddPadHole(const PAD *aPad, const VECTOR2D &aOrigin)
std::vector< TDF_Label > m_pcb_labels
bool MakeShapeAsCylinder(TopoDS_Shape &aShape, const SHAPE_LINE_CHAIN &aChain, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_LINE_CHAIN containing only one 360 deg arc to a TopoDS_Shape ( vertical cylinder) it ...
STEP_PCB_MODEL(const wxString &aPcbName)
std::vector< TopoDS_Shape > m_board_outlines
bool readIGES(Handle(TDocStd_Document)&m_doc, const char *fname)
void SetBoardColor(double r, double g, double b)
bool AddViaShape(const PCB_VIA *aVia, const VECTOR2D &aOrigin)
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()
std::vector< TopoDS_Shape > m_board_copper_tracks
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms)
bool getModelLabel(const std::string &aFileNameUTF8, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool WriteSTEP(const wxString &aFileName, bool aOptimize)
std::vector< TopoDS_Shape > m_copperCutouts
std::vector< TopoDS_Shape > m_board_copper_pads
bool AddCopperPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, bool aOnTop, const VECTOR2D &aOrigin, bool aTrack)
std::vector< TopoDS_Shape > m_board_copper_zones
void SetPCBThickness(double aThickness)
bool AddTrackSegment(const PCB_TRACK *aTrack, const VECTOR2D &aOrigin)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, VECTOR3D aScale)
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
static constexpr EDA_ANGLE ANGLE_360
void ReportMessage(const wxString &aMessage)
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
std::vector< FAB_LAYER_COLOR > dummy
static constexpr double BOARD_OFFSET
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static constexpr double USER_ANGLE_PREC
static constexpr double USER_PREC
static constexpr double COPPER_THICKNESS_DEFAULT_MM
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 ...
static constexpr double BOARD_THICKNESS_DEFAULT_MM
std::pair< std::string, TDF_Label > MODEL_DATUM
static constexpr double ARC_TO_SEGMENT_MAX_ERROR_MM
static constexpr double BOARD_THICKNESS_MIN_MM
void ReportMessage(const wxString &aMessage)
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString GetISO8601CurrentDateTime()
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
constexpr double IUTomm(int iu) const
constexpr int mmToIU(double mm) const
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 EuclideanNorm(const VECTOR2I &vector)
VECTOR3< double > VECTOR3D