32#include <wx/filename.h>
34#include <wx/sstream.h>
35#include <wx/stdpaths.h>
38#include <wx/zstream.h>
39#include <wx/wfstream.h>
40#include <wx/zipstrm.h>
41#include <wx/stdstream.h>
44#include <decompress.hpp>
64#include <IGESCAFControl_Reader.hxx>
65#include <IGESCAFControl_Writer.hxx>
66#include <IGESControl_Controller.hxx>
67#include <IGESData_GlobalSection.hxx>
68#include <IGESData_IGESModel.hxx>
69#include <Interface_Static.hxx>
70#include <Quantity_Color.hxx>
71#include <STEPCAFControl_Reader.hxx>
72#include <STEPCAFControl_Writer.hxx>
73#include <APIHeaderSection_MakeHeader.hxx>
74#include <Standard_Failure.hxx>
75#include <Standard_Handle.hxx>
76#include <Standard_Version.hxx>
77#include <TCollection_ExtendedString.hxx>
78#include <TDocStd_Document.hxx>
79#include <TDocStd_XLinkTool.hxx>
80#include <TDataStd_Name.hxx>
81#include <TDataStd_TreeNode.hxx>
82#include <TDF_LabelSequence.hxx>
83#include <TDF_Tool.hxx>
84#include <TopExp_Explorer.hxx>
86#include <XCAFApp_Application.hxx>
88#include <XCAFDoc_DocumentTool.hxx>
89#include <XCAFDoc_ColorTool.hxx>
90#include <XCAFDoc_ShapeTool.hxx>
91#include <XCAFDoc_VisMaterialTool.hxx>
92#include <XCAFDoc_Area.hxx>
93#include <XCAFDoc_Centroid.hxx>
94#include <XCAFDoc_Location.hxx>
95#include <XCAFDoc_Volume.hxx>
97#include "KI_XCAFDoc_AssemblyGraph.hxx"
99#include <BRep_Tool.hxx>
100#include <BRepMesh_IncrementalMesh.hxx>
101#include <BRepBuilderAPI_GTransform.hxx>
102#include <BRepBuilderAPI_MakeEdge.hxx>
103#include <BRepBuilderAPI_MakeWire.hxx>
104#include <BRepBuilderAPI_MakeFace.hxx>
105#include <BRepExtrema_DistShapeShape.hxx>
106#include <BRepPrimAPI_MakePrism.hxx>
107#include <BRepTools.hxx>
108#include <BRepLib_MakeWire.hxx>
109#include <BRepAdaptor_Surface.hxx>
110#include <BRepAlgoAPI_Check.hxx>
111#include <BRepAlgoAPI_Cut.hxx>
112#include <BRepAlgoAPI_Fuse.hxx>
113#include <ShapeUpgrade_UnifySameDomain.hxx>
115#include <BRepBndLib.hxx>
116#include <Bnd_BoundSortBox.hxx>
117#include <GProp_GProps.hxx>
118#include <BRepGProp.hxx>
120#include <Geom_Curve.hxx>
121#include <Geom_TrimmedCurve.hxx>
126#include <GC_MakeArcOfCircle.hxx>
127#include <GC_MakeCircle.hxx>
129#include <RWGltf_CafWriter.hxx>
130#include <StlAPI_Writer.hxx>
132#if OCC_VERSION_HEX >= 0x070700
133#include <VrmlAPI_CafReader.hxx>
134#include <RWPly_CafWriter.hxx>
162 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
164 if( !lfile.FileExists() )
167 wxString ext = lfile.GetExt().Lower();
169 if( ext == wxT(
"wrl" ) )
172 if( ext == wxT(
"wrz" ) )
175 if( ext == wxT(
"idf" ) )
178 if( ext == wxT(
"emn" ) )
181 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
195 const int max_line_count = 3;
197 for(
int ii = 0; ii < max_line_count; ii++ )
199 memset( iline, 0, 82 );
200 ifile.getline( iline, 82 );
206 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
212 std::string fstr = iline;
216 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
225 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
232 if( strncmp( iline,
"/*", 2 ) != 0 )
250 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
251 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
252 double det = -b.
x * d.
y + d.
x * b.
y;
256 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
257 center.
y = ( b.
x * cd + d.
x * bc ) * det;
264#define APPROX_DBG( stmt )
272 static const double c_radiusDeviation = 1000.0;
273 static const double c_arcCenterDeviation = 1000.0;
274 static const double c_relLengthDeviation = 0.8;
275 static const int c_last_none = -1000;
295 int last = c_last_none;
301 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
303 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
308 bool defective =
false;
314 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
322 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
323 defective |=
std::abs( a_diff ) < 0.1;
326 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
327 defective |=
std::abs( a_diff ) >= maxAngleDiff;
338 for(
int j = i; j <= jEndIdx; j++ )
343 double rad_test = ( p_test -
center ).EuclideanNorm();
344 double d_tl = ( p_test - p_prev ).EuclideanNorm();
348 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
351 if( rad_dev > c_radiusDeviation )
354 <<
" Radius deviation too large: " << int64_t( rad_dev )
355 <<
" > " << c_radiusDeviation << std::endl );
360 double maxAngleDiff =
361 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
363 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
364 if(
std::abs( a_diff_test ) >= maxAngleDiff )
366 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
371 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
373 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
374 <<
"; " << d01 << std::endl );
384 if( last != c_last_none )
393 int toRemove = last - ( aSrc.
PointCount() - 3 );
423 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
427 if( last == c_last_none )
444 if( iarc0 != -1 && iarc1 != -1 )
446 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
456 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
474 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
475 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
491static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
493 TDF_LabelSequence theLabels;
494 aShapeTool->GetFreeShapes( theLabels );
498 if( theLabels.Length() == 1 )
499 return aShapeTool->GetShape( theLabels.Value( 1 ) );
501 TopoDS_Compound aCompound;
502 BRep_Builder aBuilder;
503 aBuilder.MakeCompound( aCompound );
505 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
507 TopoDS_Shape aFreeShape;
509 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
512 aBuilder.Add( aCompound, aFreeShape );
515 if( aCompound.NbChildren() > 0 )
524static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
526 if( theLabel.IsNull() )
528 Message::SendFail(
"Null label." );
529 return Standard_False;
532 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
533 || Abs( aScale.Z() ) <= gp::Resolution() )
535 Message::SendFail(
"Scale factor is too small." );
536 return Standard_False;
539 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
541 if( aShapeTool.IsNull() )
543 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
544 return Standard_False;
547 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
551 Message::SendFail(
"Couldn't create assembly graph." );
552 return Standard_False;
555 Standard_Boolean anIsDone = Standard_True;
559 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
561 0, 0, aScale.Z() ) );
564 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
566 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
568 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
570 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
571 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
576 const TDF_Label& aLabel = aG->GetNode( idx );
578 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
580 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
581 aBRepTrsf.Perform( aShape, Standard_True );
582 if( !aBRepTrsf.IsDone() )
584 Standard_SStream aSS;
585 TCollection_AsciiString anEntry;
586 TDF_Tool::Entry( aLabel, anEntry );
587 aSS <<
"Shape " << anEntry <<
" is not scaled!";
588 Message::SendFail( aSS.str().c_str() );
589 anIsDone = Standard_False;
590 return Standard_False;
592 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
593 aShapeTool->SetShape( aLabel, aScaledShape );
596 TDF_LabelSequence aSubshapes;
597 aShapeTool->GetSubShapes( aLabel, aSubshapes );
598 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
600 const TDF_Label& aLSs = anItSs.Value();
601 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
602 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
603 aShapeTool->SetShape( aLSs, aSs1 );
607 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
608 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
609 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
611 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
613 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
614 gp_Trsf aTrsf = aLoc.Transformation();
615 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
616 XCAFDoc_Location::Set( aLabel, aTrsf );
622 return Standard_False;
625 aShapeTool->UpdateAssemblies();
633 BRepAlgoAPI_Fuse mkFuse;
634 TopTools_ListOfShape shapeArguments, shapeTools;
636 for( TopoDS_Shape& sh : aInputShapes )
641 if( shapeArguments.IsEmpty() )
642 shapeArguments.Append( sh );
644 shapeTools.Append( sh );
647 mkFuse.SetRunParallel(
true );
648 mkFuse.SetToFillHistory(
false );
649 mkFuse.SetArguments( shapeArguments );
650 mkFuse.SetTools( shapeTools );
653 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
657 if( mkFuse.HasErrors() )
659 wxString msg =
_(
"Errors:\n" );
660 wxStringOutputStream os_stream( &msg );
661 wxStdOutputStream out( os_stream );
663 mkFuse.DumpErrors( out );
667 if( mkFuse.HasWarnings() )
669 wxString msg =
_(
"Warnings:\n" );
670 wxStringOutputStream os_stream( &msg );
671 wxStdOutputStream out( os_stream );
673 mkFuse.DumpWarnings( out );
678 if( mkFuse.IsDone() )
680 TopoDS_Shape fusedShape = mkFuse.Shape();
682 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
683 unify.History() =
nullptr;
686 TopoDS_Shape unifiedShapes = unify.Shape();
688 if( unifiedShapes.IsNull() )
690 aReporter->
Report(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ),
695 aOutShape = unifiedShapes;
706 TopoDS_Compound compound;
707 BRep_Builder builder;
708 builder.MakeCompound( compound );
710 for(
const TopoDS_Shape& shape : aInputShapes )
711 builder.Add( compound, shape );
721 TopoDS_Shape outShape;
723 if( aInputShapes.Size() == 1 )
724 return aInputShapes.First();
726 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
735 const TCollection_ExtendedString& aPrefix )
737 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
741 Message::SendFail(
"Couldn't create assembly graph." );
742 return Standard_False;
745 Standard_Boolean anIsDone = Standard_True;
747 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
749 const TDF_Label& lbl = aG->GetNode( idx );
750 Handle( TDataStd_Name ) nameHandle;
752 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
754 TCollection_ExtendedString
name;
758 name += nameHandle->Get();
761 TDataStd_Name::Set( lbl,
name );
765 TDataStd_Name::Set( lbl, aPrefix );
774 m_reporter( aReporter )
776 m_app = XCAFApp_Application::GetApplication();
777 m_app->NewDocument(
"MDTV-XCAF", m_doc );
778 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
789 m_outFmt = OUTPUT_FORMAT::FMT_OUT_UNKNOWN;
795 if( m_doc->CanClose() == CDM_CCS_OK )
803 const double c_padExtraThickness = 0.005;
805 std::vector<TopoDS_Shape> padShapes;
806 bool castellated = aClipPolygon && aPad->
GetProperty() == PAD_PROP::CASTELLATED;
819 double Zpos, thickness;
825 if( pcb_layer ==
F_Cu )
826 thickness += c_padExtraThickness;
827 else if( pcb_layer ==
B_Cu )
828 thickness -= c_padExtraThickness;
831 TopoDS_Shape testShape;
845 if( testShape.IsNull() )
847 std::vector<TopoDS_Shape> testShapes;
851 if( testShapes.size() > 0 )
852 testShape = testShapes.front();
855 if( !aVia && !testShape.IsNull() )
857 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
863 if( pcb_layer ==
F_Cu )
865 else if( pcb_layer ==
B_Cu )
881 double f_pos, f_thickness;
882 double b_pos, b_thickness;
889 f_thickness += c_padExtraThickness;
890 b_thickness -= c_padExtraThickness;
893 double top = std::max( f_pos, f_pos + f_thickness );
894 double bottom = std::min( b_pos, b_pos + b_thickness );
895 double hole_height = top - bottom;
897 TopoDS_Shape plating;
905 hole_height, bottom, aOrigin ) )
907 padShapes.push_back( plating );
921 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
938 padShapes.push_back( plating );
950 if( !padShapes.empty() )
955 TopTools_ListOfShape padShapesList;
957 for(
const TopoDS_Shape& shape : padShapes )
958 padShapesList.Append( shape );
964 for(
const TopoDS_Shape& shape : padShapes )
975 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
977 double margin = 0.001;
985 double f_pos, f_thickness;
986 double b_pos, b_thickness;
989 double top = std::max( f_pos, f_pos + f_thickness );
990 double bottom = std::min( b_pos, b_pos + b_thickness );
992 double holeZsize = ( top - bottom ) + ( margin * 2 );
994 double boardDrill = aShape.
GetWidth();
995 double copperDrill = boardDrill - aPlatingThickness * 2;
997 TopoDS_Shape copperHole, boardHole;
1002 holeZsize, bottom - margin, aOrigin ) )
1015 holeZsize, bottom - margin, aOrigin ) )
1031 const wxString& aNetname )
1033 double f_pos, f_thickness;
1034 double b_pos, b_thickness;
1037 double top = std::max( f_pos, f_pos + f_thickness );
1038 double bottom = std::min( b_pos, b_pos + b_thickness );
1040 TopoDS_Shape plating;
1043 ( top - bottom ), bottom, aOrigin ) )
1058 double& aThickness )
1061 static const double c_silkscreenAboveCopper = 0.04;
1062 static const double c_soldermaskAboveCopper = 0.015;
1070 double f_pos, f_thickness;
1072 double top = std::max( f_pos, f_pos + f_thickness );
1075 aZPos = top + c_silkscreenAboveCopper;
1077 aZPos = top + c_soldermaskAboveCopper;
1083 double b_pos, b_thickness;
1085 double bottom = std::min( b_pos, b_pos + b_thickness );
1088 aZPos = bottom - c_silkscreenAboveCopper;
1090 aZPos = bottom - c_soldermaskAboveCopper;
1098 double& aThickness )
1102 bool wasPrepreg =
false;
1107 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1113 if( aLayer ==
B_Cu )
1158 double f_pos, f_thickness;
1159 double b_pos, b_thickness;
1162 double top = std::min( f_pos, f_pos + f_thickness );
1163 double bottom = std::max( b_pos, b_pos + b_thickness );
1165 aThickness = ( top - bottom );
1168 wxASSERT( aZPos == 0.0 );
1173 const VECTOR2D& aOrigin,
const wxString& aNetname )
1175 bool success =
true;
1183 double z_pos, thickness;
1193 m_reporter->
Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s.\n" ),
1209 if( aFileNameUTF8.empty() )
1211 m_reporter->
Report( wxString::Format(
_(
"No model defined for %s.\n" ), aRefDes ),
1216 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1221 wxString errorMessage;
1223 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1225 if( errorMessage.IsEmpty() )
1226 errorMessage.Printf(
_(
"No model for filename '%s'.\n" ), fileName );
1233 TopLoc_Location toploc;
1235 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1237 m_reporter->
Report( wxString::Format(
_(
"No location data for filename '%s'.\n" ), fileName ),
1243 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1245 if( llabel.IsNull() )
1247 m_reporter->
Report( wxString::Format(
_(
"Could not add component with filename '%s'.\n" ), fileName ),
1253 TCollection_ExtendedString refdes( aRefDes.c_str() );
1254 TDataStd_Name::Set( llabel, refdes );
1321 double aWidth,
double aThickness,
1322 double aZposition,
const VECTOR2D& aOrigin )
1329 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1330 double h_width = aWidth/2.0;
1332 coords[0] =
VECTOR2D{ 0.0, h_width };
1335 coords[1] =
VECTOR2D{ len, h_width };
1338 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1341 coords[3] =
VECTOR2D{ len, -h_width };
1344 coords[4] =
VECTOR2D{ 0, -h_width };
1347 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1350 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1352 for(
int ii = 0; ii < 6; ii++ )
1355 coords[ii] += aStartPoint;
1360 gp_Pnt coords3D[ 6 ];
1362 for(
int ii = 0; ii < 6; ii++ )
1369 BRepBuilderAPI_MakeWire wire;
1370 bool success =
true;
1382 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1387 edge = BRepBuilderAPI_MakeEdge(
circle );
1392 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1395 Handle( Geom_TrimmedCurve ) arcOfCircle =
1396 GC_MakeArcOfCircle( coords3D[1],
1400 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1403 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1406 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1407 GC_MakeArcOfCircle( coords3D[4],
1411 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1415 catch(
const Standard_Failure& e )
1417 m_reporter->
Report( wxString::Format(
_(
"OCC exception building shape segment: %s\n" ),
1418 e.GetMessageString() ),
1423 BRepBuilderAPI_MakeFace face;
1427 gp_Pln plane( coords3D[0], gp::DZ() );
1428 face = BRepBuilderAPI_MakeFace( plane, wire );
1430 catch(
const Standard_Failure& e )
1433 e.GetMessageString() ),
1438 if( aThickness != 0.0 )
1440 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1442 if( aShape.IsNull() )
1461 double aZposition,
const VECTOR2D& aOrigin )
1463 std::vector<TopoDS_Shape> testShapes;
1466 aHeight, aZposition, aOrigin );
1468 if( testShapes.size() > 0 )
1469 aShape = testShapes.front();
1492 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
1496 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1509 gp_Pnt start = toPoint( aPt0 );
1510 gp_Pnt
end = toPoint( aPt1 );
1512 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
1514 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1516 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
1524 aMkWire.Add( mkEdge.Edge() );
1526 if( aMkWire.Error() != BRepLib_WireDone )
1528 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)\n" ),
1542 Handle( Geom_Curve ) curve;
1544 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1546 gp_Ax2 axis = gp::XOY();
1547 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1549 curve = GC_MakeCircle( axis,
pcbIUScale.
IUTomm( aArc.GetRadius() ) ).Value();
1553 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1554 toPoint( aArc.GetP1() ) ).Value();
1557 if( curve.IsNull() )
1560 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1562 if( !aMkWire.IsDone() )
1564 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
1565 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1567 aArc.GetP0().x, aArc.GetP0().y,
1568 aArc.GetArcMid().x, aArc.GetArcMid().y,
1569 aArc.GetP1().x, aArc.GetP1().y ),
1579 bool isFirstShape =
true;
1592 if( nextShape != -1 )
1598 lastPt = aChain.
CPoint( i );
1608 firstPt = currentArc.
GetP0();
1613 lastPt = currentArc.
GetP0();
1615 if( addArc( lastPt, currentArc ) )
1616 lastPt = currentArc.
GetP1();
1635 isFirstShape =
false;
1638 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1640 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **\n" ),
1642 firstPt.
x, firstPt.
y ),
1648 catch(
const Standard_Failure& e )
1650 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s\n" ),
1651 e.GetMessageString() ),
1661 bool aConvertToArcs,
double aThickness,
double aZposition,
1669 if( aConvertToArcs )
1673 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1677 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1681 fallbackPoly = workingPoly;
1682 workingPoly = approximated;
1701 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1708 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1709 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1711 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1715 auto tryMakeWire = [
this, &aZposition,
1719 BRepLib_MakeWire mkWire;
1723 if( mkWire.IsDone() )
1725 wire = mkWire.Wire();
1729 m_reporter->
Report( wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
1730 "z: %g; bounding box: %s\n" ),
1731 static_cast<int>( aContour.PointCount() ),
1732 static_cast<int>( mkWire.Error() ),
1737 if( !wire.IsNull() )
1739 BRepAlgoAPI_Check check( wire,
false,
true );
1741 if( !check.IsValid() )
1743 m_reporter->
Report( wxString::Format(
_(
"Wire self-interference check failed\n"
1744 "z: %g; bounding box: %s\n" ),
1755 BRepBuilderAPI_MakeFace mkFace;
1757 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1761 TopoDS_Wire wire = tryMakeWire( polygon[contId] );
1763 if( aConvertToArcs && wire.IsNull() )
1769 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId] );
1774 if( !wire.IsNull() )
1776 if( basePlane.Axis().Direction().Z() < 0 )
1779 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1784 "z: %g; bounding box: %s\n" ),
1793 if( !wire.IsNull() )
1795 if( basePlane.Axis().Direction().Z() > 0 )
1803 "z: %g; bounding box: %s\n" ),
1810 catch(
const Standard_Failure& e )
1812 m_reporter->
Report( wxString::Format(
_(
"OCC exception creating contour %d: %s\n" ),
1813 static_cast<int>( contId ),
1814 e.GetMessageString() ),
1820 if( mkFace.IsDone() )
1822 TopoDS_Shape faceShape = mkFace.Shape();
1824 if( aThickness != 0.0 )
1826 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1827 aShapes.push_back( prism );
1829 if( prism.IsNull() )
1837 aShapes.push_back( faceShape );
1853 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1854 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1855 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1856 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1857 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1858 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1859 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1860 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1870 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1872 aColorOut =
COLOR4D( aColorStr );
1877 const std::vector<FAB_LAYER_COLOR>& colors =
1884 if( fabColor.GetName() == aColorStr )
1886 aColorOut = fabColor.GetColor( aType );
1908 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1913 m_reporter->
Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1918 double boardThickness;
1938 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1942 polyset.
Append( contour );
1970 BRepBndLib::Add( brdShape, brdBndBox );
1973 m_reporter->
Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1978 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1982 Bnd_Box brdWithHolesBndBox = brdBndBox;
1984 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1986 for(
size_t i = 0; i < input.size(); i++ )
1989 BRepBndLib::Add( input[i], bbox );
1990 brdWithHolesBndBox.Add( bbox );
1991 ( *holeBoxSet )[i] = bbox;
1994 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1997 auto subtractShapesMap =
1998 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
1999 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2001 m_reporter->
Report( wxString::Format(
_(
"Subtracting holes for %s\n" ), aWhat ),
2004 for(
auto& [netname, vec] : aShapesMap )
2008 auto subtractLoopFn = [&](
const int a,
const int b )
2010 for(
int shapeId = a; shapeId < b; shapeId++ )
2012 TopoDS_Shape& shape = vec[shapeId];
2015 BRepBndLib::Add( shape, shapeBbox );
2017 TopTools_ListOfShape holelist;
2020 std::unique_lock lock( mutex );
2022 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2024 for(
const Standard_Integer& index : indices )
2025 holelist.Append( aHolesList[index] );
2028 if( holelist.IsEmpty() )
2031 TopTools_ListOfShape cutArgs;
2032 cutArgs.Append( shape );
2034 BRepAlgoAPI_Cut
cut;
2036 cut.SetRunParallel(
true );
2037 cut.SetToFillHistory(
false );
2039 cut.SetArguments( cutArgs );
2040 cut.SetTools( holelist );
2043 if(
cut.HasErrors() ||
cut.HasWarnings() )
2046 "%s net '%s' **\n" ),
2052 if(
cut.HasErrors() )
2054 wxString msg =
_(
"Errors:\n" );
2055 wxStringOutputStream os_stream( &msg );
2056 wxStdOutputStream out( os_stream );
2058 cut.DumpErrors( out );
2062 if(
cut.HasWarnings() )
2064 wxString msg =
_(
"Warnings:\n" );
2065 wxStringOutputStream os_stream( &msg );
2066 wxStdOutputStream out( os_stream );
2068 cut.DumpWarnings( out );
2073 shape =
cut.Shape();
2077 tp.parallelize_loop( vec.size(), subtractLoopFn ).wait();
2081 auto subtractShapes =
2082 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2083 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2085 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2087 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
2088 aShapesList = aShapesMap[wxEmptyString];
2094 Bnd_BoundSortBox bsbHoles;
2102 Bnd_BoundSortBox bsbHoles;
2111 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2113 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2114 const std::vector<TopoDS_Shape>& aShapes )
2116 for(
const TopoDS_Shape& shape : aShapes )
2117 shapesToFuseMap[aNetname].Append( shape );
2121 addShapes( netname, shapes );
2124 addShapes( netname, shapes );
2127 addShapes( netname, shapes );
2134 auto fuseLoopFn = [&](
const wxString& aNetname )
2136 auto& toFuse = shapesToFuseMap[aNetname];
2139 if( !fusedShape.IsNull() )
2141 std::unique_lock lock( mutex );
2151 BS::multi_future<void> mf;
2153 for(
const auto& [netname,
_] : shapesToFuseMap )
2154 mf.push_back(
tp.submit( fuseLoopFn, netname ) );
2171 auto pushToAssemblyMap =
2172 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2173 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2176 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2180 std::vector<TopoDS_Shape> allShapes;
2182 for(
const auto& [netname, shapesList] : aShapesMap )
2183 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2185 if( !allShapes.empty() )
2186 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2190 shapesMap = aShapesMap;
2193 for(
const auto& [netname, shapesList] : shapesMap )
2195 std::vector<TopoDS_Shape> newList;
2200 newList = shapesList;
2204 for( TopoDS_Shape& shape : newList )
2206 Handle( TDataStd_TreeNode ) node;
2209 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2215 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2216 TDF_Label shpLbl = node->Father()->Label();
2218 if( !shpLbl.IsNull() )
2220 if( visMatTool && !aVisMatLabel.IsNull() )
2221 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2227 shapeName << aShapeName;
2229 if( !netname.empty() )
2232 shapeName << netname;
2235 if( newList.size() > 1 )
2241 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2242 TDataStd_Name::Set( shpLbl, partname );
2250 auto pushToAssembly =
2251 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2252 const wxString& aShapeName,
bool aCompound )
2254 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2256 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound );
2260 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2261 double aMetallic,
double aRoughness ) -> TDF_Label
2263 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2264 XCAFDoc_VisMaterialPBR pbr;
2265 pbr.BaseColor = aBaseColor;
2266 pbr.Metallic = aMetallic;
2267 pbr.Roughness = aRoughness;
2268 vismat->SetPbrMaterial( pbr );
2269 return visMatTool->AddMaterial( vismat, aName );
2276 Quantity_ColorRGBA board_color( 0.3f, 0.3f, 0.3f, 1.0f );
2277 Quantity_ColorRGBA silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2278 Quantity_ColorRGBA mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2288 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2291 mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2294 if( item->GetBrdLayerId() ==
F_SilkS || item->GetBrdLayerId() ==
B_SilkS )
2295 silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2298 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2303 board_color = mask_color;
2304 board_color.SetAlpha( 1.0 );
2307 TDF_Label mask_mat = makeMaterial(
"soldermask", mask_color, 0.0, 0.6 );
2308 TDF_Label silk_mat = makeMaterial(
"silkscreen", silk_color, 0.0, 0.9 );
2309 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2310 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2311 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2313 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true );
2320 if( aPushBoardBody )
2323#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2324 m_assy->UpdateAssemblies();
2333bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2337 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2343 m_outFmt = OUTPUT_FORMAT::FMT_OUT_IGES;
2345 wxFileName fn( aFileName );
2346 IGESControl_Controller::Init();
2347 IGESCAFControl_Writer writer;
2348 writer.SetColorMode( Standard_True );
2349 writer.SetNameMode( Standard_True );
2350 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2351 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2352 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2353 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2354 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2355 writer.Model()->SetGlobalSection( header );
2357 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2366 wxFileInputStream input( inputFile );
2367 wxFileOutputStream output( outputFile );
2371 m_reporter->
Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2375 if( !output.IsOk() )
2377 m_reporter->
Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2381 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2383 if( !zlibStream.IsOk() )
2389 input.Read( zlibStream );
2391 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2407 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2413 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STEP;
2415 wxFileName fn( aFileName );
2417 STEPCAFControl_Writer writer;
2418 writer.SetColorMode( Standard_True );
2419 writer.SetNameMode( Standard_True );
2426 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2428 m_reporter->
Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2434 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2436 m_reporter->
Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2440 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2443 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2447 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2450 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2451 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2452 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2453 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2455 bool success =
true;
2458 wxString currCWD = wxGetCwd();
2459 wxString workCWD = fn.GetPath();
2461 if( !workCWD.IsEmpty() )
2462 wxSetWorkingDirectory( workCWD );
2464 wxString tmpfname(
"$tempfile$.step" );
2466 if( Standard_False == writer.Write( tmpfname.c_str() ) )
2469 if( compress && success )
2471 wxString srcTmp( tmpfname );
2472 wxString dstTmp(
"$tempfile$.stpz" );
2475 wxRemoveFile( srcTmp );
2486 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2488 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2496 wxSetWorkingDirectory( currCWD );
2506 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2512 m_outFmt = OUTPUT_FORMAT::FMT_OUT_BREP;
2515 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2520 wxFileName fn( aFileName );
2522 wxFFileOutputStream ffStream( fn.GetFullPath() );
2523 wxStdOutputStream stdStream( ffStream );
2525#if OCC_VERSION_HEX >= 0x070600
2526 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2528 BRepTools::Write( shape, stdStream );
2537 wxFileName fn( aFileName );
2539 wxFFileOutputStream ffStream( fn.GetFullPath() );
2540 wxStdOutputStream file( ffStream );
2542 if( !ffStream.IsOk() )
2544 m_reporter->
Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
2549 m_outFmt = OUTPUT_FORMAT::FMT_OUT_XAO;
2552 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2557 std::map<wxString, std::vector<int>> groups[4];
2558 std::map<wxString, double> groupAreas;
2559 TopExp_Explorer exp;
2562 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2564 TopoDS_Shape subShape = exp.Current();
2567 BRepBndLib::Add( subShape, bbox );
2571 for(
const auto& pair : pairs )
2573 const auto& [point, padTestShape] = pair;
2575 if( bbox.IsOut( point ) )
2578 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2580 if( surface.GetType() != GeomAbs_Plane )
2583 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2586 if( !dist.IsDone() )
2589 if( dist.Value() < Precision::Approximation() )
2592 groups[2][padKey].push_back( faceIndex );
2594 GProp_GProps system;
2595 BRepGProp::SurfaceProperties( subShape, system );
2597 double surfaceArea = system.Mass() / 1e6;
2598 groupAreas[padKey] += surfaceArea;
2607 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2608 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2609 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2610 file <<
" <shape format=\"BREP\"><![CDATA[";
2611#if OCC_VERSION_HEX < 0x070600
2612 BRepTools::Write( shape, file );
2614 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2616 file <<
"]]></shape>" << std::endl;
2617 file <<
" <topology>" << std::endl;
2619 TopTools_IndexedMapOfShape mainMap;
2620 TopExp::MapShapes( shape, mainMap );
2621 std::set<int> topo[4];
2623 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2626 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2627 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2629 for(
int dim = 0; dim < 4; dim++ )
2631 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2633 TopoDS_Shape subShape = exp.Current();
2634 int idx = mainMap.FindIndex( subShape );
2636 if( idx && !topo[dim].count( idx ) )
2637 topo[dim].insert( idx );
2641 for(
int dim = 0; dim <= 3; dim++ )
2643 std::string labels = c_dimLabels[dim];
2644 std::string label = c_dimLabel[dim];
2646 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2649 for(
auto p : topo[dim] )
2651 std::string
name(
"" );
2652 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2653 <<
"name=\"" <<
name <<
"\" "
2654 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2658 file <<
" </" << labels <<
">" << std::endl;
2661 file <<
" </topology>" << std::endl;
2662 file <<
" </geometry>" << std::endl;
2663 file <<
" <groups count=\""
2664 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2667 int groupNumber = 1;
2672 for(
int dim = 0; dim <= 3; dim++ )
2674 std::string label = c_dimLabel[dim];
2676 for(
auto g : groups[dim] )
2679 wxString
name = g.first;
2683 std::ostringstream gs;
2684 gs <<
"G_" << dim <<
"D_" << g.first;
2687 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2693 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2695 for(
auto index : g.second )
2696 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2698 file <<
" </group>" << std::endl;
2712 file <<
" </groups>" << std::endl;
2713 file <<
" <fields count=\"0\"/>" << std::endl;
2714 file <<
"</XAO>" << std::endl;
2721 bool aSubstituteModels, wxString* aErrorMessage )
2723 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2724 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2726 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2730 aLabel = mm->second;
2736 Handle( TDocStd_Document ) doc;
2737 m_app->NewDocument(
"MDTV-XCAF", doc );
2739 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2745 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2747 m_reporter->
Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2755 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2757 m_reporter->
Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2768 wxFFileInputStream ifile( fileName );
2769 wxFileName outFile( fileName );
2771 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2772 outFile.SetExt( wxT(
"step" ) );
2773 wxFileOffset size = ifile.GetLength();
2775 if( size == wxInvalidOffset )
2777 m_reporter->
Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2784 bool success =
false;
2785 wxFFileOutputStream ofile( outFile.GetFullPath() );
2790 char* buffer =
new char[size];
2792 ifile.Read( buffer, size );
2793 std::string expanded;
2797 expanded = gzip::decompress( buffer, size );
2802 m_reporter->
Report( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2807 if( expanded.empty() )
2811 wxZipInputStream izipfile( ifile );
2812 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2814 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2816 izipfile.Read( ofile );
2822 ofile.Write( expanded.data(), expanded.size() );
2830 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2850 if( aSubstituteModels )
2852 wxFileName wrlName( fileName );
2854 wxString basePath = wrlName.GetPath();
2855 wxString baseName = wrlName.GetName();
2863 alts.Add( wxT(
"stp" ) );
2864 alts.Add( wxT(
"step" ) );
2865 alts.Add( wxT(
"STP" ) );
2866 alts.Add( wxT(
"STEP" ) );
2867 alts.Add( wxT(
"Stp" ) );
2868 alts.Add( wxT(
"Step" ) );
2869 alts.Add( wxT(
"stpz" ) );
2870 alts.Add( wxT(
"stpZ" ) );
2871 alts.Add( wxT(
"STPZ" ) );
2872 alts.Add( wxT(
"step.gz" ) );
2873 alts.Add( wxT(
"stp.gz" ) );
2876 alts.Add( wxT(
"iges" ) );
2877 alts.Add( wxT(
"IGES" ) );
2878 alts.Add( wxT(
"igs" ) );
2879 alts.Add( wxT(
"IGS" ) );
2883 for(
const auto& alt : alts )
2885 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2887 if( altFile.IsOk() && altFile.FileExists() )
2889 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2907 if(
m_outFmt == OUTPUT_FORMAT::FMT_OUT_GLTF )
2909 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2911 Handle( XCAFDoc_ShapeTool ) shapeTool =
2912 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2915 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2919 m_reporter->
Report( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2929 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2939 m_reporter->
Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'.\n" ),
2947 if( aLabel.IsNull() )
2949 m_reporter->
Report( wxString::Format(
_(
"Could not transfer model data from file '%s'.\n" ),
2957 wxFileName afile( fileName );
2958 std::string pname( afile.GetName().ToUTF8() );
2959 TCollection_ExtendedString partname( pname.c_str() );
2960 TDataStd_Name::Set( aLabel, partname );
2970 TopLoc_Location& aLocation )
2984 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2989 double boardThickness;
2992 double top = std::max( boardZPos, boardZPos + boardThickness );
2993 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2998 double f_pos, f_thickness;
3002 bottom += f_thickness;
3008 aOffset.
z -= bottom;
3009 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3010 lPos.Multiply( lRot );
3011 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
3012 lPos.Multiply( lRot );
3017 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3018 lPos.Multiply( lRot );
3022 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
3023 lPos.Multiply( lOff );
3026 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3027 lPos.Multiply( lOrient );
3028 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3029 lPos.Multiply( lOrient );
3030 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3031 lPos.Multiply( lOrient );
3033 aLocation = TopLoc_Location( lPos );
3040 IGESControl_Controller::Init();
3041 IGESCAFControl_Reader reader;
3042 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3044 if( stat != IFSelect_RetDone )
3048 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3052 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3056 reader.SetColorMode(
true );
3057 reader.SetNameMode(
false );
3058 reader.SetLayerMode(
false );
3060 if( !reader.Transfer( doc ) )
3062 if( doc->CanClose() == CDM_CCS_OK )
3069 if( reader.NbShapes() < 1 )
3071 if( doc->CanClose() == CDM_CCS_OK )
3083 STEPCAFControl_Reader reader;
3084 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3086 if( stat != IFSelect_RetDone )
3090 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3094 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3098 reader.SetColorMode(
true );
3099 reader.SetNameMode(
true );
3100 reader.SetLayerMode(
false );
3102 if( !reader.Transfer( doc ) )
3104 if( doc->CanClose() == CDM_CCS_OK )
3111 if( reader.NbRootsForTransfer() < 1 )
3113 if( doc->CanClose() == CDM_CCS_OK )
3125#if OCC_VERSION_HEX >= 0x070700
3126 VrmlAPI_CafReader reader;
3127 RWMesh_CoordinateSystemConverter conv;
3128 conv.SetInputLengthUnit( 2.54 );
3129 reader.SetCoordinateSystemConverter( conv );
3130 reader.SetDocument( doc );
3132 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3143 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
3147 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3150 TDF_LabelSequence frshapes;
3151 s_assy->GetFreeShapes( frshapes );
3154 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3157 TDF_Label d_targetLabel = d_assy->NewShape();
3159 if( frshapes.Size() == 1 )
3161 TDocStd_XLinkTool link;
3162 link.Copy( d_targetLabel, frshapes.First() );
3167 for( TDF_Label& s_shapeLabel : frshapes )
3169 TDF_Label d_component = d_assy->NewShape();
3171 TDocStd_XLinkTool link;
3172 link.Copy( d_component, s_shapeLabel );
3174 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3178 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3181 return d_targetLabel;
3187 TDF_LabelSequence freeShapes;
3188 aShapeTool->GetFreeShapes( freeShapes );
3194 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3196 TDF_Label label = freeShapes.Value( i );
3198 aShapeTool->GetShape( label, shape );
3203 const Standard_Real linearDeflection = 0.14;
3204 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3205 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3217 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3223 m_outFmt = OUTPUT_FORMAT::FMT_OUT_GLTF;
3227 wxFileName fn( aFileName );
3229 const char* tmpGltfname =
"$tempfile$.glb";
3230 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3232 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3233 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3234 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3235 RWMesh_CoordinateSystem_Zup );
3236#if OCC_VERSION_HEX >= 0x070700
3237 cafWriter.SetParallel(
true );
3239 TColStd_IndexedDataMapOfStringString metadata;
3241 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3242 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3243 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3244 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3245 metadata.Add( TCollection_AsciiString(
"generator" ),
3246 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3247 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3250 bool success =
true;
3253 wxString currCWD = wxGetCwd();
3254 wxString workCWD = fn.GetPath();
3256 if( !workCWD.IsEmpty() )
3257 wxSetWorkingDirectory( workCWD );
3259 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3266 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3268 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3276 wxSetWorkingDirectory( currCWD );
3284#if OCC_VERSION_HEX < 0x070700
3291 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3297 m_outFmt = OUTPUT_FORMAT::FMT_OUT_PLY;
3301 wxFileName fn( aFileName );
3303 const char* tmpFname =
"$tempfile$.ply";
3304 RWPly_CafWriter cafWriter( tmpFname );
3306 cafWriter.SetFaceId(
true );
3307 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3308 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
3310 TColStd_IndexedDataMapOfStringString metadata;
3312 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3313 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3314 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3315 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3316 metadata.Add( TCollection_AsciiString(
"generator" ),
3317 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
3319 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3322 bool success =
true;
3325 wxString currCWD = wxGetCwd();
3326 wxString workCWD = fn.GetPath();
3328 if( !workCWD.IsEmpty() )
3329 wxSetWorkingDirectory( workCWD );
3331 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3338 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3340 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3348 wxSetWorkingDirectory( currCWD );
3359 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3365 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STL;
3369 wxFileName fn( aFileName );
3371 const char* tmpFname =
"$tempfile$.stl";
3374 wxString currCWD = wxGetCwd();
3375 wxString workCWD = fn.GetPath();
3377 if( !workCWD.IsEmpty() )
3378 wxSetWorkingDirectory( workCWD );
3380 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
3387 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3389 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3397 wxSetWorkingDirectory( currCWD );
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.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
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.
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.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
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.
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
OUTPUT_FORMAT m_outFmt
The current output format for created file.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
std::vector< TopoDS_Shape > m_board_silkscreen
bool CreatePCB(SHAPE_POLY_SET &aOutline, VECTOR2D aOrigin, bool aPushBoardBody)
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, VECTOR2D aStartPoint, VECTOR2D aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
bool WritePLY(const wxString &aFileName)
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)
bool AddComponent(const std::string &aFileName, const std::string &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
std::vector< TopoDS_Shape > m_boardCutouts
std::vector< TopoDS_Shape > m_board_soldermask
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
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 getLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_outlines
void SetSimplifyShapes(bool aValue)
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
void SetEnabledLayers(const LSET &aLayers)
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)
Handle(XCAFApp_Application) m_app
bool getModelLocation(bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, TopLoc_Location &aLocation)
virtual ~STEP_PCB_MODEL()
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
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 getModelLabel(const std::string &aFileNameUTF8, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
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::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
void getCopperLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, VECTOR3D aScale)
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)
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
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)
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 constexpr double USER_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
std::pair< std::string, TDF_Label > MODEL_DATUM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
constexpr double IUTomm(int iu) const
constexpr int mmToIU(double mm) const
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
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
VECTOR3< double > VECTOR3D