31#include <wx/filename.h>
33#include <wx/sstream.h>
34#include <wx/stdpaths.h>
35#include <wx/wfstream.h>
36#include <wx/zipstrm.h>
37#include <wx/stdstream.h>
40#include <decompress.hpp>
58#include <IGESCAFControl_Reader.hxx>
59#include <IGESCAFControl_Writer.hxx>
60#include <IGESControl_Controller.hxx>
61#include <IGESData_GlobalSection.hxx>
62#include <IGESData_IGESModel.hxx>
63#include <Interface_Static.hxx>
64#include <Quantity_Color.hxx>
65#include <STEPCAFControl_Reader.hxx>
66#include <STEPCAFControl_Writer.hxx>
67#include <APIHeaderSection_MakeHeader.hxx>
68#include <Standard_Failure.hxx>
69#include <Standard_Handle.hxx>
70#include <Standard_Version.hxx>
71#include <TCollection_ExtendedString.hxx>
72#include <TDocStd_Document.hxx>
73#include <TDocStd_XLinkTool.hxx>
74#include <TDataStd_Name.hxx>
75#include <TDataStd_TreeNode.hxx>
76#include <TDF_LabelSequence.hxx>
77#include <TDF_Tool.hxx>
78#include <TopExp_Explorer.hxx>
80#include <XCAFApp_Application.hxx>
82#include <XCAFDoc_DocumentTool.hxx>
83#include <XCAFDoc_ColorTool.hxx>
84#include <XCAFDoc_ShapeTool.hxx>
85#include <XCAFDoc_VisMaterialTool.hxx>
86#include <XCAFDoc_Area.hxx>
87#include <XCAFDoc_Centroid.hxx>
88#include <XCAFDoc_Location.hxx>
89#include <XCAFDoc_Volume.hxx>
91#include "KI_XCAFDoc_AssemblyGraph.hxx"
93#include <BRep_Tool.hxx>
94#include <BRepMesh_IncrementalMesh.hxx>
95#include <BRepBuilderAPI_GTransform.hxx>
96#include <BRepBuilderAPI_MakeEdge.hxx>
97#include <BRepBuilderAPI_MakeWire.hxx>
98#include <BRepBuilderAPI_MakeFace.hxx>
99#include <BRepExtrema_DistShapeShape.hxx>
100#include <BRepPrimAPI_MakePrism.hxx>
101#include <BRepTools.hxx>
102#include <BRepLib_MakeWire.hxx>
103#include <BRepAdaptor_Surface.hxx>
104#include <BRepAlgoAPI_Check.hxx>
105#include <BRepAlgoAPI_Cut.hxx>
106#include <BRepAlgoAPI_Fuse.hxx>
107#include <ShapeUpgrade_UnifySameDomain.hxx>
109#include <BRepBndLib.hxx>
110#include <Bnd_BoundSortBox.hxx>
111#include <GProp_GProps.hxx>
112#include <BRepGProp.hxx>
114#include <Geom_Curve.hxx>
115#include <Geom_TrimmedCurve.hxx>
120#include <GC_MakeArcOfCircle.hxx>
121#include <GC_MakeCircle.hxx>
123#include <RWGltf_CafWriter.hxx>
124#include <StlAPI_Writer.hxx>
126#if OCC_VERSION_HEX >= 0x070700
127#include <VrmlAPI_CafReader.hxx>
128#include <RWPly_CafWriter.hxx>
156 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
158 if( !lfile.FileExists() )
161 wxString ext = lfile.GetExt().Lower();
163 if( ext == wxT(
"wrl" ) )
166 if( ext == wxT(
"wrz" ) )
169 if( ext == wxT(
"idf" ) )
172 if( ext == wxT(
"emn" ) )
175 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
189 const int max_line_count = 3;
191 for(
int ii = 0; ii < max_line_count; ii++ )
193 memset( iline, 0, 82 );
194 ifile.getline( iline, 82 );
200 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
206 std::string fstr = iline;
210 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
219 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
226 if( strncmp( iline,
"/*", 2 ) != 0 )
244 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
245 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
246 double det = -b.
x * d.
y + d.
x * b.
y;
250 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
251 center.
y = ( b.
x * cd + d.
x * bc ) * det;
258#define APPROX_DBG( stmt )
266 static const double c_radiusDeviation = 1000.0;
267 static const double c_arcCenterDeviation = 1000.0;
268 static const double c_relLengthDeviation = 0.8;
269 static const int c_last_none = -1000;
289 int last = c_last_none;
295 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
297 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
302 bool defective =
false;
308 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
316 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
317 defective |=
std::abs( a_diff ) < 0.1;
320 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
321 defective |=
std::abs( a_diff ) >= maxAngleDiff;
332 for(
int j = i; j <= jEndIdx; j++ )
337 double rad_test = ( p_test -
center ).EuclideanNorm();
338 double d_tl = ( p_test - p_prev ).EuclideanNorm();
342 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
345 if( rad_dev > c_radiusDeviation )
348 <<
" Radius deviation too large: " << int64_t( rad_dev )
349 <<
" > " << c_radiusDeviation << std::endl );
354 double maxAngleDiff =
355 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
357 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
358 if(
std::abs( a_diff_test ) >= maxAngleDiff )
360 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
365 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
367 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
368 <<
"; " << d01 << std::endl );
378 if( last != c_last_none )
387 int toRemove = last - ( aSrc.
PointCount() - 3 );
417 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
421 if( last == c_last_none )
438 if( iarc0 != -1 && iarc1 != -1 )
440 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
450 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
468 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
469 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
485static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
487 TDF_LabelSequence theLabels;
488 aShapeTool->GetFreeShapes( theLabels );
492 if( theLabels.Length() == 1 )
493 return aShapeTool->GetShape( theLabels.Value( 1 ) );
495 TopoDS_Compound aCompound;
496 BRep_Builder aBuilder;
497 aBuilder.MakeCompound( aCompound );
499 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
501 TopoDS_Shape aFreeShape;
503 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
506 aBuilder.Add( aCompound, aFreeShape );
509 if( aCompound.NbChildren() > 0 )
518static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
520 if( theLabel.IsNull() )
522 Message::SendFail(
"Null label." );
523 return Standard_False;
526 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
527 || Abs( aScale.Z() ) <= gp::Resolution() )
529 Message::SendFail(
"Scale factor is too small." );
530 return Standard_False;
533 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
535 if( aShapeTool.IsNull() )
537 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
538 return Standard_False;
541 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
545 Message::SendFail(
"Couldn't create assembly graph." );
546 return Standard_False;
549 Standard_Boolean anIsDone = Standard_True;
553 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
555 0, 0, aScale.Z() ) );
558 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
560 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
562 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
564 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
565 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
570 const TDF_Label& aLabel = aG->GetNode( idx );
572 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
574 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
575 aBRepTrsf.Perform( aShape, Standard_True );
576 if( !aBRepTrsf.IsDone() )
578 Standard_SStream aSS;
579 TCollection_AsciiString anEntry;
580 TDF_Tool::Entry( aLabel, anEntry );
581 aSS <<
"Shape " << anEntry <<
" is not scaled!";
582 Message::SendFail( aSS.str().c_str() );
583 anIsDone = Standard_False;
584 return Standard_False;
586 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
587 aShapeTool->SetShape( aLabel, aScaledShape );
590 TDF_LabelSequence aSubshapes;
591 aShapeTool->GetSubShapes( aLabel, aSubshapes );
592 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
594 const TDF_Label& aLSs = anItSs.Value();
595 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
596 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
597 aShapeTool->SetShape( aLSs, aSs1 );
601 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
602 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
603 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
605 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
607 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
608 gp_Trsf aTrsf = aLoc.Transformation();
609 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
610 XCAFDoc_Location::Set( aLabel, aTrsf );
616 return Standard_False;
619 aShapeTool->UpdateAssemblies();
627 BRepAlgoAPI_Fuse mkFuse;
628 TopTools_ListOfShape shapeArguments, shapeTools;
630 for( TopoDS_Shape& sh : aInputShapes )
635 if( shapeArguments.IsEmpty() )
636 shapeArguments.Append( sh );
638 shapeTools.Append( sh );
641 mkFuse.SetRunParallel(
true );
642 mkFuse.SetToFillHistory(
false );
643 mkFuse.SetArguments( shapeArguments );
644 mkFuse.SetTools( shapeTools );
647 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
651 if( mkFuse.HasErrors() )
653 wxString msg =
_(
"Errors:\n" );
654 wxStringOutputStream os_stream( &msg );
655 wxStdOutputStream out( os_stream );
657 mkFuse.DumpErrors( out );
661 if( mkFuse.HasWarnings() )
663 wxString msg =
_(
"Warnings:\n" );
664 wxStringOutputStream os_stream( &msg );
665 wxStdOutputStream out( os_stream );
667 mkFuse.DumpWarnings( out );
672 if( mkFuse.IsDone() )
674 TopoDS_Shape fusedShape = mkFuse.Shape();
676 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
677 unify.History() =
nullptr;
680 TopoDS_Shape unifiedShapes = unify.Shape();
682 if( unifiedShapes.IsNull() )
684 aReporter->
Report(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ),
689 aOutShape = unifiedShapes;
700 TopoDS_Compound compound;
701 BRep_Builder builder;
702 builder.MakeCompound( compound );
704 for(
const TopoDS_Shape& shape : aInputShapes )
705 builder.Add( compound, shape );
715 TopoDS_Shape outShape;
717 if( aInputShapes.Size() == 1 )
718 return aInputShapes.First();
720 if(
fuseShapes( aInputShapes, outShape, aReporter ) )
729 const TCollection_ExtendedString& aPrefix )
731 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
735 Message::SendFail(
"Couldn't create assembly graph." );
736 return Standard_False;
739 Standard_Boolean anIsDone = Standard_True;
741 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
743 const TDF_Label& lbl = aG->GetNode( idx );
744 Handle( TDataStd_Name ) nameHandle;
746 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
748 TCollection_ExtendedString
name;
752 name += nameHandle->Get();
755 TDataStd_Name::Set( lbl,
name );
759 TDataStd_Name::Set( lbl, aPrefix );
768 m_reporter( aReporter )
770 m_app = XCAFApp_Application::GetApplication();
771 m_app->NewDocument(
"MDTV-XCAF", m_doc );
772 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
784 m_outFmt = OUTPUT_FORMAT::FMT_OUT_UNKNOWN;
790 if( m_doc->CanClose() == CDM_CCS_OK )
798 const double c_padExtraThickness = 0.005;
800 std::vector<TopoDS_Shape> padShapes;
801 bool castellated = aClipPolygon && aPad->
GetProperty() == PAD_PROP::CASTELLATED;
814 double Zpos, thickness;
820 if( pcb_layer ==
F_Cu )
821 thickness += c_padExtraThickness;
822 else if( pcb_layer ==
B_Cu )
823 thickness -= c_padExtraThickness;
826 TopoDS_Shape testShape;
840 if( testShape.IsNull() )
842 std::vector<TopoDS_Shape> testShapes;
846 if( testShapes.size() > 0 )
847 testShape = testShapes.front();
850 if( !aVia && !testShape.IsNull() )
852 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
858 if( pcb_layer ==
F_Cu )
860 else if( pcb_layer ==
B_Cu )
877 double f_pos, f_thickness;
878 double b_pos, b_thickness;
885 f_thickness += c_padExtraThickness;
886 b_thickness -= c_padExtraThickness;
889 double top = std::max( f_pos, f_pos + f_thickness );
890 double bottom = std::min( b_pos, b_pos + b_thickness );
891 double hole_height = top - bottom;
893 TopoDS_Shape plating;
901 hole_height, bottom, aOrigin ) )
903 padShapes.push_back( plating );
917 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
934 padShapes.push_back( plating );
946 if( !padShapes.empty() )
951 TopTools_ListOfShape padShapesList;
953 for(
const TopoDS_Shape& shape : padShapes )
954 padShapesList.Append( shape );
960 for(
const TopoDS_Shape& shape : padShapes )
971 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
973 double margin = 0.001;
981 double f_pos, f_thickness;
982 double b_pos, b_thickness;
985 double top = std::max( f_pos, f_pos + f_thickness );
986 double bottom = std::min( b_pos, b_pos + b_thickness );
988 double holeZsize = ( top - bottom ) + ( margin * 2 );
990 double boardDrill = aShape.
GetWidth();
991 double copperDrill = boardDrill - aPlatingThickness * 2;
993 TopoDS_Shape copperHole, boardHole;
998 holeZsize, bottom - margin, aOrigin ) )
1011 holeZsize, bottom - margin, aOrigin ) )
1027 const wxString& aNetname )
1029 double f_pos, f_thickness;
1030 double b_pos, b_thickness;
1033 double top = std::max( f_pos, f_pos + f_thickness );
1034 double bottom = std::min( b_pos, b_pos + b_thickness );
1036 TopoDS_Shape plating;
1039 ( top - bottom ), bottom, aOrigin ) )
1054 double& aThickness )
1057 static const double c_silkscreenAboveCopper = 0.04;
1058 static const double c_soldermaskAboveCopper = 0.015;
1066 double f_pos, f_thickness;
1068 double top = std::max( f_pos, f_pos + f_thickness );
1071 aZPos = top + c_silkscreenAboveCopper;
1073 aZPos = top + c_soldermaskAboveCopper;
1079 double b_pos, b_thickness;
1081 double bottom = std::min( b_pos, b_pos + b_thickness );
1084 aZPos = bottom - c_silkscreenAboveCopper;
1086 aZPos = bottom - c_soldermaskAboveCopper;
1094 double& aThickness )
1098 bool wasPrepreg =
false;
1103 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1109 if( aLayer ==
B_Cu )
1154 double f_pos, f_thickness;
1155 double b_pos, b_thickness;
1158 double top = std::min( f_pos, f_pos + f_thickness );
1159 double bottom = std::max( b_pos, b_pos + b_thickness );
1161 aThickness = ( top - bottom );
1164 wxASSERT( aZPos == 0.0 );
1169 const VECTOR2D& aOrigin,
const wxString& aNetname )
1171 bool success =
true;
1179 double z_pos, thickness;
1189 m_reporter->
Report( wxString::Format(
_(
"Could not add shape (%d points) to copper layer %s.\n" ),
1205 if( aFileNameUTF8.empty() )
1207 m_reporter->
Report( wxString::Format(
_(
"No model defined for %s.\n" ), aRefDes ),
1212 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1217 wxString errorMessage;
1219 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1221 if( errorMessage.IsEmpty() )
1222 errorMessage.Printf(
_(
"No model for filename '%s'.\n" ), fileName );
1229 TopLoc_Location toploc;
1231 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1233 m_reporter->
Report( wxString::Format(
_(
"No location data for filename '%s'.\n" ), fileName ),
1239 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1241 if( llabel.IsNull() )
1243 m_reporter->
Report( wxString::Format(
_(
"Could not add component with filename '%s'.\n" ), fileName ),
1249 TCollection_ExtendedString refdes( aRefDes.c_str() );
1250 TDataStd_Name::Set( llabel, refdes );
1317 double aWidth,
double aThickness,
1318 double aZposition,
const VECTOR2D& aOrigin )
1325 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1326 double h_width = aWidth/2.0;
1328 coords[0] =
VECTOR2D{ 0.0, h_width };
1331 coords[1] =
VECTOR2D{ len, h_width };
1334 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1337 coords[3] =
VECTOR2D{ len, -h_width };
1340 coords[4] =
VECTOR2D{ 0, -h_width };
1343 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1346 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1348 for(
int ii = 0; ii < 6; ii++ )
1351 coords[ii] += aStartPoint;
1356 gp_Pnt coords3D[ 6 ];
1358 for(
int ii = 0; ii < 6; ii++ )
1365 BRepBuilderAPI_MakeWire wire;
1366 bool success =
true;
1378 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1383 edge = BRepBuilderAPI_MakeEdge(
circle );
1388 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1391 Handle( Geom_TrimmedCurve ) arcOfCircle =
1392 GC_MakeArcOfCircle( coords3D[1],
1396 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1399 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1402 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1403 GC_MakeArcOfCircle( coords3D[4],
1407 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1411 catch(
const Standard_Failure& e )
1413 m_reporter->
Report( wxString::Format(
_(
"OCC exception building shape segment: %s\n" ),
1414 e.GetMessageString() ),
1419 BRepBuilderAPI_MakeFace face;
1423 gp_Pln plane( coords3D[0], gp::DZ() );
1424 face = BRepBuilderAPI_MakeFace( plane, wire );
1426 catch(
const Standard_Failure& e )
1429 e.GetMessageString() ),
1434 if( aThickness != 0.0 )
1436 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1438 if( aShape.IsNull() )
1457 double aZposition,
const VECTOR2D& aOrigin )
1459 std::vector<TopoDS_Shape> testShapes;
1462 aHeight, aZposition, aOrigin );
1464 if( testShapes.size() > 0 )
1465 aShape = testShapes.front();
1488 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin,
1492 [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1505 gp_Pnt start = toPoint( aPt0 );
1506 gp_Pnt
end = toPoint( aPt1 );
1508 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
1510 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1512 aReporter->
Report( wxString::Format(
_(
"Failed to make segment edge (%d %d) -> (%d %d), "
1520 aMkWire.Add( mkEdge.Edge() );
1522 if( aMkWire.Error() != BRepLib_WireDone )
1524 aReporter->
Report( wxString::Format(
_(
"Failed to add segment edge (%d %d) -> (%d %d)\n" ),
1538 Handle( Geom_Curve ) curve;
1540 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1542 gp_Ax2 axis = gp::XOY();
1543 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1545 curve = GC_MakeCircle( axis,
pcbIUScale.
IUTomm( aArc.GetRadius() ) ).Value();
1549 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1550 toPoint( aArc.GetP1() ) ).Value();
1553 if( curve.IsNull() )
1556 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1558 if( !aMkWire.IsDone() )
1560 aReporter->
Report( wxString::Format(
_(
"Failed to add arc curve from (%d %d), arc p0 "
1561 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1563 aArc.GetP0().x, aArc.GetP0().y,
1564 aArc.GetArcMid().x, aArc.GetArcMid().y,
1565 aArc.GetP1().x, aArc.GetP1().y ),
1575 bool isFirstShape =
true;
1588 if( nextShape != -1 )
1594 lastPt = aChain.
CPoint( i );
1604 firstPt = currentArc.
GetP0();
1609 lastPt = currentArc.
GetP0();
1611 if( addArc( lastPt, currentArc ) )
1612 lastPt = currentArc.
GetP1();
1631 isFirstShape =
false;
1634 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1636 aReporter->
Report( wxString::Format(
_(
"Failed to close wire at %d, %d -> %d, %d **\n" ),
1638 firstPt.
x, firstPt.
y ),
1644 catch(
const Standard_Failure& e )
1646 aReporter->
Report( wxString::Format(
_(
"OCC exception creating wire: %s\n" ),
1647 e.GetMessageString() ),
1657 bool aConvertToArcs,
double aThickness,
double aZposition,
1665 if( aConvertToArcs )
1669 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1673 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1676 polygon[contId] = approxChain;
1680 fallbackPoly = workingPoly;
1681 workingPoly = approximated;
1700 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1707 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1708 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1710 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1714 auto tryMakeWire = [
this, &aZposition,
1718 BRepLib_MakeWire mkWire;
1722 if( mkWire.IsDone() )
1724 wire = mkWire.Wire();
1728 m_reporter->
Report( wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n"
1729 "z: %g; bounding box: %s\n" ),
1730 static_cast<int>( aContour.PointCount() ),
1731 static_cast<int>( mkWire.Error() ),
1736 if( !wire.IsNull() )
1738 BRepAlgoAPI_Check check( wire,
false,
true );
1740 if( !check.IsValid() )
1742 m_reporter->
Report( wxString::Format(
_(
"Wire self-interference check failed\n"
1743 "z: %g; bounding box: %s\n" ),
1754 BRepBuilderAPI_MakeFace mkFace;
1756 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1760 TopoDS_Wire wire = tryMakeWire( polygon[contId] );
1762 if( aConvertToArcs && wire.IsNull() )
1768 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId] );
1773 if( !wire.IsNull() )
1775 if( basePlane.Axis().Direction().Z() < 0 )
1778 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1783 "z: %g; bounding box: %s\n" ),
1792 if( !wire.IsNull() )
1794 if( basePlane.Axis().Direction().Z() > 0 )
1802 "z: %g; bounding box: %s\n" ),
1809 catch(
const Standard_Failure& e )
1811 m_reporter->
Report( wxString::Format(
_(
"OCC exception creating contour %d: %s\n" ),
1812 static_cast<int>( contId ),
1813 e.GetMessageString() ),
1819 if( mkFace.IsDone() )
1821 TopoDS_Shape faceShape = mkFace.Shape();
1823 if( aThickness != 0.0 )
1825 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1826 aShapes.push_back( prism );
1828 if( prism.IsNull() )
1836 aShapes.push_back( faceShape );
1852 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1853 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1854 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1855 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1856 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1857 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1858 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1859 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1869 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1871 aColorOut =
COLOR4D( aColorStr );
1876 const std::vector<FAB_LAYER_COLOR>& colors =
1883 if( fabColor.GetName() == aColorStr )
1885 aColorOut = fabColor.GetColor( aType );
1907 Handle( XCAFDoc_VisMaterialTool ) visMatTool = XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1912 m_reporter->
Report( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1917 double boardThickness;
1937 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1941 polyset.
Append( contour );
1969 BRepBndLib::Add( brdShape, brdBndBox );
1972 m_reporter->
Report( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1977 [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1981 Bnd_Box brdWithHolesBndBox = brdBndBox;
1983 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1985 for(
size_t i = 0; i < input.size(); i++ )
1988 BRepBndLib::Add( input[i], bbox );
1989 brdWithHolesBndBox.Add( bbox );
1990 ( *holeBoxSet )[i] = bbox;
1993 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1996 auto subtractShapesMap =
1997 [&
tp,
this](
const wxString& aWhat, std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
1998 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2000 m_reporter->
Report( wxString::Format(
_(
"Subtracting holes for %s\n" ), aWhat ),
2003 for(
auto& [netname, vec] : aShapesMap )
2007 auto subtractLoopFn = [&](
const int a,
const int b )
2009 for(
int shapeId = a; shapeId < b; shapeId++ )
2011 TopoDS_Shape& shape = vec[shapeId];
2014 BRepBndLib::Add( shape, shapeBbox );
2016 TopTools_ListOfShape holelist;
2019 std::unique_lock lock( mutex );
2021 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
2023 for(
const Standard_Integer& index : indices )
2024 holelist.Append( aHolesList[index] );
2027 if( holelist.IsEmpty() )
2030 TopTools_ListOfShape cutArgs;
2031 cutArgs.Append( shape );
2033 BRepAlgoAPI_Cut
cut;
2035 cut.SetRunParallel(
true );
2036 cut.SetToFillHistory(
false );
2038 cut.SetArguments( cutArgs );
2039 cut.SetTools( holelist );
2042 if(
cut.HasErrors() ||
cut.HasWarnings() )
2045 "%s net '%s' **\n" ),
2051 if(
cut.HasErrors() )
2053 wxString msg =
_(
"Errors:\n" );
2054 wxStringOutputStream os_stream( &msg );
2055 wxStdOutputStream out( os_stream );
2057 cut.DumpErrors( out );
2061 if(
cut.HasWarnings() )
2063 wxString msg =
_(
"Warnings:\n" );
2064 wxStringOutputStream os_stream( &msg );
2065 wxStdOutputStream out( os_stream );
2067 cut.DumpWarnings( out );
2072 shape =
cut.Shape();
2076 tp.parallelize_loop( vec.size(), subtractLoopFn ).wait();
2080 auto subtractShapes =
2081 [subtractShapesMap](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
2082 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
2084 std::map<wxString, std::vector<TopoDS_Shape>> aShapesMap{ { wxEmptyString, aShapesList } };
2086 subtractShapesMap( aWhat, aShapesMap, aHolesList, aBSBHoles );
2087 aShapesList = aShapesMap[wxEmptyString];
2093 Bnd_BoundSortBox bsbHoles;
2101 Bnd_BoundSortBox bsbHoles;
2110 std::map<wxString, TopTools_ListOfShape> shapesToFuseMap;
2112 auto addShapes = [&shapesToFuseMap](
const wxString& aNetname,
2113 const std::vector<TopoDS_Shape>& aShapes )
2115 for(
const TopoDS_Shape& shape : aShapes )
2116 shapesToFuseMap[aNetname].Append( shape );
2120 addShapes( netname, shapes );
2123 addShapes( netname, shapes );
2126 addShapes( netname, shapes );
2133 auto fuseLoopFn = [&](
const wxString& aNetname )
2135 auto& toFuse = shapesToFuseMap[aNetname];
2138 if( !fusedShape.IsNull() )
2140 std::unique_lock lock( mutex );
2150 BS::multi_future<void> mf;
2152 for(
const auto& [netname,
_] : shapesToFuseMap )
2153 mf.push_back(
tp.submit( fuseLoopFn, netname ) );
2170 auto pushToAssemblyMap =
2171 [&](
const std::map<wxString, std::vector<TopoDS_Shape>>& aShapesMap,
2172 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
bool aCompoundNets,
2175 std::map<wxString, std::vector<TopoDS_Shape>> shapesMap;
2179 std::vector<TopoDS_Shape> allShapes;
2181 for(
const auto& [netname, shapesList] : aShapesMap )
2182 allShapes.insert( allShapes.end(), shapesList.begin(), shapesList.end() );
2184 if( !allShapes.empty() )
2185 shapesMap[wxEmptyString].emplace_back(
makeCompound( allShapes ) );
2189 shapesMap = aShapesMap;
2192 for(
const auto& [netname, shapesList] : shapesMap )
2194 std::vector<TopoDS_Shape> newList;
2199 newList = shapesList;
2203 for( TopoDS_Shape& shape : newList )
2205 Handle( TDataStd_TreeNode ) node;
2208 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2214 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2215 TDF_Label shpLbl = node->Father()->Label();
2217 if( !shpLbl.IsNull() )
2219 if( visMatTool && !aVisMatLabel.IsNull() )
2220 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2226 shapeName << aShapeName;
2228 if( !netname.empty() )
2231 shapeName << netname;
2234 if( newList.size() > 1 )
2240 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2241 TDataStd_Name::Set( shpLbl, partname );
2249 auto pushToAssembly =
2250 [&](
const std::vector<TopoDS_Shape>& aShapesList,
const TDF_Label& aVisMatLabel,
2251 const wxString& aShapeName,
bool aCompound )
2253 const std::map<wxString, std::vector<TopoDS_Shape>> shapesMap{ { wxEmptyString, aShapesList } };
2255 pushToAssemblyMap( shapesMap, aVisMatLabel, aShapeName, aCompound, aCompound );
2259 [&](
const TCollection_AsciiString& aName,
const Quantity_ColorRGBA& aBaseColor,
2260 double aMetallic,
double aRoughness ) -> TDF_Label
2262 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2263 XCAFDoc_VisMaterialPBR pbr;
2264 pbr.BaseColor = aBaseColor;
2265 pbr.Metallic = aMetallic;
2266 pbr.Roughness = aRoughness;
2267 vismat->SetPbrMaterial( pbr );
2268 return visMatTool->AddMaterial( vismat, aName );
2275 Quantity_ColorRGBA board_color( 0.3f, 0.3f, 0.3f, 1.0f );
2276 Quantity_ColorRGBA silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2277 Quantity_ColorRGBA mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2287 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2290 mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2293 if( item->GetBrdLayerId() ==
F_SilkS || item->GetBrdLayerId() ==
B_SilkS )
2294 silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2297 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2302 board_color = mask_color;
2303 board_color.SetAlpha( 1.0 );
2306 TDF_Label mask_mat = makeMaterial(
"soldermask", mask_color, 0.0, 0.6 );
2307 TDF_Label silk_mat = makeMaterial(
"silkscreen", silk_color, 0.0, 0.9 );
2308 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2309 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2310 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2312 pushToAssemblyMap(
m_board_copper, copper_mat,
"copper",
true,
true );
2319 if( aPushBoardBody )
2322#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2323 m_assy->UpdateAssemblies();
2332bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2336 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2342 m_outFmt = OUTPUT_FORMAT::FMT_OUT_IGES;
2344 wxFileName fn( aFileName );
2345 IGESControl_Controller::Init();
2346 IGESCAFControl_Writer writer;
2347 writer.SetColorMode( Standard_True );
2348 writer.SetNameMode( Standard_True );
2349 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2350 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2351 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2352 header.SetAuthorName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2353 header.SetCompanyName(
new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2354 writer.Model()->SetGlobalSection( header );
2356 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2368 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2374 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STEP;
2376 wxFileName fn( aFileName );
2378 STEPCAFControl_Writer writer;
2379 writer.SetColorMode( Standard_True );
2380 writer.SetNameMode( Standard_True );
2387 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2389 m_reporter->
Report(
_(
"Failed to set STEP product name, but will attempt to continue." ),
2395 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2397 m_reporter->
Report(
_(
"Failed to set surface curve mode, but will attempt to continue." ),
2401 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2404 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2408 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2411 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2412 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2413 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2414 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2416 bool success =
true;
2419 wxString currCWD = wxGetCwd();
2420 wxString workCWD = fn.GetPath();
2422 if( !workCWD.IsEmpty() )
2423 wxSetWorkingDirectory( workCWD );
2425 char tmpfname[] =
"$tempfile$.step";
2427 if( Standard_False == writer.Write( tmpfname ) )
2436 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2438 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2446 wxSetWorkingDirectory( currCWD );
2456 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
2462 m_outFmt = OUTPUT_FORMAT::FMT_OUT_BREP;
2465 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2470 wxFileName fn( aFileName );
2472 wxFFileOutputStream ffStream( fn.GetFullPath() );
2473 wxStdOutputStream stdStream( ffStream );
2475#if OCC_VERSION_HEX >= 0x070600
2476 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2478 BRepTools::Write( shape, stdStream );
2487 wxFileName fn( aFileName );
2489 wxFFileOutputStream ffStream( fn.GetFullPath() );
2490 wxStdOutputStream file( ffStream );
2492 if( !ffStream.IsOk() )
2494 m_reporter->
Report( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ),
2499 m_outFmt = OUTPUT_FORMAT::FMT_OUT_XAO;
2502 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2507 std::map<wxString, std::vector<int>> groups[4];
2508 std::map<wxString, double> groupAreas;
2509 TopExp_Explorer exp;
2512 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2514 TopoDS_Shape subShape = exp.Current();
2517 BRepBndLib::Add( subShape, bbox );
2521 for(
const auto& pair : pairs )
2523 const auto& [point, padTestShape] = pair;
2525 if( bbox.IsOut( point ) )
2528 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2530 if( surface.GetType() != GeomAbs_Plane )
2533 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2536 if( !dist.IsDone() )
2539 if( dist.Value() < Precision::Approximation() )
2542 groups[2][padKey].push_back( faceIndex );
2544 GProp_GProps system;
2545 BRepGProp::SurfaceProperties( subShape, system );
2547 double surfaceArea = system.Mass() / 1e6;
2548 groupAreas[padKey] += surfaceArea;
2557 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2558 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2559 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2560 file <<
" <shape format=\"BREP\"><![CDATA[";
2561#if OCC_VERSION_HEX < 0x070600
2562 BRepTools::Write( shape, file );
2564 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2566 file <<
"]]></shape>" << std::endl;
2567 file <<
" <topology>" << std::endl;
2569 TopTools_IndexedMapOfShape mainMap;
2570 TopExp::MapShapes( shape, mainMap );
2571 std::set<int> topo[4];
2573 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2576 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2577 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2579 for(
int dim = 0; dim < 4; dim++ )
2581 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2583 TopoDS_Shape subShape = exp.Current();
2584 int idx = mainMap.FindIndex( subShape );
2586 if( idx && !topo[dim].count( idx ) )
2587 topo[dim].insert( idx );
2591 for(
int dim = 0; dim <= 3; dim++ )
2593 std::string labels = c_dimLabels[dim];
2594 std::string label = c_dimLabel[dim];
2596 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2599 for(
auto p : topo[dim] )
2601 std::string
name(
"" );
2602 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2603 <<
"name=\"" <<
name <<
"\" "
2604 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2608 file <<
" </" << labels <<
">" << std::endl;
2611 file <<
" </topology>" << std::endl;
2612 file <<
" </geometry>" << std::endl;
2613 file <<
" <groups count=\""
2614 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2617 int groupNumber = 1;
2622 for(
int dim = 0; dim <= 3; dim++ )
2624 std::string label = c_dimLabel[dim];
2626 for(
auto g : groups[dim] )
2629 wxString
name = g.first;
2633 std::ostringstream gs;
2634 gs <<
"G_" << dim <<
"D_" << g.first;
2637 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2643 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2645 for(
auto index : g.second )
2646 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2648 file <<
" </group>" << std::endl;
2662 file <<
" </groups>" << std::endl;
2663 file <<
" <fields count=\"0\"/>" << std::endl;
2664 file <<
"</XAO>" << std::endl;
2671 bool aSubstituteModels, wxString* aErrorMessage )
2673 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2674 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2676 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2680 aLabel = mm->second;
2686 Handle( TDocStd_Document ) doc;
2687 m_app->NewDocument(
"MDTV-XCAF", doc );
2689 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2695 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2697 m_reporter->
Report( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2705 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2707 m_reporter->
Report( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2718 wxFFileInputStream ifile( fileName );
2719 wxFileName outFile( fileName );
2721 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2722 outFile.SetExt( wxT(
"step" ) );
2723 wxFileOffset size = ifile.GetLength();
2725 if( size == wxInvalidOffset )
2727 m_reporter->
Report( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2734 bool success =
false;
2735 wxFFileOutputStream ofile( outFile.GetFullPath() );
2740 char* buffer =
new char[size];
2742 ifile.Read( buffer, size );
2743 std::string expanded;
2747 expanded = gzip::decompress( buffer, size );
2752 m_reporter->
Report( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2757 if( expanded.empty() )
2761 wxZipInputStream izipfile( ifile );
2762 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2764 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2766 izipfile.Read( ofile );
2772 ofile.Write( expanded.data(), expanded.size() );
2780 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2800 if( aSubstituteModels )
2802 wxFileName wrlName( fileName );
2804 wxString basePath = wrlName.GetPath();
2805 wxString baseName = wrlName.GetName();
2813 alts.Add( wxT(
"stp" ) );
2814 alts.Add( wxT(
"step" ) );
2815 alts.Add( wxT(
"STP" ) );
2816 alts.Add( wxT(
"STEP" ) );
2817 alts.Add( wxT(
"Stp" ) );
2818 alts.Add( wxT(
"Step" ) );
2819 alts.Add( wxT(
"stpz" ) );
2820 alts.Add( wxT(
"stpZ" ) );
2821 alts.Add( wxT(
"STPZ" ) );
2822 alts.Add( wxT(
"step.gz" ) );
2823 alts.Add( wxT(
"stp.gz" ) );
2826 alts.Add( wxT(
"iges" ) );
2827 alts.Add( wxT(
"IGES" ) );
2828 alts.Add( wxT(
"igs" ) );
2829 alts.Add( wxT(
"IGS" ) );
2833 for(
const auto& alt : alts )
2835 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2837 if( altFile.IsOk() && altFile.FileExists() )
2839 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2857 if(
m_outFmt == OUTPUT_FORMAT::FMT_OUT_GLTF )
2859 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2861 Handle( XCAFDoc_ShapeTool ) shapeTool =
2862 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2865 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2869 m_reporter->
Report( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2879 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2889 m_reporter->
Report( wxString::Format(
_(
"Cannot identify actual file type for '%s'.\n" ),
2897 if( aLabel.IsNull() )
2899 m_reporter->
Report( wxString::Format(
_(
"Could not transfer model data from file '%s'.\n" ),
2907 wxFileName afile( fileName );
2908 std::string pname( afile.GetName().ToUTF8() );
2909 TCollection_ExtendedString partname( pname.c_str() );
2910 TDataStd_Name::Set( aLabel, partname );
2920 TopLoc_Location& aLocation )
2934 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2939 double boardThickness;
2942 double top = std::max( boardZPos, boardZPos + boardThickness );
2943 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2948 double f_pos, f_thickness;
2952 bottom += f_thickness;
2958 aOffset.
z -= bottom;
2959 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2960 lPos.Multiply( lRot );
2961 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
2962 lPos.Multiply( lRot );
2967 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2968 lPos.Multiply( lRot );
2972 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
2973 lPos.Multiply( lOff );
2976 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), -aOrientation.
z );
2977 lPos.Multiply( lOrient );
2978 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ), -aOrientation.
y );
2979 lPos.Multiply( lOrient );
2980 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), -aOrientation.
x );
2981 lPos.Multiply( lOrient );
2983 aLocation = TopLoc_Location( lPos );
2990 IGESControl_Controller::Init();
2991 IGESCAFControl_Reader reader;
2992 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2994 if( stat != IFSelect_RetDone )
2998 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3002 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3006 reader.SetColorMode(
true );
3007 reader.SetNameMode(
false );
3008 reader.SetLayerMode(
false );
3010 if( !reader.Transfer( doc ) )
3012 if( doc->CanClose() == CDM_CCS_OK )
3019 if( reader.NbShapes() < 1 )
3021 if( doc->CanClose() == CDM_CCS_OK )
3033 STEPCAFControl_Reader reader;
3034 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
3036 if( stat != IFSelect_RetDone )
3040 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
3044 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
3048 reader.SetColorMode(
true );
3049 reader.SetNameMode(
true );
3050 reader.SetLayerMode(
false );
3052 if( !reader.Transfer( doc ) )
3054 if( doc->CanClose() == CDM_CCS_OK )
3061 if( reader.NbRootsForTransfer() < 1 )
3063 if( doc->CanClose() == CDM_CCS_OK )
3075#if OCC_VERSION_HEX >= 0x070700
3076 VrmlAPI_CafReader reader;
3077 RWMesh_CoordinateSystemConverter conv;
3078 conv.SetInputLengthUnit( 2.54 );
3079 reader.SetCoordinateSystemConverter( conv );
3080 reader.SetDocument( doc );
3082 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
3093 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
3097 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
3100 TDF_LabelSequence frshapes;
3101 s_assy->GetFreeShapes( frshapes );
3104 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
3107 TDF_Label d_targetLabel = d_assy->NewShape();
3109 if( frshapes.Size() == 1 )
3111 TDocStd_XLinkTool link;
3112 link.Copy( d_targetLabel, frshapes.First() );
3117 for( TDF_Label& s_shapeLabel : frshapes )
3119 TDF_Label d_component = d_assy->NewShape();
3121 TDocStd_XLinkTool link;
3122 link.Copy( d_component, s_shapeLabel );
3124 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
3128 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
3131 return d_targetLabel;
3137 TDF_LabelSequence freeShapes;
3138 aShapeTool->GetFreeShapes( freeShapes );
3144 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3146 TDF_Label label = freeShapes.Value( i );
3148 aShapeTool->GetShape( label, shape );
3153 const Standard_Real linearDeflection = 0.14;
3154 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3155 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3167 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3173 m_outFmt = OUTPUT_FORMAT::FMT_OUT_GLTF;
3177 wxFileName fn( aFileName );
3179 const char* tmpGltfname =
"$tempfile$.glb";
3180 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3182 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3183 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3184 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3185 RWMesh_CoordinateSystem_Zup );
3186#if OCC_VERSION_HEX >= 0x070700
3187 cafWriter.SetParallel(
true );
3189 TColStd_IndexedDataMapOfStringString metadata;
3191 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3192 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3193 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3194 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3195 metadata.Add( TCollection_AsciiString(
"generator" ),
3196 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3197 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3200 bool success =
true;
3203 wxString currCWD = wxGetCwd();
3204 wxString workCWD = fn.GetPath();
3206 if( !workCWD.IsEmpty() )
3207 wxSetWorkingDirectory( workCWD );
3209 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3216 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3218 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3226 wxSetWorkingDirectory( currCWD );
3234#if OCC_VERSION_HEX < 0x070700
3241 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3247 m_outFmt = OUTPUT_FORMAT::FMT_OUT_PLY;
3251 wxFileName fn( aFileName );
3253 const char* tmpFname =
"$tempfile$.ply";
3254 RWPly_CafWriter cafWriter( tmpFname );
3256 cafWriter.SetFaceId(
true );
3257 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3258 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem( RWMesh_CoordinateSystem_Zup );
3260 TColStd_IndexedDataMapOfStringString metadata;
3262 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3263 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3264 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3265 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3266 metadata.Add( TCollection_AsciiString(
"generator" ),
3267 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
3269 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3272 bool success =
true;
3275 wxString currCWD = wxGetCwd();
3276 wxString workCWD = fn.GetPath();
3278 if( !workCWD.IsEmpty() )
3279 wxSetWorkingDirectory( workCWD );
3281 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3288 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3290 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3298 wxSetWorkingDirectory( currCWD );
3309 m_reporter->
Report( wxString::Format(
_(
"No valid PCB assembly; cannot create output file '%s'.\n" ),
3315 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STL;
3319 wxFileName fn( aFileName );
3321 const char* tmpFname =
"$tempfile$.stl";
3324 wxString currCWD = wxGetCwd();
3325 wxString workCWD = fn.GetPath();
3327 if( !workCWD.IsEmpty() )
3328 wxSetWorkingDirectory( workCWD );
3330 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
3337 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3339 m_reporter->
Report( wxString::Format(
_(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3347 wxSetWorkingDirectory( currCWD );
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
wxString GetNetname() const
const wxString & GetShortNetname() const
FOOTPRINT * GetParentFootprint() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
PAD_PROP GetProperty() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
const VECTOR2I & GetArcMid() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
const SHAPE_LINE_CHAIN Slice(int aStartIndex, int aEndIndex=-1) const
Return a subset of this line chain containing the [start_index, end_index] range of points.
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.
virtual size_t GetSegmentCount() const override
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int FullPointCount() const
Return the number of points in the shape poly set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
const POLYGON & CPolygon(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
const SEG & GetSeg() const
OUTPUT_FORMAT m_outFmt
The current output format for created file.
void SetCopperColor(double r, double g, double b)
bool isBoardOutlineValid()
std::vector< TopoDS_Shape > m_board_silkscreen
bool CreatePCB(SHAPE_POLY_SET &aOutline, VECTOR2D aOrigin, bool aPushBoardBody)
bool MakeShapeAsThickSegment(TopoDS_Shape &aShape, VECTOR2D aStartPoint, VECTOR2D aEndPoint, double aWidth, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Make a segment shape based on start and end point.
bool WritePLY(const wxString &aFileName)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_vias
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_pads
bool AddComponent(const std::string &aFileName, const std::string &aRefDes, bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels=true)
wxString m_pcbName
Name of the PCB, which will most likely be the file name of the path.
std::vector< TopoDS_Shape > m_boardCutouts
std::vector< TopoDS_Shape > m_board_soldermask
bool AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin, const wxString &aNetname)
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
void SetFuseShapes(bool aValue)
bool WriteXAO(const wxString &aFileName)
bool WriteGLTF(const wxString &aFileName)
Write the assembly in binary GLTF Format.
std::vector< TDF_Label > m_pcb_labels
STEP_PCB_MODEL(const wxString &aPcbName, REPORTER *aReporter)
void getLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_outlines
void SetSimplifyShapes(bool aValue)
bool readVRML(Handle(TDocStd_Document) &aDoc, const char *aFname)
void SetPadColor(double r, double g, double b)
void SetEnabledLayers(const LSET &aLayers)
bool performMeshing(Handle(XCAFDoc_ShapeTool) &aShapeTool)
bool MakePolygonAsWall(TopoDS_Shape &aShape, SHAPE_POLY_SET &aPolySet, double aHeight, double aZposition, const VECTOR2D &aOrigin)
Make a polygonal shape to create a vertical wall.
bool readSTEP(Handle(TDocStd_Document) &aDoc, const char *aFname)
Handle(XCAFApp_Application) m_app
bool getModelLocation(bool aBottom, VECTOR2D aPosition, double aRotation, VECTOR3D aOffset, VECTOR3D aOrientation, TopLoc_Location &aLocation)
virtual ~STEP_PCB_MODEL()
bool WriteSTL(const wxString &aFileName)
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper
bool MakeShapes(std::vector< TopoDS_Shape > &aShapes, const SHAPE_POLY_SET &aPolySet, bool aConvertToArcs, double aThickness, double aZposition, const VECTOR2D &aOrigin)
Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, const wxString &aNetname)
bool getModelLabel(const std::string &aFileNameUTF8, VECTOR3D aScale, TDF_Label &aLabel, bool aSubstituteModels, wxString *aErrorMessage=nullptr)
Load a 3D model data.
bool readIGES(Handle(TDocStd_Document) &aDoc, const char *aFname)
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin, bool aCutCopper, bool aCutBody)
bool WriteSTEP(const wxString &aFileName, bool aOptimize)
std::vector< TopoDS_Shape > m_copperCutouts
std::map< wxString, std::vector< std::pair< gp_Pnt, TopoDS_Shape > > > m_pad_points
void getCopperLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
TDF_Label transferModel(Handle(TDocStd_Document)&source, Handle(TDocStd_Document) &dest, VECTOR3D aScale)
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia, SHAPE_POLY_SET *aClipPolygon=nullptr)
std::map< wxString, std::vector< TopoDS_Shape > > m_board_copper_fused
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE ANGLE_360
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
wxString NotSpecifiedPrm()
static TopoDS_Shape fuseShapesOrCompound(const TopTools_ListOfShape &aInputShapes, REPORTER *aReporter)
static bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin, REPORTER *aReporter)
static Standard_Boolean prefixNames(const TDF_Label &aLabel, const TCollection_ExtendedString &aPrefix)
static Standard_Boolean rescaleShapes(const TDF_Label &theLabel, const gp_XYZ &aScale)
static constexpr double BOARD_OFFSET
static wxString formatBBox(const BOX2I &aBBox)
static bool fuseShapes(auto &aInputShapes, TopoDS_Shape &aOutShape, REPORTER *aReporter)
static TopoDS_Compound makeCompound(const auto &aInputShapes)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
static SHAPE_LINE_CHAIN approximateLineChainWithArcs(const SHAPE_LINE_CHAIN &aSrc)
static constexpr double USER_ANGLE_PREC
static constexpr double USER_PREC
static TopoDS_Shape getOneShape(Handle(XCAFDoc_ShapeTool) aShapeTool)
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS
Default distance between points to treat them as separate ones (mm) 0.001 mm or less is a reasonable ...
std::pair< std::string, TDF_Label > MODEL_DATUM
static constexpr double ARC_TO_SEGMENT_MAX_ERROR_MM
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
constexpr double IUTomm(int iu) const
constexpr int mmToIU(double mm) const
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
VECTOR2< int32_t > VECTOR2I
VECTOR3< double > VECTOR3D