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() );
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 )
254 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
284 if( pcblayer !=
F_Cu && pcblayer !=
B_Cu )
292 zposition, aOrigin );
302 const VECTOR2D& aOrigin,
bool aTrack )
312 wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
313 aPolyShapes->
FullPointCount(), aOnTop ? wxT(
"top" ) : wxT(
"bottom" ) ) );
328 const double margin = 0.01;
341 BRepBuilderAPI_Transform hole( s, shift );
374 seg_hole->GetSeg().A, seg_hole->GetSeg().B,
394 if( aFileNameUTF8.empty() )
396 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
400 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
401 ReportMessage( wxString::Format( wxT(
"Add component %s.\n" ), aRefDes ) );
405 wxString errorMessage;
407 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
409 if( errorMessage.IsEmpty() )
410 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
418 TopLoc_Location toploc;
420 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
423 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
428 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
430 if( llabel.IsNull() )
432 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
438 TCollection_ExtendedString refdes( aRefDes.c_str() );
439 TDataStd_Name::Set( llabel, refdes );
447 if( aThickness < 0.0 )
493 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
495 if( arcs.size() == 1 )
499 if( arc. GetP0() == arc.
GetP1() )
510 double aZposition,
const VECTOR2D& aOrigin )
512 if( !aShape.IsNull() )
518 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
521 TopoDS_Shape base_shape;
522 base_shape = BRepPrimAPI_MakeCylinder(
528 BRepBuilderAPI_Transform round_shape( base_shape, shift );
529 aShape = round_shape;
531 if( aShape.IsNull() )
533 ReportMessage( wxT(
"failed to create a cylinder vertical shape\n" ) );
543 double aWidth,
double aThickness,
544 double aZposition,
const VECTOR2D& aOrigin )
552 double h_width = aWidth/2.0;
554 coords[0] =
VECTOR2D{ 0.0, h_width };
557 coords[1] =
VECTOR2D{ len, h_width };
560 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
563 coords[3] =
VECTOR2D{ len, -h_width };
566 coords[4] =
VECTOR2D{ 0, -h_width };
569 coords[5] =
VECTOR2D{ -h_width, 0.0 };
572 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
574 for(
int ii = 0; ii < 6; ii++ )
577 coords[ii] += aStartPoint;
582 gp_Pnt coords3D[ 6 ];
584 for(
int ii = 0; ii < 6; ii++ )
591 BRepBuilderAPI_MakeWire wire;
604 Handle( Geom_Circle ) circle = GC_MakeCircle( coords3D[1],
609 edge = BRepBuilderAPI_MakeEdge( circle );
614 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
617 Handle( Geom_TrimmedCurve ) arcOfCircle =
618 GC_MakeArcOfCircle( coords3D[1],
622 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
625 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
628 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
629 GC_MakeArcOfCircle( coords3D[4],
633 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
637 catch(
const Standard_Failure& e )
639 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
640 e.GetMessageString() ) );
645 BRepBuilderAPI_MakeFace face;
649 gp_Pln plane( coords3D[0], gp::DZ() );
650 face = BRepBuilderAPI_MakeFace( plane, wire );
652 catch(
const Standard_Failure& e )
655 wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
656 e.GetMessageString() ) );
660 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
662 if( aShape.IsNull() )
664 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
673 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
678 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
686 auto makeWireFromChain = [&]( BRepLib_MakeWire& aMkWire,
693 gp_Pnt start = toPoint( aPt0 );
694 gp_Pnt end = toPoint( aPt1 );
698 double seg_len = std::hypot( end.X() - start.X(), end.Y() - start.Y() );
703 BRepBuilderAPI_MakeEdge mkEdge( start, end );
705 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
711 aMkWire.Add( mkEdge.Edge() );
713 if( aMkWire.Error() != BRepLib_WireDone )
723 auto addArc = [&](
const SHAPE_ARC& aArc ) ->
bool
726 Handle( Geom_Curve ) curve;
728 if( aArc.GetCentralAngle() ==
ANGLE_360 )
730 gp_Ax2 axis = gp::XOY();
731 axis.SetLocation( toPoint( aArc.GetCenter() ) );
738 curve = GC_MakeArcOfCircle( toPoint( aArc.GetP0() ),
739 toPoint( aArc.GetArcMid() ),
740 toPoint( aArc.GetP1() ) )
747 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
749 if( !aMkWire.IsDone() )
760 bool isFirstShape =
true;
770 std::cout <<
"Skip looping arc" << std::endl;
782 lastPt = aChain.
CPoint( i );
792 firstPt = currentArc.
GetP0();
796 if( lastPt != currentArc.
GetP0() )
799 if( addArc( currentArc ) )
800 lastPt = currentArc.
GetP1();
816 isFirstShape =
false;
819 if( lastPt != firstPt )
822 catch(
const Standard_Failure& e )
824 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
825 e.GetMessageString() ) );
832 BRepBuilderAPI_MakeFace mkFace;
834 for(
size_t contId = 0; contId < polygon.size(); contId++ )
837 BRepLib_MakeWire mkWire;
841 if( !makeWireFromChain( mkWire, contour ) )
844 wxASSERT( mkWire.IsDone() );
847 mkFace = BRepBuilderAPI_MakeFace( mkWire.Wire() );
849 mkFace.Add( mkWire );
851 catch(
const Standard_Failure& e )
854 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
855 contId, e.GetMessageString() ) );
860 if( mkFace.IsDone() )
862 TopoDS_Shape prism = BRepPrimAPI_MakePrism( mkFace, gp_Vec( 0, 0, aThickness ) );
863 aShapes.push_back( prism );
867 ReportMessage( wxT(
"Failed to create a prismatic shape\n" ) );
891 Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
896 for(
int cnt = 0; cnt < aOutline.
OutlineCount(); cnt++ )
900 ReportMessage( wxString::Format( wxT(
"Build board main outline %d with %d points.\n" ),
907 wxT(
"OCC error adding main outline polygon %d with %d points.\n" ), cnt + 1,
915 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
918 Bnd_BoundSortBox bsb;
920 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0,
m_cutouts.size() - 1 );
922 for(
size_t i = 0; i <
m_cutouts.size(); i++ )
926 ( *holeBoxSet )[i] = bbox;
929 bsb.Initialize( holeBoxSet );
931 auto subtractShapes = [&](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList )
935 for( TopoDS_Shape& shape : aShapesList )
938 BRepBndLib::Add( shape, shapeBbox );
940 const TColStd_ListOfInteger& indices = bsb.Compare( shapeBbox );
942 TopTools_ListOfShape holelist;
944 for(
const Standard_Integer& index : indices )
948 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
954 (
int) aShapesList.size(), aWhat ) );
956 if( holelist.IsEmpty() )
959 TopTools_ListOfShape cutArgs;
960 cutArgs.Append( shape );
963 cut.SetArguments( cutArgs );
965 cut.SetTools( holelist );
981 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_Color aColor,
982 const wxString& aShapeName )
985 for( TopoDS_Shape& shape : aShapesList )
987 Handle( TDataStd_TreeNode ) node;
990 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
996 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
997 TDF_Label shpLbl = node->Father()->Label();
998 if( !shpLbl.IsNull() )
1000 colorTool->SetColor( shpLbl, aColor, XCAFDoc_ColorSurf );
1003 if( aShapesList.size() > 1 )
1005 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
1009 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
1013 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
1014 TDataStd_Name::Set( shpLbl, partname );
1039#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
1040 m_assy->UpdateAssemblies();
1049bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
1053 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1059 wxFileName fn( aFileName );
1060 IGESControl_Controller::Init();
1061 IGESCAFControl_Writer writer;
1062 writer.SetColorMode( Standard_True );
1063 writer.SetNameMode( Standard_True );
1064 IGESData_GlobalSection header = writer.Model()->GlobalSection();
1065 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
1066 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
1067 header.SetAuthorName(
1068 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
1069 header.SetCompanyName(
1070 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
1071 writer.Model()->SetGlobalSection( header );
1073 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
1085 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1091 wxFileName fn( aFileName );
1093 STEPCAFControl_Writer writer;
1094 writer.SetColorMode( Standard_True );
1095 writer.SetNameMode( Standard_True );
1102 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
1103 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
1105 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
1108 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
1112 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
1115 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
1116 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
1117 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
1118 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
1120 bool success =
true;
1123 wxString currCWD = wxGetCwd();
1124 wxString workCWD = fn.GetPath();
1126 if( !workCWD.IsEmpty() )
1127 wxSetWorkingDirectory( workCWD );
1129 char tmpfname[] =
"$tempfile$.step";
1131 if( Standard_False == writer.Write( tmpfname ) )
1140 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
1142 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
1144 fn.GetFullName() ) );
1149 wxSetWorkingDirectory( currCWD );
1156 bool aSubstituteModels, wxString* aErrorMessage )
1158 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
1159 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
1161 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
1165 aLabel = mm->second;
1171 Handle( TDocStd_Document ) doc;
1172 m_app->NewDocument(
"MDTV-XCAF", doc );
1174 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1180 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
1182 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
1189 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
1191 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
1201 wxFFileInputStream ifile( fileName );
1202 wxFileName outFile( fileName );
1204 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
1205 outFile.SetExt( wxT(
"step" ) );
1206 wxFileOffset size = ifile.GetLength();
1208 if( size == wxInvalidOffset )
1210 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
1216 bool success =
false;
1217 wxFFileOutputStream ofile( outFile.GetFullPath() );
1222 char* buffer =
new char[size];
1224 ifile.Read( buffer, size );
1225 std::string expanded;
1229 expanded = gzip::decompress( buffer, size );
1234 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
1238 if( expanded.empty() )
1242 wxZipInputStream izipfile( ifile );
1243 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
1245 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
1247 izipfile.Read( ofile );
1253 ofile.Write( expanded.data(), expanded.size() );
1261 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
1282 if( aSubstituteModels )
1284 wxFileName wrlName( fileName );
1286 wxString basePath = wrlName.GetPath();
1287 wxString baseName = wrlName.GetName();
1295 alts.Add( wxT(
"stp" ) );
1296 alts.Add( wxT(
"step" ) );
1297 alts.Add( wxT(
"STP" ) );
1298 alts.Add( wxT(
"STEP" ) );
1299 alts.Add( wxT(
"Stp" ) );
1300 alts.Add( wxT(
"Step" ) );
1301 alts.Add( wxT(
"stpz" ) );
1302 alts.Add( wxT(
"stpZ" ) );
1303 alts.Add( wxT(
"STPZ" ) );
1304 alts.Add( wxT(
"step.gz" ) );
1305 alts.Add( wxT(
"stp.gz" ) );
1308 alts.Add( wxT(
"iges" ) );
1309 alts.Add( wxT(
"IGES" ) );
1310 alts.Add( wxT(
"igs" ) );
1311 alts.Add( wxT(
"IGS" ) );
1315 for(
const auto& alt : alts )
1317 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
1319 if( altFile.IsOk() && altFile.FileExists() )
1321 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
1342 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
1357 if( aLabel.IsNull() )
1359 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
1366 wxFileName afile( fileName );
1367 std::string pname( afile.GetName().ToUTF8() );
1368 TCollection_ExtendedString partname( pname.c_str() );
1369 TDataStd_Name::Set( aLabel, partname );
1378 TopLoc_Location& aLocation )
1392 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
1401 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
1402 lPos.Multiply( lRot );
1403 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
1404 lPos.Multiply( lRot );
1409 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
1410 lPos.Multiply( lRot );
1414 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
1415 lPos.Multiply( lOff );
1418 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
1420 lPos.Multiply( lOrient );
1421 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
1423 lPos.Multiply( lOrient );
1424 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
1426 lPos.Multiply( lOrient );
1428 aLocation = TopLoc_Location( lPos );
1435 IGESControl_Controller::Init();
1436 IGESCAFControl_Reader reader;
1437 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
1439 if( stat != IFSelect_RetDone )
1443 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
1447 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
1451 reader.SetColorMode(
true );
1452 reader.SetNameMode(
false );
1453 reader.SetLayerMode(
false );
1455 if( !reader.Transfer( doc ) )
1462 if( reader.NbShapes() < 1 )
1474 STEPCAFControl_Reader reader;
1475 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
1477 if( stat != IFSelect_RetDone )
1481 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
1485 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
1489 reader.SetColorMode(
true );
1490 reader.SetNameMode(
false );
1491 reader.SetLayerMode(
false );
1493 if( !reader.Transfer( doc ) )
1500 if( reader.NbRootsForTransfer() < 1 )
1511 Handle( TDocStd_Document )& dest,
VECTOR3D aScale )
1514 gp_GTrsf scale_transform;
1515 scale_transform.SetVectorialPart( gp_Mat( aScale.
x, 0, 0,
1518 BRepBuilderAPI_GTransform brep( scale_transform );
1521 Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
1524 TDF_LabelSequence frshapes;
1525 s_assy->GetFreeShapes( frshapes );
1528 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool ( dest->Main() );
1531 TDF_Label component = d_assy->NewShape();
1533 int nshapes = frshapes.Length();
1535 Handle( XCAFDoc_ColorTool ) scolor = XCAFDoc_DocumentTool::ColorTool( source->Main() );
1536 Handle( XCAFDoc_ColorTool ) dcolor = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
1537 TopExp_Explorer dtop;
1538 TopExp_Explorer stop;
1540 while(
id <= nshapes )
1542 TopoDS_Shape shape = s_assy->GetShape( frshapes.Value(
id ) );
1544 if( !shape.IsNull() )
1546 TopoDS_Shape scaled_shape( shape );
1548 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
1550 brep.Perform( shape, Standard_False );
1554 scaled_shape = brep.Shape();
1558 ReportMessage( wxT(
" * transfertModel(): failed to scale model\n" ) );
1560 scaled_shape = shape;
1564 TDF_Label niulab = d_assy->AddComponent( component, scaled_shape, Standard_False );
1567 stop.Init( shape, TopAbs_FACE );
1568 dtop.Init( d_assy->GetShape( niulab ), TopAbs_FACE );
1570 while( stop.More() && dtop.More() )
1572 Quantity_Color face_color;
1577 if( s_assy->FindShape( stop.Current(), tl ) )
1579 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1580 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1581 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1583 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1586 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1587 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1588 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1590 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1598 stop.Init( shape, TopAbs_SOLID );
1599 dtop.Init( d_assy->GetShape( niulab ), TopAbs_SOLID, TopAbs_FACE );
1601 while( stop.More() && dtop.More() )
1603 Quantity_Color face_color;
1608 if( s_assy->FindShape( stop.Current(), tl ) )
1610 if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
1611 || scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
1612 || scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
1614 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorGen );
1617 else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
1618 || scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
1619 || scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
1621 dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
1640 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
1646 TDF_LabelSequence freeShapes;
1647 m_assy->GetFreeShapes( freeShapes );
1653 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
1655 TDF_Label label = freeShapes.Value( i );
1657 m_assy->GetShape( label, shape );
1662 const Standard_Real linearDeflection = 0.01;
1663 const Standard_Real angularDeflection = 0.5;
1664 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
1668 wxFileName fn( aFileName );
1670 const char* tmpGltfname =
"$tempfile$.glb";
1671 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
1673 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
1674 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
1675 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
1676 RWMesh_CoordinateSystem_Zup );
1677#if OCC_VERSION_HEX >= 0x070700
1678 cafWriter.SetParallel(
true );
1680 TColStd_IndexedDataMapOfStringString metadata;
1682 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
1683 TCollection_ExtendedString( fn.GetName().wc_str() ) );
1684 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
1685 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
1686 metadata.Add( TCollection_AsciiString(
"generator" ),
1687 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
1688 metadata.Add( TCollection_AsciiString(
"generated_at" ),
1691 bool success =
true;
1694 wxString currCWD = wxGetCwd();
1695 wxString workCWD = fn.GetPath();
1697 if( !workCWD.IsEmpty() )
1698 wxSetWorkingDirectory( workCWD );
1700 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
1707 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
1709 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
1710 tmpGltfname, fn.GetFullName() ) );
1715 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.
PAD_DRILL_SHAPE_T GetDrillShape() const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
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
PAD_SHAPE GetShape() const
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon() 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 NextShape(int aPointIndex, bool aForwards=true) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
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
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.
int FullPointCount() const
Return the number of points in the shape poly set.
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 SHAPE_LINE_CHAIN & COutline(int aIndex) const
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.
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 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
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)
double EuclideanNorm(const VECTOR2I &vector)
VECTOR3< double > VECTOR3D