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;
1786 double aStandoff,
const VECTOR2D& aOrigin )
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 zOffset = aBody ? aBody->
m_offset.
z : 0.0;
1816 double pinZBot, pinHeight;
1820 pinZBot = boardBotZ - c_protrusion + zOffset;
1821 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1825 double pinZTop = boardTopZ + c_protrusion - zOffset;
1826 pinZBot = boardBotZ - aStandoff;
1827 pinHeight = pinZTop - pinZBot;
1833 bool success =
true;
1848 const VECTOR2D& aOrigin,
const wxString& aNetname )
1850 bool success =
true;
1858 double z_pos, thickness;
1861 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1869 else if( aLayer ==
F_Mask )
1876 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1889 const std::vector<wxString>& aAltFilenames,
1890 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1892 VECTOR3D aScale,
bool aSubstituteModels )
1894 if( aFileName.empty() )
1896 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1905 wxString errorMessage;
1907 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1910 if( errorMessage.IsEmpty() )
1911 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1918 TopLoc_Location toploc;
1920 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1923 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1929 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1931 if( llabel.IsNull() )
1934 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1942 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1943 TDataStd_Name::Set( llabel, refdes );
1954 m_assy->UpdateAssemblies();
2026 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
2027 double aZposition,
const VECTOR2D& aOrigin )
2034 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
2035 double h_width = aWidth/2.0;
2037 coords[0] =
VECTOR2D{ 0.0, h_width };
2040 coords[1] =
VECTOR2D{ len, h_width };
2043 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
2046 coords[3] =
VECTOR2D{ len, -h_width };
2049 coords[4] =
VECTOR2D{ 0, -h_width };
2052 coords[5] =
VECTOR2D{ -h_width, 0.0 };
2055 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
2057 for(
int ii = 0; ii < 6; ii++ )
2060 coords[ii] += aStartPoint;
2065 gp_Pnt coords3D[ 6 ];
2067 for(
int ii = 0; ii < 6; ii++ )
2069 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
2070 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
2074 BRepBuilderAPI_MakeWire wire;
2075 bool success =
true;
2087 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2092 edge = BRepBuilderAPI_MakeEdge(
circle );
2097 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2100 Handle( Geom_TrimmedCurve ) arcOfCircle =
2101 GC_MakeArcOfCircle( coords3D[1],
2105 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2108 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2111 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2112 GC_MakeArcOfCircle( coords3D[4],
2116 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2120 catch(
const Standard_Failure& e )
2122 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2123 e.GetMessageString() ),
2128 BRepBuilderAPI_MakeFace face;
2132 gp_Pln plane( coords3D[0], gp::DZ() );
2133 face = BRepBuilderAPI_MakeFace( plane, wire );
2135 catch(
const Standard_Failure& e )
2137 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2138 e.GetMessageString() ),
2143 if( aThickness != 0.0 )
2145 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2147 if( aShape.IsNull() )
2149 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2166 double aZposition,
const VECTOR2D& aOrigin )
2168 std::vector<TopoDS_Shape> testShapes;
2171 aHeight, aZposition, aOrigin );
2173 if( testShapes.size() > 0 )
2174 aShape = testShapes.front();
2197 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2201 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2203 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2204 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2214 gp_Pnt start = toPoint( aPt0 );
2215 gp_Pnt
end = toPoint( aPt1 );
2217 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2219 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2221 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2229 aMkWire.Add( mkEdge.Edge() );
2231 if( aMkWire.Error() != BRepLib_WireDone )
2233 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2247 Handle( Geom_Curve ) curve;
2249 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2251 gp_Ax2 axis = gp::XOY();
2252 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2254 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2258 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2259 toPoint( aArc.GetP1() ) ).Value();
2262 if( curve.IsNull() )
2265 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2267 if( !aMkWire.IsDone() )
2269 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2270 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2272 aArc.GetP0().x, aArc.GetP0().y,
2273 aArc.GetArcMid().x, aArc.GetArcMid().y,
2274 aArc.GetP1().x, aArc.GetP1().y ),
2284 bool isFirstShape =
true;
2297 if( nextShape != -1 )
2303 lastPt = aChain.
CPoint( i );
2313 firstPt = currentArc.
GetP0();
2318 lastPt = currentArc.
GetP0();
2320 if( addArc( lastPt, currentArc ) )
2321 lastPt = currentArc.
GetP1();
2340 isFirstShape =
false;
2343 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2345 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2347 firstPt.
x, firstPt.
y ),
2353 catch(
const Standard_Failure& e )
2355 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2356 e.GetMessageString() ),
2366 bool aConvertToArcs,
double aThickness,
double aZposition,
2374 if( aConvertToArcs )
2378 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2382 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2386 fallbackPoly = workingPoly;
2387 workingPoly = approximated;
2406 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2408 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2409 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2413 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2414 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2416 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2420 auto tryMakeWire = [
this, &aZposition,
2421 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2424 BRepLib_MakeWire mkWire;
2428 if( mkWire.IsDone() )
2430 wire = mkWire.Wire();
2435 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2436 "z: %g; bounding box: %s" ),
2437 static_cast<int>( aContour.PointCount() ),
2438 static_cast<int>( mkWire.Error() ),
2443 if( !wire.IsNull() )
2445 BRepAlgoAPI_Check check( wire,
false,
true );
2447 if( !check.IsValid() )
2449 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2450 "z: %g; bounding box: %s" ),
2462 BRepBuilderAPI_MakeFace mkFace;
2464 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2470 bool allow_retry = aConvertToArcs ? true :
false;
2472 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2474 if( aConvertToArcs && wire.IsNull() )
2476 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2480 allow_retry =
false;
2481 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2486 if( !wire.IsNull() )
2488 if( basePlane.Axis().Direction().Z() < 0 )
2491 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2495 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2496 "z: %g; bounding box: %s" ),
2505 if( !wire.IsNull() )
2507 if( basePlane.Axis().Direction().Z() > 0 )
2514 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2515 "z: %g; bounding box: %s" ),
2522 catch(
const Standard_Failure& e )
2524 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2525 static_cast<int>( contId ),
2526 e.GetMessageString() ),
2532 if( mkFace.IsDone() )
2534 TopoDS_Shape faceShape = mkFace.Shape();
2536 if( aThickness != 0.0 )
2538 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2539 aShapes.push_back( prism );
2541 if( prism.IsNull() )
2549 aShapes.push_back( faceShape );
2565 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2566 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2567 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2568 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2569 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2570 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2571 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2572 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2582 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2584 aColorOut =
COLOR4D( aColorStr );
2589 const std::vector<FAB_LAYER_COLOR>& colors =
2596 if( fabColor.GetName() == aColorStr )
2598 aColorOut = fabColor.GetColor( aType );
2620 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2625 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2630 double boardThickness;
2650 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2654 polyset.
Append( contour );
2661 m_reporter->Report(
_(
"OCC error creating main outline." ),
2670 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2682 BRepBndLib::Add( brdShape, brdBndBox );
2685 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2690 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2691 std::vector<Bnd_Box>& holeBoxes )
2695 Bnd_Box brdWithHolesBndBox = brdBndBox;
2697 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2698 holeBoxes.resize( input.size() );
2700 for(
size_t i = 0; i < input.size(); i++ )
2703 BRepBndLib::Add( input[i], bbox );
2704 brdWithHolesBndBox.Add( bbox );
2705 ( *holeBoxSet )[i] = bbox;
2706 holeBoxes[i] = bbox;
2709 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2712 auto subtractShapesMap =
2713 [
this, &
tp](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2714 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2715 const std::vector<Bnd_Box>& aHoleBoxes )
2717 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2720 for(
auto& [netname, vec] : aShapesMap )
2728 auto subtractLoopFn = [&](
const int shapeId )
2730 TopoDS_Shape& shape = vec[shapeId];
2733 BRepBndLib::Add( shape, shapeBbox );
2735 NCollection_List<TopoDS_Shape> holelist;
2738 std::unique_lock lock( mutex );
2740 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2742 for(
const int&
index : indices )
2743 holelist.Append( aHolesList[
index] );
2749 if( holelist.IsEmpty() )
2751 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2753 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2754 holelist.Append( aHolesList[i] );
2759 if( holelist.IsEmpty() )
2762 NCollection_List<TopoDS_Shape> cutArgs;
2763 cutArgs.Append( shape );
2765 BRepAlgoAPI_Cut
cut;
2769 cut.SetNonDestructive(
true );
2770 cut.SetRunParallel(
false );
2771 cut.SetToFillHistory(
false );
2773 cut.SetArguments( cutArgs );
2774 cut.SetTools( holelist );
2777 if(
cut.HasErrors() ||
cut.HasWarnings() )
2779 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2788 std::unique_lock lock( mutex );
2792 if(
cut.HasErrors() )
2794 wxString msg =
_(
"Errors:\n" );
2795 wxStringOutputStream os_stream( &msg );
2796 wxStdOutputStream out( os_stream );
2798 cut.DumpErrors( out );
2802 if(
cut.HasWarnings() )
2804 wxString msg =
_(
"Warnings:\n" );
2805 wxStringOutputStream os_stream( &msg );
2806 wxStdOutputStream out( os_stream );
2808 cut.DumpWarnings( out );
2813 shape =
cut.Shape();
2819 BS::multi_future<void> cutFutures;
2823 cutFutures =
tp.submit_loop( 0, vec.size(), subtractLoopFn );
2836 auto subtractShapes =
2837 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2838 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2839 const std::vector<Bnd_Box>& aHoleBoxes )
2841 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2843 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2844 aShapesList = aShapesMap[wxEmptyString];
2850 Bnd_BoundSortBox bsbHoles;
2851 std::vector<Bnd_Box> holeBoxes;
2859 Bnd_BoundSortBox bsbHoles;
2860 std::vector<Bnd_Box> holeBoxes;
2869 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2871 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2872 const std::vector<TopoDS_Shape>& aShapes )
2874 for(
const TopoDS_Shape& shape : aShapes )
2875 shapesToFuseMap[aNetname].Append( shape );
2879 addShapes( netname, shapes );
2882 addShapes( netname, shapes );
2885 addShapes( netname, shapes );
2893 std::vector<std::pair<wxString, const NCollection_List<TopoDS_Shape>*>> fuseWork;
2894 fuseWork.reserve( shapesToFuseMap.size() );
2896 for(
const auto& [netname, toFuse] : shapesToFuseMap )
2897 fuseWork.emplace_back( netname, &toFuse );
2900 BS::multi_future<void> mf;
2901 mf.reserve( fuseWork.size() );
2907 for(
const auto& work : fuseWork )
2909 const wxString netname = work.first;
2910 const NCollection_List<TopoDS_Shape>* toFuse = work.second;
2912 mf.push_back(
tp.submit_task(
2913 [
this, &mutex, netname, toFuse]()
2915 TopoDS_Shape fusedShape = fuseShapesOrCompound( *toFuse, m_reporter );
2917 if( !fusedShape.IsNull() )
2919 std::unique_lock lock( mutex );
2921 m_board_copper_fused[netname].emplace_back( fusedShape );
2923 m_board_copper[netname].clear();
2924 m_board_copper_pads[netname].clear();
2925 m_board_copper_vias[netname].clear();
2952 auto pushToAssemblyMap =
2953 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2954 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2955 bool aCompoundAll,
const wxString& aNiceName )
2957 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2961 std::vector<TopoDS_Shape> allShapes;
2963 for(
const auto& [netname, shapesList] : aShapesMap )
2964 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2966 if( !allShapes.empty() )
2967 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2971 shapesMap = aShapesMap;
2974 for(
const auto& [netname, shapesList] : shapesMap )
2976 std::vector<TopoDS_Shape> newList;
2981 newList = shapesList;
2985 for( TopoDS_Shape& shape : newList )
2987 Handle( TDataStd_TreeNode ) node;
2990 TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape,
false );
2992 m_pcb_labels.push_back( lbl );
2994 if( m_pcb_labels.back().IsNull() )
2997 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2998 TDF_Label shpLbl = node->Father()->Label();
3000 if( !shpLbl.IsNull() )
3002 if( visMatTool && !aVisMatLabel.IsNull() )
3003 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
3007 shapeName << m_pcbName;
3009 shapeName << aShapeName;
3011 if( !netname.empty() )
3014 shapeName << netname;
3017 if( newList.size() > 1 )
3023 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
3024 TDataStd_Name::Set( shpLbl, partname );
3032 auto pushToAssembly =
3033 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
3034 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
3036 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
3038 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
3042 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
3043 double aMetallic,
double aRoughness ) -> TDF_Label
3045 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
3046 XCAFDoc_VisMaterialPBR pbr;
3047 pbr.BaseColor = aBaseColor;
3048 pbr.Metallic = aMetallic;
3049 pbr.Roughness = aRoughness;
3050 vismat->SetPbrMaterial( pbr );
3051 return visMatTool->AddMaterial( vismat, aName );
3055 Quantity_ColorRGBA copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], 1.0 );
3056 Quantity_ColorRGBA pad_color( m_padColor[0], m_padColor[1], m_padColor[2], 1.0 );
3059 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 1.0f );
3060 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
3061 Quantity_ColorRGBA back_silk_color = front_silk_color;
3062 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
3063 Quantity_ColorRGBA back_mask_color = front_mask_color;
3073 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
3077 if( item->GetBrdLayerId() ==
F_Mask )
3078 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3080 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3083 if( item->GetBrdLayerId() ==
F_SilkS )
3084 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3085 else if( item->GetBrdLayerId() ==
B_SilkS )
3086 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3089 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3093 if( !m_enabledLayers.Contains(
F_Mask ) && !m_enabledLayers.Contains(
B_Mask ) )
3095 board_color = front_mask_color;
3096 board_color.SetAlpha( 1.0 );
3099 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
3100 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
3101 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
3102 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
3103 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
3104 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
3105 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
3107 pushToAssemblyMap( m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
3108 pushToAssemblyMap( m_board_copper_pads, pad_mat,
"pad",
true,
true,
"Pads" );
3109 pushToAssemblyMap( m_board_copper_vias, copper_mat,
"via",
true,
true,
"Via" );
3110 pushToAssemblyMap( m_board_copper_fused, copper_mat,
"copper",
true,
true,
"Copper" );
3111 pushToAssembly( m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
3112 pushToAssembly( m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
3113 pushToAssembly( m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
3114 pushToAssembly( m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
3116 if( aPushBoardBody )
3117 pushToAssembly( m_board_outlines, board_mat,
"PCB",
false,
"Body" );
3119 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
3120 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
3122 for(
auto& entry : m_extruded_bodies )
3124 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
3127 TopoDS_Compound asmCompound;
3128 BRep_Builder asmBuilder;
3129 asmBuilder.MakeCompound( asmCompound );
3130 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
3131 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
3133 if( !entry.bodyShapes.empty() )
3135 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
3136 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
3137 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
3138 double a = ( entry.colorKey & 0xFF ) / 255.0;
3140 double metallic, roughness;
3142 switch( entry.material )
3163 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3164 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3166 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3167 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3169 Handle( TDataStd_TreeNode ) bodyNode;
3170 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3171 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3173 if( !bodyShpLbl.IsNull() )
3175 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3176 TDataStd_Name::Set( bodyShpLbl,
3177 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3183 for( TopoDS_Shape& pinShape : entry.pinShapes )
3185 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3187 Handle( TDataStd_TreeNode ) pinNode;
3188 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3189 TDF_Label pinShpLbl = pinNode->Father()->Label();
3191 if( !pinShpLbl.IsNull() )
3193 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3194 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3195 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3199 TopLoc_Location loc;
3200 TDF_Label fpCompLbl = m_assy->AddComponent( m_assy_label, fpLabel, loc );
3201 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3203 m_pcb_labels.push_back( fpCompLbl );
3206#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3207 m_assy->UpdateAssemblies();
3216bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3220 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3228 wxFileName fn( aFileName );
3229 IGESControl_Controller::Init();
3230 IGESCAFControl_Writer writer;
3231 writer.SetColorMode(
true );
3232 writer.SetNameMode(
true );
3233 IGESData_GlobalSection header = writer.Model()->GlobalSection();
3234 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3235 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3236 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3237 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3238 writer.Model()->SetGlobalSection( header );
3240 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3249 wxFileInputStream input( inputFile );
3250 wxFileOutputStream output( outputFile );
3254 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3258 if( !output.IsOk() )
3260 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3264 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
3266 if( !zlibStream.IsOk() )
3268 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3272 input.Read( zlibStream );
3274 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3276 m_reporter->Report(
_(
"Compress read or write error" ) );
3290 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3298 wxFileName fn( aFileName );
3300 STEPCAFControl_Writer writer;
3301 writer.SetColorMode(
true );
3302 writer.SetNameMode(
true );
3309 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3311 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3317 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3319 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3323 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3326 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3330 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3333 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3334 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3335 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3336 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3338 bool success =
true;
3341 wxString currCWD = wxGetCwd();
3342 wxString workCWD = fn.GetPath();
3344 if( !workCWD.IsEmpty() )
3345 wxSetWorkingDirectory( workCWD );
3347 wxString tmpfname(
"$tempfile$.step" );
3349 if(
false == writer.Write( tmpfname.c_str() ) )
3352 if( compress && success )
3354 wxString srcTmp( tmpfname );
3355 wxString dstTmp(
"$tempfile$.stpz" );
3358 wxRemoveFile( srcTmp );
3369 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3371 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3379 wxSetWorkingDirectory( currCWD );
3389 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3398 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3403 wxFileName fn( aFileName );
3405 wxFFileOutputStream ffStream( fn.GetFullPath() );
3406 wxStdOutputStream stdStream( ffStream );
3408#if OCC_VERSION_HEX >= 0x070600
3409 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3411 BRepTools::Write( shape, stdStream );
3420 wxFileName fn( aFileName );
3422 wxFFileOutputStream ffStream( fn.GetFullPath() );
3423 wxStdOutputStream file( ffStream );
3425 if( !ffStream.IsOk() )
3427 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3435 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3440 std::map<wxString, std::vector<int>> groups[4];
3441 std::map<wxString, double> groupAreas;
3442 TopExp_Explorer exp;
3445 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3447 TopoDS_Shape subShape = exp.Current();
3450 BRepBndLib::Add( subShape, bbox );
3454 for(
const auto& pair : pairs )
3456 const auto& [point, padTestShape] = pair;
3458 if( bbox.IsOut( point ) )
3461 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3463 if( surface.GetType() != GeomAbs_Plane )
3466 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3469 if( !dist.IsDone() )
3472 if( dist.Value() < Precision::Approximation() )
3475 groups[2][padKey].push_back( faceIndex );
3477 GProp_GProps system;
3478 BRepGProp::SurfaceProperties( subShape, system );
3480 double surfaceArea = system.Mass() / 1e6;
3481 groupAreas[padKey] += surfaceArea;
3490 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3491 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3492 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3493 file <<
" <shape format=\"BREP\"><![CDATA[";
3494#if OCC_VERSION_HEX < 0x070600
3495 BRepTools::Write( shape, file );
3497 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3499 file <<
"]]></shape>" << std::endl;
3500 file <<
" <topology>" << std::endl;
3502 TopTools_IndexedMapOfShape mainMap;
3503 TopExp::MapShapes( shape, mainMap );
3504 std::set<int> topo[4];
3506 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3509 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3510 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3512 for(
int dim = 0; dim < 4; dim++ )
3514 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3516 TopoDS_Shape subShape = exp.Current();
3517 int idx = mainMap.FindIndex( subShape );
3519 if( idx && !topo[dim].count( idx ) )
3520 topo[dim].insert( idx );
3524 for(
int dim = 0; dim <= 3; dim++ )
3526 std::string labels = c_dimLabels[dim];
3527 std::string label = c_dimLabel[dim];
3529 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3532 for(
auto p : topo[dim] )
3534 std::string
name(
"" );
3535 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3536 <<
"name=\"" <<
name <<
"\" "
3537 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3541 file <<
" </" << labels <<
">" << std::endl;
3544 file <<
" </topology>" << std::endl;
3545 file <<
" </geometry>" << std::endl;
3546 file <<
" <groups count=\""
3547 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3550 int groupNumber = 1;
3555 for(
int dim = 0; dim <= 3; dim++ )
3557 std::string label = c_dimLabel[dim];
3559 for(
auto g : groups[dim] )
3562 wxString
name = g.first;
3566 std::ostringstream gs;
3567 gs <<
"G_" << dim <<
"D_" << g.first;
3570 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3576 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3578 for(
auto index : g.second )
3579 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3581 file <<
" </group>" << std::endl;
3583 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3595 file <<
" </groups>" << std::endl;
3596 file <<
" <fields count=\"0\"/>" << std::endl;
3597 file <<
"</XAO>" << std::endl;
3604 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3605 TDF_Label& aLabel,
bool aSubstituteModels,
3606 wxString* aErrorMessage )
3608 std::string fileNameUTF8 = aFileName.utf8_string();
3610 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3611 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3613 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3617 aLabel = mm->second;
3623 Handle( TDocStd_Document ) doc;
3624 m_app->NewDocument(
"MDTV-XCAF", doc );
3627 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3632 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3634 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3642 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3644 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3655 wxFFileInputStream ifile( aFileName );
3656 wxFileName outFile( aFileName );
3658 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3659 outFile.SetExt( wxT(
"step" ) );
3660 wxFileOffset size = ifile.GetLength();
3662 if( size == wxInvalidOffset )
3664 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3671 bool success =
false;
3674 wxFFileOutputStream ofile( outFile.GetFullPath() );
3679 char* buffer =
new char[size];
3681 ifile.Read( buffer, size );
3682 std::string expanded;
3686 expanded = gzip::decompress( buffer, size );
3694 if( expanded.empty() )
3698 wxZipInputStream izipfile( ifile );
3699 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3701 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3703 izipfile.Read( ofile );
3708 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3714 ofile.Write( expanded.data(), expanded.size() );
3722 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3723 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3742 if( aSubstituteModels )
3744 wxFileName wrlName( aFileName );
3746 wxString basePath = wrlName.GetPath();
3747 wxString baseName = wrlName.GetName();
3755 alts.Add( wxT(
"stp" ) );
3756 alts.Add( wxT(
"step" ) );
3757 alts.Add( wxT(
"STP" ) );
3758 alts.Add( wxT(
"STEP" ) );
3759 alts.Add( wxT(
"Stp" ) );
3760 alts.Add( wxT(
"Step" ) );
3761 alts.Add( wxT(
"stpz" ) );
3762 alts.Add( wxT(
"stpZ" ) );
3763 alts.Add( wxT(
"STPZ" ) );
3764 alts.Add( wxT(
"step.gz" ) );
3765 alts.Add( wxT(
"stp.gz" ) );
3768 alts.Add( wxT(
"iges" ) );
3769 alts.Add( wxT(
"IGES" ) );
3770 alts.Add( wxT(
"igs" ) );
3771 alts.Add( wxT(
"IGS" ) );
3775 for(
const auto& altExt : alts )
3779 if( !aAltFilenames.empty() )
3781 for(
const wxString& altPath : aAltFilenames )
3783 wxFileName iterFn( altPath );
3785 if( iterFn.GetExt() == altExt )
3794 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3797 if( altFile.IsOk() && altFile.FileExists() )
3807 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3821 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3823 Handle( XCAFDoc_ShapeTool ) shapeTool =
3824 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3831 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3841 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3851 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3858 if( aLabel.IsNull() )
3860 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3867 TDataStd_Name::Set( aLabel, partname );
3877 TopLoc_Location& aLocation )
3891 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3897 double boardThickness;
3900 double top = std::max( boardZPos, boardZPos + boardThickness );
3901 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3906 double f_pos, f_thickness;
3910 bottom += f_thickness;
3917 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3918 lPos.Multiply( lRot );
3919 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3920 lPos.Multiply( lRot );
3925 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3926 lPos.Multiply( lRot );
3930 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3931 lPos.Multiply( lOff );
3934 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3935 lPos.Multiply( lOrient );
3936 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3937 lPos.Multiply( lOrient );
3938 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3939 lPos.Multiply( lOrient );
3941 aLocation = TopLoc_Location( lPos );
3948 IGESControl_Controller::Init();
3949 IGESCAFControl_Reader reader;
3950 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3952 if( stat != IFSelect_RetDone )
3956 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3960 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3964 reader.SetColorMode(
true );
3965 reader.SetNameMode(
false );
3966 reader.SetLayerMode(
false );
3968 if( !reader.Transfer( doc ) )
3970 if( doc->CanClose() == CDM_CCS_OK )
3977 if( reader.NbShapes() < 1 )
3979 if( doc->CanClose() == CDM_CCS_OK )
3991 STEPCAFControl_Reader reader;
3992 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3994 if( stat != IFSelect_RetDone )
3998 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
4002 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
4006 reader.SetColorMode(
true );
4007 reader.SetNameMode(
true );
4008 reader.SetLayerMode(
false );
4010 if( !reader.Transfer( doc ) )
4012 if( doc->CanClose() == CDM_CCS_OK )
4019 if( reader.NbRootsForTransfer() < 1 )
4021 if( doc->CanClose() == CDM_CCS_OK )
4033#if OCC_VERSION_HEX >= 0x070700
4034 VrmlAPI_CafReader reader;
4035 RWMesh_CoordinateSystemConverter conv;
4036 conv.SetInputLengthUnit( 2.54 );
4037 reader.SetCoordinateSystemConverter( conv );
4038 reader.SetDocument( doc );
4040 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
4053 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool(
source->Main() );
4055 NCollection_Sequence<TDF_Label> frshapes;
4056 s_assy->GetFreeShapes( frshapes );
4058 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
4067 TDF_Label d_targetLabel = d_assy->NewShape();
4069 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
4075 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
4078 return d_targetLabel;
4084 NCollection_Sequence<TDF_Label> freeShapes;
4085 aShapeTool->GetFreeShapes( freeShapes );
4091 for(
int i = 1; i <= freeShapes.Length(); ++i )
4093 TDF_Label label = freeShapes.Value( i );
4095 aShapeTool->GetShape( label, shape );
4100 const double linearDeflection = 0.14;
4101 const double angularDeflection =
DEG2RAD( 30.0 );
4102 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
4124 wxFileName fn( aFileName );
4126 const char* tmpGltfname =
"$tempfile$.glb";
4127 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
4129 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
4130 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4131 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
4132 RWMesh_CoordinateSystem_Zup );
4133#if OCC_VERSION_HEX >= 0x070700
4134 cafWriter.SetParallel(
true );
4136 TColStd_IndexedDataMapOfStringString metadata;
4138 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4139 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4140 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4141 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4142 metadata.Add( TCollection_AsciiString(
"generator" ),
4143 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4144 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4147 bool success =
true;
4150 wxString currCWD = wxGetCwd();
4151 wxString workCWD = fn.GetPath();
4153 if( !workCWD.IsEmpty() )
4154 wxSetWorkingDirectory( workCWD );
4156 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4165 m_reporter->Report(
_(
"Could not post-process GLB line primitives; the exported "
4166 "model may not import in strict glTF viewers." ),
4173 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4175 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4183 wxSetWorkingDirectory( currCWD );
4191#if OCC_VERSION_HEX < 0x070700
4198 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4208 wxFileName fn( aFileName );
4210 const char* tmpFname =
"$tempfile$.ply";
4211 RWPly_CafWriter cafWriter( tmpFname );
4213 cafWriter.SetFaceId(
true );
4214 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4215 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4217 TColStd_IndexedDataMapOfStringString metadata;
4219 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4220 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4221 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4222 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4223 metadata.Add( TCollection_AsciiString(
"generator" ),
4224 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4226 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4229 bool success =
true;
4232 wxString currCWD = wxGetCwd();
4233 wxString workCWD = fn.GetPath();
4235 if( !workCWD.IsEmpty() )
4236 wxSetWorkingDirectory( workCWD );
4238 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4245 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4247 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4255 wxSetWorkingDirectory( currCWD );
4266 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4276 wxFileName fn( aFileName );
4278 const char* tmpFname =
"$tempfile$.stl";
4281 wxString currCWD = wxGetCwd();
4282 wxString workCWD = fn.GetPath();
4284 if( !workCWD.IsEmpty() )
4285 wxSetWorkingDirectory( workCWD );
4287 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4294 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4296 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4304 wxSetWorkingDirectory( currCWD );
4316 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4325 wxFileName fn( aFileName );
4327 const char* tmpFname =
"$tempfile$.u3d";
4330 wxString currCWD = wxGetCwd();
4331 wxString workCWD = fn.GetPath();
4333 if( !workCWD.IsEmpty() )
4334 wxSetWorkingDirectory( workCWD );
4337 bool success = writer.
Perform( m_doc );
4343 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4345 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4352 wxSetWorkingDirectory( currCWD );
4363 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4372 wxFileName fn( aFileName );
4374 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4375 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4377 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4378 bool success = writer.
Perform( m_doc );
4381 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4383 plotter->SetColorMode(
true );
4384 plotter->Set3DExport(
true );
4387 plotter->SetRenderSettings( &renderSettings );
4389 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4391 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4397 plotter->StartPlot(
"1",
"3D Model" );
4398 double fov_degrees = 16.5f;
4403 std::vector<PDF_3D_VIEW> views;
4408 std::vector<float> c2wMatrix =
4412 .m_name =
"Default",
4413 .m_cameraMatrix = c2wMatrix,
4414 .m_cameraCenter = (float)
distance,
4415 .m_fov = (
float) fov_degrees,
4424 .m_cameraMatrix = c2wMatrix,
4425 .m_cameraCenter = (float)
distance,
4426 .m_fov = (
float) fov_degrees,
4435 .m_cameraMatrix = c2wMatrix,
4436 .m_cameraCenter = (float)
distance,
4437 .m_fov = (
float) fov_degrees,
4446 .m_cameraMatrix = c2wMatrix,
4447 .m_cameraCenter = (float)
distance,
4448 .m_fov = (
float) fov_degrees,
4451 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4460 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4462 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4463 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4469 wxRemoveFile( u3dTmpfn.GetFullPath() );
bool GetExtrusionPinOutlines(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly, SHAPE_POLY_SET &aPegPoly)
Get the hole outline polygons for extruded pin rendering.
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetMajorMinorPatchVersion()
Get the major, minor and patch version in a string major.minor.patch This is extracted by CMake from ...
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
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
VECTOR2I GetDrillSize() const
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
bool AddExtrudedPins(const FOOTPRINT *aFootprint, const EXTRUDED_3D_BODY *aBody, bool aBottom, double aStandoff, const VECTOR2D &aOrigin)
Add pin extrusions for pad holes.
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
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