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>
72#include <IGESCAFControl_Reader.hxx>
73#include <IGESCAFControl_Writer.hxx>
74#include <IGESControl_Controller.hxx>
75#include <IGESData_GlobalSection.hxx>
76#include <IGESData_IGESModel.hxx>
77#include <Interface_Static.hxx>
78#include <Quantity_Color.hxx>
79#include <STEPCAFControl_Reader.hxx>
80#include <STEPCAFControl_Writer.hxx>
81#include <APIHeaderSection_MakeHeader.hxx>
82#include <Standard_Failure.hxx>
83#include <Standard_Handle.hxx>
84#include <Standard_Version.hxx>
85#include <TCollection_ExtendedString.hxx>
86#include <TDocStd_Document.hxx>
87#include <TDocStd_XLinkTool.hxx>
88#include <TDataStd_Name.hxx>
89#include <TDataStd_TreeNode.hxx>
90#include <TDF_ChildIterator.hxx>
91#include <TDF_LabelSequence.hxx>
92#include <TDF_Tool.hxx>
93#include <TopExp_Explorer.hxx>
95#include <XCAFApp_Application.hxx>
97#include <XCAFDoc_DocumentTool.hxx>
98#include <XCAFDoc_ColorTool.hxx>
99#include <XCAFDoc_ShapeTool.hxx>
100#include <XCAFDoc_VisMaterialTool.hxx>
101#include <XCAFDoc_Area.hxx>
102#include <XCAFDoc_Centroid.hxx>
103#include <XCAFDoc_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 <GProp_GProps.hxx>
130#include <BRepGProp.hxx>
132#include <Geom_Curve.hxx>
133#include <Geom_TrimmedCurve.hxx>
138#include <GC_MakeArcOfCircle.hxx>
139#include <GC_MakeCircle.hxx>
141#include <RWGltf_CafWriter.hxx>
142#include <StlAPI_Writer.hxx>
144#if OCC_VERSION_HEX >= 0x070700
145#include <VrmlAPI_CafReader.hxx>
146#include <RWPly_CafWriter.hxx>
174 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
176 if( !lfile.FileExists() )
179 wxString ext = lfile.GetExt().Lower();
181 if( ext == wxT(
"wrl" ) )
184 if( ext == wxT(
"wrz" ) )
187 if( ext == wxT(
"idf" ) )
190 if( ext == wxT(
"emn" ) )
193 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
207 const int max_line_count = 3;
209 for(
int ii = 0; ii < max_line_count; ii++ )
211 memset( iline, 0, 82 );
212 ifile.getline( iline, 82 );
218 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
224 std::string fstr = iline;
228 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
237 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
244 if( strncmp( iline,
"/*", 2 ) != 0 )
262 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
263 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
264 double det = -b.
x * d.
y + d.
x * b.
y;
268 center.x = ( -bc * d.
y - cd * b.
y ) * det;
269 center.y = ( b.
x * cd + d.
x * bc ) * det;
276#define APPROX_DBG( stmt )
284 static const double c_radiusDeviation = 1000.0;
285 static const double c_arcCenterDeviation = 1000.0;
286 static const double c_relLengthDeviation = 0.8;
287 static const int c_last_none = -1000;
289 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
290 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
307 int last = c_last_none;
313 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
315 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
320 bool defective =
false;
326 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
334 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
335 defective |=
std::abs( a_diff ) < 0.1;
338 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
339 defective |=
std::abs( a_diff ) >= maxAngleDiff;
350 for(
int j = i; j <= jEndIdx; j++ )
355 double rad_test = ( p_test -
center ).EuclideanNorm();
356 double d_tl = ( p_test - p_prev ).EuclideanNorm();
360 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
363 if( rad_dev > c_radiusDeviation )
366 <<
" Radius deviation too large: " << int64_t( rad_dev )
367 <<
" > " << c_radiusDeviation << std::endl );
372 double maxAngleDiff =
373 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
375 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
376 if(
std::abs( a_diff_test ) >= maxAngleDiff )
378 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
383 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
385 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
386 <<
"; " << d01 << std::endl );
396 if( last != c_last_none )
405 int toRemove = last - ( aSrc.
PointCount() - 3 );
435 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
439 if( last == c_last_none )
456 if( iarc0 != -1 && iarc1 != -1 )
458 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
468 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
486 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
487 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
505 TDF_LabelSequence theLabels;
506 aShapeTool->GetFreeShapes( theLabels );
510 if( theLabels.Length() == 1 )
511 return aShapeTool->GetShape( theLabels.Value( 1 ) );
513 TopoDS_Compound aCompound;
514 BRep_Builder aBuilder;
515 aBuilder.MakeCompound( aCompound );
517 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
519 TopoDS_Shape aFreeShape;
521 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
524 aBuilder.Add( aCompound, aFreeShape );
527 if( aCompound.NbChildren() > 0 )
536static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
538 if( theLabel.IsNull() )
540 Message::SendFail(
"Null label." );
541 return Standard_False;
544 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
545 || Abs( aScale.Z() ) <= gp::Resolution() )
547 Message::SendFail(
"Scale factor is too small." );
548 return Standard_False;
551 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
553 if( aShapeTool.IsNull() )
555 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
556 return Standard_False;
559 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
563 Message::SendFail(
"Couldn't create assembly graph." );
564 return Standard_False;
567 Standard_Boolean anIsDone = Standard_True;
571 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
573 0, 0, aScale.Z() ) );
576 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
578 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
580 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
582 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
583 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
588 const TDF_Label& aLabel = aG->GetNode( idx );
590 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
592 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
593 aBRepTrsf.Perform( aShape, Standard_True );
594 if( !aBRepTrsf.IsDone() )
596 Standard_SStream aSS;
597 TCollection_AsciiString anEntry;
598 TDF_Tool::Entry( aLabel, anEntry );
599 aSS <<
"Shape " << anEntry <<
" is not scaled!";
600 Message::SendFail( aSS.str().c_str() );
601 anIsDone = Standard_False;
602 return Standard_False;
604 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
605 aShapeTool->SetShape( aLabel, aScaledShape );
608 TDF_LabelSequence aSubshapes;
609 aShapeTool->GetSubShapes( aLabel, aSubshapes );
610 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
612 const TDF_Label& aLSs = anItSs.Value();
613 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
614 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
615 aShapeTool->SetShape( aLSs, aSs1 );
619 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
620 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
621 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
623 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
625 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
626 gp_Trsf aTrsf = aLoc.Transformation();
627 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
628 XCAFDoc_Location::Set( aLabel, aTrsf );
634 return Standard_False;
637 aShapeTool->UpdateAssemblies();
645 BRepAlgoAPI_Fuse mkFuse;
646 TopTools_ListOfShape shapeArguments, shapeTools;
648 for( TopoDS_Shape& sh : aInputShapes )
653 if( shapeArguments.IsEmpty() )
654 shapeArguments.Append( sh );
656 shapeTools.Append( sh );
661 mkFuse.SetRunParallel(
true );
662 mkFuse.SetToFillHistory(
false );
663 mkFuse.SetArguments( shapeArguments );
664 mkFuse.SetTools( shapeTools );
667 catch(
const std::bad_alloc& )
669 aReporter->
Report(
_(
"Out of memory while fusing shapes. Consider disabling shape fusing, "
670 "reducing the number of objects (e.g., vias), or freeing system memory." ),
674 catch(
const Standard_Failure& e )
676 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while fusing shapes: %s\n"
677 "This may indicate insufficient memory. Consider "
678 "disabling shape fusing or reducing board complexity." ),
679 e.GetMessageString() ),
684 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
686 aReporter->
Report(
_(
"Problems encountered while fusing shapes. This operation is "
687 "memory-intensive; insufficient memory may cause failures." ),
690 if( mkFuse.HasErrors() )
692 wxString msg =
_(
"Errors:\n" );
693 wxStringOutputStream os_stream( &msg );
694 wxStdOutputStream out( os_stream );
696 mkFuse.DumpErrors( out );
700 if( mkFuse.HasWarnings() )
702 wxString msg =
_(
"Warnings:\n" );
703 wxStringOutputStream os_stream( &msg );
704 wxStdOutputStream out( os_stream );
706 mkFuse.DumpWarnings( out );
711 if( mkFuse.IsDone() )
713 TopoDS_Shape fusedShape = mkFuse.Shape();
717 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
718 unify.History() =
nullptr;
721 TopoDS_Shape unifiedShapes = unify.Shape();
723 if( unifiedShapes.IsNull() )
725 aReporter->
Report(
_(
"ShapeUpgrade_UnifySameDomain produced a null shape." ),
730 aOutShape = unifiedShapes;
734 catch(
const std::bad_alloc& )
736 aReporter->
Report(
_(
"Out of memory while unifying shape domains. Consider disabling "
737 "shape fusing or reducing the number of objects." ),
741 catch(
const Standard_Failure& e )
743 aReporter->
Report( wxString::Format(
_(
"OpenCASCADE error while unifying shapes: %s" ),
744 e.GetMessageString() ),
756 TopoDS_Compound compound;
757 BRep_Builder builder;
758 builder.MakeCompound( compound );
760 for(
const TopoDS_Shape& shape : aInputShapes )
761 builder.Add( compound, shape );
771 TopoDS_Shape outShape;
773 if( aInputShapes.Size() == 1 )
774 return aInputShapes.First();
776 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
785 const TCollection_ExtendedString& aPrefix )
787 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
791 Message::SendFail(
"Couldn't create assembly graph." );
792 return Standard_False;
795 Standard_Boolean anIsDone = Standard_True;
797 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
799 const TDF_Label& lbl = aG->GetNode( idx );
800 Handle( TDataStd_Name ) nameHandle;
802 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
804 TCollection_ExtendedString
name;
808 name += nameHandle->Get();
811 TDataStd_Name::Set( lbl,
name );
815 TDataStd_Name::Set( lbl, aPrefix );
826 m_app = XCAFApp_Application::GetApplication();
827 m_app->NewDocument(
"MDTV-XCAF", m_doc );
828 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
846 if( m_doc->CanClose() == CDM_CCS_OK )
854 const double c_padExtraThickness = 0.005;
856 std::vector<TopoDS_Shape> padShapes;
870 double Zpos, thickness;
876 if( pcb_layer ==
F_Cu )
877 thickness += c_padExtraThickness;
878 else if( pcb_layer ==
B_Cu )
879 thickness -= c_padExtraThickness;
882 TopoDS_Shape testShape;
896 if( testShape.IsNull() )
898 std::vector<TopoDS_Shape> testShapes;
902 if( testShapes.size() > 0 )
903 testShape = testShapes.front();
908 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
914 if( pcb_layer ==
F_Cu )
916 else if( pcb_layer ==
B_Cu )
932 double f_pos, f_thickness;
933 double b_pos, b_thickness;
940 f_thickness += c_padExtraThickness;
941 b_thickness -= c_padExtraThickness;
944 double top = std::max( f_pos, f_pos + f_thickness );
945 double bottom = std::min( b_pos, b_pos + b_thickness );
946 double hole_height =
top - bottom;
948 TopoDS_Shape plating;
956 hole_height, bottom, aOrigin ) )
958 padShapes.push_back( plating );
972 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
989 padShapes.push_back( plating );
1001 if( !padShapes.empty() )
1006 TopTools_ListOfShape padShapesList;
1008 for(
const TopoDS_Shape& shape : padShapes )
1009 padShapesList.Append( shape );
1015 for(
const TopoDS_Shape& shape : padShapes )
1026 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
1028 double margin = 0.001;
1036 double f_pos, f_thickness;
1037 double b_pos, b_thickness;
1040 double top = std::max( f_pos, f_pos + f_thickness );
1041 double bottom = std::min( b_pos, b_pos + b_thickness );
1043 double holeZsize = (
top - bottom ) + ( margin * 2 );
1045 double boardDrill = aShape.
GetWidth();
1046 double copperDrill = boardDrill - aPlatingThickness * 2;
1048 TopoDS_Shape copperHole, boardHole;
1053 holeZsize, bottom - margin, aOrigin ) )
1066 holeZsize, bottom - margin, aOrigin ) )
1082 const wxString& aNetname )
1084 double f_pos, f_thickness;
1085 double b_pos, b_thickness;
1088 double top = std::max( f_pos, f_pos + f_thickness );
1089 double bottom = std::min( b_pos, b_pos + b_thickness );
1091 TopoDS_Shape plating;
1094 (
top - bottom ), bottom, aOrigin ) )
1116 double margin = 0.001;
1120 double copperMargin = 0.5;
1122 double start_pos, start_thickness;
1123 double end_pos, end_thickness;
1128 double top = std::max( { start_pos, start_pos + start_thickness,
1129 end_pos, end_pos + end_thickness } );
1130 double bottom = std::min( { start_pos, start_pos + start_thickness,
1131 end_pos, end_pos + end_thickness } );
1134 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1135 top += copperMargin;
1136 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1137 bottom -= copperMargin;
1139 double holeZsize = (
top - bottom ) + ( margin * 2 );
1140 double holeZpos = bottom - margin;
1142 double backdrillDiameter = aShape.
GetWidth();
1144 TopoDS_Shape backdrillHole;
1148 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1165 bool aFrontSide,
const VECTOR2D& aOrigin )
1167 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1168 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1171 if( aDiameter <= 0 || aDepth <= 0 )
1173 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1174 aDiameter, aDepth );
1178 double margin = 0.001;
1181 double copperMargin = 0.5;
1184 double boardZpos, boardThickness;
1188 double f_pos, f_thickness, b_pos, b_thickness;
1195 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1196 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1198 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1199 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1202 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1203 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1204 double radius_mm = diameter_mm / 2.0;
1206 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1207 diameter_mm, depth_mm, radius_mm );
1211 double cylinderZpos;
1212 double cylinderHeight;
1218 cylinderZpos = topOuterSurface - depth_mm - margin;
1219 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1225 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1226 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1230 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1231 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1233 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1234 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1240 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1242 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1244 if( cylinder.IsNull() )
1246 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1247 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1256 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1259 catch(
const Standard_Failure& e )
1261 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1262 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1263 e.GetMessageString() ),
1273 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1275 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1276 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1281 if( aDiameter <= 0 || aAngle <= 0 )
1283 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1284 aDiameter, aAngle );
1288 double margin = 0.001;
1291 double copperMargin = 0.5;
1294 double boardZpos, boardThickness;
1298 double f_pos, f_thickness, b_pos, b_thickness;
1303 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1304 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1306 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1307 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1310 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1311 double radius_mm = diameter_mm / 2.0;
1315 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1323 depth_mm = radius_mm / tan( halfAngleRad );
1324 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1325 depth_mm, radius_mm );
1332 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1333 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1344 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1346 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1347 bottomRadius_mm, tan( halfAngleRad ) );
1349 if( bottomRadius_mm < 0 )
1350 bottomRadius_mm = 0;
1355 double coneHeight = depth_mm + copperMargin + margin;
1359 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1360 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1371 coneZpos = topOuterSurface - depth_mm - margin;
1372 r1 = bottomRadius_mm;
1374 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1376 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1377 coneZpos, r1, r2, coneHeight );
1379 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1380 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1387 coneZpos = bottomOuterSurface - copperMargin - margin;
1389 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1390 r2 = bottomRadius_mm;
1392 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1393 coneZpos, r1, r2, coneHeight );
1395 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1396 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1401 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1402 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1411 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1414 catch(
const Standard_Failure& e )
1416 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1417 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1418 e.GetMessageString() ),
1428 int aAngle,
bool aFrontSide )
1430 std::map<PCB_LAYER_ID, int> knockouts;
1433 double f_pos, f_thickness, b_pos, b_thickness;
1437 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1438 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1441 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1442 double radius_mm = diameter_mm / 2.0;
1446 double halfAngleRad = 0.0;
1451 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1455 depth_mm = radius_mm / tan( halfAngleRad );
1466 double featureTop, featureBottom;
1470 featureTop = topOuterSurface;
1471 featureBottom = topOuterSurface - depth_mm;
1475 featureBottom = bottomOuterSurface;
1476 featureTop = bottomOuterSurface + depth_mm;
1479 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1480 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1489 double layerZ, layerThickness;
1493 double layerTop = std::max( layerZ, layerZ + layerThickness );
1494 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1498 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1500 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1501 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1506 int knockoutDiameter;
1512 double layerSurfaceZ;
1516 layerSurfaceZ = layerTop;
1521 layerSurfaceZ = layerBottom;
1525 double distanceFromSurface;
1527 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1529 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1532 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1534 if( radiusAtLayer_mm <= 0 )
1536 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1537 static_cast<int>( layer ) );
1541 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1542 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1543 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1548 knockoutDiameter = aDiameter;
1549 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1550 static_cast<int>( layer ), knockoutDiameter );
1553 knockouts[layer] = knockoutDiameter;
1561 double& aThickness )
1564 static const double c_silkscreenAboveCopper = 0.04;
1565 static const double c_soldermaskAboveCopper = 0.015;
1573 double f_pos, f_thickness;
1575 double top = std::max( f_pos, f_pos + f_thickness );
1578 aZPos =
top + c_silkscreenAboveCopper;
1580 aZPos =
top + c_soldermaskAboveCopper;
1586 double b_pos, b_thickness;
1588 double bottom = std::min( b_pos, b_pos + b_thickness );
1591 aZPos = bottom - c_silkscreenAboveCopper;
1593 aZPos = bottom - c_soldermaskAboveCopper;
1601 double& aThickness )
1605 bool wasPrepreg =
false;
1607 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1610 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1616 if( aLayer ==
B_Cu )
1661 double f_pos, f_thickness;
1662 double b_pos, b_thickness;
1665 double top = std::min( f_pos, f_pos + f_thickness );
1666 double bottom = std::max( b_pos, b_pos + b_thickness );
1668 aThickness = (
top - bottom );
1671 wxASSERT( aZPos == 0.0 );
1676 const VECTOR2D& aOrigin,
const wxString& aNetname )
1678 bool success =
true;
1686 double z_pos, thickness;
1689 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1697 else if( aLayer ==
F_Mask )
1704 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1717 const std::vector<wxString>& aAltFilenames,
1718 const wxString& aRefDes,
bool aBottom,
VECTOR2D aPosition,
1720 VECTOR3D aScale,
bool aSubstituteModels )
1722 if( aFileName.empty() )
1724 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1733 wxString errorMessage;
1735 if( !
getModelLabel( aBaseName, aFileName, aAltFilenames, aScale, lmodel, aSubstituteModels,
1738 if( errorMessage.IsEmpty() )
1739 errorMessage.Printf(
_(
"No model for filename '%s'." ), aFileName );
1746 TopLoc_Location toploc;
1748 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1751 wxString::Format(
_(
"No location data for filename '%s'." ), aFileName ),
1757 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1759 if( llabel.IsNull() )
1762 wxString::Format(
_(
"Could not add component with filename '%s'." ), aFileName ),
1768 TCollection_ExtendedString refdes( aRefDes.utf8_str() );
1769 TDataStd_Name::Set( llabel, refdes );
1843 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1844 double aZposition,
const VECTOR2D& aOrigin )
1851 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1852 double h_width = aWidth/2.0;
1854 coords[0] =
VECTOR2D{ 0.0, h_width };
1857 coords[1] =
VECTOR2D{ len, h_width };
1860 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1863 coords[3] =
VECTOR2D{ len, -h_width };
1866 coords[4] =
VECTOR2D{ 0, -h_width };
1869 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1872 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1874 for(
int ii = 0; ii < 6; ii++ )
1877 coords[ii] += aStartPoint;
1882 gp_Pnt coords3D[ 6 ];
1884 for(
int ii = 0; ii < 6; ii++ )
1886 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1887 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1891 BRepBuilderAPI_MakeWire wire;
1892 bool success =
true;
1904 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1909 edge = BRepBuilderAPI_MakeEdge(
circle );
1914 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1917 Handle( Geom_TrimmedCurve ) arcOfCircle =
1918 GC_MakeArcOfCircle( coords3D[1],
1922 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1925 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1928 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1929 GC_MakeArcOfCircle( coords3D[4],
1933 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1937 catch(
const Standard_Failure& e )
1939 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
1940 e.GetMessageString() ),
1945 BRepBuilderAPI_MakeFace face;
1949 gp_Pln plane( coords3D[0], gp::DZ() );
1950 face = BRepBuilderAPI_MakeFace( plane, wire );
1952 catch(
const Standard_Failure& e )
1954 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
1955 e.GetMessageString() ),
1960 if( aThickness != 0.0 )
1962 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1964 if( aShape.IsNull() )
1966 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
1983 double aZposition,
const VECTOR2D& aOrigin )
1985 std::vector<TopoDS_Shape> testShapes;
1988 aHeight, aZposition, aOrigin );
1990 if( testShapes.size() > 0 )
1991 aShape = testShapes.front();
2014 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
2018 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2020 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2021 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2031 gp_Pnt start = toPoint( aPt0 );
2032 gp_Pnt
end = toPoint( aPt1 );
2034 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
2036 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
2038 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2046 aMkWire.Add( mkEdge.Edge() );
2048 if( aMkWire.Error() != BRepLib_WireDone )
2050 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2064 Handle( Geom_Curve ) curve;
2066 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2068 gp_Ax2 axis = gp::XOY();
2069 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2071 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2075 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2076 toPoint( aArc.GetP1() ) ).Value();
2079 if( curve.IsNull() )
2082 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2084 if( !aMkWire.IsDone() )
2086 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2087 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2089 aArc.GetP0().x, aArc.GetP0().y,
2090 aArc.GetArcMid().x, aArc.GetArcMid().y,
2091 aArc.GetP1().x, aArc.GetP1().y ),
2101 bool isFirstShape =
true;
2114 if( nextShape != -1 )
2120 lastPt = aChain.
CPoint( i );
2130 firstPt = currentArc.
GetP0();
2135 lastPt = currentArc.
GetP0();
2137 if( addArc( lastPt, currentArc ) )
2138 lastPt = currentArc.
GetP1();
2157 isFirstShape =
false;
2160 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2162 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2164 firstPt.
x, firstPt.
y ),
2170 catch(
const Standard_Failure& e )
2172 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2173 e.GetMessageString() ),
2183 bool aConvertToArcs,
double aThickness,
double aZposition,
2191 if( aConvertToArcs )
2195 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2199 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2203 fallbackPoly = workingPoly;
2204 workingPoly = approximated;
2223 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2225 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2226 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2230 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2231 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2233 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2237 auto tryMakeWire = [
this, &aZposition,
2238 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2241 BRepLib_MakeWire mkWire;
2245 if( mkWire.IsDone() )
2247 wire = mkWire.Wire();
2252 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2253 "z: %g; bounding box: %s" ),
2254 static_cast<int>( aContour.PointCount() ),
2255 static_cast<int>( mkWire.Error() ),
2260 if( !wire.IsNull() )
2262 BRepAlgoAPI_Check check( wire,
false,
true );
2264 if( !check.IsValid() )
2266 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2267 "z: %g; bounding box: %s" ),
2279 BRepBuilderAPI_MakeFace mkFace;
2281 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2287 bool allow_retry = aConvertToArcs ? true :
false;
2289 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2291 if( aConvertToArcs && wire.IsNull() )
2293 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2297 allow_retry =
false;
2298 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2303 if( !wire.IsNull() )
2305 if( basePlane.Axis().Direction().Z() < 0 )
2308 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2312 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2313 "z: %g; bounding box: %s" ),
2322 if( !wire.IsNull() )
2324 if( basePlane.Axis().Direction().Z() > 0 )
2331 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2332 "z: %g; bounding box: %s" ),
2339 catch(
const Standard_Failure& e )
2341 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2342 static_cast<int>( contId ),
2343 e.GetMessageString() ),
2349 if( mkFace.IsDone() )
2351 TopoDS_Shape faceShape = mkFace.Shape();
2353 if( aThickness != 0.0 )
2355 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2356 aShapes.push_back( prism );
2358 if( prism.IsNull() )
2366 aShapes.push_back( faceShape );
2382 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2383 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2384 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2385 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2386 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2387 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2388 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2389 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2399 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2401 aColorOut =
COLOR4D( aColorStr );
2406 const std::vector<FAB_LAYER_COLOR>& colors =
2413 if( fabColor.GetName() == aColorStr )
2415 aColorOut = fabColor.GetColor( aType );
2437 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2442 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2447 double boardThickness;
2467 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2471 polyset.
Append( contour );
2478 m_reporter->Report(
_(
"OCC error creating main outline." ),
2487 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2499 BRepBndLib::Add( brdShape, brdBndBox );
2502 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2507 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles,
2508 std::vector<Bnd_Box>& holeBoxes )
2512 Bnd_Box brdWithHolesBndBox = brdBndBox;
2514 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2515 holeBoxes.resize( input.size() );
2517 for(
size_t i = 0; i < input.size(); i++ )
2520 BRepBndLib::Add( input[i], bbox );
2521 brdWithHolesBndBox.Add( bbox );
2522 ( *holeBoxSet )[i] = bbox;
2523 holeBoxes[i] = bbox;
2526 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2529 auto subtractShapesMap =
2530 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2531 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2532 const std::vector<Bnd_Box>& aHoleBoxes )
2534 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2537 for(
auto& [netname, vec] : aShapesMap )
2541 auto subtractLoopFn = [&](
const int shapeId )
2543 TopoDS_Shape& shape = vec[shapeId];
2546 BRepBndLib::Add( shape, shapeBbox );
2548 TopTools_ListOfShape holelist;
2551 std::unique_lock lock( mutex );
2553 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2555 for(
const Standard_Integer&
index : indices )
2556 holelist.Append( aHolesList[
index] );
2562 if( holelist.IsEmpty() )
2564 for(
size_t i = 0; i < aHoleBoxes.size(); i++ )
2566 if( !shapeBbox.IsOut( aHoleBoxes[i] ) )
2567 holelist.Append( aHolesList[i] );
2572 if( holelist.IsEmpty() )
2575 TopTools_ListOfShape cutArgs;
2576 cutArgs.Append( shape );
2578 BRepAlgoAPI_Cut
cut;
2580 cut.SetRunParallel(
true );
2581 cut.SetToFillHistory(
false );
2583 cut.SetArguments( cutArgs );
2584 cut.SetTools( holelist );
2587 if(
cut.HasErrors() ||
cut.HasWarnings() )
2589 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2596 if(
cut.HasErrors() )
2598 wxString msg =
_(
"Errors:\n" );
2599 wxStringOutputStream os_stream( &msg );
2600 wxStdOutputStream out( os_stream );
2602 cut.DumpErrors( out );
2606 if(
cut.HasWarnings() )
2608 wxString msg =
_(
"Warnings:\n" );
2609 wxStringOutputStream os_stream( &msg );
2610 wxStdOutputStream out( os_stream );
2612 cut.DumpWarnings( out );
2617 shape =
cut.Shape();
2620 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2624 auto subtractShapes =
2625 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2626 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles,
2627 const std::vector<Bnd_Box>& aHoleBoxes )
2629 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2631 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles, aHoleBoxes );
2632 aShapesList = aShapesMap[wxEmptyString];
2638 Bnd_BoundSortBox bsbHoles;
2639 std::vector<Bnd_Box> holeBoxes;
2647 Bnd_BoundSortBox bsbHoles;
2648 std::vector<Bnd_Box> holeBoxes;
2657 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2659 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2660 const std::vector<TopoDS_Shape>& aShapes )
2662 for(
const TopoDS_Shape& shape : aShapes )
2663 shapesToFuseMap[aNetname].Append( shape );
2667 addShapes( netname, shapes );
2670 addShapes( netname, shapes );
2673 addShapes( netname, shapes );
2680 auto fuseLoopFn = [&](
const wxString& aNetname )
2682 auto& toFuse = shapesToFuseMap[aNetname];
2685 if( !fusedShape.IsNull() )
2687 std::unique_lock lock( mutex );
2697 BS::multi_future<void> mf;
2699 for(
const auto& [netname,
_] : shapesToFuseMap )
2700 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2717 auto pushToAssemblyMap =
2718 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2719 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2720 bool aCompoundAll,
const wxString& aNiceName )
2722 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2726 std::vector<TopoDS_Shape> allShapes;
2728 for(
const auto& [netname, shapesList] : aShapesMap )
2729 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2731 if( !allShapes.empty() )
2732 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2736 shapesMap = aShapesMap;
2739 for(
const auto& [netname, shapesList] : shapesMap )
2741 std::vector<TopoDS_Shape> newList;
2746 newList = shapesList;
2750 for( TopoDS_Shape& shape : newList )
2752 Handle( TDataStd_TreeNode ) node;
2755 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2762 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2763 TDF_Label shpLbl = node->Father()->Label();
2765 if( !shpLbl.IsNull() )
2767 if( visMatTool && !aVisMatLabel.IsNull() )
2768 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2774 shapeName << aShapeName;
2776 if( !netname.empty() )
2779 shapeName << netname;
2782 if( newList.size() > 1 )
2788 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2789 TDataStd_Name::Set( shpLbl, partname );
2797 auto pushToAssembly =
2798 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2799 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2801 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2803 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2807 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2808 double aMetallic,
double aRoughness ) -> TDF_Label
2810 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2811 XCAFDoc_VisMaterialPBR pbr;
2812 pbr.BaseColor = aBaseColor;
2813 pbr.Metallic = aMetallic;
2814 pbr.Roughness = aRoughness;
2815 vismat->SetPbrMaterial( pbr );
2816 return visMatTool->AddMaterial( vismat, aName );
2823 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2824 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2825 Quantity_ColorRGBA back_silk_color = front_silk_color;
2826 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2827 Quantity_ColorRGBA back_mask_color = front_mask_color;
2837 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2841 if( item->GetBrdLayerId() ==
F_Mask )
2842 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2844 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2847 if( item->GetBrdLayerId() ==
F_SilkS )
2848 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2849 else if( item->GetBrdLayerId() ==
B_SilkS )
2850 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2853 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2859 board_color = front_mask_color;
2860 board_color.SetAlpha( 1.0 );
2863 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2864 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2865 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2866 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2867 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2868 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2869 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2871 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2875 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2876 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2877 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2878 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2880 if( aPushBoardBody )
2883#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2884 m_assy->UpdateAssemblies();
2893bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2897 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2905 wxFileName fn( aFileName );
2906 IGESControl_Controller::Init();
2907 IGESCAFControl_Writer writer;
2908 writer.SetColorMode( Standard_True );
2909 writer.SetNameMode( Standard_True );
2910 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2911 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2912 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2913 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2914 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2915 writer.Model()->SetGlobalSection( header );
2917 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2926 wxFileInputStream input( inputFile );
2927 wxFileOutputStream output( outputFile );
2931 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2935 if( !output.IsOk() )
2937 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2941 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2943 if( !zlibStream.IsOk() )
2945 m_reporter->Report(
_(
"Impossible create compress stream" ) );
2949 input.Read( zlibStream );
2951 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2953 m_reporter->Report(
_(
"Compress read or write error" ) );
2967 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2975 wxFileName fn( aFileName );
2977 STEPCAFControl_Writer writer;
2978 writer.SetColorMode( Standard_True );
2979 writer.SetNameMode( Standard_True );
2986 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2988 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2994 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2996 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
3000 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
3003 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
3007 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
3010 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
3011 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
3012 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
3013 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
3015 bool success =
true;
3018 wxString currCWD = wxGetCwd();
3019 wxString workCWD = fn.GetPath();
3021 if( !workCWD.IsEmpty() )
3022 wxSetWorkingDirectory( workCWD );
3024 wxString tmpfname(
"$tempfile$.step" );
3026 if( Standard_False == writer.Write( tmpfname.c_str() ) )
3029 if( compress && success )
3031 wxString srcTmp( tmpfname );
3032 wxString dstTmp(
"$tempfile$.stpz" );
3035 wxRemoveFile( srcTmp );
3046 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3048 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3056 wxSetWorkingDirectory( currCWD );
3066 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3075 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3080 wxFileName fn( aFileName );
3082 wxFFileOutputStream ffStream( fn.GetFullPath() );
3083 wxStdOutputStream stdStream( ffStream );
3085#if OCC_VERSION_HEX >= 0x070600
3086 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3088 BRepTools::Write( shape, stdStream );
3097 wxFileName fn( aFileName );
3099 wxFFileOutputStream ffStream( fn.GetFullPath() );
3100 wxStdOutputStream file( ffStream );
3102 if( !ffStream.IsOk() )
3104 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3112 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3117 std::map<wxString, std::vector<int>> groups[4];
3118 std::map<wxString, double> groupAreas;
3119 TopExp_Explorer exp;
3122 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3124 TopoDS_Shape subShape = exp.Current();
3127 BRepBndLib::Add( subShape, bbox );
3131 for(
const auto& pair : pairs )
3133 const auto& [point, padTestShape] = pair;
3135 if( bbox.IsOut( point ) )
3138 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3140 if( surface.GetType() != GeomAbs_Plane )
3143 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3146 if( !dist.IsDone() )
3149 if( dist.Value() < Precision::Approximation() )
3152 groups[2][padKey].push_back( faceIndex );
3154 GProp_GProps system;
3155 BRepGProp::SurfaceProperties( subShape, system );
3157 double surfaceArea = system.Mass() / 1e6;
3158 groupAreas[padKey] += surfaceArea;
3167 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3168 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3169 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3170 file <<
" <shape format=\"BREP\"><![CDATA[";
3171#if OCC_VERSION_HEX < 0x070600
3172 BRepTools::Write( shape, file );
3174 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
3176 file <<
"]]></shape>" << std::endl;
3177 file <<
" <topology>" << std::endl;
3179 TopTools_IndexedMapOfShape mainMap;
3180 TopExp::MapShapes( shape, mainMap );
3181 std::set<int> topo[4];
3183 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3186 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3187 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3189 for(
int dim = 0; dim < 4; dim++ )
3191 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3193 TopoDS_Shape subShape = exp.Current();
3194 int idx = mainMap.FindIndex( subShape );
3196 if( idx && !topo[dim].count( idx ) )
3197 topo[dim].insert( idx );
3201 for(
int dim = 0; dim <= 3; dim++ )
3203 std::string labels = c_dimLabels[dim];
3204 std::string label = c_dimLabel[dim];
3206 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3209 for(
auto p : topo[dim] )
3211 std::string
name(
"" );
3212 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3213 <<
"name=\"" <<
name <<
"\" "
3214 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3218 file <<
" </" << labels <<
">" << std::endl;
3221 file <<
" </topology>" << std::endl;
3222 file <<
" </geometry>" << std::endl;
3223 file <<
" <groups count=\""
3224 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3227 int groupNumber = 1;
3232 for(
int dim = 0; dim <= 3; dim++ )
3234 std::string label = c_dimLabel[dim];
3236 for(
auto g : groups[dim] )
3239 wxString
name = g.first;
3243 std::ostringstream gs;
3244 gs <<
"G_" << dim <<
"D_" << g.first;
3247 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3253 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3255 for(
auto index : g.second )
3256 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3258 file <<
" </group>" << std::endl;
3260 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3272 file <<
" </groups>" << std::endl;
3273 file <<
" <fields count=\"0\"/>" << std::endl;
3274 file <<
"</XAO>" << std::endl;
3281 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3282 TDF_Label& aLabel,
bool aSubstituteModels,
3283 wxString* aErrorMessage )
3285 std::string fileNameUTF8 = aFileName.utf8_string();
3287 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3288 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3290 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3294 aLabel = mm->second;
3300 Handle( TDocStd_Document ) doc;
3301 m_app->NewDocument(
"MDTV-XCAF", doc );
3304 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3309 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3311 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3319 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3321 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3332 wxFFileInputStream ifile( aFileName );
3333 wxFileName outFile( aFileName );
3335 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3336 outFile.SetExt( wxT(
"step" ) );
3337 wxFileOffset size = ifile.GetLength();
3339 if( size == wxInvalidOffset )
3341 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3348 bool success =
false;
3351 wxFFileOutputStream ofile( outFile.GetFullPath() );
3356 char* buffer =
new char[size];
3358 ifile.Read( buffer, size );
3359 std::string expanded;
3363 expanded = gzip::decompress( buffer, size );
3369 wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3373 if( expanded.empty() )
3377 wxZipInputStream izipfile( ifile );
3378 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3380 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3382 izipfile.Read( ofile );
3388 ofile.Write( expanded.data(), expanded.size() );
3396 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3397 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3416 if( aSubstituteModels )
3418 wxFileName wrlName( aFileName );
3420 wxString basePath = wrlName.GetPath();
3421 wxString baseName = wrlName.GetName();
3429 alts.Add( wxT(
"stp" ) );
3430 alts.Add( wxT(
"step" ) );
3431 alts.Add( wxT(
"STP" ) );
3432 alts.Add( wxT(
"STEP" ) );
3433 alts.Add( wxT(
"Stp" ) );
3434 alts.Add( wxT(
"Step" ) );
3435 alts.Add( wxT(
"stpz" ) );
3436 alts.Add( wxT(
"stpZ" ) );
3437 alts.Add( wxT(
"STPZ" ) );
3438 alts.Add( wxT(
"step.gz" ) );
3439 alts.Add( wxT(
"stp.gz" ) );
3442 alts.Add( wxT(
"iges" ) );
3443 alts.Add( wxT(
"IGES" ) );
3444 alts.Add( wxT(
"igs" ) );
3445 alts.Add( wxT(
"IGS" ) );
3449 for(
const auto& altExt : alts )
3453 if( !aAltFilenames.empty() )
3455 for(
const wxString& altPath : aAltFilenames )
3457 wxFileName iterFn( altPath );
3459 if( iterFn.GetExt() == altExt )
3468 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3471 if( altFile.IsOk() && altFile.FileExists() )
3481 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3495 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3497 Handle( XCAFDoc_ShapeTool ) shapeTool =
3498 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3505 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3515 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3525 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3532 if( aLabel.IsNull() )
3534 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3541 TDataStd_Name::Set( aLabel, partname );
3551 TopLoc_Location& aLocation )
3565 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3571 double boardThickness;
3574 double top = std::max( boardZPos, boardZPos + boardThickness );
3575 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3580 double f_pos, f_thickness;
3584 bottom += f_thickness;
3591 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3592 lPos.Multiply( lRot );
3593 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3594 lPos.Multiply( lRot );
3599 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3600 lPos.Multiply( lRot );
3604 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3605 lPos.Multiply( lOff );
3608 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3609 lPos.Multiply( lOrient );
3610 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3611 lPos.Multiply( lOrient );
3612 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3613 lPos.Multiply( lOrient );
3615 aLocation = TopLoc_Location( lPos );
3622 IGESControl_Controller::Init();
3623 IGESCAFControl_Reader reader;
3624 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3626 if( stat != IFSelect_RetDone )
3630 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3634 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3638 reader.SetColorMode(
true );
3639 reader.SetNameMode(
false );
3640 reader.SetLayerMode(
false );
3642 if( !reader.Transfer( doc ) )
3644 if( doc->CanClose() == CDM_CCS_OK )
3651 if( reader.NbShapes() < 1 )
3653 if( doc->CanClose() == CDM_CCS_OK )
3665 STEPCAFControl_Reader reader;
3666 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3668 if( stat != IFSelect_RetDone )
3672 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3676 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3680 reader.SetColorMode(
true );
3681 reader.SetNameMode(
true );
3682 reader.SetLayerMode(
false );
3684 if( !reader.Transfer( doc ) )
3686 if( doc->CanClose() == CDM_CCS_OK )
3693 if( reader.NbRootsForTransfer() < 1 )
3695 if( doc->CanClose() == CDM_CCS_OK )
3707#if OCC_VERSION_HEX >= 0x070700
3708 VrmlAPI_CafReader reader;
3709 RWMesh_CoordinateSystemConverter conv;
3710 conv.SetInputLengthUnit( 2.54 );
3711 reader.SetCoordinateSystemConverter( conv );
3712 reader.SetDocument( doc );
3714 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3725 Handle( XCAFDoc_ColorTool )& aSrcColorTool,
3726 Handle( XCAFDoc_ShapeTool )& aDstShapeTool,
3727 Handle( XCAFDoc_ColorTool )& aDstColorTool )
3730 TDF_LabelSequence srcLabels;
3731 aSrcShapeTool->GetShapes( srcLabels );
3733 for( Standard_Integer i = 1; i <= srcLabels.Length(); i++ )
3735 TDF_Label srcLabel = srcLabels.Value( i );
3736 TopoDS_Shape srcShape = aSrcShapeTool->GetShape( srcLabel );
3738 if( srcShape.IsNull() )
3744 if( !aDstShapeTool->Search( srcShape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3748 Quantity_ColorRGBA surfColor;
3750 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorSurf, surfColor ) )
3751 aDstColorTool->SetColor( dstLabel, surfColor, XCAFDoc_ColorSurf );
3754 Quantity_ColorRGBA curvColor;
3756 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorCurv, curvColor ) )
3757 aDstColorTool->SetColor( dstLabel, curvColor, XCAFDoc_ColorCurv );
3760 Quantity_ColorRGBA genColor;
3762 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorGen, genColor ) )
3763 aDstColorTool->SetColor( dstLabel, genColor, XCAFDoc_ColorGen );
3766 if( aSrcShapeTool->IsSimpleShape( srcLabel ) )
3768 TopoDS_Shape shape = aSrcShapeTool->GetShape( srcLabel );
3770 for( TopExp_Explorer exp( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3772 TopoDS_Face face = TopoDS::Face( exp.Current() );
3773 Quantity_ColorRGBA faceColor;
3775 if( aSrcColorTool->GetColor( face, XCAFDoc_ColorSurf, faceColor ) )
3776 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorSurf );
3777 else if( aSrcColorTool->GetColor( face, XCAFDoc_ColorGen, faceColor ) )
3778 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorGen );
3784 TDF_LabelSequence srcFreeShapes;
3785 aSrcShapeTool->GetFreeShapes( srcFreeShapes );
3787 std::function<void(
const TDF_Label& )> transferColorsRecursive = [&](
const TDF_Label& aLabel )
3789 TopoDS_Shape shape = aSrcShapeTool->GetShape( aLabel );
3791 if( shape.IsNull() )
3797 if( aDstShapeTool->Search( shape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3799 Quantity_ColorRGBA color;
3801 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorSurf, color ) )
3802 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorSurf );
3804 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorCurv, color ) )
3805 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorCurv );
3807 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorGen, color ) )
3808 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorGen );
3812 for( TDF_ChildIterator it( aLabel ); it.More(); it.Next() )
3813 transferColorsRecursive( it.Value() );
3816 if( aSrcShapeTool->IsAssembly( aLabel ) )
3818 TDF_LabelSequence components;
3819 aSrcShapeTool->GetComponents( aLabel, components );
3821 for( Standard_Integer j = 1; j <= components.Length(); j++ )
3823 TDF_Label compLabel = components.Value( j );
3826 if( aSrcShapeTool->GetReferredShape( compLabel, refLabel ) )
3827 transferColorsRecursive( refLabel );
3832 for( Standard_Integer i = 1; i <= srcFreeShapes.Length(); i++ )
3833 transferColorsRecursive( srcFreeShapes.Value( i ) );
3842 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3843 Handle( XCAFDoc_ColorTool ) s_color = XCAFDoc_DocumentTool::ColorTool( source->Main() );
3846 TDF_LabelSequence frshapes;
3847 s_assy->GetFreeShapes( frshapes );
3850 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3851 Handle( XCAFDoc_ColorTool ) d_color = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
3854 TDF_Label d_targetLabel = d_assy->NewShape();
3856 auto copyLabel = [&]( TDF_Label& d_label,
const TDF_Label& s_label ) ->
bool
3862 if( TDF_Tool::IsSelfContained( s_label ) )
3864 TDocStd_XLinkTool link;
3865 link.Copy( d_label, s_label );
3871 TopoDS_Shape shape = s_assy->GetShape( s_label );
3873 if( shape.IsNull() )
3878 d_assy->SetShape( d_label, shape );
3880 m_reporter->Report( wxT(
"Model contains non-self-contained data; some metadata may be lost." ),
3886 if( frshapes.Size() == 1 )
3888 if( !copyLabel( d_targetLabel, frshapes.First() ) )
3897 for( TDF_Label& s_shapeLabel : frshapes )
3899 TDF_Label d_component = d_assy->NewShape();
3901 if( !copyLabel( d_component, s_shapeLabel ) )
3907 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3916 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3919 return d_targetLabel;
3925 TDF_LabelSequence freeShapes;
3926 aShapeTool->GetFreeShapes( freeShapes );
3932 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3934 TDF_Label label = freeShapes.Value( i );
3936 aShapeTool->GetShape( label, shape );
3941 const Standard_Real linearDeflection = 0.14;
3942 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3943 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3965 wxFileName fn( aFileName );
3967 const char* tmpGltfname =
"$tempfile$.glb";
3968 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3970 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3971 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3972 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3973 RWMesh_CoordinateSystem_Zup );
3974#if OCC_VERSION_HEX >= 0x070700
3975 cafWriter.SetParallel(
true );
3977 TColStd_IndexedDataMapOfStringString metadata;
3979 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3980 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3981 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3982 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3983 metadata.Add( TCollection_AsciiString(
"generator" ),
3984 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3985 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3988 bool success =
true;
3991 wxString currCWD = wxGetCwd();
3992 wxString workCWD = fn.GetPath();
3994 if( !workCWD.IsEmpty() )
3995 wxSetWorkingDirectory( workCWD );
3997 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4004 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
4006 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4014 wxSetWorkingDirectory( currCWD );
4022#if OCC_VERSION_HEX < 0x070700
4029 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4039 wxFileName fn( aFileName );
4041 const char* tmpFname =
"$tempfile$.ply";
4042 RWPly_CafWriter cafWriter( tmpFname );
4044 cafWriter.SetFaceId(
true );
4045 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4046 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4048 TColStd_IndexedDataMapOfStringString metadata;
4050 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4051 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4052 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4053 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4054 metadata.Add( TCollection_AsciiString(
"generator" ),
4055 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4057 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4060 bool success =
true;
4063 wxString currCWD = wxGetCwd();
4064 wxString workCWD = fn.GetPath();
4066 if( !workCWD.IsEmpty() )
4067 wxSetWorkingDirectory( workCWD );
4069 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4076 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4078 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4086 wxSetWorkingDirectory( currCWD );
4097 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4107 wxFileName fn( aFileName );
4109 const char* tmpFname =
"$tempfile$.stl";
4112 wxString currCWD = wxGetCwd();
4113 wxString workCWD = fn.GetPath();
4115 if( !workCWD.IsEmpty() )
4116 wxSetWorkingDirectory( workCWD );
4118 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4125 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4127 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4135 wxSetWorkingDirectory( currCWD );
4147 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4156 wxFileName fn( aFileName );
4158 const char* tmpFname =
"$tempfile$.u3d";
4161 wxString currCWD = wxGetCwd();
4162 wxString workCWD = fn.GetPath();
4164 if( !workCWD.IsEmpty() )
4165 wxSetWorkingDirectory( workCWD );
4168 bool success = writer.
Perform( m_doc );
4174 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4176 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4183 wxSetWorkingDirectory( currCWD );
4194 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4203 wxFileName fn( aFileName );
4205 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4206 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4208 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4209 bool success = writer.
Perform( m_doc );
4212 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4214 plotter->SetColorMode(
true );
4215 plotter->Set3DExport(
true );
4216 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4218 plotter->SetRenderSettings( &renderSettings );
4220 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4222 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4228 plotter->StartPlot(
"1",
"3D Model" );
4229 double fov_degrees = 16.5f;
4234 std::vector<PDF_3D_VIEW> views;
4239 std::vector<float> c2wMatrix =
4243 .m_name =
"Default",
4244 .m_cameraMatrix = c2wMatrix,
4245 .m_cameraCenter = (float)
distance,
4246 .m_fov = (
float) fov_degrees,
4255 .m_cameraMatrix = c2wMatrix,
4256 .m_cameraCenter = (float)
distance,
4257 .m_fov = (
float) fov_degrees,
4266 .m_cameraMatrix = c2wMatrix,
4267 .m_cameraCenter = (float)
distance,
4268 .m_fov = (
float) fov_degrees,
4277 .m_cameraMatrix = c2wMatrix,
4278 .m_cameraCenter = (float)
distance,
4279 .m_fov = (
float) fov_degrees,
4282 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4291 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4293 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4294 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4300 wxRemoveFile( u3dTmpfn.GetFullPath() );
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)
void transferColors(Handle(XCAFDoc_ShapeTool)&aSrcShapeTool, Handle(XCAFDoc_ColorTool)&aSrcColorTool, Handle(XCAFDoc_ShapeTool)&aDstShapeTool, Handle(XCAFDoc_ColorTool)&aDstColorTool)
Transfer color information from source document to destination document.
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
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)
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
bool Perform(const Handle(TDocStd_Document) &aDocument)
const VECTOR3D & GetCenter() const
const Bnd_Box & GetMeshBoundingBox() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
Handle(KICAD3D_INFO) KICAD3D_INFO
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ CASTELLATED
a pad with a castellated through hole
Plotting engines similar to ps (PostScript, Gerber, svg)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static TopoDS_Shape fuseShapesOrCompound(const TopTools_ListOfShape &aInputShapes, REPORTER *aReporter)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static Standard_Boolean prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static Standard_Boolean rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
static constexpr double USER_ANGLE_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
std::pair< std::string, TDF_Label > MODEL_DATUM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
KIBIS top(path, &reporter)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D