34#include <wx/filename.h>
36#include <wx/sstream.h>
37#include <wx/stdpaths.h>
40#include <wx/zstream.h>
41#include <wx/wfstream.h>
42#include <wx/zipstrm.h>
43#include <wx/stdstream.h>
46#include <decompress.hpp>
73#include <IGESCAFControl_Reader.hxx>
74#include <IGESCAFControl_Writer.hxx>
75#include <IGESControl_Controller.hxx>
76#include <IGESData_GlobalSection.hxx>
77#include <IGESData_IGESModel.hxx>
78#include <Interface_Static.hxx>
79#include <Quantity_Color.hxx>
80#include <STEPCAFControl_Reader.hxx>
81#include <STEPCAFControl_Writer.hxx>
82#include <APIHeaderSection_MakeHeader.hxx>
83#include <Standard_Failure.hxx>
84#include <Standard_Handle.hxx>
85#include <Standard_Version.hxx>
86#include <TCollection_ExtendedString.hxx>
87#include <TDocStd_Document.hxx>
88#include <TDataStd_Name.hxx>
89#include <TDataStd_TreeNode.hxx>
90#include <TDF_ChildIterator.hxx>
91#include <TDF_LabelSequence.hxx>
92#include <TDF_Tool.hxx>
93#include <TopExp_Explorer.hxx>
95#include <XCAFApp_Application.hxx>
97#include <XCAFDoc_DocumentTool.hxx>
98#include <XCAFDoc_ColorTool.hxx>
99#include <XCAFDoc_ShapeTool.hxx>
100#include <XCAFDoc_VisMaterialTool.hxx>
101#include <XCAFDoc_Area.hxx>
102#include <XCAFDoc_Centroid.hxx>
103#include <XCAFDoc_Editor.hxx>
104#include <XCAFDoc_Location.hxx>
105#include <XCAFDoc_Volume.hxx>
108#include "KI_XCAFDoc_AssemblyGraph.hxx"
110#include <BRep_Tool.hxx>
111#include <BRepMesh_IncrementalMesh.hxx>
112#include <BRepBuilderAPI_GTransform.hxx>
113#include <BRepBuilderAPI_MakeEdge.hxx>
114#include <BRepBuilderAPI_MakeWire.hxx>
115#include <BRepBuilderAPI_MakeFace.hxx>
116#include <BRepExtrema_DistShapeShape.hxx>
117#include <BRepPrimAPI_MakeCone.hxx>
118#include <BRepPrimAPI_MakeCylinder.hxx>
119#include <BRepPrimAPI_MakePrism.hxx>
120#include <BRepTools.hxx>
121#include <BRepLib_MakeWire.hxx>
122#include <BRepAdaptor_Surface.hxx>
123#include <BRepAlgoAPI_Check.hxx>
124#include <BRepAlgoAPI_Cut.hxx>
125#include <BRepAlgoAPI_Fuse.hxx>
126#include <ShapeUpgrade_UnifySameDomain.hxx>
128#include <BRepBndLib.hxx>
129#include <Bnd_BoundSortBox.hxx>
130#include <GProp_GProps.hxx>
131#include <BRepGProp.hxx>
133#include <Geom_Curve.hxx>
134#include <Geom_TrimmedCurve.hxx>
139#include <GC_MakeArcOfCircle.hxx>
140#include <GC_MakeCircle.hxx>
142#include <RWGltf_CafWriter.hxx>
143#include <StlAPI_Writer.hxx>
145#if OCC_VERSION_HEX >= 0x070700
146#include <VrmlAPI_CafReader.hxx>
147#include <RWPly_CafWriter.hxx>
175 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
177 if( !lfile.FileExists() )
180 wxString ext = lfile.GetExt().Lower();
182 if( ext == wxT(
"wrl" ) )
185 if( ext == wxT(
"wrz" ) )
188 if( ext == wxT(
"idf" ) )
191 if( ext == wxT(
"emn" ) )
194 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
208 const int max_line_count = 3;
210 for(
int ii = 0; ii < max_line_count; ii++ )
212 memset( iline, 0, 82 );
213 ifile.getline( iline, 82 );
219 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
225 std::string fstr = iline;
229 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
238 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
245 if( strncmp( iline,
"/*", 2 ) != 0 )
263 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
264 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
265 double det = -b.
x * d.
y + d.
x * b.
y;
269 center.x = ( -bc * d.
y - cd * b.
y ) * det;
270 center.y = ( b.
x * cd + d.
x * bc ) * det;
277#define APPROX_DBG( stmt )
285 static const double c_radiusDeviation = 1000.0;
286 static const double c_arcCenterDeviation = 1000.0;
287 static const double c_relLengthDeviation = 0.8;
288 static const int c_last_none = -1000;
290 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
291 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
308 int last = c_last_none;
314 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
316 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
321 bool defective =
false;
327 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
335 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
336 defective |=
std::abs( a_diff ) < 0.1;
339 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
340 defective |=
std::abs( a_diff ) >= maxAngleDiff;
351 for(
int j = i; j <= jEndIdx; j++ )
356 double rad_test = ( p_test -
center ).EuclideanNorm();
357 double d_tl = ( p_test - p_prev ).EuclideanNorm();
361 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
364 if( rad_dev > c_radiusDeviation )
367 <<
" Radius deviation too large: " << int64_t( rad_dev )
368 <<
" > " << c_radiusDeviation << std::endl );
373 double maxAngleDiff =
374 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
376 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
377 if(
std::abs( a_diff_test ) >= maxAngleDiff )
379 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
384 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
386 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
387 <<
"; " << d01 << std::endl );
397 if( last != c_last_none )
406 int toRemove = last - ( aSrc.
PointCount() - 3 );
436 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
440 if( last == c_last_none )
457 if( iarc0 != -1 && iarc1 != -1 )
459 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
469 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
487 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
488 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
506 TDF_LabelSequence theLabels;
507 aShapeTool->GetFreeShapes( theLabels );
511 if( theLabels.Length() == 1 )
512 return aShapeTool->GetShape( theLabels.Value( 1 ) );
514 TopoDS_Compound aCompound;
515 BRep_Builder aBuilder;
516 aBuilder.MakeCompound( aCompound );
518 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
520 TopoDS_Shape aFreeShape;
522 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
525 aBuilder.Add( aCompound, aFreeShape );
528 if( aCompound.NbChildren() > 0 )
537static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
539 if( theLabel.IsNull() )
541 Message::SendFail(
"Null label." );
542 return Standard_False;
545 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
546 || Abs( aScale.Z() ) <= gp::Resolution() )
548 Message::SendFail(
"Scale factor is too small." );
549 return Standard_False;
552 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
554 if( aShapeTool.IsNull() )
556 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
557 return Standard_False;
560 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
564 Message::SendFail(
"Couldn't create assembly graph." );
565 return Standard_False;
568 Standard_Boolean anIsDone = Standard_True;
572 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
574 0, 0, aScale.Z() ) );
577 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
579 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
581 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
583 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
584 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
589 const TDF_Label& aLabel = aG->GetNode( idx );
591 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
593 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
594 aBRepTrsf.Perform( aShape, Standard_True );
595 if( !aBRepTrsf.IsDone() )
597 Standard_SStream aSS;
598 TCollection_AsciiString anEntry;
599 TDF_Tool::Entry( aLabel, anEntry );
600 aSS <<
"Shape " << anEntry <<
" is not scaled!";
601 Message::SendFail( aSS.str().c_str() );
602 anIsDone = Standard_False;
603 return Standard_False;
605 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
606 aShapeTool->SetShape( aLabel, aScaledShape );
609 TDF_LabelSequence aSubshapes;
610 aShapeTool->GetSubShapes( aLabel, aSubshapes );
611 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
613 const TDF_Label& aLSs = anItSs.Value();
614 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
615 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
616 aShapeTool->SetShape( aLSs, aSs1 );
620 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
621 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
622 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
624 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
626 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
627 gp_Trsf aTrsf = aLoc.Transformation();
628 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
629 XCAFDoc_Location::Set( aLabel, aTrsf );
635 return Standard_False;
638 aShapeTool->UpdateAssemblies();
646 BRepAlgoAPI_Fuse mkFuse;
647 TopTools_ListOfShape shapeArguments, shapeTools;
649 for( TopoDS_Shape& sh : aInputShapes )
654 if( shapeArguments.IsEmpty() )
655 shapeArguments.Append( sh );
657 shapeTools.Append( sh );
662 mkFuse.SetRunParallel(
true );
663 mkFuse.SetToFillHistory(
false );
664 mkFuse.SetArguments( shapeArguments );
665 mkFuse.SetTools( shapeTools );
668 catch(
const std::bad_alloc& )
670 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
671 "reducing the number of objects (e.g., vias), or freeing system memory." ),
675 catch(
const Standard_Failure& e )
677 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
678 "This may indicate insufficient memory. Consider "
679 "disabling shape fusing or reducing board complexity." ),
680 e.GetMessageString() ),
685 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
687 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
688 "memory-intensive; insufficient memory may cause failures." ),
691 if( mkFuse.HasErrors() )
693 wxString msg =
_(
"Errors:\n" );
694 wxStringOutputStream os_stream( &msg );
695 wxStdOutputStream out( os_stream );
697 mkFuse.DumpErrors( out );
701 if( mkFuse.HasWarnings() )
703 wxString msg =
_(
"Warnings:\n" );
704 wxStringOutputStream os_stream( &msg );
705 wxStdOutputStream out( os_stream );
707 mkFuse.DumpWarnings( out );
712 if( mkFuse.IsDone() )
714 TopoDS_Shape fusedShape = mkFuse.Shape();
718 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
719 unify.History() =
nullptr;
722 TopoDS_Shape unifiedShapes = unify.Shape();
724 if( unifiedShapes.IsNull() )
726 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
731 aOutShape = unifiedShapes;
735 catch(
const std::bad_alloc& )
737 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
738 "shape fusing or reducing the number of objects." ),
742 catch(
const Standard_Failure& e )
744 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
745 e.GetMessageString() ),
757 TopoDS_Compound compound;
758 BRep_Builder builder;
759 builder.MakeCompound( compound );
761 for(
const TopoDS_Shape& shape : aInputShapes )
762 builder.Add( compound, shape );
772 TopoDS_Shape outShape;
774 if( aInputShapes.Size() == 1 )
775 return aInputShapes.First();
777 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
786 const TCollection_ExtendedString& aPrefix )
788 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
792 Message::SendFail(
"Couldn't create assembly graph." );
793 return Standard_False;
796 Standard_Boolean anIsDone = Standard_True;
798 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
800 const TDF_Label& lbl = aG->GetNode( idx );
801 Handle( TDataStd_Name ) nameHandle;
803 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
805 TCollection_ExtendedString
name;
809 name += nameHandle->Get();
812 TDataStd_Name::Set( lbl,
name );
816 TDataStd_Name::Set( lbl, aPrefix );
827 m_app = XCAFApp_Application::GetApplication();
828 m_app->NewDocument(
"MDTV-XCAF", m_doc );
829 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
847 if( m_doc->CanClose() == CDM_CCS_OK )
855 const double c_padExtraThickness = 0.005;
857 std::vector<TopoDS_Shape> padShapes;
871 double Zpos, thickness;
877 if( pcb_layer ==
F_Cu )
878 thickness += c_padExtraThickness;
879 else if( pcb_layer ==
B_Cu )
880 thickness -= c_padExtraThickness;
883 TopoDS_Shape testShape;
897 if( testShape.IsNull() )
899 std::vector<TopoDS_Shape> testShapes;
903 if( testShapes.size() > 0 )
904 testShape = testShapes.front();
909 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
915 if( pcb_layer ==
F_Cu )
917 else if( pcb_layer ==
B_Cu )
933 double f_pos, f_thickness;
934 double b_pos, b_thickness;
941 f_thickness += c_padExtraThickness;
942 b_thickness -= c_padExtraThickness;
945 double top = std::max( f_pos, f_pos + f_thickness );
946 double bottom = std::min( b_pos, b_pos + b_thickness );
947 double hole_height =
top - bottom;
949 TopoDS_Shape plating;
957 hole_height, bottom, aOrigin ) )
959 padShapes.push_back( plating );
973 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
990 padShapes.push_back( plating );
1002 if( !padShapes.empty() )
1007 TopTools_ListOfShape padShapesList;
1009 for(
const TopoDS_Shape& shape : padShapes )
1010 padShapesList.Append( shape );
1016 for(
const TopoDS_Shape& shape : padShapes )
1027 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1029 double margin = 0.001;
1037 double f_pos, f_thickness;
1038 double b_pos, b_thickness;
1041 double top = std::max( f_pos, f_pos + f_thickness );
1042 double bottom = std::min( b_pos, b_pos + b_thickness );
1044 double holeZsize = (
top - bottom ) + ( margin * 2 );
1046 double boardDrill = aShape.
GetWidth();
1047 double copperDrill = boardDrill - aPlatingThickness * 2;
1049 TopoDS_Shape copperHole, boardHole;
1054 holeZsize, bottom - margin, aOrigin ) )
1067 holeZsize, bottom - margin, aOrigin ) )
1083 const wxString& aNetname )
1085 double f_pos, f_thickness;
1086 double b_pos, b_thickness;
1089 double top = std::max( f_pos, f_pos + f_thickness );
1090 double bottom = std::min( b_pos, b_pos + b_thickness );
1092 TopoDS_Shape plating;
1095 (
top - bottom ), bottom, aOrigin ) )
1117 double margin = 0.001;
1121 double copperMargin = 0.5;
1123 double start_pos, start_thickness;
1124 double end_pos, end_thickness;
1129 double top = std::max( { start_pos, start_pos + start_thickness,
1130 end_pos, end_pos + end_thickness } );
1131 double bottom = std::min( { start_pos, start_pos + start_thickness,
1132 end_pos, end_pos + end_thickness } );
1135 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1136 top += copperMargin;
1137 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1138 bottom -= copperMargin;
1140 double holeZsize = (
top - bottom ) + ( margin * 2 );
1141 double holeZpos = bottom - margin;
1143 double backdrillDiameter = aShape.
GetWidth();
1145 TopoDS_Shape backdrillHole;
1149 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1166 bool aFrontSide,
const VECTOR2D& aOrigin )
1168 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1169 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1172 if( aDiameter <= 0 || aDepth <= 0 )
1174 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1175 aDiameter, aDepth );
1179 double margin = 0.001;
1182 double copperMargin = 0.5;
1185 double boardZpos, boardThickness;
1189 double f_pos, f_thickness, b_pos, b_thickness;
1196 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1197 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1199 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1200 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1203 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1204 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1205 double radius_mm = diameter_mm / 2.0;
1207 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1208 diameter_mm, depth_mm, radius_mm );
1212 double cylinderZpos;
1213 double cylinderHeight;
1219 cylinderZpos = topOuterSurface - depth_mm - margin;
1220 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1226 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1227 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1231 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1232 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1234 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1235 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1241 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1243 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1245 if( cylinder.IsNull() )
1247 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1248 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1257 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1260 catch(
const Standard_Failure& e )
1262 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1263 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1264 e.GetMessageString() ),
1274 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1276 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1277 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1282 if( aDiameter <= 0 || aAngle <= 0 )
1284 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1285 aDiameter, aAngle );
1289 double margin = 0.001;
1292 double copperMargin = 0.5;
1295 double boardZpos, boardThickness;
1299 double f_pos, f_thickness, b_pos, b_thickness;
1304 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1305 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1307 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1308 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1311 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1312 double radius_mm = diameter_mm / 2.0;
1316 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1324 depth_mm = radius_mm / tan( halfAngleRad );
1325 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1326 depth_mm, radius_mm );
1333 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1334 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1345 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1347 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1348 bottomRadius_mm, tan( halfAngleRad ) );
1350 if( bottomRadius_mm < 0 )
1351 bottomRadius_mm = 0;
1356 double coneHeight = depth_mm + copperMargin + margin;
1360 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1361 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1372 coneZpos = topOuterSurface - depth_mm - margin;
1373 r1 = bottomRadius_mm;
1375 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1377 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1378 coneZpos, r1, r2, coneHeight );
1380 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1381 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1388 coneZpos = bottomOuterSurface - copperMargin - margin;
1390 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1391 r2 = bottomRadius_mm;
1393 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1394 coneZpos, r1, r2, coneHeight );
1396 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1397 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1402 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1403 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1412 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1415 catch(
const Standard_Failure& e )
1417 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1418 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1419 e.GetMessageString() ),
1429 int aAngle,
bool aFrontSide )
1431 std::map<PCB_LAYER_ID, int> knockouts;
1434 double f_pos, f_thickness, b_pos, b_thickness;
1438 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1439 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1442 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1443 double radius_mm = diameter_mm / 2.0;
1447 double halfAngleRad = 0.0;
1452 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1456 depth_mm = radius_mm / tan( halfAngleRad );
1467 double featureTop, featureBottom;
1471 featureTop = topOuterSurface;
1472 featureBottom = topOuterSurface - depth_mm;
1476 featureBottom = bottomOuterSurface;
1477 featureTop = bottomOuterSurface + depth_mm;
1480 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1481 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1490 double layerZ, layerThickness;
1494 double layerTop = std::max( layerZ, layerZ + layerThickness );
1495 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1499 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1501 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1502 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1507 int knockoutDiameter;
1513 double layerSurfaceZ;
1517 layerSurfaceZ = layerTop;
1522 layerSurfaceZ = layerBottom;
1526 double distanceFromSurface;
1528 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1530 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1533 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1535 if( radiusAtLayer_mm <= 0 )
1537 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1538 static_cast<int>( layer ) );
1542 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1543 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1544 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1549 knockoutDiameter = aDiameter;
1550 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1551 static_cast<int>( layer ), knockoutDiameter );
1554 knockouts[layer] = knockoutDiameter;
1562 double& aThickness )
1565 static const double c_silkscreenAboveCopper = 0.04;
1566 static const double c_soldermaskAboveCopper = 0.015;
1574 double f_pos, f_thickness;
1576 double top = std::max( f_pos, f_pos + f_thickness );
1579 aZPos =
top + c_silkscreenAboveCopper;
1581 aZPos =
top + c_soldermaskAboveCopper;
1587 double b_pos, b_thickness;
1589 double bottom = std::min( b_pos, b_pos + b_thickness );
1592 aZPos = bottom - c_silkscreenAboveCopper;
1594 aZPos = bottom - c_soldermaskAboveCopper;
1602 double& aThickness )
1606 bool wasPrepreg =
false;
1608 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1611 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1617 if( aLayer ==
B_Cu )
1662 double f_pos, f_thickness;
1663 double b_pos, b_thickness;
1666 double top = std::min( f_pos, f_pos + f_thickness );
1667 double bottom = std::max( b_pos, b_pos + b_thickness );
1669 aThickness = (
top - bottom );
1672 wxASSERT( aZPos == 0.0 );
1678 const wxString& aRefDes )
1680 double f_pos, f_thickness;
1681 double b_pos, b_thickness;
1685 double boardSurfaceZ;
1688 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1690 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1692 double bodyThickness = aHeight - aStandoff;
1696 zBot = boardSurfaceZ + aStandoff;
1698 zBot = boardSurfaceZ - aHeight;
1708 if( aStandoff <= 0.0 )
1724 double f_pos, f_thickness;
1725 double b_pos, b_thickness;
1729 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1730 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1732 static const double c_protrusion = 1.0;
1734 double pinZBot, pinHeight;
1738 pinZBot = boardBotZ - c_protrusion;
1739 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1743 double pinZTop = boardTopZ + c_protrusion;
1744 pinZBot = boardBotZ - aStandoff;
1745 pinHeight = pinZTop - pinZBot;
1756 const VECTOR2D& aOrigin,
const wxString& aNetname )
1758 bool success =
true;
1766 double z_pos, thickness;
1769 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1777 else if( aLayer ==
F_Mask )
1784 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1797 const std::vector<wxString>& aAltFilenames,
1798 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1800 VECTOR3D aScale,
bool aSubstituteModels )
1802 if( aFileName.empty() )
1804 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1813 wxString errorMessage;
1815 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1818 if( errorMessage.IsEmpty() )
1819 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1826 TopLoc_Location toploc;
1828 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1831 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1837 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1839 if( llabel.IsNull() )
1842 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1848 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1849 TDataStd_Name::Set( llabel, refdes );
1860 m_assy->UpdateAssemblies();
1932 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1933 double aZposition,
const VECTOR2D& aOrigin )
1940 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1941 double h_width = aWidth/2.0;
1943 coords[0] =
VECTOR2D{ 0.0, h_width };
1946 coords[1] =
VECTOR2D{ len, h_width };
1949 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1952 coords[3] =
VECTOR2D{ len, -h_width };
1955 coords[4] =
VECTOR2D{ 0, -h_width };
1958 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1961 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1963 for(
int ii = 0; ii < 6; ii++ )
1966 coords[ii] += aStartPoint;
1971 gp_Pnt coords3D[ 6 ];
1973 for(
int ii = 0; ii < 6; ii++ )
1975 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1976 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1980 BRepBuilderAPI_MakeWire wire;
1981 bool success =
true;
1993 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1998 edge = BRepBuilderAPI_MakeEdge(
circle );
2003 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2006 Handle( Geom_TrimmedCurve ) arcOfCircle =
2007 GC_MakeArcOfCircle( coords3D[1],
2011 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2014 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2017 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2018 GC_MakeArcOfCircle( coords3D[4],
2022 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2026 catch(
const Standard_Failure& e )
2028 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2029 e.GetMessageString() ),
2034 BRepBuilderAPI_MakeFace face;
2038 gp_Pln plane( coords3D[0], gp::DZ() );
2039 face = BRepBuilderAPI_MakeFace( plane, wire );
2041 catch(
const Standard_Failure& e )
2043 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2044 e.GetMessageString() ),
2049 if( aThickness != 0.0 )
2051 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2053 if( aShape.IsNull() )
2055 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2072 double aZposition,
const VECTOR2D& aOrigin )
2074 std::vector<TopoDS_Shape> testShapes;
2077 aHeight, aZposition, aOrigin );
2079 if( testShapes.size() > 0 )
2080 aShape = testShapes.front();
2103 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2107 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2109 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2110 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2120 gp_Pnt start = toPoint( aPt0 );
2121 gp_Pnt
end = toPoint( aPt1 );
2123 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2125 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2127 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2135 aMkWire.Add( mkEdge.Edge() );
2137 if( aMkWire.Error() != BRepLib_WireDone )
2139 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2153 Handle( Geom_Curve ) curve;
2155 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2157 gp_Ax2 axis = gp::XOY();
2158 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2160 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2164 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2165 toPoint( aArc.GetP1() ) ).Value();
2168 if( curve.IsNull() )
2171 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2173 if( !aMkWire.IsDone() )
2175 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2176 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2178 aArc.GetP0().x, aArc.GetP0().y,
2179 aArc.GetArcMid().x, aArc.GetArcMid().y,
2180 aArc.GetP1().x, aArc.GetP1().y ),
2190 bool isFirstShape =
true;
2203 if( nextShape != -1 )
2209 lastPt = aChain.
CPoint( i );
2219 firstPt = currentArc.
GetP0();
2224 lastPt = currentArc.
GetP0();
2226 if( addArc( lastPt, currentArc ) )
2227 lastPt = currentArc.
GetP1();
2246 isFirstShape =
false;
2249 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2251 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2253 firstPt.
x, firstPt.
y ),
2259 catch(
const Standard_Failure& e )
2261 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2262 e.GetMessageString() ),
2272 bool aConvertToArcs,
double aThickness,
double aZposition,
2280 if( aConvertToArcs )
2284 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2288 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2292 fallbackPoly = workingPoly;
2293 workingPoly = approximated;
2312 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2314 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2315 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2319 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2320 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2322 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2326 auto tryMakeWire = [
this, &aZposition,
2327 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2330 BRepLib_MakeWire mkWire;
2334 if( mkWire.IsDone() )
2336 wire = mkWire.Wire();
2341 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2342 "z: %g; bounding box: %s" ),
2343 static_cast<int>( aContour.PointCount() ),
2344 static_cast<int>( mkWire.Error() ),
2349 if( !wire.IsNull() )
2351 BRepAlgoAPI_Check check( wire,
false,
true );
2353 if( !check.IsValid() )
2355 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2356 "z: %g; bounding box: %s" ),
2368 BRepBuilderAPI_MakeFace mkFace;
2370 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2376 bool allow_retry = aConvertToArcs ? true :
false;
2378 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2380 if( aConvertToArcs && wire.IsNull() )
2382 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2386 allow_retry =
false;
2387 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2392 if( !wire.IsNull() )
2394 if( basePlane.Axis().Direction().Z() < 0 )
2397 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2401 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2402 "z: %g; bounding box: %s" ),
2411 if( !wire.IsNull() )
2413 if( basePlane.Axis().Direction().Z() > 0 )
2420 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2421 "z: %g; bounding box: %s" ),
2428 catch(
const Standard_Failure& e )
2430 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2431 static_cast<int>( contId ),
2432 e.GetMessageString() ),
2438 if( mkFace.IsDone() )
2440 TopoDS_Shape faceShape = mkFace.Shape();
2442 if( aThickness != 0.0 )
2444 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2445 aShapes.push_back( prism );
2447 if( prism.IsNull() )
2455 aShapes.push_back( faceShape );
2471 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2472 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2473 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2474 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2475 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2476 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2477 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2478 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2488 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2490 aColorOut =
COLOR4D( aColorStr );
2495 const std::vector<FAB_LAYER_COLOR>& colors =
2502 if( fabColor.GetName() == aColorStr )
2504 aColorOut = fabColor.GetColor( aType );
2526 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2531 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2536 double boardThickness;
2556 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2560 polyset.
Append( contour );
2567 m_reporter->Report(
_(
"OCC error creating main outline." ),
2576 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2588 BRepBndLib::Add( brdShape, brdBndBox );
2591 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2596 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2597 std::vector<Bnd_Box>& holeBoxes )
2601 Bnd_Box brdWithHolesBndBox = brdBndBox;
2603 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2604 holeBoxes.resize( input.size() );
2606 for(
size_t i = 0; i < input.size(); i++ )
2609 BRepBndLib::Add( input[i], bbox );
2610 brdWithHolesBndBox.Add( bbox );
2611 ( *holeBoxSet )[i] = bbox;
2612 holeBoxes[i] = bbox;
2615 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2618 auto subtractShapesMap =
2619 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2620 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2621 const std::vector<Bnd_Box>& aHoleBoxes )
2623 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2626 for(
auto& [netname, vec] : aShapesMap )
2630 auto subtractLoopFn = [&](
const int shapeId )
2632 TopoDS_Shape& shape = vec[shapeId];
2635 BRepBndLib::Add( shape, shapeBbox );
2637 TopTools_ListOfShape holelist;
2640 std::unique_lock lock( mutex );
2642 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2644 for(
const Standard_Integer&
index : indices )
2645 holelist.Append( aHolesList[
index] );
2651 if( holelist.IsEmpty() )
2653 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2655 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2656 holelist.Append( aHolesList[i] );
2661 if( holelist.IsEmpty() )
2664 TopTools_ListOfShape cutArgs;
2665 cutArgs.Append( shape );
2667 BRepAlgoAPI_Cut
cut;
2669 cut.SetRunParallel(
true );
2670 cut.SetToFillHistory(
false );
2672 cut.SetArguments( cutArgs );
2673 cut.SetTools( holelist );
2676 if(
cut.HasErrors() ||
cut.HasWarnings() )
2678 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2685 if(
cut.HasErrors() )
2687 wxString msg =
_(
"Errors:\n" );
2688 wxStringOutputStream os_stream( &msg );
2689 wxStdOutputStream out( os_stream );
2691 cut.DumpErrors( out );
2695 if(
cut.HasWarnings() )
2697 wxString msg =
_(
"Warnings:\n" );
2698 wxStringOutputStream os_stream( &msg );
2699 wxStdOutputStream out( os_stream );
2701 cut.DumpWarnings( out );
2706 shape =
cut.Shape();
2709 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2713 auto subtractShapes =
2714 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2715 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2716 const std::vector<Bnd_Box>& aHoleBoxes )
2718 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2720 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2721 aShapesList = aShapesMap[wxEmptyString];
2727 Bnd_BoundSortBox bsbHoles;
2728 std::vector<Bnd_Box> holeBoxes;
2736 Bnd_BoundSortBox bsbHoles;
2737 std::vector<Bnd_Box> holeBoxes;
2746 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2748 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2749 const std::vector<TopoDS_Shape>& aShapes )
2751 for(
const TopoDS_Shape& shape : aShapes )
2752 shapesToFuseMap[aNetname].Append( shape );
2756 addShapes( netname, shapes );
2759 addShapes( netname, shapes );
2762 addShapes( netname, shapes );
2769 auto fuseLoopFn = [&](
const wxString& aNetname )
2771 auto& toFuse = shapesToFuseMap[aNetname];
2774 if( !fusedShape.IsNull() )
2776 std::unique_lock lock( mutex );
2786 BS::multi_future<void> mf;
2788 for(
const auto& [netname,
_] : shapesToFuseMap )
2789 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2806 auto pushToAssemblyMap =
2807 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2808 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2809 bool aCompoundAll,
const wxString& aNiceName )
2811 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2815 std::vector<TopoDS_Shape> allShapes;
2817 for(
const auto& [netname, shapesList] : aShapesMap )
2818 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2820 if( !allShapes.empty() )
2821 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2825 shapesMap = aShapesMap;
2828 for(
const auto& [netname, shapesList] : shapesMap )
2830 std::vector<TopoDS_Shape> newList;
2835 newList = shapesList;
2839 for( TopoDS_Shape& shape : newList )
2841 Handle( TDataStd_TreeNode ) node;
2844 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2851 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2852 TDF_Label shpLbl = node->Father()->Label();
2854 if( !shpLbl.IsNull() )
2856 if( visMatTool && !aVisMatLabel.IsNull() )
2857 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2863 shapeName << aShapeName;
2865 if( !netname.empty() )
2868 shapeName << netname;
2871 if( newList.size() > 1 )
2877 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2878 TDataStd_Name::Set( shpLbl, partname );
2886 auto pushToAssembly =
2887 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2888 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2890 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2892 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2896 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2897 double aMetallic,
double aRoughness ) -> TDF_Label
2899 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2900 XCAFDoc_VisMaterialPBR pbr;
2901 pbr.BaseColor = aBaseColor;
2902 pbr.Metallic = aMetallic;
2903 pbr.Roughness = aRoughness;
2904 vismat->SetPbrMaterial( pbr );
2905 return visMatTool->AddMaterial( vismat, aName );
2912 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2913 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2914 Quantity_ColorRGBA back_silk_color = front_silk_color;
2915 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2916 Quantity_ColorRGBA back_mask_color = front_mask_color;
2926 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2930 if( item->GetBrdLayerId() ==
F_Mask )
2931 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2933 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2936 if( item->GetBrdLayerId() ==
F_SilkS )
2937 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2938 else if( item->GetBrdLayerId() ==
B_SilkS )
2939 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2942 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2948 board_color = front_mask_color;
2949 board_color.SetAlpha( 1.0 );
2952 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2953 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2954 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2955 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2956 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2957 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2958 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2960 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2964 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2965 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2966 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2967 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2969 if( aPushBoardBody )
2972 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
2973 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
2977 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
2980 TopoDS_Compound asmCompound;
2981 BRep_Builder asmBuilder;
2982 asmBuilder.MakeCompound( asmCompound );
2983 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
2984 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
2986 if( !entry.bodyShapes.empty() )
2988 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
2989 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
2990 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
2991 double a = ( entry.colorKey & 0xFF ) / 255.0;
2993 double metallic, roughness;
2995 switch( entry.material )
3016 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3017 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3019 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3020 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3022 Handle( TDataStd_TreeNode ) bodyNode;
3023 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3024 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3026 if( !bodyShpLbl.IsNull() )
3028 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3029 TDataStd_Name::Set( bodyShpLbl,
3030 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3036 for( TopoDS_Shape& pinShape : entry.pinShapes )
3038 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3040 Handle( TDataStd_TreeNode ) pinNode;
3041 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3042 TDF_Label pinShpLbl = pinNode->Father()->Label();
3044 if( !pinShpLbl.IsNull() )
3046 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3047 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3048 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3052 TopLoc_Location loc;
3053 TDF_Label fpCompLbl = m_assy->AddComponent(
m_assy_label, fpLabel, loc );
3054 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3059#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3060 m_assy->UpdateAssemblies();
3069bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3073 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3081 wxFileName fn( aFileName );
3082 IGESControl_Controller::Init();
3083 IGESCAFControl_Writer writer;
3084 writer.SetColorMode( Standard_True );
3085 writer.SetNameMode( Standard_True );
3086 IGESData_GlobalSection
header = writer.Model()->GlobalSection();
3087 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3088 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3089 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3090 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3091 writer.Model()->SetGlobalSection(
header );
3093 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
3102 wxFileInputStream input( inputFile );
3103 wxFileOutputStream
output( outputFile );
3107 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3113 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3117 wxZlibOutputStream zlibStream(
output, -1, wxZLIB_GZIP );
3119 if( !zlibStream.IsOk() )
3121 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3125 input.Read( zlibStream );
3127 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3129 m_reporter->Report(
_(
"Compress read or write error" ) );
3143 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3151 wxFileName fn( aFileName );
3153 STEPCAFControl_Writer writer;
3154 writer.SetColorMode( Standard_True );
3155 writer.SetNameMode( Standard_True );
3162 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3164 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3170 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3172 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3176 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
3179 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3183 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3186 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3187 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3188 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3189 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3191 bool success =
true;
3194 wxString currCWD = wxGetCwd();
3195 wxString workCWD = fn.GetPath();
3197 if( !workCWD.IsEmpty() )
3198 wxSetWorkingDirectory( workCWD );
3200 wxString tmpfname(
"$tempfile$.step" );
3202 if( Standard_False == writer.Write( tmpfname.c_str() ) )
3205 if( compress && success )
3207 wxString srcTmp( tmpfname );
3208 wxString dstTmp(
"$tempfile$.stpz" );
3211 wxRemoveFile( srcTmp );
3222 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3224 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3232 wxSetWorkingDirectory( currCWD );
3242 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3251 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3256 wxFileName fn( aFileName );
3258 wxFFileOutputStream ffStream( fn.GetFullPath() );
3259 wxStdOutputStream stdStream( ffStream );
3261#if OCC_VERSION_HEX >= 0x070600
3262 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3264 BRepTools::Write( shape, stdStream );
3273 wxFileName fn( aFileName );
3275 wxFFileOutputStream ffStream( fn.GetFullPath() );
3276 wxStdOutputStream file( ffStream );
3278 if( !ffStream.IsOk() )
3280 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3288 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3293 std::map<wxString, std::vector<int>> groups[4];
3294 std::map<wxString, double> groupAreas;
3295 TopExp_Explorer exp;
3298 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3300 TopoDS_Shape subShape = exp.Current();
3303 BRepBndLib::Add( subShape, bbox );
3307 for(
const auto& pair : pairs )
3309 const auto& [point, padTestShape] = pair;
3311 if( bbox.IsOut( point ) )
3314 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3316 if( surface.GetType() != GeomAbs_Plane )
3319 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3322 if( !dist.IsDone() )
3325 if( dist.Value() < Precision::Approximation() )
3328 groups[2][padKey].push_back( faceIndex );
3330 GProp_GProps system;
3331 BRepGProp::SurfaceProperties( subShape, system );
3333 double surfaceArea = system.Mass() / 1e6;
3334 groupAreas[padKey] += surfaceArea;
3343 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3344 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3345 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3346 file <<
" <shape format=\"BREP\"><![CDATA[";
3347#if OCC_VERSION_HEX < 0x070600
3348 BRepTools::Write( shape, file );
3350 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
3352 file <<
"]]></shape>" << std::endl;
3353 file <<
" <topology>" << std::endl;
3355 TopTools_IndexedMapOfShape mainMap;
3356 TopExp::MapShapes( shape, mainMap );
3357 std::set<int> topo[4];
3359 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3362 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3363 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3365 for(
int dim = 0; dim < 4; dim++ )
3367 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3369 TopoDS_Shape subShape = exp.Current();
3370 int idx = mainMap.FindIndex( subShape );
3372 if( idx && !topo[dim].count( idx ) )
3373 topo[dim].insert( idx );
3377 for(
int dim = 0; dim <= 3; dim++ )
3379 std::string labels = c_dimLabels[dim];
3380 std::string label = c_dimLabel[dim];
3382 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3385 for(
auto p : topo[dim] )
3387 std::string
name(
"" );
3388 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3389 <<
"name=\"" <<
name <<
"\" "
3390 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3394 file <<
" </" << labels <<
">" << std::endl;
3397 file <<
" </topology>" << std::endl;
3398 file <<
" </geometry>" << std::endl;
3399 file <<
" <groups count=\""
3400 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3403 int groupNumber = 1;
3408 for(
int dim = 0; dim <= 3; dim++ )
3410 std::string label = c_dimLabel[dim];
3412 for(
auto g : groups[dim] )
3415 wxString
name = g.first;
3419 std::ostringstream gs;
3420 gs <<
"G_" << dim <<
"D_" << g.first;
3423 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3429 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3431 for(
auto index : g.second )
3432 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3434 file <<
" </group>" << std::endl;
3436 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3448 file <<
" </groups>" << std::endl;
3449 file <<
" <fields count=\"0\"/>" << std::endl;
3450 file <<
"</XAO>" << std::endl;
3457 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3458 TDF_Label& aLabel,
bool aSubstituteModels,
3459 wxString* aErrorMessage )
3461 std::string fileNameUTF8 = aFileName.utf8_string();
3463 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3464 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3466 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3470 aLabel = mm->second;
3476 Handle( TDocStd_Document ) doc;
3477 m_app->NewDocument(
"MDTV-XCAF", doc );
3480 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3485 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3487 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3495 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3497 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3508 wxFFileInputStream ifile( aFileName );
3509 wxFileName outFile( aFileName );
3511 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3512 outFile.SetExt( wxT(
"step" ) );
3513 wxFileOffset size = ifile.GetLength();
3515 if( size == wxInvalidOffset )
3517 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3524 bool success =
false;
3527 wxFFileOutputStream ofile( outFile.GetFullPath() );
3532 char* buffer =
new char[size];
3534 ifile.Read( buffer, size );
3535 std::string expanded;
3539 expanded = gzip::decompress( buffer, size );
3547 if( expanded.empty() )
3551 wxZipInputStream izipfile( ifile );
3552 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3554 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3556 izipfile.Read( ofile );
3561 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3567 ofile.Write( expanded.data(), expanded.size() );
3575 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3576 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3595 if( aSubstituteModels )
3597 wxFileName wrlName( aFileName );
3599 wxString basePath = wrlName.GetPath();
3600 wxString baseName = wrlName.GetName();
3608 alts.Add( wxT(
"stp" ) );
3609 alts.Add( wxT(
"step" ) );
3610 alts.Add( wxT(
"STP" ) );
3611 alts.Add( wxT(
"STEP" ) );
3612 alts.Add( wxT(
"Stp" ) );
3613 alts.Add( wxT(
"Step" ) );
3614 alts.Add( wxT(
"stpz" ) );
3615 alts.Add( wxT(
"stpZ" ) );
3616 alts.Add( wxT(
"STPZ" ) );
3617 alts.Add( wxT(
"step.gz" ) );
3618 alts.Add( wxT(
"stp.gz" ) );
3621 alts.Add( wxT(
"iges" ) );
3622 alts.Add( wxT(
"IGES" ) );
3623 alts.Add( wxT(
"igs" ) );
3624 alts.Add( wxT(
"IGS" ) );
3628 for(
const auto& altExt : alts )
3632 if( !aAltFilenames.empty() )
3634 for(
const wxString& altPath : aAltFilenames )
3636 wxFileName iterFn( altPath );
3638 if( iterFn.GetExt() == altExt )
3647 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3650 if( altFile.IsOk() && altFile.FileExists() )
3660 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3674 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3676 Handle( XCAFDoc_ShapeTool ) shapeTool =
3677 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3684 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3694 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3704 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3711 if( aLabel.IsNull() )
3713 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3720 TDataStd_Name::Set( aLabel, partname );
3730 TopLoc_Location& aLocation )
3744 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3750 double boardThickness;
3753 double top = std::max( boardZPos, boardZPos + boardThickness );
3754 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3759 double f_pos, f_thickness;
3763 bottom += f_thickness;
3770 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3771 lPos.Multiply( lRot );
3772 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3773 lPos.Multiply( lRot );
3778 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3779 lPos.Multiply( lRot );
3783 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3784 lPos.Multiply( lOff );
3787 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3788 lPos.Multiply( lOrient );
3789 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3790 lPos.Multiply( lOrient );
3791 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3792 lPos.Multiply( lOrient );
3794 aLocation = TopLoc_Location( lPos );
3801 IGESControl_Controller::Init();
3802 IGESCAFControl_Reader reader;
3803 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3805 if( stat != IFSelect_RetDone )
3809 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3813 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3817 reader.SetColorMode(
true );
3818 reader.SetNameMode(
false );
3819 reader.SetLayerMode(
false );
3821 if( !reader.Transfer( doc ) )
3823 if( doc->CanClose() == CDM_CCS_OK )
3830 if( reader.NbShapes() < 1 )
3832 if( doc->CanClose() == CDM_CCS_OK )
3844 STEPCAFControl_Reader reader;
3845 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3847 if( stat != IFSelect_RetDone )
3851 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3855 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3859 reader.SetColorMode(
true );
3860 reader.SetNameMode(
true );
3861 reader.SetLayerMode(
false );
3863 if( !reader.Transfer( doc ) )
3865 if( doc->CanClose() == CDM_CCS_OK )
3872 if( reader.NbRootsForTransfer() < 1 )
3874 if( doc->CanClose() == CDM_CCS_OK )
3886#if OCC_VERSION_HEX >= 0x070700
3887 VrmlAPI_CafReader reader;
3888 RWMesh_CoordinateSystemConverter conv;
3889 conv.SetInputLengthUnit( 2.54 );
3890 reader.SetCoordinateSystemConverter( conv );
3891 reader.SetDocument( doc );
3893 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3906 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3908 TDF_LabelSequence frshapes;
3909 s_assy->GetFreeShapes( frshapes );
3911 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3920 TDF_Label d_targetLabel = d_assy->NewShape();
3922 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel, Standard_False ) )
3928 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3931 return d_targetLabel;
3937 TDF_LabelSequence freeShapes;
3938 aShapeTool->GetFreeShapes( freeShapes );
3944 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3946 TDF_Label label = freeShapes.Value( i );
3948 aShapeTool->GetShape( label, shape );
3953 const Standard_Real linearDeflection = 0.14;
3954 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3955 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3977 wxFileName fn( aFileName );
3979 const char* tmpGltfname =
"$tempfile$.glb";
3980 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3982 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3983 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3984 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3985 RWMesh_CoordinateSystem_Zup );
3986#if OCC_VERSION_HEX >= 0x070700
3987 cafWriter.SetParallel(
true );
3989 TColStd_IndexedDataMapOfStringString metadata;
3991 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3992 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3993 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3994 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3995 metadata.Add( TCollection_AsciiString(
"generator" ),
3996 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3997 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4000 bool success =
true;
4003 wxString currCWD = wxGetCwd();
4004 wxString workCWD = fn.GetPath();
4006 if( !workCWD.IsEmpty() )
4007 wxSetWorkingDirectory( workCWD );
4009 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4016 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4018 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4026 wxSetWorkingDirectory( currCWD );
4034#if OCC_VERSION_HEX < 0x070700
4041 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4051 wxFileName fn( aFileName );
4053 const char* tmpFname =
"$tempfile$.ply";
4054 RWPly_CafWriter cafWriter( tmpFname );
4056 cafWriter.SetFaceId(
true );
4057 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4058 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4060 TColStd_IndexedDataMapOfStringString metadata;
4062 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4063 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4064 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4065 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4066 metadata.Add( TCollection_AsciiString(
"generator" ),
4067 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4069 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4072 bool success =
true;
4075 wxString currCWD = wxGetCwd();
4076 wxString workCWD = fn.GetPath();
4078 if( !workCWD.IsEmpty() )
4079 wxSetWorkingDirectory( workCWD );
4081 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4088 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4090 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4098 wxSetWorkingDirectory( currCWD );
4109 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4119 wxFileName fn( aFileName );
4121 const char* tmpFname =
"$tempfile$.stl";
4124 wxString currCWD = wxGetCwd();
4125 wxString workCWD = fn.GetPath();
4127 if( !workCWD.IsEmpty() )
4128 wxSetWorkingDirectory( workCWD );
4130 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4137 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4139 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4147 wxSetWorkingDirectory( currCWD );
4159 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4168 wxFileName fn( aFileName );
4170 const char* tmpFname =
"$tempfile$.u3d";
4173 wxString currCWD = wxGetCwd();
4174 wxString workCWD = fn.GetPath();
4176 if( !workCWD.IsEmpty() )
4177 wxSetWorkingDirectory( workCWD );
4180 bool success = writer.
Perform( m_doc );
4186 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4188 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4195 wxSetWorkingDirectory( currCWD );
4206 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4215 wxFileName fn( aFileName );
4217 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4218 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4220 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4221 bool success = writer.
Perform( m_doc );
4224 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4226 plotter->SetColorMode(
true );
4227 plotter->Set3DExport(
true );
4228 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4230 plotter->SetRenderSettings( &renderSettings );
4232 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4234 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4240 plotter->StartPlot(
"1",
"3D Model" );
4241 double fov_degrees = 16.5f;
4246 std::vector<PDF_3D_VIEW> views;
4251 std::vector<float> c2wMatrix =
4255 .m_name =
"Default",
4256 .m_cameraMatrix = c2wMatrix,
4257 .m_cameraCenter = (float)
distance,
4258 .m_fov = (
float) fov_degrees,
4267 .m_cameraMatrix = c2wMatrix,
4268 .m_cameraCenter = (float)
distance,
4269 .m_fov = (
float) fov_degrees,
4278 .m_cameraMatrix = c2wMatrix,
4279 .m_cameraCenter = (float)
distance,
4280 .m_fov = (
float) fov_degrees,
4289 .m_cameraMatrix = c2wMatrix,
4290 .m_cameraCenter = (float)
distance,
4291 .m_fov = (
float) fov_degrees,
4294 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4303 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4305 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4306 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4312 wxRemoveFile( u3dTmpfn.GetFullPath() );
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
bool GetExtrusionPinOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly)
Get the pin outline polygons for extruded THT pin rendering.
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetNetname() const
const wxString & GetShortNetname() const
FOOTPRINT * GetParentFootprint() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
PCB specific render settings.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
PAD_PROP GetProperty() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
const VECTOR2I & GetArcMid() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
const std::optional< INTERSECTION > SelfIntersectingWithArcs() const
Check if the line chain is self-intersecting.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
virtual size_t GetSegmentCount() const override
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int FullPointCount() const
Return the number of points in the shape poly set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
const POLYGON & CPolygon(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
const SEG & GetSeg() const
int GetWidth() const override
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
OUTPUT_FORMAT m_outFmt
The current output format for created file.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
bool WritePLY(const wxString &aFileName)
bool AddCountersink(const VECTOR2I &aPosition, int aDiameter, int aDepth, int aAngle, bool aFrontSide, const VECTOR2D &aOrigin)
Add a countersink shape to remove board material from the top or bottom of a hole.
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_vias
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_pads
bool WriteSTEP(const wxString &aFileName, bool aOptimize, bool compress)
std::vector< TopoDS_Shape > m_board_back_mask
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
std::vector< TopoDS_Shape > m_boardCutouts
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
bool CreatePCB(SHAPE_POLY_SET &aOutline, const VECTOR2D &aOrigin, bool aPushBoardBody)
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, const VECTOR3D &aScale)
bool getModelLocation(bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, TopLoc_Location &aLocation)
void SetFuseShapes(bool aValue)
bool WriteXAO(const wxString &aFileName)
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
std::vector< TDF_Label > m_pcb_labels
STEP_PCB_MODEL(const wxString &aPcbName, REPORTER *aReporter)
std::vector< EXTRUDED_BODY_ENTRY > m_extruded_bodies
bool AddBackdrill(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerStart, PCB_LAYER_ID aLayerEnd, const VECTOR2D &aOrigin)
Add a backdrill hole shape to remove board material and copper plating.
void getLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_outlines
void SetSimplifyShapes(bool aValue)
bool WriteU3D(const wxString &aFileName)
bool getModelLabel(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
bool AddCounterbore(const VECTOR2I &aPosition, int aDiameter, int aDepth, bool aFrontSide, const VECTOR2D &aOrigin)
Add a counterbore shape to remove board material from the top or bottom of a hole.
void SetEnabledLayers(const LSET &aLayers)
void SetExtraPadThickness(bool aValue)
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
std::vector< TopoDS_Shape > m_board_front_silk
bool AddExtrudedPins(const FOOTPRINT *aFootprint, bool aBottom, double aStandoff, const VECTOR2D &aOrigin)
Add metallic pin extrusions for through-hole pads.
Handle(XCAFApp_Application) m_app
bool WritePDF(const wxString &aFileName)
virtual ~STEP_PCB_MODEL()
std::vector< TopoDS_Shape > m_board_front_mask
bool WriteSTL(const wxString &aFileName)
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
std::map< PCB_LAYER_ID, int > GetCopperLayerKnockouts(int aDiameter, int aDepth, int aAngle, bool aFrontSide)
Get the knockout diameters for copper layers that a counterbore or countersink crosses.
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
std::vector< TopoDS_Shape > m_copperCutouts
bool CompressSTEP(wxString &inputFile, wxString &outputFile)
std::vector< TopoDS_Shape > m_board_back_silk
void getCopperLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
bool AddComponent(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, const wxString &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
bool AddExtrudedBody(const SHAPE_POLY_SET &aOutline, bool aBottom, double aStandoff, double aHeight, const VECTOR2D &aOrigin, uint32_t aColor, EXTRUSION_MATERIAL aMaterial, const wxString &aRefDes)
Add an extruded 3D body from a 2D outline polygon.
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
bool Perform(const Handle(TDocStd_Document) &aDocument)
const VECTOR3D & GetCenter() const
const Bnd_Box & GetMeshBoundingBox() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
Handle(KICAD3D_INFO) KICAD3D_INFO
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static TopoDS_Shape fuseShapesOrCompound(const TopTools_ListOfShape &aInputShapes, REPORTER *aReporter)
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 Standard_Boolean prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static Standard_Boolean rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
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
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 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