33#include <wx/filename.h>
35#include <wx/sstream.h>
36#include <wx/stdpaths.h>
39#include <wx/zstream.h>
40#include <wx/wfstream.h>
41#include <wx/zipstrm.h>
42#include <wx/stdstream.h>
45#include <decompress.hpp>
71#include <IGESCAFControl_Reader.hxx>
72#include <IGESCAFControl_Writer.hxx>
73#include <IGESControl_Controller.hxx>
74#include <IGESData_GlobalSection.hxx>
75#include <IGESData_IGESModel.hxx>
76#include <Interface_Static.hxx>
77#include <Quantity_Color.hxx>
78#include <STEPCAFControl_Reader.hxx>
79#include <STEPCAFControl_Writer.hxx>
80#include <APIHeaderSection_MakeHeader.hxx>
81#include <Standard_Failure.hxx>
82#include <Standard_Handle.hxx>
83#include <Standard_Version.hxx>
84#include <TCollection_ExtendedString.hxx>
85#include <TDocStd_Document.hxx>
86#include <TDocStd_XLinkTool.hxx>
87#include <TDataStd_Name.hxx>
88#include <TDataStd_TreeNode.hxx>
89#include <TDF_ChildIterator.hxx>
90#include <TDF_LabelSequence.hxx>
91#include <TDF_Tool.hxx>
92#include <TopExp_Explorer.hxx>
94#include <XCAFApp_Application.hxx>
96#include <XCAFDoc_DocumentTool.hxx>
97#include <XCAFDoc_ColorTool.hxx>
98#include <XCAFDoc_ShapeTool.hxx>
99#include <XCAFDoc_VisMaterialTool.hxx>
100#include <XCAFDoc_Area.hxx>
101#include <XCAFDoc_Centroid.hxx>
102#include <XCAFDoc_Location.hxx>
103#include <XCAFDoc_Volume.hxx>
106#include "KI_XCAFDoc_AssemblyGraph.hxx"
108#include <BRep_Tool.hxx>
109#include <BRepMesh_IncrementalMesh.hxx>
110#include <BRepBuilderAPI_GTransform.hxx>
111#include <BRepBuilderAPI_MakeEdge.hxx>
112#include <BRepBuilderAPI_MakeWire.hxx>
113#include <BRepBuilderAPI_MakeFace.hxx>
114#include <BRepExtrema_DistShapeShape.hxx>
115#include <BRepPrimAPI_MakeCone.hxx>
116#include <BRepPrimAPI_MakeCylinder.hxx>
117#include <BRepPrimAPI_MakePrism.hxx>
118#include <BRepTools.hxx>
119#include <BRepLib_MakeWire.hxx>
120#include <BRepAdaptor_Surface.hxx>
121#include <BRepAlgoAPI_Check.hxx>
122#include <BRepAlgoAPI_Cut.hxx>
123#include <BRepAlgoAPI_Fuse.hxx>
124#include <ShapeUpgrade_UnifySameDomain.hxx>
126#include <BRepBndLib.hxx>
127#include <Bnd_BoundSortBox.hxx>
128#include <GProp_GProps.hxx>
129#include <BRepGProp.hxx>
131#include <Geom_Curve.hxx>
132#include <Geom_TrimmedCurve.hxx>
137#include <GC_MakeArcOfCircle.hxx>
138#include <GC_MakeCircle.hxx>
140#include <RWGltf_CafWriter.hxx>
141#include <StlAPI_Writer.hxx>
143#if OCC_VERSION_HEX >= 0x070700
144#include <VrmlAPI_CafReader.hxx>
145#include <RWPly_CafWriter.hxx>
173 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
175 if( !lfile.FileExists() )
178 wxString ext = lfile.GetExt().Lower();
180 if( ext == wxT(
"wrl" ) )
183 if( ext == wxT(
"wrz" ) )
186 if( ext == wxT(
"idf" ) )
189 if( ext == wxT(
"emn" ) )
192 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
206 const int max_line_count = 3;
208 for(
int ii = 0; ii < max_line_count; ii++ )
210 memset( iline, 0, 82 );
211 ifile.getline( iline, 82 );
217 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
223 std::string fstr = iline;
227 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
236 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
243 if( strncmp( iline,
"/*", 2 ) != 0 )
261 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
262 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
263 double det = -b.
x * d.
y + d.
x * b.
y;
267 center.x = ( -bc * d.
y - cd * b.
y ) * det;
268 center.y = ( b.
x * cd + d.
x * bc ) * det;
275#define APPROX_DBG( stmt )
283 static const double c_radiusDeviation = 1000.0;
284 static const double c_arcCenterDeviation = 1000.0;
285 static const double c_relLengthDeviation = 0.8;
286 static const int c_last_none = -1000;
288 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
289 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
306 int last = c_last_none;
312 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
314 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
319 bool defective =
false;
325 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
333 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
334 defective |=
std::abs( a_diff ) < 0.1;
337 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
338 defective |=
std::abs( a_diff ) >= maxAngleDiff;
349 for(
int j = i; j <= jEndIdx; j++ )
354 double rad_test = ( p_test -
center ).EuclideanNorm();
355 double d_tl = ( p_test - p_prev ).EuclideanNorm();
359 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
362 if( rad_dev > c_radiusDeviation )
365 <<
" Radius deviation too large: " << int64_t( rad_dev )
366 <<
" > " << c_radiusDeviation << std::endl );
371 double maxAngleDiff =
372 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
374 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
375 if(
std::abs( a_diff_test ) >= maxAngleDiff )
377 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
382 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
384 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
385 <<
"; " << d01 << std::endl );
395 if( last != c_last_none )
404 int toRemove = last - ( aSrc.
PointCount() - 3 );
434 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
438 if( last == c_last_none )
455 if( iarc0 != -1 && iarc1 != -1 )
457 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
467 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
485 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
486 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
504 TDF_LabelSequence theLabels;
505 aShapeTool->GetFreeShapes( theLabels );
509 if( theLabels.Length() == 1 )
510 return aShapeTool->GetShape( theLabels.Value( 1 ) );
512 TopoDS_Compound aCompound;
513 BRep_Builder aBuilder;
514 aBuilder.MakeCompound( aCompound );
516 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
518 TopoDS_Shape aFreeShape;
520 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
523 aBuilder.Add( aCompound, aFreeShape );
526 if( aCompound.NbChildren() > 0 )
535static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
537 if( theLabel.IsNull() )
539 Message::SendFail(
"Null label." );
540 return Standard_False;
543 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
544 || Abs( aScale.Z() ) <= gp::Resolution() )
546 Message::SendFail(
"Scale factor is too small." );
547 return Standard_False;
550 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
552 if( aShapeTool.IsNull() )
554 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
555 return Standard_False;
558 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
562 Message::SendFail(
"Couldn't create assembly graph." );
563 return Standard_False;
566 Standard_Boolean anIsDone = Standard_True;
570 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
572 0, 0, aScale.Z() ) );
575 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
577 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
579 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
581 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
582 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
587 const TDF_Label& aLabel = aG->GetNode( idx );
589 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
591 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
592 aBRepTrsf.Perform( aShape, Standard_True );
593 if( !aBRepTrsf.IsDone() )
595 Standard_SStream aSS;
596 TCollection_AsciiString anEntry;
597 TDF_Tool::Entry( aLabel, anEntry );
598 aSS <<
"Shape " << anEntry <<
" is not scaled!";
599 Message::SendFail( aSS.str().c_str() );
600 anIsDone = Standard_False;
601 return Standard_False;
603 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
604 aShapeTool->SetShape( aLabel, aScaledShape );
607 TDF_LabelSequence aSubshapes;
608 aShapeTool->GetSubShapes( aLabel, aSubshapes );
609 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
611 const TDF_Label& aLSs = anItSs.Value();
612 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
613 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
614 aShapeTool->SetShape( aLSs, aSs1 );
618 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
619 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
620 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
622 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
624 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
625 gp_Trsf aTrsf = aLoc.Transformation();
626 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
627 XCAFDoc_Location::Set( aLabel, aTrsf );
633 return Standard_False;
636 aShapeTool->UpdateAssemblies();
644 BRepAlgoAPI_Fuse mkFuse;
645 TopTools_ListOfShape shapeArguments, shapeTools;
647 for( TopoDS_Shape& sh : aInputShapes )
652 if( shapeArguments.IsEmpty() )
653 shapeArguments.Append( sh );
655 shapeTools.Append( sh );
658 mkFuse.SetRunParallel(
true );
659 mkFuse.SetToFillHistory(
false );
660 mkFuse.SetArguments( shapeArguments );
661 mkFuse.SetTools( shapeTools );
664 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
668 if( mkFuse.HasErrors() )
670 wxString msg =
_(
"Errors:\n" );
671 wxStringOutputStream os_stream( &msg );
672 wxStdOutputStream out( os_stream );
674 mkFuse.DumpErrors( out );
678 if( mkFuse.HasWarnings() )
680 wxString msg =
_(
"Warnings:\n" );
681 wxStringOutputStream os_stream( &msg );
682 wxStdOutputStream out( os_stream );
684 mkFuse.DumpWarnings( out );
689 if( mkFuse.IsDone() )
691 TopoDS_Shape fusedShape = mkFuse.Shape();
693 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
694 unify.History() =
nullptr;
697 TopoDS_Shape unifiedShapes = unify.Shape();
699 if( unifiedShapes.IsNull() )
701 aReporter->
Report(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **" ),
706 aOutShape = unifiedShapes;
717 TopoDS_Compound compound;
718 BRep_Builder builder;
719 builder.MakeCompound( compound );
721 for(
const TopoDS_Shape& shape : aInputShapes )
722 builder.Add( compound, shape );
732 TopoDS_Shape outShape;
734 if( aInputShapes.Size() == 1 )
735 return aInputShapes.First();
737 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
746 const TCollection_ExtendedString& aPrefix )
748 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
752 Message::SendFail(
"Couldn't create assembly graph." );
753 return Standard_False;
756 Standard_Boolean anIsDone = Standard_True;
758 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
760 const TDF_Label& lbl = aG->GetNode( idx );
761 Handle( TDataStd_Name ) nameHandle;
763 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
765 TCollection_ExtendedString
name;
769 name += nameHandle->Get();
772 TDataStd_Name::Set( lbl,
name );
776 TDataStd_Name::Set( lbl, aPrefix );
787 m_app = XCAFApp_Application::GetApplication();
788 m_app->NewDocument(
"MDTV-XCAF", m_doc );
789 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
807 if( m_doc->CanClose() == CDM_CCS_OK )
815 const double c_padExtraThickness = 0.005;
817 std::vector<TopoDS_Shape> padShapes;
831 double Zpos, thickness;
837 if( pcb_layer ==
F_Cu )
838 thickness += c_padExtraThickness;
839 else if( pcb_layer ==
B_Cu )
840 thickness -= c_padExtraThickness;
843 TopoDS_Shape testShape;
857 if( testShape.IsNull() )
859 std::vector<TopoDS_Shape> testShapes;
863 if( testShapes.size() > 0 )
864 testShape = testShapes.front();
869 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
875 if( pcb_layer ==
F_Cu )
877 else if( pcb_layer ==
B_Cu )
893 double f_pos, f_thickness;
894 double b_pos, b_thickness;
901 f_thickness += c_padExtraThickness;
902 b_thickness -= c_padExtraThickness;
905 double top = std::max( f_pos, f_pos + f_thickness );
906 double bottom = std::min( b_pos, b_pos + b_thickness );
907 double hole_height =
top - bottom;
909 TopoDS_Shape plating;
917 hole_height, bottom, aOrigin ) )
919 padShapes.push_back( plating );
933 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
950 padShapes.push_back( plating );
962 if( !padShapes.empty() )
967 TopTools_ListOfShape padShapesList;
969 for(
const TopoDS_Shape& shape : padShapes )
970 padShapesList.Append( shape );
976 for(
const TopoDS_Shape& shape : padShapes )
987 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
989 double margin = 0.001;
997 double f_pos, f_thickness;
998 double b_pos, b_thickness;
1001 double top = std::max( f_pos, f_pos + f_thickness );
1002 double bottom = std::min( b_pos, b_pos + b_thickness );
1004 double holeZsize = (
top - bottom ) + ( margin * 2 );
1006 double boardDrill = aShape.
GetWidth();
1007 double copperDrill = boardDrill - aPlatingThickness * 2;
1009 TopoDS_Shape copperHole, boardHole;
1014 holeZsize, bottom - margin, aOrigin ) )
1027 holeZsize, bottom - margin, aOrigin ) )
1043 const wxString& aNetname )
1045 double f_pos, f_thickness;
1046 double b_pos, b_thickness;
1049 double top = std::max( f_pos, f_pos + f_thickness );
1050 double bottom = std::min( b_pos, b_pos + b_thickness );
1052 TopoDS_Shape plating;
1055 (
top - bottom ), bottom, aOrigin ) )
1077 double margin = 0.001;
1081 double copperMargin = 0.5;
1083 double start_pos, start_thickness;
1084 double end_pos, end_thickness;
1089 double top = std::max( { start_pos, start_pos + start_thickness,
1090 end_pos, end_pos + end_thickness } );
1091 double bottom = std::min( { start_pos, start_pos + start_thickness,
1092 end_pos, end_pos + end_thickness } );
1095 if( aLayerStart ==
F_Cu || aLayerEnd ==
F_Cu )
1096 top += copperMargin;
1097 if( aLayerStart ==
B_Cu || aLayerEnd ==
B_Cu )
1098 bottom -= copperMargin;
1100 double holeZsize = (
top - bottom ) + ( margin * 2 );
1101 double holeZpos = bottom - margin;
1103 double backdrillDiameter = aShape.
GetWidth();
1105 TopoDS_Shape backdrillHole;
1109 backdrillDiameter, holeZsize, holeZpos, aOrigin ) )
1126 bool aFrontSide,
const VECTOR2D& aOrigin )
1128 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: pos=(%d,%d) diameter=%d depth=%d frontSide=%d origin=(%f,%f)" ),
1129 aPosition.
x, aPosition.
y, aDiameter, aDepth, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1132 if( aDiameter <= 0 || aDepth <= 0 )
1134 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: REJECTED - invalid diameter=%d or depth=%d" ),
1135 aDiameter, aDepth );
1139 double margin = 0.001;
1142 double copperMargin = 0.5;
1145 double boardZpos, boardThickness;
1149 double f_pos, f_thickness, b_pos, b_thickness;
1156 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1157 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1159 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1160 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1163 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1164 double depth_mm =
pcbIUScale.IUTomm( aDepth );
1165 double radius_mm = diameter_mm / 2.0;
1167 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: diameter_mm=%f depth_mm=%f radius_mm=%f" ),
1168 diameter_mm, depth_mm, radius_mm );
1172 double cylinderZpos;
1173 double cylinderHeight;
1179 cylinderZpos = topOuterSurface - depth_mm - margin;
1180 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1186 cylinderZpos = bottomOuterSurface - copperMargin - margin;
1187 cylinderHeight = depth_mm + copperMargin + 2 * margin;
1191 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1192 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1194 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: posX_mm=%f posY_mm=%f cylinderZpos=%f cylinderHeight=%f" ),
1195 posX_mm, posY_mm, cylinderZpos, cylinderHeight );
1201 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, cylinderZpos ), gp::DZ() );
1203 TopoDS_Shape cylinder = BRepPrimAPI_MakeCylinder( axis, radius_mm, cylinderHeight );
1205 if( cylinder.IsNull() )
1207 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: FAILED - cylinder shape is null" ) );
1208 m_reporter->Report(
_(
"Failed to create counterbore cylinder shape" ),
1217 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: SUCCESS - added cylinder. boardCutouts=%zu copperCutouts=%zu" ),
1220 catch(
const Standard_Failure& e )
1222 wxLogTrace(
traceKiCad2Step, wxT(
"AddCounterbore: EXCEPTION - %s" ), e.GetMessageString() );
1223 m_reporter->Report( wxString::Format(
_(
"OCC exception creating counterbore: %s" ),
1224 e.GetMessageString() ),
1234 int aAngle,
bool aFrontSide,
const VECTOR2D& aOrigin )
1236 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: pos=(%d,%d) diameter=%d depth=%d angle=%d frontSide=%d origin=(%f,%f)" ),
1237 aPosition.
x, aPosition.
y, aDiameter, aDepth, aAngle, aFrontSide ? 1 : 0, aOrigin.
x, aOrigin.
y );
1242 if( aDiameter <= 0 || aAngle <= 0 )
1244 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: REJECTED - invalid diameter=%d or angle=%d" ),
1245 aDiameter, aAngle );
1249 double margin = 0.001;
1252 double copperMargin = 0.5;
1255 double boardZpos, boardThickness;
1259 double f_pos, f_thickness, b_pos, b_thickness;
1264 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1265 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1267 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: boardZpos=%f boardThickness=%f f_pos=%f f_thickness=%f topOuter=%f bottomOuter=%f" ),
1268 boardZpos, boardThickness, f_pos, f_thickness, topOuterSurface, bottomOuterSurface );
1271 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1272 double radius_mm = diameter_mm / 2.0;
1276 double halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1284 depth_mm = radius_mm / tan( halfAngleRad );
1285 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: depth not specified, calculated depth_mm=%f from radius=%f and angle" ),
1286 depth_mm, radius_mm );
1293 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: diameter_mm=%f depth_mm=%f radius_mm=%f halfAngleRad=%f (deg=%f)" ),
1294 diameter_mm, depth_mm, radius_mm, halfAngleRad, halfAngleRad * 180.0 /
M_PI );
1305 double bottomRadius_mm = radius_mm - depth_mm * tan( halfAngleRad );
1307 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: bottomRadius_mm=%f (before clamp), tan(halfAngle)=%f" ),
1308 bottomRadius_mm, tan( halfAngleRad ) );
1310 if( bottomRadius_mm < 0 )
1311 bottomRadius_mm = 0;
1316 double coneHeight = depth_mm + copperMargin + margin;
1320 double posX_mm =
pcbIUScale.IUTomm( aPosition.
x - aOrigin.
x );
1321 double posY_mm = -
pcbIUScale.IUTomm( aPosition.
y - aOrigin.
y );
1332 coneZpos = topOuterSurface - depth_mm - margin;
1333 r1 = bottomRadius_mm;
1335 r2 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1337 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FRONT - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1338 coneZpos, r1, r2, coneHeight );
1340 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1341 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1348 coneZpos = bottomOuterSurface - copperMargin - margin;
1350 r1 = radius_mm + ( copperMargin + margin ) * tan( halfAngleRad );
1351 r2 = bottomRadius_mm;
1353 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: BACK - coneZpos=%f r1=%f r2=%f coneHeight=%f" ),
1354 coneZpos, r1, r2, coneHeight );
1356 gp_Ax2 axis( gp_Pnt( posX_mm, posY_mm, coneZpos ), gp::DZ() );
1357 cone = BRepPrimAPI_MakeCone( axis, r1, r2, coneHeight );
1362 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: FAILED - cone shape is null" ) );
1363 m_reporter->Report(
_(
"Failed to create countersink cone shape" ),
1372 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: SUCCESS - added cone. boardCutouts=%zu copperCutouts=%zu" ),
1375 catch(
const Standard_Failure& e )
1377 wxLogTrace(
traceKiCad2Step, wxT(
"AddCountersink: EXCEPTION - %s" ), e.GetMessageString() );
1378 m_reporter->Report( wxString::Format(
_(
"OCC exception creating countersink: %s" ),
1379 e.GetMessageString() ),
1389 int aAngle,
bool aFrontSide )
1391 std::map<PCB_LAYER_ID, int> knockouts;
1394 double f_pos, f_thickness, b_pos, b_thickness;
1398 double topOuterSurface = std::max( f_pos, f_pos + f_thickness );
1399 double bottomOuterSurface = std::min( b_pos, b_pos + b_thickness );
1402 double diameter_mm =
pcbIUScale.IUTomm( aDiameter );
1403 double radius_mm = diameter_mm / 2.0;
1407 double halfAngleRad = 0.0;
1412 halfAngleRad = ( aAngle / 10.0 ) *
M_PI / 180.0 / 2.0;
1416 depth_mm = radius_mm / tan( halfAngleRad );
1427 double featureTop, featureBottom;
1431 featureTop = topOuterSurface;
1432 featureBottom = topOuterSurface - depth_mm;
1436 featureBottom = bottomOuterSurface;
1437 featureTop = bottomOuterSurface + depth_mm;
1440 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: featureTop=%f featureBottom=%f depth_mm=%f frontSide=%d" ),
1441 featureTop, featureBottom, depth_mm, aFrontSide ? 1 : 0 );
1450 double layerZ, layerThickness;
1454 double layerTop = std::max( layerZ, layerZ + layerThickness );
1455 double layerBottom = std::min( layerZ, layerZ + layerThickness );
1459 bool layerInRange = ( layerTop >= featureBottom && layerBottom <= featureTop );
1461 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d Z=[%f, %f] feature=[%f, %f] inRange=%d" ),
1462 static_cast<int>( layer ), layerBottom, layerTop, featureBottom, featureTop, layerInRange ? 1 : 0 );
1467 int knockoutDiameter;
1473 double layerSurfaceZ;
1477 layerSurfaceZ = layerTop;
1482 layerSurfaceZ = layerBottom;
1486 double distanceFromSurface;
1488 distanceFromSurface = topOuterSurface - layerSurfaceZ;
1490 distanceFromSurface = layerSurfaceZ - bottomOuterSurface;
1493 double radiusAtLayer_mm = radius_mm - distanceFromSurface * tan( halfAngleRad );
1495 if( radiusAtLayer_mm <= 0 )
1497 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d - countersink tapers to point before this layer" ),
1498 static_cast<int>( layer ) );
1502 knockoutDiameter =
pcbIUScale.mmToIU( radiusAtLayer_mm * 2.0 );
1503 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (countersink) - distFromSurface=%f radiusAtLayer=%f diameter=%d" ),
1504 static_cast<int>( layer ), distanceFromSurface, radiusAtLayer_mm, knockoutDiameter );
1509 knockoutDiameter = aDiameter;
1510 wxLogTrace(
traceKiCad2Step, wxT(
"GetCopperLayerKnockouts: layer %d (counterbore) - diameter=%d" ),
1511 static_cast<int>( layer ), knockoutDiameter );
1514 knockouts[layer] = knockoutDiameter;
1522 double& aThickness )
1525 static const double c_silkscreenAboveCopper = 0.04;
1526 static const double c_soldermaskAboveCopper = 0.015;
1534 double f_pos, f_thickness;
1536 double top = std::max( f_pos, f_pos + f_thickness );
1539 aZPos =
top + c_silkscreenAboveCopper;
1541 aZPos =
top + c_soldermaskAboveCopper;
1547 double b_pos, b_thickness;
1549 double bottom = std::min( b_pos, b_pos + b_thickness );
1552 aZPos = bottom - c_silkscreenAboveCopper;
1554 aZPos = bottom - c_soldermaskAboveCopper;
1562 double& aThickness )
1566 bool wasPrepreg =
false;
1568 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1571 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1577 if( aLayer ==
B_Cu )
1622 double f_pos, f_thickness;
1623 double b_pos, b_thickness;
1626 double top = std::min( f_pos, f_pos + f_thickness );
1627 double bottom = std::max( b_pos, b_pos + b_thickness );
1629 aThickness = (
top - bottom );
1632 wxASSERT( aZPos == 0.0 );
1637 const VECTOR2D& aOrigin,
const wxString& aNetname )
1639 bool success =
true;
1647 double z_pos, thickness;
1650 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1658 else if( aLayer ==
F_Mask )
1665 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1678 bool aBottom,
const VECTOR2D& aPosition,
double aRotation,
const VECTOR3D& aOffset,
1679 const VECTOR3D& aOrientation,
const VECTOR3D& aScale,
bool aSubstituteModels )
1681 if( aFileNameUTF8.empty() )
1683 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1688 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1693 wxString errorMessage;
1695 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1697 if( errorMessage.IsEmpty() )
1698 errorMessage.Printf(
_(
"No model for filename '%s'." ), fileName );
1705 TopLoc_Location toploc;
1707 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1709 m_reporter->Report( wxString::Format(
_(
"No location data for filename '%s'." ), fileName ),
1715 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1717 if( llabel.IsNull() )
1719 m_reporter->Report( wxString::Format(
_(
"Could not add component with filename '%s'." ), fileName ),
1725 TCollection_ExtendedString refdes( aRefDes.c_str() );
1726 TDataStd_Name::Set( llabel, refdes );
1800 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1801 double aZposition,
const VECTOR2D& aOrigin )
1808 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1809 double h_width = aWidth/2.0;
1811 coords[0] =
VECTOR2D{ 0.0, h_width };
1814 coords[1] =
VECTOR2D{ len, h_width };
1817 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1820 coords[3] =
VECTOR2D{ len, -h_width };
1823 coords[4] =
VECTOR2D{ 0, -h_width };
1826 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1829 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1831 for(
int ii = 0; ii < 6; ii++ )
1834 coords[ii] += aStartPoint;
1839 gp_Pnt coords3D[ 6 ];
1841 for(
int ii = 0; ii < 6; ii++ )
1843 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1844 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1848 BRepBuilderAPI_MakeWire wire;
1849 bool success =
true;
1861 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1866 edge = BRepBuilderAPI_MakeEdge(
circle );
1871 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1874 Handle( Geom_TrimmedCurve ) arcOfCircle =
1875 GC_MakeArcOfCircle( coords3D[1],
1879 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1882 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1885 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1886 GC_MakeArcOfCircle( coords3D[4],
1890 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1894 catch(
const Standard_Failure& e )
1896 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
1897 e.GetMessageString() ),
1902 BRepBuilderAPI_MakeFace face;
1906 gp_Pln plane( coords3D[0], gp::DZ() );
1907 face = BRepBuilderAPI_MakeFace( plane, wire );
1909 catch(
const Standard_Failure& e )
1911 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
1912 e.GetMessageString() ),
1917 if( aThickness != 0.0 )
1919 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1921 if( aShape.IsNull() )
1923 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
1940 double aZposition,
const VECTOR2D& aOrigin )
1942 std::vector<TopoDS_Shape> testShapes;
1945 aHeight, aZposition, aOrigin );
1947 if( testShapes.size() > 0 )
1948 aShape = testShapes.front();
1971 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
1975 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1977 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
1978 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
1988 gp_Pnt start = toPoint( aPt0 );
1989 gp_Pnt
end = toPoint( aPt1 );
1991 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
1993 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1995 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
2003 aMkWire.Add( mkEdge.Edge() );
2005 if( aMkWire.Error() != BRepLib_WireDone )
2007 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
2021 Handle( Geom_Curve ) curve;
2023 if( aArc.GetCentralAngle() ==
ANGLE_360 )
2025 gp_Ax2 axis = gp::XOY();
2026 axis.SetLocation( toPoint( aArc.GetCenter() ) );
2028 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
2032 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
2033 toPoint( aArc.GetP1() ) ).Value();
2036 if( curve.IsNull() )
2039 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
2041 if( !aMkWire.IsDone() )
2043 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
2044 "(%d %d), mid (%d %d), p1 (%d %d)" ),
2046 aArc.GetP0().x, aArc.GetP0().y,
2047 aArc.GetArcMid().x, aArc.GetArcMid().y,
2048 aArc.GetP1().x, aArc.GetP1().y ),
2058 bool isFirstShape =
true;
2071 if( nextShape != -1 )
2077 lastPt = aChain.
CPoint( i );
2087 firstPt = currentArc.
GetP0();
2092 lastPt = currentArc.
GetP0();
2094 if( addArc( lastPt, currentArc ) )
2095 lastPt = currentArc.
GetP1();
2114 isFirstShape =
false;
2117 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
2119 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
2121 firstPt.
x, firstPt.
y ),
2127 catch(
const Standard_Failure& e )
2129 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
2130 e.GetMessageString() ),
2140 bool aConvertToArcs,
double aThickness,
double aZposition,
2148 if( aConvertToArcs )
2152 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
2156 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2160 fallbackPoly = workingPoly;
2161 workingPoly = approximated;
2180 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
2182 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
2183 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
2187 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
2188 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
2190 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
2194 auto tryMakeWire = [
this, &aZposition,
2195 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
2198 BRepLib_MakeWire mkWire;
2202 if( mkWire.IsDone() )
2204 wire = mkWire.Wire();
2209 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
2210 "z: %g; bounding box: %s" ),
2211 static_cast<int>( aContour.PointCount() ),
2212 static_cast<int>( mkWire.Error() ),
2217 if( !wire.IsNull() )
2219 BRepAlgoAPI_Check check( wire,
false,
true );
2221 if( !check.IsValid() )
2223 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
2224 "z: %g; bounding box: %s" ),
2236 BRepBuilderAPI_MakeFace mkFace;
2238 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2244 bool allow_retry = aConvertToArcs ? true :
false;
2246 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
2248 if( aConvertToArcs && wire.IsNull() )
2250 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
2254 allow_retry =
false;
2255 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
2260 if( !wire.IsNull() )
2262 if( basePlane.Axis().Direction().Z() < 0 )
2265 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
2269 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
2270 "z: %g; bounding box: %s" ),
2279 if( !wire.IsNull() )
2281 if( basePlane.Axis().Direction().Z() > 0 )
2288 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
2289 "z: %g; bounding box: %s" ),
2296 catch(
const Standard_Failure& e )
2298 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
2299 static_cast<int>( contId ),
2300 e.GetMessageString() ),
2306 if( mkFace.IsDone() )
2308 TopoDS_Shape faceShape = mkFace.Shape();
2310 if( aThickness != 0.0 )
2312 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
2313 aShapes.push_back( prism );
2315 if( prism.IsNull() )
2323 aShapes.push_back( faceShape );
2339 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
2340 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
2341 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
2342 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
2343 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
2344 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
2345 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
2346 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
2356 if( aColorStr.StartsWith( wxT(
"#" ) ) )
2358 aColorOut =
COLOR4D( aColorStr );
2363 const std::vector<FAB_LAYER_COLOR>& colors =
2370 if( fabColor.GetName() == aColorStr )
2372 aColorOut = fabColor.GetColor( aType );
2394 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
2399 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
2404 double boardThickness;
2424 for(
size_t contId = 0; contId < polygon.size(); contId++ )
2428 polyset.
Append( contour );
2435 m_reporter->Report(
_(
"OCC error creating main outline." ),
2444 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
2456 BRepBndLib::Add( brdShape, brdBndBox );
2459 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2464 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
2468 Bnd_Box brdWithHolesBndBox = brdBndBox;
2470 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2472 for(
size_t i = 0; i < input.size(); i++ )
2475 BRepBndLib::Add( input[i], bbox );
2476 brdWithHolesBndBox.Add( bbox );
2477 ( *holeBoxSet )[i] = bbox;
2480 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2483 auto subtractShapesMap =
2484 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2485 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2487 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2490 for(
auto& [netname, vec] : aShapesMap )
2494 auto subtractLoopFn = [&](
const int shapeId )
2496 TopoDS_Shape& shape = vec[shapeId];
2499 BRepBndLib::Add( shape, shapeBbox );
2501 TopTools_ListOfShape holelist;
2504 std::unique_lock lock( mutex );
2506 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2508 for(
const Standard_Integer&
index : indices )
2509 holelist.Append( aHolesList[
index] );
2512 if( holelist.IsEmpty() )
2515 TopTools_ListOfShape cutArgs;
2516 cutArgs.Append( shape );
2518 BRepAlgoAPI_Cut
cut;
2520 cut.SetRunParallel(
true );
2521 cut.SetToFillHistory(
false );
2523 cut.SetArguments( cutArgs );
2524 cut.SetTools( holelist );
2527 if(
cut.HasErrors() ||
cut.HasWarnings() )
2529 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2536 if(
cut.HasErrors() )
2538 wxString msg =
_(
"Errors:\n" );
2539 wxStringOutputStream os_stream( &msg );
2540 wxStdOutputStream out( os_stream );
2542 cut.DumpErrors( out );
2546 if(
cut.HasWarnings() )
2548 wxString msg =
_(
"Warnings:\n" );
2549 wxStringOutputStream os_stream( &msg );
2550 wxStdOutputStream out( os_stream );
2552 cut.DumpWarnings( out );
2557 shape =
cut.Shape();
2560 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2564 auto subtractShapes =
2565 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2566 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2568 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2570 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
2571 aShapesList = aShapesMap[wxEmptyString];
2577 Bnd_BoundSortBox bsbHoles;
2585 Bnd_BoundSortBox bsbHoles;
2594 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2596 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2597 const std::vector<TopoDS_Shape>& aShapes )
2599 for(
const TopoDS_Shape& shape : aShapes )
2600 shapesToFuseMap[aNetname].Append( shape );
2604 addShapes( netname, shapes );
2607 addShapes( netname, shapes );
2610 addShapes( netname, shapes );
2617 auto fuseLoopFn = [&](
const wxString& aNetname )
2619 auto& toFuse = shapesToFuseMap[aNetname];
2622 if( !fusedShape.IsNull() )
2624 std::unique_lock lock( mutex );
2634 BS::multi_future<void> mf;
2636 for(
const auto& [netname,
_] : shapesToFuseMap )
2637 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2654 auto pushToAssemblyMap =
2655 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2656 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2657 bool aCompoundAll,
const wxString& aNiceName )
2659 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2663 std::vector<TopoDS_Shape> allShapes;
2665 for(
const auto& [netname, shapesList] : aShapesMap )
2666 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2668 if( !allShapes.empty() )
2669 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2673 shapesMap = aShapesMap;
2676 for(
const auto& [netname, shapesList] : shapesMap )
2678 std::vector<TopoDS_Shape> newList;
2683 newList = shapesList;
2687 for( TopoDS_Shape& shape : newList )
2689 Handle( TDataStd_TreeNode ) node;
2692 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2699 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2700 TDF_Label shpLbl = node->Father()->Label();
2702 if( !shpLbl.IsNull() )
2704 if( visMatTool && !aVisMatLabel.IsNull() )
2705 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2711 shapeName << aShapeName;
2713 if( !netname.empty() )
2716 shapeName << netname;
2719 if( newList.size() > 1 )
2725 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2726 TDataStd_Name::Set( shpLbl, partname );
2734 auto pushToAssembly =
2735 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2736 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2738 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2740 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2744 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2745 double aMetallic,
double aRoughness ) -> TDF_Label
2747 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2748 XCAFDoc_VisMaterialPBR pbr;
2749 pbr.BaseColor = aBaseColor;
2750 pbr.Metallic = aMetallic;
2751 pbr.Roughness = aRoughness;
2752 vismat->SetPbrMaterial( pbr );
2753 return visMatTool->AddMaterial( vismat, aName );
2760 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2761 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2762 Quantity_ColorRGBA back_silk_color = front_silk_color;
2763 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2764 Quantity_ColorRGBA back_mask_color = front_mask_color;
2774 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2778 if( item->GetBrdLayerId() ==
F_Mask )
2779 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2781 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2784 if( item->GetBrdLayerId() ==
F_SilkS )
2785 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2786 else if( item->GetBrdLayerId() ==
B_SilkS )
2787 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2790 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2796 board_color = front_mask_color;
2797 board_color.SetAlpha( 1.0 );
2800 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2801 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2802 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2803 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2804 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2805 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2806 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2808 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2812 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2813 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2814 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2815 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2817 if( aPushBoardBody )
2820#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2821 m_assy->UpdateAssemblies();
2830bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2834 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2842 wxFileName fn( aFileName );
2843 IGESControl_Controller::Init();
2844 IGESCAFControl_Writer writer;
2845 writer.SetColorMode( Standard_True );
2846 writer.SetNameMode( Standard_True );
2847 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2848 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2849 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2850 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2851 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2852 writer.Model()->SetGlobalSection( header );
2854 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2863 wxFileInputStream input( inputFile );
2864 wxFileOutputStream output( outputFile );
2868 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2872 if( !output.IsOk() )
2874 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2878 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2880 if( !zlibStream.IsOk() )
2882 m_reporter->Report(
_(
"Impossible create compress stream" ) );
2886 input.Read( zlibStream );
2888 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2890 m_reporter->Report(
_(
"Compress read or write error" ) );
2904 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2912 wxFileName fn( aFileName );
2914 STEPCAFControl_Writer writer;
2915 writer.SetColorMode( Standard_True );
2916 writer.SetNameMode( Standard_True );
2923 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2925 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2931 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2933 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2937 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2940 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2944 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2947 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2948 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2949 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2950 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2952 bool success =
true;
2955 wxString currCWD = wxGetCwd();
2956 wxString workCWD = fn.GetPath();
2958 if( !workCWD.IsEmpty() )
2959 wxSetWorkingDirectory( workCWD );
2961 wxString tmpfname(
"$tempfile$.step" );
2963 if( Standard_False == writer.Write( tmpfname.c_str() ) )
2966 if( compress && success )
2968 wxString srcTmp( tmpfname );
2969 wxString dstTmp(
"$tempfile$.stpz" );
2972 wxRemoveFile( srcTmp );
2983 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2985 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
2993 wxSetWorkingDirectory( currCWD );
3003 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3012 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3017 wxFileName fn( aFileName );
3019 wxFFileOutputStream ffStream( fn.GetFullPath() );
3020 wxStdOutputStream stdStream( ffStream );
3022#if OCC_VERSION_HEX >= 0x070600
3023 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
3025 BRepTools::Write( shape, stdStream );
3034 wxFileName fn( aFileName );
3036 wxFFileOutputStream ffStream( fn.GetFullPath() );
3037 wxStdOutputStream file( ffStream );
3039 if( !ffStream.IsOk() )
3041 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
3049 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
3054 std::map<wxString, std::vector<int>> groups[4];
3055 std::map<wxString, double> groupAreas;
3056 TopExp_Explorer exp;
3059 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3061 TopoDS_Shape subShape = exp.Current();
3064 BRepBndLib::Add( subShape, bbox );
3068 for(
const auto& pair : pairs )
3070 const auto& [point, padTestShape] = pair;
3072 if( bbox.IsOut( point ) )
3075 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
3077 if( surface.GetType() != GeomAbs_Plane )
3080 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
3083 if( !dist.IsDone() )
3086 if( dist.Value() < Precision::Approximation() )
3089 groups[2][padKey].push_back( faceIndex );
3091 GProp_GProps system;
3092 BRepGProp::SurfaceProperties( subShape, system );
3094 double surfaceArea = system.Mass() / 1e6;
3095 groupAreas[padKey] += surfaceArea;
3104 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
3105 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
3106 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
3107 file <<
" <shape format=\"BREP\"><![CDATA[";
3108#if OCC_VERSION_HEX < 0x070600
3109 BRepTools::Write( shape, file );
3111 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
3113 file <<
"]]></shape>" << std::endl;
3114 file <<
" <topology>" << std::endl;
3116 TopTools_IndexedMapOfShape mainMap;
3117 TopExp::MapShapes( shape, mainMap );
3118 std::set<int> topo[4];
3120 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
3123 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
3124 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
3126 for(
int dim = 0; dim < 4; dim++ )
3128 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
3130 TopoDS_Shape subShape = exp.Current();
3131 int idx = mainMap.FindIndex( subShape );
3133 if( idx && !topo[dim].count( idx ) )
3134 topo[dim].insert( idx );
3138 for(
int dim = 0; dim <= 3; dim++ )
3140 std::string labels = c_dimLabels[dim];
3141 std::string label = c_dimLabel[dim];
3143 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
3146 for(
auto p : topo[dim] )
3148 std::string
name(
"" );
3149 file <<
" <" << label <<
" index=\"" <<
index <<
"\" "
3150 <<
"name=\"" <<
name <<
"\" "
3151 <<
"reference=\"" << p <<
"\"/>" << std::endl;
3155 file <<
" </" << labels <<
">" << std::endl;
3158 file <<
" </topology>" << std::endl;
3159 file <<
" </geometry>" << std::endl;
3160 file <<
" <groups count=\""
3161 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
3164 int groupNumber = 1;
3169 for(
int dim = 0; dim <= 3; dim++ )
3171 std::string label = c_dimLabel[dim];
3173 for(
auto g : groups[dim] )
3176 wxString
name = g.first;
3180 std::ostringstream gs;
3181 gs <<
"G_" << dim <<
"D_" << g.first;
3184 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
3190 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
3192 for(
auto index : g.second )
3193 file <<
" <element index=\"" <<
index <<
"\"/>" << std::endl;
3195 file <<
" </group>" << std::endl;
3197 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
3209 file <<
" </groups>" << std::endl;
3210 file <<
" <fields count=\"0\"/>" << std::endl;
3211 file <<
"</XAO>" << std::endl;
3218 bool aSubstituteModels, wxString* aErrorMessage )
3220 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
3221 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
3223 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
3227 aLabel = mm->second;
3233 Handle( TDocStd_Document ) doc;
3234 m_app->NewDocument(
"MDTV-XCAF", doc );
3236 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
3239 wxFileName modelFile( fileName );
3240 std::string pname( modelFile.GetName().ToUTF8() );
3241 TCollection_ExtendedString partname( pname.c_str() );
3246 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
3248 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ),
3257 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
3259 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ),
3271 wxFFileInputStream ifile( fileName );
3272 wxFileName outFile( fileName );
3274 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
3275 outFile.SetExt( wxT(
"step" ) );
3276 wxFileOffset size = ifile.GetLength();
3278 if( size == wxInvalidOffset )
3280 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
3287 bool success =
false;
3288 wxFFileOutputStream ofile( outFile.GetFullPath() );
3293 char* buffer =
new char[size];
3295 ifile.Read( buffer, size );
3296 std::string expanded;
3300 expanded = gzip::decompress( buffer, size );
3305 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ),
3310 if( expanded.empty() )
3314 wxZipInputStream izipfile( ifile );
3315 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
3317 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
3319 izipfile.Read( ofile );
3325 ofile.Write( expanded.data(), expanded.size() );
3333 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
3353 if( aSubstituteModels )
3355 wxFileName wrlName( fileName );
3357 wxString basePath = wrlName.GetPath();
3358 wxString baseName = wrlName.GetName();
3366 alts.Add( wxT(
"stp" ) );
3367 alts.Add( wxT(
"step" ) );
3368 alts.Add( wxT(
"STP" ) );
3369 alts.Add( wxT(
"STEP" ) );
3370 alts.Add( wxT(
"Stp" ) );
3371 alts.Add( wxT(
"Step" ) );
3372 alts.Add( wxT(
"stpz" ) );
3373 alts.Add( wxT(
"stpZ" ) );
3374 alts.Add( wxT(
"STPZ" ) );
3375 alts.Add( wxT(
"step.gz" ) );
3376 alts.Add( wxT(
"stp.gz" ) );
3379 alts.Add( wxT(
"iges" ) );
3380 alts.Add( wxT(
"IGES" ) );
3381 alts.Add( wxT(
"igs" ) );
3382 alts.Add( wxT(
"IGS" ) );
3386 for(
const auto& alt : alts )
3388 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
3390 if( altFile.IsOk() && altFile.FileExists() )
3392 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
3415 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
3417 Handle( XCAFDoc_ShapeTool ) shapeTool = XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
3423 m_reporter->Report( wxString::Format( wxT(
"readVRML() failed on filename '%s'." ), fileName ),
3431 aErrorMessage->Printf(
_(
"Cannot use VRML models when exporting to non-mesh formats." ) );
3441 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ),
3449 if( aLabel.IsNull() )
3451 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ),
3459 TDataStd_Name::Set( aLabel, partname );
3469 TopLoc_Location& aLocation )
3483 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3489 double boardThickness;
3492 double top = std::max( boardZPos, boardZPos + boardThickness );
3493 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3498 double f_pos, f_thickness;
3502 bottom += f_thickness;
3509 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3510 lPos.Multiply( lRot );
3511 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3512 lPos.Multiply( lRot );
3517 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3518 lPos.Multiply( lRot );
3522 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3523 lPos.Multiply( lOff );
3526 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3527 lPos.Multiply( lOrient );
3528 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3529 lPos.Multiply( lOrient );
3530 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3531 lPos.Multiply( lOrient );
3533 aLocation = TopLoc_Location( lPos );
3540 IGESControl_Controller::Init();
3541 IGESCAFControl_Reader reader;
3542 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3544 if( stat != IFSelect_RetDone )
3548 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3552 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3556 reader.SetColorMode(
true );
3557 reader.SetNameMode(
false );
3558 reader.SetLayerMode(
false );
3560 if( !reader.Transfer( doc ) )
3562 if( doc->CanClose() == CDM_CCS_OK )
3569 if( reader.NbShapes() < 1 )
3571 if( doc->CanClose() == CDM_CCS_OK )
3583 STEPCAFControl_Reader reader;
3584 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3586 if( stat != IFSelect_RetDone )
3590 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3594 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3598 reader.SetColorMode(
true );
3599 reader.SetNameMode(
true );
3600 reader.SetLayerMode(
false );
3602 if( !reader.Transfer( doc ) )
3604 if( doc->CanClose() == CDM_CCS_OK )
3611 if( reader.NbRootsForTransfer() < 1 )
3613 if( doc->CanClose() == CDM_CCS_OK )
3625#if OCC_VERSION_HEX >= 0x070700
3626 VrmlAPI_CafReader reader;
3627 RWMesh_CoordinateSystemConverter conv;
3628 conv.SetInputLengthUnit( 2.54 );
3629 reader.SetCoordinateSystemConverter( conv );
3630 reader.SetDocument( doc );
3632 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3643 Handle( XCAFDoc_ColorTool )& aSrcColorTool,
3644 Handle( XCAFDoc_ShapeTool )& aDstShapeTool,
3645 Handle( XCAFDoc_ColorTool )& aDstColorTool )
3648 TDF_LabelSequence srcLabels;
3649 aSrcShapeTool->GetShapes( srcLabels );
3651 for( Standard_Integer i = 1; i <= srcLabels.Length(); i++ )
3653 TDF_Label srcLabel = srcLabels.Value( i );
3654 TopoDS_Shape srcShape = aSrcShapeTool->GetShape( srcLabel );
3656 if( srcShape.IsNull() )
3662 if( !aDstShapeTool->Search( srcShape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3666 Quantity_ColorRGBA surfColor;
3668 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorSurf, surfColor ) )
3669 aDstColorTool->SetColor( dstLabel, surfColor, XCAFDoc_ColorSurf );
3672 Quantity_ColorRGBA curvColor;
3674 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorCurv, curvColor ) )
3675 aDstColorTool->SetColor( dstLabel, curvColor, XCAFDoc_ColorCurv );
3678 Quantity_ColorRGBA genColor;
3680 if( aSrcColorTool->GetColor( srcLabel, XCAFDoc_ColorGen, genColor ) )
3681 aDstColorTool->SetColor( dstLabel, genColor, XCAFDoc_ColorGen );
3684 if( aSrcShapeTool->IsSimpleShape( srcLabel ) )
3686 TopoDS_Shape shape = aSrcShapeTool->GetShape( srcLabel );
3688 for( TopExp_Explorer exp( shape, TopAbs_FACE ); exp.More(); exp.Next() )
3690 TopoDS_Face face = TopoDS::Face( exp.Current() );
3691 Quantity_ColorRGBA faceColor;
3693 if( aSrcColorTool->GetColor( face, XCAFDoc_ColorSurf, faceColor ) )
3694 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorSurf );
3695 else if( aSrcColorTool->GetColor( face, XCAFDoc_ColorGen, faceColor ) )
3696 aDstColorTool->SetColor( face, faceColor, XCAFDoc_ColorGen );
3702 TDF_LabelSequence srcFreeShapes;
3703 aSrcShapeTool->GetFreeShapes( srcFreeShapes );
3705 std::function<void(
const TDF_Label& )> transferColorsRecursive = [&](
const TDF_Label& aLabel )
3707 TopoDS_Shape shape = aSrcShapeTool->GetShape( aLabel );
3709 if( shape.IsNull() )
3715 if( aDstShapeTool->Search( shape, dstLabel, Standard_True, Standard_True, Standard_False ) )
3717 Quantity_ColorRGBA color;
3719 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorSurf, color ) )
3720 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorSurf );
3722 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorCurv, color ) )
3723 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorCurv );
3725 if( aSrcColorTool->GetColor( aLabel, XCAFDoc_ColorGen, color ) )
3726 aDstColorTool->SetColor( dstLabel, color, XCAFDoc_ColorGen );
3730 for( TDF_ChildIterator it( aLabel ); it.More(); it.Next() )
3731 transferColorsRecursive( it.Value() );
3734 if( aSrcShapeTool->IsAssembly( aLabel ) )
3736 TDF_LabelSequence components;
3737 aSrcShapeTool->GetComponents( aLabel, components );
3739 for( Standard_Integer j = 1; j <= components.Length(); j++ )
3741 TDF_Label compLabel = components.Value( j );
3744 if( aSrcShapeTool->GetReferredShape( compLabel, refLabel ) )
3745 transferColorsRecursive( refLabel );
3750 for( Standard_Integer i = 1; i <= srcFreeShapes.Length(); i++ )
3751 transferColorsRecursive( srcFreeShapes.Value( i ) );
3760 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3761 Handle( XCAFDoc_ColorTool ) s_color = XCAFDoc_DocumentTool::ColorTool( source->Main() );
3764 TDF_LabelSequence frshapes;
3765 s_assy->GetFreeShapes( frshapes );
3768 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3769 Handle( XCAFDoc_ColorTool ) d_color = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
3772 TDF_Label d_targetLabel = d_assy->NewShape();
3774 auto copyLabel = [&]( TDF_Label& d_label,
const TDF_Label& s_label ) ->
bool
3780 if( TDF_Tool::IsSelfContained( s_label ) )
3782 TDocStd_XLinkTool link;
3783 link.Copy( d_label, s_label );
3789 TopoDS_Shape shape = s_assy->GetShape( s_label );
3791 if( shape.IsNull() )
3796 d_assy->SetShape( d_label, shape );
3798 m_reporter->Report( wxT(
"Model contains non-self-contained data; some metadata may be lost." ),
3804 if( frshapes.Size() == 1 )
3806 if( !copyLabel( d_targetLabel, frshapes.First() ) )
3815 for( TDF_Label& s_shapeLabel : frshapes )
3817 TDF_Label d_component = d_assy->NewShape();
3819 if( !copyLabel( d_component, s_shapeLabel ) )
3825 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3834 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3837 return d_targetLabel;
3843 TDF_LabelSequence freeShapes;
3844 aShapeTool->GetFreeShapes( freeShapes );
3850 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3852 TDF_Label label = freeShapes.Value( i );
3854 aShapeTool->GetShape( label, shape );
3859 const Standard_Real linearDeflection = 0.14;
3860 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3861 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3883 wxFileName fn( aFileName );
3885 const char* tmpGltfname =
"$tempfile$.glb";
3886 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3888 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3889 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3890 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3891 RWMesh_CoordinateSystem_Zup );
3892#if OCC_VERSION_HEX >= 0x070700
3893 cafWriter.SetParallel(
true );
3895 TColStd_IndexedDataMapOfStringString metadata;
3897 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3898 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3899 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3900 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3901 metadata.Add( TCollection_AsciiString(
"generator" ),
3902 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3903 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3906 bool success =
true;
3909 wxString currCWD = wxGetCwd();
3910 wxString workCWD = fn.GetPath();
3912 if( !workCWD.IsEmpty() )
3913 wxSetWorkingDirectory( workCWD );
3915 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3922 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3924 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3932 wxSetWorkingDirectory( currCWD );
3940#if OCC_VERSION_HEX < 0x070700
3947 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3957 wxFileName fn( aFileName );
3959 const char* tmpFname =
"$tempfile$.ply";
3960 RWPly_CafWriter cafWriter( tmpFname );
3962 cafWriter.SetFaceId(
true );
3963 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3964 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
3966 TColStd_IndexedDataMapOfStringString metadata;
3968 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3969 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3970 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3971 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3972 metadata.Add( TCollection_AsciiString(
"generator" ),
3973 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
3975 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3978 bool success =
true;
3981 wxString currCWD = wxGetCwd();
3982 wxString workCWD = fn.GetPath();
3984 if( !workCWD.IsEmpty() )
3985 wxSetWorkingDirectory( workCWD );
3987 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3994 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3996 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4004 wxSetWorkingDirectory( currCWD );
4015 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
4025 wxFileName fn( aFileName );
4027 const char* tmpFname =
"$tempfile$.stl";
4030 wxString currCWD = wxGetCwd();
4031 wxString workCWD = fn.GetPath();
4033 if( !workCWD.IsEmpty() )
4034 wxSetWorkingDirectory( workCWD );
4036 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
4043 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4045 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
4053 wxSetWorkingDirectory( currCWD );
4065 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4074 wxFileName fn( aFileName );
4076 const char* tmpFname =
"$tempfile$.u3d";
4079 wxString currCWD = wxGetCwd();
4080 wxString workCWD = fn.GetPath();
4082 if( !workCWD.IsEmpty() )
4083 wxSetWorkingDirectory( workCWD );
4086 bool success = writer.
Perform( m_doc );
4092 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
4094 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
4101 wxSetWorkingDirectory( currCWD );
4112 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
4121 wxFileName fn( aFileName );
4123 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
4124 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
4126 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
4127 bool success = writer.
Perform( m_doc );
4130 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
4132 plotter->SetColorMode(
true );
4133 plotter->Set3DExport(
true );
4134 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
4136 plotter->SetRenderSettings( &renderSettings );
4138 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
4140 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
4146 plotter->StartPlot(
"1",
"3D Model" );
4147 double fov_degrees = 16.5f;
4152 std::vector<PDF_3D_VIEW> views;
4157 std::vector<float> c2wMatrix =
4161 .m_name =
"Default",
4162 .m_cameraMatrix = c2wMatrix,
4163 .m_cameraCenter = (float)
distance,
4164 .m_fov = (
float) fov_degrees,
4173 .m_cameraMatrix = c2wMatrix,
4174 .m_cameraCenter = (float)
distance,
4175 .m_fov = (
float) fov_degrees,
4184 .m_cameraMatrix = c2wMatrix,
4185 .m_cameraCenter = (float)
distance,
4186 .m_fov = (
float) fov_degrees,
4195 .m_cameraMatrix = c2wMatrix,
4196 .m_cameraCenter = (float)
distance,
4197 .m_fov = (
float) fov_degrees,
4200 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
4209 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
4211 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
4212 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
4218 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 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)
bool getModelLabel(const std::string &aFileNameUTF8, const VECTOR3D &aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
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)
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)
bool AddComponent(const std::string &aFileName, const std::string &aRefDes, bool aBottom, const VECTOR2D &aPosition, double aRotation, const VECTOR3D &aOffset, const VECTOR3D &aOrientation, const VECTOR3D &aScale, bool aSubstituteModels=true)
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()
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
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