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 );
2332 board_color = front_mask_color;
2333 board_color.SetAlpha( 1.0 );
2336 TDF_Label front_mask_mat = makeMaterial(
"soldermask", front_mask_color, 0.0, 0.6 );
2337 TDF_Label back_mask_mat = makeMaterial(
"soldermask", back_mask_color, 0.0, 0.6 );
2338 TDF_Label front_silk_mat = makeMaterial(
"silkscreen", front_silk_color, 0.0, 0.9 );
2339 TDF_Label back_silk_mat = makeMaterial(
"silkscreen", back_silk_color, 0.0, 0.9 );
2340 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2341 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2342 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2344 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true,
"Copper" );
2348 pushToAssembly(
m_board_front_silk, front_silk_mat,
"silkscreen",
true,
"Top Silkscreen" );
2349 pushToAssembly(
m_board_back_silk, back_silk_mat,
"silkscreen",
true,
"Bottom Silkscreen" );
2350 pushToAssembly(
m_board_front_mask, front_mask_mat,
"soldermask",
true,
"Top Soldermask" );
2351 pushToAssembly(
m_board_back_mask, back_mask_mat,
"soldermask",
true,
"Bottom Soldermask" );
2353 if( aPushBoardBody )
2356#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2357 m_assy->UpdateAssemblies();
2366bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2370 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2378 wxFileName fn( aFileName );
2379 IGESControl_Controller::Init();
2380 IGESCAFControl_Writer writer;
2381 writer.SetColorMode( Standard_True );
2382 writer.SetNameMode( Standard_True );
2383 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2384 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2385 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2386 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2387 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2388 writer.Model()->SetGlobalSection( header );
2390 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2399 wxFileInputStream input( inputFile );
2400 wxFileOutputStream output( outputFile );
2404 m_reporter->Report( wxString::Format(
_(
"Cannot create input stream '%s'.\n" ), inputFile ) );
2408 if( !output.IsOk() )
2410 m_reporter->Report( wxString::Format(
_(
"Cannot create output stream '%s'.\n" ), outputFile ) );
2414 wxZlibOutputStream zlibStream( output, -1, wxZLIB_GZIP );
2416 if( !zlibStream.IsOk() )
2418 m_reporter->Report(
_(
"Impossible create compress stream" ) );
2422 input.Read( zlibStream );
2424 if( input.LastRead() == 0 || zlibStream.LastWrite() == 0 )
2426 m_reporter->Report(
_(
"Compress read or write error" ) );
2440 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2448 wxFileName fn( aFileName );
2450 STEPCAFControl_Writer writer;
2451 writer.SetColorMode( Standard_True );
2452 writer.SetNameMode( Standard_True );
2459 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2461 m_reporter->Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2467 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2469 m_reporter->Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2473 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2476 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2480 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2483 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2484 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2485 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2486 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2488 bool success =
true;
2491 wxString currCWD = wxGetCwd();
2492 wxString workCWD = fn.GetPath();
2494 if( !workCWD.IsEmpty() )
2495 wxSetWorkingDirectory( workCWD );
2497 wxString tmpfname(
"$tempfile$.step" );
2499 if( Standard_False == writer.Write( tmpfname.c_str() ) )
2502 if( compress && success )
2504 wxString srcTmp( tmpfname );
2505 wxString dstTmp(
"$tempfile$.stpz" );
2508 wxRemoveFile( srcTmp );
2519 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2521 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
2529 wxSetWorkingDirectory( currCWD );
2539 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
2548 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2553 wxFileName fn( aFileName );
2555 wxFFileOutputStream ffStream( fn.GetFullPath() );
2556 wxStdOutputStream stdStream( ffStream );
2558#if OCC_VERSION_HEX >= 0x070600
2559 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2561 BRepTools::Write( shape, stdStream );
2570 wxFileName fn( aFileName );
2572 wxFFileOutputStream ffStream( fn.GetFullPath() );
2573 wxStdOutputStream file( ffStream );
2575 if( !ffStream.IsOk() )
2577 m_reporter->Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
2585 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2590 std::map<wxString, std::vector<int>> groups[4];
2591 std::map<wxString, double> groupAreas;
2592 TopExp_Explorer exp;
2595 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2597 TopoDS_Shape subShape = exp.Current();
2600 BRepBndLib::Add( subShape, bbox );
2604 for(
const auto& pair : pairs )
2606 const auto& [point, padTestShape] = pair;
2608 if( bbox.IsOut( point ) )
2611 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2613 if( surface.GetType() != GeomAbs_Plane )
2616 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2619 if( !dist.IsDone() )
2622 if( dist.Value() < Precision::Approximation() )
2625 groups[2][padKey].push_back( faceIndex );
2627 GProp_GProps system;
2628 BRepGProp::SurfaceProperties( subShape, system );
2630 double surfaceArea = system.Mass() / 1e6;
2631 groupAreas[padKey] += surfaceArea;
2640 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2641 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2642 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2643 file <<
" <shape format=\"BREP\"><![CDATA[";
2644#if OCC_VERSION_HEX < 0x070600
2645 BRepTools::Write( shape, file );
2647 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2649 file <<
"]]></shape>" << std::endl;
2650 file <<
" <topology>" << std::endl;
2652 TopTools_IndexedMapOfShape mainMap;
2653 TopExp::MapShapes( shape, mainMap );
2654 std::set<int> topo[4];
2656 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2659 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2660 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2662 for(
int dim = 0; dim < 4; dim++ )
2664 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2666 TopoDS_Shape subShape = exp.Current();
2667 int idx = mainMap.FindIndex( subShape );
2669 if( idx && !topo[dim].count( idx ) )
2670 topo[dim].insert( idx );
2674 for(
int dim = 0; dim <= 3; dim++ )
2676 std::string labels = c_dimLabels[dim];
2677 std::string label = c_dimLabel[dim];
2679 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2682 for(
auto p : topo[dim] )
2684 std::string
name(
"" );
2685 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2686 <<
"name=\"" <<
name <<
"\" "
2687 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2691 file <<
" </" << labels <<
">" << std::endl;
2694 file <<
" </topology>" << std::endl;
2695 file <<
" </geometry>" << std::endl;
2696 file <<
" <groups count=\""
2697 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2700 int groupNumber = 1;
2705 for(
int dim = 0; dim <= 3; dim++ )
2707 std::string label = c_dimLabel[dim];
2709 for(
auto g : groups[dim] )
2712 wxString
name = g.first;
2716 std::ostringstream gs;
2717 gs <<
"G_" << dim <<
"D_" << g.first;
2720 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2726 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2728 for(
auto index : g.second )
2729 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2731 file <<
" </group>" << std::endl;
2733 m_reporter->Report( wxString::Format(
"%d\t%s\t%g",
2745 file <<
" </groups>" << std::endl;
2746 file <<
" <fields count=\"0\"/>" << std::endl;
2747 file <<
"</XAO>" << std::endl;
2754 bool aSubstituteModels, wxString* aErrorMessage )
2756 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2757 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2759 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2763 aLabel = mm->second;
2769 Handle( TDocStd_Document ) doc;
2770 m_app->NewDocument(
"MDTV-XCAF", doc );
2772 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2778 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2780 m_reporter->Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'." ),
2788 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2790 m_reporter->Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'." ),
2801 wxFFileInputStream ifile( fileName );
2802 wxFileName outFile( fileName );
2804 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2805 outFile.SetExt( wxT(
"step" ) );
2806 wxFileOffset size = ifile.GetLength();
2808 if( size == wxInvalidOffset )
2810 m_reporter->Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'." ),
2817 bool success =
false;
2818 wxFFileOutputStream ofile( outFile.GetFullPath() );
2823 char* buffer =
new char[size];
2825 ifile.Read( buffer, size );
2826 std::string expanded;
2830 expanded = gzip::decompress( buffer, size );
2835 m_reporter->Report( wxString::Format( wxT(
"failed to decompress '%s'." ),
2840 if( expanded.empty() )
2844 wxZipInputStream izipfile( ifile );
2845 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2847 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2849 izipfile.Read( ofile );
2855 ofile.Write( expanded.data(), expanded.size() );
2863 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2883 if( aSubstituteModels )
2885 wxFileName wrlName( fileName );
2887 wxString basePath = wrlName.GetPath();
2888 wxString baseName = wrlName.GetName();
2896 alts.Add( wxT(
"stp" ) );
2897 alts.Add( wxT(
"step" ) );
2898 alts.Add( wxT(
"STP" ) );
2899 alts.Add( wxT(
"STEP" ) );
2900 alts.Add( wxT(
"Stp" ) );
2901 alts.Add( wxT(
"Step" ) );
2902 alts.Add( wxT(
"stpz" ) );
2903 alts.Add( wxT(
"stpZ" ) );
2904 alts.Add( wxT(
"STPZ" ) );
2905 alts.Add( wxT(
"step.gz" ) );
2906 alts.Add( wxT(
"stp.gz" ) );
2909 alts.Add( wxT(
"iges" ) );
2910 alts.Add( wxT(
"IGES" ) );
2911 alts.Add( wxT(
"igs" ) );
2912 alts.Add( wxT(
"IGS" ) );
2916 for(
const auto& alt : alts )
2918 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2920 if( altFile.IsOk() && altFile.FileExists() )
2922 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2942 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2944 Handle( XCAFDoc_ShapeTool ) shapeTool =
2945 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2948 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2952 m_reporter->Report( wxString::Format( wxT(
"readVRML() failed on filename '%s'." ),
2962 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export." ) );
2972 m_reporter->Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'." ),
2980 if( aLabel.IsNull() )
2982 m_reporter->Report( wxString::Format(
_(
"Could not transfer model data from file '%s'." ),
2990 wxFileName afile( fileName );
2991 std::string pname( afile.GetName().ToUTF8() );
2992 TCollection_ExtendedString partname( pname.c_str() );
2993 TDataStd_Name::Set( aLabel, partname );
3003 TopLoc_Location& aLocation )
3017 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
3023 double boardThickness;
3026 double top = std::max( boardZPos, boardZPos + boardThickness );
3027 double bottom = std::min( boardZPos, boardZPos + boardThickness );
3032 double f_pos, f_thickness;
3036 bottom += f_thickness;
3043 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3044 lPos.Multiply( lRot );
3045 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
M_PI );
3046 lPos.Multiply( lRot );
3051 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
3052 lPos.Multiply( lRot );
3056 lOff.SetTranslation( gp_Vec( offset.
x, offset.
y, offset.
z ) );
3057 lPos.Multiply( lOff );
3060 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
3061 lPos.Multiply( lOrient );
3062 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
3063 lPos.Multiply( lOrient );
3064 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
3065 lPos.Multiply( lOrient );
3067 aLocation = TopLoc_Location( lPos );
3074 IGESControl_Controller::Init();
3075 IGESCAFControl_Reader reader;
3076 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3078 if( stat != IFSelect_RetDone )
3082 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3086 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3090 reader.SetColorMode(
true );
3091 reader.SetNameMode(
false );
3092 reader.SetLayerMode(
false );
3094 if( !reader.Transfer( doc ) )
3096 if( doc->CanClose() == CDM_CCS_OK )
3103 if( reader.NbShapes() < 1 )
3105 if( doc->CanClose() == CDM_CCS_OK )
3117 STEPCAFControl_Reader reader;
3118 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3120 if( stat != IFSelect_RetDone )
3124 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3128 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3132 reader.SetColorMode(
true );
3133 reader.SetNameMode(
true );
3134 reader.SetLayerMode(
false );
3136 if( !reader.Transfer( doc ) )
3138 if( doc->CanClose() == CDM_CCS_OK )
3145 if( reader.NbRootsForTransfer() < 1 )
3147 if( doc->CanClose() == CDM_CCS_OK )
3159#if OCC_VERSION_HEX >= 0x070700
3160 VrmlAPI_CafReader reader;
3161 RWMesh_CoordinateSystemConverter conv;
3162 conv.SetInputLengthUnit( 2.54 );
3163 reader.SetCoordinateSystemConverter( conv );
3164 reader.SetDocument( doc );
3166 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3181 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3184 TDF_LabelSequence frshapes;
3185 s_assy->GetFreeShapes( frshapes );
3188 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3191 TDF_Label d_targetLabel = d_assy->NewShape();
3193 if( frshapes.Size() == 1 )
3195 TDocStd_XLinkTool link;
3196 link.Copy( d_targetLabel, frshapes.First() );
3201 for( TDF_Label& s_shapeLabel : frshapes )
3203 TDF_Label d_component = d_assy->NewShape();
3205 TDocStd_XLinkTool link;
3206 link.Copy( d_component, s_shapeLabel );
3208 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3212 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3215 return d_targetLabel;
3221 TDF_LabelSequence freeShapes;
3222 aShapeTool->GetFreeShapes( freeShapes );
3228 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3230 TDF_Label label = freeShapes.Value( i );
3232 aShapeTool->GetShape( label, shape );
3237 const Standard_Real linearDeflection = 0.14;
3238 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3239 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3261 wxFileName fn( aFileName );
3263 const char* tmpGltfname =
"$tempfile$.glb";
3264 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3266 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3267 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3268 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3269 RWMesh_CoordinateSystem_Zup );
3270#if OCC_VERSION_HEX >= 0x070700
3271 cafWriter.SetParallel(
true );
3273 TColStd_IndexedDataMapOfStringString metadata;
3275 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3276 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3277 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3278 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3279 metadata.Add( TCollection_AsciiString(
"generator" ),
3280 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3281 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3284 bool success =
true;
3287 wxString currCWD = wxGetCwd();
3288 wxString workCWD = fn.GetPath();
3290 if( !workCWD.IsEmpty() )
3291 wxSetWorkingDirectory( workCWD );
3293 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3300 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3302 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3310 wxSetWorkingDirectory( currCWD );
3318#if OCC_VERSION_HEX < 0x070700
3325 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3335 wxFileName fn( aFileName );
3337 const char* tmpFname =
"$tempfile$.ply";
3338 RWPly_CafWriter cafWriter( tmpFname );
3340 cafWriter.SetFaceId(
true );
3341 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3342 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
3344 TColStd_IndexedDataMapOfStringString metadata;
3346 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3347 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3348 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3349 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3350 metadata.Add( TCollection_AsciiString(
"generator" ),
3351 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
3353 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3356 bool success =
true;
3359 wxString currCWD = wxGetCwd();
3360 wxString workCWD = fn.GetPath();
3362 if( !workCWD.IsEmpty() )
3363 wxSetWorkingDirectory( workCWD );
3365 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3372 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3374 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3382 wxSetWorkingDirectory( currCWD );
3393 m_reporter->Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'." ),
3403 wxFileName fn( aFileName );
3405 const char* tmpFname =
"$tempfile$.stl";
3408 wxString currCWD = wxGetCwd();
3409 wxString workCWD = fn.GetPath();
3411 if( !workCWD.IsEmpty() )
3412 wxSetWorkingDirectory( workCWD );
3414 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
3421 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3423 m_reporter->Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'." ),
3431 wxSetWorkingDirectory( currCWD );
3443 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
3452 wxFileName fn( aFileName );
3454 const char* tmpFname =
"$tempfile$.u3d";
3457 wxString currCWD = wxGetCwd();
3458 wxString workCWD = fn.GetPath();
3460 if( !workCWD.IsEmpty() )
3461 wxSetWorkingDirectory( workCWD );
3464 bool success = writer.
Perform( m_doc );
3470 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3472 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ), tmpFname,
3479 wxSetWorkingDirectory( currCWD );
3490 wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ), aFileName ),
3499 wxFileName fn( aFileName );
3501 wxFileName u3dTmpfn = wxFileName::CreateTempFileName(
"" );
3502 wxFileName pdfTmpfn = wxFileName::CreateTempFileName(
"" );
3504 U3D::WRITER writer( u3dTmpfn.GetFullPath().ToStdString() );
3505 bool success = writer.
Perform( m_doc );
3508 std::unique_ptr<PDF_PLOTTER> plotter = std::make_unique<PDF_PLOTTER>();
3510 plotter->SetColorMode(
true );
3511 plotter->Set3DExport(
true );
3512 plotter->SetCreator( wxT(
"Mark's awesome 3d exporter" ) );
3514 plotter->SetRenderSettings( &renderSettings );
3516 if( !plotter->OpenFile( pdfTmpfn.GetFullPath() ) )
3518 m_reporter->Report( wxString::Format( wxT(
"Cannot open temporary file '%s'.\n" ), pdfTmpfn.GetFullPath() ),
3524 plotter->StartPlot(
"1",
"3D Model" );
3525 double fov_degrees = 16.5f;
3530 std::vector<PDF_3D_VIEW> views;
3535 std::vector<float> c2wMatrix =
3539 .m_name =
"Default",
3540 .m_cameraMatrix = c2wMatrix,
3541 .m_cameraCenter = (float)
distance,
3542 .m_fov = (
float) fov_degrees,
3551 .m_cameraMatrix = c2wMatrix,
3552 .m_cameraCenter = (float)
distance,
3553 .m_fov = (
float) fov_degrees,
3562 .m_cameraMatrix = c2wMatrix,
3563 .m_cameraCenter = (float)
distance,
3564 .m_fov = (
float) fov_degrees,
3573 .m_cameraMatrix = c2wMatrix,
3574 .m_cameraCenter = (float)
distance,
3575 .m_fov = (
float) fov_degrees,
3578 plotter->Plot3DModel( u3dTmpfn.GetFullPath(), views );
3587 if( !wxRenameFile( pdfTmpfn.GetFullPath(), fn.GetFullPath(),
true ) )
3589 m_reporter->Report( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3590 pdfTmpfn.GetFullPath(), fn.GetFullPath() ),
3596 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