34#include <wx/filename.h>
36#include <wx/sstream.h>
37#include <wx/stdpaths.h>
40#include <wx/zstream.h>
41#include <wx/wfstream.h>
42#include <wx/zipstrm.h>
43#include <wx/stdstream.h>
46#include <decompress.hpp>
73#include <IGESCAFControl_Reader.hxx>
74#include <IGESCAFControl_Writer.hxx>
75#include <IGESControl_Controller.hxx>
76#include <IGESData_GlobalSection.hxx>
77#include <IGESData_IGESModel.hxx>
78#include <Interface_Static.hxx>
79#include <Quantity_Color.hxx>
80#include <STEPCAFControl_Reader.hxx>
81#include <STEPCAFControl_Writer.hxx>
82#include <APIHeaderSection_MakeHeader.hxx>
83#include <Standard_Failure.hxx>
84#include <Standard_Handle.hxx>
85#include <Standard_Version.hxx>
86#include <TCollection_ExtendedString.hxx>
87#include <TDocStd_Document.hxx>
88#include <TDataStd_Name.hxx>
89#include <TDataStd_TreeNode.hxx>
90#include <TDF_ChildIterator.hxx>
91#include <NCollection_Sequence.hxx>
92#include <TColStd_IndexedDataMapOfStringString.hxx>
93#include <TDF_Tool.hxx>
94#include <TopTools_IndexedMapOfShape.hxx>
95#include <TopExp_Explorer.hxx>
97#include <XCAFApp_Application.hxx>
99#include <XCAFDoc_DocumentTool.hxx>
100#include <XCAFDoc_ColorTool.hxx>
101#include <XCAFDoc_ShapeTool.hxx>
102#include <XCAFDoc_VisMaterialTool.hxx>
103#include <XCAFDoc_Area.hxx>
104#include <XCAFDoc_Centroid.hxx>
105#include <XCAFDoc_Editor.hxx>
106#include <XCAFDoc_Location.hxx>
107#include <XCAFDoc_Volume.hxx>
110#include "KI_XCAFDoc_AssemblyGraph.hxx"
112#include <BRep_Tool.hxx>
113#include <BRepMesh_IncrementalMesh.hxx>
114#include <BRepBuilderAPI_GTransform.hxx>
115#include <BRepBuilderAPI_MakeEdge.hxx>
116#include <BRepBuilderAPI_MakeWire.hxx>
117#include <BRepBuilderAPI_MakeFace.hxx>
118#include <BRepExtrema_DistShapeShape.hxx>
119#include <BRepPrimAPI_MakeCone.hxx>
120#include <BRepPrimAPI_MakeCylinder.hxx>
121#include <BRepPrimAPI_MakePrism.hxx>
122#include <BRepTools.hxx>
123#include <BRepLib_MakeWire.hxx>
124#include <BRepAdaptor_Surface.hxx>
125#include <BRepAlgoAPI_Check.hxx>
126#include <BRepAlgoAPI_Cut.hxx>
127#include <BRepAlgoAPI_Fuse.hxx>
128#include <ShapeUpgrade_UnifySameDomain.hxx>
130#include <BRepBndLib.hxx>
131#include <Bnd_BoundSortBox.hxx>
132#include <Bnd_HArray1OfBox.hxx>
133#include <GProp_GProps.hxx>
134#include <BRepGProp.hxx>
136#include <Geom_Curve.hxx>
137#include <Geom_TrimmedCurve.hxx>
142#include <GC_MakeArcOfCircle.hxx>
143#include <GC_MakeCircle.hxx>
145#include <RWGltf_CafWriter.hxx>
146#include <StlAPI_Writer.hxx>
148#if OCC_VERSION_HEX >= 0x070700
149#include <VrmlAPI_CafReader.hxx>
150#include <RWPly_CafWriter.hxx>
178 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
180 if( !lfile.FileExists() )
183 wxString ext = lfile.GetExt().Lower();
185 if( ext == wxT(
"wrl" ) )
188 if( ext == wxT(
"wrz" ) )
191 if( ext == wxT(
"idf" ) )
194 if( ext == wxT(
"emn" ) )
197 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
211 const int max_line_count = 3;
213 for(
int ii = 0; ii < max_line_count; ii++ )
215 memset( iline, 0, 82 );
216 ifile.getline( iline, 82 );
222 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
228 std::string fstr = iline;
232 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
241 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
248 if( strncmp( iline,
"/*", 2 ) != 0 )
266 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
267 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
268 double det = -b.
x * d.
y + d.
x * b.
y;
272 center.x = ( -bc * d.
y - cd * b.
y ) * det;
273 center.y = ( b.
x * cd + d.
x * bc ) * det;
280#define APPROX_DBG( stmt )
288 static const double c_radiusDeviation = 1000.0;
289 static const double c_arcCenterDeviation = 1000.0;
290 static const double c_relLengthDeviation = 0.8;
291 static const int c_last_none = -1000;
293 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
294 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
311 int last = c_last_none;
317 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
319 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
324 bool defective =
false;
330 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
338 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
339 defective |=
std::abs( a_diff ) < 0.1;
342 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
343 defective |=
std::abs( a_diff ) >= maxAngleDiff;
354 for(
int j = i; j <= jEndIdx; j++ )
359 double rad_test = ( p_test -
center ).EuclideanNorm();
360 double d_tl = ( p_test - p_prev ).EuclideanNorm();
364 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
367 if( rad_dev > c_radiusDeviation )
370 <<
" Radius deviation too large: " << int64_t( rad_dev )
371 <<
" > " << c_radiusDeviation << std::endl );
376 double maxAngleDiff =
377 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
379 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
380 if(
std::abs( a_diff_test ) >= maxAngleDiff )
382 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
387 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
389 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
390 <<
"; " << d01 << std::endl );
400 if( last != c_last_none )
409 int toRemove = last - ( aSrc.
PointCount() - 3 );
439 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
443 if( last == c_last_none )
460 if( iarc0 != -1 && iarc1 != -1 )
462 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
472 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
490 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
491 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
509 NCollection_Sequence<TDF_Label> theLabels;
510 aShapeTool->GetFreeShapes( theLabels );
514 if( theLabels.Length() == 1 )
515 return aShapeTool->GetShape( theLabels.Value( 1 ) );
517 TopoDS_Compound aCompound;
518 BRep_Builder aBuilder;
519 aBuilder.MakeCompound( aCompound );
521 for( NCollection_Sequence<TDF_Label>::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
523 TopoDS_Shape aFreeShape;
525 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
528 aBuilder.Add( aCompound, aFreeShape );
531 if( aCompound.NbChildren() > 0 )
542 if( theLabel.IsNull() )
544 Message::SendFail(
"Null label." );
548 if(
std::abs( aScale.X() ) <= gp::Resolution() ||
std::abs( aScale.Y() ) <= gp::Resolution()
549 ||
std::abs( aScale.Z() ) <= gp::Resolution() )
551 Message::SendFail(
"Scale factor is too small." );
555 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
557 if( aShapeTool.IsNull() )
559 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
563 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
567 Message::SendFail(
"Couldn't create assembly graph." );
571 bool anIsDone =
true;
575 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
577 0, 0, aScale.Z() ) );
580 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
582 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
584 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
586 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
587 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
592 const TDF_Label& aLabel = aG->GetNode( idx );
594 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
596 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
597 aBRepTrsf.Perform( aShape,
true );
598 if( !aBRepTrsf.IsDone() )
600 Standard_SStream aSS;
601 TCollection_AsciiString anEntry;
602 TDF_Tool::Entry( aLabel, anEntry );
603 aSS <<
"Shape " << anEntry <<
" is not scaled!";
604 Message::SendFail( aSS.str().c_str() );
608 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
609 aShapeTool->SetShape( aLabel, aScaledShape );
612 NCollection_Sequence<TDF_Label> aSubshapes;
613 aShapeTool->GetSubShapes( aLabel, aSubshapes );
614 for( NCollection_Sequence<TDF_Label>::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
616 const TDF_Label& aLSs = anItSs.Value();
617 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
618 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
619 aShapeTool->SetShape( aLSs, aSs1 );
623 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
624 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
625 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
627 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
629 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
630 gp_Trsf aTrsf = aLoc.Transformation();
631 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
632 XCAFDoc_Location::Set( aLabel, aTrsf );
641 aShapeTool->UpdateAssemblies();
649 BRepAlgoAPI_Fuse mkFuse;
650 NCollection_List<TopoDS_Shape> shapeArguments, shapeTools;
652 for(
const TopoDS_Shape& sh : aInputShapes )
657 if( shapeArguments.IsEmpty() )
658 shapeArguments.Append( sh );
660 shapeTools.Append( sh );
665 mkFuse.SetRunParallel(
true );
666 mkFuse.SetToFillHistory(
false );
667 mkFuse.SetArguments( shapeArguments );
668 mkFuse.SetTools( shapeTools );
671 catch(
const std::bad_alloc& )
673 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
674 "reducing the number of objects (e.g., vias), or freeing system memory." ),
678 catch(
const Standard_Failure& e )
680 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
681 "This may indicate insufficient memory. Consider "
682 "disabling shape fusing or reducing board complexity." ),
683 e.GetMessageString() ),
688 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
690 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
691 "memory-intensive; insufficient memory may cause failures." ),
694 if( mkFuse.HasErrors() )
696 wxString msg =
_(
"Errors:\n" );
697 wxStringOutputStream os_stream( &msg );
698 wxStdOutputStream out( os_stream );
700 mkFuse.DumpErrors( out );
704 if( mkFuse.HasWarnings() )
706 wxString msg =
_(
"Warnings:\n" );
707 wxStringOutputStream os_stream( &msg );
708 wxStdOutputStream out( os_stream );
710 mkFuse.DumpWarnings( out );
715 if( mkFuse.IsDone() )
717 TopoDS_Shape fusedShape = mkFuse.Shape();
721 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
722 unify.History() =
nullptr;
725 TopoDS_Shape unifiedShapes = unify.Shape();
727 if( unifiedShapes.IsNull() )
729 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
734 aOutShape = unifiedShapes;
738 catch(
const std::bad_alloc& )
740 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
741 "shape fusing or reducing the number of objects." ),
745 catch(
const Standard_Failure& e )
747 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
748 e.GetMessageString() ),
760 TopoDS_Compound compound;
761 BRep_Builder builder;
762 builder.MakeCompound( compound );
764 for(
const TopoDS_Shape& shape : aInputShapes )
765 builder.Add( compound, shape );
774 TopoDS_Shape outShape;
776 if( aInputShapes.Size() == 1 )
777 return aInputShapes.First();
779 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
788 const TCollection_ExtendedString& aPrefix )
790 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
794 Message::SendFail(
"Couldn't create assembly graph." );
798 bool anIsDone =
true;
800 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
802 const TDF_Label& lbl = aG->GetNode( idx );
803 Handle( TDataStd_Name ) nameHandle;
805 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
807 TCollection_ExtendedString
name;
811 name += nameHandle->Get();
814 TDataStd_Name::Set( lbl,
name );
818 TDataStd_Name::Set( lbl, aPrefix );
829 m_app = XCAFApp_Application::GetApplication();
830 m_app->NewDocument(
"MDTV-XCAF", m_doc );
831 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
849 if( m_doc->CanClose() == CDM_CCS_OK )
857 const double c_padExtraThickness = 0.005;
859 std::vector<TopoDS_Shape> padShapes;
873 double Zpos, thickness;
879 if( pcb_layer ==
F_Cu )
880 thickness += c_padExtraThickness;
881 else if( pcb_layer ==
B_Cu )
882 thickness -= c_padExtraThickness;
885 TopoDS_Shape testShape;
899 if( testShape.IsNull() )
901 std::vector<TopoDS_Shape> testShapes;
905 if( testShapes.size() > 0 )
906 testShape = testShapes.front();
911 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
917 if( pcb_layer ==
F_Cu )
919 else if( pcb_layer ==
B_Cu )
935 double f_pos, f_thickness;
936 double b_pos, b_thickness;
943 f_thickness += c_padExtraThickness;
944 b_thickness -= c_padExtraThickness;
947 double top = std::max( f_pos, f_pos + f_thickness );
948 double bottom = std::min( b_pos, b_pos + b_thickness );
949 double hole_height =
top - bottom;
951 TopoDS_Shape plating;
959 hole_height, bottom, aOrigin ) )
961 padShapes.push_back( plating );
975 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
992 padShapes.push_back( plating );
1004 if( !padShapes.empty() )
1009 NCollection_List<TopoDS_Shape> padShapesList;
1011 for(
const TopoDS_Shape& shape : padShapes )
1012 padShapesList.Append( shape );
1018 for(
const TopoDS_Shape& shape : padShapes )
1029 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1031 double margin = 0.001;
1039 double f_pos, f_thickness;
1040 double b_pos, b_thickness;
1043 double top = std::max( f_pos, f_pos + f_thickness );
1044 double bottom = std::min( b_pos, b_pos + b_thickness );
1046 double holeZsize = (
top - bottom ) + ( margin * 2 );
1048 double boardDrill = aShape.
GetWidth();
1049 double copperDrill = boardDrill - aPlatingThickness * 2;
1051 TopoDS_Shape copperHole, boardHole;
1056 holeZsize, bottom - margin, aOrigin ) )
1069 holeZsize, bottom - margin, aOrigin ) )
1085 const wxString& aNetname )
1087 double f_pos, f_thickness;
1088 double b_pos, b_thickness;
1091 double top = std::max( f_pos, f_pos + f_thickness );
1092 double bottom = std::min( b_pos, b_pos + b_thickness );
1094 TopoDS_Shape plating;
1097 (
top - bottom ), bottom, aOrigin ) )
1119 double margin = 0.001;
1123 double copperMargin = 0.5;
1125 double start_pos, start_thickness;
1126 double end_pos, end_thickness;
1131 double top = std::max( { start_pos, start_pos + start_thickness,
1132 end_pos, end_pos + end_thickness } );
1133 double bottom = std::min( { start_pos, start_pos + start_thickness,
1134 end_pos, end_pos + end_thickness } );
1137 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1138 top += copperMargin;
1139 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1140 bottom -= copperMargin;
1142 double holeZsize = (
top - bottom ) + ( margin * 2 );
1143 double holeZpos = bottom - margin;
1145 double backdrillDiameter = aShape.
GetWidth();
1147 TopoDS_Shape backdrillHole;
1151 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1168 bool aFrontSide,
const VECTOR2D& aOrigin )
1170 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1171 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1174 if( aDiameter <= 0 || aDepth <= 0 )
1176 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1177 aDiameter, aDepth );
1181 double margin = 0.001;
1184 double copperMargin = 0.5;
1187 double boardZpos, boardThickness;
1191 double f_pos, f_thickness, b_pos, b_thickness;
1198 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1199 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1201 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1202 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1205 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1206 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1207 double radius_mm = diameter_mm / 2.0;
1209 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1210 diameter_mm, depth_mm, radius_mm );
1214 double cylinderZpos;
1215 double cylinderHeight;
1221 cylinderZpos = topOuterSurface - depth_mm - margin;
1222 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1228 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1229 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1233 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1234 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1236 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1237 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1243 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1245 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1247 if( cylinder.IsNull() )
1249 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1250 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1259 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1262 catch(
const Standard_Failure& e )
1264 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1265 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1266 e.GetMessageString() ),
1276 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1278 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1279 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1284 if( aDiameter <= 0 || aAngle <= 0 )
1286 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1287 aDiameter, aAngle );
1291 double margin = 0.001;
1294 double copperMargin = 0.5;
1297 double boardZpos, boardThickness;
1301 double f_pos, f_thickness, b_pos, b_thickness;
1306 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1307 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1309 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1310 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1313 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1314 double radius_mm = diameter_mm / 2.0;
1318 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1326 depth_mm = radius_mm / tan( halfAngleRad );
1327 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1328 depth_mm, radius_mm );
1335 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1336 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1347 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1349 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1350 bottomRadius_mm, tan( halfAngleRad ) );
1352 if( bottomRadius_mm < 0 )
1353 bottomRadius_mm = 0;
1358 double coneHeight = depth_mm + copperMargin + margin;
1362 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1363 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1374 coneZpos = topOuterSurface - depth_mm - margin;
1375 r1 = bottomRadius_mm;
1377 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1379 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1380 coneZpos, r1, r2, coneHeight );
1382 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1383 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1390 coneZpos = bottomOuterSurface - copperMargin - margin;
1392 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1393 r2 = bottomRadius_mm;
1395 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1396 coneZpos, r1, r2, coneHeight );
1398 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1399 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1404 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1405 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1414 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1417 catch(
const Standard_Failure& e )
1419 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1420 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1421 e.GetMessageString() ),
1431 int aAngle,
bool aFrontSide )
1433 std::map<PCB_LAYER_ID, int> knockouts;
1436 double f_pos, f_thickness, b_pos, b_thickness;
1440 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1441 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1444 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1445 double radius_mm = diameter_mm / 2.0;
1449 double halfAngleRad = 0.0;
1454 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1458 depth_mm = radius_mm / tan( halfAngleRad );
1469 double featureTop, featureBottom;
1473 featureTop = topOuterSurface;
1474 featureBottom = topOuterSurface - depth_mm;
1478 featureBottom = bottomOuterSurface;
1479 featureTop = bottomOuterSurface + depth_mm;
1482 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1483 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1492 double layerZ, layerThickness;
1496 double layerTop = std::max( layerZ, layerZ + layerThickness );
1497 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1501 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1503 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1504 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1509 int knockoutDiameter;
1515 double layerSurfaceZ;
1519 layerSurfaceZ = layerTop;
1524 layerSurfaceZ = layerBottom;
1528 double distanceFromSurface;
1530 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1532 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1535 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1537 if( radiusAtLayer_mm <= 0 )
1539 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1540 static_cast<int>( layer ) );
1544 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1545 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1546 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1551 knockoutDiameter = aDiameter;
1552 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1553 static_cast<int>( layer ), knockoutDiameter );
1556 knockouts[layer] = knockoutDiameter;
1564 double& aThickness )
1567 static const double c_silkscreenAboveCopper = 0.04;
1568 static const double c_soldermaskAboveCopper = 0.015;
1576 double f_pos, f_thickness;
1578 double top = std::max( f_pos, f_pos + f_thickness );
1581 aZPos =
top + c_silkscreenAboveCopper;
1583 aZPos =
top + c_soldermaskAboveCopper;
1589 double b_pos, b_thickness;
1591 double bottom = std::min( b_pos, b_pos + b_thickness );
1594 aZPos = bottom - c_silkscreenAboveCopper;
1596 aZPos = bottom - c_soldermaskAboveCopper;
1604 double& aThickness )
1608 bool wasPrepreg =
false;
1610 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1613 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1619 if( aLayer ==
B_Cu )
1664 double f_pos, f_thickness;
1665 double b_pos, b_thickness;
1668 double top = std::min( f_pos, f_pos + f_thickness );
1669 double bottom = std::max( b_pos, b_pos + b_thickness );
1671 aThickness = (
top - bottom );
1674 wxASSERT( aZPos == 0.0 );
1680 const wxString& aRefDes )
1682 double f_pos, f_thickness;
1683 double b_pos, b_thickness;
1687 double boardSurfaceZ;
1690 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1692 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1694 double bodyThickness = aHeight - aStandoff;
1698 zBot = boardSurfaceZ + aStandoff;
1700 zBot = boardSurfaceZ - aHeight;
1710 if( aStandoff <= 0.0 )
1726 double f_pos, f_thickness;
1727 double b_pos, b_thickness;
1731 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1732 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1734 static const double c_protrusion = 1.0;
1736 double pinZBot, pinHeight;
1740 pinZBot = boardBotZ - c_protrusion;
1741 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1745 double pinZTop = boardTopZ + c_protrusion;
1746 pinZBot = boardBotZ - aStandoff;
1747 pinHeight = pinZTop - pinZBot;
1758 const VECTOR2D& aOrigin,
const wxString& aNetname )
1760 bool success =
true;
1768 double z_pos, thickness;
1771 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1779 else if( aLayer ==
F_Mask )
1786 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1799 const std::vector<wxString>& aAltFilenames,
1800 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1802 VECTOR3D aScale,
bool aSubstituteModels )
1804 if( aFileName.empty() )
1806 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1815 wxString errorMessage;
1817 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1820 if( errorMessage.IsEmpty() )
1821 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1828 TopLoc_Location toploc;
1830 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1833 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1839 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1841 if( llabel.IsNull() )
1844 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1852 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1853 TDataStd_Name::Set( llabel, refdes );
1864 m_assy->UpdateAssemblies();
1936 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1937 double aZposition,
const VECTOR2D& aOrigin )
1944 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1945 double h_width = aWidth/2.0;
1947 coords[0] =
VECTOR2D{ 0.0, h_width };
1950 coords[1] =
VECTOR2D{ len, h_width };
1953 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1956 coords[3] =
VECTOR2D{ len, -h_width };
1959 coords[4] =
VECTOR2D{ 0, -h_width };
1962 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1965 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1967 for(
int ii = 0; ii < 6; ii++ )
1970 coords[ii] += aStartPoint;
1975 gp_Pnt coords3D[ 6 ];
1977 for(
int ii = 0; ii < 6; ii++ )
1979 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1980 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1984 BRepBuilderAPI_MakeWire wire;
1985 bool success =
true;
1997 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2002 edge = BRepBuilderAPI_MakeEdge(
circle );
2007 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2010 Handle( Geom_TrimmedCurve ) arcOfCircle =
2011 GC_MakeArcOfCircle( coords3D[1],
2015 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2018 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2021 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2022 GC_MakeArcOfCircle( coords3D[4],
2026 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2030 catch(
const Standard_Failure& e )
2032 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2033 e.GetMessageString() ),
2038 BRepBuilderAPI_MakeFace face;
2042 gp_Pln plane( coords3D[0], gp::DZ() );
2043 face = BRepBuilderAPI_MakeFace( plane, wire );
2045 catch(
const Standard_Failure& e )
2047 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2048 e.GetMessageString() ),
2053 if( aThickness != 0.0 )
2055 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2057 if( aShape.IsNull() )
2059 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2076 double aZposition,
const VECTOR2D& aOrigin )
2078 std::vector<TopoDS_Shape> testShapes;
2081 aHeight, aZposition, aOrigin );
2083 if( testShapes.size() > 0 )
2084 aShape = testShapes.front();
2107 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2111 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2113 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2114 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2124 gp_Pnt start = toPoint( aPt0 );
2125 gp_Pnt
end = toPoint( aPt1 );
2127 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2129 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2131 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2139 aMkWire.Add( mkEdge.Edge() );
2141 if( aMkWire.Error() != BRepLib_WireDone )
2143 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2157 Handle( Geom_Curve ) curve;
2159 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2161 gp_Ax2 axis = gp::XOY();
2162 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2164 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2168 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2169 toPoint( aArc.GetP1() ) ).Value();
2172 if( curve.IsNull() )
2175 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2177 if( !aMkWire.IsDone() )
2179 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2180 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2182 aArc.GetP0().x, aArc.GetP0().y,
2183 aArc.GetArcMid().x, aArc.GetArcMid().y,
2184 aArc.GetP1().x, aArc.GetP1().y ),
2194 bool isFirstShape =
true;
2207 if( nextShape != -1 )
2213 lastPt = aChain.
CPoint( i );
2223 firstPt = currentArc.
GetP0();
2228 lastPt = currentArc.
GetP0();
2230 if( addArc( lastPt, currentArc ) )
2231 lastPt = currentArc.
GetP1();
2250 isFirstShape =
false;
2253 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2255 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2257 firstPt.
x, firstPt.
y ),
2263 catch(
const Standard_Failure& e )
2265 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2266 e.GetMessageString() ),
2276 bool aConvertToArcs,
double aThickness,
double aZposition,
2284 if( aConvertToArcs )
2288 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2292 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2296 fallbackPoly = workingPoly;
2297 workingPoly = approximated;
2316 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2318 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2319 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2323 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2324 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2326 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2330 auto tryMakeWire = [
this, &aZposition,
2331 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2334 BRepLib_MakeWire mkWire;
2338 if( mkWire.IsDone() )
2340 wire = mkWire.Wire();
2345 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2346 "z: %g; bounding box: %s" ),
2347 static_cast<int>( aContour.PointCount() ),
2348 static_cast<int>( mkWire.Error() ),
2353 if( !wire.IsNull() )
2355 BRepAlgoAPI_Check check( wire,
false,
true );
2357 if( !check.IsValid() )
2359 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2360 "z: %g; bounding box: %s" ),
2372 BRepBuilderAPI_MakeFace mkFace;
2374 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2380 bool allow_retry = aConvertToArcs ? true :
false;
2382 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2384 if( aConvertToArcs && wire.IsNull() )
2386 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2390 allow_retry =
false;
2391 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2396 if( !wire.IsNull() )
2398 if( basePlane.Axis().Direction().Z() < 0 )
2401 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2405 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2406 "z: %g; bounding box: %s" ),
2415 if( !wire.IsNull() )
2417 if( basePlane.Axis().Direction().Z() > 0 )
2424 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2425 "z: %g; bounding box: %s" ),
2432 catch(
const Standard_Failure& e )
2434 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2435 static_cast<int>( contId ),
2436 e.GetMessageString() ),
2442 if( mkFace.IsDone() )
2444 TopoDS_Shape faceShape = mkFace.Shape();
2446 if( aThickness != 0.0 )
2448 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2449 aShapes.push_back( prism );
2451 if( prism.IsNull() )
2459 aShapes.push_back( faceShape );
2475 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2476 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2477 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2478 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2479 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2480 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2481 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2482 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2492 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2494 aColorOut =
COLOR4D( aColorStr );
2499 const std::vector<FAB_LAYER_COLOR>& colors =
2506 if( fabColor.GetName() == aColorStr )
2508 aColorOut = fabColor.GetColor( aType );
2530 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2535 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2540 double boardThickness;
2560 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2564 polyset.
Append( contour );
2571 m_reporter->Report(
_(
"OCC error creating main outline." ),
2580 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2592 BRepBndLib::Add( brdShape, brdBndBox );
2595 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2600 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2601 std::vector<Bnd_Box>& holeBoxes )
2605 Bnd_Box brdWithHolesBndBox = brdBndBox;
2607 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2608 holeBoxes.resize( input.size() );
2610 for(
size_t i = 0; i < input.size(); i++ )
2613 BRepBndLib::Add( input[i], bbox );
2614 brdWithHolesBndBox.Add( bbox );
2615 ( *holeBoxSet )[i] = bbox;
2616 holeBoxes[i] = bbox;
2619 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2622 auto subtractShapesMap =
2623 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2624 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2625 const std::vector<Bnd_Box>& aHoleBoxes )
2627 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2630 for(
auto& [netname, vec] : aShapesMap )
2634 auto subtractLoopFn = [&](
const int shapeId )
2636 TopoDS_Shape& shape = vec[shapeId];
2639 BRepBndLib::Add( shape, shapeBbox );
2641 NCollection_List<TopoDS_Shape> holelist;
2644 std::unique_lock lock( mutex );
2646 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2648 for(
const int&
index : indices )
2649 holelist.Append( aHolesList[
index] );
2655 if( holelist.IsEmpty() )
2657 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2659 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2660 holelist.Append( aHolesList[i] );
2665 if( holelist.IsEmpty() )
2668 NCollection_List<TopoDS_Shape> cutArgs;
2669 cutArgs.Append( shape );
2671 BRepAlgoAPI_Cut
cut;
2673 cut.SetRunParallel(
true );
2674 cut.SetToFillHistory(
false );
2676 cut.SetArguments( cutArgs );
2677 cut.SetTools( holelist );
2680 if(
cut.HasErrors() ||
cut.HasWarnings() )
2682 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2689 if(
cut.HasErrors() )
2691 wxString msg =
_(
"Errors:\n" );
2692 wxStringOutputStream os_stream( &msg );
2693 wxStdOutputStream out( os_stream );
2695 cut.DumpErrors( out );
2699 if(
cut.HasWarnings() )
2701 wxString msg =
_(
"Warnings:\n" );
2702 wxStringOutputStream os_stream( &msg );
2703 wxStdOutputStream out( os_stream );
2705 cut.DumpWarnings( out );
2710 shape =
cut.Shape();
2713 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2717 auto subtractShapes =
2718 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2719 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2720 const std::vector<Bnd_Box>& aHoleBoxes )
2722 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2724 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2725 aShapesList = aShapesMap[wxEmptyString];
2731 Bnd_BoundSortBox bsbHoles;
2732 std::vector<Bnd_Box> holeBoxes;
2740 Bnd_BoundSortBox bsbHoles;
2741 std::vector<Bnd_Box> holeBoxes;
2750 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2752 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2753 const std::vector<TopoDS_Shape>& aShapes )
2755 for(
const TopoDS_Shape& shape : aShapes )
2756 shapesToFuseMap[aNetname].Append( shape );
2760 addShapes( netname, shapes );
2763 addShapes( netname, shapes );
2766 addShapes( netname, shapes );
2773 auto fuseLoopFn = [&](
const wxString& aNetname )
2775 auto& toFuse = shapesToFuseMap[aNetname];
2778 if( !fusedShape.IsNull() )
2780 std::unique_lock lock( mutex );
2790 BS::multi_future<void> mf;
2792 for(
const auto& [netname,
_] : shapesToFuseMap )
2793 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2810 auto pushToAssemblyMap =
2811 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2812 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2813 bool aCompoundAll,
const wxString& aNiceName )
2815 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2819 std::vector<TopoDS_Shape> allShapes;
2821 for(
const auto& [netname, shapesList] : aShapesMap )
2822 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2824 if( !allShapes.empty() )
2825 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2829 shapesMap = aShapesMap;
2832 for(
const auto& [netname, shapesList] : shapesMap )
2834 std::vector<TopoDS_Shape> newList;
2839 newList = shapesList;
2843 for( TopoDS_Shape& shape : newList )
2845 Handle( TDataStd_TreeNode ) node;
2848 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2855 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2856 TDF_Label shpLbl = node->Father()->Label();
2858 if( !shpLbl.IsNull() )
2860 if( visMatTool && !aVisMatLabel.IsNull() )
2861 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2867 shapeName << aShapeName;
2869 if( !netname.empty() )
2872 shapeName << netname;
2875 if( newList.size() > 1 )
2881 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2882 TDataStd_Name::Set( shpLbl, partname );
2890 auto pushToAssembly =
2891 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2892 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2894 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2896 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2900 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2901 double aMetallic,
double aRoughness ) -> TDF_Label
2903 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2904 XCAFDoc_VisMaterialPBR pbr;
2905 pbr.BaseColor = aBaseColor;
2906 pbr.Metallic = aMetallic;
2907 pbr.Roughness = aRoughness;
2908 vismat->SetPbrMaterial( pbr );
2909 return visMatTool->AddMaterial( vismat, aName );
2916 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2917 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2918 Quantity_ColorRGBA back_silk_color = front_silk_color;
2919 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2920 Quantity_ColorRGBA back_mask_color = front_mask_color;
2930 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2934 if( item->GetBrdLayerId() ==
F_Mask )
2935 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2937 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2940 if( item->GetBrdLayerId() ==
F_SilkS )
2941 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2942 else if( item->GetBrdLayerId() ==
B_SilkS )
2943 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2946 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2952 board_color = front_mask_color;
2953 board_color.SetAlpha( 1.0 );
2956 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2957 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2958 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2959 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2960 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2961 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2962 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2964 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2968 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2969 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2970 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2971 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2973 if( aPushBoardBody )
2976 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
2977 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
2981 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
2984 TopoDS_Compound asmCompound;
2985 BRep_Builder asmBuilder;
2986 asmBuilder.MakeCompound( asmCompound );
2987 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
2988 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
2990 if( !entry.bodyShapes.empty() )
2992 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
2993 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
2994 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
2995 double a = ( entry.colorKey & 0xFF ) / 255.0;
2997 double metallic, roughness;
2999 switch( entry.material )
3020 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3021 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3023 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3024 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3026 Handle( TDataStd_TreeNode ) bodyNode;
3027 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3028 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3030 if( !bodyShpLbl.IsNull() )
3032 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3033 TDataStd_Name::Set( bodyShpLbl,
3034 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3040 for( TopoDS_Shape& pinShape : entry.pinShapes )
3042 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3044 Handle( TDataStd_TreeNode ) pinNode;
3045 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3046 TDF_Label pinShpLbl = pinNode->Father()->Label();
3048 if( !pinShpLbl.IsNull() )
3050 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3051 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3052 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3056 TopLoc_Location loc;
3057 TDF_Label fpCompLbl = m_assy->AddComponent(
m_assy_label, fpLabel, loc );
3058 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3063#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3064 m_assy->UpdateAssemblies();
3073bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3077 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3085 wxFileName fn( aFileName );
3086 IGESControl_Controller::Init();
3087 IGESCAFControl_Writer writer;
3088 writer.SetColorMode(
true );
3089 writer.SetNameMode(
true );
3090 IGESData_GlobalSection
header = writer.Model()->GlobalSection();
3091 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3092 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3093 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3094 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3095 writer.Model()->SetGlobalSection(
header );
3097 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3106 wxFileInputStream input( inputFile );
3107 wxFileOutputStream
output( outputFile );
3111 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3117 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3121 wxZlibOutputStream zlibStream(
output, -1, wxZLIB_GZIP );
3123 if( !zlibStream.IsOk() )
3125 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3129 input.Read( zlibStream );
3131 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3133 m_reporter->Report(
_(
"Compress read or write error" ) );
3147 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3155 wxFileName fn( aFileName );
3157 STEPCAFControl_Writer writer;
3158 writer.SetColorMode(
true );
3159 writer.SetNameMode(
true );
3166 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3168 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3174 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3176 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3180 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3183 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3187 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3190 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3191 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3192 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3193 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3195 bool success =
true;
3198 wxString currCWD = wxGetCwd();
3199 wxString workCWD = fn.GetPath();
3201 if( !workCWD.IsEmpty() )
3202 wxSetWorkingDirectory( workCWD );
3204 wxString tmpfname(
"$tempfile$.step" );
3206 if(
false == writer.Write( tmpfname.c_str() ) )
3209 if( compress && success )
3211 wxString srcTmp( tmpfname );
3212 wxString dstTmp(
"$tempfile$.stpz" );
3215 wxRemoveFile( srcTmp );
3226 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3228 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3236 wxSetWorkingDirectory( currCWD );
3246 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3255 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3260 wxFileName fn( aFileName );
3262 wxFFileOutputStream ffStream( fn.GetFullPath() );
3263 wxStdOutputStream stdStream( ffStream );
3265#if OCC_VERSION_HEX >= 0x070600
3266 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3268 BRepTools::Write( shape, stdStream );
3277 wxFileName fn( aFileName );
3279 wxFFileOutputStream ffStream( fn.GetFullPath() );
3280 wxStdOutputStream file( ffStream );
3282 if( !ffStream.IsOk() )
3284 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3292 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3297 std::map<wxString, std::vector<int>> groups[4];
3298 std::map<wxString, double> groupAreas;
3299 TopExp_Explorer exp;
3302 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3304 TopoDS_Shape subShape = exp.Current();
3307 BRepBndLib::Add( subShape, bbox );
3311 for(
const auto& pair : pairs )
3313 const auto& [point, padTestShape] = pair;
3315 if( bbox.IsOut( point ) )
3318 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3320 if( surface.GetType() != GeomAbs_Plane )
3323 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3326 if( !dist.IsDone() )
3329 if( dist.Value() < Precision::Approximation() )
3332 groups[2][padKey].push_back( faceIndex );
3334 GProp_GProps system;
3335 BRepGProp::SurfaceProperties( subShape, system );
3337 double surfaceArea = system.Mass() / 1e6;
3338 groupAreas[padKey] += surfaceArea;
3347 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3348 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3349 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3350 file <<
" <shape format=\"BREP\"><![CDATA[";
3351#if OCC_VERSION_HEX < 0x070600
3352 BRepTools::Write( shape, file );
3354 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3356 file <<
"]]></shape>" << std::endl;
3357 file <<
" <topology>" << std::endl;
3359 TopTools_IndexedMapOfShape mainMap;
3360 TopExp::MapShapes( shape, mainMap );
3361 std::set<int> topo[4];
3363 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3366 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3367 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3369 for(
int dim = 0; dim < 4; dim++ )
3371 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3373 TopoDS_Shape subShape = exp.Current();
3374 int idx = mainMap.FindIndex( subShape );
3376 if( idx && !topo[dim].count( idx ) )
3377 topo[dim].insert( idx );
3381 for(
int dim = 0; dim <= 3; dim++ )
3383 std::string labels = c_dimLabels[dim];
3384 std::string label = c_dimLabel[dim];
3386 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3389 for(
auto p : topo[dim] )
3391 std::string
name(
"" );
3392 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3393 <<
"name=\"" <<
name <<
"\" "
3394 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3398 file <<
" </" << labels <<
">" << std::endl;
3401 file <<
" </topology>" << std::endl;
3402 file <<
" </geometry>" << std::endl;
3403 file <<
" <groups count=\""
3404 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3407 int groupNumber = 1;
3412 for(
int dim = 0; dim <= 3; dim++ )
3414 std::string label = c_dimLabel[dim];
3416 for(
auto g : groups[dim] )
3419 wxString
name = g.first;
3423 std::ostringstream gs;
3424 gs <<
"G_" << dim <<
"D_" << g.first;
3427 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3433 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3435 for(
auto index : g.second )
3436 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3438 file <<
" </group>" << std::endl;
3440 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3452 file <<
" </groups>" << std::endl;
3453 file <<
" <fields count=\"0\"/>" << std::endl;
3454 file <<
"</XAO>" << std::endl;
3461 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3462 TDF_Label& aLabel,
bool aSubstituteModels,
3463 wxString* aErrorMessage )
3465 std::string fileNameUTF8 = aFileName.utf8_string();
3467 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3468 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3470 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3474 aLabel = mm->second;
3480 Handle( TDocStd_Document ) doc;
3481 m_app->NewDocument(
"MDTV-XCAF", doc );
3484 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3489 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3491 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3499 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3501 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3512 wxFFileInputStream ifile( aFileName );
3513 wxFileName outFile( aFileName );
3515 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3516 outFile.SetExt( wxT(
"step" ) );
3517 wxFileOffset size = ifile.GetLength();
3519 if( size == wxInvalidOffset )
3521 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3528 bool success =
false;
3531 wxFFileOutputStream ofile( outFile.GetFullPath() );
3536 char* buffer =
new char[size];
3538 ifile.Read( buffer, size );
3539 std::string expanded;
3543 expanded = gzip::decompress( buffer, size );
3551 if( expanded.empty() )
3555 wxZipInputStream izipfile( ifile );
3556 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3558 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3560 izipfile.Read( ofile );
3565 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3571 ofile.Write( expanded.data(), expanded.size() );
3579 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3580 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3599 if( aSubstituteModels )
3601 wxFileName wrlName( aFileName );
3603 wxString basePath = wrlName.GetPath();
3604 wxString baseName = wrlName.GetName();
3612 alts.Add( wxT(
"stp" ) );
3613 alts.Add( wxT(
"step" ) );
3614 alts.Add( wxT(
"STP" ) );
3615 alts.Add( wxT(
"STEP" ) );
3616 alts.Add( wxT(
"Stp" ) );
3617 alts.Add( wxT(
"Step" ) );
3618 alts.Add( wxT(
"stpz" ) );
3619 alts.Add( wxT(
"stpZ" ) );
3620 alts.Add( wxT(
"STPZ" ) );
3621 alts.Add( wxT(
"step.gz" ) );
3622 alts.Add( wxT(
"stp.gz" ) );
3625 alts.Add( wxT(
"iges" ) );
3626 alts.Add( wxT(
"IGES" ) );
3627 alts.Add( wxT(
"igs" ) );
3628 alts.Add( wxT(
"IGS" ) );
3632 for(
const auto& altExt : alts )
3636 if( !aAltFilenames.empty() )
3638 for(
const wxString& altPath : aAltFilenames )
3640 wxFileName iterFn( altPath );
3642 if( iterFn.GetExt() == altExt )
3651 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3654 if( altFile.IsOk() && altFile.FileExists() )
3664 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3678 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3680 Handle( XCAFDoc_ShapeTool ) shapeTool =
3681 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3688 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3698 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3708 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3715 if( aLabel.IsNull() )
3717 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3724 TDataStd_Name::Set( aLabel, partname );
3734 TopLoc_Location& aLocation )
3748 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3754 double boardThickness;
3757 double top = std::max( boardZPos, boardZPos + boardThickness );
3758 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3763 double f_pos, f_thickness;
3767 bottom += f_thickness;
3774 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3775 lPos.Multiply( lRot );
3776 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3777 lPos.Multiply( lRot );
3782 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3783 lPos.Multiply( lRot );
3787 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3788 lPos.Multiply( lOff );
3791 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3792 lPos.Multiply( lOrient );
3793 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3794 lPos.Multiply( lOrient );
3795 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3796 lPos.Multiply( lOrient );
3798 aLocation = TopLoc_Location( lPos );
3805 IGESControl_Controller::Init();
3806 IGESCAFControl_Reader reader;
3807 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3809 if( stat != IFSelect_RetDone )
3813 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3817 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3821 reader.SetColorMode(
true );
3822 reader.SetNameMode(
false );
3823 reader.SetLayerMode(
false );
3825 if( !reader.Transfer( doc ) )
3827 if( doc->CanClose() == CDM_CCS_OK )
3834 if( reader.NbShapes() < 1 )
3836 if( doc->CanClose() == CDM_CCS_OK )
3848 STEPCAFControl_Reader reader;
3849 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3851 if( stat != IFSelect_RetDone )
3855 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3859 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3863 reader.SetColorMode(
true );
3864 reader.SetNameMode(
true );
3865 reader.SetLayerMode(
false );
3867 if( !reader.Transfer( doc ) )
3869 if( doc->CanClose() == CDM_CCS_OK )
3876 if( reader.NbRootsForTransfer() < 1 )
3878 if( doc->CanClose() == CDM_CCS_OK )
3890#if OCC_VERSION_HEX >= 0x070700
3891 VrmlAPI_CafReader reader;
3892 RWMesh_CoordinateSystemConverter conv;
3893 conv.SetInputLengthUnit( 2.54 );
3894 reader.SetCoordinateSystemConverter( conv );
3895 reader.SetDocument( doc );
3897 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3910 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3912 NCollection_Sequence<TDF_Label> frshapes;
3913 s_assy->GetFreeShapes( frshapes );
3915 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3924 TDF_Label d_targetLabel = d_assy->NewShape();
3926 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
3932 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3935 return d_targetLabel;
3941 NCollection_Sequence<TDF_Label> freeShapes;
3942 aShapeTool->GetFreeShapes( freeShapes );
3948 for(
int i = 1; i <= freeShapes.Length(); ++i )
3950 TDF_Label label = freeShapes.Value( i );
3952 aShapeTool->GetShape( label, shape );
3957 const double linearDeflection = 0.14;
3958 const double angularDeflection =
DEG2RAD( 30.0 );
3959 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
3981 wxFileName fn( aFileName );
3983 const char* tmpGltfname =
"$tempfile$.glb";
3984 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3986 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3987 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3988 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3989 RWMesh_CoordinateSystem_Zup );
3990#if OCC_VERSION_HEX >= 0x070700
3991 cafWriter.SetParallel(
true );
3993 TColStd_IndexedDataMapOfStringString metadata;
3995 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3996 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3997 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3998 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3999 metadata.Add( TCollection_AsciiString(
"generator" ),
4000 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4001 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4004 bool success =
true;
4007 wxString currCWD = wxGetCwd();
4008 wxString workCWD = fn.GetPath();
4010 if( !workCWD.IsEmpty() )
4011 wxSetWorkingDirectory( workCWD );
4013 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4020 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4022 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4030 wxSetWorkingDirectory( currCWD );
4038#if OCC_VERSION_HEX < 0x070700
4045 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4055 wxFileName fn( aFileName );
4057 const char* tmpFname =
"$tempfile$.ply";
4058 RWPly_CafWriter cafWriter( tmpFname );
4060 cafWriter.SetFaceId(
true );
4061 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4062 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4064 TColStd_IndexedDataMapOfStringString metadata;
4066 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4067 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4068 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4069 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4070 metadata.Add( TCollection_AsciiString(
"generator" ),
4071 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4073 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4076 bool success =
true;
4079 wxString currCWD = wxGetCwd();
4080 wxString workCWD = fn.GetPath();
4082 if( !workCWD.IsEmpty() )
4083 wxSetWorkingDirectory( workCWD );
4085 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4092 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4094 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4102 wxSetWorkingDirectory( currCWD );
4113 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4123 wxFileName fn( aFileName );
4125 const char* tmpFname =
"$tempfile$.stl";
4128 wxString currCWD = wxGetCwd();
4129 wxString workCWD = fn.GetPath();
4131 if( !workCWD.IsEmpty() )
4132 wxSetWorkingDirectory( workCWD );
4134 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4141 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4143 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4151 wxSetWorkingDirectory( currCWD );
4163 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4172 wxFileName fn( aFileName );
4174 const char* tmpFname =
"$tempfile$.u3d";
4177 wxString currCWD = wxGetCwd();
4178 wxString workCWD = fn.GetPath();
4180 if( !workCWD.IsEmpty() )
4181 wxSetWorkingDirectory( workCWD );
4184 bool success = writer.
Perform( m_doc );
4190 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4192 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4199 wxSetWorkingDirectory( currCWD );
4210 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4219 wxFileName fn( aFileName );
4221 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4222 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4224 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4225 bool success = writer.
Perform( m_doc );
4228 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4230 plotter->SetColorMode(
true );
4231 plotter->Set3DExport(
true );
4232 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4234 plotter->SetRenderSettings( &renderSettings );
4236 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4238 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4244 plotter->StartPlot(
"1",
"3D Model" );
4245 double fov_degrees = 16.5f;
4250 std::vector<PDF_3D_VIEW> views;
4255 std::vector<float> c2wMatrix =
4259 .m_name =
"Default",
4260 .m_cameraMatrix = c2wMatrix,
4261 .m_cameraCenter = (float)
distance,
4262 .m_fov = (
float) fov_degrees,
4271 .m_cameraMatrix = c2wMatrix,
4272 .m_cameraCenter = (float)
distance,
4273 .m_fov = (
float) fov_degrees,
4282 .m_cameraMatrix = c2wMatrix,
4283 .m_cameraCenter = (float)
distance,
4284 .m_fov = (
float) fov_degrees,
4293 .m_cameraMatrix = c2wMatrix,
4294 .m_cameraCenter = (float)
distance,
4295 .m_fov = (
float) fov_degrees,
4298 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4307 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4309 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4310 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4316 wxRemoveFile( u3dTmpfn.GetFullPath() );
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
bool GetExtrusionPinOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly)
Get the pin outline polygons for extruded THT pin rendering.
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetNetname() const
const wxString & GetShortNetname() const
FOOTPRINT * GetParentFootprint() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
PCB specific render settings.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
PAD_PROP GetProperty() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
const VECTOR2I & GetArcMid() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
const std::optional< INTERSECTION > SelfIntersectingWithArcs() const
Check if the line chain is self-intersecting.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
virtual size_t GetSegmentCount() const override
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int FullPointCount() const
Return the number of points in the shape poly set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
const POLYGON & CPolygon(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
const SEG & GetSeg() const
int GetWidth() const override
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
OUTPUT_FORMAT m_outFmt
The current output format for created file.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
bool WritePLY(const wxString &aFileName)
bool AddCountersink(const VECTOR2I &aPosition, int aDiameter, int aDepth, int aAngle, bool aFrontSide, const VECTOR2D &aOrigin)
Add a countersink shape to remove board material from the top or bottom of a hole.
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_vias
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_pads
bool WriteSTEP(const wxString &aFileName, bool aOptimize, bool compress)
std::vector< TopoDS_Shape > m_board_back_mask
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
std::vector< TopoDS_Shape > m_boardCutouts
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
bool CreatePCB(SHAPE_POLY_SET &aOutline, const VECTOR2D &aOrigin, bool aPushBoardBody)
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, const VECTOR3D &aScale)
bool getModelLocation(bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, TopLoc_Location &aLocation)
void SetFuseShapes(bool aValue)
bool WriteXAO(const wxString &aFileName)
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
std::vector< TDF_Label > m_pcb_labels
STEP_PCB_MODEL(const wxString &aPcbName, REPORTER *aReporter)
std::vector< EXTRUDED_BODY_ENTRY > m_extruded_bodies
bool AddBackdrill(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerStart, PCB_LAYER_ID aLayerEnd, const VECTOR2D &aOrigin)
Add a backdrill hole shape to remove board material and copper plating.
void getLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_outlines
void SetSimplifyShapes(bool aValue)
bool WriteU3D(const wxString &aFileName)
bool getModelLabel(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
bool AddCounterbore(const VECTOR2I &aPosition, int aDiameter, int aDepth, bool aFrontSide, const VECTOR2D &aOrigin)
Add a counterbore shape to remove board material from the top or bottom of a hole.
void SetEnabledLayers(const LSET &aLayers)
void SetExtraPadThickness(bool aValue)
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
std::vector< TopoDS_Shape > m_board_front_silk
bool AddExtrudedPins(const FOOTPRINT *aFootprint, bool aBottom, double aStandoff, const VECTOR2D &aOrigin)
Add metallic pin extrusions for through-hole pads.
Handle(XCAFApp_Application) m_app
bool WritePDF(const wxString &aFileName)
virtual ~STEP_PCB_MODEL()
std::vector< TopoDS_Shape > m_board_front_mask
bool WriteSTL(const wxString &aFileName)
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
std::map< PCB_LAYER_ID, int > GetCopperLayerKnockouts(int aDiameter, int aDepth, int aAngle, bool aFrontSide)
Get the knockout diameters for copper layers that a counterbore or countersink crosses.
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
std::vector< TopoDS_Shape > m_copperCutouts
bool CompressSTEP(wxString &inputFile, wxString &outputFile)
std::vector< TopoDS_Shape > m_board_back_silk
void getCopperLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
bool AddComponent(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, const wxString &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
bool AddExtrudedBody(const SHAPE_POLY_SET &aOutline, bool aBottom, double aStandoff, double aHeight, const VECTOR2D &aOrigin, uint32_t aColor, EXTRUSION_MATERIAL aMaterial, const wxString &aRefDes)
Add an extruded 3D body from a 2D outline polygon.
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
bool Perform(const Handle(TDocStd_Document) &aDocument)
const VECTOR3D & GetCenter() const
const Bnd_Box & GetMeshBoundingBox() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
Handle(KICAD3D_INFO) KICAD3D_INFO
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static bool rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
static TopoDS_Shape fuseShapesOrCompound(const NCollection_List< TopoDS_Shape > &aInputShapes, REPORTER *aReporter)
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 bool prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
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
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
std::vector< std::string > header
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D