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>
144#if OCC_VERSION_HEX >= 0x070700
145#include <VrmlAPI_CafReader.hxx>
146#include <RWPly_CafWriter.hxx>
174 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
176 if( !lfile.FileExists() )
179 wxString ext = lfile.GetExt().Lower();
181 if( ext == wxT(
"wrl" ) )
184 if( ext == wxT(
"wrz" ) )
187 if( ext == wxT(
"idf" ) )
190 if( ext == wxT(
"emn" ) )
193 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
207 const int max_line_count = 3;
209 for(
int ii = 0; ii < max_line_count; ii++ )
211 memset( iline, 0, 82 );
212 ifile.getline( iline, 82 );
218 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
224 std::string fstr = iline;
228 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
237 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
244 if( strncmp( iline,
"/*", 2 ) != 0 )
262 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
263 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
264 double det = -b.
x * d.
y + d.
x * b.
y;
268 center.x = ( -bc * d.
y - cd * b.
y ) * det;
269 center.y = ( b.
x * cd + d.
x * bc ) * det;
276#define APPROX_DBG( stmt )
284 static const double c_radiusDeviation = 1000.0;
285 static const double c_arcCenterDeviation = 1000.0;
286 static const double c_relLengthDeviation = 0.8;
287 static const int c_last_none = -1000;
289 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
290 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
309 int last = c_last_none;
315 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
317 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
322 bool defective =
false;
328 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
336 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
337 defective |=
std::abs( a_diff ) < 0.1;
340 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
341 defective |=
std::abs( a_diff ) >= maxAngleDiff;
352 for(
int j = i; j <= jEndIdx; j++ )
357 double rad_test = ( p_test -
center ).EuclideanNorm();
358 double d_tl = ( p_test - p_prev ).EuclideanNorm();
362 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
365 if( rad_dev > c_radiusDeviation )
368 <<
" Radius deviation too large: " << int64_t( rad_dev )
369 <<
" > " << c_radiusDeviation << std::endl );
374 double maxAngleDiff =
375 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
377 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
378 if(
std::abs( a_diff_test ) >= maxAngleDiff )
380 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
385 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
387 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
388 <<
"; " << d01 << std::endl );
398 if( last != c_last_none )
410 APPROX_DBG( std::cout <<
" Arc central angle too small: "
412 << c_minArcCentralAngle.
AsDegrees() << std::endl );
418 for(
int k = first + 1; last != c_last_none && k < last; k++ )
424 if( dist > c_radiusDeviation )
426 APPROX_DBG( std::cout <<
" Point " << k <<
" too far from arc: " << dist
427 <<
" > " << c_radiusDeviation << std::endl );
432 if( last != c_last_none )
437 int toRemove = last - ( aSrc.
PointCount() - 3 );
467 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
472 if( last == c_last_none )
489 if( iarc0 != -1 && iarc1 != -1 )
491 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
501 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
519 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
520 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
538 NCollection_Sequence<TDF_Label> theLabels;
539 aShapeTool->GetFreeShapes( theLabels );
543 if( theLabels.Length() == 1 )
544 return aShapeTool->GetShape( theLabels.Value( 1 ) );
546 TopoDS_Compound aCompound;
547 BRep_Builder aBuilder;
548 aBuilder.MakeCompound( aCompound );
550 for( NCollection_Sequence<TDF_Label>::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
552 TopoDS_Shape aFreeShape;
554 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
557 aBuilder.Add( aCompound, aFreeShape );
560 if( aCompound.NbChildren() > 0 )
571 if( theLabel.IsNull() )
573 Message::SendFail(
"Null label." );
577 if(
std::abs( aScale.X() ) <= gp::Resolution() ||
std::abs( aScale.Y() ) <= gp::Resolution()
578 ||
std::abs( aScale.Z() ) <= gp::Resolution() )
580 Message::SendFail(
"Scale factor is too small." );
584 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
586 if( aShapeTool.IsNull() )
588 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
592 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
596 Message::SendFail(
"Couldn't create assembly graph." );
600 bool anIsDone =
true;
604 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
606 0, 0, aScale.Z() ) );
609 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
611 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
613 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
615 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
616 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
621 const TDF_Label& aLabel = aG->GetNode( idx );
623 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
625 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
626 aBRepTrsf.Perform( aShape,
true );
627 if( !aBRepTrsf.IsDone() )
629 Standard_SStream aSS;
630 TCollection_AsciiString anEntry;
631 TDF_Tool::Entry( aLabel, anEntry );
632 aSS <<
"Shape " << anEntry <<
" is not scaled!";
633 Message::SendFail( aSS.str().c_str() );
637 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
638 aShapeTool->SetShape( aLabel, aScaledShape );
641 NCollection_Sequence<TDF_Label> aSubshapes;
642 aShapeTool->GetSubShapes( aLabel, aSubshapes );
643 for( NCollection_Sequence<TDF_Label>::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
645 const TDF_Label& aLSs = anItSs.Value();
646 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
647 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
648 aShapeTool->SetShape( aLSs, aSs1 );
652 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
653 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
654 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
656 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
658 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
659 gp_Trsf aTrsf = aLoc.Transformation();
660 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
661 XCAFDoc_Location::Set( aLabel, aTrsf );
670 aShapeTool->UpdateAssemblies();
678 BRepAlgoAPI_Fuse mkFuse;
679 NCollection_List<TopoDS_Shape> shapeArguments, shapeTools;
681 for(
const TopoDS_Shape& sh : aInputShapes )
686 if( shapeArguments.IsEmpty() )
687 shapeArguments.Append( sh );
689 shapeTools.Append( sh );
694 mkFuse.SetRunParallel(
true );
695 mkFuse.SetToFillHistory(
false );
696 mkFuse.SetArguments( shapeArguments );
697 mkFuse.SetTools( shapeTools );
700 catch(
const std::bad_alloc& )
702 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
703 "reducing the number of objects (e.g., vias), or freeing system memory." ),
707 catch(
const Standard_Failure& e )
709 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
710 "This may indicate insufficient memory. Consider "
711 "disabling shape fusing or reducing board complexity." ),
712 e.GetMessageString() ),
717 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
719 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
720 "memory-intensive; insufficient memory may cause failures." ),
723 if( mkFuse.HasErrors() )
725 wxString msg =
_(
"Errors:\n" );
726 wxStringOutputStream os_stream( &msg );
727 wxStdOutputStream out( os_stream );
729 mkFuse.DumpErrors( out );
733 if( mkFuse.HasWarnings() )
735 wxString msg =
_(
"Warnings:\n" );
736 wxStringOutputStream os_stream( &msg );
737 wxStdOutputStream out( os_stream );
739 mkFuse.DumpWarnings( out );
744 if( mkFuse.IsDone() )
746 TopoDS_Shape fusedShape = mkFuse.Shape();
750 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
751 unify.History() =
nullptr;
754 TopoDS_Shape unifiedShapes = unify.Shape();
756 if( unifiedShapes.IsNull() )
758 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
763 aOutShape = unifiedShapes;
767 catch(
const std::bad_alloc& )
769 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
770 "shape fusing or reducing the number of objects." ),
774 catch(
const Standard_Failure& e )
776 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
777 e.GetMessageString() ),
789 TopoDS_Compound compound;
790 BRep_Builder builder;
791 builder.MakeCompound( compound );
793 for(
const TopoDS_Shape& shape : aInputShapes )
794 builder.Add( compound, shape );
803 TopoDS_Shape outShape;
805 if( aInputShapes.Size() == 1 )
806 return aInputShapes.First();
808 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
817 const TCollection_ExtendedString& aPrefix )
819 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
823 Message::SendFail(
"Couldn't create assembly graph." );
827 bool anIsDone =
true;
829 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
831 const TDF_Label& lbl = aG->GetNode( idx );
832 Handle( TDataStd_Name ) nameHandle;
834 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
836 TCollection_ExtendedString
name;
840 name += nameHandle->Get();
843 TDataStd_Name::Set( lbl,
name );
847 TDataStd_Name::Set( lbl, aPrefix );
858 m_app = XCAFApp_Application::GetApplication();
859 m_app->NewDocument(
"MDTV-XCAF", m_doc );
860 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
878 if( m_doc->CanClose() == CDM_CCS_OK )
886 const double c_padExtraThickness = 0.005;
888 std::vector<TopoDS_Shape> padShapes;
902 double Zpos, thickness;
908 if( pcb_layer ==
F_Cu )
909 thickness += c_padExtraThickness;
910 else if( pcb_layer ==
B_Cu )
911 thickness -= c_padExtraThickness;
914 TopoDS_Shape testShape;
928 if( testShape.IsNull() )
930 std::vector<TopoDS_Shape> testShapes;
934 if( testShapes.size() > 0 )
935 testShape = testShapes.front();
940 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
946 if( pcb_layer ==
F_Cu )
948 else if( pcb_layer ==
B_Cu )
964 double f_pos, f_thickness;
965 double b_pos, b_thickness;
972 f_thickness += c_padExtraThickness;
973 b_thickness -= c_padExtraThickness;
976 double top = std::max( f_pos, f_pos + f_thickness );
977 double bottom = std::min( b_pos, b_pos + b_thickness );
978 double hole_height =
top - bottom;
980 TopoDS_Shape plating;
988 hole_height, bottom, aOrigin ) )
990 padShapes.push_back( plating );
1004 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
1021 padShapes.push_back( plating );
1033 if( !padShapes.empty() )
1038 NCollection_List<TopoDS_Shape> padShapesList;
1040 for(
const TopoDS_Shape& shape : padShapes )
1041 padShapesList.Append( shape );
1047 for(
const TopoDS_Shape& shape : padShapes )
1058 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1060 double margin = 0.001;
1068 double f_pos, f_thickness;
1069 double b_pos, b_thickness;
1072 double top = std::max( f_pos, f_pos + f_thickness );
1073 double bottom = std::min( b_pos, b_pos + b_thickness );
1075 double holeZsize = (
top - bottom ) + ( margin * 2 );
1077 double boardDrill = aShape.
GetWidth();
1078 double copperDrill = boardDrill - aPlatingThickness * 2;
1080 TopoDS_Shape copperHole, boardHole;
1085 holeZsize, bottom - margin, aOrigin ) )
1098 holeZsize, bottom - margin, aOrigin ) )
1114 const wxString& aNetname )
1116 double f_pos, f_thickness;
1117 double b_pos, b_thickness;
1120 double top = std::max( f_pos, f_pos + f_thickness );
1121 double bottom = std::min( b_pos, b_pos + b_thickness );
1123 TopoDS_Shape plating;
1126 (
top - bottom ), bottom, aOrigin ) )
1148 double margin = 0.001;
1152 double copperMargin = 0.5;
1154 double start_pos, start_thickness;
1155 double end_pos, end_thickness;
1160 double top = std::max( { start_pos, start_pos + start_thickness,
1161 end_pos, end_pos + end_thickness } );
1162 double bottom = std::min( { start_pos, start_pos + start_thickness,
1163 end_pos, end_pos + end_thickness } );
1166 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1167 top += copperMargin;
1168 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1169 bottom -= copperMargin;
1171 double holeZsize = (
top - bottom ) + ( margin * 2 );
1172 double holeZpos = bottom - margin;
1174 double backdrillDiameter = aShape.
GetWidth();
1176 TopoDS_Shape backdrillHole;
1180 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1197 bool aFrontSide,
const VECTOR2D& aOrigin )
1199 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1200 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1203 if( aDiameter <= 0 || aDepth <= 0 )
1205 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1206 aDiameter, aDepth );
1210 double margin = 0.001;
1213 double copperMargin = 0.5;
1216 double boardZpos, boardThickness;
1220 double f_pos, f_thickness, b_pos, b_thickness;
1227 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1228 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1230 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1231 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1234 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1235 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1236 double radius_mm = diameter_mm / 2.0;
1238 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1239 diameter_mm, depth_mm, radius_mm );
1243 double cylinderZpos;
1244 double cylinderHeight;
1250 cylinderZpos = topOuterSurface - depth_mm - margin;
1251 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1257 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1258 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1262 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1263 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1265 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1266 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1272 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1274 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1276 if( cylinder.IsNull() )
1278 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1279 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1288 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1291 catch(
const Standard_Failure& e )
1293 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1294 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1295 e.GetMessageString() ),
1305 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1307 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1308 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1313 if( aDiameter <= 0 || aAngle <= 0 )
1315 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1316 aDiameter, aAngle );
1320 double margin = 0.001;
1323 double copperMargin = 0.5;
1326 double boardZpos, boardThickness;
1330 double f_pos, f_thickness, b_pos, b_thickness;
1335 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1336 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1338 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1339 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1342 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1343 double radius_mm = diameter_mm / 2.0;
1347 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1355 depth_mm = radius_mm / tan( halfAngleRad );
1356 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1357 depth_mm, radius_mm );
1364 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1365 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1376 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1378 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1379 bottomRadius_mm, tan( halfAngleRad ) );
1381 if( bottomRadius_mm < 0 )
1382 bottomRadius_mm = 0;
1387 double coneHeight = depth_mm + copperMargin + margin;
1391 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1392 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1403 coneZpos = topOuterSurface - depth_mm - margin;
1404 r1 = bottomRadius_mm;
1406 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1408 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1409 coneZpos, r1, r2, coneHeight );
1411 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1412 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1419 coneZpos = bottomOuterSurface - copperMargin - margin;
1421 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1422 r2 = bottomRadius_mm;
1424 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1425 coneZpos, r1, r2, coneHeight );
1427 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1428 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1433 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1434 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1443 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1446 catch(
const Standard_Failure& e )
1448 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1449 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1450 e.GetMessageString() ),
1460 int aAngle,
bool aFrontSide )
1462 std::map<PCB_LAYER_ID, int> knockouts;
1465 double f_pos, f_thickness, b_pos, b_thickness;
1469 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1470 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1473 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1474 double radius_mm = diameter_mm / 2.0;
1478 double halfAngleRad = 0.0;
1483 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1487 depth_mm = radius_mm / tan( halfAngleRad );
1498 double featureTop, featureBottom;
1502 featureTop = topOuterSurface;
1503 featureBottom = topOuterSurface - depth_mm;
1507 featureBottom = bottomOuterSurface;
1508 featureTop = bottomOuterSurface + depth_mm;
1511 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1512 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1521 double layerZ, layerThickness;
1525 double layerTop = std::max( layerZ, layerZ + layerThickness );
1526 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1530 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1532 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1533 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1538 int knockoutDiameter;
1544 double layerSurfaceZ;
1548 layerSurfaceZ = layerTop;
1553 layerSurfaceZ = layerBottom;
1557 double distanceFromSurface;
1559 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1561 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1564 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1566 if( radiusAtLayer_mm <= 0 )
1568 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1569 static_cast<int>( layer ) );
1573 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1574 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1575 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1580 knockoutDiameter = aDiameter;
1581 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1582 static_cast<int>( layer ), knockoutDiameter );
1585 knockouts[layer] = knockoutDiameter;
1593 double& aThickness )
1596 static const double c_silkscreenAboveCopper = 0.04;
1597 static const double c_soldermaskAboveCopper = 0.015;
1605 double f_pos, f_thickness;
1607 double top = std::max( f_pos, f_pos + f_thickness );
1610 aZPos =
top + c_silkscreenAboveCopper;
1612 aZPos =
top + c_soldermaskAboveCopper;
1618 double b_pos, b_thickness;
1620 double bottom = std::min( b_pos, b_pos + b_thickness );
1623 aZPos = bottom - c_silkscreenAboveCopper;
1625 aZPos = bottom - c_soldermaskAboveCopper;
1633 double& aThickness )
1637 bool wasPrepreg =
false;
1639 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1642 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1648 if( aLayer ==
B_Cu )
1693 double f_pos, f_thickness;
1694 double b_pos, b_thickness;
1697 double top = std::min( f_pos, f_pos + f_thickness );
1698 double bottom = std::max( b_pos, b_pos + b_thickness );
1700 aThickness = (
top - bottom );
1703 wxASSERT( aZPos == 0.0 );
1709 const wxString& aRefDes )
1711 double f_pos, f_thickness;
1712 double b_pos, b_thickness;
1716 double boardSurfaceZ;
1719 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1721 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1723 double bodyThickness = aHeight - aStandoff;
1727 zBot = boardSurfaceZ + aStandoff;
1729 zBot = boardSurfaceZ - aHeight;
1739 if( aStandoff <= 0.0 )
1755 double f_pos, f_thickness;
1756 double b_pos, b_thickness;
1760 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1761 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1763 static const double c_protrusion = 1.0;
1765 double pinZBot, pinHeight;
1769 pinZBot = boardBotZ - c_protrusion;
1770 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1774 double pinZTop = boardTopZ + c_protrusion;
1775 pinZBot = boardBotZ - aStandoff;
1776 pinHeight = pinZTop - pinZBot;
1787 const VECTOR2D& aOrigin,
const wxString& aNetname )
1789 bool success =
true;
1797 double z_pos, thickness;
1800 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1808 else if( aLayer ==
F_Mask )
1815 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1828 const std::vector<wxString>& aAltFilenames,
1829 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1831 VECTOR3D aScale,
bool aSubstituteModels )
1833 if( aFileName.empty() )
1835 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1844 wxString errorMessage;
1846 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1849 if( errorMessage.IsEmpty() )
1850 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1857 TopLoc_Location toploc;
1859 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1862 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1868 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1870 if( llabel.IsNull() )
1873 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1881 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1882 TDataStd_Name::Set( llabel, refdes );
1893 m_assy->UpdateAssemblies();
1965 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1966 double aZposition,
const VECTOR2D& aOrigin )
1973 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1974 double h_width = aWidth/2.0;
1976 coords[0] =
VECTOR2D{ 0.0, h_width };
1979 coords[1] =
VECTOR2D{ len, h_width };
1982 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1985 coords[3] =
VECTOR2D{ len, -h_width };
1988 coords[4] =
VECTOR2D{ 0, -h_width };
1991 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1994 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1996 for(
int ii = 0; ii < 6; ii++ )
1999 coords[ii] += aStartPoint;
2004 gp_Pnt coords3D[ 6 ];
2006 for(
int ii = 0; ii < 6; ii++ )
2008 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
2009 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
2013 BRepBuilderAPI_MakeWire wire;
2014 bool success =
true;
2026 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2031 edge = BRepBuilderAPI_MakeEdge(
circle );
2036 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2039 Handle( Geom_TrimmedCurve ) arcOfCircle =
2040 GC_MakeArcOfCircle( coords3D[1],
2044 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2047 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2050 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2051 GC_MakeArcOfCircle( coords3D[4],
2055 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2059 catch(
const Standard_Failure& e )
2061 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2062 e.GetMessageString() ),
2067 BRepBuilderAPI_MakeFace face;
2071 gp_Pln plane( coords3D[0], gp::DZ() );
2072 face = BRepBuilderAPI_MakeFace( plane, wire );
2074 catch(
const Standard_Failure& e )
2076 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2077 e.GetMessageString() ),
2082 if( aThickness != 0.0 )
2084 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2086 if( aShape.IsNull() )
2088 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2105 double aZposition,
const VECTOR2D& aOrigin )
2107 std::vector<TopoDS_Shape> testShapes;
2110 aHeight, aZposition, aOrigin );
2112 if( testShapes.size() > 0 )
2113 aShape = testShapes.front();
2136 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2140 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2142 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2143 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2153 gp_Pnt start = toPoint( aPt0 );
2154 gp_Pnt
end = toPoint( aPt1 );
2156 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2158 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2160 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2168 aMkWire.Add( mkEdge.Edge() );
2170 if( aMkWire.Error() != BRepLib_WireDone )
2172 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2186 Handle( Geom_Curve ) curve;
2188 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2190 gp_Ax2 axis = gp::XOY();
2191 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2193 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2197 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2198 toPoint( aArc.GetP1() ) ).Value();
2201 if( curve.IsNull() )
2204 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2206 if( !aMkWire.IsDone() )
2208 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2209 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2211 aArc.GetP0().x, aArc.GetP0().y,
2212 aArc.GetArcMid().x, aArc.GetArcMid().y,
2213 aArc.GetP1().x, aArc.GetP1().y ),
2223 bool isFirstShape =
true;
2236 if( nextShape != -1 )
2242 lastPt = aChain.
CPoint( i );
2252 firstPt = currentArc.
GetP0();
2257 lastPt = currentArc.
GetP0();
2259 if( addArc( lastPt, currentArc ) )
2260 lastPt = currentArc.
GetP1();
2279 isFirstShape =
false;
2282 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2284 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2286 firstPt.
x, firstPt.
y ),
2292 catch(
const Standard_Failure& e )
2294 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2295 e.GetMessageString() ),
2305 bool aConvertToArcs,
double aThickness,
double aZposition,
2313 if( aConvertToArcs )
2317 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2321 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2325 fallbackPoly = workingPoly;
2326 workingPoly = approximated;
2345 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2347 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2348 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2352 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2353 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2355 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2359 auto tryMakeWire = [
this, &aZposition,
2360 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2363 BRepLib_MakeWire mkWire;
2367 if( mkWire.IsDone() )
2369 wire = mkWire.Wire();
2374 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2375 "z: %g; bounding box: %s" ),
2376 static_cast<int>( aContour.PointCount() ),
2377 static_cast<int>( mkWire.Error() ),
2382 if( !wire.IsNull() )
2384 BRepAlgoAPI_Check check( wire,
false,
true );
2386 if( !check.IsValid() )
2388 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2389 "z: %g; bounding box: %s" ),
2401 BRepBuilderAPI_MakeFace mkFace;
2403 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2409 bool allow_retry = aConvertToArcs ? true :
false;
2411 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2413 if( aConvertToArcs && wire.IsNull() )
2415 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2419 allow_retry =
false;
2420 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2425 if( !wire.IsNull() )
2427 if( basePlane.Axis().Direction().Z() < 0 )
2430 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2434 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2435 "z: %g; bounding box: %s" ),
2444 if( !wire.IsNull() )
2446 if( basePlane.Axis().Direction().Z() > 0 )
2453 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2454 "z: %g; bounding box: %s" ),
2461 catch(
const Standard_Failure& e )
2463 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2464 static_cast<int>( contId ),
2465 e.GetMessageString() ),
2471 if( mkFace.IsDone() )
2473 TopoDS_Shape faceShape = mkFace.Shape();
2475 if( aThickness != 0.0 )
2477 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2478 aShapes.push_back( prism );
2480 if( prism.IsNull() )
2488 aShapes.push_back( faceShape );
2504 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2505 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2506 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2507 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2508 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2509 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2510 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2511 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2521 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2523 aColorOut =
COLOR4D( aColorStr );
2528 const std::vector<FAB_LAYER_COLOR>& colors =
2535 if( fabColor.GetName() == aColorStr )
2537 aColorOut = fabColor.GetColor( aType );
2559 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2564 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2569 double boardThickness;
2589 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2593 polyset.
Append( contour );
2600 m_reporter->Report(
_(
"OCC error creating main outline." ),
2609 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2621 BRepBndLib::Add( brdShape, brdBndBox );
2624 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2629 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2630 std::vector<Bnd_Box>& holeBoxes )
2634 Bnd_Box brdWithHolesBndBox = brdBndBox;
2636 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2637 holeBoxes.resize( input.size() );
2639 for(
size_t i = 0; i < input.size(); i++ )
2642 BRepBndLib::Add( input[i], bbox );
2643 brdWithHolesBndBox.Add( bbox );
2644 ( *holeBoxSet )[i] = bbox;
2645 holeBoxes[i] = bbox;
2648 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2651 auto subtractShapesMap =
2652 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2653 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2654 const std::vector<Bnd_Box>& aHoleBoxes )
2656 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2659 for(
auto& [netname, vec] : aShapesMap )
2663 auto subtractLoopFn = [&](
const int shapeId )
2665 TopoDS_Shape& shape = vec[shapeId];
2668 BRepBndLib::Add( shape, shapeBbox );
2670 NCollection_List<TopoDS_Shape> holelist;
2673 std::unique_lock lock( mutex );
2675 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2677 for(
const int&
index : indices )
2678 holelist.Append( aHolesList[
index] );
2684 if( holelist.IsEmpty() )
2686 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2688 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2689 holelist.Append( aHolesList[i] );
2694 if( holelist.IsEmpty() )
2697 NCollection_List<TopoDS_Shape> cutArgs;
2698 cutArgs.Append( shape );
2700 BRepAlgoAPI_Cut
cut;
2702 cut.SetRunParallel(
true );
2703 cut.SetToFillHistory(
false );
2705 cut.SetArguments( cutArgs );
2706 cut.SetTools( holelist );
2709 if(
cut.HasErrors() ||
cut.HasWarnings() )
2711 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2718 if(
cut.HasErrors() )
2720 wxString msg =
_(
"Errors:\n" );
2721 wxStringOutputStream os_stream( &msg );
2722 wxStdOutputStream out( os_stream );
2724 cut.DumpErrors( out );
2728 if(
cut.HasWarnings() )
2730 wxString msg =
_(
"Warnings:\n" );
2731 wxStringOutputStream os_stream( &msg );
2732 wxStdOutputStream out( os_stream );
2734 cut.DumpWarnings( out );
2739 shape =
cut.Shape();
2742 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2746 auto subtractShapes =
2747 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2748 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2749 const std::vector<Bnd_Box>& aHoleBoxes )
2751 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2753 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2754 aShapesList = aShapesMap[wxEmptyString];
2760 Bnd_BoundSortBox bsbHoles;
2761 std::vector<Bnd_Box> holeBoxes;
2769 Bnd_BoundSortBox bsbHoles;
2770 std::vector<Bnd_Box> holeBoxes;
2779 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2781 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2782 const std::vector<TopoDS_Shape>& aShapes )
2784 for(
const TopoDS_Shape& shape : aShapes )
2785 shapesToFuseMap[aNetname].Append( shape );
2789 addShapes( netname, shapes );
2792 addShapes( netname, shapes );
2795 addShapes( netname, shapes );
2802 auto fuseLoopFn = [&](
const wxString& aNetname )
2804 auto& toFuse = shapesToFuseMap[aNetname];
2807 if( !fusedShape.IsNull() )
2809 std::unique_lock lock( mutex );
2819 BS::multi_future<void> mf;
2821 for(
const auto& [netname,
_] : shapesToFuseMap )
2822 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2839 auto pushToAssemblyMap =
2840 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2841 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2842 bool aCompoundAll,
const wxString& aNiceName )
2844 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2848 std::vector<TopoDS_Shape> allShapes;
2850 for(
const auto& [netname, shapesList] : aShapesMap )
2851 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2853 if( !allShapes.empty() )
2854 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2858 shapesMap = aShapesMap;
2861 for(
const auto& [netname, shapesList] : shapesMap )
2863 std::vector<TopoDS_Shape> newList;
2868 newList = shapesList;
2872 for( TopoDS_Shape& shape : newList )
2874 Handle( TDataStd_TreeNode ) node;
2877 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2884 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2885 TDF_Label shpLbl = node->Father()->Label();
2887 if( !shpLbl.IsNull() )
2889 if( visMatTool && !aVisMatLabel.IsNull() )
2890 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2896 shapeName << aShapeName;
2898 if( !netname.empty() )
2901 shapeName << netname;
2904 if( newList.size() > 1 )
2910 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2911 TDataStd_Name::Set( shpLbl, partname );
2919 auto pushToAssembly =
2920 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2921 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2923 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2925 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2929 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2930 double aMetallic,
double aRoughness ) -> TDF_Label
2932 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2933 XCAFDoc_VisMaterialPBR pbr;
2934 pbr.BaseColor = aBaseColor;
2935 pbr.Metallic = aMetallic;
2936 pbr.Roughness = aRoughness;
2937 vismat->SetPbrMaterial( pbr );
2938 return visMatTool->AddMaterial( vismat, aName );
2945 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2946 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2947 Quantity_ColorRGBA back_silk_color = front_silk_color;
2948 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2949 Quantity_ColorRGBA back_mask_color = front_mask_color;
2959 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2963 if( item->GetBrdLayerId() ==
F_Mask )
2964 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2966 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2969 if( item->GetBrdLayerId() ==
F_SilkS )
2970 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2971 else if( item->GetBrdLayerId() ==
B_SilkS )
2972 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2975 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2981 board_color = front_mask_color;
2982 board_color.SetAlpha( 1.0 );
2985 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2986 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2987 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2988 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2989 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2990 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2991 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2993 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2997 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2998 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2999 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
3000 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
3002 if( aPushBoardBody )
3005 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
3006 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
3010 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
3013 TopoDS_Compound asmCompound;
3014 BRep_Builder asmBuilder;
3015 asmBuilder.MakeCompound( asmCompound );
3016 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
3017 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
3019 if( !entry.bodyShapes.empty() )
3021 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
3022 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
3023 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
3024 double a = ( entry.colorKey & 0xFF ) / 255.0;
3026 double metallic, roughness;
3028 switch( entry.material )
3049 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3050 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3052 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3053 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3055 Handle( TDataStd_TreeNode ) bodyNode;
3056 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3057 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3059 if( !bodyShpLbl.IsNull() )
3061 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3062 TDataStd_Name::Set( bodyShpLbl,
3063 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3069 for( TopoDS_Shape& pinShape : entry.pinShapes )
3071 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3073 Handle( TDataStd_TreeNode ) pinNode;
3074 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3075 TDF_Label pinShpLbl = pinNode->Father()->Label();
3077 if( !pinShpLbl.IsNull() )
3079 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3080 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3081 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3085 TopLoc_Location loc;
3086 TDF_Label fpCompLbl = m_assy->AddComponent(
m_assy_label, fpLabel, loc );
3087 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3092#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3093 m_assy->UpdateAssemblies();
3102bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3106 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3114 wxFileName fn( aFileName );
3115 IGESControl_Controller::Init();
3116 IGESCAFControl_Writer writer;
3117 writer.SetColorMode(
true );
3118 writer.SetNameMode(
true );
3119 IGESData_GlobalSection
header = writer.Model()->GlobalSection();
3120 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3121 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3122 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3123 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3124 writer.Model()->SetGlobalSection(
header );
3126 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3135 wxFileInputStream input( inputFile );
3136 wxFileOutputStream
output( outputFile );
3140 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3146 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3150 wxZlibOutputStream zlibStream(
output, -1, wxZLIB_GZIP );
3152 if( !zlibStream.IsOk() )
3154 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3158 input.Read( zlibStream );
3160 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3162 m_reporter->Report(
_(
"Compress read or write error" ) );
3176 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3184 wxFileName fn( aFileName );
3186 STEPCAFControl_Writer writer;
3187 writer.SetColorMode(
true );
3188 writer.SetNameMode(
true );
3195 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3197 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3203 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3205 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3209 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3212 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3216 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3219 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3220 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3221 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3222 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3224 bool success =
true;
3227 wxString currCWD = wxGetCwd();
3228 wxString workCWD = fn.GetPath();
3230 if( !workCWD.IsEmpty() )
3231 wxSetWorkingDirectory( workCWD );
3233 wxString tmpfname(
"$tempfile$.step" );
3235 if(
false == writer.Write( tmpfname.c_str() ) )
3238 if( compress && success )
3240 wxString srcTmp( tmpfname );
3241 wxString dstTmp(
"$tempfile$.stpz" );
3244 wxRemoveFile( srcTmp );
3255 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3257 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3265 wxSetWorkingDirectory( currCWD );
3275 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3284 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3289 wxFileName fn( aFileName );
3291 wxFFileOutputStream ffStream( fn.GetFullPath() );
3292 wxStdOutputStream stdStream( ffStream );
3294#if OCC_VERSION_HEX >= 0x070600
3295 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3297 BRepTools::Write( shape, stdStream );
3306 wxFileName fn( aFileName );
3308 wxFFileOutputStream ffStream( fn.GetFullPath() );
3309 wxStdOutputStream file( ffStream );
3311 if( !ffStream.IsOk() )
3313 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3321 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3326 std::map<wxString, std::vector<int>> groups[4];
3327 std::map<wxString, double> groupAreas;
3328 TopExp_Explorer exp;
3331 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3333 TopoDS_Shape subShape = exp.Current();
3336 BRepBndLib::Add( subShape, bbox );
3340 for(
const auto& pair : pairs )
3342 const auto& [point, padTestShape] = pair;
3344 if( bbox.IsOut( point ) )
3347 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3349 if( surface.GetType() != GeomAbs_Plane )
3352 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3355 if( !dist.IsDone() )
3358 if( dist.Value() < Precision::Approximation() )
3361 groups[2][padKey].push_back( faceIndex );
3363 GProp_GProps system;
3364 BRepGProp::SurfaceProperties( subShape, system );
3366 double surfaceArea = system.Mass() / 1e6;
3367 groupAreas[padKey] += surfaceArea;
3376 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3377 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3378 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3379 file <<
" <shape format=\"BREP\"><![CDATA[";
3380#if OCC_VERSION_HEX < 0x070600
3381 BRepTools::Write( shape, file );
3383 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3385 file <<
"]]></shape>" << std::endl;
3386 file <<
" <topology>" << std::endl;
3388 TopTools_IndexedMapOfShape mainMap;
3389 TopExp::MapShapes( shape, mainMap );
3390 std::set<int> topo[4];
3392 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3395 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3396 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3398 for(
int dim = 0; dim < 4; dim++ )
3400 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3402 TopoDS_Shape subShape = exp.Current();
3403 int idx = mainMap.FindIndex( subShape );
3405 if( idx && !topo[dim].count( idx ) )
3406 topo[dim].insert( idx );
3410 for(
int dim = 0; dim <= 3; dim++ )
3412 std::string labels = c_dimLabels[dim];
3413 std::string label = c_dimLabel[dim];
3415 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3418 for(
auto p : topo[dim] )
3420 std::string
name(
"" );
3421 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3422 <<
"name=\"" <<
name <<
"\" "
3423 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3427 file <<
" </" << labels <<
">" << std::endl;
3430 file <<
" </topology>" << std::endl;
3431 file <<
" </geometry>" << std::endl;
3432 file <<
" <groups count=\""
3433 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3436 int groupNumber = 1;
3441 for(
int dim = 0; dim <= 3; dim++ )
3443 std::string label = c_dimLabel[dim];
3445 for(
auto g : groups[dim] )
3448 wxString
name = g.first;
3452 std::ostringstream gs;
3453 gs <<
"G_" << dim <<
"D_" << g.first;
3456 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3462 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3464 for(
auto index : g.second )
3465 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3467 file <<
" </group>" << std::endl;
3469 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3481 file <<
" </groups>" << std::endl;
3482 file <<
" <fields count=\"0\"/>" << std::endl;
3483 file <<
"</XAO>" << std::endl;
3490 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3491 TDF_Label& aLabel,
bool aSubstituteModels,
3492 wxString* aErrorMessage )
3494 std::string fileNameUTF8 = aFileName.utf8_string();
3496 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3497 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3499 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3503 aLabel = mm->second;
3509 Handle( TDocStd_Document ) doc;
3510 m_app->NewDocument(
"MDTV-XCAF", doc );
3513 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3518 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3520 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3528 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3530 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3541 wxFFileInputStream ifile( aFileName );
3542 wxFileName outFile( aFileName );
3544 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3545 outFile.SetExt( wxT(
"step" ) );
3546 wxFileOffset size = ifile.GetLength();
3548 if( size == wxInvalidOffset )
3550 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3557 bool success =
false;
3560 wxFFileOutputStream ofile( outFile.GetFullPath() );
3565 char* buffer =
new char[size];
3567 ifile.Read( buffer, size );
3568 std::string expanded;
3572 expanded = gzip::decompress( buffer, size );
3580 if( expanded.empty() )
3584 wxZipInputStream izipfile( ifile );
3585 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3587 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3589 izipfile.Read( ofile );
3594 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3600 ofile.Write( expanded.data(), expanded.size() );
3608 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3609 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3628 if( aSubstituteModels )
3630 wxFileName wrlName( aFileName );
3632 wxString basePath = wrlName.GetPath();
3633 wxString baseName = wrlName.GetName();
3641 alts.Add( wxT(
"stp" ) );
3642 alts.Add( wxT(
"step" ) );
3643 alts.Add( wxT(
"STP" ) );
3644 alts.Add( wxT(
"STEP" ) );
3645 alts.Add( wxT(
"Stp" ) );
3646 alts.Add( wxT(
"Step" ) );
3647 alts.Add( wxT(
"stpz" ) );
3648 alts.Add( wxT(
"stpZ" ) );
3649 alts.Add( wxT(
"STPZ" ) );
3650 alts.Add( wxT(
"step.gz" ) );
3651 alts.Add( wxT(
"stp.gz" ) );
3654 alts.Add( wxT(
"iges" ) );
3655 alts.Add( wxT(
"IGES" ) );
3656 alts.Add( wxT(
"igs" ) );
3657 alts.Add( wxT(
"IGS" ) );
3661 for(
const auto& altExt : alts )
3665 if( !aAltFilenames.empty() )
3667 for(
const wxString& altPath : aAltFilenames )
3669 wxFileName iterFn( altPath );
3671 if( iterFn.GetExt() == altExt )
3680 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3683 if( altFile.IsOk() && altFile.FileExists() )
3693 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3707 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3709 Handle( XCAFDoc_ShapeTool ) shapeTool =
3710 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3717 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3727 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3737 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3744 if( aLabel.IsNull() )
3746 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3753 TDataStd_Name::Set( aLabel, partname );
3763 TopLoc_Location& aLocation )
3777 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3783 double boardThickness;
3786 double top = std::max( boardZPos, boardZPos + boardThickness );
3787 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3792 double f_pos, f_thickness;
3796 bottom += f_thickness;
3803 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3804 lPos.Multiply( lRot );
3805 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3806 lPos.Multiply( lRot );
3811 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3812 lPos.Multiply( lRot );
3816 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3817 lPos.Multiply( lOff );
3820 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3821 lPos.Multiply( lOrient );
3822 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3823 lPos.Multiply( lOrient );
3824 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3825 lPos.Multiply( lOrient );
3827 aLocation = TopLoc_Location( lPos );
3834 IGESControl_Controller::Init();
3835 IGESCAFControl_Reader reader;
3836 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3838 if( stat != IFSelect_RetDone )
3842 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3846 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3850 reader.SetColorMode(
true );
3851 reader.SetNameMode(
false );
3852 reader.SetLayerMode(
false );
3854 if( !reader.Transfer( doc ) )
3856 if( doc->CanClose() == CDM_CCS_OK )
3863 if( reader.NbShapes() < 1 )
3865 if( doc->CanClose() == CDM_CCS_OK )
3877 STEPCAFControl_Reader reader;
3878 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3880 if( stat != IFSelect_RetDone )
3884 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3888 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3892 reader.SetColorMode(
true );
3893 reader.SetNameMode(
true );
3894 reader.SetLayerMode(
false );
3896 if( !reader.Transfer( doc ) )
3898 if( doc->CanClose() == CDM_CCS_OK )
3905 if( reader.NbRootsForTransfer() < 1 )
3907 if( doc->CanClose() == CDM_CCS_OK )
3919#if OCC_VERSION_HEX >= 0x070700
3920 VrmlAPI_CafReader reader;
3921 RWMesh_CoordinateSystemConverter conv;
3922 conv.SetInputLengthUnit( 2.54 );
3923 reader.SetCoordinateSystemConverter( conv );
3924 reader.SetDocument( doc );
3926 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3939 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3941 NCollection_Sequence<TDF_Label> frshapes;
3942 s_assy->GetFreeShapes( frshapes );
3944 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3953 TDF_Label d_targetLabel = d_assy->NewShape();
3955 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
3961 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3964 return d_targetLabel;
3970 NCollection_Sequence<TDF_Label> freeShapes;
3971 aShapeTool->GetFreeShapes( freeShapes );
3977 for(
int i = 1; i <= freeShapes.Length(); ++i )
3979 TDF_Label label = freeShapes.Value( i );
3981 aShapeTool->GetShape( label, shape );
3986 const double linearDeflection = 0.14;
3987 const double angularDeflection =
DEG2RAD( 30.0 );
3988 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
4010 wxFileName fn( aFileName );
4012 const char* tmpGltfname =
"$tempfile$.glb";
4013 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
4015 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
4016 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4017 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
4018 RWMesh_CoordinateSystem_Zup );
4019#if OCC_VERSION_HEX >= 0x070700
4020 cafWriter.SetParallel(
true );
4022 TColStd_IndexedDataMapOfStringString metadata;
4024 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4025 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4026 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4027 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4028 metadata.Add( TCollection_AsciiString(
"generator" ),
4029 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4030 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4033 bool success =
true;
4036 wxString currCWD = wxGetCwd();
4037 wxString workCWD = fn.GetPath();
4039 if( !workCWD.IsEmpty() )
4040 wxSetWorkingDirectory( workCWD );
4042 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4049 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4051 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4059 wxSetWorkingDirectory( currCWD );
4067#if OCC_VERSION_HEX < 0x070700
4074 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4084 wxFileName fn( aFileName );
4086 const char* tmpFname =
"$tempfile$.ply";
4087 RWPly_CafWriter cafWriter( tmpFname );
4089 cafWriter.SetFaceId(
true );
4090 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4091 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4093 TColStd_IndexedDataMapOfStringString metadata;
4095 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4096 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4097 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4098 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4099 metadata.Add( TCollection_AsciiString(
"generator" ),
4100 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4102 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4105 bool success =
true;
4108 wxString currCWD = wxGetCwd();
4109 wxString workCWD = fn.GetPath();
4111 if( !workCWD.IsEmpty() )
4112 wxSetWorkingDirectory( workCWD );
4114 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4121 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4123 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4131 wxSetWorkingDirectory( currCWD );
4142 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4152 wxFileName fn( aFileName );
4154 const char* tmpFname =
"$tempfile$.stl";
4157 wxString currCWD = wxGetCwd();
4158 wxString workCWD = fn.GetPath();
4160 if( !workCWD.IsEmpty() )
4161 wxSetWorkingDirectory( workCWD );
4163 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4170 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4172 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4180 wxSetWorkingDirectory( currCWD );
4192 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4201 wxFileName fn( aFileName );
4203 const char* tmpFname =
"$tempfile$.u3d";
4206 wxString currCWD = wxGetCwd();
4207 wxString workCWD = fn.GetPath();
4209 if( !workCWD.IsEmpty() )
4210 wxSetWorkingDirectory( workCWD );
4213 bool success = writer.
Perform( m_doc );
4219 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4221 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4228 wxSetWorkingDirectory( currCWD );
4239 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4248 wxFileName fn( aFileName );
4250 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4251 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4253 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4254 bool success = writer.
Perform( m_doc );
4257 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4259 plotter->SetColorMode(
true );
4260 plotter->Set3DExport(
true );
4261 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4263 plotter->SetRenderSettings( &renderSettings );
4265 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4267 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4273 plotter->StartPlot(
"1",
"3D Model" );
4274 double fov_degrees = 16.5f;
4279 std::vector<PDF_3D_VIEW> views;
4284 std::vector<float> c2wMatrix =
4288 .m_name =
"Default",
4289 .m_cameraMatrix = c2wMatrix,
4290 .m_cameraCenter = (float)
distance,
4291 .m_fov = (
float) fov_degrees,
4300 .m_cameraMatrix = c2wMatrix,
4301 .m_cameraCenter = (float)
distance,
4302 .m_fov = (
float) fov_degrees,
4311 .m_cameraMatrix = c2wMatrix,
4312 .m_cameraCenter = (float)
distance,
4313 .m_fov = (
float) fov_degrees,
4322 .m_cameraMatrix = c2wMatrix,
4323 .m_cameraCenter = (float)
distance,
4324 .m_fov = (
float) fov_degrees,
4327 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4336 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4338 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4339 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4345 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)
bool getModelLabel(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
bool AddCounterbore(const VECTOR2I &aPosition, int aDiameter, int aDepth, bool aFrontSide, const VECTOR2D &aOrigin)
Add a counterbore shape to remove board material from the top or bottom of a hole.
void SetEnabledLayers(const LSET &aLayers)
void SetExtraPadThickness(bool aValue)
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
std::vector< TopoDS_Shape > m_board_front_silk
bool AddExtrudedPins(const FOOTPRINT *aFootprint, bool aBottom, double aStandoff, const VECTOR2D &aOrigin)
Add metallic pin extrusions for through-hole pads.
Handle(XCAFApp_Application) m_app
bool WritePDF(const wxString &aFileName)
virtual ~STEP_PCB_MODEL()
std::vector< TopoDS_Shape > m_board_front_mask
bool WriteSTL(const wxString &aFileName)
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
std::map< PCB_LAYER_ID, int > GetCopperLayerKnockouts(int aDiameter, int aDepth, int aAngle, bool aFrontSide)
Get the knockout diameters for copper layers that a counterbore or countersink crosses.
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
std::vector< TopoDS_Shape > m_copperCutouts
bool CompressSTEP(wxString &inputFile, wxString &outputFile)
std::vector< TopoDS_Shape > m_board_back_silk
void getCopperLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
bool AddComponent(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, const wxString &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
bool AddExtrudedBody(const SHAPE_POLY_SET &aOutline, bool aBottom, double aStandoff, double aHeight, const VECTOR2D &aOrigin, uint32_t aColor, EXTRUSION_MATERIAL aMaterial, const wxString &aRefDes)
Add an extruded 3D body from a 2D outline polygon.
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
bool Perform(const Handle(TDocStd_Document) &aDocument)
const VECTOR3D & GetCenter() const
const Bnd_Box & GetMeshBoundingBox() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
Handle(KICAD3D_INFO) KICAD3D_INFO
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static bool rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
static TopoDS_Shape fuseShapesOrCompound(const NCollection_List< TopoDS_Shape > &aInputShapes, REPORTER *aReporter)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
static bool prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static constexpr double USER_ANGLE_PREC
static constexpr double USER_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
std::pair< std::string, TDF_Label > MODEL_DATUM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
std::vector< std::string > header
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D