31#include <wx/filename.h>
33#include <wx/stdpaths.h>
34#include <wx/wfstream.h>
35#include <wx/zipstrm.h>
36#include <wx/stdstream.h>
38#include <decompress.hpp>
54#include <IGESCAFControl_Reader.hxx>
55#include <IGESCAFControl_Writer.hxx>
56#include <IGESControl_Controller.hxx>
57#include <IGESData_GlobalSection.hxx>
58#include <IGESData_IGESModel.hxx>
59#include <Interface_Static.hxx>
60#include <Quantity_Color.hxx>
61#include <STEPCAFControl_Reader.hxx>
62#include <STEPCAFControl_Writer.hxx>
63#include <APIHeaderSection_MakeHeader.hxx>
64#include <Standard_Failure.hxx>
65#include <Standard_Handle.hxx>
66#include <Standard_Version.hxx>
67#include <TCollection_ExtendedString.hxx>
68#include <TDocStd_Document.hxx>
69#include <TDocStd_XLinkTool.hxx>
70#include <TDataStd_Name.hxx>
71#include <TDataStd_TreeNode.hxx>
72#include <TDF_LabelSequence.hxx>
73#include <TDF_Tool.hxx>
74#include <TopExp_Explorer.hxx>
76#include <XCAFApp_Application.hxx>
78#include <XCAFDoc_DocumentTool.hxx>
79#include <XCAFDoc_ColorTool.hxx>
80#include <XCAFDoc_ShapeTool.hxx>
81#include <XCAFDoc_Area.hxx>
82#include <XCAFDoc_Centroid.hxx>
83#include <XCAFDoc_Location.hxx>
84#include <XCAFDoc_Volume.hxx>
86#include "KI_XCAFDoc_AssemblyGraph.hxx"
88#include <BRep_Tool.hxx>
89#include <BRepMesh_IncrementalMesh.hxx>
90#include <BRepBuilderAPI.hxx>
91#include <BRepBuilderAPI_Transform.hxx>
92#include <BRepBuilderAPI_GTransform.hxx>
93#include <BRepBuilderAPI_MakeEdge.hxx>
94#include <BRepBuilderAPI_MakeWire.hxx>
95#include <BRepBuilderAPI_MakeFace.hxx>
96#include <BRepBuilderAPI_MakeVertex.hxx>
97#include <BRepExtrema_DistShapeShape.hxx>
98#include <BRepPrimAPI_MakePrism.hxx>
99#include <BRepPrimAPI_MakeCylinder.hxx>
100#include <BRepTools.hxx>
101#include <BRepLib_MakeWire.hxx>
102#include <BRepAdaptor_Surface.hxx>
103#include <BRepAlgoAPI_Check.hxx>
104#include <BRepAlgoAPI_Cut.hxx>
105#include <BRepAlgoAPI_Fuse.hxx>
106#include <ShapeUpgrade_UnifySameDomain.hxx>
108#include <BRepBndLib.hxx>
109#include <Bnd_BoundSortBox.hxx>
111#include <Geom_Curve.hxx>
112#include <Geom_TrimmedCurve.hxx>
117#include <GC_MakeArcOfCircle.hxx>
118#include <GC_MakeCircle.hxx>
120#include <RWGltf_CafWriter.hxx>
122#if OCC_VERSION_HEX >= 0x070700
123#include <VrmlAPI_CafReader.hxx>
150 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
152 if( !lfile.FileExists() )
155 msg.Printf( wxT(
" * fileType(): no such file: %s\n" ),
156 wxString::FromUTF8Unchecked( aFileName ) );
162 wxString ext = lfile.GetExt().Lower();
164 if( ext == wxT(
"wrl" ) )
167 if( ext == wxT(
"wrz" ) )
170 if( ext == wxT(
"idf" ) )
173 if( ext == wxT(
"emn" ) )
176 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
185 memset( iline, 0, 82 );
186 ifile.getline( iline, 82 );
192 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
195 std::string fstr = iline;
199 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
205 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
220 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
221 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
222 double det = -b.
x * d.
y + d.
x * b.
y;
226 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
227 center.
y = ( b.
x * cd + d.
x * bc ) * det;
234#define APPROX_DBG( stmt )
242 static const double c_radiusDeviation = 1000.0;
243 static const double c_arcCenterDeviation = 1000.0;
244 static const double c_relLengthDeviation = 0.8;
245 static const int c_last_none = -1000;
265 int last = c_last_none;
271 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
273 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
278 bool defective =
false;
284 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
292 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
293 defective |=
std::abs( a_diff ) < 0.1;
296 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
297 defective |=
std::abs( a_diff ) >= maxAngleDiff;
308 for(
int j = i; j <= jEndIdx; j++ )
315 double rad_dev =
std::abs( radius - rad_test );
318 << int64_t( rad_test ) <<
" ref " << int64_t( radius )
321 if( rad_dev > c_radiusDeviation )
324 <<
" Radius deviation too large: " << int64_t( rad_dev )
325 <<
" > " << c_radiusDeviation << std::endl );
330 double maxAngleDiff =
331 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
333 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
334 if(
std::abs( a_diff_test ) >= maxAngleDiff )
336 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
341 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
343 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
344 <<
"; " << d01 << std::endl );
354 if( last != c_last_none )
363 int toRemove = last - ( aSrc.
PointCount() - 3 );
393 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
397 if( last == c_last_none )
414 if( iarc0 != -1 && iarc1 != -1 )
416 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
444 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
461static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
463 TDF_LabelSequence theLabels;
464 aShapeTool->GetFreeShapes( theLabels );
468 if( theLabels.Length() == 1 )
469 return aShapeTool->GetShape( theLabels.Value( 1 ) );
471 TopoDS_Compound aCompound;
472 BRep_Builder aBuilder;
473 aBuilder.MakeCompound( aCompound );
475 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
477 TopoDS_Shape aFreeShape;
479 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
482 aBuilder.Add( aCompound, aFreeShape );
485 if( aCompound.NbChildren() > 0 )
494static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
496 if( theLabel.IsNull() )
498 Message::SendFail(
"Null label." );
499 return Standard_False;
502 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
503 || Abs( aScale.Z() ) <= gp::Resolution() )
505 Message::SendFail(
"Scale factor is too small." );
506 return Standard_False;
509 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
510 if( aShapeTool.IsNull() )
512 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
513 return Standard_False;
516 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
519 Message::SendFail(
"Couldn't create assembly graph." );
520 return Standard_False;
523 Standard_Boolean anIsDone = Standard_True;
527 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
529 0, 0, aScale.Z() ) );
532 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
534 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
536 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
538 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
539 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
544 const TDF_Label& aLabel = aG->GetNode( idx );
546 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
548 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
549 aBRepTrsf.Perform( aShape, Standard_True );
550 if( !aBRepTrsf.IsDone() )
552 Standard_SStream aSS;
553 TCollection_AsciiString anEntry;
554 TDF_Tool::Entry( aLabel, anEntry );
555 aSS <<
"Shape " << anEntry <<
" is not scaled!";
556 Message::SendFail( aSS.str().c_str() );
557 anIsDone = Standard_False;
558 return Standard_False;
560 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
561 aShapeTool->SetShape( aLabel, aScaledShape );
564 TDF_LabelSequence aSubshapes;
565 aShapeTool->GetSubShapes( aLabel, aSubshapes );
566 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
568 const TDF_Label& aLSs = anItSs.Value();
569 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
570 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
571 aShapeTool->SetShape( aLSs, aSs1 );
575 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
576 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
577 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
579 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
581 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
582 gp_Trsf aTrsf = aLoc.Transformation();
583 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
584 XCAFDoc_Location::Set( aLabel, aTrsf );
590 return Standard_False;
593 aShapeTool->UpdateAssemblies();
601 const TCollection_ExtendedString& aPrefix )
603 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
607 Message::SendFail(
"Couldn't create assembly graph." );
608 return Standard_False;
611 Standard_Boolean anIsDone = Standard_True;
613 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
615 const TDF_Label& lbl = aG->GetNode( idx );
616 Handle( TDataStd_Name ) nameHandle;
618 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
620 TCollection_ExtendedString
name;
624 name += nameHandle->Get();
627 TDataStd_Name::Set( lbl,
name );
631 TDataStd_Name::Set( lbl, aPrefix );
641 m_app = XCAFApp_Application::GetApplication();
642 m_app->NewDocument(
"MDTV-XCAF", m_doc );
643 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
662 if( m_doc->CanClose() == CDM_CCS_OK )
679 TopoDS_Shape curr_shape;
681 double Zpos, thickness;
687 if( pcb_layer ==
F_Cu )
689 else if( pcb_layer ==
B_Cu )
693 TopoDS_Shape testShape;
698 wxCHECK( effShapePtr->Type() == SHAPE_TYPE::SH_COMPOUND,
false );
701 std::vector<TopoDS_Shape> topodsShapes;
705 if( shape->Type() == SHAPE_TYPE::SH_SEGMENT || shape->Type() == SHAPE_TYPE::SH_CIRCLE )
710 if( shape->Type() == SHAPE_TYPE::SH_SEGMENT )
718 else if( shape->Type() == SHAPE_TYPE::SH_CIRCLE )
726 TopoDS_Shape topods_shape;
731 topodsShapes.emplace_back( topods_shape );
733 if( testShape.IsNull() )
736 Zpos + thickness, aOrigin );
749 success &=
MakeShapes( topodsShapes, polySet,
false, thickness, Zpos, aOrigin );
751 if( testShape.IsNull() )
753 std::vector<TopoDS_Shape> testShapes;
755 MakeShapes( testShapes, polySet,
false, 0.0, Zpos + thickness, aOrigin );
757 if( testShapes.size() > 0 )
758 testShape = testShapes.front();
764 if( topodsShapes.size() == 1 )
770 BRepAlgoAPI_Fuse mkFuse;
771 TopTools_ListOfShape shapeArguments, shapeTools;
773 for( TopoDS_Shape& sh : topodsShapes )
778 if( shapeArguments.IsEmpty() )
779 shapeArguments.Append( sh );
781 shapeTools.Append( sh );
784 mkFuse.SetRunParallel(
true );
785 mkFuse.SetToFillHistory(
false );
786 mkFuse.SetArguments( shapeArguments );
787 mkFuse.SetTools( shapeTools );
790 if( mkFuse.IsDone() )
792 TopoDS_Shape fusedShape = mkFuse.Shape();
794 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
795 unify.History() =
nullptr;
798 TopoDS_Shape unifiedShapes = unify.Shape();
800 if( !unifiedShapes.IsNull() )
807 _(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) );
813 for( TopoDS_Shape& sh : topodsShapes )
818 if( !aVia && !testShape.IsNull() )
820 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
826 if( pcb_layer ==
F_Cu )
828 else if( pcb_layer ==
B_Cu )
845 double f_pos, f_thickness;
846 double b_pos, b_thickness;
849 double top = std::max( f_pos, f_pos + f_thickness );
850 double bottom = std::min( b_pos, b_pos + b_thickness );
852 TopoDS_Shape plating;
858 ( top - bottom ), bottom, aOrigin ) )
869 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
904 double zposition, thickness;
908 aTrack->
GetWidth(), thickness, zposition, aOrigin );
921 static const double c_silkscreenAboveCopper = 0.04;
922 static const double c_soldermaskAboveCopper = 0.015;
930 double f_pos, f_thickness;
932 double top = std::max( f_pos, f_pos + f_thickness );
935 aZPos = top + c_silkscreenAboveCopper;
937 aZPos = top + c_soldermaskAboveCopper;
943 double b_pos, b_thickness;
945 double bottom = std::min( b_pos, b_pos + b_thickness );
948 aZPos = bottom - c_silkscreenAboveCopper;
950 aZPos = bottom - c_soldermaskAboveCopper;
962 bool wasPrepreg =
false;
967 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1013 double f_pos, f_thickness;
1014 double b_pos, b_thickness;
1017 double top = std::min( f_pos, f_pos + f_thickness );
1018 double bottom = std::max( b_pos, b_pos + b_thickness );
1020 aThickness = ( top - bottom );
1023 wxASSERT( aZPos == 0.0 );
1028 const VECTOR2D& aOrigin,
bool aTrack )
1030 bool success =
true;
1038 double z_pos, thickness;
1042 thickness, z_pos, aOrigin ) )
1045 wxString::Format( wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
1060 const double margin = 0.01;
1064 double f_pos, f_thickness;
1065 double b_pos, b_thickness;
1068 double top = std::max( f_pos, f_pos + f_thickness );
1069 double bottom = std::min( b_pos, b_pos + b_thickness );
1071 double holeZsize = ( top - bottom ) + ( margin * 2 );
1078 double copperDrill = boardDrill - platingThickness * 2;
1080 TopoDS_Shape copperHole, boardHole;
1083 copperDrill, holeZsize, bottom - margin, aOrigin ) )
1093 holeZsize, bottom - margin, aOrigin ) )
1110 if( aFileNameUTF8.empty() )
1112 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
1116 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1117 ReportMessage( wxString::Format( wxT(
"Add component %s.\n" ), aRefDes ) );
1121 wxString errorMessage;
1123 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1125 if( errorMessage.IsEmpty() )
1126 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
1134 TopLoc_Location toploc;
1136 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1139 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
1144 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1146 if( llabel.IsNull() )
1148 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
1154 TCollection_ExtendedString refdes( aRefDes.c_str() );
1155 TDataStd_Name::Set( llabel, refdes );
1221 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
1223 if( arcs.size() == 1 )
1227 if( arc. GetP0() == arc.
GetP1() )
1238 double aZposition,
const VECTOR2D& aOrigin )
1240 if( !aShape.IsNull() )
1246 const std::vector<SHAPE_ARC>& arcs = aChain.
CArcs();
1249 TopoDS_Shape base_shape;
1250 base_shape = BRepPrimAPI_MakeCylinder(
1256 BRepBuilderAPI_Transform round_shape( base_shape, shift );
1257 aShape = round_shape;
1259 if( aShape.IsNull() )
1261 ReportMessage( wxT(
"failed to create a cylinder vertical shape\n" ) );
1271 double aWidth,
double aThickness,
1272 double aZposition,
const VECTOR2D& aOrigin )
1280 double h_width = aWidth/2.0;
1282 coords[0] =
VECTOR2D{ 0.0, h_width };
1285 coords[1] =
VECTOR2D{ len, h_width };
1288 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1291 coords[3] =
VECTOR2D{ len, -h_width };
1294 coords[4] =
VECTOR2D{ 0, -h_width };
1297 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1300 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1302 for(
int ii = 0; ii < 6; ii++ )
1305 coords[ii] += aStartPoint;
1310 gp_Pnt coords3D[ 6 ];
1312 for(
int ii = 0; ii < 6; ii++ )
1319 BRepBuilderAPI_MakeWire wire;
1320 bool success =
true;
1332 Handle( Geom_Circle ) circle = GC_MakeCircle( coords3D[1],
1337 edge = BRepBuilderAPI_MakeEdge( circle );
1342 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1345 Handle( Geom_TrimmedCurve ) arcOfCircle =
1346 GC_MakeArcOfCircle( coords3D[1],
1350 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1353 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1356 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1357 GC_MakeArcOfCircle( coords3D[4],
1361 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1365 catch(
const Standard_Failure& e )
1367 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
1368 e.GetMessageString() ) );
1373 BRepBuilderAPI_MakeFace face;
1377 gp_Pln plane( coords3D[0], gp::DZ() );
1378 face = BRepBuilderAPI_MakeFace( plane, wire );
1380 catch(
const Standard_Failure& e )
1382 ReportMessage( wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
1383 e.GetMessageString() ) );
1387 if( aThickness != 0.0 )
1389 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1391 if( aShape.IsNull() )
1393 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
1411 str <<
"x0: " <<
up.StringFromValue( aBBox.
GetLeft(),
false ) <<
"; ";
1412 str <<
"y0: " <<
up.StringFromValue( aBBox.
GetTop(),
false ) <<
"; ";
1413 str <<
"x1: " <<
up.StringFromValue( aBBox.
GetRight(),
false ) <<
"; ";
1414 str <<
"y1: " <<
up.StringFromValue( aBBox.
GetBottom(),
false );
1421 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
1426 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1434 auto makeWireFromChain = [&]( BRepLib_MakeWire& aMkWire,
1444 gp_Pnt start = toPoint( aPt0 );
1445 gp_Pnt end = toPoint( aPt1 );
1449 double seg_len = std::hypot( end.X() - start.X(), end.Y() - start.Y() );
1454 BRepBuilderAPI_MakeEdge mkEdge( start, end );
1456 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1458 ReportMessage( wxString::Format( wxT(
"failed to make segment edge at (%d "
1459 "%d) -> (%d %d), skipping\n" ),
1460 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1464 aMkWire.Add( mkEdge.Edge() );
1466 if( aMkWire.Error() != BRepLib_WireDone )
1468 ReportMessage( wxString::Format( wxT(
"failed to add segment edge "
1469 "at (%d %d) -> (%d %d)\n" ),
1470 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1481 Handle( Geom_Curve ) curve;
1483 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1485 gp_Ax2 axis = gp::XOY();
1486 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1493 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1494 toPoint( aArc.GetP1() ) )
1498 if( curve.IsNull() )
1501 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1503 if( !aMkWire.IsDone() )
1506 wxT(
"failed to add arc curve from (%d %d), arc p0 "
1507 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1508 aPt0.
x, aPt0.
y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x,
1509 aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) );
1518 bool isFirstShape =
true;
1532 if( nextShape != -1 )
1538 lastPt = aChain.
CPoint( i );
1548 firstPt = currentArc.
GetP0();
1553 lastPt = currentArc.
GetP0();
1555 if( addArc( lastPt, currentArc ) )
1556 lastPt = currentArc.
GetP1();
1575 isFirstShape =
false;
1578 if( lastPt != firstPt )
1581 catch(
const Standard_Failure& e )
1583 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
1584 e.GetMessageString() ) );
1591 auto tryMakeWire = [&makeWireFromChain,
1595 BRepLib_MakeWire mkWire;
1597 makeWireFromChain( mkWire, aContour );
1599 if( mkWire.IsDone() )
1601 wire = mkWire.Wire();
1606 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n" ),
1607 static_cast<int>( aContour.PointCount() ),
1608 static_cast<int>( mkWire.Error() ) ) );
1610 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1614 if( !wire.IsNull() )
1616 BRepAlgoAPI_Check check( wire,
false,
true );
1619 if( !check.IsValid() )
1621 ReportMessage( wxString::Format(
_(
"\nWire self-interference check "
1624 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1634 BRepBuilderAPI_MakeFace mkFace;
1636 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1643 if( aConvertToArcs )
1649 wire = tryMakeWire( polygon[contId] );
1651 if( aConvertToArcs && !wire.IsNull() )
1652 ReportMessage( wxString::Format(
_(
"Using non-simplified polygon.\n" ) ) );
1657 if( !wire.IsNull() )
1658 mkFace = BRepBuilderAPI_MakeFace( wire );
1661 ReportMessage( wxString::Format(
_(
"\n** Outline skipped **\n" ) ) );
1663 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ),
1672 if( !wire.IsNull() )
1676 ReportMessage( wxString::Format(
_(
"\n** Hole skipped **\n" ) ) );
1678 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ),
1684 catch(
const Standard_Failure& e )
1687 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
1688 static_cast<int>( contId ), e.GetMessageString() ) );
1693 if( mkFace.IsDone() )
1695 if( aThickness != 0.0 )
1697 TopoDS_Shape prism = BRepPrimAPI_MakePrism( mkFace, gp_Vec( 0, 0, aThickness ) );
1698 aShapes.push_back( prism );
1700 if( prism.IsNull() )
1702 ReportMessage( wxT(
"Failed to create a prismatic shape\n" ) );
1708 aShapes.push_back( mkFace );
1731 Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
1735 ReportMessage( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1738 double boardThickness;
1753 wxT(
"OCC error creating main outline.\n" ) ) );
1759 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1763 polyset.
Append( contour );
1770 ReportMessage( wxT(
"OCC error creating main outline.\n" ) );
1778 ReportMessage( wxT(
"OCC error creating hole in main outline.\n" ) );
1789 BRepBndLib::Add( brdShape, brdBndBox );
1792 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1795 auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1799 Bnd_Box brdWithHolesBndBox = brdBndBox;
1801 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1803 for(
size_t i = 0; i < input.size(); i++ )
1806 BRepBndLib::Add( input[i], bbox );
1807 brdWithHolesBndBox.Add( bbox );
1808 ( *holeBoxSet )[i] = bbox;
1811 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1814 auto subtractShapes = [](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
1815 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
1819 for( TopoDS_Shape& shape : aShapesList )
1822 BRepBndLib::Add( shape, shapeBbox );
1824 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
1826 TopTools_ListOfShape holelist;
1828 for(
const Standard_Integer& index : indices )
1829 holelist.Append( aHolesList[index] );
1832 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
1838 (
int) aShapesList.size(), aWhat ) );
1840 if( holelist.IsEmpty() )
1843 TopTools_ListOfShape cutArgs;
1844 cutArgs.Append( shape );
1846 BRepAlgoAPI_Cut
cut;
1848 cut.SetRunParallel(
true );
1849 cut.SetToFillHistory(
false );
1851 cut.SetArguments( cutArgs );
1852 cut.SetTools( holelist );
1855 if(
cut.HasErrors() ||
cut.HasWarnings() )
1858 _(
"\n** Got problems while cutting %s number %d **\n" ), aWhat, cnt ) );
1861 if(
cut.HasErrors() )
1864 cut.DumpErrors( std::cout );
1867 if(
cut.HasWarnings() )
1870 cut.DumpWarnings( std::cout );
1876 shape =
cut.Shape();
1882 Bnd_BoundSortBox bsbHoles;
1890 Bnd_BoundSortBox bsbHoles;
1901 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_Color aColor,
1902 const wxString& aShapeName )
1905 for( TopoDS_Shape& shape : aShapesList )
1907 Handle( TDataStd_TreeNode ) node;
1910 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
1916 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
1917 TDF_Label shpLbl = node->Father()->Label();
1918 if( !shpLbl.IsNull() )
1920 colorTool->SetColor( shpLbl, aColor, XCAFDoc_ColorSurf );
1923 if( aShapesList.size() > 1 )
1925 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
1929 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
1933 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
1934 TDataStd_Name::Set( shpLbl, partname );
1958 auto iterateCopperItems = [
this]( std::function<void( TopoDS_Shape& )> aFn )
1970 BRepAlgoAPI_Fuse mkFuse;
1971 TopTools_ListOfShape shapeArguments, shapeTools;
1974 [&]( TopoDS_Shape& sh )
1979 if( shapeArguments.IsEmpty() )
1980 shapeArguments.Append( sh );
1982 shapeTools.Append( sh );
1985 mkFuse.SetRunParallel(
true );
1986 mkFuse.SetToFillHistory(
false );
1987 mkFuse.SetArguments( shapeArguments );
1988 mkFuse.SetTools( shapeTools );
1991 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
1993 ReportMessage(
_(
"** Got problems while fusing shapes **\n" ) );
1995 if( mkFuse.HasErrors() )
1998 mkFuse.DumpErrors( std::cout );
2001 if( mkFuse.HasWarnings() )
2004 mkFuse.DumpWarnings( std::cout );
2010 if( mkFuse.IsDone() )
2014 TopoDS_Shape fusedShape = mkFuse.Shape();
2016 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
2017 unify.History() =
nullptr;
2020 TopoDS_Shape unifiedShapes = unify.Shape();
2022 if( !unifiedShapes.IsNull() )
2028 ReportMessage(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) );
2043 if( aPushBoardBody )
2046#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2047 m_assy->UpdateAssemblies();
2056bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2060 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2066 wxFileName fn( aFileName );
2067 IGESControl_Controller::Init();
2068 IGESCAFControl_Writer writer;
2069 writer.SetColorMode( Standard_True );
2070 writer.SetNameMode( Standard_True );
2071 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2072 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2073 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2074 header.SetAuthorName(
2075 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2076 header.SetCompanyName(
2077 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2078 writer.Model()->SetGlobalSection( header );
2080 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2092 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2098 wxFileName fn( aFileName );
2100 STEPCAFControl_Writer writer;
2101 writer.SetColorMode( Standard_True );
2102 writer.SetNameMode( Standard_True );
2109 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2110 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
2114 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2115 ReportMessage( wxT(
"Failed to set surface curve mode, but will attempt to continue." ) );
2117 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2120 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2124 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2127 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2128 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2129 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2130 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2132 bool success =
true;
2135 wxString currCWD = wxGetCwd();
2136 wxString workCWD = fn.GetPath();
2138 if( !workCWD.IsEmpty() )
2139 wxSetWorkingDirectory( workCWD );
2141 char tmpfname[] =
"$tempfile$.step";
2143 if( Standard_False == writer.Write( tmpfname ) )
2152 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2154 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2156 fn.GetFullName() ) );
2161 wxSetWorkingDirectory( currCWD );
2171 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2178 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2183 wxFileName fn( aFileName );
2185 wxFFileOutputStream ffStream( fn.GetFullPath() );
2186 wxStdOutputStream stdStream( ffStream );
2188#if OCC_VERSION_HEX >= 0x070600
2189 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2191 BRepTools::Write( shape, stdStream );
2200 wxFileName fn( aFileName );
2202 wxFFileOutputStream ffStream( fn.GetFullPath() );
2203 wxStdOutputStream file( ffStream );
2205 if( !ffStream.IsOk() )
2207 ReportMessage( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ) );
2212 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2217 std::map<wxString, std::vector<int>> groups[4];
2218 TopExp_Explorer exp;
2221 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2223 TopoDS_Shape subShape = exp.Current();
2226 BRepBndLib::Add( subShape, bbox );
2230 const auto& [point, padTestShape] = pair;
2232 if( bbox.IsOut( point ) )
2235 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2237 if( surface.GetType() != GeomAbs_Plane )
2240 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2243 if( !dist.IsDone() )
2246 if( dist.Value() < Precision::Approximation() )
2249 groups[2][padKey].push_back( faceIndex );
2257 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2258 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2259 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2260 file <<
" <shape format=\"BREP\"><![CDATA[";
2261#if OCC_VERSION_HEX < 0x070600
2262 BRepTools::Write( shape, file );
2264 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2266 file <<
"]]></shape>" << std::endl;
2267 file <<
" <topology>" << std::endl;
2269 TopTools_IndexedMapOfShape mainMap;
2270 TopExp::MapShapes( shape, mainMap );
2271 std::set<int> topo[4];
2273 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2276 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2277 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2279 for(
int dim = 0; dim < 4; dim++ )
2281 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2283 TopoDS_Shape subShape = exp.Current();
2284 int idx = mainMap.FindIndex( subShape );
2286 if( idx && !topo[dim].count( idx ) )
2287 topo[dim].insert( idx );
2291 for(
int dim = 0; dim <= 3; dim++ )
2293 std::string labels = c_dimLabels[dim];
2294 std::string label = c_dimLabel[dim];
2296 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2299 for(
auto p : topo[dim] )
2301 std::string
name(
"" );
2302 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2303 <<
"name=\"" <<
name <<
"\" "
2304 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2308 file <<
" </" << labels <<
">" << std::endl;
2311 file <<
" </topology>" << std::endl;
2312 file <<
" </geometry>" << std::endl;
2313 file <<
" <groups count=\""
2314 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2316 for(
int dim = 0; dim <= 3; dim++ )
2318 std::string label = c_dimLabel[dim];
2320 for(
auto g : groups[dim] )
2323 wxString
name = g.first;
2327 std::ostringstream gs;
2328 gs <<
"G_" << dim <<
"D_" << g.first;
2331 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2337 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2338 for(
auto index : g.second )
2340 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2342 file <<
" </group>" << std::endl;
2345 file <<
" </groups>" << std::endl;
2346 file <<
" <fields count=\"0\"/>" << std::endl;
2347 file <<
"</XAO>" << std::endl;
2354 bool aSubstituteModels, wxString* aErrorMessage )
2356 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2357 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2359 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2363 aLabel = mm->second;
2369 Handle( TDocStd_Document ) doc;
2370 m_app->NewDocument(
"MDTV-XCAF", doc );
2372 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2378 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2380 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2387 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2389 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2399 wxFFileInputStream ifile( fileName );
2400 wxFileName outFile( fileName );
2402 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2403 outFile.SetExt( wxT(
"step" ) );
2404 wxFileOffset size = ifile.GetLength();
2406 if( size == wxInvalidOffset )
2408 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2414 bool success =
false;
2415 wxFFileOutputStream ofile( outFile.GetFullPath() );
2420 char* buffer =
new char[size];
2422 ifile.Read( buffer, size );
2423 std::string expanded;
2427 expanded = gzip::decompress( buffer, size );
2432 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2436 if( expanded.empty() )
2440 wxZipInputStream izipfile( ifile );
2441 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2443 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2445 izipfile.Read( ofile );
2451 ofile.Write( expanded.data(), expanded.size() );
2459 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2480 if( aSubstituteModels )
2482 wxFileName wrlName( fileName );
2484 wxString basePath = wrlName.GetPath();
2485 wxString baseName = wrlName.GetName();
2493 alts.Add( wxT(
"stp" ) );
2494 alts.Add( wxT(
"step" ) );
2495 alts.Add( wxT(
"STP" ) );
2496 alts.Add( wxT(
"STEP" ) );
2497 alts.Add( wxT(
"Stp" ) );
2498 alts.Add( wxT(
"Step" ) );
2499 alts.Add( wxT(
"stpz" ) );
2500 alts.Add( wxT(
"stpZ" ) );
2501 alts.Add( wxT(
"STPZ" ) );
2502 alts.Add( wxT(
"step.gz" ) );
2503 alts.Add( wxT(
"stp.gz" ) );
2506 alts.Add( wxT(
"iges" ) );
2507 alts.Add( wxT(
"IGES" ) );
2508 alts.Add( wxT(
"igs" ) );
2509 alts.Add( wxT(
"IGS" ) );
2513 for(
const auto& alt : alts )
2515 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2517 if( altFile.IsOk() && altFile.FileExists() )
2519 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2537 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2539 Handle( XCAFDoc_ShapeTool ) shapeTool =
2540 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2543 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2547 ReportMessage( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2555 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2570 if( aLabel.IsNull() )
2572 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
2579 wxFileName afile( fileName );
2580 std::string pname( afile.GetName().ToUTF8() );
2581 TCollection_ExtendedString partname( pname.c_str() );
2582 TDataStd_Name::Set( aLabel, partname );
2591 TopLoc_Location& aLocation )
2605 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2610 double boardThickness;
2613 double top = std::max( boardZPos, boardZPos + boardThickness );
2614 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2620 aOffset.
z -= bottom;
2621 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2622 lPos.Multiply( lRot );
2623 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
2624 lPos.Multiply( lRot );
2629 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2630 lPos.Multiply( lRot );
2634 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
2635 lPos.Multiply( lOff );
2638 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
2640 lPos.Multiply( lOrient );
2641 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
2643 lPos.Multiply( lOrient );
2644 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
2646 lPos.Multiply( lOrient );
2648 aLocation = TopLoc_Location( lPos );
2655 IGESControl_Controller::Init();
2656 IGESCAFControl_Reader reader;
2657 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2659 if( stat != IFSelect_RetDone )
2663 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2667 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2671 reader.SetColorMode(
true );
2672 reader.SetNameMode(
false );
2673 reader.SetLayerMode(
false );
2675 if( !reader.Transfer( doc ) )
2677 if( doc->CanClose() == CDM_CCS_OK )
2684 if( reader.NbShapes() < 1 )
2686 if( doc->CanClose() == CDM_CCS_OK )
2698 STEPCAFControl_Reader reader;
2699 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2701 if( stat != IFSelect_RetDone )
2705 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2709 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2713 reader.SetColorMode(
true );
2714 reader.SetNameMode(
true );
2715 reader.SetLayerMode(
false );
2717 if( !reader.Transfer( doc ) )
2719 if( doc->CanClose() == CDM_CCS_OK )
2726 if( reader.NbRootsForTransfer() < 1 )
2728 if( doc->CanClose() == CDM_CCS_OK )
2740#if OCC_VERSION_HEX >= 0x070700
2741 VrmlAPI_CafReader reader;
2742 RWMesh_CoordinateSystemConverter conv;
2743 conv.SetInputLengthUnit( 2.54 );
2744 reader.SetCoordinateSystemConverter( conv );
2745 reader.SetDocument( doc );
2747 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
2758 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
2762 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
2765 TDF_LabelSequence frshapes;
2766 s_assy->GetFreeShapes( frshapes );
2769 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
2772 TDF_Label d_targetLabel = d_assy->NewShape();
2774 if( frshapes.Size() == 1 )
2776 TDocStd_XLinkTool link;
2777 link.Copy( d_targetLabel, frshapes.First() );
2782 for( TDF_Label& s_shapeLabel : frshapes )
2784 TDF_Label d_component = d_assy->NewShape();
2786 TDocStd_XLinkTool link;
2787 link.Copy( d_component, s_shapeLabel );
2789 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
2793 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
2796 return d_targetLabel;
2804 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2810 TDF_LabelSequence freeShapes;
2811 m_assy->GetFreeShapes( freeShapes );
2817 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
2819 TDF_Label label = freeShapes.Value( i );
2821 m_assy->GetShape( label, shape );
2826 const Standard_Real linearDeflection = 0.01;
2827 const Standard_Real angularDeflection = 0.5;
2828 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
2832 wxFileName fn( aFileName );
2834 const char* tmpGltfname =
"$tempfile$.glb";
2835 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
2837 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
2838 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
2839 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
2840 RWMesh_CoordinateSystem_Zup );
2841#if OCC_VERSION_HEX >= 0x070700
2842 cafWriter.SetParallel(
true );
2844 TColStd_IndexedDataMapOfStringString metadata;
2846 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
2847 TCollection_ExtendedString( fn.GetName().wc_str() ) );
2848 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
2849 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
2850 metadata.Add( TCollection_AsciiString(
"generator" ),
2851 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
2852 metadata.Add( TCollection_AsciiString(
"generated_at" ),
2855 bool success =
true;
2858 wxString currCWD = wxGetCwd();
2859 wxString workCWD = fn.GetPath();
2861 if( !workCWD.IsEmpty() )
2862 wxSetWorkingDirectory( workCWD );
2864 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
2871 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
2873 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2874 tmpGltfname, fn.GetFullName() ) );
2879 wxSetWorkingDirectory( currCWD );
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
@ BS_ITEM_TYPE_DIELECTRIC
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetShortNetname() const
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
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.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
coord_type GetTop() const
coord_type GetRight() const
coord_type GetLeft() const
coord_type GetBottom() const
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
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
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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 & GetArcMid() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
const VECTOR2I GetCenter() const
const std::vector< SHAPE * > & Shapes() 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 SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
const std::vector< SHAPE_ARC > & CArcs() const
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.
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.
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.
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
const std::vector< POLYGON > & CPolygons() const
const SEG & GetSeg() const
An abstract shape on 2D plane.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
bool CreatePCB(SHAPE_POLY_SET &aOutline, VECTOR2D aOrigin, bool aPushBoardBody)
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
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_copper_fused
void SetFuseShapes(bool aValue)
bool WriteXAO(const wxString &aFileName)
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 ...
void getLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
STEP_PCB_MODEL(const wxString &aPcbName)
std::vector< TopoDS_Shape > m_board_outlines
void SetBoardColor(double r, double g, double b)
bool AddViaShape(const PCB_VIA *aVia, const VECTOR2D &aOrigin)
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetEnabledLayers(const LSET &aLayers)
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
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
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia)
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)
bool getModelLabel(const std::string &aFileNameUTF8, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool WriteSTEP(const wxString &aFileName, bool aOptimize)
std::vector< TopoDS_Shape > m_copperCutouts
std::vector< TopoDS_Shape > m_board_copper_pads
std::vector< TopoDS_Shape > m_board_copper_zones
std::map< wxString, std::pair< gp_Pnt, TopoDS_Shape > > m_pad_points
void getCopperLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, 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)
bool AddCopperPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, bool aTrack)
bool WriteBREP(const wxString &aFileName)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
static constexpr EDA_ANGLE ANGLE_360
void ReportMessage(const wxString &aMessage)
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)
Tests 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)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
std::vector< FAB_LAYER_COLOR > dummy
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)
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 constexpr double USER_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
static constexpr double ARC_TO_SEGMENT_MAX_ERROR_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