30#include <wx/filename.h>
32#include <wx/sstream.h>
33#include <wx/stdpaths.h>
36#include <wx/zstream.h>
37#include <wx/wfstream.h>
38#include <wx/zipstrm.h>
39#include <wx/stdstream.h>
42#include <decompress.hpp>
69#include <IGESCAFControl_Reader.hxx>
70#include <IGESCAFControl_Writer.hxx>
71#include <IGESControl_Controller.hxx>
72#include <IGESData_GlobalSection.hxx>
73#include <IGESData_IGESModel.hxx>
74#include <Interface_Static.hxx>
75#include <Quantity_Color.hxx>
76#include <STEPCAFControl_Reader.hxx>
77#include <STEPCAFControl_Writer.hxx>
78#include <APIHeaderSection_MakeHeader.hxx>
79#include <Standard_Failure.hxx>
80#include <Standard_Handle.hxx>
81#include <Standard_Version.hxx>
82#include <TCollection_ExtendedString.hxx>
83#include <TDocStd_Document.hxx>
84#include <TDataStd_Name.hxx>
85#include <TDataStd_TreeNode.hxx>
86#include <TDF_ChildIterator.hxx>
87#include <NCollection_Sequence.hxx>
88#include <TColStd_IndexedDataMapOfStringString.hxx>
89#include <TDF_Tool.hxx>
90#include <TopTools_IndexedMapOfShape.hxx>
91#include <TopExp_Explorer.hxx>
93#include <XCAFApp_Application.hxx>
95#include <XCAFDoc_DocumentTool.hxx>
96#include <XCAFDoc_ColorTool.hxx>
97#include <XCAFDoc_ShapeTool.hxx>
98#include <XCAFDoc_VisMaterialTool.hxx>
99#include <XCAFDoc_Area.hxx>
100#include <XCAFDoc_Centroid.hxx>
101#include <XCAFDoc_Editor.hxx>
102#include <XCAFDoc_Location.hxx>
103#include <XCAFDoc_Volume.hxx>
106#include "KI_XCAFDoc_AssemblyGraph.hxx"
108#include <BRep_Tool.hxx>
109#include <BRepMesh_IncrementalMesh.hxx>
110#include <BRepBuilderAPI_GTransform.hxx>
111#include <BRepBuilderAPI_MakeEdge.hxx>
112#include <BRepBuilderAPI_MakeWire.hxx>
113#include <BRepBuilderAPI_MakeFace.hxx>
114#include <BRepExtrema_DistShapeShape.hxx>
115#include <BRepPrimAPI_MakeCone.hxx>
116#include <BRepPrimAPI_MakeCylinder.hxx>
117#include <BRepPrimAPI_MakePrism.hxx>
118#include <BRepTools.hxx>
119#include <BRepLib_MakeWire.hxx>
120#include <BRepAdaptor_Surface.hxx>
121#include <BRepAlgoAPI_Check.hxx>
122#include <BRepAlgoAPI_Cut.hxx>
123#include <BRepAlgoAPI_Fuse.hxx>
124#include <ShapeUpgrade_UnifySameDomain.hxx>
126#include <BRepBndLib.hxx>
127#include <Bnd_BoundSortBox.hxx>
128#include <Bnd_HArray1OfBox.hxx>
129#include <GProp_GProps.hxx>
130#include <BRepGProp.hxx>
132#include <Geom_Curve.hxx>
133#include <Geom_TrimmedCurve.hxx>
138#include <GC_MakeArcOfCircle.hxx>
139#include <GC_MakeCircle.hxx>
141#include <RWGltf_CafWriter.hxx>
142#include <StlAPI_Writer.hxx>
146#if OCC_VERSION_HEX >= 0x070700
147#include <VrmlAPI_CafReader.hxx>
148#include <RWPly_CafWriter.hxx>
176 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
178 if( !lfile.FileExists() )
181 wxString ext = lfile.GetExt().Lower();
183 if( ext == wxT(
"wrl" ) )
186 if( ext == wxT(
"wrz" ) )
189 if( ext == wxT(
"idf" ) )
192 if( ext == wxT(
"emn" ) )
195 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
209 const int max_line_count = 3;
211 for(
int ii = 0; ii < max_line_count; ii++ )
213 memset( iline, 0, 82 );
214 ifile.getline( iline, 82 );
220 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
226 std::string fstr = iline;
230 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
239 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
246 if( strncmp( iline,
"/*", 2 ) != 0 )
264 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
265 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
266 double det = -b.
x * d.
y + d.
x * b.
y;
270 center.x = ( -bc * d.
y - cd * b.
y ) * det;
271 center.y = ( b.
x * cd + d.
x * bc ) * det;
278#define APPROX_DBG( stmt )
286 static const double c_radiusDeviation = 1000.0;
287 static const double c_arcCenterDeviation = 1000.0;
288 static const double c_relLengthDeviation = 0.8;
289 static const int c_last_none = -1000;
291 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
292 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 )
412 APPROX_DBG( std::cout <<
" Arc central angle too small: "
414 << c_minArcCentralAngle.
AsDegrees() << std::endl );
420 for(
int k = first + 1; last != c_last_none && k < last; k++ )
426 if( dist > c_radiusDeviation )
428 APPROX_DBG( std::cout <<
" Point " << k <<
" too far from arc: " << dist
429 <<
" > " << c_radiusDeviation << std::endl );
434 if( last != c_last_none )
439 int toRemove = last - ( aSrc.
PointCount() - 3 );
469 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
474 if( last == c_last_none )
491 if( iarc0 != -1 && iarc1 != -1 )
493 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
503 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
521 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
522 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
540 NCollection_Sequence<TDF_Label> theLabels;
541 aShapeTool->GetFreeShapes( theLabels );
545 if( theLabels.Length() == 1 )
546 return aShapeTool->GetShape( theLabels.Value( 1 ) );
548 TopoDS_Compound aCompound;
549 BRep_Builder aBuilder;
550 aBuilder.MakeCompound( aCompound );
552 for( NCollection_Sequence<TDF_Label>::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
554 TopoDS_Shape aFreeShape;
556 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
559 aBuilder.Add( aCompound, aFreeShape );
562 if( aCompound.NbChildren() > 0 )
573 if( theLabel.IsNull() )
575 Message::SendFail(
"Null label." );
579 if(
std::abs( aScale.X() ) <= gp::Resolution() ||
std::abs( aScale.Y() ) <= gp::Resolution()
580 ||
std::abs( aScale.Z() ) <= gp::Resolution() )
582 Message::SendFail(
"Scale factor is too small." );
586 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
588 if( aShapeTool.IsNull() )
590 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
594 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
598 Message::SendFail(
"Couldn't create assembly graph." );
602 bool anIsDone =
true;
606 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
608 0, 0, aScale.Z() ) );
611 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
613 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
615 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
617 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
618 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
623 const TDF_Label& aLabel = aG->GetNode( idx );
625 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
627 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
628 aBRepTrsf.Perform( aShape,
true );
629 if( !aBRepTrsf.IsDone() )
631 Standard_SStream aSS;
632 TCollection_AsciiString anEntry;
633 TDF_Tool::Entry( aLabel, anEntry );
634 aSS <<
"Shape " << anEntry <<
" is not scaled!";
635 Message::SendFail( aSS.str().c_str() );
639 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
640 aShapeTool->SetShape( aLabel, aScaledShape );
643 NCollection_Sequence<TDF_Label> aSubshapes;
644 aShapeTool->GetSubShapes( aLabel, aSubshapes );
645 for( NCollection_Sequence<TDF_Label>::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
647 const TDF_Label& aLSs = anItSs.Value();
648 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
649 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
650 aShapeTool->SetShape( aLSs, aSs1 );
654 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
655 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
656 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
658 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
660 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
661 gp_Trsf aTrsf = aLoc.Transformation();
662 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
663 XCAFDoc_Location::Set( aLabel, aTrsf );
672 aShapeTool->UpdateAssemblies();
680 BRepAlgoAPI_Fuse mkFuse;
681 NCollection_List<TopoDS_Shape> shapeArguments, shapeTools;
683 for(
const TopoDS_Shape& sh : aInputShapes )
688 if( shapeArguments.IsEmpty() )
689 shapeArguments.Append( sh );
691 shapeTools.Append( sh );
698 mkFuse.SetNonDestructive(
true );
699 mkFuse.SetRunParallel(
true );
700 mkFuse.SetToFillHistory(
false );
701 mkFuse.SetArguments( shapeArguments );
702 mkFuse.SetTools( shapeTools );
705 catch(
const std::bad_alloc& )
707 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
708 "reducing the number of objects (e.g., vias), or freeing system memory." ),
712 catch(
const Standard_Failure& e )
714 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
715 "This may indicate insufficient memory. Consider "
716 "disabling shape fusing or reducing board complexity." ),
717 e.GetMessageString() ),
722 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
724 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
725 "memory-intensive; insufficient memory may cause failures." ),
728 if( mkFuse.HasErrors() )
730 wxString msg =
_(
"Errors:\n" );
731 wxStringOutputStream os_stream( &msg );
732 wxStdOutputStream out( os_stream );
734 mkFuse.DumpErrors( out );
738 if( mkFuse.HasWarnings() )
740 wxString msg =
_(
"Warnings:\n" );
741 wxStringOutputStream os_stream( &msg );
742 wxStdOutputStream out( os_stream );
744 mkFuse.DumpWarnings( out );
749 if( mkFuse.IsDone() )
751 TopoDS_Shape fusedShape = mkFuse.Shape();
755 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
756 unify.SetSafeInputMode(
true );
757 unify.History() =
nullptr;
760 TopoDS_Shape unifiedShapes = unify.Shape();
762 if( unifiedShapes.IsNull() )
764 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
769 aOutShape = unifiedShapes;
773 catch(
const std::bad_alloc& )
775 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
776 "shape fusing or reducing the number of objects." ),
780 catch(
const Standard_Failure& e )
782 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
783 e.GetMessageString() ),
795 TopoDS_Compound compound;
796 BRep_Builder builder;
797 builder.MakeCompound( compound );
799 for(
const TopoDS_Shape& shape : aInputShapes )
800 builder.Add( compound, shape );
809 TopoDS_Shape outShape;
811 if( aInputShapes.Size() == 1 )
812 return aInputShapes.First();
814 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
823 const TCollection_ExtendedString& aPrefix )
825 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
829 Message::SendFail(
"Couldn't create assembly graph." );
833 bool anIsDone =
true;
835 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
837 const TDF_Label& lbl = aG->GetNode( idx );
838 Handle( TDataStd_Name ) nameHandle;
840 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
842 TCollection_ExtendedString
name;
846 name += nameHandle->Get();
849 TDataStd_Name::Set( lbl,
name );
853 TDataStd_Name::Set( lbl, aPrefix );
865 m_app = XCAFApp_Application::GetApplication();
866 m_app->NewDocument(
"MDTV-XCAF", m_doc );
867 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
885 if( m_doc->CanClose() == CDM_CCS_OK )
893 const double c_padExtraThickness = 0.005;
895 std::vector<TopoDS_Shape> padShapes;
909 double Zpos, thickness;
915 if( pcb_layer ==
F_Cu )
916 thickness += c_padExtraThickness;
917 else if( pcb_layer ==
B_Cu )
918 thickness -= c_padExtraThickness;
921 TopoDS_Shape testShape;
935 if( testShape.IsNull() )
937 std::vector<TopoDS_Shape> testShapes;
941 if( testShapes.size() > 0 )
942 testShape = testShapes.front();
947 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
953 if( pcb_layer ==
F_Cu )
955 else if( pcb_layer ==
B_Cu )
971 double f_pos, f_thickness;
972 double b_pos, b_thickness;
979 f_thickness += c_padExtraThickness;
980 b_thickness -= c_padExtraThickness;
983 double top = std::max( f_pos, f_pos + f_thickness );
984 double bottom = std::min( b_pos, b_pos + b_thickness );
985 double hole_height =
top - bottom;
987 TopoDS_Shape plating;
995 hole_height, bottom, aOrigin ) )
997 padShapes.push_back( plating );
1011 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
1028 padShapes.push_back( plating );
1040 if( !padShapes.empty() )
1045 NCollection_List<TopoDS_Shape> padShapesList;
1047 for(
const TopoDS_Shape& shape : padShapes )
1048 padShapesList.Append( shape );
1054 for(
const TopoDS_Shape& shape : padShapes )
1065 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1067 double margin = 0.001;
1075 double f_pos, f_thickness;
1076 double b_pos, b_thickness;
1079 double top = std::max( f_pos, f_pos + f_thickness );
1080 double bottom = std::min( b_pos, b_pos + b_thickness );
1082 double holeZsize = (
top - bottom ) + ( margin * 2 );
1084 double boardDrill = aShape.
GetWidth();
1085 double copperDrill = boardDrill - aPlatingThickness * 2;
1087 TopoDS_Shape copperHole, boardHole;
1092 holeZsize, bottom - margin, aOrigin ) )
1105 holeZsize, bottom - margin, aOrigin ) )
1121 const wxString& aNetname )
1123 double f_pos, f_thickness;
1124 double b_pos, b_thickness;
1127 double top = std::max( f_pos, f_pos + f_thickness );
1128 double bottom = std::min( b_pos, b_pos + b_thickness );
1130 TopoDS_Shape plating;
1133 (
top - bottom ), bottom, aOrigin ) )
1155 double margin = 0.001;
1159 double copperMargin = 0.5;
1161 double start_pos, start_thickness;
1162 double end_pos, end_thickness;
1167 double top = std::max( { start_pos, start_pos + start_thickness,
1168 end_pos, end_pos + end_thickness } );
1169 double bottom = std::min( { start_pos, start_pos + start_thickness,
1170 end_pos, end_pos + end_thickness } );
1173 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1174 top += copperMargin;
1175 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1176 bottom -= copperMargin;
1178 double holeZsize = (
top - bottom ) + ( margin * 2 );
1179 double holeZpos = bottom - margin;
1181 double backdrillDiameter = aShape.
GetWidth();
1183 TopoDS_Shape backdrillHole;
1187 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1204 bool aFrontSide,
const VECTOR2D& aOrigin )
1206 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1207 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1210 if( aDiameter <= 0 || aDepth <= 0 )
1212 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1213 aDiameter, aDepth );
1217 double margin = 0.001;
1220 double copperMargin = 0.5;
1223 double boardZpos, boardThickness;
1227 double f_pos, f_thickness, b_pos, b_thickness;
1234 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1235 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1237 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1238 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1241 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1242 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1243 double radius_mm = diameter_mm / 2.0;
1245 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1246 diameter_mm, depth_mm, radius_mm );
1250 double cylinderZpos;
1251 double cylinderHeight;
1257 cylinderZpos = topOuterSurface - depth_mm - margin;
1258 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1264 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1265 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1269 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1270 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1272 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1273 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1279 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1281 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1283 if( cylinder.IsNull() )
1285 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1286 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1295 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1298 catch(
const Standard_Failure& e )
1300 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1301 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1302 e.GetMessageString() ),
1312 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1314 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1315 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1320 if( aDiameter <= 0 || aAngle <= 0 )
1322 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1323 aDiameter, aAngle );
1327 double margin = 0.001;
1330 double copperMargin = 0.5;
1333 double boardZpos, boardThickness;
1337 double f_pos, f_thickness, b_pos, b_thickness;
1342 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1343 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1345 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1346 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1349 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1350 double radius_mm = diameter_mm / 2.0;
1354 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1362 depth_mm = radius_mm / tan( halfAngleRad );
1363 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1364 depth_mm, radius_mm );
1371 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1372 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1383 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1385 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1386 bottomRadius_mm, tan( halfAngleRad ) );
1388 if( bottomRadius_mm < 0 )
1389 bottomRadius_mm = 0;
1394 double coneHeight = depth_mm + copperMargin + margin;
1398 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1399 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1410 coneZpos = topOuterSurface - depth_mm - margin;
1411 r1 = bottomRadius_mm;
1413 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1415 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1416 coneZpos, r1, r2, coneHeight );
1418 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1419 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1426 coneZpos = bottomOuterSurface - copperMargin - margin;
1428 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1429 r2 = bottomRadius_mm;
1431 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1432 coneZpos, r1, r2, coneHeight );
1434 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1435 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1440 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1441 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1450 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1453 catch(
const Standard_Failure& e )
1455 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1456 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1457 e.GetMessageString() ),
1467 int aAngle,
bool aFrontSide )
1469 std::map<PCB_LAYER_ID, int> knockouts;
1472 double f_pos, f_thickness, b_pos, b_thickness;
1476 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1477 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1480 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1481 double radius_mm = diameter_mm / 2.0;
1485 double halfAngleRad = 0.0;
1490 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1494 depth_mm = radius_mm / tan( halfAngleRad );
1505 double featureTop, featureBottom;
1509 featureTop = topOuterSurface;
1510 featureBottom = topOuterSurface - depth_mm;
1514 featureBottom = bottomOuterSurface;
1515 featureTop = bottomOuterSurface + depth_mm;
1518 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1519 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1528 double layerZ, layerThickness;
1532 double layerTop = std::max( layerZ, layerZ + layerThickness );
1533 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1537 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1539 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1540 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1545 int knockoutDiameter;
1551 double layerSurfaceZ;
1555 layerSurfaceZ = layerTop;
1560 layerSurfaceZ = layerBottom;
1564 double distanceFromSurface;
1566 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1568 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1571 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1573 if( radiusAtLayer_mm <= 0 )
1575 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1576 static_cast<int>( layer ) );
1580 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1581 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1582 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1587 knockoutDiameter = aDiameter;
1588 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1589 static_cast<int>( layer ), knockoutDiameter );
1592 knockouts[layer] = knockoutDiameter;
1600 double& aThickness )
1603 static const double c_silkscreenAboveCopper = 0.04;
1604 static const double c_soldermaskAboveCopper = 0.015;
1612 double f_pos, f_thickness;
1614 double top = std::max( f_pos, f_pos + f_thickness );
1617 aZPos =
top + c_silkscreenAboveCopper;
1619 aZPos =
top + c_soldermaskAboveCopper;
1625 double b_pos, b_thickness;
1627 double bottom = std::min( b_pos, b_pos + b_thickness );
1630 aZPos = bottom - c_silkscreenAboveCopper;
1632 aZPos = bottom - c_soldermaskAboveCopper;
1640 double& aThickness )
1644 bool wasPrepreg =
false;
1646 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1649 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1655 if( aLayer ==
B_Cu )
1704 if( !item->IsEnabled() )
1709 for(
int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
1710 thickness += item->GetThickness( sublayer );
1715 thickness += item->GetThickness();
1725 double f_pos, f_thickness;
1726 double b_pos, b_thickness;
1729 double top = std::min( f_pos, f_pos + f_thickness );
1730 double bottom = std::max( b_pos, b_pos + b_thickness );
1732 aThickness = (
top - bottom );
1746 m_reporter->Report( wxString::Format(
_(
"Board stackup does not define a board thickness; "
1747 "exporting a %.3f mm board body." ),
1752 wxASSERT( aZPos == 0.0 );
1758 const wxString& aRefDes )
1760 double f_pos, f_thickness;
1761 double b_pos, b_thickness;
1765 double boardSurfaceZ;
1768 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1770 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1772 double bodyThickness = aHeight - aStandoff;
1776 zBot = boardSurfaceZ + aStandoff;
1778 zBot = boardSurfaceZ - aHeight;
1788 if( aStandoff <= 0.0 )
1804 double f_pos, f_thickness;
1805 double b_pos, b_thickness;
1809 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1810 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1812 static const double c_protrusion = 1.0;
1814 double pinZBot, pinHeight;
1818 pinZBot = boardBotZ - c_protrusion;
1819 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1823 double pinZTop = boardTopZ + c_protrusion;
1824 pinZBot = boardBotZ - aStandoff;
1825 pinHeight = pinZTop - pinZBot;
1836 const VECTOR2D& aOrigin,
const wxString& aNetname )
1838 bool success =
true;
1846 double z_pos, thickness;
1849 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1857 else if( aLayer ==
F_Mask )
1864 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1877 const std::vector<wxString>& aAltFilenames,
1878 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1880 VECTOR3D aScale,
bool aSubstituteModels )
1882 if( aFileName.empty() )
1884 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1893 wxString errorMessage;
1895 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1898 if( errorMessage.IsEmpty() )
1899 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1906 TopLoc_Location toploc;
1908 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1911 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1917 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1919 if( llabel.IsNull() )
1922 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1930 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1931 TDataStd_Name::Set( llabel, refdes );
1942 m_assy->UpdateAssemblies();
2014 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
2015 double aZposition,
const VECTOR2D& aOrigin )
2022 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
2023 double h_width = aWidth/2.0;
2025 coords[0] =
VECTOR2D{ 0.0, h_width };
2028 coords[1] =
VECTOR2D{ len, h_width };
2031 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
2034 coords[3] =
VECTOR2D{ len, -h_width };
2037 coords[4] =
VECTOR2D{ 0, -h_width };
2040 coords[5] =
VECTOR2D{ -h_width, 0.0 };
2043 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
2045 for(
int ii = 0; ii < 6; ii++ )
2048 coords[ii] += aStartPoint;
2053 gp_Pnt coords3D[ 6 ];
2055 for(
int ii = 0; ii < 6; ii++ )
2057 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
2058 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
2062 BRepBuilderAPI_MakeWire wire;
2063 bool success =
true;
2075 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2080 edge = BRepBuilderAPI_MakeEdge(
circle );
2085 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2088 Handle( Geom_TrimmedCurve ) arcOfCircle =
2089 GC_MakeArcOfCircle( coords3D[1],
2093 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2096 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2099 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2100 GC_MakeArcOfCircle( coords3D[4],
2104 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2108 catch(
const Standard_Failure& e )
2110 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2111 e.GetMessageString() ),
2116 BRepBuilderAPI_MakeFace face;
2120 gp_Pln plane( coords3D[0], gp::DZ() );
2121 face = BRepBuilderAPI_MakeFace( plane, wire );
2123 catch(
const Standard_Failure& e )
2125 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2126 e.GetMessageString() ),
2131 if( aThickness != 0.0 )
2133 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2135 if( aShape.IsNull() )
2137 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2154 double aZposition,
const VECTOR2D& aOrigin )
2156 std::vector<TopoDS_Shape> testShapes;
2159 aHeight, aZposition, aOrigin );
2161 if( testShapes.size() > 0 )
2162 aShape = testShapes.front();
2185 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2189 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2191 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2192 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2202 gp_Pnt start = toPoint( aPt0 );
2203 gp_Pnt
end = toPoint( aPt1 );
2205 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2207 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2209 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2217 aMkWire.Add( mkEdge.Edge() );
2219 if( aMkWire.Error() != BRepLib_WireDone )
2221 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2235 Handle( Geom_Curve ) curve;
2237 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2239 gp_Ax2 axis = gp::XOY();
2240 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2242 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2246 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2247 toPoint( aArc.GetP1() ) ).Value();
2250 if( curve.IsNull() )
2253 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2255 if( !aMkWire.IsDone() )
2257 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2258 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2260 aArc.GetP0().x, aArc.GetP0().y,
2261 aArc.GetArcMid().x, aArc.GetArcMid().y,
2262 aArc.GetP1().x, aArc.GetP1().y ),
2272 bool isFirstShape =
true;
2285 if( nextShape != -1 )
2291 lastPt = aChain.
CPoint( i );
2301 firstPt = currentArc.
GetP0();
2306 lastPt = currentArc.
GetP0();
2308 if( addArc( lastPt, currentArc ) )
2309 lastPt = currentArc.
GetP1();
2328 isFirstShape =
false;
2331 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2333 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2335 firstPt.
x, firstPt.
y ),
2341 catch(
const Standard_Failure& e )
2343 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2344 e.GetMessageString() ),
2354 bool aConvertToArcs,
double aThickness,
double aZposition,
2362 if( aConvertToArcs )
2366 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2370 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2374 fallbackPoly = workingPoly;
2375 workingPoly = approximated;
2394 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2396 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2397 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2401 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2402 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2404 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2408 auto tryMakeWire = [
this, &aZposition,
2409 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2412 BRepLib_MakeWire mkWire;
2416 if( mkWire.IsDone() )
2418 wire = mkWire.Wire();
2423 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2424 "z: %g; bounding box: %s" ),
2425 static_cast<int>( aContour.PointCount() ),
2426 static_cast<int>( mkWire.Error() ),
2431 if( !wire.IsNull() )
2433 BRepAlgoAPI_Check check( wire,
false,
true );
2435 if( !check.IsValid() )
2437 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2438 "z: %g; bounding box: %s" ),
2450 BRepBuilderAPI_MakeFace mkFace;
2452 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2458 bool allow_retry = aConvertToArcs ? true :
false;
2460 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2462 if( aConvertToArcs && wire.IsNull() )
2464 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2468 allow_retry =
false;
2469 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2474 if( !wire.IsNull() )
2476 if( basePlane.Axis().Direction().Z() < 0 )
2479 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2483 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2484 "z: %g; bounding box: %s" ),
2493 if( !wire.IsNull() )
2495 if( basePlane.Axis().Direction().Z() > 0 )
2502 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2503 "z: %g; bounding box: %s" ),
2510 catch(
const Standard_Failure& e )
2512 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2513 static_cast<int>( contId ),
2514 e.GetMessageString() ),
2520 if( mkFace.IsDone() )
2522 TopoDS_Shape faceShape = mkFace.Shape();
2524 if( aThickness != 0.0 )
2526 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2527 aShapes.push_back( prism );
2529 if( prism.IsNull() )
2537 aShapes.push_back( faceShape );
2553 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2554 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2555 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2556 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2557 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2558 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2559 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2560 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2570 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2572 aColorOut =
COLOR4D( aColorStr );
2577 const std::vector<FAB_LAYER_COLOR>& colors =
2584 if( fabColor.GetName() == aColorStr )
2586 aColorOut = fabColor.GetColor( aType );
2608 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2613 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2618 double boardThickness;
2638 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2642 polyset.
Append( contour );
2649 m_reporter->Report(
_(
"OCC error creating main outline." ),
2658 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2670 BRepBndLib::Add( brdShape, brdBndBox );
2673 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2678 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2679 std::vector<Bnd_Box>& holeBoxes )
2683 Bnd_Box brdWithHolesBndBox = brdBndBox;
2685 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2686 holeBoxes.resize( input.size() );
2688 for(
size_t i = 0; i < input.size(); i++ )
2691 BRepBndLib::Add( input[i], bbox );
2692 brdWithHolesBndBox.Add( bbox );
2693 ( *holeBoxSet )[i] = bbox;
2694 holeBoxes[i] = bbox;
2697 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2700 auto subtractShapesMap =
2701 [
this, &
tp](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2702 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2703 const std::vector<Bnd_Box>& aHoleBoxes )
2705 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2708 for(
auto& [netname, vec] : aShapesMap )
2716 auto subtractLoopFn = [&](
const int shapeId )
2718 TopoDS_Shape& shape = vec[shapeId];
2721 BRepBndLib::Add( shape, shapeBbox );
2723 NCollection_List<TopoDS_Shape> holelist;
2726 std::unique_lock lock( mutex );
2728 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2730 for(
const int&
index : indices )
2731 holelist.Append( aHolesList[
index] );
2737 if( holelist.IsEmpty() )
2739 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2741 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2742 holelist.Append( aHolesList[i] );
2747 if( holelist.IsEmpty() )
2750 NCollection_List<TopoDS_Shape> cutArgs;
2751 cutArgs.Append( shape );
2753 BRepAlgoAPI_Cut
cut;
2757 cut.SetNonDestructive(
true );
2758 cut.SetRunParallel(
false );
2759 cut.SetToFillHistory(
false );
2761 cut.SetArguments( cutArgs );
2762 cut.SetTools( holelist );
2765 if(
cut.HasErrors() ||
cut.HasWarnings() )
2767 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2776 std::unique_lock lock( mutex );
2780 if(
cut.HasErrors() )
2782 wxString msg =
_(
"Errors:\n" );
2783 wxStringOutputStream os_stream( &msg );
2784 wxStdOutputStream out( os_stream );
2786 cut.DumpErrors( out );
2790 if(
cut.HasWarnings() )
2792 wxString msg =
_(
"Warnings:\n" );
2793 wxStringOutputStream os_stream( &msg );
2794 wxStdOutputStream out( os_stream );
2796 cut.DumpWarnings( out );
2801 shape =
cut.Shape();
2807 BS::multi_future<void> cutFutures;
2811 cutFutures =
tp.submit_loop( 0, vec.size(), subtractLoopFn );
2824 auto subtractShapes =
2825 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2826 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2827 const std::vector<Bnd_Box>& aHoleBoxes )
2829 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2831 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2832 aShapesList = aShapesMap[wxEmptyString];
2838 Bnd_BoundSortBox bsbHoles;
2839 std::vector<Bnd_Box> holeBoxes;
2847 Bnd_BoundSortBox bsbHoles;
2848 std::vector<Bnd_Box> holeBoxes;
2857 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2859 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2860 const std::vector<TopoDS_Shape>& aShapes )
2862 for(
const TopoDS_Shape& shape : aShapes )
2863 shapesToFuseMap[aNetname].Append( shape );
2867 addShapes( netname, shapes );
2870 addShapes( netname, shapes );
2873 addShapes( netname, shapes );
2881 std::vector<std::pair<wxString, const NCollection_List<TopoDS_Shape>*>> fuseWork;
2882 fuseWork.reserve( shapesToFuseMap.size() );
2884 for(
const auto& [netname, toFuse] : shapesToFuseMap )
2885 fuseWork.emplace_back( netname, &toFuse );
2888 BS::multi_future<void> mf;
2889 mf.reserve( fuseWork.size() );
2895 for(
const auto& work : fuseWork )
2897 const wxString netname = work.first;
2898 const NCollection_List<TopoDS_Shape>* toFuse = work.second;
2900 mf.push_back(
tp.submit_task(
2901 [
this, &mutex, netname, toFuse]()
2903 TopoDS_Shape fusedShape = fuseShapesOrCompound( *toFuse, m_reporter );
2905 if( !fusedShape.IsNull() )
2907 std::unique_lock lock( mutex );
2909 m_board_copper_fused[netname].emplace_back( fusedShape );
2911 m_board_copper[netname].clear();
2912 m_board_copper_pads[netname].clear();
2913 m_board_copper_vias[netname].clear();
2940 auto pushToAssemblyMap =
2941 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2942 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2943 bool aCompoundAll,
const wxString& aNiceName )
2945 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2949 std::vector<TopoDS_Shape> allShapes;
2951 for(
const auto& [netname, shapesList] : aShapesMap )
2952 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2954 if( !allShapes.empty() )
2955 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2959 shapesMap = aShapesMap;
2962 for(
const auto& [netname, shapesList] : shapesMap )
2964 std::vector<TopoDS_Shape> newList;
2969 newList = shapesList;
2973 for( TopoDS_Shape& shape : newList )
2975 Handle( TDataStd_TreeNode ) node;
2978 TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape,
false );
2980 m_pcb_labels.push_back( lbl );
2982 if( m_pcb_labels.back().IsNull() )
2985 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2986 TDF_Label shpLbl = node->Father()->Label();
2988 if( !shpLbl.IsNull() )
2990 if( visMatTool && !aVisMatLabel.IsNull() )
2991 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2995 shapeName << m_pcbName;
2997 shapeName << aShapeName;
2999 if( !netname.empty() )
3002 shapeName << netname;
3005 if( newList.size() > 1 )
3011 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
3012 TDataStd_Name::Set( shpLbl, partname );
3020 auto pushToAssembly =
3021 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
3022 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
3024 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
3026 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
3030 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
3031 double aMetallic,
double aRoughness ) -> TDF_Label
3033 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
3034 XCAFDoc_VisMaterialPBR pbr;
3035 pbr.BaseColor = aBaseColor;
3036 pbr.Metallic = aMetallic;
3037 pbr.Roughness = aRoughness;
3038 vismat->SetPbrMaterial( pbr );
3039 return visMatTool->AddMaterial( vismat, aName );
3043 Quantity_ColorRGBA copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], 1.0 );
3044 Quantity_ColorRGBA pad_color( m_padColor[0], m_padColor[1], m_padColor[2], 1.0 );
3046 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
3047 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
3048 Quantity_ColorRGBA back_silk_color = front_silk_color;
3049 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
3050 Quantity_ColorRGBA back_mask_color = front_mask_color;
3060 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
3064 if( item->GetBrdLayerId() ==
F_Mask )
3065 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3067 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3070 if( item->GetBrdLayerId() ==
F_SilkS )
3071 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3072 else if( item->GetBrdLayerId() ==
B_SilkS )
3073 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3076 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3080 if( !m_enabledLayers.Contains(
F_Mask ) && !m_enabledLayers.Contains(
B_Mask ) )
3082 board_color = front_mask_color;
3083 board_color.SetAlpha( 1.0 );
3086 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
3087 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
3088 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
3089 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
3090 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
3091 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
3092 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
3094 pushToAssemblyMap( m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
3095 pushToAssemblyMap( m_board_copper_pads, pad_mat,
"pad",
true,
true,
"Pads" );
3096 pushToAssemblyMap( m_board_copper_vias, copper_mat,
"via",
true,
true,
"Via" );
3097 pushToAssemblyMap( m_board_copper_fused, copper_mat,
"copper",
true,
true,
"Copper" );
3098 pushToAssembly( m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
3099 pushToAssembly( m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
3100 pushToAssembly( m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
3101 pushToAssembly( m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
3103 if( aPushBoardBody )
3104 pushToAssembly( m_board_outlines, board_mat,
"PCB",
false,
"Body" );
3106 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
3107 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
3109 for(
auto& entry : m_extruded_bodies )
3111 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
3114 TopoDS_Compound asmCompound;
3115 BRep_Builder asmBuilder;
3116 asmBuilder.MakeCompound( asmCompound );
3117 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
3118 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
3120 if( !entry.bodyShapes.empty() )
3122 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
3123 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
3124 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
3125 double a = ( entry.colorKey & 0xFF ) / 255.0;
3127 double metallic, roughness;
3129 switch( entry.material )
3150 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3151 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3153 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3154 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3156 Handle( TDataStd_TreeNode ) bodyNode;
3157 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3158 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3160 if( !bodyShpLbl.IsNull() )
3162 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3163 TDataStd_Name::Set( bodyShpLbl,
3164 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3170 for( TopoDS_Shape& pinShape : entry.pinShapes )
3172 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3174 Handle( TDataStd_TreeNode ) pinNode;
3175 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3176 TDF_Label pinShpLbl = pinNode->Father()->Label();
3178 if( !pinShpLbl.IsNull() )
3180 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3181 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3182 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3186 TopLoc_Location loc;
3187 TDF_Label fpCompLbl = m_assy->AddComponent( m_assy_label, fpLabel, loc );
3188 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3190 m_pcb_labels.push_back( fpCompLbl );
3193#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3194 m_assy->UpdateAssemblies();
3203bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3207 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3215 wxFileName fn( aFileName );
3216 IGESControl_Controller::Init();
3217 IGESCAFControl_Writer writer;
3218 writer.SetColorMode(
true );
3219 writer.SetNameMode(
true );
3220 IGESData_GlobalSection header = writer.Model()->GlobalSection();
3221 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3222 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3223 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3224 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3225 writer.Model()->SetGlobalSection( header );
3227 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3236 wxFileInputStream input( inputFile );
3237 wxFileOutputStream output( outputFile );
3241 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3245 if( !output.IsOk() )
3247 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3251 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
3253 if( !zlibStream.IsOk() )
3255 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3259 input.Read( zlibStream );
3261 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3263 m_reporter->Report(
_(
"Compress read or write error" ) );
3277 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3285 wxFileName fn( aFileName );
3287 STEPCAFControl_Writer writer;
3288 writer.SetColorMode(
true );
3289 writer.SetNameMode(
true );
3296 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3298 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3304 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3306 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3310 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3313 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3317 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3320 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3321 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3322 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3323 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3325 bool success =
true;
3328 wxString currCWD = wxGetCwd();
3329 wxString workCWD = fn.GetPath();
3331 if( !workCWD.IsEmpty() )
3332 wxSetWorkingDirectory( workCWD );
3334 wxString tmpfname(
"$tempfile$.step" );
3336 if(
false == writer.Write( tmpfname.c_str() ) )
3339 if( compress && success )
3341 wxString srcTmp( tmpfname );
3342 wxString dstTmp(
"$tempfile$.stpz" );
3345 wxRemoveFile( srcTmp );
3356 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3358 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3366 wxSetWorkingDirectory( currCWD );
3376 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3385 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3390 wxFileName fn( aFileName );
3392 wxFFileOutputStream ffStream( fn.GetFullPath() );
3393 wxStdOutputStream stdStream( ffStream );
3395#if OCC_VERSION_HEX >= 0x070600
3396 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3398 BRepTools::Write( shape, stdStream );
3407 wxFileName fn( aFileName );
3409 wxFFileOutputStream ffStream( fn.GetFullPath() );
3410 wxStdOutputStream file( ffStream );
3412 if( !ffStream.IsOk() )
3414 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3422 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3427 std::map<wxString, std::vector<int>> groups[4];
3428 std::map<wxString, double> groupAreas;
3429 TopExp_Explorer exp;
3432 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3434 TopoDS_Shape subShape = exp.Current();
3437 BRepBndLib::Add( subShape, bbox );
3441 for(
const auto& pair : pairs )
3443 const auto& [point, padTestShape] = pair;
3445 if( bbox.IsOut( point ) )
3448 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3450 if( surface.GetType() != GeomAbs_Plane )
3453 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3456 if( !dist.IsDone() )
3459 if( dist.Value() < Precision::Approximation() )
3462 groups[2][padKey].push_back( faceIndex );
3464 GProp_GProps system;
3465 BRepGProp::SurfaceProperties( subShape, system );
3467 double surfaceArea = system.Mass() / 1e6;
3468 groupAreas[padKey] += surfaceArea;
3477 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3478 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3479 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3480 file <<
" <shape format=\"BREP\"><![CDATA[";
3481#if OCC_VERSION_HEX < 0x070600
3482 BRepTools::Write( shape, file );
3484 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3486 file <<
"]]></shape>" << std::endl;
3487 file <<
" <topology>" << std::endl;
3489 TopTools_IndexedMapOfShape mainMap;
3490 TopExp::MapShapes( shape, mainMap );
3491 std::set<int> topo[4];
3493 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3496 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3497 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3499 for(
int dim = 0; dim < 4; dim++ )
3501 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3503 TopoDS_Shape subShape = exp.Current();
3504 int idx = mainMap.FindIndex( subShape );
3506 if( idx && !topo[dim].count( idx ) )
3507 topo[dim].insert( idx );
3511 for(
int dim = 0; dim <= 3; dim++ )
3513 std::string labels = c_dimLabels[dim];
3514 std::string label = c_dimLabel[dim];
3516 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3519 for(
auto p : topo[dim] )
3521 std::string
name(
"" );
3522 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3523 <<
"name=\"" <<
name <<
"\" "
3524 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3528 file <<
" </" << labels <<
">" << std::endl;
3531 file <<
" </topology>" << std::endl;
3532 file <<
" </geometry>" << std::endl;
3533 file <<
" <groups count=\""
3534 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3537 int groupNumber = 1;
3542 for(
int dim = 0; dim <= 3; dim++ )
3544 std::string label = c_dimLabel[dim];
3546 for(
auto g : groups[dim] )
3549 wxString
name = g.first;
3553 std::ostringstream gs;
3554 gs <<
"G_" << dim <<
"D_" << g.first;
3557 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3563 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3565 for(
auto index : g.second )
3566 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3568 file <<
" </group>" << std::endl;
3570 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3582 file <<
" </groups>" << std::endl;
3583 file <<
" <fields count=\"0\"/>" << std::endl;
3584 file <<
"</XAO>" << std::endl;
3591 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3592 TDF_Label& aLabel,
bool aSubstituteModels,
3593 wxString* aErrorMessage )
3595 std::string fileNameUTF8 = aFileName.utf8_string();
3597 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3598 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3600 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3604 aLabel = mm->second;
3610 Handle( TDocStd_Document ) doc;
3611 m_app->NewDocument(
"MDTV-XCAF", doc );
3614 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3619 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3621 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3629 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3631 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3642 wxFFileInputStream ifile( aFileName );
3643 wxFileName outFile( aFileName );
3645 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3646 outFile.SetExt( wxT(
"step" ) );
3647 wxFileOffset size = ifile.GetLength();
3649 if( size == wxInvalidOffset )
3651 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3658 bool success =
false;
3661 wxFFileOutputStream ofile( outFile.GetFullPath() );
3666 char* buffer =
new char[size];
3668 ifile.Read( buffer, size );
3669 std::string expanded;
3673 expanded = gzip::decompress( buffer, size );
3681 if( expanded.empty() )
3685 wxZipInputStream izipfile( ifile );
3686 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3688 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3690 izipfile.Read( ofile );
3695 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3701 ofile.Write( expanded.data(), expanded.size() );
3709 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3710 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3729 if( aSubstituteModels )
3731 wxFileName wrlName( aFileName );
3733 wxString basePath = wrlName.GetPath();
3734 wxString baseName = wrlName.GetName();
3742 alts.Add( wxT(
"stp" ) );
3743 alts.Add( wxT(
"step" ) );
3744 alts.Add( wxT(
"STP" ) );
3745 alts.Add( wxT(
"STEP" ) );
3746 alts.Add( wxT(
"Stp" ) );
3747 alts.Add( wxT(
"Step" ) );
3748 alts.Add( wxT(
"stpz" ) );
3749 alts.Add( wxT(
"stpZ" ) );
3750 alts.Add( wxT(
"STPZ" ) );
3751 alts.Add( wxT(
"step.gz" ) );
3752 alts.Add( wxT(
"stp.gz" ) );
3755 alts.Add( wxT(
"iges" ) );
3756 alts.Add( wxT(
"IGES" ) );
3757 alts.Add( wxT(
"igs" ) );
3758 alts.Add( wxT(
"IGS" ) );
3762 for(
const auto& altExt : alts )
3766 if( !aAltFilenames.empty() )
3768 for(
const wxString& altPath : aAltFilenames )
3770 wxFileName iterFn( altPath );
3772 if( iterFn.GetExt() == altExt )
3781 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3784 if( altFile.IsOk() && altFile.FileExists() )
3794 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3808 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3810 Handle( XCAFDoc_ShapeTool ) shapeTool =
3811 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3818 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3828 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3838 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3845 if( aLabel.IsNull() )
3847 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3854 TDataStd_Name::Set( aLabel, partname );
3864 TopLoc_Location& aLocation )
3878 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3884 double boardThickness;
3887 double top = std::max( boardZPos, boardZPos + boardThickness );
3888 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3893 double f_pos, f_thickness;
3897 bottom += f_thickness;
3904 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3905 lPos.Multiply( lRot );
3906 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3907 lPos.Multiply( lRot );
3912 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3913 lPos.Multiply( lRot );
3917 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3918 lPos.Multiply( lOff );
3921 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3922 lPos.Multiply( lOrient );
3923 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3924 lPos.Multiply( lOrient );
3925 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3926 lPos.Multiply( lOrient );
3928 aLocation = TopLoc_Location( lPos );
3935 IGESControl_Controller::Init();
3936 IGESCAFControl_Reader reader;
3937 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3939 if( stat != IFSelect_RetDone )
3943 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3947 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3951 reader.SetColorMode(
true );
3952 reader.SetNameMode(
false );
3953 reader.SetLayerMode(
false );
3955 if( !reader.Transfer( doc ) )
3957 if( doc->CanClose() == CDM_CCS_OK )
3964 if( reader.NbShapes() < 1 )
3966 if( doc->CanClose() == CDM_CCS_OK )
3978 STEPCAFControl_Reader reader;
3979 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3981 if( stat != IFSelect_RetDone )
3985 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3989 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3993 reader.SetColorMode(
true );
3994 reader.SetNameMode(
true );
3995 reader.SetLayerMode(
false );
3997 if( !reader.Transfer( doc ) )
3999 if( doc->CanClose() == CDM_CCS_OK )
4006 if( reader.NbRootsForTransfer() < 1 )
4008 if( doc->CanClose() == CDM_CCS_OK )
4020#if OCC_VERSION_HEX >= 0x070700
4021 VrmlAPI_CafReader reader;
4022 RWMesh_CoordinateSystemConverter conv;
4023 conv.SetInputLengthUnit( 2.54 );
4024 reader.SetCoordinateSystemConverter( conv );
4025 reader.SetDocument( doc );
4027 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
4040 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
4042 NCollection_Sequence<TDF_Label> frshapes;
4043 s_assy->GetFreeShapes( frshapes );
4045 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
4054 TDF_Label d_targetLabel = d_assy->NewShape();
4056 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
4062 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
4065 return d_targetLabel;
4071 NCollection_Sequence<TDF_Label> freeShapes;
4072 aShapeTool->GetFreeShapes( freeShapes );
4078 for(
int i = 1; i <= freeShapes.Length(); ++i )
4080 TDF_Label label = freeShapes.Value( i );
4082 aShapeTool->GetShape( label, shape );
4087 const double linearDeflection = 0.14;
4088 const double angularDeflection =
DEG2RAD( 30.0 );
4089 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
4111 wxFileName fn( aFileName );
4113 const char* tmpGltfname =
"$tempfile$.glb";
4114 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
4116 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
4117 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4118 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
4119 RWMesh_CoordinateSystem_Zup );
4120#if OCC_VERSION_HEX >= 0x070700
4121 cafWriter.SetParallel(
true );
4123 TColStd_IndexedDataMapOfStringString metadata;
4125 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4126 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4127 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4128 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4129 metadata.Add( TCollection_AsciiString(
"generator" ),
4130 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4131 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4134 bool success =
true;
4137 wxString currCWD = wxGetCwd();
4138 wxString workCWD = fn.GetPath();
4140 if( !workCWD.IsEmpty() )
4141 wxSetWorkingDirectory( workCWD );
4143 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4152 m_reporter->Report(
_(
"Could not post-process GLB line primitives; the exported "
4153 "model may not import in strict glTF viewers." ),
4160 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4162 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4170 wxSetWorkingDirectory( currCWD );
4178#if OCC_VERSION_HEX < 0x070700
4185 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4195 wxFileName fn( aFileName );
4197 const char* tmpFname =
"$tempfile$.ply";
4198 RWPly_CafWriter cafWriter( tmpFname );
4200 cafWriter.SetFaceId(
true );
4201 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4202 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4204 TColStd_IndexedDataMapOfStringString metadata;
4206 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4207 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4208 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4209 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4210 metadata.Add( TCollection_AsciiString(
"generator" ),
4211 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4213 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4216 bool success =
true;
4219 wxString currCWD = wxGetCwd();
4220 wxString workCWD = fn.GetPath();
4222 if( !workCWD.IsEmpty() )
4223 wxSetWorkingDirectory( workCWD );
4225 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4232 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4234 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4242 wxSetWorkingDirectory( currCWD );
4253 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4263 wxFileName fn( aFileName );
4265 const char* tmpFname =
"$tempfile$.stl";
4268 wxString currCWD = wxGetCwd();
4269 wxString workCWD = fn.GetPath();
4271 if( !workCWD.IsEmpty() )
4272 wxSetWorkingDirectory( workCWD );
4274 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4281 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4283 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4291 wxSetWorkingDirectory( currCWD );
4303 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4312 wxFileName fn( aFileName );
4314 const char* tmpFname =
"$tempfile$.u3d";
4317 wxString currCWD = wxGetCwd();
4318 wxString workCWD = fn.GetPath();
4320 if( !workCWD.IsEmpty() )
4321 wxSetWorkingDirectory( workCWD );
4324 bool success = writer.
Perform( m_doc );
4330 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4332 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4339 wxSetWorkingDirectory( currCWD );
4350 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4359 wxFileName fn( aFileName );
4361 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4362 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4364 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4365 bool success = writer.
Perform( m_doc );
4368 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4370 plotter->SetColorMode(
true );
4371 plotter->Set3DExport(
true );
4372 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4374 plotter->SetRenderSettings( &renderSettings );
4376 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4378 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4384 plotter->StartPlot(
"1",
"3D Model" );
4385 double fov_degrees = 16.5f;
4390 std::vector<PDF_3D_VIEW> views;
4395 std::vector<float> c2wMatrix =
4399 .m_name =
"Default",
4400 .m_cameraMatrix = c2wMatrix,
4401 .m_cameraCenter = (float)
distance,
4402 .m_fov = (
float) fov_degrees,
4411 .m_cameraMatrix = c2wMatrix,
4412 .m_cameraCenter = (float)
distance,
4413 .m_fov = (
float) fov_degrees,
4422 .m_cameraMatrix = c2wMatrix,
4423 .m_cameraCenter = (float)
distance,
4424 .m_fov = (
float) fov_degrees,
4433 .m_cameraMatrix = c2wMatrix,
4434 .m_cameraCenter = (float)
distance,
4435 .m_fov = (
float) fov_degrees,
4438 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4447 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4449 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4450 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4456 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.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
VECTOR2I GetDrillSize() 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.
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.
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
const VECTOR2I & GetArcMid() const
VECTOR2I NearestPoint(const VECTOR2I &aP) 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)
double getStackupBodyThickness() const
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)
SYNC_REPORTER m_syncReporter
Thread-safe wrapper around the caller's reporter.
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)
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
bool FixGlbLinesPrimitives(const wxString &aFilePath)
Fix LINES primitives in a GLB file that have odd index counts.
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.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) 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 ...
static constexpr double BOARD_THICKNESS_DEFAULT_MM
std::pair< std::string, TDF_Label > MODEL_DATUM
static constexpr double BOARD_THICKNESS_MIN_MM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
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