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 )
1700 double f_pos, f_thickness;
1701 double b_pos, b_thickness;
1704 double top = std::min( f_pos, f_pos + f_thickness );
1705 double bottom = std::max( b_pos, b_pos + b_thickness );
1707 aThickness = (
top - bottom );
1710 wxASSERT( aZPos == 0.0 );
1716 const wxString& aRefDes )
1718 double f_pos, f_thickness;
1719 double b_pos, b_thickness;
1723 double boardSurfaceZ;
1726 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1728 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1730 double bodyThickness = aHeight - aStandoff;
1734 zBot = boardSurfaceZ + aStandoff;
1736 zBot = boardSurfaceZ - aHeight;
1746 if( aStandoff <= 0.0 )
1762 double f_pos, f_thickness;
1763 double b_pos, b_thickness;
1767 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1768 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1770 static const double c_protrusion = 1.0;
1772 double pinZBot, pinHeight;
1776 pinZBot = boardBotZ - c_protrusion;
1777 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1781 double pinZTop = boardTopZ + c_protrusion;
1782 pinZBot = boardBotZ - aStandoff;
1783 pinHeight = pinZTop - pinZBot;
1794 const VECTOR2D& aOrigin,
const wxString& aNetname )
1796 bool success =
true;
1804 double z_pos, thickness;
1807 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1815 else if( aLayer ==
F_Mask )
1822 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1835 const std::vector<wxString>& aAltFilenames,
1836 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1838 VECTOR3D aScale,
bool aSubstituteModels )
1840 if( aFileName.empty() )
1842 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1851 wxString errorMessage;
1853 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1856 if( errorMessage.IsEmpty() )
1857 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1864 TopLoc_Location toploc;
1866 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1869 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1875 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1877 if( llabel.IsNull() )
1880 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1888 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1889 TDataStd_Name::Set( llabel, refdes );
1900 m_assy->UpdateAssemblies();
1972 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1973 double aZposition,
const VECTOR2D& aOrigin )
1980 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1981 double h_width = aWidth/2.0;
1983 coords[0] =
VECTOR2D{ 0.0, h_width };
1986 coords[1] =
VECTOR2D{ len, h_width };
1989 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1992 coords[3] =
VECTOR2D{ len, -h_width };
1995 coords[4] =
VECTOR2D{ 0, -h_width };
1998 coords[5] =
VECTOR2D{ -h_width, 0.0 };
2001 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
2003 for(
int ii = 0; ii < 6; ii++ )
2006 coords[ii] += aStartPoint;
2011 gp_Pnt coords3D[ 6 ];
2013 for(
int ii = 0; ii < 6; ii++ )
2015 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
2016 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
2020 BRepBuilderAPI_MakeWire wire;
2021 bool success =
true;
2033 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2038 edge = BRepBuilderAPI_MakeEdge(
circle );
2043 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2046 Handle( Geom_TrimmedCurve ) arcOfCircle =
2047 GC_MakeArcOfCircle( coords3D[1],
2051 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2054 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2057 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2058 GC_MakeArcOfCircle( coords3D[4],
2062 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2066 catch(
const Standard_Failure& e )
2068 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2069 e.GetMessageString() ),
2074 BRepBuilderAPI_MakeFace face;
2078 gp_Pln plane( coords3D[0], gp::DZ() );
2079 face = BRepBuilderAPI_MakeFace( plane, wire );
2081 catch(
const Standard_Failure& e )
2083 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2084 e.GetMessageString() ),
2089 if( aThickness != 0.0 )
2091 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2093 if( aShape.IsNull() )
2095 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2112 double aZposition,
const VECTOR2D& aOrigin )
2114 std::vector<TopoDS_Shape> testShapes;
2117 aHeight, aZposition, aOrigin );
2119 if( testShapes.size() > 0 )
2120 aShape = testShapes.front();
2143 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2147 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2149 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2150 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2160 gp_Pnt start = toPoint( aPt0 );
2161 gp_Pnt
end = toPoint( aPt1 );
2163 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2165 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2167 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2175 aMkWire.Add( mkEdge.Edge() );
2177 if( aMkWire.Error() != BRepLib_WireDone )
2179 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2193 Handle( Geom_Curve ) curve;
2195 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2197 gp_Ax2 axis = gp::XOY();
2198 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2200 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2204 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2205 toPoint( aArc.GetP1() ) ).Value();
2208 if( curve.IsNull() )
2211 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2213 if( !aMkWire.IsDone() )
2215 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2216 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2218 aArc.GetP0().x, aArc.GetP0().y,
2219 aArc.GetArcMid().x, aArc.GetArcMid().y,
2220 aArc.GetP1().x, aArc.GetP1().y ),
2230 bool isFirstShape =
true;
2243 if( nextShape != -1 )
2249 lastPt = aChain.
CPoint( i );
2259 firstPt = currentArc.
GetP0();
2264 lastPt = currentArc.
GetP0();
2266 if( addArc( lastPt, currentArc ) )
2267 lastPt = currentArc.
GetP1();
2286 isFirstShape =
false;
2289 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2291 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2293 firstPt.
x, firstPt.
y ),
2299 catch(
const Standard_Failure& e )
2301 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2302 e.GetMessageString() ),
2312 bool aConvertToArcs,
double aThickness,
double aZposition,
2320 if( aConvertToArcs )
2324 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2328 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2332 fallbackPoly = workingPoly;
2333 workingPoly = approximated;
2352 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2354 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2355 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2359 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2360 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2362 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2366 auto tryMakeWire = [
this, &aZposition,
2367 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2370 BRepLib_MakeWire mkWire;
2374 if( mkWire.IsDone() )
2376 wire = mkWire.Wire();
2381 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2382 "z: %g; bounding box: %s" ),
2383 static_cast<int>( aContour.PointCount() ),
2384 static_cast<int>( mkWire.Error() ),
2389 if( !wire.IsNull() )
2391 BRepAlgoAPI_Check check( wire,
false,
true );
2393 if( !check.IsValid() )
2395 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2396 "z: %g; bounding box: %s" ),
2408 BRepBuilderAPI_MakeFace mkFace;
2410 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2416 bool allow_retry = aConvertToArcs ? true :
false;
2418 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2420 if( aConvertToArcs && wire.IsNull() )
2422 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2426 allow_retry =
false;
2427 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2432 if( !wire.IsNull() )
2434 if( basePlane.Axis().Direction().Z() < 0 )
2437 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2441 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2442 "z: %g; bounding box: %s" ),
2451 if( !wire.IsNull() )
2453 if( basePlane.Axis().Direction().Z() > 0 )
2460 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2461 "z: %g; bounding box: %s" ),
2468 catch(
const Standard_Failure& e )
2470 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2471 static_cast<int>( contId ),
2472 e.GetMessageString() ),
2478 if( mkFace.IsDone() )
2480 TopoDS_Shape faceShape = mkFace.Shape();
2482 if( aThickness != 0.0 )
2484 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2485 aShapes.push_back( prism );
2487 if( prism.IsNull() )
2495 aShapes.push_back( faceShape );
2511 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2512 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2513 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2514 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2515 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2516 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2517 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2518 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2528 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2530 aColorOut =
COLOR4D( aColorStr );
2535 const std::vector<FAB_LAYER_COLOR>& colors =
2542 if( fabColor.GetName() == aColorStr )
2544 aColorOut = fabColor.GetColor( aType );
2566 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2571 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2576 double boardThickness;
2596 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2600 polyset.
Append( contour );
2607 m_reporter->Report(
_(
"OCC error creating main outline." ),
2616 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2628 BRepBndLib::Add( brdShape, brdBndBox );
2631 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2636 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2637 std::vector<Bnd_Box>& holeBoxes )
2641 Bnd_Box brdWithHolesBndBox = brdBndBox;
2643 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2644 holeBoxes.resize( input.size() );
2646 for(
size_t i = 0; i < input.size(); i++ )
2649 BRepBndLib::Add( input[i], bbox );
2650 brdWithHolesBndBox.Add( bbox );
2651 ( *holeBoxSet )[i] = bbox;
2652 holeBoxes[i] = bbox;
2655 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2658 auto subtractShapesMap =
2659 [
this, &
tp](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2660 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2661 const std::vector<Bnd_Box>& aHoleBoxes )
2663 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2666 for(
auto& [netname, vec] : aShapesMap )
2674 auto subtractLoopFn = [&](
const int shapeId )
2676 TopoDS_Shape& shape = vec[shapeId];
2679 BRepBndLib::Add( shape, shapeBbox );
2681 NCollection_List<TopoDS_Shape> holelist;
2684 std::unique_lock lock( mutex );
2686 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2688 for(
const int&
index : indices )
2689 holelist.Append( aHolesList[
index] );
2695 if( holelist.IsEmpty() )
2697 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2699 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2700 holelist.Append( aHolesList[i] );
2705 if( holelist.IsEmpty() )
2708 NCollection_List<TopoDS_Shape> cutArgs;
2709 cutArgs.Append( shape );
2711 BRepAlgoAPI_Cut
cut;
2715 cut.SetNonDestructive(
true );
2716 cut.SetRunParallel(
false );
2717 cut.SetToFillHistory(
false );
2719 cut.SetArguments( cutArgs );
2720 cut.SetTools( holelist );
2723 if(
cut.HasErrors() ||
cut.HasWarnings() )
2725 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2734 std::unique_lock lock( mutex );
2738 if(
cut.HasErrors() )
2740 wxString msg =
_(
"Errors:\n" );
2741 wxStringOutputStream os_stream( &msg );
2742 wxStdOutputStream out( os_stream );
2744 cut.DumpErrors( out );
2748 if(
cut.HasWarnings() )
2750 wxString msg =
_(
"Warnings:\n" );
2751 wxStringOutputStream os_stream( &msg );
2752 wxStdOutputStream out( os_stream );
2754 cut.DumpWarnings( out );
2759 shape =
cut.Shape();
2765 BS::multi_future<void> cutFutures;
2769 cutFutures =
tp.submit_loop( 0, vec.size(), subtractLoopFn );
2782 auto subtractShapes =
2783 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2784 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2785 const std::vector<Bnd_Box>& aHoleBoxes )
2787 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2789 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2790 aShapesList = aShapesMap[wxEmptyString];
2796 Bnd_BoundSortBox bsbHoles;
2797 std::vector<Bnd_Box> holeBoxes;
2805 Bnd_BoundSortBox bsbHoles;
2806 std::vector<Bnd_Box> holeBoxes;
2815 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2817 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2818 const std::vector<TopoDS_Shape>& aShapes )
2820 for(
const TopoDS_Shape& shape : aShapes )
2821 shapesToFuseMap[aNetname].Append( shape );
2825 addShapes( netname, shapes );
2828 addShapes( netname, shapes );
2831 addShapes( netname, shapes );
2839 std::vector<std::pair<wxString, const NCollection_List<TopoDS_Shape>*>> fuseWork;
2840 fuseWork.reserve( shapesToFuseMap.size() );
2842 for(
const auto& [netname, toFuse] : shapesToFuseMap )
2843 fuseWork.emplace_back( netname, &toFuse );
2846 BS::multi_future<void> mf;
2847 mf.reserve( fuseWork.size() );
2853 for(
const auto& work : fuseWork )
2855 const wxString netname = work.first;
2856 const NCollection_List<TopoDS_Shape>* toFuse = work.second;
2858 mf.push_back(
tp.submit_task(
2859 [
this, &mutex, netname, toFuse]()
2861 TopoDS_Shape fusedShape = fuseShapesOrCompound( *toFuse, m_reporter );
2863 if( !fusedShape.IsNull() )
2865 std::unique_lock lock( mutex );
2867 m_board_copper_fused[netname].emplace_back( fusedShape );
2869 m_board_copper[netname].clear();
2870 m_board_copper_pads[netname].clear();
2871 m_board_copper_vias[netname].clear();
2898 auto pushToAssemblyMap =
2899 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2900 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2901 bool aCompoundAll,
const wxString& aNiceName )
2903 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2907 std::vector<TopoDS_Shape> allShapes;
2909 for(
const auto& [netname, shapesList] : aShapesMap )
2910 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2912 if( !allShapes.empty() )
2913 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2917 shapesMap = aShapesMap;
2920 for(
const auto& [netname, shapesList] : shapesMap )
2922 std::vector<TopoDS_Shape> newList;
2927 newList = shapesList;
2931 for( TopoDS_Shape& shape : newList )
2933 Handle( TDataStd_TreeNode ) node;
2936 TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape,
false );
2938 m_pcb_labels.push_back( lbl );
2940 if( m_pcb_labels.back().IsNull() )
2943 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2944 TDF_Label shpLbl = node->Father()->Label();
2946 if( !shpLbl.IsNull() )
2948 if( visMatTool && !aVisMatLabel.IsNull() )
2949 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2953 shapeName << m_pcbName;
2955 shapeName << aShapeName;
2957 if( !netname.empty() )
2960 shapeName << netname;
2963 if( newList.size() > 1 )
2969 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2970 TDataStd_Name::Set( shpLbl, partname );
2978 auto pushToAssembly =
2979 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2980 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2982 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2984 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2988 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2989 double aMetallic,
double aRoughness ) -> TDF_Label
2991 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2992 XCAFDoc_VisMaterialPBR pbr;
2993 pbr.BaseColor = aBaseColor;
2994 pbr.Metallic = aMetallic;
2995 pbr.Roughness = aRoughness;
2996 vismat->SetPbrMaterial( pbr );
2997 return visMatTool->AddMaterial( vismat, aName );
3001 Quantity_ColorRGBA copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], 1.0 );
3002 Quantity_ColorRGBA pad_color( m_padColor[0], m_padColor[1], m_padColor[2], 1.0 );
3004 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
3005 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
3006 Quantity_ColorRGBA back_silk_color = front_silk_color;
3007 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
3008 Quantity_ColorRGBA back_mask_color = front_mask_color;
3018 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
3022 if( item->GetBrdLayerId() ==
F_Mask )
3023 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3025 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3028 if( item->GetBrdLayerId() ==
F_SilkS )
3029 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3030 else if( item->GetBrdLayerId() ==
B_SilkS )
3031 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3034 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3038 if( !m_enabledLayers.Contains(
F_Mask ) && !m_enabledLayers.Contains(
B_Mask ) )
3040 board_color = front_mask_color;
3041 board_color.SetAlpha( 1.0 );
3044 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
3045 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
3046 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
3047 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
3048 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
3049 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
3050 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
3052 pushToAssemblyMap( m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
3053 pushToAssemblyMap( m_board_copper_pads, pad_mat,
"pad",
true,
true,
"Pads" );
3054 pushToAssemblyMap( m_board_copper_vias, copper_mat,
"via",
true,
true,
"Via" );
3055 pushToAssemblyMap( m_board_copper_fused, copper_mat,
"copper",
true,
true,
"Copper" );
3056 pushToAssembly( m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
3057 pushToAssembly( m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
3058 pushToAssembly( m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
3059 pushToAssembly( m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
3061 if( aPushBoardBody )
3062 pushToAssembly( m_board_outlines, board_mat,
"PCB",
false,
"Body" );
3064 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
3065 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
3067 for(
auto& entry : m_extruded_bodies )
3069 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
3072 TopoDS_Compound asmCompound;
3073 BRep_Builder asmBuilder;
3074 asmBuilder.MakeCompound( asmCompound );
3075 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
3076 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
3078 if( !entry.bodyShapes.empty() )
3080 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
3081 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
3082 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
3083 double a = ( entry.colorKey & 0xFF ) / 255.0;
3085 double metallic, roughness;
3087 switch( entry.material )
3108 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3109 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3111 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3112 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3114 Handle( TDataStd_TreeNode ) bodyNode;
3115 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3116 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3118 if( !bodyShpLbl.IsNull() )
3120 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3121 TDataStd_Name::Set( bodyShpLbl,
3122 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3128 for( TopoDS_Shape& pinShape : entry.pinShapes )
3130 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3132 Handle( TDataStd_TreeNode ) pinNode;
3133 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3134 TDF_Label pinShpLbl = pinNode->Father()->Label();
3136 if( !pinShpLbl.IsNull() )
3138 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3139 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3140 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3144 TopLoc_Location loc;
3145 TDF_Label fpCompLbl = m_assy->AddComponent( m_assy_label, fpLabel, loc );
3146 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3148 m_pcb_labels.push_back( fpCompLbl );
3151#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3152 m_assy->UpdateAssemblies();
3161bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3165 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3173 wxFileName fn( aFileName );
3174 IGESControl_Controller::Init();
3175 IGESCAFControl_Writer writer;
3176 writer.SetColorMode(
true );
3177 writer.SetNameMode(
true );
3178 IGESData_GlobalSection header = writer.Model()->GlobalSection();
3179 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3180 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3181 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3182 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3183 writer.Model()->SetGlobalSection( header );
3185 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3194 wxFileInputStream input( inputFile );
3195 wxFileOutputStream output( outputFile );
3199 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3203 if( !output.IsOk() )
3205 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3209 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
3211 if( !zlibStream.IsOk() )
3213 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3217 input.Read( zlibStream );
3219 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3221 m_reporter->Report(
_(
"Compress read or write error" ) );
3235 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3243 wxFileName fn( aFileName );
3245 STEPCAFControl_Writer writer;
3246 writer.SetColorMode(
true );
3247 writer.SetNameMode(
true );
3254 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3256 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3262 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3264 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3268 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3271 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3275 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3278 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3279 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3280 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3281 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3283 bool success =
true;
3286 wxString currCWD = wxGetCwd();
3287 wxString workCWD = fn.GetPath();
3289 if( !workCWD.IsEmpty() )
3290 wxSetWorkingDirectory( workCWD );
3292 wxString tmpfname(
"$tempfile$.step" );
3294 if(
false == writer.Write( tmpfname.c_str() ) )
3297 if( compress && success )
3299 wxString srcTmp( tmpfname );
3300 wxString dstTmp(
"$tempfile$.stpz" );
3303 wxRemoveFile( srcTmp );
3314 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3316 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3324 wxSetWorkingDirectory( currCWD );
3334 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3343 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3348 wxFileName fn( aFileName );
3350 wxFFileOutputStream ffStream( fn.GetFullPath() );
3351 wxStdOutputStream stdStream( ffStream );
3353#if OCC_VERSION_HEX >= 0x070600
3354 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3356 BRepTools::Write( shape, stdStream );
3365 wxFileName fn( aFileName );
3367 wxFFileOutputStream ffStream( fn.GetFullPath() );
3368 wxStdOutputStream file( ffStream );
3370 if( !ffStream.IsOk() )
3372 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3380 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3385 std::map<wxString, std::vector<int>> groups[4];
3386 std::map<wxString, double> groupAreas;
3387 TopExp_Explorer exp;
3390 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3392 TopoDS_Shape subShape = exp.Current();
3395 BRepBndLib::Add( subShape, bbox );
3399 for(
const auto& pair : pairs )
3401 const auto& [point, padTestShape] = pair;
3403 if( bbox.IsOut( point ) )
3406 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3408 if( surface.GetType() != GeomAbs_Plane )
3411 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3414 if( !dist.IsDone() )
3417 if( dist.Value() < Precision::Approximation() )
3420 groups[2][padKey].push_back( faceIndex );
3422 GProp_GProps system;
3423 BRepGProp::SurfaceProperties( subShape, system );
3425 double surfaceArea = system.Mass() / 1e6;
3426 groupAreas[padKey] += surfaceArea;
3435 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3436 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3437 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3438 file <<
" <shape format=\"BREP\"><![CDATA[";
3439#if OCC_VERSION_HEX < 0x070600
3440 BRepTools::Write( shape, file );
3442 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3444 file <<
"]]></shape>" << std::endl;
3445 file <<
" <topology>" << std::endl;
3447 TopTools_IndexedMapOfShape mainMap;
3448 TopExp::MapShapes( shape, mainMap );
3449 std::set<int> topo[4];
3451 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3454 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3455 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3457 for(
int dim = 0; dim < 4; dim++ )
3459 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3461 TopoDS_Shape subShape = exp.Current();
3462 int idx = mainMap.FindIndex( subShape );
3464 if( idx && !topo[dim].count( idx ) )
3465 topo[dim].insert( idx );
3469 for(
int dim = 0; dim <= 3; dim++ )
3471 std::string labels = c_dimLabels[dim];
3472 std::string label = c_dimLabel[dim];
3474 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3477 for(
auto p : topo[dim] )
3479 std::string
name(
"" );
3480 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3481 <<
"name=\"" <<
name <<
"\" "
3482 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3486 file <<
" </" << labels <<
">" << std::endl;
3489 file <<
" </topology>" << std::endl;
3490 file <<
" </geometry>" << std::endl;
3491 file <<
" <groups count=\""
3492 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3495 int groupNumber = 1;
3500 for(
int dim = 0; dim <= 3; dim++ )
3502 std::string label = c_dimLabel[dim];
3504 for(
auto g : groups[dim] )
3507 wxString
name = g.first;
3511 std::ostringstream gs;
3512 gs <<
"G_" << dim <<
"D_" << g.first;
3515 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3521 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3523 for(
auto index : g.second )
3524 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3526 file <<
" </group>" << std::endl;
3528 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3540 file <<
" </groups>" << std::endl;
3541 file <<
" <fields count=\"0\"/>" << std::endl;
3542 file <<
"</XAO>" << std::endl;
3549 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3550 TDF_Label& aLabel,
bool aSubstituteModels,
3551 wxString* aErrorMessage )
3553 std::string fileNameUTF8 = aFileName.utf8_string();
3555 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3556 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3558 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3562 aLabel = mm->second;
3568 Handle( TDocStd_Document ) doc;
3569 m_app->NewDocument(
"MDTV-XCAF", doc );
3572 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3577 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3579 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3587 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3589 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3600 wxFFileInputStream ifile( aFileName );
3601 wxFileName outFile( aFileName );
3603 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3604 outFile.SetExt( wxT(
"step" ) );
3605 wxFileOffset size = ifile.GetLength();
3607 if( size == wxInvalidOffset )
3609 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3616 bool success =
false;
3619 wxFFileOutputStream ofile( outFile.GetFullPath() );
3624 char* buffer =
new char[size];
3626 ifile.Read( buffer, size );
3627 std::string expanded;
3631 expanded = gzip::decompress( buffer, size );
3639 if( expanded.empty() )
3643 wxZipInputStream izipfile( ifile );
3644 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3646 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3648 izipfile.Read( ofile );
3653 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3659 ofile.Write( expanded.data(), expanded.size() );
3667 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3668 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3687 if( aSubstituteModels )
3689 wxFileName wrlName( aFileName );
3691 wxString basePath = wrlName.GetPath();
3692 wxString baseName = wrlName.GetName();
3700 alts.Add( wxT(
"stp" ) );
3701 alts.Add( wxT(
"step" ) );
3702 alts.Add( wxT(
"STP" ) );
3703 alts.Add( wxT(
"STEP" ) );
3704 alts.Add( wxT(
"Stp" ) );
3705 alts.Add( wxT(
"Step" ) );
3706 alts.Add( wxT(
"stpz" ) );
3707 alts.Add( wxT(
"stpZ" ) );
3708 alts.Add( wxT(
"STPZ" ) );
3709 alts.Add( wxT(
"step.gz" ) );
3710 alts.Add( wxT(
"stp.gz" ) );
3713 alts.Add( wxT(
"iges" ) );
3714 alts.Add( wxT(
"IGES" ) );
3715 alts.Add( wxT(
"igs" ) );
3716 alts.Add( wxT(
"IGS" ) );
3720 for(
const auto& altExt : alts )
3724 if( !aAltFilenames.empty() )
3726 for(
const wxString& altPath : aAltFilenames )
3728 wxFileName iterFn( altPath );
3730 if( iterFn.GetExt() == altExt )
3739 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3742 if( altFile.IsOk() && altFile.FileExists() )
3752 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3766 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3768 Handle( XCAFDoc_ShapeTool ) shapeTool =
3769 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3776 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3786 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3796 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3803 if( aLabel.IsNull() )
3805 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3812 TDataStd_Name::Set( aLabel, partname );
3822 TopLoc_Location& aLocation )
3836 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3842 double boardThickness;
3845 double top = std::max( boardZPos, boardZPos + boardThickness );
3846 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3851 double f_pos, f_thickness;
3855 bottom += f_thickness;
3862 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3863 lPos.Multiply( lRot );
3864 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3865 lPos.Multiply( lRot );
3870 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3871 lPos.Multiply( lRot );
3875 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3876 lPos.Multiply( lOff );
3879 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3880 lPos.Multiply( lOrient );
3881 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3882 lPos.Multiply( lOrient );
3883 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3884 lPos.Multiply( lOrient );
3886 aLocation = TopLoc_Location( lPos );
3893 IGESControl_Controller::Init();
3894 IGESCAFControl_Reader reader;
3895 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3897 if( stat != IFSelect_RetDone )
3901 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3905 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3909 reader.SetColorMode(
true );
3910 reader.SetNameMode(
false );
3911 reader.SetLayerMode(
false );
3913 if( !reader.Transfer( doc ) )
3915 if( doc->CanClose() == CDM_CCS_OK )
3922 if( reader.NbShapes() < 1 )
3924 if( doc->CanClose() == CDM_CCS_OK )
3936 STEPCAFControl_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(
true );
3953 reader.SetLayerMode(
false );
3955 if( !reader.Transfer( doc ) )
3957 if( doc->CanClose() == CDM_CCS_OK )
3964 if( reader.NbRootsForTransfer() < 1 )
3966 if( doc->CanClose() == CDM_CCS_OK )
3978#if OCC_VERSION_HEX >= 0x070700
3979 VrmlAPI_CafReader reader;
3980 RWMesh_CoordinateSystemConverter conv;
3981 conv.SetInputLengthUnit( 2.54 );
3982 reader.SetCoordinateSystemConverter( conv );
3983 reader.SetDocument( doc );
3985 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3998 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
4000 NCollection_Sequence<TDF_Label> frshapes;
4001 s_assy->GetFreeShapes( frshapes );
4003 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
4012 TDF_Label d_targetLabel = d_assy->NewShape();
4014 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
4020 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
4023 return d_targetLabel;
4029 NCollection_Sequence<TDF_Label> freeShapes;
4030 aShapeTool->GetFreeShapes( freeShapes );
4036 for(
int i = 1; i <= freeShapes.Length(); ++i )
4038 TDF_Label label = freeShapes.Value( i );
4040 aShapeTool->GetShape( label, shape );
4045 const double linearDeflection = 0.14;
4046 const double angularDeflection =
DEG2RAD( 30.0 );
4047 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
4069 wxFileName fn( aFileName );
4071 const char* tmpGltfname =
"$tempfile$.glb";
4072 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
4074 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
4075 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4076 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
4077 RWMesh_CoordinateSystem_Zup );
4078#if OCC_VERSION_HEX >= 0x070700
4079 cafWriter.SetParallel(
true );
4081 TColStd_IndexedDataMapOfStringString metadata;
4083 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4084 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4085 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4086 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4087 metadata.Add( TCollection_AsciiString(
"generator" ),
4088 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4089 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4092 bool success =
true;
4095 wxString currCWD = wxGetCwd();
4096 wxString workCWD = fn.GetPath();
4098 if( !workCWD.IsEmpty() )
4099 wxSetWorkingDirectory( workCWD );
4101 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4110 m_reporter->Report(
_(
"Could not post-process GLB line primitives; the exported "
4111 "model may not import in strict glTF viewers." ),
4118 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4120 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4128 wxSetWorkingDirectory( currCWD );
4136#if OCC_VERSION_HEX < 0x070700
4143 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4153 wxFileName fn( aFileName );
4155 const char* tmpFname =
"$tempfile$.ply";
4156 RWPly_CafWriter cafWriter( tmpFname );
4158 cafWriter.SetFaceId(
true );
4159 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4160 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4162 TColStd_IndexedDataMapOfStringString metadata;
4164 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4165 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4166 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4167 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4168 metadata.Add( TCollection_AsciiString(
"generator" ),
4169 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4171 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4174 bool success =
true;
4177 wxString currCWD = wxGetCwd();
4178 wxString workCWD = fn.GetPath();
4180 if( !workCWD.IsEmpty() )
4181 wxSetWorkingDirectory( workCWD );
4183 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4190 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4192 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4200 wxSetWorkingDirectory( currCWD );
4211 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4221 wxFileName fn( aFileName );
4223 const char* tmpFname =
"$tempfile$.stl";
4226 wxString currCWD = wxGetCwd();
4227 wxString workCWD = fn.GetPath();
4229 if( !workCWD.IsEmpty() )
4230 wxSetWorkingDirectory( workCWD );
4232 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4239 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4241 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4249 wxSetWorkingDirectory( currCWD );
4261 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4270 wxFileName fn( aFileName );
4272 const char* tmpFname =
"$tempfile$.u3d";
4275 wxString currCWD = wxGetCwd();
4276 wxString workCWD = fn.GetPath();
4278 if( !workCWD.IsEmpty() )
4279 wxSetWorkingDirectory( workCWD );
4282 bool success = writer.
Perform( m_doc );
4288 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4290 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4297 wxSetWorkingDirectory( currCWD );
4308 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4317 wxFileName fn( aFileName );
4319 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4320 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4322 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4323 bool success = writer.
Perform( m_doc );
4326 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4328 plotter->SetColorMode(
true );
4329 plotter->Set3DExport(
true );
4330 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4332 plotter->SetRenderSettings( &renderSettings );
4334 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4336 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4342 plotter->StartPlot(
"1",
"3D Model" );
4343 double fov_degrees = 16.5f;
4348 std::vector<PDF_3D_VIEW> views;
4353 std::vector<float> c2wMatrix =
4357 .m_name =
"Default",
4358 .m_cameraMatrix = c2wMatrix,
4359 .m_cameraCenter = (float)
distance,
4360 .m_fov = (
float) fov_degrees,
4369 .m_cameraMatrix = c2wMatrix,
4370 .m_cameraCenter = (float)
distance,
4371 .m_fov = (
float) fov_degrees,
4380 .m_cameraMatrix = c2wMatrix,
4381 .m_cameraCenter = (float)
distance,
4382 .m_fov = (
float) fov_degrees,
4391 .m_cameraMatrix = c2wMatrix,
4392 .m_cameraCenter = (float)
distance,
4393 .m_fov = (
float) fov_degrees,
4396 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4405 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4407 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4408 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4414 wxRemoveFile( u3dTmpfn.GetFullPath() );
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
bool GetExtrusionPinOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly)
Get the pin outline polygons for extruded THT pin rendering.
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetNetname() const
const wxString & GetShortNetname() const
FOOTPRINT * GetParentFootprint() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
PCB specific render settings.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
PAD_PROP GetProperty() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
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.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
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)
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.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static bool rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
static TopoDS_Shape fuseShapesOrCompound(const NCollection_List< TopoDS_Shape > &aInputShapes, REPORTER *aReporter)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
static bool prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static constexpr double USER_ANGLE_PREC
static constexpr double USER_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
std::pair< std::string, TDF_Label > MODEL_DATUM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
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