30#include <wx/filename.h>
32#include <wx/sstream.h>
33#include <wx/stdpaths.h>
36#include <wx/zstream.h>
37#include <wx/wfstream.h>
38#include <wx/zipstrm.h>
39#include <wx/stdstream.h>
42#include <decompress.hpp>
70#include <IGESCAFControl_Reader.hxx>
71#include <IGESCAFControl_Writer.hxx>
72#include <IGESControl_Controller.hxx>
73#include <IGESData_GlobalSection.hxx>
74#include <IGESData_IGESModel.hxx>
75#include <Interface_Static.hxx>
76#include <Quantity_Color.hxx>
77#include <STEPCAFControl_Reader.hxx>
78#include <STEPCAFControl_Writer.hxx>
79#include <APIHeaderSection_MakeHeader.hxx>
80#include <Standard_Failure.hxx>
81#include <Standard_Handle.hxx>
82#include <Standard_Version.hxx>
83#include <TCollection_ExtendedString.hxx>
84#include <TDocStd_Document.hxx>
85#include <TDataStd_Name.hxx>
86#include <TDataStd_TreeNode.hxx>
87#include <TDF_ChildIterator.hxx>
88#include <NCollection_Sequence.hxx>
89#include <TColStd_IndexedDataMapOfStringString.hxx>
90#include <TDF_Tool.hxx>
91#include <TopTools_IndexedMapOfShape.hxx>
92#include <TopExp_Explorer.hxx>
94#include <XCAFApp_Application.hxx>
96#include <XCAFDoc_DocumentTool.hxx>
97#include <XCAFDoc_ColorTool.hxx>
98#include <XCAFDoc_ShapeTool.hxx>
99#include <XCAFDoc_VisMaterialTool.hxx>
100#include <XCAFDoc_Area.hxx>
101#include <XCAFDoc_Centroid.hxx>
102#include <XCAFDoc_Editor.hxx>
103#include <XCAFDoc_Location.hxx>
104#include <XCAFDoc_Volume.hxx>
107#include "KI_XCAFDoc_AssemblyGraph.hxx"
109#include <BRep_Tool.hxx>
110#include <BRepMesh_IncrementalMesh.hxx>
111#include <BRepBuilderAPI_GTransform.hxx>
112#include <BRepBuilderAPI_MakeEdge.hxx>
113#include <BRepBuilderAPI_MakeWire.hxx>
114#include <BRepBuilderAPI_MakeFace.hxx>
115#include <BRepExtrema_DistShapeShape.hxx>
116#include <BRepPrimAPI_MakeCone.hxx>
117#include <BRepPrimAPI_MakeCylinder.hxx>
118#include <BRepPrimAPI_MakePrism.hxx>
119#include <BRepTools.hxx>
120#include <BRepLib_MakeWire.hxx>
121#include <BRepAdaptor_Surface.hxx>
122#include <BRepAlgoAPI_Check.hxx>
123#include <BRepAlgoAPI_Cut.hxx>
124#include <BRepAlgoAPI_Fuse.hxx>
125#include <ShapeUpgrade_UnifySameDomain.hxx>
127#include <BRepBndLib.hxx>
128#include <Bnd_BoundSortBox.hxx>
129#include <Bnd_HArray1OfBox.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>
147#if OCC_VERSION_HEX >= 0x070700
148#include <VrmlAPI_CafReader.hxx>
149#include <RWPly_CafWriter.hxx>
177 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
179 if( !lfile.FileExists() )
182 wxString ext = lfile.GetExt().Lower();
184 if( ext == wxT(
"wrl" ) )
187 if( ext == wxT(
"wrz" ) )
190 if( ext == wxT(
"idf" ) )
193 if( ext == wxT(
"emn" ) )
196 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
210 const int max_line_count = 3;
212 for(
int ii = 0; ii < max_line_count; ii++ )
214 memset( iline, 0, 82 );
215 ifile.getline( iline, 82 );
221 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
227 std::string fstr = iline;
231 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
240 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
247 if( strncmp( iline,
"/*", 2 ) != 0 )
265 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
266 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
267 double det = -b.
x * d.
y + d.
x * b.
y;
271 center.x = ( -bc * d.
y - cd * b.
y ) * det;
272 center.y = ( b.
x * cd + d.
x * bc ) * det;
279#define APPROX_DBG( stmt )
287 static const double c_radiusDeviation = 1000.0;
288 static const double c_arcCenterDeviation = 1000.0;
289 static const double c_relLengthDeviation = 0.8;
290 static const int c_last_none = -1000;
292 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
293 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
312 int last = c_last_none;
318 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
320 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
325 bool defective =
false;
331 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
339 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
340 defective |=
std::abs( a_diff ) < 0.1;
343 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
344 defective |=
std::abs( a_diff ) >= maxAngleDiff;
355 for(
int j = i; j <= jEndIdx; j++ )
360 double rad_test = ( p_test -
center ).EuclideanNorm();
361 double d_tl = ( p_test - p_prev ).EuclideanNorm();
365 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
368 if( rad_dev > c_radiusDeviation )
371 <<
" Radius deviation too large: " << int64_t( rad_dev )
372 <<
" > " << c_radiusDeviation << std::endl );
377 double maxAngleDiff =
378 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
380 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
381 if(
std::abs( a_diff_test ) >= maxAngleDiff )
383 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
388 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
390 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
391 <<
"; " << d01 << std::endl );
401 if( last != c_last_none )
413 APPROX_DBG( std::cout <<
" Arc central angle too small: "
415 << c_minArcCentralAngle.
AsDegrees() << std::endl );
421 for(
int k = first + 1; last != c_last_none && k < last; k++ )
427 if( dist > c_radiusDeviation )
429 APPROX_DBG( std::cout <<
" Point " << k <<
" too far from arc: " << dist
430 <<
" > " << c_radiusDeviation << std::endl );
435 if( last != c_last_none )
440 int toRemove = last - ( aSrc.
PointCount() - 3 );
470 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
475 if( last == c_last_none )
492 if( iarc0 != -1 && iarc1 != -1 )
494 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
504 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
522 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
523 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
541 NCollection_Sequence<TDF_Label> theLabels;
542 aShapeTool->GetFreeShapes( theLabels );
546 if( theLabels.Length() == 1 )
547 return aShapeTool->GetShape( theLabels.Value( 1 ) );
549 TopoDS_Compound aCompound;
550 BRep_Builder aBuilder;
551 aBuilder.MakeCompound( aCompound );
553 for( NCollection_Sequence<TDF_Label>::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
555 TopoDS_Shape aFreeShape;
557 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
560 aBuilder.Add( aCompound, aFreeShape );
563 if( aCompound.NbChildren() > 0 )
574 if( theLabel.IsNull() )
576 Message::SendFail(
"Null label." );
580 if(
std::abs( aScale.X() ) <= gp::Resolution() ||
std::abs( aScale.Y() ) <= gp::Resolution()
581 ||
std::abs( aScale.Z() ) <= gp::Resolution() )
583 Message::SendFail(
"Scale factor is too small." );
587 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
589 if( aShapeTool.IsNull() )
591 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
595 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
599 Message::SendFail(
"Couldn't create assembly graph." );
603 bool anIsDone =
true;
607 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
609 0, 0, aScale.Z() ) );
612 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
614 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
616 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
618 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
619 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
624 const TDF_Label& aLabel = aG->GetNode( idx );
626 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
628 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
629 aBRepTrsf.Perform( aShape,
true );
630 if( !aBRepTrsf.IsDone() )
632 Standard_SStream aSS;
633 TCollection_AsciiString anEntry;
634 TDF_Tool::Entry( aLabel, anEntry );
635 aSS <<
"Shape " << anEntry <<
" is not scaled!";
636 Message::SendFail( aSS.str().c_str() );
640 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
641 aShapeTool->SetShape( aLabel, aScaledShape );
644 NCollection_Sequence<TDF_Label> aSubshapes;
645 aShapeTool->GetSubShapes( aLabel, aSubshapes );
646 for( NCollection_Sequence<TDF_Label>::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
648 const TDF_Label& aLSs = anItSs.Value();
649 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
650 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
651 aShapeTool->SetShape( aLSs, aSs1 );
655 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
656 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
657 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
659 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
661 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
662 gp_Trsf aTrsf = aLoc.Transformation();
663 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
664 XCAFDoc_Location::Set( aLabel, aTrsf );
673 aShapeTool->UpdateAssemblies();
681 BRepAlgoAPI_Fuse mkFuse;
682 NCollection_List<TopoDS_Shape> shapeArguments, shapeTools;
684 for(
const TopoDS_Shape& sh : aInputShapes )
689 if( shapeArguments.IsEmpty() )
690 shapeArguments.Append( sh );
692 shapeTools.Append( sh );
699 mkFuse.SetNonDestructive(
true );
700 mkFuse.SetRunParallel(
true );
701 mkFuse.SetToFillHistory(
false );
702 mkFuse.SetArguments( shapeArguments );
703 mkFuse.SetTools( shapeTools );
706 catch(
const std::bad_alloc& )
708 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
709 "reducing the number of objects (e.g., vias), or freeing system memory." ),
713 catch(
const Standard_Failure& e )
715 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
716 "This may indicate insufficient memory. Consider "
717 "disabling shape fusing or reducing board complexity." ),
718 e.GetMessageString() ),
723 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
725 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
726 "memory-intensive; insufficient memory may cause failures." ),
729 if( mkFuse.HasErrors() )
731 wxString msg =
_(
"Errors:\n" );
732 wxStringOutputStream os_stream( &msg );
733 wxStdOutputStream out( os_stream );
735 mkFuse.DumpErrors( out );
739 if( mkFuse.HasWarnings() )
741 wxString msg =
_(
"Warnings:\n" );
742 wxStringOutputStream os_stream( &msg );
743 wxStdOutputStream out( os_stream );
745 mkFuse.DumpWarnings( out );
750 if( mkFuse.IsDone() )
752 TopoDS_Shape fusedShape = mkFuse.Shape();
756 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
757 unify.SetSafeInputMode(
true );
758 unify.History() =
nullptr;
761 TopoDS_Shape unifiedShapes = unify.Shape();
763 if( unifiedShapes.IsNull() )
765 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
770 aOutShape = unifiedShapes;
774 catch(
const std::bad_alloc& )
776 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
777 "shape fusing or reducing the number of objects." ),
781 catch(
const Standard_Failure& e )
783 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
784 e.GetMessageString() ),
796 TopoDS_Compound compound;
797 BRep_Builder builder;
798 builder.MakeCompound( compound );
800 for(
const TopoDS_Shape& shape : aInputShapes )
801 builder.Add( compound, shape );
810 TopoDS_Shape outShape;
812 if( aInputShapes.Size() == 1 )
813 return aInputShapes.First();
815 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
824 const TCollection_ExtendedString& aPrefix )
826 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
830 Message::SendFail(
"Couldn't create assembly graph." );
834 bool anIsDone =
true;
836 for(
int idx = 1; idx <= aG->NbNodes(); idx++ )
838 const TDF_Label& lbl = aG->GetNode( idx );
839 Handle( TDataStd_Name ) nameHandle;
841 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
843 TCollection_ExtendedString
name;
847 name += nameHandle->Get();
850 TDataStd_Name::Set( lbl,
name );
854 TDataStd_Name::Set( lbl, aPrefix );
866 m_app = XCAFApp_Application::GetApplication();
867 m_app->NewDocument(
"MDTV-XCAF", m_doc );
868 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
886 if( m_doc->CanClose() == CDM_CCS_OK )
894 const double c_padExtraThickness = 0.005;
896 std::vector<TopoDS_Shape> padShapes;
910 double Zpos, thickness;
916 if( pcb_layer ==
F_Cu )
917 thickness += c_padExtraThickness;
918 else if( pcb_layer ==
B_Cu )
919 thickness -= c_padExtraThickness;
922 TopoDS_Shape testShape;
936 if( testShape.IsNull() )
938 std::vector<TopoDS_Shape> testShapes;
942 if( testShapes.size() > 0 )
943 testShape = testShapes.front();
948 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
954 if( pcb_layer ==
F_Cu )
956 else if( pcb_layer ==
B_Cu )
972 double f_pos, f_thickness;
973 double b_pos, b_thickness;
980 f_thickness += c_padExtraThickness;
981 b_thickness -= c_padExtraThickness;
984 double top = std::max( f_pos, f_pos + f_thickness );
985 double bottom = std::min( b_pos, b_pos + b_thickness );
986 double hole_height =
top - bottom;
988 TopoDS_Shape plating;
996 hole_height, bottom, aOrigin ) )
998 padShapes.push_back( plating );
1012 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
1029 padShapes.push_back( plating );
1041 if( !padShapes.empty() )
1046 NCollection_List<TopoDS_Shape> padShapesList;
1048 for(
const TopoDS_Shape& shape : padShapes )
1049 padShapesList.Append( shape );
1055 for(
const TopoDS_Shape& shape : padShapes )
1066 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1068 double margin = 0.001;
1076 double f_pos, f_thickness;
1077 double b_pos, b_thickness;
1080 double top = std::max( f_pos, f_pos + f_thickness );
1081 double bottom = std::min( b_pos, b_pos + b_thickness );
1083 double holeZsize = (
top - bottom ) + ( margin * 2 );
1085 double boardDrill = aShape.
GetWidth();
1086 double copperDrill = boardDrill - aPlatingThickness * 2;
1088 TopoDS_Shape copperHole, boardHole;
1093 holeZsize, bottom - margin, aOrigin ) )
1106 holeZsize, bottom - margin, aOrigin ) )
1122 const wxString& aNetname )
1124 double f_pos, f_thickness;
1125 double b_pos, b_thickness;
1128 double top = std::max( f_pos, f_pos + f_thickness );
1129 double bottom = std::min( b_pos, b_pos + b_thickness );
1131 TopoDS_Shape plating;
1134 (
top - bottom ), bottom, aOrigin ) )
1156 double margin = 0.001;
1160 double copperMargin = 0.5;
1162 double start_pos, start_thickness;
1163 double end_pos, end_thickness;
1168 double top = std::max( { start_pos, start_pos + start_thickness,
1169 end_pos, end_pos + end_thickness } );
1170 double bottom = std::min( { start_pos, start_pos + start_thickness,
1171 end_pos, end_pos + end_thickness } );
1174 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1175 top += copperMargin;
1176 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1177 bottom -= copperMargin;
1179 double holeZsize = (
top - bottom ) + ( margin * 2 );
1180 double holeZpos = bottom - margin;
1182 double backdrillDiameter = aShape.
GetWidth();
1184 TopoDS_Shape backdrillHole;
1188 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1205 bool aFrontSide,
const VECTOR2D& aOrigin )
1207 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1208 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1211 if( aDiameter <= 0 || aDepth <= 0 )
1213 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1214 aDiameter, aDepth );
1218 double margin = 0.001;
1221 double copperMargin = 0.5;
1224 double boardZpos, boardThickness;
1228 double f_pos, f_thickness, b_pos, b_thickness;
1235 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1236 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1238 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1239 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1242 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1243 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1244 double radius_mm = diameter_mm / 2.0;
1246 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1247 diameter_mm, depth_mm, radius_mm );
1251 double cylinderZpos;
1252 double cylinderHeight;
1258 cylinderZpos = topOuterSurface - depth_mm - margin;
1259 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1265 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1266 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1270 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1271 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1273 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1274 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1280 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1282 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1284 if( cylinder.IsNull() )
1286 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1287 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1296 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1299 catch(
const Standard_Failure& e )
1301 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1302 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1303 e.GetMessageString() ),
1313 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1315 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1316 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1321 if( aDiameter <= 0 || aAngle <= 0 )
1323 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1324 aDiameter, aAngle );
1328 double margin = 0.001;
1331 double copperMargin = 0.5;
1334 double boardZpos, boardThickness;
1338 double f_pos, f_thickness, b_pos, b_thickness;
1343 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1344 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1346 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1347 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1350 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1351 double radius_mm = diameter_mm / 2.0;
1355 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1363 depth_mm = radius_mm / tan( halfAngleRad );
1364 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1365 depth_mm, radius_mm );
1372 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1373 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1384 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1386 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1387 bottomRadius_mm, tan( halfAngleRad ) );
1389 if( bottomRadius_mm < 0 )
1390 bottomRadius_mm = 0;
1395 double coneHeight = depth_mm + copperMargin + margin;
1399 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1400 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1411 coneZpos = topOuterSurface - depth_mm - margin;
1412 r1 = bottomRadius_mm;
1414 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1416 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1417 coneZpos, r1, r2, coneHeight );
1419 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1420 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1427 coneZpos = bottomOuterSurface - copperMargin - margin;
1429 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1430 r2 = bottomRadius_mm;
1432 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1433 coneZpos, r1, r2, coneHeight );
1435 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1436 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1441 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1442 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1451 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1454 catch(
const Standard_Failure& e )
1456 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1457 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1458 e.GetMessageString() ),
1468 int aAngle,
bool aFrontSide )
1470 std::map<PCB_LAYER_ID, int> knockouts;
1473 double f_pos, f_thickness, b_pos, b_thickness;
1477 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1478 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1481 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1482 double radius_mm = diameter_mm / 2.0;
1486 double halfAngleRad = 0.0;
1491 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1495 depth_mm = radius_mm / tan( halfAngleRad );
1506 double featureTop, featureBottom;
1510 featureTop = topOuterSurface;
1511 featureBottom = topOuterSurface - depth_mm;
1515 featureBottom = bottomOuterSurface;
1516 featureTop = bottomOuterSurface + depth_mm;
1519 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1520 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1529 double layerZ, layerThickness;
1533 double layerTop = std::max( layerZ, layerZ + layerThickness );
1534 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1538 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1540 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1541 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1546 int knockoutDiameter;
1552 double layerSurfaceZ;
1556 layerSurfaceZ = layerTop;
1561 layerSurfaceZ = layerBottom;
1565 double distanceFromSurface;
1567 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1569 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1572 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1574 if( radiusAtLayer_mm <= 0 )
1576 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1577 static_cast<int>( layer ) );
1581 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1582 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1583 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1588 knockoutDiameter = aDiameter;
1589 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1590 static_cast<int>( layer ), knockoutDiameter );
1593 knockouts[layer] = knockoutDiameter;
1601 double& aThickness )
1604 static const double c_silkscreenAboveCopper = 0.04;
1605 static const double c_soldermaskAboveCopper = 0.015;
1613 double f_pos, f_thickness;
1615 double top = std::max( f_pos, f_pos + f_thickness );
1618 aZPos =
top + c_silkscreenAboveCopper;
1620 aZPos =
top + c_soldermaskAboveCopper;
1626 double b_pos, b_thickness;
1628 double bottom = std::min( b_pos, b_pos + b_thickness );
1631 aZPos = bottom - c_silkscreenAboveCopper;
1633 aZPos = bottom - c_soldermaskAboveCopper;
1641 double& aThickness )
1645 bool wasPrepreg =
false;
1647 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1650 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1656 if( aLayer ==
B_Cu )
1705 if( !item->IsEnabled() )
1710 for(
int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
1711 thickness += item->GetThickness( sublayer );
1716 thickness += item->GetThickness();
1726 double f_pos, f_thickness;
1727 double b_pos, b_thickness;
1730 double top = std::min( f_pos, f_pos + f_thickness );
1731 double bottom = std::max( b_pos, b_pos + b_thickness );
1733 aThickness = (
top - bottom );
1747 m_reporter->Report( wxString::Format(
_(
"Board stackup does not define a board thickness; "
1748 "exporting a %.3f mm board body." ),
1753 wxASSERT( aZPos == 0.0 );
1759 const wxString& aRefDes )
1761 double f_pos, f_thickness;
1762 double b_pos, b_thickness;
1766 double boardSurfaceZ;
1769 boardSurfaceZ = std::max( f_pos, f_pos + f_thickness );
1771 boardSurfaceZ = std::min( b_pos, b_pos + b_thickness );
1773 double bodyThickness = aHeight - aStandoff;
1777 zBot = boardSurfaceZ + aStandoff;
1779 zBot = boardSurfaceZ - aHeight;
1787 double aStandoff,
const VECTOR2D& aOrigin )
1789 if( aStandoff <= 0.0 )
1805 double f_pos, f_thickness;
1806 double b_pos, b_thickness;
1810 double boardTopZ = std::max( f_pos, f_pos + f_thickness );
1811 double boardBotZ = std::min( b_pos, b_pos + b_thickness );
1813 static const double c_protrusion = 1.0;
1815 double zOffset = aBody ? aBody->
m_offset.
z : 0.0;
1817 double pinZBot, pinHeight;
1821 pinZBot = boardBotZ - c_protrusion + zOffset;
1822 pinHeight = ( boardTopZ + aStandoff ) - pinZBot;
1826 double pinZTop = boardTopZ + c_protrusion - zOffset;
1827 pinZBot = boardBotZ - aStandoff;
1828 pinHeight = pinZTop - pinZBot;
1834 bool success =
true;
1849 const VECTOR2D& aOrigin,
const wxString& aNetname )
1851 bool success =
true;
1859 double z_pos, thickness;
1862 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1870 else if( aLayer ==
F_Mask )
1877 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1890 const std::vector<wxString>& aAltFilenames,
1891 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1893 VECTOR3D aScale,
bool aSubstituteModels )
1895 if( aFileName.empty() )
1897 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1906 wxString errorMessage;
1908 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1911 if( errorMessage.IsEmpty() )
1912 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1919 TopLoc_Location toploc;
1921 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1924 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1930 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1932 if( llabel.IsNull() )
1935 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1943 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1944 TDataStd_Name::Set( llabel, refdes );
1955 m_assy->UpdateAssemblies();
2027 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
2028 double aZposition,
const VECTOR2D& aOrigin )
2035 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
2036 double h_width = aWidth/2.0;
2038 coords[0] =
VECTOR2D{ 0.0, h_width };
2041 coords[1] =
VECTOR2D{ len, h_width };
2044 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
2047 coords[3] =
VECTOR2D{ len, -h_width };
2050 coords[4] =
VECTOR2D{ 0, -h_width };
2053 coords[5] =
VECTOR2D{ -h_width, 0.0 };
2056 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
2058 for(
int ii = 0; ii < 6; ii++ )
2061 coords[ii] += aStartPoint;
2066 gp_Pnt coords3D[ 6 ];
2068 for(
int ii = 0; ii < 6; ii++ )
2070 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
2071 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
2075 BRepBuilderAPI_MakeWire wire;
2076 bool success =
true;
2088 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
2093 edge = BRepBuilderAPI_MakeEdge(
circle );
2098 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
2101 Handle( Geom_TrimmedCurve ) arcOfCircle =
2102 GC_MakeArcOfCircle( coords3D[1],
2106 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
2109 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
2112 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
2113 GC_MakeArcOfCircle( coords3D[4],
2117 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
2121 catch(
const Standard_Failure& e )
2123 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
2124 e.GetMessageString() ),
2129 BRepBuilderAPI_MakeFace face;
2133 gp_Pln plane( coords3D[0], gp::DZ() );
2134 face = BRepBuilderAPI_MakeFace( plane, wire );
2136 catch(
const Standard_Failure& e )
2138 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
2139 e.GetMessageString() ),
2144 if( aThickness != 0.0 )
2146 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
2148 if( aShape.IsNull() )
2150 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
2167 double aZposition,
const VECTOR2D& aOrigin )
2169 std::vector<TopoDS_Shape> testShapes;
2172 aHeight, aZposition, aOrigin );
2174 if( testShapes.size() > 0 )
2175 aShape = testShapes.front();
2198 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2202 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2204 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2205 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2215 gp_Pnt start = toPoint( aPt0 );
2216 gp_Pnt
end = toPoint( aPt1 );
2218 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2220 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2222 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2230 aMkWire.Add( mkEdge.Edge() );
2232 if( aMkWire.Error() != BRepLib_WireDone )
2234 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2248 Handle( Geom_Curve ) curve;
2250 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2252 gp_Ax2 axis = gp::XOY();
2253 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2255 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2259 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2260 toPoint( aArc.GetP1() ) ).Value();
2263 if( curve.IsNull() )
2266 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2268 if( !aMkWire.IsDone() )
2270 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2271 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2273 aArc.GetP0().x, aArc.GetP0().y,
2274 aArc.GetArcMid().x, aArc.GetArcMid().y,
2275 aArc.GetP1().x, aArc.GetP1().y ),
2285 bool isFirstShape =
true;
2298 if( nextShape != -1 )
2304 lastPt = aChain.
CPoint( i );
2314 firstPt = currentArc.
GetP0();
2319 lastPt = currentArc.
GetP0();
2321 if( addArc( lastPt, currentArc ) )
2322 lastPt = currentArc.
GetP1();
2341 isFirstShape =
false;
2344 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2346 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2348 firstPt.
x, firstPt.
y ),
2354 catch(
const Standard_Failure& e )
2356 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2357 e.GetMessageString() ),
2367 bool aConvertToArcs,
double aThickness,
double aZposition,
2375 if( aConvertToArcs )
2379 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2383 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2387 fallbackPoly = workingPoly;
2388 workingPoly = approximated;
2407 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2409 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2410 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2414 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2415 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2417 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2421 auto tryMakeWire = [
this, &aZposition,
2422 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2425 BRepLib_MakeWire mkWire;
2429 if( mkWire.IsDone() )
2431 wire = mkWire.Wire();
2436 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2437 "z: %g; bounding box: %s" ),
2438 static_cast<int>( aContour.PointCount() ),
2439 static_cast<int>( mkWire.Error() ),
2445 if( !wire.IsNull() )
2447 BRepAlgoAPI_Check check( wire,
false,
true );
2449 if( !check.IsValid() )
2451 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2452 "z: %g; bounding box: %s" ),
2464 BRepBuilderAPI_MakeFace mkFace;
2466 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2472 bool allow_retry = aConvertToArcs ? true :
false;
2474 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2476 if( aConvertToArcs && wire.IsNull() )
2478 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2482 allow_retry =
false;
2483 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2488 if( !wire.IsNull() )
2490 if( basePlane.Axis().Direction().Z() < 0 )
2493 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2497 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2498 "z: %g; bounding box: %s" ),
2507 if( !wire.IsNull() )
2509 if( basePlane.Axis().Direction().Z() > 0 )
2516 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2517 "z: %g; bounding box: %s" ),
2524 catch(
const Standard_Failure& e )
2526 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2527 static_cast<int>( contId ),
2528 e.GetMessageString() ),
2534 if( mkFace.IsDone() )
2536 TopoDS_Shape faceShape = mkFace.Shape();
2538 if( aThickness != 0.0 )
2540 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2541 aShapes.push_back( prism );
2543 if( prism.IsNull() )
2551 aShapes.push_back( faceShape );
2567 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2568 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2569 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2570 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2571 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2572 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2573 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2574 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2584 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2586 aColorOut =
COLOR4D( aColorStr );
2591 const std::vector<FAB_LAYER_COLOR>& colors =
2598 if( fabColor.GetName() == aColorStr )
2600 aColorOut = fabColor.GetColor( aType );
2622 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2627 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2632 double boardThickness;
2652 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2656 polyset.
Append( contour );
2663 m_reporter->Report(
_(
"OCC error creating main outline." ),
2672 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2684 BRepBndLib::Add( brdShape, brdBndBox );
2687 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2692 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2693 std::vector<Bnd_Box>& holeBoxes )
2697 Bnd_Box brdWithHolesBndBox = brdBndBox;
2699 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2700 holeBoxes.resize( input.size() );
2702 for(
size_t i = 0; i < input.size(); i++ )
2705 BRepBndLib::Add( input[i], bbox );
2706 brdWithHolesBndBox.Add( bbox );
2707 ( *holeBoxSet )[i] = bbox;
2708 holeBoxes[i] = bbox;
2711 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2714 auto subtractShapesMap =
2715 [
this, &
tp](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2716 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2717 const std::vector<Bnd_Box>& aHoleBoxes )
2719 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2722 for(
auto& [netname, vec] : aShapesMap )
2730 auto subtractLoopFn = [&](
const int shapeId )
2732 TopoDS_Shape& shape = vec[shapeId];
2735 BRepBndLib::Add( shape, shapeBbox );
2737 NCollection_List<TopoDS_Shape> holelist;
2740 std::unique_lock lock( mutex );
2742 const NCollection_List<int>& indices = aBSBHoles.Compare( shapeBbox );
2744 for(
const int&
index : indices )
2745 holelist.Append( aHolesList[
index] );
2751 if( holelist.IsEmpty() )
2753 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2755 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2756 holelist.Append( aHolesList[i] );
2761 if( holelist.IsEmpty() )
2764 NCollection_List<TopoDS_Shape> cutArgs;
2765 cutArgs.Append( shape );
2767 BRepAlgoAPI_Cut
cut;
2771 cut.SetNonDestructive(
true );
2772 cut.SetRunParallel(
false );
2773 cut.SetToFillHistory(
false );
2775 cut.SetArguments( cutArgs );
2776 cut.SetTools( holelist );
2779 if(
cut.HasErrors() ||
cut.HasWarnings() )
2781 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2790 std::unique_lock lock( mutex );
2794 if(
cut.HasErrors() )
2796 wxString msg =
_(
"Errors:\n" );
2797 wxStringOutputStream os_stream( &msg );
2798 wxStdOutputStream out( os_stream );
2800 cut.DumpErrors( out );
2804 if(
cut.HasWarnings() )
2806 wxString msg =
_(
"Warnings:\n" );
2807 wxStringOutputStream os_stream( &msg );
2808 wxStdOutputStream out( os_stream );
2810 cut.DumpWarnings( out );
2815 shape =
cut.Shape();
2821 BS::multi_future<void> cutFutures;
2825 cutFutures =
tp.submit_loop( 0, vec.size(), subtractLoopFn );
2838 auto subtractShapes =
2839 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2840 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2841 const std::vector<Bnd_Box>& aHoleBoxes )
2843 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2845 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2846 aShapesList = aShapesMap[wxEmptyString];
2852 Bnd_BoundSortBox bsbHoles;
2853 std::vector<Bnd_Box> holeBoxes;
2861 Bnd_BoundSortBox bsbHoles;
2862 std::vector<Bnd_Box> holeBoxes;
2871 std::map<wxString, NCollection_List<TopoDS_Shape>> shapesToFuseMap;
2873 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2874 const std::vector<TopoDS_Shape>& aShapes )
2876 for(
const TopoDS_Shape& shape : aShapes )
2877 shapesToFuseMap[aNetname].Append( shape );
2881 addShapes( netname, shapes );
2884 addShapes( netname, shapes );
2887 addShapes( netname, shapes );
2895 std::vector<std::pair<wxString, const NCollection_List<TopoDS_Shape>*>> fuseWork;
2896 fuseWork.reserve( shapesToFuseMap.size() );
2898 for(
const auto& [netname, toFuse] : shapesToFuseMap )
2899 fuseWork.emplace_back( netname, &toFuse );
2902 BS::multi_future<void> mf;
2903 mf.reserve( fuseWork.size() );
2909 for(
const auto& work : fuseWork )
2911 const wxString netname = work.first;
2912 const NCollection_List<TopoDS_Shape>* toFuse = work.second;
2914 mf.push_back(
tp.submit_task(
2915 [
this, &mutex, netname, toFuse]()
2917 TopoDS_Shape fusedShape = fuseShapesOrCompound( *toFuse, m_reporter );
2919 if( !fusedShape.IsNull() )
2921 std::unique_lock lock( mutex );
2923 m_board_copper_fused[netname].emplace_back( fusedShape );
2925 m_board_copper[netname].clear();
2926 m_board_copper_pads[netname].clear();
2927 m_board_copper_vias[netname].clear();
2954 auto pushToAssemblyMap =
2955 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2956 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2957 bool aCompoundAll,
const wxString& aNiceName )
2959 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2963 std::vector<TopoDS_Shape> allShapes;
2965 for(
const auto& [netname, shapesList] : aShapesMap )
2966 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2968 if( !allShapes.empty() )
2969 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2973 shapesMap = aShapesMap;
2976 for(
const auto& [netname, shapesList] : shapesMap )
2978 std::vector<TopoDS_Shape> newList;
2983 newList = shapesList;
2987 for( TopoDS_Shape& shape : newList )
2989 Handle( TDataStd_TreeNode ) node;
2992 TDF_Label lbl = m_assy->AddComponent( m_assy_label, shape,
false );
2994 m_pcb_labels.push_back( lbl );
2996 if( m_pcb_labels.back().IsNull() )
2999 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
3000 TDF_Label shpLbl = node->Father()->Label();
3002 if( !shpLbl.IsNull() )
3004 if( visMatTool && !aVisMatLabel.IsNull() )
3005 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
3009 shapeName << m_pcbName;
3011 shapeName << aShapeName;
3013 if( !netname.empty() )
3016 shapeName << netname;
3019 if( newList.size() > 1 )
3025 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
3026 TDataStd_Name::Set( shpLbl, partname );
3034 auto pushToAssembly =
3035 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
3036 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
3038 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
3040 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
3044 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
3045 double aMetallic,
double aRoughness ) -> TDF_Label
3047 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
3048 XCAFDoc_VisMaterialPBR pbr;
3049 pbr.BaseColor = aBaseColor;
3050 pbr.Metallic = aMetallic;
3051 pbr.Roughness = aRoughness;
3052 vismat->SetPbrMaterial( pbr );
3053 return visMatTool->AddMaterial( vismat, aName );
3057 Quantity_ColorRGBA copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2], 1.0 );
3058 Quantity_ColorRGBA pad_color( m_padColor[0], m_padColor[1], m_padColor[2], 1.0 );
3061 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 1.0f );
3062 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
3063 Quantity_ColorRGBA back_silk_color = front_silk_color;
3064 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
3065 Quantity_ColorRGBA back_mask_color = front_mask_color;
3075 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
3079 if( item->GetBrdLayerId() ==
F_Mask )
3080 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3082 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3085 if( item->GetBrdLayerId() ==
F_SilkS )
3086 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3087 else if( item->GetBrdLayerId() ==
B_SilkS )
3088 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3091 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
3095 if( !m_enabledLayers.Contains(
F_Mask ) && !m_enabledLayers.Contains(
B_Mask ) )
3097 board_color = front_mask_color;
3098 board_color.SetAlpha( 1.0 );
3101 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
3102 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
3103 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
3104 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
3105 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
3106 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
3107 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
3109 pushToAssemblyMap( m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
3110 pushToAssemblyMap( m_board_copper_pads, pad_mat,
"pad",
true,
true,
"Pads" );
3111 pushToAssemblyMap( m_board_copper_vias, copper_mat,
"via",
true,
true,
"Via" );
3112 pushToAssemblyMap( m_board_copper_fused, copper_mat,
"copper",
true,
true,
"Copper" );
3113 pushToAssembly( m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
3114 pushToAssembly( m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
3115 pushToAssembly( m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
3116 pushToAssembly( m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
3118 if( aPushBoardBody )
3119 pushToAssembly( m_board_outlines, board_mat,
"PCB",
false,
"Body" );
3121 Quantity_ColorRGBA pinClr( Quantity_Color( 0.75, 0.75, 0.75, Quantity_TOC_RGB ), 1.0 );
3122 TDF_Label pin_mat = makeMaterial(
"extruded_pin", pinClr, 0.6, 0.3 );
3124 for(
auto& entry : m_extruded_bodies )
3126 if( entry.bodyShapes.empty() && entry.pinShapes.empty() )
3129 TopoDS_Compound asmCompound;
3130 BRep_Builder asmBuilder;
3131 asmBuilder.MakeCompound( asmCompound );
3132 TDF_Label fpLabel = m_assy->AddShape( asmCompound,
true );
3133 TDataStd_Name::Set( fpLabel, TCollection_ExtendedString( ( entry.refDes +
" (extruded)" ).ToUTF8().data() ) );
3135 if( !entry.bodyShapes.empty() )
3137 double r = ( ( entry.colorKey >> 24 ) & 0xFF ) / 255.0;
3138 double g = ( ( entry.colorKey >> 16 ) & 0xFF ) / 255.0;
3139 double b = ( ( entry.colorKey >> 8 ) & 0xFF ) / 255.0;
3140 double a = ( entry.colorKey & 0xFF ) / 255.0;
3142 double metallic, roughness;
3144 switch( entry.material )
3165 Quantity_ColorRGBA bodyClr( Quantity_Color( r, g, b, Quantity_TOC_RGB ), a );
3166 TDF_Label body_mat = makeMaterial(
"extruded_body", bodyClr, metallic, roughness );
3168 TopoDS_Shape bodyCompound =
makeCompound( entry.bodyShapes );
3169 TDF_Label bodyLbl = m_assy->AddComponent( fpLabel, bodyCompound,
false );
3171 Handle( TDataStd_TreeNode ) bodyNode;
3172 bodyLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), bodyNode );
3173 TDF_Label bodyShpLbl = bodyNode->Father()->Label();
3175 if( !bodyShpLbl.IsNull() )
3177 visMatTool->SetShapeMaterial( bodyShpLbl, body_mat );
3178 TDataStd_Name::Set( bodyShpLbl,
3179 TCollection_ExtendedString( ( entry.refDes +
"_body" ).ToUTF8().data() ) );
3185 for( TopoDS_Shape& pinShape : entry.pinShapes )
3187 TDF_Label pinLbl = m_assy->AddComponent( fpLabel, pinShape,
false );
3189 Handle( TDataStd_TreeNode ) pinNode;
3190 pinLbl.FindAttribute( XCAFDoc::ShapeRefGUID(), pinNode );
3191 TDF_Label pinShpLbl = pinNode->Father()->Label();
3193 if( !pinShpLbl.IsNull() )
3195 visMatTool->SetShapeMaterial( pinShpLbl, pin_mat );
3196 wxString pinName = wxString::Format(
"%s_pin_%d", entry.refDes, pinIdx++ );
3197 TDataStd_Name::Set( pinShpLbl, TCollection_ExtendedString( pinName.ToUTF8().data() ) );
3201 TopLoc_Location loc;
3202 TDF_Label fpCompLbl = m_assy->AddComponent( m_assy_label, fpLabel, loc );
3203 TDataStd_Name::Set( fpCompLbl, TCollection_ExtendedString( entry.refDes.ToUTF8().data() ) );
3205 m_pcb_labels.push_back( fpCompLbl );
3208#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
3209 m_assy->UpdateAssemblies();
3218bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
3222 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3230 wxFileName fn( aFileName );
3231 IGESControl_Controller::Init();
3232 IGESCAFControl_Writer writer;
3233 writer.SetColorMode(
true );
3234 writer.SetNameMode(
true );
3235 IGESData_GlobalSection header = writer.Model()->GlobalSection();
3236 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3237 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3238 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
3239 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
3240 writer.Model()->SetGlobalSection( header );
3242 if(
false == writer.Perform( m_doc, aFileName.c_str() ) )
3251 wxFileInputStream input( inputFile );
3252 wxFileOutputStream output( outputFile );
3256 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
3260 if( !output.IsOk() )
3262 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
3266 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
3268 if( !zlibStream.IsOk() )
3270 m_reporter->Report(
_(
"Impossible create compress stream" ) );
3274 input.Read( zlibStream );
3276 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
3278 m_reporter->Report(
_(
"Compress read or write error" ) );
3292 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3300 wxFileName fn( aFileName );
3302 STEPCAFControl_Writer writer;
3303 writer.SetColorMode(
true );
3304 writer.SetNameMode(
true );
3311 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
3313 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
3319 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
3321 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3325 if(
false == writer.Transfer( m_doc, STEPControl_AsIs ) )
3328 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3332 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3335 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3336 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3337 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3338 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3340 bool success =
true;
3343 wxString currCWD = wxGetCwd();
3344 wxString workCWD = fn.GetPath();
3346 if( !workCWD.IsEmpty() )
3347 wxSetWorkingDirectory( workCWD );
3349 wxString tmpfname(
"$tempfile$.step" );
3351 if(
false == writer.Write( tmpfname.c_str() ) )
3354 if( compress && success )
3356 wxString srcTmp( tmpfname );
3357 wxString dstTmp(
"$tempfile$.stpz" );
3360 wxRemoveFile( srcTmp );
3371 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3373 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3381 wxSetWorkingDirectory( currCWD );
3391 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3400 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3405 wxFileName fn( aFileName );
3407 wxFFileOutputStream ffStream( fn.GetFullPath() );
3408 wxStdOutputStream stdStream( ffStream );
3410#if OCC_VERSION_HEX >= 0x070600
3411 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3413 BRepTools::Write( shape, stdStream );
3422 wxFileName fn( aFileName );
3424 wxFFileOutputStream ffStream( fn.GetFullPath() );
3425 wxStdOutputStream file( ffStream );
3427 if( !ffStream.IsOk() )
3429 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3437 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3442 std::map<wxString, std::vector<int>> groups[4];
3443 std::map<wxString, double> groupAreas;
3444 TopExp_Explorer exp;
3447 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3449 TopoDS_Shape subShape = exp.Current();
3452 BRepBndLib::Add( subShape, bbox );
3456 for(
const auto& pair : pairs )
3458 const auto& [point, padTestShape] = pair;
3460 if( bbox.IsOut( point ) )
3463 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3465 if( surface.GetType() != GeomAbs_Plane )
3468 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3471 if( !dist.IsDone() )
3474 if( dist.Value() < Precision::Approximation() )
3477 groups[2][padKey].push_back( faceIndex );
3479 GProp_GProps system;
3480 BRepGProp::SurfaceProperties( subShape, system );
3482 double surfaceArea = system.Mass() / 1e6;
3483 groupAreas[padKey] += surfaceArea;
3492 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3493 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3494 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3495 file <<
" <shape format=\"BREP\"><![CDATA[";
3496#if OCC_VERSION_HEX < 0x070600
3497 BRepTools::Write( shape, file );
3499 BRepTools::Write( shape, file,
true,
true, TopTools_FormatVersion_VERSION_1 );
3501 file <<
"]]></shape>" << std::endl;
3502 file <<
" <topology>" << std::endl;
3504 TopTools_IndexedMapOfShape mainMap;
3505 TopExp::MapShapes( shape, mainMap );
3506 std::set<int> topo[4];
3508 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3511 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3512 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3514 for(
int dim = 0; dim < 4; dim++ )
3516 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3518 TopoDS_Shape subShape = exp.Current();
3519 int idx = mainMap.FindIndex( subShape );
3521 if( idx && !topo[dim].count( idx ) )
3522 topo[dim].insert( idx );
3526 for(
int dim = 0; dim <= 3; dim++ )
3528 std::string labels = c_dimLabels[dim];
3529 std::string label = c_dimLabel[dim];
3531 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3534 for(
auto p : topo[dim] )
3536 std::string
name(
"" );
3537 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3538 <<
"name=\"" <<
name <<
"\" "
3539 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3543 file <<
" </" << labels <<
">" << std::endl;
3546 file <<
" </topology>" << std::endl;
3547 file <<
" </geometry>" << std::endl;
3548 file <<
" <groups count=\""
3549 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3552 int groupNumber = 1;
3557 for(
int dim = 0; dim <= 3; dim++ )
3559 std::string label = c_dimLabel[dim];
3561 for(
auto g : groups[dim] )
3564 wxString
name = g.first;
3568 std::ostringstream gs;
3569 gs <<
"G_" << dim <<
"D_" << g.first;
3572 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3578 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3580 for(
auto index : g.second )
3581 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3583 file <<
" </group>" << std::endl;
3585 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3597 file <<
" </groups>" << std::endl;
3598 file <<
" <fields count=\"0\"/>" << std::endl;
3599 file <<
"</XAO>" << std::endl;
3606 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3607 TDF_Label& aLabel,
bool aSubstituteModels,
3608 wxString* aErrorMessage )
3610 std::string fileNameUTF8 = aFileName.utf8_string();
3612 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3613 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3615 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3619 aLabel = mm->second;
3625 Handle( TDocStd_Document ) doc;
3626 m_app->NewDocument(
"MDTV-XCAF", doc );
3629 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3634 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3636 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3644 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3646 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3657 wxFFileInputStream ifile( aFileName );
3658 wxFileName outFile( aFileName );
3660 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3661 outFile.SetExt( wxT(
"step" ) );
3662 wxFileOffset size = ifile.GetLength();
3664 if( size == wxInvalidOffset )
3666 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3673 bool success =
false;
3676 wxFFileOutputStream ofile( outFile.GetFullPath() );
3681 char* buffer =
new char[size];
3683 ifile.Read( buffer, size );
3684 std::string expanded;
3688 expanded = gzip::decompress( buffer, size );
3696 if( expanded.empty() )
3700 wxZipInputStream izipfile( ifile );
3701 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3703 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3705 izipfile.Read( ofile );
3710 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3716 ofile.Write( expanded.data(), expanded.size() );
3724 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3725 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3744 if( aSubstituteModels )
3746 wxFileName wrlName( aFileName );
3748 wxString basePath = wrlName.GetPath();
3749 wxString baseName = wrlName.GetName();
3757 alts.Add( wxT(
"stp" ) );
3758 alts.Add( wxT(
"step" ) );
3759 alts.Add( wxT(
"STP" ) );
3760 alts.Add( wxT(
"STEP" ) );
3761 alts.Add( wxT(
"Stp" ) );
3762 alts.Add( wxT(
"Step" ) );
3763 alts.Add( wxT(
"stpz" ) );
3764 alts.Add( wxT(
"stpZ" ) );
3765 alts.Add( wxT(
"STPZ" ) );
3766 alts.Add( wxT(
"step.gz" ) );
3767 alts.Add( wxT(
"stp.gz" ) );
3770 alts.Add( wxT(
"iges" ) );
3771 alts.Add( wxT(
"IGES" ) );
3772 alts.Add( wxT(
"igs" ) );
3773 alts.Add( wxT(
"IGS" ) );
3777 for(
const auto& altExt : alts )
3781 if( !aAltFilenames.empty() )
3783 for(
const wxString& altPath : aAltFilenames )
3785 wxFileName iterFn( altPath );
3787 if( iterFn.GetExt() == altExt )
3796 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3799 if( altFile.IsOk() && altFile.FileExists() )
3809 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3823 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3825 Handle( XCAFDoc_ShapeTool ) shapeTool =
3826 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3833 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3843 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3853 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3860 if( aLabel.IsNull() )
3862 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3869 TDataStd_Name::Set( aLabel, partname );
3879 TopLoc_Location& aLocation )
3893 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3899 double boardThickness;
3902 double top = std::max( boardZPos, boardZPos + boardThickness );
3903 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3908 double f_pos, f_thickness;
3912 bottom += f_thickness;
3919 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3920 lPos.Multiply( lRot );
3921 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3922 lPos.Multiply( lRot );
3927 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3928 lPos.Multiply( lRot );
3932 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3933 lPos.Multiply( lOff );
3936 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3937 lPos.Multiply( lOrient );
3938 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3939 lPos.Multiply( lOrient );
3940 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3941 lPos.Multiply( lOrient );
3943 aLocation = TopLoc_Location( lPos );
3950 IGESControl_Controller::Init();
3951 IGESCAFControl_Reader reader;
3952 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3954 if( stat != IFSelect_RetDone )
3958 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3962 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3966 reader.SetColorMode(
true );
3967 reader.SetNameMode(
false );
3968 reader.SetLayerMode(
false );
3970 if( !reader.Transfer( doc ) )
3972 if( doc->CanClose() == CDM_CCS_OK )
3979 if( reader.NbShapes() < 1 )
3981 if( doc->CanClose() == CDM_CCS_OK )
3993 STEPCAFControl_Reader reader;
3994 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3996 if( stat != IFSelect_RetDone )
4000 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
4004 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
4008 reader.SetColorMode(
true );
4009 reader.SetNameMode(
true );
4010 reader.SetLayerMode(
false );
4012 if( !reader.Transfer( doc ) )
4014 if( doc->CanClose() == CDM_CCS_OK )
4021 if( reader.NbRootsForTransfer() < 1 )
4023 if( doc->CanClose() == CDM_CCS_OK )
4035#if OCC_VERSION_HEX >= 0x070700
4036 VrmlAPI_CafReader reader;
4037 RWMesh_CoordinateSystemConverter conv;
4038 conv.SetInputLengthUnit( 2.54 );
4039 reader.SetCoordinateSystemConverter( conv );
4040 reader.SetDocument( doc );
4042 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
4055 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool(
source->Main() );
4057 NCollection_Sequence<TDF_Label> frshapes;
4058 s_assy->GetFreeShapes( frshapes );
4060 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
4069 TDF_Label d_targetLabel = d_assy->NewShape();
4071 if( !XCAFDoc_Editor::Extract( frshapes, d_targetLabel,
false ) )
4077 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
4080 return d_targetLabel;
4086 NCollection_Sequence<TDF_Label> freeShapes;
4087 aShapeTool->GetFreeShapes( freeShapes );
4093 for(
int i = 1; i <= freeShapes.Length(); ++i )
4095 TDF_Label label = freeShapes.Value( i );
4097 aShapeTool->GetShape( label, shape );
4102 const double linearDeflection = 0.14;
4103 const double angularDeflection =
DEG2RAD( 30.0 );
4104 BRepMesh_IncrementalMesh mesh( shape, linearDeflection,
false, angularDeflection,
4126 wxFileName fn( aFileName );
4128 const char* tmpGltfname =
"$tempfile$.glb";
4129 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
4131 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
4132 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4133 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
4134 RWMesh_CoordinateSystem_Zup );
4135#if OCC_VERSION_HEX >= 0x070700
4136 cafWriter.SetParallel(
true );
4138 TColStd_IndexedDataMapOfStringString metadata;
4140 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4141 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4142 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4143 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4144 metadata.Add( TCollection_AsciiString(
"generator" ),
4145 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
4146 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4149 bool success =
true;
4152 wxString currCWD = wxGetCwd();
4153 wxString workCWD = fn.GetPath();
4155 if( !workCWD.IsEmpty() )
4156 wxSetWorkingDirectory( workCWD );
4158 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4167 m_reporter->Report(
_(
"Could not post-process GLB line primitives; the exported "
4168 "model may not import in strict glTF viewers." ),
4175 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4177 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4185 wxSetWorkingDirectory( currCWD );
4193#if OCC_VERSION_HEX < 0x070700
4200 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4210 wxFileName fn( aFileName );
4212 const char* tmpFname =
"$tempfile$.ply";
4213 RWPly_CafWriter cafWriter( tmpFname );
4215 cafWriter.SetFaceId(
true );
4216 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4217 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4219 TColStd_IndexedDataMapOfStringString metadata;
4221 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4222 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4223 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4224 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4225 metadata.Add( TCollection_AsciiString(
"generator" ),
4226 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4228 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4231 bool success =
true;
4234 wxString currCWD = wxGetCwd();
4235 wxString workCWD = fn.GetPath();
4237 if( !workCWD.IsEmpty() )
4238 wxSetWorkingDirectory( workCWD );
4240 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4247 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4249 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4257 wxSetWorkingDirectory( currCWD );
4268 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4278 wxFileName fn( aFileName );
4280 const char* tmpFname =
"$tempfile$.stl";
4283 wxString currCWD = wxGetCwd();
4284 wxString workCWD = fn.GetPath();
4286 if( !workCWD.IsEmpty() )
4287 wxSetWorkingDirectory( workCWD );
4289 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4296 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4298 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4306 wxSetWorkingDirectory( currCWD );
4318 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4327 wxFileName fn( aFileName );
4329 const char* tmpFname =
"$tempfile$.u3d";
4332 wxString currCWD = wxGetCwd();
4333 wxString workCWD = fn.GetPath();
4335 if( !workCWD.IsEmpty() )
4336 wxSetWorkingDirectory( workCWD );
4339 bool success = writer.
Perform( m_doc );
4345 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4347 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4354 wxSetWorkingDirectory( currCWD );
4365 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4374 wxFileName fn( aFileName );
4376 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4377 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4379 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4380 bool success = writer.
Perform( m_doc );
4383 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4385 plotter->SetColorMode(
true );
4386 plotter->Set3DExport(
true );
4389 plotter->SetRenderSettings( &renderSettings );
4391 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4393 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4399 plotter->StartPlot(
"1",
"3D Model" );
4400 double fov_degrees = 16.5f;
4405 std::vector<PDF_3D_VIEW> views;
4410 std::vector<float> c2wMatrix =
4414 .m_name =
"Default",
4415 .m_cameraMatrix = c2wMatrix,
4416 .m_cameraCenter = (float)
distance,
4417 .m_fov = (
float) fov_degrees,
4426 .m_cameraMatrix = c2wMatrix,
4427 .m_cameraCenter = (float)
distance,
4428 .m_fov = (
float) fov_degrees,
4437 .m_cameraMatrix = c2wMatrix,
4438 .m_cameraCenter = (float)
distance,
4439 .m_fov = (
float) fov_degrees,
4448 .m_cameraMatrix = c2wMatrix,
4449 .m_cameraCenter = (float)
distance,
4450 .m_fov = (
float) fov_degrees,
4453 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4462 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4464 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4465 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4471 wxRemoveFile( u3dTmpfn.GetFullPath() );
bool GetExtrusionPinOutlines(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly, SHAPE_POLY_SET &aPegPoly)
Get the hole outline polygons for extruded pin rendering.
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetMajorMinorPatchVersion()
Get the major, minor and patch version in a string major.minor.patch This is extracted by CMake from ...
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetNetname() const
const wxString & GetShortNetname() const
FOOTPRINT * GetParentFootprint() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
PCB specific render settings.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
PAD_PROP GetProperty() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
VECTOR2I GetDrillSize() const
static std::vector< float > CreateC2WMatrixFromAngles(const VECTOR3D &aTargetPosition, float aCameraDistance, float aYawDegrees, float aPitchDegrees, float aRollDegrees)
Generates the camera to world matrix for use with a 3D View.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
const VECTOR2I & GetArcMid() const
VECTOR2I NearestPoint(const VECTOR2I &aP) const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
const std::optional< INTERSECTION > SelfIntersectingWithArcs() const
Check if the line chain is self-intersecting.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
virtual size_t GetSegmentCount() const override
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int FullPointCount() const
Return the number of points in the shape poly set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
const POLYGON & CPolygon(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
const SEG & GetSeg() const
int GetWidth() const override
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
OUTPUT_FORMAT m_outFmt
The current output format for created file.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
bool WritePLY(const wxString &aFileName)
bool AddCountersink(const VECTOR2I &aPosition, int aDiameter, int aDepth, int aAngle, bool aFrontSide, const VECTOR2D &aOrigin)
Add a countersink shape to remove board material from the top or bottom of a hole.
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_vias
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_pads
bool WriteSTEP(const wxString &aFileName, bool aOptimize, bool compress)
std::vector< TopoDS_Shape > m_board_back_mask
bool AddExtrudedPins(const FOOTPRINT *aFootprint, const EXTRUDED_3D_BODY *aBody, bool aBottom, double aStandoff, const VECTOR2D &aOrigin)
Add pin extrusions for pad holes.
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
std::vector< TopoDS_Shape > m_boardCutouts
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
bool CreatePCB(SHAPE_POLY_SET &aOutline, const VECTOR2D &aOrigin, bool aPushBoardBody)
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
double getStackupBodyThickness() const
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, const VECTOR3D &aScale)
bool getModelLocation(bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, TopLoc_Location &aLocation)
void SetFuseShapes(bool aValue)
bool WriteXAO(const wxString &aFileName)
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
std::vector< TDF_Label > m_pcb_labels
STEP_PCB_MODEL(const wxString &aPcbName, REPORTER *aReporter)
std::vector< EXTRUDED_BODY_ENTRY > m_extruded_bodies
bool AddBackdrill(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerStart, PCB_LAYER_ID aLayerEnd, const VECTOR2D &aOrigin)
Add a backdrill hole shape to remove board material and copper plating.
void getLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_outlines
void SetSimplifyShapes(bool aValue)
bool WriteU3D(const wxString &aFileName)
SYNC_REPORTER m_syncReporter
Thread-safe wrapper around the caller's reporter.
bool getModelLabel(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
bool AddCounterbore(const VECTOR2I &aPosition, int aDiameter, int aDepth, bool aFrontSide, const VECTOR2D &aOrigin)
Add a counterbore shape to remove board material from the top or bottom of a hole.
void SetEnabledLayers(const LSET &aLayers)
void SetExtraPadThickness(bool aValue)
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
std::vector< TopoDS_Shape > m_board_front_silk
Handle(XCAFApp_Application) m_app
bool WritePDF(const wxString &aFileName)
virtual ~STEP_PCB_MODEL()
std::vector< TopoDS_Shape > m_board_front_mask
bool WriteSTL(const wxString &aFileName)
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
std::map< PCB_LAYER_ID, int > GetCopperLayerKnockouts(int aDiameter, int aDepth, int aAngle, bool aFrontSide)
Get the knockout diameters for copper layers that a counterbore or countersink crosses.
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
std::vector< TopoDS_Shape > m_copperCutouts
bool CompressSTEP(wxString &inputFile, wxString &outputFile)
std::vector< TopoDS_Shape > m_board_back_silk
void getCopperLayerZPlacement(PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
bool AddComponent(const wxString &aBaseName, const wxString &aFileName, const std::vector< wxString > &aAltFilenames, const wxString &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
bool AddExtrudedBody(const SHAPE_POLY_SET &aOutline, bool aBottom, double aStandoff, double aHeight, const VECTOR2D &aOrigin, uint32_t aColor, EXTRUSION_MATERIAL aMaterial, const wxString &aRefDes)
Add an extruded 3D body from a 2D outline polygon.
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
bool Perform(const Handle(TDocStd_Document) &aDocument)
const VECTOR3D & GetCenter() const
const Bnd_Box & GetMeshBoundingBox() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
bool FixGlbLinesPrimitives(const wxString &aFilePath)
Fix LINES primitives in a GLB file that have odd index counts.
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
Handle(KICAD3D_INFO) KICAD3D_INFO
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static bool rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
static TopoDS_Shape fuseShapesOrCompound(const NCollection_List< TopoDS_Shape > &aInputShapes, REPORTER *aReporter)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
static bool prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static constexpr double USER_ANGLE_PREC
static constexpr double USER_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
static constexpr double BOARD_THICKNESS_DEFAULT_MM
std::pair< std::string, TDF_Label > MODEL_DATUM
static constexpr double BOARD_THICKNESS_MIN_MM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D