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>
69#include <IGESCAFControl_Reader.hxx>
70#include <IGESCAFControl_Writer.hxx>
71#include <IGESControl_Controller.hxx>
72#include <IGESData_GlobalSection.hxx>
73#include <IGESData_IGESModel.hxx>
74#include <Interface_Static.hxx>
75#include <Quantity_Color.hxx>
76#include <STEPCAFControl_Reader.hxx>
77#include <STEPCAFControl_Writer.hxx>
78#include <APIHeaderSection_MakeHeader.hxx>
79#include <Standard_Failure.hxx>
80#include <Standard_Handle.hxx>
81#include <Standard_Version.hxx>
82#include <TCollection_ExtendedString.hxx>
83#include <TDocStd_Document.hxx>
84#include <TDocStd_XLinkTool.hxx>
85#include <TDataStd_Name.hxx>
86#include <TDataStd_TreeNode.hxx>
87#include <TDF_LabelSequence.hxx>
88#include <TDF_Tool.hxx>
89#include <TopExp_Explorer.hxx>
91#include <XCAFApp_Application.hxx>
93#include <XCAFDoc_DocumentTool.hxx>
94#include <XCAFDoc_ColorTool.hxx>
95#include <XCAFDoc_ShapeTool.hxx>
96#include <XCAFDoc_VisMaterialTool.hxx>
97#include <XCAFDoc_Area.hxx>
98#include <XCAFDoc_Centroid.hxx>
99#include <XCAFDoc_Location.hxx>
100#include <XCAFDoc_Volume.hxx>
103#include "KI_XCAFDoc_AssemblyGraph.hxx"
105#include <BRep_Tool.hxx>
106#include <BRepMesh_IncrementalMesh.hxx>
107#include <BRepBuilderAPI_GTransform.hxx>
108#include <BRepBuilderAPI_MakeEdge.hxx>
109#include <BRepBuilderAPI_MakeWire.hxx>
110#include <BRepBuilderAPI_MakeFace.hxx>
111#include <BRepExtrema_DistShapeShape.hxx>
112#include <BRepPrimAPI_MakePrism.hxx>
113#include <BRepTools.hxx>
114#include <BRepLib_MakeWire.hxx>
115#include <BRepAdaptor_Surface.hxx>
116#include <BRepAlgoAPI_Check.hxx>
117#include <BRepAlgoAPI_Cut.hxx>
118#include <BRepAlgoAPI_Fuse.hxx>
119#include <ShapeUpgrade_UnifySameDomain.hxx>
121#include <BRepBndLib.hxx>
122#include <Bnd_BoundSortBox.hxx>
123#include <GProp_GProps.hxx>
124#include <BRepGProp.hxx>
126#include <Geom_Curve.hxx>
127#include <Geom_TrimmedCurve.hxx>
132#include <GC_MakeArcOfCircle.hxx>
133#include <GC_MakeCircle.hxx>
135#include <RWGltf_CafWriter.hxx>
136#include <StlAPI_Writer.hxx>
138#if OCC_VERSION_HEX >= 0x070700
139#include <VrmlAPI_CafReader.hxx>
140#include <RWPly_CafWriter.hxx>
168 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
170 if( !lfile.FileExists() )
173 wxString ext = lfile.GetExt().Lower();
175 if( ext == wxT(
"wrl" ) )
178 if( ext == wxT(
"wrz" ) )
181 if( ext == wxT(
"idf" ) )
184 if( ext == wxT(
"emn" ) )
187 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
201 const int max_line_count = 3;
203 for(
int ii = 0; ii < max_line_count; ii++ )
205 memset( iline, 0, 82 );
206 ifile.getline( iline, 82 );
212 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
218 std::string fstr = iline;
222 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
231 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
238 if( strncmp( iline,
"/*", 2 ) != 0 )
256 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
257 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
258 double det = -b.
x * d.
y + d.
x * b.
y;
262 center.x = ( -bc * d.
y - cd * b.
y ) * det;
263 center.y = ( b.
x * cd + d.
x * bc ) * det;
270#define APPROX_DBG( stmt )
278 static const double c_radiusDeviation = 1000.0;
279 static const double c_arcCenterDeviation = 1000.0;
280 static const double c_relLengthDeviation = 0.8;
281 static const int c_last_none = -1000;
283 static const double c_smallSize =
pcbIUScale.mmToIU( 0.1 );
284 static const double c_circleCloseGap =
pcbIUScale.mmToIU( 1.0 );
301 int last = c_last_none;
307 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
309 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
314 bool defective =
false;
320 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
328 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
329 defective |=
std::abs( a_diff ) < 0.1;
332 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
333 defective |=
std::abs( a_diff ) >= maxAngleDiff;
344 for(
int j = i; j <= jEndIdx; j++ )
349 double rad_test = ( p_test -
center ).EuclideanNorm();
350 double d_tl = ( p_test - p_prev ).EuclideanNorm();
354 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
357 if( rad_dev > c_radiusDeviation )
360 <<
" Radius deviation too large: " << int64_t( rad_dev )
361 <<
" > " << c_radiusDeviation << std::endl );
366 double maxAngleDiff =
367 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
369 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
370 if(
std::abs( a_diff_test ) >= maxAngleDiff )
372 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
377 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
379 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
380 <<
"; " << d01 << std::endl );
390 if( last != c_last_none )
399 int toRemove = last - ( aSrc.
PointCount() - 3 );
429 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
433 if( last == c_last_none )
450 if( iarc0 != -1 && iarc1 != -1 )
452 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
462 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
480 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
481 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
499 TDF_LabelSequence theLabels;
500 aShapeTool->GetFreeShapes( theLabels );
504 if( theLabels.Length() == 1 )
505 return aShapeTool->GetShape( theLabels.Value( 1 ) );
507 TopoDS_Compound aCompound;
508 BRep_Builder aBuilder;
509 aBuilder.MakeCompound( aCompound );
511 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
513 TopoDS_Shape aFreeShape;
515 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
518 aBuilder.Add( aCompound, aFreeShape );
521 if( aCompound.NbChildren() > 0 )
530static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
532 if( theLabel.IsNull() )
534 Message::SendFail(
"Null label." );
535 return Standard_False;
538 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
539 || Abs( aScale.Z() ) <= gp::Resolution() )
541 Message::SendFail(
"Scale factor is too small." );
542 return Standard_False;
545 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
547 if( aShapeTool.IsNull() )
549 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
550 return Standard_False;
553 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
557 Message::SendFail(
"Couldn't create assembly graph." );
558 return Standard_False;
561 Standard_Boolean anIsDone = Standard_True;
565 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
567 0, 0, aScale.Z() ) );
570 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
572 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
574 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
576 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
577 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
582 const TDF_Label& aLabel = aG->GetNode( idx );
584 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
586 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
587 aBRepTrsf.Perform( aShape, Standard_True );
588 if( !aBRepTrsf.IsDone() )
590 Standard_SStream aSS;
591 TCollection_AsciiString anEntry;
592 TDF_Tool::Entry( aLabel, anEntry );
593 aSS <<
"Shape " << anEntry <<
" is not scaled!";
594 Message::SendFail( aSS.str().c_str() );
595 anIsDone = Standard_False;
596 return Standard_False;
598 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
599 aShapeTool->SetShape( aLabel, aScaledShape );
602 TDF_LabelSequence aSubshapes;
603 aShapeTool->GetSubShapes( aLabel, aSubshapes );
604 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
606 const TDF_Label& aLSs = anItSs.Value();
607 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
608 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
609 aShapeTool->SetShape( aLSs, aSs1 );
613 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
614 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
615 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
617 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
619 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
620 gp_Trsf aTrsf = aLoc.Transformation();
621 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
622 XCAFDoc_Location::Set( aLabel, aTrsf );
628 return Standard_False;
631 aShapeTool->UpdateAssemblies();
639 BRepAlgoAPI_Fuse mkFuse;
640 TopTools_ListOfShape shapeArguments, shapeTools;
642 for( TopoDS_Shape& sh : aInputShapes )
647 if( shapeArguments.IsEmpty() )
648 shapeArguments.Append( sh );
650 shapeTools.Append( sh );
653 mkFuse.SetRunParallel(
true );
654 mkFuse.SetToFillHistory(
false );
655 mkFuse.SetArguments( shapeArguments );
656 mkFuse.SetTools( shapeTools );
659 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
663 if( mkFuse.HasErrors() )
665 wxString msg =
_(
"Errors:\n" );
666 wxStringOutputStream os_stream( &msg );
667 wxStdOutputStream out( os_stream );
669 mkFuse.DumpErrors( out );
673 if( mkFuse.HasWarnings() )
675 wxString msg =
_(
"Warnings:\n" );
676 wxStringOutputStream os_stream( &msg );
677 wxStdOutputStream out( os_stream );
679 mkFuse.DumpWarnings( out );
684 if( mkFuse.IsDone() )
686 TopoDS_Shape fusedShape = mkFuse.Shape();
688 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
689 unify.History() =
nullptr;
692 TopoDS_Shape unifiedShapes = unify.Shape();
694 if( unifiedShapes.IsNull() )
696 aReporter->
Report(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **" ),
701 aOutShape = unifiedShapes;
712 TopoDS_Compound compound;
713 BRep_Builder builder;
714 builder.MakeCompound( compound );
716 for(
const TopoDS_Shape& shape : aInputShapes )
717 builder.Add( compound, shape );
727 TopoDS_Shape outShape;
729 if( aInputShapes.Size() == 1 )
730 return aInputShapes.First();
732 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
741 const TCollection_ExtendedString& aPrefix )
743 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
747 Message::SendFail(
"Couldn't create assembly graph." );
748 return Standard_False;
751 Standard_Boolean anIsDone = Standard_True;
753 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
755 const TDF_Label& lbl = aG->GetNode( idx );
756 Handle( TDataStd_Name ) nameHandle;
758 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
760 TCollection_ExtendedString
name;
764 name += nameHandle->Get();
767 TDataStd_Name::Set( lbl,
name );
771 TDataStd_Name::Set( lbl, aPrefix );
782 m_app = XCAFApp_Application::GetApplication();
783 m_app->NewDocument(
"MDTV-XCAF", m_doc );
784 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
801 if( m_doc->CanClose() == CDM_CCS_OK )
809 const double c_padExtraThickness = 0.005;
811 std::vector<TopoDS_Shape> padShapes;
825 double Zpos, thickness;
831 if( pcb_layer ==
F_Cu )
832 thickness += c_padExtraThickness;
833 else if( pcb_layer ==
B_Cu )
834 thickness -= c_padExtraThickness;
837 TopoDS_Shape testShape;
851 if( testShape.IsNull() )
853 std::vector<TopoDS_Shape> testShapes;
857 if( testShapes.size() > 0 )
858 testShape = testShapes.front();
861 if( !aVia && !testShape.IsNull() )
863 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
869 if( pcb_layer ==
F_Cu )
871 else if( pcb_layer ==
B_Cu )
887 double f_pos, f_thickness;
888 double b_pos, b_thickness;
895 f_thickness += c_padExtraThickness;
896 b_thickness -= c_padExtraThickness;
899 double top = std::max( f_pos, f_pos + f_thickness );
900 double bottom = std::min( b_pos, b_pos + b_thickness );
901 double hole_height = top - bottom;
903 TopoDS_Shape plating;
911 hole_height, bottom, aOrigin ) )
913 padShapes.push_back( plating );
927 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
944 padShapes.push_back( plating );
956 if( !padShapes.empty() )
961 TopTools_ListOfShape padShapesList;
963 for(
const TopoDS_Shape& shape : padShapes )
964 padShapesList.Append( shape );
970 for(
const TopoDS_Shape& shape : padShapes )
981 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
983 double margin = 0.001;
991 double f_pos, f_thickness;
992 double b_pos, b_thickness;
995 double top = std::max( f_pos, f_pos + f_thickness );
996 double bottom = std::min( b_pos, b_pos + b_thickness );
998 double holeZsize = ( top - bottom ) + ( margin * 2 );
1000 double boardDrill = aShape.
GetWidth();
1001 double copperDrill = boardDrill - aPlatingThickness * 2;
1003 TopoDS_Shape copperHole, boardHole;
1008 holeZsize, bottom - margin, aOrigin ) )
1021 holeZsize, bottom - margin, aOrigin ) )
1037 const wxString& aNetname )
1039 double f_pos, f_thickness;
1040 double b_pos, b_thickness;
1043 double top = std::max( f_pos, f_pos + f_thickness );
1044 double bottom = std::min( b_pos, b_pos + b_thickness );
1046 TopoDS_Shape plating;
1049 ( top - bottom ), bottom, aOrigin ) )
1064 double& aThickness )
1067 static const double c_silkscreenAboveCopper = 0.04;
1068 static const double c_soldermaskAboveCopper = 0.015;
1076 double f_pos, f_thickness;
1078 double top = std::max( f_pos, f_pos + f_thickness );
1081 aZPos = top + c_silkscreenAboveCopper;
1083 aZPos = top + c_soldermaskAboveCopper;
1089 double b_pos, b_thickness;
1091 double bottom = std::min( b_pos, b_pos + b_thickness );
1094 aZPos = bottom - c_silkscreenAboveCopper;
1096 aZPos = bottom - c_soldermaskAboveCopper;
1104 double& aThickness )
1108 bool wasPrepreg =
false;
1110 const std::vector<BOARD_STACKUP_ITEM*>& materials =
m_stackup.GetList();
1113 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1119 if( aLayer ==
B_Cu )
1164 double f_pos, f_thickness;
1165 double b_pos, b_thickness;
1168 double top = std::min( f_pos, f_pos + f_thickness );
1169 double bottom = std::max( b_pos, b_pos + b_thickness );
1171 aThickness = ( top - bottom );
1174 wxASSERT( aZPos == 0.0 );
1179 const VECTOR2D& aOrigin,
const wxString& aNetname )
1181 bool success =
true;
1189 double z_pos, thickness;
1192 std::vector<TopoDS_Shape>* targetVec =
nullptr;
1200 else if( aLayer ==
F_Mask )
1207 m_reporter->Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s." ),
1220 bool aBottom,
const VECTOR2D& aPosition,
double aRotation,
const VECTOR3D& aOffset,
1221 const VECTOR3D& aOrientation,
const VECTOR3D& aScale,
bool aSubstituteModels )
1223 if( aFileNameUTF8.empty() )
1225 m_reporter->Report( wxString::Format(
_(
"No model defined for %s." ), aRefDes ),
1230 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1235 wxString errorMessage;
1237 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1239 if( errorMessage.IsEmpty() )
1240 errorMessage.Printf(
_(
"No model for filename '%s'." ), fileName );
1247 TopLoc_Location toploc;
1249 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1251 m_reporter->Report( wxString::Format(
_(
"No location data for filename '%s'." ), fileName ),
1257 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1259 if( llabel.IsNull() )
1261 m_reporter->Report( wxString::Format(
_(
"Could not add component with filename '%s'." ), fileName ),
1267 TCollection_ExtendedString refdes( aRefDes.c_str() );
1268 TDataStd_Name::Set( llabel, refdes );
1336 const VECTOR2D& aEndPoint,
double aWidth,
double aThickness,
1337 double aZposition,
const VECTOR2D& aOrigin )
1344 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1345 double h_width = aWidth/2.0;
1347 coords[0] =
VECTOR2D{ 0.0, h_width };
1350 coords[1] =
VECTOR2D{ len, h_width };
1353 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1356 coords[3] =
VECTOR2D{ len, -h_width };
1359 coords[4] =
VECTOR2D{ 0, -h_width };
1362 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1365 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1367 for(
int ii = 0; ii < 6; ii++ )
1370 coords[ii] += aStartPoint;
1375 gp_Pnt coords3D[ 6 ];
1377 for(
int ii = 0; ii < 6; ii++ )
1379 coords3D[ii] = gp_Pnt(
pcbIUScale.IUTomm( coords[ii].
x - aOrigin.
x ),
1380 -
pcbIUScale.IUTomm( coords[ii].
y - aOrigin.
y ), aZposition );
1384 BRepBuilderAPI_MakeWire wire;
1385 bool success =
true;
1397 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1402 edge = BRepBuilderAPI_MakeEdge(
circle );
1407 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1410 Handle( Geom_TrimmedCurve ) arcOfCircle =
1411 GC_MakeArcOfCircle( coords3D[1],
1415 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1418 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1421 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1422 GC_MakeArcOfCircle( coords3D[4],
1426 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1430 catch(
const Standard_Failure& e )
1432 m_reporter->Report( wxString::Format(
_(
"OCC exception building shape segment: %s" ),
1433 e.GetMessageString() ),
1438 BRepBuilderAPI_MakeFace face;
1442 gp_Pln plane( coords3D[0], gp::DZ() );
1443 face = BRepBuilderAPI_MakeFace( plane, wire );
1445 catch(
const Standard_Failure& e )
1447 m_reporter->Report( wxString::Format(
_(
"OCC exception building face: %s" ),
1448 e.GetMessageString() ),
1453 if( aThickness != 0.0 )
1455 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1457 if( aShape.IsNull() )
1459 m_reporter->Report(
_(
"Failed to create a prismatic shape" ),
1476 double aZposition,
const VECTOR2D& aOrigin )
1478 std::vector<TopoDS_Shape> testShapes;
1481 aHeight, aZposition, aOrigin );
1483 if( testShapes.size() > 0 )
1484 aShape = testShapes.front();
1507 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
1511 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1513 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
1514 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
1524 gp_Pnt start = toPoint( aPt0 );
1525 gp_Pnt
end = toPoint( aPt1 );
1527 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
1529 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1531 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
1539 aMkWire.Add( mkEdge.Edge() );
1541 if( aMkWire.Error() != BRepLib_WireDone )
1543 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)" ),
1557 Handle( Geom_Curve ) curve;
1559 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1561 gp_Ax2 axis = gp::XOY();
1562 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1564 curve = GC_MakeCircle( axis,
pcbIUScale.IUTomm( aArc.GetRadius() ) ).Value();
1568 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1569 toPoint( aArc.GetP1() ) ).Value();
1572 if( curve.IsNull() )
1575 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1577 if( !aMkWire.IsDone() )
1579 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
1580 "(%d %d), mid (%d %d), p1 (%d %d)" ),
1582 aArc.GetP0().x, aArc.GetP0().y,
1583 aArc.GetArcMid().x, aArc.GetArcMid().y,
1584 aArc.GetP1().x, aArc.GetP1().y ),
1594 bool isFirstShape =
true;
1607 if( nextShape != -1 )
1613 lastPt = aChain.
CPoint( i );
1623 firstPt = currentArc.
GetP0();
1628 lastPt = currentArc.
GetP0();
1630 if( addArc( lastPt, currentArc ) )
1631 lastPt = currentArc.
GetP1();
1650 isFirstShape =
false;
1653 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1655 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **" ),
1657 firstPt.
x, firstPt.
y ),
1663 catch(
const Standard_Failure& e )
1665 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s" ),
1666 e.GetMessageString() ),
1676 bool aConvertToArcs,
double aThickness,
double aZposition,
1684 if( aConvertToArcs )
1688 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1692 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1696 fallbackPoly = workingPoly;
1697 workingPoly = approximated;
1716 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1718 return gp_Pnt(
pcbIUScale.IUTomm( aKiCoords.x - aOrigin.
x ),
1719 -
pcbIUScale.IUTomm( aKiCoords.y - aOrigin.
y ), aZposition );
1723 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1724 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1726 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1730 auto tryMakeWire = [
this, &aZposition,
1731 &aOrigin](
const SHAPE_LINE_CHAIN& aContour,
bool aAllowRetry ) -> TopoDS_Wire
1734 BRepLib_MakeWire mkWire;
1738 if( mkWire.IsDone() )
1740 wire = mkWire.Wire();
1745 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
1746 "z: %g; bounding box: %s" ),
1747 static_cast<int>( aContour.PointCount() ),
1748 static_cast<int>( mkWire.Error() ),
1753 if( !wire.IsNull() )
1755 BRepAlgoAPI_Check check( wire,
false,
true );
1757 if( !check.IsValid() )
1759 m_reporter->Report( wxString::Format(
_(
"Wire self-interference check failed\n"
1760 "z: %g; bounding box: %s" ),
1772 BRepBuilderAPI_MakeFace mkFace;
1774 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1780 bool allow_retry = aConvertToArcs ? true :
false;
1782 TopoDS_Wire wire = tryMakeWire( polygon[contId], allow_retry );
1784 if( aConvertToArcs && wire.IsNull() )
1786 m_reporter->Report( wxString::Format(
_(
"Using non-simplified polygon." ) ),
1790 allow_retry =
false;
1791 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId], allow_retry );
1796 if( !wire.IsNull() )
1798 if( basePlane.Axis().Direction().Z() < 0 )
1801 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1805 m_reporter->Report( wxString::Format( wxT(
"** Outline skipped **\n"
1806 "z: %g; bounding box: %s" ),
1815 if( !wire.IsNull() )
1817 if( basePlane.Axis().Direction().Z() > 0 )
1824 m_reporter->Report( wxString::Format( wxT(
"** Hole skipped **\n"
1825 "z: %g; bounding box: %s" ),
1832 catch(
const Standard_Failure& e )
1834 m_reporter->Report( wxString::Format(
_(
"OCC exception creating contour %d: %s" ),
1835 static_cast<int>( contId ),
1836 e.GetMessageString() ),
1842 if( mkFace.IsDone() )
1844 TopoDS_Shape faceShape = mkFace.Shape();
1846 if( aThickness != 0.0 )
1848 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1849 aShapes.push_back( prism );
1851 if( prism.IsNull() )
1859 aShapes.push_back( faceShape );
1875 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1876 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1877 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1878 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1879 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1880 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1881 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1882 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1892 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1894 aColorOut =
COLOR4D( aColorStr );
1899 const std::vector<FAB_LAYER_COLOR>& colors =
1906 if( fabColor.GetName() == aColorStr )
1908 aColorOut = fabColor.GetColor( aType );
1930 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1935 m_reporter->Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points." ),
1940 double boardThickness;
1960 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1964 polyset.
Append( contour );
1971 m_reporter->Report(
_(
"OCC error creating main outline." ),
1980 m_reporter->Report(
_(
"OCC error creating hole in main outline." ),
1992 BRepBndLib::Add( brdShape, brdBndBox );
1995 m_reporter->Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s))." ),
2000 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
2004 Bnd_Box brdWithHolesBndBox = brdBndBox;
2006 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
2008 for(
size_t i = 0; i < input.size(); i++ )
2011 BRepBndLib::Add( input[i], bbox );
2012 brdWithHolesBndBox.Add( bbox );
2013 ( *holeBoxSet )[i] = bbox;
2016 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
2019 auto subtractShapesMap =
2020 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2021 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2023 m_reporter->Report( wxString::Format(
_(
"Subtracting holes for %s" ), aWhat ),
2026 for(
auto& [netname, vec] : aShapesMap )
2030 auto subtractLoopFn = [&](
const int shapeId )
2032 TopoDS_Shape& shape = vec[shapeId];
2035 BRepBndLib::Add( shape, shapeBbox );
2037 TopTools_ListOfShape holelist;
2040 std::unique_lock lock( mutex );
2042 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2044 for(
const Standard_Integer& index : indices )
2045 holelist.Append( aHolesList[index] );
2048 if( holelist.IsEmpty() )
2051 TopTools_ListOfShape cutArgs;
2052 cutArgs.Append( shape );
2054 BRepAlgoAPI_Cut
cut;
2056 cut.SetRunParallel(
true );
2057 cut.SetToFillHistory(
false );
2059 cut.SetArguments( cutArgs );
2060 cut.SetTools( holelist );
2063 if(
cut.HasErrors() ||
cut.HasWarnings() )
2065 m_reporter->Report( wxString::Format(
_(
"** Got problems while cutting "
2072 if(
cut.HasErrors() )
2074 wxString msg =
_(
"Errors:\n" );
2075 wxStringOutputStream os_stream( &msg );
2076 wxStdOutputStream out( os_stream );
2078 cut.DumpErrors( out );
2082 if(
cut.HasWarnings() )
2084 wxString msg =
_(
"Warnings:\n" );
2085 wxStringOutputStream os_stream( &msg );
2086 wxStdOutputStream out( os_stream );
2088 cut.DumpWarnings( out );
2093 shape =
cut.Shape();
2096 tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
2100 auto subtractShapes =
2101 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2102 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2104 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2106 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
2107 aShapesList = aShapesMap[wxEmptyString];
2113 Bnd_BoundSortBox bsbHoles;
2121 Bnd_BoundSortBox bsbHoles;
2130 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2132 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2133 const std::vector<TopoDS_Shape>& aShapes )
2135 for(
const TopoDS_Shape& shape : aShapes )
2136 shapesToFuseMap[aNetname].Append( shape );
2140 addShapes( netname, shapes );
2143 addShapes( netname, shapes );
2146 addShapes( netname, shapes );
2153 auto fuseLoopFn = [&](
const wxString& aNetname )
2155 auto& toFuse = shapesToFuseMap[aNetname];
2158 if( !fusedShape.IsNull() )
2160 std::unique_lock lock( mutex );
2170 BS::multi_future<void> mf;
2172 for(
const auto& [netname,
_] : shapesToFuseMap )
2173 mf.push_back(
tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
2190 auto pushToAssemblyMap =
2191 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2192 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2193 bool aCompoundAll,
const wxString& aNiceName )
2195 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2199 std::vector<TopoDS_Shape> allShapes;
2201 for(
const auto& [netname, shapesList] : aShapesMap )
2202 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2204 if( !allShapes.empty() )
2205 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2209 shapesMap = aShapesMap;
2212 for(
const auto& [netname, shapesList] : shapesMap )
2214 std::vector<TopoDS_Shape> newList;
2219 newList = shapesList;
2223 for( TopoDS_Shape& shape : newList )
2225 Handle( TDataStd_TreeNode ) node;
2228 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2235 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2236 TDF_Label shpLbl = node->Father()->Label();
2238 if( !shpLbl.IsNull() )
2240 if( visMatTool && !aVisMatLabel.IsNull() )
2241 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2247 shapeName << aShapeName;
2249 if( !netname.empty() )
2252 shapeName << netname;
2255 if( newList.size() > 1 )
2261 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2262 TDataStd_Name::Set( shpLbl, partname );
2270 auto pushToAssembly =
2271 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2272 const wxString& aShapeName,
bool aCompound,
const wxString& aNiceName )
2274 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2276 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound, aNiceName );
2280 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2281 double aMetallic,
double aRoughness ) -> TDF_Label
2283 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2284 XCAFDoc_VisMaterialPBR pbr;
2285 pbr.BaseColor = aBaseColor;
2286 pbr.Metallic = aMetallic;
2287 pbr.Roughness = aRoughness;
2288 vismat->SetPbrMaterial( pbr );
2289 return visMatTool->AddMaterial( vismat, aName );
2296 Quantity_ColorRGBA board_color( 0.42f, 0.45f, 0.29f, 0.98f );
2297 Quantity_ColorRGBA front_silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2298 Quantity_ColorRGBA back_silk_color = front_silk_color;
2299 Quantity_ColorRGBA front_mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2300 Quantity_ColorRGBA back_mask_color = front_mask_color;
2310 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2314 if( item->GetBrdLayerId() ==
F_Mask )
2315 front_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2317 back_mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2320 if( item->GetBrdLayerId() ==
F_SilkS )
2321 front_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2322 else if( item->GetBrdLayerId() ==
B_SilkS )
2323 back_silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2326 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2329 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2330 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2331 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2332 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2333 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2334 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2335 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2337 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2341 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2342 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2343 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2344 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2346 if( aPushBoardBody )
2349#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2350 m_assy->UpdateAssemblies();
2359bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2363 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2371 wxFileName fn( aFileName );
2372 IGESControl_Controller::Init();
2373 IGESCAFControl_Writer writer;
2374 writer.SetColorMode( Standard_True );
2375 writer.SetNameMode( Standard_True );
2376 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2377 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2378 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2379 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2380 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2381 writer.Model()->SetGlobalSection( header );
2383 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2392 wxFileInputStream input( inputFile );
2393 wxFileOutputStream output( outputFile );
2397 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2401 if( !output.IsOk() )
2403 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2407 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2409 if( !zlibStream.IsOk() )
2411 m_reporter->Report(
_(
"Impossible create compress stream" ) );
2415 input.Read( zlibStream );
2417 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2419 m_reporter->Report(
_(
"Compress read or write error" ) );
2433 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2441 wxFileName fn( aFileName );
2443 STEPCAFControl_Writer writer;
2444 writer.SetColorMode( Standard_True );
2445 writer.SetNameMode( Standard_True );
2452 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2454 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2460 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2462 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2466 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2469 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2473 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2476 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2477 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2478 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2479 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2481 bool success =
true;
2484 wxString currCWD = wxGetCwd();
2485 wxString workCWD = fn.GetPath();
2487 if( !workCWD.IsEmpty() )
2488 wxSetWorkingDirectory( workCWD );
2490 wxString tmpfname(
"$tempfile$.step" );
2492 if( Standard_False == writer.Write( tmpfname.c_str() ) )
2495 if( compress && success )
2497 wxString srcTmp( tmpfname );
2498 wxString dstTmp(
"$tempfile$.stpz" );
2501 wxRemoveFile( srcTmp );
2512 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2514 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
2522 wxSetWorkingDirectory( currCWD );
2532 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2541 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2546 wxFileName fn( aFileName );
2548 wxFFileOutputStream ffStream( fn.GetFullPath() );
2549 wxStdOutputStream stdStream( ffStream );
2551#if OCC_VERSION_HEX >= 0x070600
2552 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2554 BRepTools::Write( shape, stdStream );
2563 wxFileName fn( aFileName );
2565 wxFFileOutputStream ffStream( fn.GetFullPath() );
2566 wxStdOutputStream file( ffStream );
2568 if( !ffStream.IsOk() )
2570 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
2578 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2583 std::map<wxString, std::vector<int>> groups[4];
2584 std::map<wxString, double> groupAreas;
2585 TopExp_Explorer exp;
2588 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2590 TopoDS_Shape subShape = exp.Current();
2593 BRepBndLib::Add( subShape, bbox );
2597 for(
const auto& pair : pairs )
2599 const auto& [point, padTestShape] = pair;
2601 if( bbox.IsOut( point ) )
2604 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2606 if( surface.GetType() != GeomAbs_Plane )
2609 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2612 if( !dist.IsDone() )
2615 if( dist.Value() < Precision::Approximation() )
2618 groups[2][padKey].push_back( faceIndex );
2620 GProp_GProps system;
2621 BRepGProp::SurfaceProperties( subShape, system );
2623 double surfaceArea = system.Mass() / 1e6;
2624 groupAreas[padKey] += surfaceArea;
2633 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2634 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2635 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2636 file <<
" <shape format=\"BREP\"><![CDATA[";
2637#if OCC_VERSION_HEX < 0x070600
2638 BRepTools::Write( shape, file );
2640 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2642 file <<
"]]></shape>" << std::endl;
2643 file <<
" <topology>" << std::endl;
2645 TopTools_IndexedMapOfShape mainMap;
2646 TopExp::MapShapes( shape, mainMap );
2647 std::set<int> topo[4];
2649 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2652 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2653 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2655 for(
int dim = 0; dim < 4; dim++ )
2657 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2659 TopoDS_Shape subShape = exp.Current();
2660 int idx = mainMap.FindIndex( subShape );
2662 if( idx && !topo[dim].count( idx ) )
2663 topo[dim].insert( idx );
2667 for(
int dim = 0; dim <= 3; dim++ )
2669 std::string labels = c_dimLabels[dim];
2670 std::string label = c_dimLabel[dim];
2672 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2675 for(
auto p : topo[dim] )
2677 std::string
name(
"" );
2678 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2679 <<
"name=\"" <<
name <<
"\" "
2680 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2684 file <<
" </" << labels <<
">" << std::endl;
2687 file <<
" </topology>" << std::endl;
2688 file <<
" </geometry>" << std::endl;
2689 file <<
" <groups count=\""
2690 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2693 int groupNumber = 1;
2698 for(
int dim = 0; dim <= 3; dim++ )
2700 std::string label = c_dimLabel[dim];
2702 for(
auto g : groups[dim] )
2705 wxString
name = g.first;
2709 std::ostringstream gs;
2710 gs <<
"G_" << dim <<
"D_" << g.first;
2713 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2719 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2721 for(
auto index : g.second )
2722 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2724 file <<
" </group>" << std::endl;
2726 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
2738 file <<
" </groups>" << std::endl;
2739 file <<
" <fields count=\"0\"/>" << std::endl;
2740 file <<
"</XAO>" << std::endl;
2747 bool aSubstituteModels, wxString* aErrorMessage )
2749 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2750 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2752 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2756 aLabel = mm->second;
2762 Handle( TDocStd_Document ) doc;
2763 m_app->NewDocument(
"MDTV-XCAF", doc );
2765 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2771 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2773 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ),
2781 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2783 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ),
2794 wxFFileInputStream ifile( fileName );
2795 wxFileName outFile( fileName );
2797 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2798 outFile.SetExt( wxT(
"step" ) );
2799 wxFileOffset size = ifile.GetLength();
2801 if( size == wxInvalidOffset )
2803 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
2810 bool success =
false;
2811 wxFFileOutputStream ofile( outFile.GetFullPath() );
2816 char* buffer =
new char[size];
2818 ifile.Read( buffer, size );
2819 std::string expanded;
2823 expanded = gzip::decompress( buffer, size );
2828 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ),
2833 if( expanded.empty() )
2837 wxZipInputStream izipfile( ifile );
2838 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2840 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2842 izipfile.Read( ofile );
2848 ofile.Write( expanded.data(), expanded.size() );
2856 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2876 if( aSubstituteModels )
2878 wxFileName wrlName( fileName );
2880 wxString basePath = wrlName.GetPath();
2881 wxString baseName = wrlName.GetName();
2889 alts.Add( wxT(
"stp" ) );
2890 alts.Add( wxT(
"step" ) );
2891 alts.Add( wxT(
"STP" ) );
2892 alts.Add( wxT(
"STEP" ) );
2893 alts.Add( wxT(
"Stp" ) );
2894 alts.Add( wxT(
"Step" ) );
2895 alts.Add( wxT(
"stpz" ) );
2896 alts.Add( wxT(
"stpZ" ) );
2897 alts.Add( wxT(
"STPZ" ) );
2898 alts.Add( wxT(
"step.gz" ) );
2899 alts.Add( wxT(
"stp.gz" ) );
2902 alts.Add( wxT(
"iges" ) );
2903 alts.Add( wxT(
"IGES" ) );
2904 alts.Add( wxT(
"igs" ) );
2905 alts.Add( wxT(
"IGS" ) );
2909 for(
const auto& alt : alts )
2911 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2913 if( altFile.IsOk() && altFile.FileExists() )
2915 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2935 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2937 Handle( XCAFDoc_ShapeTool ) shapeTool =
2938 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2941 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2945 m_reporter->Report( wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
2955 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export." ) );
2965 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ),
2973 if( aLabel.IsNull() )
2975 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ),
2983 wxFileName afile( fileName );
2984 std::string pname( afile.GetName().ToUTF8() );
2985 TCollection_ExtendedString partname( pname.c_str() );
2986 TDataStd_Name::Set( aLabel, partname );
2996 TopLoc_Location& aLocation )
3010 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3016 double boardThickness;
3019 double top = std::max( boardZPos, boardZPos + boardThickness );
3020 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3025 double f_pos, f_thickness;
3029 bottom += f_thickness;
3036 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3037 lPos.Multiply( lRot );
3038 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3039 lPos.Multiply( lRot );
3044 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3045 lPos.Multiply( lRot );
3049 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3050 lPos.Multiply( lOff );
3053 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3054 lPos.Multiply( lOrient );
3055 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3056 lPos.Multiply( lOrient );
3057 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3058 lPos.Multiply( lOrient );
3060 aLocation = TopLoc_Location( lPos );
3067 IGESControl_Controller::Init();
3068 IGESCAFControl_Reader reader;
3069 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3071 if( stat != IFSelect_RetDone )
3075 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3079 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3083 reader.SetColorMode(
true );
3084 reader.SetNameMode(
false );
3085 reader.SetLayerMode(
false );
3087 if( !reader.Transfer( doc ) )
3089 if( doc->CanClose() == CDM_CCS_OK )
3096 if( reader.NbShapes() < 1 )
3098 if( doc->CanClose() == CDM_CCS_OK )
3110 STEPCAFControl_Reader reader;
3111 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3113 if( stat != IFSelect_RetDone )
3117 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3121 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3125 reader.SetColorMode(
true );
3126 reader.SetNameMode(
true );
3127 reader.SetLayerMode(
false );
3129 if( !reader.Transfer( doc ) )
3131 if( doc->CanClose() == CDM_CCS_OK )
3138 if( reader.NbRootsForTransfer() < 1 )
3140 if( doc->CanClose() == CDM_CCS_OK )
3152#if OCC_VERSION_HEX >= 0x070700
3153 VrmlAPI_CafReader reader;
3154 RWMesh_CoordinateSystemConverter conv;
3155 conv.SetInputLengthUnit( 2.54 );
3156 reader.SetCoordinateSystemConverter( conv );
3157 reader.SetDocument( doc );
3159 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3174 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3177 TDF_LabelSequence frshapes;
3178 s_assy->GetFreeShapes( frshapes );
3181 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3184 TDF_Label d_targetLabel = d_assy->NewShape();
3186 if( frshapes.Size() == 1 )
3188 TDocStd_XLinkTool link;
3189 link.Copy( d_targetLabel, frshapes.First() );
3194 for( TDF_Label& s_shapeLabel : frshapes )
3196 TDF_Label d_component = d_assy->NewShape();
3198 TDocStd_XLinkTool link;
3199 link.Copy( d_component, s_shapeLabel );
3201 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3205 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3208 return d_targetLabel;
3214 TDF_LabelSequence freeShapes;
3215 aShapeTool->GetFreeShapes( freeShapes );
3221 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3223 TDF_Label label = freeShapes.Value( i );
3225 aShapeTool->GetShape( label, shape );
3230 const Standard_Real linearDeflection = 0.14;
3231 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3232 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3254 wxFileName fn( aFileName );
3256 const char* tmpGltfname =
"$tempfile$.glb";
3257 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3259 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3260 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3261 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3262 RWMesh_CoordinateSystem_Zup );
3263#if OCC_VERSION_HEX >= 0x070700
3264 cafWriter.SetParallel(
true );
3266 TColStd_IndexedDataMapOfStringString metadata;
3268 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3269 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3270 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3271 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3272 metadata.Add( TCollection_AsciiString(
"generator" ),
3273 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3274 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3277 bool success =
true;
3280 wxString currCWD = wxGetCwd();
3281 wxString workCWD = fn.GetPath();
3283 if( !workCWD.IsEmpty() )
3284 wxSetWorkingDirectory( workCWD );
3286 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3293 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3295 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3303 wxSetWorkingDirectory( currCWD );
3311#if OCC_VERSION_HEX < 0x070700
3318 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3328 wxFileName fn( aFileName );
3330 const char* tmpFname =
"$tempfile$.ply";
3331 RWPly_CafWriter cafWriter( tmpFname );
3333 cafWriter.SetFaceId(
true );
3334 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3335 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
3337 TColStd_IndexedDataMapOfStringString metadata;
3339 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3340 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3341 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3342 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3343 metadata.Add( TCollection_AsciiString(
"generator" ),
3344 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
3346 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3349 bool success =
true;
3352 wxString currCWD = wxGetCwd();
3353 wxString workCWD = fn.GetPath();
3355 if( !workCWD.IsEmpty() )
3356 wxSetWorkingDirectory( workCWD );
3358 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3365 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3367 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3375 wxSetWorkingDirectory( currCWD );
3386 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3396 wxFileName fn( aFileName );
3398 const char* tmpFname =
"$tempfile$.stl";
3401 wxString currCWD = wxGetCwd();
3402 wxString workCWD = fn.GetPath();
3404 if( !workCWD.IsEmpty() )
3405 wxSetWorkingDirectory( workCWD );
3407 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
3414 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3416 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3424 wxSetWorkingDirectory( currCWD );
3436 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
3445 wxFileName fn( aFileName );
3447 const char* tmpFname =
"$tempfile$.u3d";
3450 wxString currCWD = wxGetCwd();
3451 wxString workCWD = fn.GetPath();
3453 if( !workCWD.IsEmpty() )
3454 wxSetWorkingDirectory( workCWD );
3457 bool success = writer.
Perform( m_doc );
3463 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3465 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
3472 wxSetWorkingDirectory( currCWD );
3483 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
3492 wxFileName fn( aFileName );
3494 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
3495 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
3497 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
3498 bool success = writer.
Perform( m_doc );
3501 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
3503 plotter->SetColorMode(
true );
3504 plotter->Set3DExport(
true );
3505 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
3507 plotter->SetRenderSettings( &renderSettings );
3509 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
3511 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
3517 plotter->StartPlot(
"1",
"3D Model" );
3518 double fov_degrees = 16.5f;
3523 std::vector<PDF_3D_VIEW> views;
3528 std::vector<float> c2wMatrix =
3532 .m_name =
"Default",
3533 .m_cameraMatrix = c2wMatrix,
3534 .m_cameraCenter = (float)
distance,
3535 .m_fov = (
float) fov_degrees,
3544 .m_cameraMatrix = c2wMatrix,
3545 .m_cameraCenter = (float)
distance,
3546 .m_fov = (
float) fov_degrees,
3555 .m_cameraMatrix = c2wMatrix,
3556 .m_cameraCenter = (float)
distance,
3557 .m_fov = (
float) fov_degrees,
3566 .m_cameraMatrix = c2wMatrix,
3567 .m_cameraCenter = (float)
distance,
3568 .m_fov = (
float) fov_degrees,
3571 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
3580 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
3582 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3583 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
3589 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)
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 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)
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)
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
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
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.
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< 0 > 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
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D