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 <NCollection_Sequence.hxx>
92#include <TColStd_IndexedDataMapOfStringString.hxx>
93#include <TDF_Tool.hxx>
94#include <TopTools_IndexedMapOfShape.hxx>
95#include <TopExp_Explorer.hxx>
97#include <XCAFApp_Application.hxx>
99#include <XCAFDoc_DocumentTool.hxx>
100#include <XCAFDoc_ColorTool.hxx>
101#include <XCAFDoc_ShapeTool.hxx>
102#include <XCAFDoc_VisMaterialTool.hxx>
103#include <XCAFDoc_Area.hxx>
104#include <XCAFDoc_Centroid.hxx>
105#include <XCAFDoc_Editor.hxx>
106#include <XCAFDoc_Location.hxx>
107#include <XCAFDoc_Volume.hxx>
110#include "KI_XCAFDoc_AssemblyGraph.hxx"
112#include <BRep_Tool.hxx>
113#include <BRepMesh_IncrementalMesh.hxx>
114#include <BRepBuilderAPI_GTransform.hxx>
115#include <BRepBuilderAPI_MakeEdge.hxx>
116#include <BRepBuilderAPI_MakeWire.hxx>
117#include <BRepBuilderAPI_MakeFace.hxx>
118#include <BRepExtrema_DistShapeShape.hxx>
119#include <BRepPrimAPI_MakeCone.hxx>
120#include <BRepPrimAPI_MakeCylinder.hxx>
121#include <BRepPrimAPI_MakePrism.hxx>
122#include <BRepTools.hxx>
123#include <BRepLib_MakeWire.hxx>
124#include <BRepAdaptor_Surface.hxx>
125#include <BRepAlgoAPI_Check.hxx>
126#include <BRepAlgoAPI_Cut.hxx>
127#include <BRepAlgoAPI_Fuse.hxx>
128#include <ShapeUpgrade_UnifySameDomain.hxx>
130#include <BRepBndLib.hxx>
131#include <Bnd_BoundSortBox.hxx>
132#include <Bnd_HArray1OfBox.hxx>
133#include <GProp_GProps.hxx>
134#include <BRepGProp.hxx>
136#include <Geom_Curve.hxx>
137#include <Geom_TrimmedCurve.hxx>
142#include <GC_MakeArcOfCircle.hxx>
143#include <GC_MakeCircle.hxx>
145#include <RWGltf_CafWriter.hxx>
146#include <StlAPI_Writer.hxx>
148#if OCC_VERSION_HEX >= 0x070700
149#include <VrmlAPI_CafReader.hxx>
150#include <RWPly_CafWriter.hxx>
178 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
180 if( !lfile.FileExists() )
183 wxString ext = lfile.GetExt().Lower();
185 if( ext == wxT(
"wrl" ) )
188 if( ext == wxT(
"wrz" ) )
191 if( ext == wxT(
"idf" ) )
194 if( ext == wxT(
"emn" ) )
197 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
211 const int max_line_count = 3;
213 for(
int ii = 0; ii < max_line_count; ii++ )
215 memset( iline, 0, 82 );
216 ifile.getline( iline, 82 );
222 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
228 std::string fstr = iline;
232 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
241 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
248 if( strncmp( iline,
"/*", 2 ) != 0 )
266 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
267 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
268 double det = -b.
x * d.
y + d.
x * b.
y;
272 center.x = ( -bc * d.
y - cd * b.
y ) * det;
273 center.y = ( b.
x * cd + d.
x * bc ) * det;
280#define APPROX_DBG( stmt )
288 static const double c_radiusDeviation = 1000.0;
289 static const double c_arcCenterDeviation = 1000.0;
290 static const double c_relLengthDeviation = 0.8;
291 static const int c_last_none = -1000;
293 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
294 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
311 int last = c_last_none;
317 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
319 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
324 bool defective =
false;
330 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
338 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
339 defective |=
std::abs( a_diff ) < 0.1;
342 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
343 defective |=
std::abs( a_diff ) >= maxAngleDiff;
354 for(
int j = i; j <= jEndIdx; j++ )
359 double rad_test = ( p_test -
center ).EuclideanNorm();
360 double d_tl = ( p_test - p_prev ).EuclideanNorm();
364 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
367 if( rad_dev > c_radiusDeviation )
370 <<
" Radius deviation too large: " << int64_t( rad_dev )
371 <<
" > " << c_radiusDeviation << std::endl );
376 double maxAngleDiff =
377 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
379 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
380 if(
std::abs( a_diff_test ) >= maxAngleDiff )
382 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
387 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
389 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
390 <<
"; " << d01 << std::endl );
400 if( last != c_last_none )
409 int toRemove = last - ( aSrc.
PointCount() - 3 );
439 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
443 if( last == c_last_none )
460 if( iarc0 != -1 && iarc1 != -1 )
462 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
472 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
490 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
491 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
509 NCollection_Sequence<TDF_Label> theLabels;
510 aShapeTool->GetFreeShapes( theLabels );
514 if( theLabels.Length() == 1 )
515 return aShapeTool->GetShape( theLabels.Value( 1 ) );
517 TopoDS_Compound aCompound;
518 BRep_Builder aBuilder;
519 aBuilder.MakeCompound( aCompound );
521 for( NCollection_Sequence<TDF_Label>::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
523 TopoDS_Shape aFreeShape;
525 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
528 aBuilder.Add( aCompound, aFreeShape );
531 if( aCompound.NbChildren() > 0 )
542 if( theLabel.IsNull() )
544 Message::SendFail(
"Null label." );
548 if(
std::abs( aScale.X() ) <= gp::Resolution() ||
std::abs( aScale.Y() ) <= gp::Resolution()
549 ||
std::abs( aScale.Z() ) <= gp::Resolution() )
551 Message::SendFail(
"Scale factor is too small." );
555 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
557 if( aShapeTool.IsNull() )
559 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
563 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
567 Message::SendFail(
"Couldn't create assembly graph." );
571 bool anIsDone =
true;
575 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
577 0, 0, aScale.Z() ) );
580 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
582 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
584 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
586 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
587 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
592 const TDF_Label& aLabel = aG->GetNode( idx );
594 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
596 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
597 aBRepTrsf.Perform( aShape,
true );
598 if( !aBRepTrsf.IsDone() )
600 Standard_SStream aSS;
601 TCollection_AsciiString anEntry;
602 TDF_Tool::Entry( aLabel, anEntry );
603 aSS <<
"Shape " << anEntry <<
" is not scaled!";
604 Message::SendFail( aSS.str().c_str() );
608 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
609 aShapeTool->SetShape( aLabel, aScaledShape );
612 NCollection_Sequence<TDF_Label> aSubshapes;
613 aShapeTool->GetSubShapes( aLabel, aSubshapes );
614 for( NCollection_Sequence<TDF_Label>::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
616 const TDF_Label& aLSs = anItSs.Value();
617 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
618 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
619 aShapeTool->SetShape( aLSs, aSs1 );
623 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
624 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
625 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
627 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
629 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
630 gp_Trsf aTrsf = aLoc.Transformation();
631 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
632 XCAFDoc_Location::Set( aLabel, aTrsf );
641 aShapeTool->UpdateAssemblies();
649 BRepAlgoAPI_Fuse mkFuse;
650 NCollection_List<TopoDS_Shape> shapeArguments, shapeTools;
652 for(
const TopoDS_Shape& sh : aInputShapes )
657 if( shapeArguments.IsEmpty() )
658 shapeArguments.Append( sh );
660 shapeTools.Append( sh );
665 mkFuse.SetRunParallel(
true );
666 mkFuse.SetToFillHistory(
false );
667 mkFuse.SetArguments( shapeArguments );
668 mkFuse.SetTools( shapeTools );
671 catch(
const std::bad_alloc& )
673 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
674 "reducing the number of objects (e.g., vias), or freeing system memory." ),
678 catch(
const Standard_Failure& e )
680 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
681 "This may indicate insufficient memory. Consider "
682 "disabling shape fusing or reducing board complexity." ),
683 e.GetMessageString() ),
688 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
690 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
691 "memory-intensive; insufficient memory may cause failures." ),
694 if( mkFuse.HasErrors() )
696 wxString msg =
_(
"Errors:\n" );
697 wxStringOutputStream os_stream( &msg );
698 wxStdOutputStream out( os_stream );
700 mkFuse.DumpErrors( out );
704 if( mkFuse.HasWarnings() )
706 wxString msg =
_(
"Warnings:\n" );
707 wxStringOutputStream os_stream( &msg );
708 wxStdOutputStream out( os_stream );
710 mkFuse.DumpWarnings( out );
715 if( mkFuse.IsDone() )
717 TopoDS_Shape fusedShape = mkFuse.Shape();
721 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
722 unify.History() =
nullptr;
725 TopoDS_Shape unifiedShapes = unify.Shape();
727 if( unifiedShapes.IsNull() )
729 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
734 aOutShape = unifiedShapes;
738 catch(
const std::bad_alloc& )
740 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
741 "shape fusing or reducing the number of objects." ),
745 catch(
const Standard_Failure& e )
747 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
748 e.GetMessageString() ),
760 TopoDS_Compound compound;
761 BRep_Builder builder;
762 builder.MakeCompound( compound );
764 for(
const TopoDS_Shape& shape : aInputShapes )
765 builder.Add( compound, shape );
774 TopoDS_Shape outShape;
776 if( aInputShapes.Size() == 1 )
777 return aInputShapes.First();
779 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
788 const TCollection_ExtendedString& aPrefix )
790 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
794 Message::SendFail(
"Couldn't create assembly graph." );
798 bool anIsDone =
true;
800 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
802 const TDF_Label& lbl = aG->GetNode( idx );
803 Handle( TDataStd_Name ) nameHandle;
805 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
807 TCollection_ExtendedString
name;
811 name += nameHandle->Get();
814 TDataStd_Name::Set( lbl,
name );
818 TDataStd_Name::Set( lbl, aPrefix );
829 m_app = XCAFApp_Application::GetApplication();
830 m_app->NewDocument(
"MDTV-XCAF", m_doc );
831 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
849 if( m_doc->CanClose() == CDM_CCS_OK )
857 const double c_padExtraThickness = 0.005;
859 std::vector<TopoDS_Shape> padShapes;
873 double Zpos, thickness;
879 if( pcb_layer ==
F_Cu )
880 thickness += c_padExtraThickness;
881 else if( pcb_layer ==
B_Cu )
882 thickness -= c_padExtraThickness;
885 TopoDS_Shape testShape;
899 if( testShape.IsNull() )
901 std::vector<TopoDS_Shape> testShapes;
905 if( testShapes.size() > 0 )
906 testShape = testShapes.front();
911 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
917 if( pcb_layer ==
F_Cu )
919 else if( pcb_layer ==
B_Cu )
935 double f_pos, f_thickness;
936 double b_pos, b_thickness;
943 f_thickness += c_padExtraThickness;
944 b_thickness -= c_padExtraThickness;
947 double top = std::max( f_pos, f_pos + f_thickness );
948 double bottom = std::min( b_pos, b_pos + b_thickness );
949 double hole_height =
top - bottom;
951 TopoDS_Shape plating;
959 hole_height, bottom, aOrigin ) )
961 padShapes.push_back( plating );
975 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
992 padShapes.push_back( plating );
1004 if( !padShapes.empty() )
1009 NCollection_List<TopoDS_Shape> padShapesList;
1011 for(
const TopoDS_Shape& shape : padShapes )
1012 padShapesList.Append( shape );
1018 for(
const TopoDS_Shape& shape : padShapes )
1029 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1031 double margin = 0.001;
1039 double f_pos, f_thickness;
1040 double b_pos, b_thickness;
1043 double top = std::max( f_pos, f_pos + f_thickness );
1044 double bottom = std::min( b_pos, b_pos + b_thickness );
1046 double holeZsize = (
top - bottom ) + ( margin * 2 );
1048 double boardDrill = aShape.
GetWidth();
1049 double copperDrill = boardDrill - aPlatingThickness * 2;
1051 TopoDS_Shape copperHole, boardHole;
1056 holeZsize, bottom - margin, aOrigin ) )
1069 holeZsize, bottom - margin, aOrigin ) )
1085 const wxString& aNetname )
1087 double f_pos, f_thickness;
1088 double b_pos, b_thickness;
1091 double top = std::max( f_pos, f_pos + f_thickness );
1092 double bottom = std::min( b_pos, b_pos + b_thickness );
1094 TopoDS_Shape plating;
1097 (
top - bottom ), bottom, aOrigin ) )
1119 double margin = 0.001;
1123 double copperMargin = 0.5;
1125 double start_pos, start_thickness;
1126 double end_pos, end_thickness;
1131 double top = std::max( { start_pos, start_pos + start_thickness,
1132 end_pos, end_pos + end_thickness } );
1133 double bottom = std::min( { start_pos, start_pos + start_thickness,
1134 end_pos, end_pos + end_thickness } );
1137 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1138 top += copperMargin;
1139 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1140 bottom -= copperMargin;
1142 double holeZsize = (
top - bottom ) + ( margin * 2 );
1143 double holeZpos = bottom - margin;
1145 double backdrillDiameter = aShape.
GetWidth();
1147 TopoDS_Shape backdrillHole;
1151 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1168 bool aFrontSide,
const VECTOR2D& aOrigin )
1170 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1171 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1174 if( aDiameter <= 0 || aDepth <= 0 )
1176 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1177 aDiameter, aDepth );
1181 double margin = 0.001;
1184 double copperMargin = 0.5;
1187 double boardZpos, boardThickness;
1191 double f_pos, f_thickness, b_pos, b_thickness;
1198 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1199 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1201 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1202 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1205 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1206 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1207 double radius_mm = diameter_mm / 2.0;
1209 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1210 diameter_mm, depth_mm, radius_mm );
1214 double cylinderZpos;
1215 double cylinderHeight;
1221 cylinderZpos = topOuterSurface - depth_mm - margin;
1222 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1228 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1229 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1233 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1234 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1236 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1237 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1243 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1245 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1247 if( cylinder.IsNull() )
1249 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1250 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1259 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1262 catch(
const Standard_Failure& e )
1264 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1265 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1266 e.GetMessageString() ),
1276 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1278 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1279 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1284 if( aDiameter <= 0 || aAngle <= 0 )
1286 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1287 aDiameter, aAngle );
1291 double margin = 0.001;
1294 double copperMargin = 0.5;
1297 double boardZpos, boardThickness;
1301 double f_pos, f_thickness, b_pos, b_thickness;
1306 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1307 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1309 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1310 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1313 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1314 double radius_mm = diameter_mm / 2.0;
1318 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1326 depth_mm = radius_mm / tan( halfAngleRad );
1327 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1328 depth_mm, radius_mm );
1335 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1336 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1347 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1349 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1350 bottomRadius_mm, tan( halfAngleRad ) );
1352 if( bottomRadius_mm < 0 )
1353 bottomRadius_mm = 0;
1358 double coneHeight = depth_mm + copperMargin + margin;
1362 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1363 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1374 coneZpos = topOuterSurface - depth_mm - margin;
1375 r1 = bottomRadius_mm;
1377 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1379 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1380 coneZpos, r1, r2, coneHeight );
1382 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1383 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1390 coneZpos = bottomOuterSurface - copperMargin - margin;
1392 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1393 r2 = bottomRadius_mm;
1395 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1396 coneZpos, r1, r2, coneHeight );
1398 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1399 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1404 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1405 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1414 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1417 catch(
const Standard_Failure& e )
1419 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1420 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1421 e.GetMessageString() ),
1431 int aAngle,
bool aFrontSide )
1433 std::map<PCB_LAYER_ID, int> knockouts;
1436 double f_pos, f_thickness, b_pos, b_thickness;
1440 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1441 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1444 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1445 double radius_mm = diameter_mm / 2.0;
1449 double halfAngleRad = 0.0;
1454 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1458 depth_mm = radius_mm / tan( halfAngleRad );
1469 double featureTop, featureBottom;
1473 featureTop = topOuterSurface;
1474 featureBottom = topOuterSurface - depth_mm;
1478 featureBottom = bottomOuterSurface;
1479 featureTop = bottomOuterSurface + depth_mm;
1482 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1483 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1492 double layerZ, layerThickness;
1496 double layerTop = std::max( layerZ, layerZ + layerThickness );
1497 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1501 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1503 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1504 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1509 int knockoutDiameter;
1515 double layerSurfaceZ;
1519 layerSurfaceZ = layerTop;
1524 layerSurfaceZ = layerBottom;
1528 double distanceFromSurface;
1530 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1532 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1535 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1537 if( radiusAtLayer_mm <= 0 )
1539 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1540 static_cast<int>( layer ) );
1544 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1545 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1546 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1551 knockoutDiameter = aDiameter;
1552 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1553 static_cast<int>( layer ), knockoutDiameter );
1556 knockouts[layer] = knockoutDiameter;
1564 double& aThickness )
1567 static const double c_silkscreenAboveCopper = 0.04;
1568 static const double c_soldermaskAboveCopper = 0.015;
1576 double f_pos, f_thickness;
1578 double top = std::max( f_pos, f_pos + f_thickness );
1581 aZPos =
top + c_silkscreenAboveCopper;
1583 aZPos =
top + c_soldermaskAboveCopper;
1589 double b_pos, b_thickness;
1591 double bottom = std::min( b_pos, b_pos + b_thickness );
1594 aZPos = bottom - c_silkscreenAboveCopper;
1596 aZPos = bottom - c_soldermaskAboveCopper;
1604 double& aThickness )
1608 bool wasPrepreg =
false;
1610 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1613 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1619 if( aLayer ==
B_Cu )
1664 double f_pos, f_thickness;
1665 double b_pos, b_thickness;
1668 double top = std::min( f_pos, f_pos + f_thickness );
1669 double bottom = std::max( b_pos, b_pos + b_thickness );
1671 aThickness = (
top - bottom );
1674 wxASSERT( aZPos == 0.0 );
1680 const wxString& aRefDes )
1682 double f_pos, f_thickness;
1683 double b_pos, b_thickness;
1687 double boardSurfaceZ;
1690 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1692 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1694 double bodyThickness = aHeight - aStandoff;
1698 zBot = boardSurfaceZ + aStandoff;
1700 zBot = boardSurfaceZ - aHeight;
1710 if( aStandoff <= 0.0 )
1726 double f_pos, f_thickness;
1727 double b_pos, b_thickness;
1731 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1732 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1734 static const double c_protrusion = 1.0;
1736 double pinZBot, pinHeight;
1740 pinZBot = boardBotZ - c_protrusion;
1741 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1745 double pinZTop = boardTopZ + c_protrusion;
1746 pinZBot = boardBotZ - aStandoff;
1747 pinHeight = pinZTop - pinZBot;
1758 const VECTOR2D& aOrigin,
const wxString& aNetname )
1760 bool success =
true;
1768 double z_pos, thickness;
1771 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1779 else if( aLayer ==
F_Mask )
1786 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1799 const std::vector<wxString>& aAltFilenames,
1800 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1802 VECTOR3D aScale,
bool aSubstituteModels )
1804 if( aFileName.empty() )
1806 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1815 wxString errorMessage;
1817 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1820 if( errorMessage.IsEmpty() )
1821 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1828 TopLoc_Location toploc;
1830 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1833 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1839 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1841 if( llabel.IsNull() )
1844 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1850 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1851 TDataStd_Name::Set( llabel, refdes );
1862 m_assy->UpdateAssemblies();
1934 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1935 double aZposition,
const VECTOR2D& aOrigin )
1942 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1943 double h_width = aWidth/2.0;
1945 coords[0] =
VECTOR2D{ 0.0, h_width };
1948 coords[1] =
VECTOR2D{ len, h_width };
1951 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1954 coords[3] =
VECTOR2D{ len, -h_width };
1957 coords[4] =
VECTOR2D{ 0, -h_width };
1960 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1963 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1965 for(
int ii = 0; ii < 6; ii++ )
1968 coords[ii] += aStartPoint;
1973 gp_Pnt coords3D[ 6 ];
1975 for(
int ii = 0; ii < 6; ii++ )
1977 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1978 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1982 BRepBuilderAPI_MakeWire wire;
1983 bool success =
true;
1995 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2000 edge = BRepBuilderAPI_MakeEdge(
circle );
2005 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2008 Handle( Geom_TrimmedCurve ) arcOfCircle =
2009 GC_MakeArcOfCircle( coords3D[1],
2013 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2016 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2019 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2020 GC_MakeArcOfCircle( coords3D[4],
2024 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2028 catch(
const Standard_Failure& e )
2030 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2031 e.GetMessageString() ),
2036 BRepBuilderAPI_MakeFace face;
2040 gp_Pln plane( coords3D[0], gp::DZ() );
2041 face = BRepBuilderAPI_MakeFace( plane, wire );
2043 catch(
const Standard_Failure& e )
2045 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2046 e.GetMessageString() ),
2051 if( aThickness != 0.0 )
2053 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2055 if( aShape.IsNull() )
2057 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2074 double aZposition,
const VECTOR2D& aOrigin )
2076 std::vector<TopoDS_Shape> testShapes;
2079 aHeight, aZposition, aOrigin );
2081 if( testShapes.size() > 0 )
2082 aShape = testShapes.front();
2105 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2109 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2111 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2112 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2122 gp_Pnt start = toPoint( aPt0 );
2123 gp_Pnt
end = toPoint( aPt1 );
2125 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2127 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2129 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2137 aMkWire.Add( mkEdge.Edge() );
2139 if( aMkWire.Error() != BRepLib_WireDone )
2141 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2155 Handle( Geom_Curve ) curve;
2157 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2159 gp_Ax2 axis = gp::XOY();
2160 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2162 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2166 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2167 toPoint( aArc.GetP1() ) ).Value();
2170 if( curve.IsNull() )
2173 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2175 if( !aMkWire.IsDone() )
2177 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2178 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2180 aArc.GetP0().x, aArc.GetP0().y,
2181 aArc.GetArcMid().x, aArc.GetArcMid().y,
2182 aArc.GetP1().x, aArc.GetP1().y ),
2192 bool isFirstShape =
true;
2205 if( nextShape != -1 )
2211 lastPt = aChain.
CPoint( i );
2221 firstPt = currentArc.
GetP0();
2226 lastPt = currentArc.
GetP0();
2228 if( addArc( lastPt, currentArc ) )
2229 lastPt = currentArc.
GetP1();
2248 isFirstShape =
false;
2251 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2253 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2255 firstPt.
x, firstPt.
y ),
2261 catch(
const Standard_Failure& e )
2263 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2264 e.GetMessageString() ),
2274 bool aConvertToArcs,
double aThickness,
double aZposition,
2282 if( aConvertToArcs )
2286 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2290 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2294 fallbackPoly = workingPoly;
2295 workingPoly = approximated;
2314 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2316 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2317 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2321 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2322 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2324 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2328 auto tryMakeWire = [
this, &aZposition,
2329 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2332 BRepLib_MakeWire mkWire;
2336 if( mkWire.IsDone() )
2338 wire = mkWire.Wire();
2343 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2344 "z: %g; bounding box: %s" ),
2345 static_cast<int>( aContour.PointCount() ),
2346 static_cast<int>( mkWire.Error() ),
2351 if( !wire.IsNull() )
2353 BRepAlgoAPI_Check check( wire,
false,
true );
2355 if( !check.IsValid() )
2357 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2358 "z: %g; bounding box: %s" ),
2370 BRepBuilderAPI_MakeFace mkFace;
2372 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2378 bool allow_retry = aConvertToArcs ? true :
false;
2380 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2382 if( aConvertToArcs && wire.IsNull() )
2384 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2388 allow_retry =
false;
2389 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2394 if( !wire.IsNull() )
2396 if( basePlane.Axis().Direction().Z() < 0 )
2399 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2403 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2404 "z: %g; bounding box: %s" ),
2413 if( !wire.IsNull() )
2415 if( basePlane.Axis().Direction().Z() > 0 )
2422 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2423 "z: %g; bounding box: %s" ),
2430 catch(
const Standard_Failure& e )
2432 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2433 static_cast<int>( contId ),
2434 e.GetMessageString() ),
2440 if( mkFace.IsDone() )
2442 TopoDS_Shape faceShape = mkFace.Shape();
2444 if( aThickness != 0.0 )
2446 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2447 aShapes.push_back( prism );
2449 if( prism.IsNull() )
2457 aShapes.push_back( faceShape );
2473 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2474 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2475 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2476 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2477 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2478 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2479 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2480 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2490 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2492 aColorOut =
COLOR4D( aColorStr );
2497 const std::vector<FAB_LAYER_COLOR>& colors =
2504 if( fabColor.GetName() == aColorStr )
2506 aColorOut = fabColor.GetColor( aType );
2528 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2533 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2538 double boardThickness;
2558 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2562 polyset.
Append( contour );
2569 m_reporter->Report(
_(
"OCC error creating main outline." ),
2578 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2590 BRepBndLib::Add( brdShape, brdBndBox );
2593 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2598 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2599 std::vector<Bnd_Box>& holeBoxes )
2603 Bnd_Box brdWithHolesBndBox = brdBndBox;
2605 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2606 holeBoxes.resize( input.size() );
2608 for(
size_t i = 0; i < input.size(); i++ )
2611 BRepBndLib::Add( input[i], bbox );
2612 brdWithHolesBndBox.Add( bbox );
2613 ( *holeBoxSet )[i] = bbox;
2614 holeBoxes[i] = bbox;
2617 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2620 auto subtractShapesMap =
2621 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2622 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2623 const std::vector<Bnd_Box>& aHoleBoxes )
2625 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2628 for(
auto& [netname, vec] : aShapesMap )
2632 auto subtractLoopFn = [&](
const int shapeId )
2634 TopoDS_Shape& shape = vec[shapeId];
2637 BRepBndLib::Add( shape, shapeBbox );
2639 NCollection_List<TopoDS_Shape> holelist;
2642 std::unique_lock lock( mutex );
2644 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2646 for(
const int&
index : indices )
2647 holelist.Append( aHolesList[
index] );
2653 if( holelist.IsEmpty() )
2655 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2657 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2658 holelist.Append( aHolesList[i] );
2663 if( holelist.IsEmpty() )
2666 NCollection_List<TopoDS_Shape> cutArgs;
2667 cutArgs.Append( shape );
2669 BRepAlgoAPI_Cut
cut;
2671 cut.SetRunParallel(
true );
2672 cut.SetToFillHistory(
false );
2674 cut.SetArguments( cutArgs );
2675 cut.SetTools( holelist );
2678 if(
cut.HasErrors() ||
cut.HasWarnings() )
2680 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2687 if(
cut.HasErrors() )
2689 wxString msg =
_(
"Errors:\n" );
2690 wxStringOutputStream os_stream( &msg );
2691 wxStdOutputStream out( os_stream );
2693 cut.DumpErrors( out );
2697 if(
cut.HasWarnings() )
2699 wxString msg =
_(
"Warnings:\n" );
2700 wxStringOutputStream os_stream( &msg );
2701 wxStdOutputStream out( os_stream );
2703 cut.DumpWarnings( out );
2708 shape =
cut.Shape();
2711 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2715 auto subtractShapes =
2716 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2717 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2718 const std::vector<Bnd_Box>& aHoleBoxes )
2720 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2722 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2723 aShapesList = aShapesMap[wxEmptyString];
2729 Bnd_BoundSortBox bsbHoles;
2730 std::vector<Bnd_Box> holeBoxes;
2738 Bnd_BoundSortBox bsbHoles;
2739 std::vector<Bnd_Box> holeBoxes;
2748 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2750 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2751 const std::vector<TopoDS_Shape>& aShapes )
2753 for(
const TopoDS_Shape& shape : aShapes )
2754 shapesToFuseMap[aNetname].Append( shape );
2758 addShapes( netname, shapes );
2761 addShapes( netname, shapes );
2764 addShapes( netname, shapes );
2771 auto fuseLoopFn = [&](
const wxString& aNetname )
2773 auto& toFuse = shapesToFuseMap[aNetname];
2776 if( !fusedShape.IsNull() )
2778 std::unique_lock lock( mutex );
2788 BS::multi_future<void> mf;
2790 for(
const auto& [netname,
_] : shapesToFuseMap )
2791 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2808 auto pushToAssemblyMap =
2809 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2810 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2811 bool aCompoundAll,
const wxString& aNiceName )
2813 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2817 std::vector<TopoDS_Shape> allShapes;
2819 for(
const auto& [netname, shapesList] : aShapesMap )
2820 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2822 if( !allShapes.empty() )
2823 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2827 shapesMap = aShapesMap;
2830 for(
const auto& [netname, shapesList] : shapesMap )
2832 std::vector<TopoDS_Shape> newList;
2837 newList = shapesList;
2841 for( TopoDS_Shape& shape : newList )
2843 Handle( TDataStd_TreeNode ) node;
2846 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2853 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2854 TDF_Label shpLbl = node->Father()->Label();
2856 if( !shpLbl.IsNull() )
2858 if( visMatTool && !aVisMatLabel.IsNull() )
2859 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2865 shapeName << aShapeName;
2867 if( !netname.empty() )
2870 shapeName << netname;
2873 if( newList.size() > 1 )
2879 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2880 TDataStd_Name::Set( shpLbl, partname );
2888 auto pushToAssembly =
2889 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2890 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2892 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2894 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2898 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2899 double aMetallic,
double aRoughness ) -> TDF_Label
2901 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2902 XCAFDoc_VisMaterialPBR pbr;
2903 pbr.BaseColor = aBaseColor;
2904 pbr.Metallic = aMetallic;
2905 pbr.Roughness = aRoughness;
2906 vismat->SetPbrMaterial( pbr );
2907 return visMatTool->AddMaterial( vismat, aName );
2914 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2915 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2916 Quantity_ColorRGBA back_silk_color = front_silk_color;
2917 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2918 Quantity_ColorRGBA back_mask_color = front_mask_color;
2928 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2932 if( item->GetBrdLayerId() ==
F_Mask )
2933 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2935 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2938 if( item->GetBrdLayerId() ==
F_SilkS )
2939 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2940 else if( item->GetBrdLayerId() ==
B_SilkS )
2941 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2944 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2950 board_color = front_mask_color;
2951 board_color.SetAlpha( 1.0 );
2954 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2955 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2956 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2957 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2958 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2959 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2960 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2962 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2966 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2967 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2968 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2969 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2971 if( aPushBoardBody )
2974 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
2975 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
2979 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
2982 TopoDS_Compound asmCompound;
2983 BRep_Builder asmBuilder;
2984 asmBuilder.MakeCompound( asmCompound );
2985 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
2986 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
2988 if( !entry.bodyShapes.empty() )
2990 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
2991 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
2992 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
2993 double a = ( entry.colorKey & 0xFF ) / 255.0;
2995 double metallic, roughness;
2997 switch( entry.material )
3018 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3019 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3021 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3022 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3024 Handle( TDataStd_TreeNode ) bodyNode;
3025 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3026 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3028 if( !bodyShpLbl.IsNull() )
3030 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3031 TDataStd_Name::Set( bodyShpLbl,
3032 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3038 for( TopoDS_Shape& pinShape : entry.pinShapes )
3040 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3042 Handle( TDataStd_TreeNode ) pinNode;
3043 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3044 TDF_Label pinShpLbl = pinNode->Father()->Label();
3046 if( !pinShpLbl.IsNull() )
3048 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3049 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3050 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3054 TopLoc_Location loc;
3055 TDF_Label fpCompLbl = m_assy->AddComponent(
m_assy_label, fpLabel, loc );
3056 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3061#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3062 m_assy->UpdateAssemblies();
3071bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3075 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3083 wxFileName fn( aFileName );
3084 IGESControl_Controller::Init();
3085 IGESCAFControl_Writer writer;
3086 writer.SetColorMode(
true );
3087 writer.SetNameMode(
true );
3088 IGESData_GlobalSection
header = writer.Model()->GlobalSection();
3089 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3090 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3091 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3092 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3093 writer.Model()->SetGlobalSection(
header );
3095 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3104 wxFileInputStream input( inputFile );
3105 wxFileOutputStream
output( outputFile );
3109 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3115 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3119 wxZlibOutputStream zlibStream(
output, -1, wxZLIB_GZIP );
3121 if( !zlibStream.IsOk() )
3123 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3127 input.Read( zlibStream );
3129 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3131 m_reporter->Report(
_(
"Compress read or write error" ) );
3145 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3153 wxFileName fn( aFileName );
3155 STEPCAFControl_Writer writer;
3156 writer.SetColorMode(
true );
3157 writer.SetNameMode(
true );
3164 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3166 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3172 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3174 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3178 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3181 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3185 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3188 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3189 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3190 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3191 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3193 bool success =
true;
3196 wxString currCWD = wxGetCwd();
3197 wxString workCWD = fn.GetPath();
3199 if( !workCWD.IsEmpty() )
3200 wxSetWorkingDirectory( workCWD );
3202 wxString tmpfname(
"$tempfile$.step" );
3204 if(
false == writer.Write( tmpfname.c_str() ) )
3207 if( compress && success )
3209 wxString srcTmp( tmpfname );
3210 wxString dstTmp(
"$tempfile$.stpz" );
3213 wxRemoveFile( srcTmp );
3224 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3226 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3234 wxSetWorkingDirectory( currCWD );
3244 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3253 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3258 wxFileName fn( aFileName );
3260 wxFFileOutputStream ffStream( fn.GetFullPath() );
3261 wxStdOutputStream stdStream( ffStream );
3263#if OCC_VERSION_HEX >= 0x070600
3264 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3266 BRepTools::Write( shape, stdStream );
3275 wxFileName fn( aFileName );
3277 wxFFileOutputStream ffStream( fn.GetFullPath() );
3278 wxStdOutputStream file( ffStream );
3280 if( !ffStream.IsOk() )
3282 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3290 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3295 std::map<wxString, std::vector<int>> groups[4];
3296 std::map<wxString, double> groupAreas;
3297 TopExp_Explorer exp;
3300 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3302 TopoDS_Shape subShape = exp.Current();
3305 BRepBndLib::Add( subShape, bbox );
3309 for(
const auto& pair : pairs )
3311 const auto& [point, padTestShape] = pair;
3313 if( bbox.IsOut( point ) )
3316 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3318 if( surface.GetType() != GeomAbs_Plane )
3321 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3324 if( !dist.IsDone() )
3327 if( dist.Value() < Precision::Approximation() )
3330 groups[2][padKey].push_back( faceIndex );
3332 GProp_GProps system;
3333 BRepGProp::SurfaceProperties( subShape, system );
3335 double surfaceArea = system.Mass() / 1e6;
3336 groupAreas[padKey] += surfaceArea;
3345 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3346 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3347 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3348 file <<
" <shape format=\"BREP\"><![CDATA[";
3349#if OCC_VERSION_HEX < 0x070600
3350 BRepTools::Write( shape, file );
3352 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3354 file <<
"]]></shape>" << std::endl;
3355 file <<
" <topology>" << std::endl;
3357 TopTools_IndexedMapOfShape mainMap;
3358 TopExp::MapShapes( shape, mainMap );
3359 std::set<int> topo[4];
3361 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3364 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3365 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3367 for(
int dim = 0; dim < 4; dim++ )
3369 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3371 TopoDS_Shape subShape = exp.Current();
3372 int idx = mainMap.FindIndex( subShape );
3374 if( idx && !topo[dim].count( idx ) )
3375 topo[dim].insert( idx );
3379 for(
int dim = 0; dim <= 3; dim++ )
3381 std::string labels = c_dimLabels[dim];
3382 std::string label = c_dimLabel[dim];
3384 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3387 for(
auto p : topo[dim] )
3389 std::string
name(
"" );
3390 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3391 <<
"name=\"" <<
name <<
"\" "
3392 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3396 file <<
" </" << labels <<
">" << std::endl;
3399 file <<
" </topology>" << std::endl;
3400 file <<
" </geometry>" << std::endl;
3401 file <<
" <groups count=\""
3402 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3405 int groupNumber = 1;
3410 for(
int dim = 0; dim <= 3; dim++ )
3412 std::string label = c_dimLabel[dim];
3414 for(
auto g : groups[dim] )
3417 wxString
name = g.first;
3421 std::ostringstream gs;
3422 gs <<
"G_" << dim <<
"D_" << g.first;
3425 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3431 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3433 for(
auto index : g.second )
3434 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3436 file <<
" </group>" << std::endl;
3438 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3450 file <<
" </groups>" << std::endl;
3451 file <<
" <fields count=\"0\"/>" << std::endl;
3452 file <<
"</XAO>" << std::endl;
3459 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3460 TDF_Label& aLabel,
bool aSubstituteModels,
3461 wxString* aErrorMessage )
3463 std::string fileNameUTF8 = aFileName.utf8_string();
3465 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3466 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3468 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3472 aLabel = mm->second;
3478 Handle( TDocStd_Document ) doc;
3479 m_app->NewDocument(
"MDTV-XCAF", doc );
3482 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3487 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3489 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3497 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3499 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3510 wxFFileInputStream ifile( aFileName );
3511 wxFileName outFile( aFileName );
3513 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3514 outFile.SetExt( wxT(
"step" ) );
3515 wxFileOffset size = ifile.GetLength();
3517 if( size == wxInvalidOffset )
3519 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3526 bool success =
false;
3529 wxFFileOutputStream ofile( outFile.GetFullPath() );
3534 char* buffer =
new char[size];
3536 ifile.Read( buffer, size );
3537 std::string expanded;
3541 expanded = gzip::decompress( buffer, size );
3549 if( expanded.empty() )
3553 wxZipInputStream izipfile( ifile );
3554 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3556 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3558 izipfile.Read( ofile );
3563 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3569 ofile.Write( expanded.data(), expanded.size() );
3577 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3578 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3597 if( aSubstituteModels )
3599 wxFileName wrlName( aFileName );
3601 wxString basePath = wrlName.GetPath();
3602 wxString baseName = wrlName.GetName();
3610 alts.Add( wxT(
"stp" ) );
3611 alts.Add( wxT(
"step" ) );
3612 alts.Add( wxT(
"STP" ) );
3613 alts.Add( wxT(
"STEP" ) );
3614 alts.Add( wxT(
"Stp" ) );
3615 alts.Add( wxT(
"Step" ) );
3616 alts.Add( wxT(
"stpz" ) );
3617 alts.Add( wxT(
"stpZ" ) );
3618 alts.Add( wxT(
"STPZ" ) );
3619 alts.Add( wxT(
"step.gz" ) );
3620 alts.Add( wxT(
"stp.gz" ) );
3623 alts.Add( wxT(
"iges" ) );
3624 alts.Add( wxT(
"IGES" ) );
3625 alts.Add( wxT(
"igs" ) );
3626 alts.Add( wxT(
"IGS" ) );
3630 for(
const auto& altExt : alts )
3634 if( !aAltFilenames.empty() )
3636 for(
const wxString& altPath : aAltFilenames )
3638 wxFileName iterFn( altPath );
3640 if( iterFn.GetExt() == altExt )
3649 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3652 if( altFile.IsOk() && altFile.FileExists() )
3662 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3676 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3678 Handle( XCAFDoc_ShapeTool ) shapeTool =
3679 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3686 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3696 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3706 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3713 if( aLabel.IsNull() )
3715 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3722 TDataStd_Name::Set( aLabel, partname );
3732 TopLoc_Location& aLocation )
3746 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3752 double boardThickness;
3755 double top = std::max( boardZPos, boardZPos + boardThickness );
3756 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3761 double f_pos, f_thickness;
3765 bottom += f_thickness;
3772 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3773 lPos.Multiply( lRot );
3774 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3775 lPos.Multiply( lRot );
3780 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3781 lPos.Multiply( lRot );
3785 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3786 lPos.Multiply( lOff );
3789 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3790 lPos.Multiply( lOrient );
3791 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3792 lPos.Multiply( lOrient );
3793 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3794 lPos.Multiply( lOrient );
3796 aLocation = TopLoc_Location( lPos );
3803 IGESControl_Controller::Init();
3804 IGESCAFControl_Reader reader;
3805 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3807 if( stat != IFSelect_RetDone )
3811 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3815 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3819 reader.SetColorMode(
true );
3820 reader.SetNameMode(
false );
3821 reader.SetLayerMode(
false );
3823 if( !reader.Transfer( doc ) )
3825 if( doc->CanClose() == CDM_CCS_OK )
3832 if( reader.NbShapes() < 1 )
3834 if( doc->CanClose() == CDM_CCS_OK )
3846 STEPCAFControl_Reader reader;
3847 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3849 if( stat != IFSelect_RetDone )
3853 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3857 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3861 reader.SetColorMode(
true );
3862 reader.SetNameMode(
true );
3863 reader.SetLayerMode(
false );
3865 if( !reader.Transfer( doc ) )
3867 if( doc->CanClose() == CDM_CCS_OK )
3874 if( reader.NbRootsForTransfer() < 1 )
3876 if( doc->CanClose() == CDM_CCS_OK )
3888#if OCC_VERSION_HEX >= 0x070700
3889 VrmlAPI_CafReader reader;
3890 RWMesh_CoordinateSystemConverter conv;
3891 conv.SetInputLengthUnit( 2.54 );
3892 reader.SetCoordinateSystemConverter( conv );
3893 reader.SetDocument( doc );
3895 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3908 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3910 NCollection_Sequence<TDF_Label> frshapes;
3911 s_assy->GetFreeShapes( frshapes );
3913 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3922 TDF_Label d_targetLabel = d_assy->NewShape();
3924 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
3930 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3933 return d_targetLabel;
3939 NCollection_Sequence<TDF_Label> freeShapes;
3940 aShapeTool->GetFreeShapes( freeShapes );
3946 for(
int i = 1; i <= freeShapes.Length(); ++i )
3948 TDF_Label label = freeShapes.Value( i );
3950 aShapeTool->GetShape( label, shape );
3955 const double linearDeflection = 0.14;
3956 const double angularDeflection =
DEG2RAD( 30.0 );
3957 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
3979 wxFileName fn( aFileName );
3981 const char* tmpGltfname =
"$tempfile$.glb";
3982 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3984 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3985 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3986 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3987 RWMesh_CoordinateSystem_Zup );
3988#if OCC_VERSION_HEX >= 0x070700
3989 cafWriter.SetParallel(
true );
3991 TColStd_IndexedDataMapOfStringString metadata;
3993 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3994 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3995 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3996 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3997 metadata.Add( TCollection_AsciiString(
"generator" ),
3998 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3999 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4002 bool success =
true;
4005 wxString currCWD = wxGetCwd();
4006 wxString workCWD = fn.GetPath();
4008 if( !workCWD.IsEmpty() )
4009 wxSetWorkingDirectory( workCWD );
4011 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4018 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4020 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4028 wxSetWorkingDirectory( currCWD );
4036#if OCC_VERSION_HEX < 0x070700
4043 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4053 wxFileName fn( aFileName );
4055 const char* tmpFname =
"$tempfile$.ply";
4056 RWPly_CafWriter cafWriter( tmpFname );
4058 cafWriter.SetFaceId(
true );
4059 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4060 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4062 TColStd_IndexedDataMapOfStringString metadata;
4064 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4065 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4066 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4067 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4068 metadata.Add( TCollection_AsciiString(
"generator" ),
4069 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4071 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4074 bool success =
true;
4077 wxString currCWD = wxGetCwd();
4078 wxString workCWD = fn.GetPath();
4080 if( !workCWD.IsEmpty() )
4081 wxSetWorkingDirectory( workCWD );
4083 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4090 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4092 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4100 wxSetWorkingDirectory( currCWD );
4111 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4121 wxFileName fn( aFileName );
4123 const char* tmpFname =
"$tempfile$.stl";
4126 wxString currCWD = wxGetCwd();
4127 wxString workCWD = fn.GetPath();
4129 if( !workCWD.IsEmpty() )
4130 wxSetWorkingDirectory( workCWD );
4132 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4139 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4141 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4149 wxSetWorkingDirectory( currCWD );
4161 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4170 wxFileName fn( aFileName );
4172 const char* tmpFname =
"$tempfile$.u3d";
4175 wxString currCWD = wxGetCwd();
4176 wxString workCWD = fn.GetPath();
4178 if( !workCWD.IsEmpty() )
4179 wxSetWorkingDirectory( workCWD );
4182 bool success = writer.
Perform( m_doc );
4188 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4190 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4197 wxSetWorkingDirectory( currCWD );
4208 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4217 wxFileName fn( aFileName );
4219 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4220 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4222 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4223 bool success = writer.
Perform( m_doc );
4226 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4228 plotter->SetColorMode(
true );
4229 plotter->Set3DExport(
true );
4230 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4232 plotter->SetRenderSettings( &renderSettings );
4234 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4236 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4242 plotter->StartPlot(
"1",
"3D Model" );
4243 double fov_degrees = 16.5f;
4248 std::vector<PDF_3D_VIEW> views;
4253 std::vector<float> c2wMatrix =
4257 .m_name =
"Default",
4258 .m_cameraMatrix = c2wMatrix,
4259 .m_cameraCenter = (float)
distance,
4260 .m_fov = (
float) fov_degrees,
4269 .m_cameraMatrix = c2wMatrix,
4270 .m_cameraCenter = (float)
distance,
4271 .m_fov = (
float) fov_degrees,
4280 .m_cameraMatrix = c2wMatrix,
4281 .m_cameraCenter = (float)
distance,
4282 .m_fov = (
float) fov_degrees,
4291 .m_cameraMatrix = c2wMatrix,
4292 .m_cameraCenter = (float)
distance,
4293 .m_fov = (
float) fov_degrees,
4296 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4305 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4307 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4308 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4314 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 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