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 )
2511 Bnd_Box brdWithHolesBndBox = brdBndBox;
2513 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2515 for(
size_t i = 0; i < input.size(); i++ )
2518 BRepBndLib::Add( input[i], bbox );
2519 brdWithHolesBndBox.Add( bbox );
2520 ( *holeBoxSet )[i] = bbox;
2523 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2526 auto subtractShapesMap =
2527 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2528 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2530 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2533 for(
auto& [netname, vec] : aShapesMap )
2537 auto subtractLoopFn = [&](
const int shapeId )
2539 TopoDS_Shape& shape = vec[shapeId];
2542 BRepBndLib::Add( shape, shapeBbox );
2544 TopTools_ListOfShape holelist;
2547 std::unique_lock lock( mutex );
2549 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2551 for(
const Standard_Integer&
index : indices )
2552 holelist.Append( aHolesList[
index] );
2555 if( holelist.IsEmpty() )
2558 TopTools_ListOfShape cutArgs;
2559 cutArgs.Append( shape );
2561 BRepAlgoAPI_Cut
cut;
2563 cut.SetRunParallel(
true );
2564 cut.SetToFillHistory(
false );
2566 cut.SetArguments( cutArgs );
2567 cut.SetTools( holelist );
2570 if(
cut.HasErrors() ||
cut.HasWarnings() )
2572 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2579 if(
cut.HasErrors() )
2581 wxString msg =
_(
"Errors:\n" );
2582 wxStringOutputStream os_stream( &msg );
2583 wxStdOutputStream out( os_stream );
2585 cut.DumpErrors( out );
2589 if(
cut.HasWarnings() )
2591 wxString msg =
_(
"Warnings:\n" );
2592 wxStringOutputStream os_stream( &msg );
2593 wxStdOutputStream out( os_stream );
2595 cut.DumpWarnings( out );
2600 shape =
cut.Shape();
2603 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2607 auto subtractShapes =
2608 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2609 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2611 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2613 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
2614 aShapesList = aShapesMap[wxEmptyString];
2620 Bnd_BoundSortBox bsbHoles;
2628 Bnd_BoundSortBox bsbHoles;
2637 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2639 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2640 const std::vector<TopoDS_Shape>& aShapes )
2642 for(
const TopoDS_Shape& shape : aShapes )
2643 shapesToFuseMap[aNetname].Append( shape );
2647 addShapes( netname, shapes );
2650 addShapes( netname, shapes );
2653 addShapes( netname, shapes );
2660 auto fuseLoopFn = [&](
const wxString& aNetname )
2662 auto& toFuse = shapesToFuseMap[aNetname];
2665 if( !fusedShape.IsNull() )
2667 std::unique_lock lock( mutex );
2677 BS::multi_future<void> mf;
2679 for(
const auto& [netname,
_] : shapesToFuseMap )
2680 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2697 auto pushToAssemblyMap =
2698 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2699 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2700 bool aCompoundAll,
const wxString& aNiceName )
2702 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2706 std::vector<TopoDS_Shape> allShapes;
2708 for(
const auto& [netname, shapesList] : aShapesMap )
2709 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2711 if( !allShapes.empty() )
2712 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2716 shapesMap = aShapesMap;
2719 for(
const auto& [netname, shapesList] : shapesMap )
2721 std::vector<TopoDS_Shape> newList;
2726 newList = shapesList;
2730 for( TopoDS_Shape& shape : newList )
2732 Handle( TDataStd_TreeNode ) node;
2735 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2742 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2743 TDF_Label shpLbl = node->Father()->Label();
2745 if( !shpLbl.IsNull() )
2747 if( visMatTool && !aVisMatLabel.IsNull() )
2748 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2754 shapeName << aShapeName;
2756 if( !netname.empty() )
2759 shapeName << netname;
2762 if( newList.size() > 1 )
2768 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2769 TDataStd_Name::Set( shpLbl, partname );
2777 auto pushToAssembly =
2778 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2779 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2781 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2783 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2787 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2788 double aMetallic,
double aRoughness ) -> TDF_Label
2790 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2791 XCAFDoc_VisMaterialPBR pbr;
2792 pbr.BaseColor = aBaseColor;
2793 pbr.Metallic = aMetallic;
2794 pbr.Roughness = aRoughness;
2795 vismat->SetPbrMaterial( pbr );
2796 return visMatTool->AddMaterial( vismat, aName );
2803 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2804 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2805 Quantity_ColorRGBA back_silk_color = front_silk_color;
2806 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2807 Quantity_ColorRGBA back_mask_color = front_mask_color;
2817 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2821 if( item->GetBrdLayerId() ==
F_Mask )
2822 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2824 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2827 if( item->GetBrdLayerId() ==
F_SilkS )
2828 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2829 else if( item->GetBrdLayerId() ==
B_SilkS )
2830 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2833 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2839 board_color = front_mask_color;
2840 board_color.SetAlpha( 1.0 );
2843 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2844 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2845 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2846 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2847 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2848 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2849 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2851 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2855 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2856 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2857 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2858 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2860 if( aPushBoardBody )
2863#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2864 m_assy->UpdateAssemblies();
2873bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2877 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2885 wxFileName fn( aFileName );
2886 IGESControl_Controller::Init();
2887 IGESCAFControl_Writer writer;
2888 writer.SetColorMode( Standard_True );
2889 writer.SetNameMode( Standard_True );
2890 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2891 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2892 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2893 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2894 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2895 writer.Model()->SetGlobalSection( header );
2897 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2906 wxFileInputStream input( inputFile );
2907 wxFileOutputStream output( outputFile );
2911 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2915 if( !output.IsOk() )
2917 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2921 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2923 if( !zlibStream.IsOk() )
2925 m_reporter->Report(
_(
"Impossible create compress stream" ) );
2929 input.Read( zlibStream );
2931 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2933 m_reporter->Report(
_(
"Compress read or write error" ) );
2947 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2955 wxFileName fn( aFileName );
2957 STEPCAFControl_Writer writer;
2958 writer.SetColorMode( Standard_True );
2959 writer.SetNameMode( Standard_True );
2966 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2968 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2974 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2976 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2980 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2983 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2987 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2990 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2991 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2992 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2993 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2995 bool success =
true;
2998 wxString currCWD = wxGetCwd();
2999 wxString workCWD = fn.GetPath();
3001 if( !workCWD.IsEmpty() )
3002 wxSetWorkingDirectory( workCWD );
3004 wxString tmpfname(
"$tempfile$.step" );
3006 if( Standard_False == writer.Write( tmpfname.c_str() ) )
3009 if( compress && success )
3011 wxString srcTmp( tmpfname );
3012 wxString dstTmp(
"$tempfile$.stpz" );
3015 wxRemoveFile( srcTmp );
3026 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
3028 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3036 wxSetWorkingDirectory( currCWD );
3046 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3055 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3060 wxFileName fn( aFileName );
3062 wxFFileOutputStream ffStream( fn.GetFullPath() );
3063 wxStdOutputStream stdStream( ffStream );
3065#if OCC_VERSION_HEX >= 0x070600
3066 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3068 BRepTools::Write( shape, stdStream );
3077 wxFileName fn( aFileName );
3079 wxFFileOutputStream ffStream( fn.GetFullPath() );
3080 wxStdOutputStream file( ffStream );
3082 if( !ffStream.IsOk() )
3084 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3092 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3097 std::map<wxString, std::vector<int>> groups[4];
3098 std::map<wxString, double> groupAreas;
3099 TopExp_Explorer exp;
3102 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3104 TopoDS_Shape subShape = exp.Current();
3107 BRepBndLib::Add( subShape, bbox );
3111 for(
const auto& pair : pairs )
3113 const auto& [point, padTestShape] = pair;
3115 if( bbox.IsOut( point ) )
3118 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3120 if( surface.GetType() != GeomAbs_Plane )
3123 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3126 if( !dist.IsDone() )
3129 if( dist.Value() < Precision::Approximation() )
3132 groups[2][padKey].push_back( faceIndex );
3134 GProp_GProps system;
3135 BRepGProp::SurfaceProperties( subShape, system );
3137 double surfaceArea = system.Mass() / 1e6;
3138 groupAreas[padKey] += surfaceArea;
3147 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3148 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3149 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3150 file <<
" <shape format=\"BREP\"><![CDATA[";
3151#if OCC_VERSION_HEX < 0x070600
3152 BRepTools::Write( shape, file );
3154 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
3156 file <<
"]]></shape>" << std::endl;
3157 file <<
" <topology>" << std::endl;
3159 TopTools_IndexedMapOfShape mainMap;
3160 TopExp::MapShapes( shape, mainMap );
3161 std::set<int> topo[4];
3163 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3166 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3167 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3169 for(
int dim = 0; dim < 4; dim++ )
3171 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3173 TopoDS_Shape subShape = exp.Current();
3174 int idx = mainMap.FindIndex( subShape );
3176 if( idx && !topo[dim].count( idx ) )
3177 topo[dim].insert( idx );
3181 for(
int dim = 0; dim <= 3; dim++ )
3183 std::string labels = c_dimLabels[dim];
3184 std::string label = c_dimLabel[dim];
3186 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3189 for(
auto p : topo[dim] )
3191 std::string
name(
"" );
3192 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3193 <<
"name=\"" <<
name <<
"\" "
3194 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3198 file <<
" </" << labels <<
">" << std::endl;
3201 file <<
" </topology>" << std::endl;
3202 file <<
" </geometry>" << std::endl;
3203 file <<
" <groups count=\""
3204 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3207 int groupNumber = 1;
3212 for(
int dim = 0; dim <= 3; dim++ )
3214 std::string label = c_dimLabel[dim];
3216 for(
auto g : groups[dim] )
3219 wxString
name = g.first;
3223 std::ostringstream gs;
3224 gs <<
"G_" << dim <<
"D_" << g.first;
3227 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3233 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3235 for(
auto index : g.second )
3236 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3238 file <<
" </group>" << std::endl;
3240 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3252 file <<
" </groups>" << std::endl;
3253 file <<
" <fields count=\"0\"/>" << std::endl;
3254 file <<
"</XAO>" << std::endl;
3261 const std::vector<wxString>& aAltFilenames,
VECTOR3D aScale,
3262 TDF_Label& aLabel,
bool aSubstituteModels,
3263 wxString* aErrorMessage )
3265 std::string fileNameUTF8 = aFileName.utf8_string();
3267 std::string model_key = fileNameUTF8 +
"_" + std::to_string( aScale.
x ) +
"_"
3268 + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3270 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3274 aLabel = mm->second;
3280 Handle( TDocStd_Document ) doc;
3281 m_app->NewDocument(
"MDTV-XCAF", doc );
3284 TCollection_ExtendedString partname( aBaseName.utf8_str() );
3289 if( !
readIGES( doc, fileNameUTF8.c_str() ) )
3291 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ), aFileName ),
3299 if( !
readSTEP( doc, fileNameUTF8.c_str() ) )
3301 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ), aFileName ),
3312 wxFFileInputStream ifile( aFileName );
3313 wxFileName outFile( aFileName );
3315 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3316 outFile.SetExt( wxT(
"step" ) );
3317 wxFileOffset size = ifile.GetLength();
3319 if( size == wxInvalidOffset )
3321 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3328 bool success =
false;
3331 wxFFileOutputStream ofile( outFile.GetFullPath() );
3336 char* buffer =
new char[size];
3338 ifile.Read( buffer, size );
3339 std::string expanded;
3343 expanded = gzip::decompress( buffer, size );
3349 wxString::Format( wxT(
"failed to decompress '%s'." ), aFileName ),
3353 if( expanded.empty() )
3357 wxZipInputStream izipfile( ifile );
3358 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3360 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3362 izipfile.Read( ofile );
3368 ofile.Write( expanded.data(), expanded.size() );
3376 success =
getModelLabel( aBaseName, outFile.GetFullPath(), aAltFilenames,
3377 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false );
3396 if( aSubstituteModels )
3398 wxFileName wrlName( aFileName );
3400 wxString basePath = wrlName.GetPath();
3401 wxString baseName = wrlName.GetName();
3409 alts.Add( wxT(
"stp" ) );
3410 alts.Add( wxT(
"step" ) );
3411 alts.Add( wxT(
"STP" ) );
3412 alts.Add( wxT(
"STEP" ) );
3413 alts.Add( wxT(
"Stp" ) );
3414 alts.Add( wxT(
"Step" ) );
3415 alts.Add( wxT(
"stpz" ) );
3416 alts.Add( wxT(
"stpZ" ) );
3417 alts.Add( wxT(
"STPZ" ) );
3418 alts.Add( wxT(
"step.gz" ) );
3419 alts.Add( wxT(
"stp.gz" ) );
3422 alts.Add( wxT(
"iges" ) );
3423 alts.Add( wxT(
"IGES" ) );
3424 alts.Add( wxT(
"igs" ) );
3425 alts.Add( wxT(
"IGS" ) );
3429 for(
const auto& altExt : alts )
3433 if( !aAltFilenames.empty() )
3435 for(
const wxString& altPath : aAltFilenames )
3437 wxFileName iterFn( altPath );
3439 if( iterFn.GetExt() == altExt )
3448 altFile = wxFileName( basePath, baseName + wxT(
"." ) + altExt );
3451 if( altFile.IsOk() && altFile.FileExists() )
3461 VECTOR3D( 1.0, 1.0, 1.0 ), aLabel,
false ) )
3475 if(
readVRML( doc, fileNameUTF8.c_str() ) )
3477 Handle( XCAFDoc_ShapeTool ) shapeTool =
3478 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3485 wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
3495 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3505 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ), aFileName ),
3512 if( aLabel.IsNull() )
3514 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ), aFileName ),
3521 TDataStd_Name::Set( aLabel, partname );
3531 TopLoc_Location& aLocation )
3545 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3551 double boardThickness;
3554 double top = std::max( boardZPos, boardZPos + boardThickness );
3555 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3560 double f_pos, f_thickness;
3564 bottom += f_thickness;
3571 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3572 lPos.Multiply( lRot );
3573 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3574 lPos.Multiply( lRot );
3579 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3580 lPos.Multiply( lRot );
3584 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3585 lPos.Multiply( lOff );
3588 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3589 lPos.Multiply( lOrient );
3590 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3591 lPos.Multiply( lOrient );
3592 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3593 lPos.Multiply( lOrient );
3595 aLocation = TopLoc_Location( lPos );
3602 IGESControl_Controller::Init();
3603 IGESCAFControl_Reader reader;
3604 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3606 if( stat != IFSelect_RetDone )
3610 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3614 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3618 reader.SetColorMode(
true );
3619 reader.SetNameMode(
false );
3620 reader.SetLayerMode(
false );
3622 if( !reader.Transfer( doc ) )
3624 if( doc->CanClose() == CDM_CCS_OK )
3631 if( reader.NbShapes() < 1 )
3633 if( doc->CanClose() == CDM_CCS_OK )
3645 STEPCAFControl_Reader reader;
3646 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3648 if( stat != IFSelect_RetDone )
3652 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3656 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3660 reader.SetColorMode(
true );
3661 reader.SetNameMode(
true );
3662 reader.SetLayerMode(
false );
3664 if( !reader.Transfer( doc ) )
3666 if( doc->CanClose() == CDM_CCS_OK )
3673 if( reader.NbRootsForTransfer() < 1 )
3675 if( doc->CanClose() == CDM_CCS_OK )
3687#if OCC_VERSION_HEX >= 0x070700
3688 VrmlAPI_CafReader reader;
3689 RWMesh_CoordinateSystemConverter conv;
3690 conv.SetInputLengthUnit( 2.54 );
3691 reader.SetCoordinateSystemConverter( conv );
3692 reader.SetDocument( doc );
3694 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3705 Handle( XCAFDoc_ColorTool )& aSrcColorTool,
3706 Handle( XCAFDoc_ShapeTool )& aDstShapeTool,
3707 Handle( XCAFDoc_ColorTool )& aDstColorTool )
3710 TDF_LabelSequence srcLabels;
3711 aSrcShapeTool->GetShapes( srcLabels );
3713 for( Standard_Integer i = 1; i <= srcLabels.Length(); i++ )
3715 TDF_Label srcLabel = srcLabels.Value( i );
3716 TopoDS_Shape srcShape = aSrcShapeTool->GetShape( srcLabel );
3718 if( srcShape.IsNull() )
3724 if( !aDstShapeTool->Search( srcShape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3728 Quantity_ColorRGBA surfColor;
3730 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorSurf, surfColor ) )
3731 aDstColorTool->SetColor( dstLabel, surfColor, XCAFDoc_ColorSurf );
3734 Quantity_ColorRGBA curvColor;
3736 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorCurv, curvColor ) )
3737 aDstColorTool->SetColor( dstLabel, curvColor, XCAFDoc_ColorCurv );
3740 Quantity_ColorRGBA genColor;
3742 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorGen, genColor ) )
3743 aDstColorTool->SetColor( dstLabel, genColor, XCAFDoc_ColorGen );
3746 if( aSrcShapeTool->IsSimpleShape( srcLabel ) )
3748 TopoDS_Shape shape = aSrcShapeTool->GetShape( srcLabel );
3750 for( TopExp_Explorer exp( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3752 TopoDS_Face face = TopoDS::Face( exp.Current() );
3753 Quantity_ColorRGBA faceColor;
3755 if( aSrcColorTool->GetColor( face, XCAFDoc_ColorSurf, faceColor ) )
3756 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorSurf );
3757 else if( aSrcColorTool->GetColor( face, XCAFDoc_ColorGen, faceColor ) )
3758 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorGen );
3764 TDF_LabelSequence srcFreeShapes;
3765 aSrcShapeTool->GetFreeShapes( srcFreeShapes );
3767 std::function<void(
const TDF_Label& )> transferColorsRecursive = [&](
const TDF_Label& aLabel )
3769 TopoDS_Shape shape = aSrcShapeTool->GetShape( aLabel );
3771 if( shape.IsNull() )
3777 if( aDstShapeTool->Search( shape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3779 Quantity_ColorRGBA color;
3781 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorSurf, color ) )
3782 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorSurf );
3784 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorCurv, color ) )
3785 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorCurv );
3787 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorGen, color ) )
3788 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorGen );
3792 for( TDF_ChildIterator it( aLabel ); it.More(); it.Next() )
3793 transferColorsRecursive( it.Value() );
3796 if( aSrcShapeTool->IsAssembly( aLabel ) )
3798 TDF_LabelSequence components;
3799 aSrcShapeTool->GetComponents( aLabel, components );
3801 for( Standard_Integer j = 1; j <= components.Length(); j++ )
3803 TDF_Label compLabel = components.Value( j );
3806 if( aSrcShapeTool->GetReferredShape( compLabel, refLabel ) )
3807 transferColorsRecursive( refLabel );
3812 for( Standard_Integer i = 1; i <= srcFreeShapes.Length(); i++ )
3813 transferColorsRecursive( srcFreeShapes.Value( i ) );
3822 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3823 Handle( XCAFDoc_ColorTool ) s_color = XCAFDoc_DocumentTool::ColorTool( source->Main() );
3826 TDF_LabelSequence frshapes;
3827 s_assy->GetFreeShapes( frshapes );
3830 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3831 Handle( XCAFDoc_ColorTool ) d_color = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
3834 TDF_Label d_targetLabel = d_assy->NewShape();
3836 auto copyLabel = [&]( TDF_Label& d_label,
const TDF_Label& s_label ) ->
bool
3842 if( TDF_Tool::IsSelfContained( s_label ) )
3844 TDocStd_XLinkTool link;
3845 link.Copy( d_label, s_label );
3851 TopoDS_Shape shape = s_assy->GetShape( s_label );
3853 if( shape.IsNull() )
3858 d_assy->SetShape( d_label, shape );
3860 m_reporter->Report( wxT(
"Model contains non-self-contained data; some metadata may be lost." ),
3866 if( frshapes.Size() == 1 )
3868 if( !copyLabel( d_targetLabel, frshapes.First() ) )
3877 for( TDF_Label& s_shapeLabel : frshapes )
3879 TDF_Label d_component = d_assy->NewShape();
3881 if( !copyLabel( d_component, s_shapeLabel ) )
3887 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3896 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3899 return d_targetLabel;
3905 TDF_LabelSequence freeShapes;
3906 aShapeTool->GetFreeShapes( freeShapes );
3912 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3914 TDF_Label label = freeShapes.Value( i );
3916 aShapeTool->GetShape( label, shape );
3921 const Standard_Real linearDeflection = 0.14;
3922 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3923 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3945 wxFileName fn( aFileName );
3947 const char* tmpGltfname =
"$tempfile$.glb";
3948 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3950 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3951 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3952 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3953 RWMesh_CoordinateSystem_Zup );
3954#if OCC_VERSION_HEX >= 0x070700
3955 cafWriter.SetParallel(
true );
3957 TColStd_IndexedDataMapOfStringString metadata;
3959 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3960 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3961 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3962 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3963 metadata.Add( TCollection_AsciiString(
"generator" ),
3964 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3965 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3968 bool success =
true;
3971 wxString currCWD = wxGetCwd();
3972 wxString workCWD = fn.GetPath();
3974 if( !workCWD.IsEmpty() )
3975 wxSetWorkingDirectory( workCWD );
3977 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3984 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3986 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3994 wxSetWorkingDirectory( currCWD );
4002#if OCC_VERSION_HEX < 0x070700
4009 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4019 wxFileName fn( aFileName );
4021 const char* tmpFname =
"$tempfile$.ply";
4022 RWPly_CafWriter cafWriter( tmpFname );
4024 cafWriter.SetFaceId(
true );
4025 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
4026 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
4028 TColStd_IndexedDataMapOfStringString metadata;
4030 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
4031 TCollection_ExtendedString( fn.GetName().wc_str() ) );
4032 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
4033 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
4034 metadata.Add( TCollection_AsciiString(
"generator" ),
4035 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
4037 metadata.Add( TCollection_AsciiString(
"generated_at" ),
4040 bool success =
true;
4043 wxString currCWD = wxGetCwd();
4044 wxString workCWD = fn.GetPath();
4046 if( !workCWD.IsEmpty() )
4047 wxSetWorkingDirectory( workCWD );
4049 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
4056 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4058 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4066 wxSetWorkingDirectory( currCWD );
4077 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4087 wxFileName fn( aFileName );
4089 const char* tmpFname =
"$tempfile$.stl";
4092 wxString currCWD = wxGetCwd();
4093 wxString workCWD = fn.GetPath();
4095 if( !workCWD.IsEmpty() )
4096 wxSetWorkingDirectory( workCWD );
4098 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4105 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4107 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4115 wxSetWorkingDirectory( currCWD );
4127 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4136 wxFileName fn( aFileName );
4138 const char* tmpFname =
"$tempfile$.u3d";
4141 wxString currCWD = wxGetCwd();
4142 wxString workCWD = fn.GetPath();
4144 if( !workCWD.IsEmpty() )
4145 wxSetWorkingDirectory( workCWD );
4148 bool success = writer.
Perform( m_doc );
4154 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4156 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4163 wxSetWorkingDirectory( currCWD );
4174 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4183 wxFileName fn( aFileName );
4185 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4186 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4188 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4189 bool success = writer.
Perform( m_doc );
4192 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4194 plotter->SetColorMode(
true );
4195 plotter->Set3DExport(
true );
4196 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4198 plotter->SetRenderSettings( &renderSettings );
4200 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4202 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4208 plotter->StartPlot(
"1",
"3D Model" );
4209 double fov_degrees = 16.5f;
4214 std::vector<PDF_3D_VIEW> views;
4219 std::vector<float> c2wMatrix =
4223 .m_name =
"Default",
4224 .m_cameraMatrix = c2wMatrix,
4225 .m_cameraCenter = (float)
distance,
4226 .m_fov = (
float) fov_degrees,
4235 .m_cameraMatrix = c2wMatrix,
4236 .m_cameraCenter = (float)
distance,
4237 .m_fov = (
float) fov_degrees,
4246 .m_cameraMatrix = c2wMatrix,
4247 .m_cameraCenter = (float)
distance,
4248 .m_fov = (
float) fov_degrees,
4257 .m_cameraMatrix = c2wMatrix,
4258 .m_cameraCenter = (float)
distance,
4259 .m_fov = (
float) fov_degrees,
4262 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4271 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4273 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4274 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4280 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