31#include <wx/filename.h>
33#include <wx/stdpaths.h>
34#include <wx/wfstream.h>
35#include <wx/zipstrm.h>
36#include <wx/stdstream.h>
38#include <decompress.hpp>
54#include <IGESCAFControl_Reader.hxx>
55#include <IGESCAFControl_Writer.hxx>
56#include <IGESControl_Controller.hxx>
57#include <IGESData_GlobalSection.hxx>
58#include <IGESData_IGESModel.hxx>
59#include <Interface_Static.hxx>
60#include <Quantity_Color.hxx>
61#include <STEPCAFControl_Reader.hxx>
62#include <STEPCAFControl_Writer.hxx>
63#include <APIHeaderSection_MakeHeader.hxx>
64#include <Standard_Failure.hxx>
65#include <Standard_Handle.hxx>
66#include <Standard_Version.hxx>
67#include <TCollection_ExtendedString.hxx>
68#include <TDocStd_Document.hxx>
69#include <TDocStd_XLinkTool.hxx>
70#include <TDataStd_Name.hxx>
71#include <TDataStd_TreeNode.hxx>
72#include <TDF_LabelSequence.hxx>
73#include <TDF_Tool.hxx>
74#include <TopExp_Explorer.hxx>
76#include <XCAFApp_Application.hxx>
78#include <XCAFDoc_DocumentTool.hxx>
79#include <XCAFDoc_ColorTool.hxx>
80#include <XCAFDoc_ShapeTool.hxx>
81#include <XCAFDoc_VisMaterialTool.hxx>
82#include <XCAFDoc_Area.hxx>
83#include <XCAFDoc_Centroid.hxx>
84#include <XCAFDoc_Location.hxx>
85#include <XCAFDoc_Volume.hxx>
87#include "KI_XCAFDoc_AssemblyGraph.hxx"
89#include <BRep_Tool.hxx>
90#include <BRepMesh_IncrementalMesh.hxx>
91#include <BRepBuilderAPI_GTransform.hxx>
92#include <BRepBuilderAPI_MakeEdge.hxx>
93#include <BRepBuilderAPI_MakeWire.hxx>
94#include <BRepBuilderAPI_MakeFace.hxx>
95#include <BRepExtrema_DistShapeShape.hxx>
96#include <BRepPrimAPI_MakePrism.hxx>
97#include <BRepTools.hxx>
98#include <BRepLib_MakeWire.hxx>
99#include <BRepAdaptor_Surface.hxx>
100#include <BRepAlgoAPI_Check.hxx>
101#include <BRepAlgoAPI_Cut.hxx>
102#include <BRepAlgoAPI_Fuse.hxx>
103#include <ShapeUpgrade_UnifySameDomain.hxx>
105#include <BRepBndLib.hxx>
106#include <Bnd_BoundSortBox.hxx>
107#include <GProp_GProps.hxx>
108#include <BRepGProp.hxx>
110#include <Geom_Curve.hxx>
111#include <Geom_TrimmedCurve.hxx>
116#include <GC_MakeArcOfCircle.hxx>
117#include <GC_MakeCircle.hxx>
119#include <RWGltf_CafWriter.hxx>
120#include <StlAPI_Writer.hxx>
122#if OCC_VERSION_HEX >= 0x070700
123#include <VrmlAPI_CafReader.hxx>
124#include <RWPly_CafWriter.hxx>
152 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
154 if( !lfile.FileExists() )
157 msg.Printf( wxT(
" * fileType(): no such file: %s\n" ),
158 wxString::FromUTF8Unchecked( aFileName ) );
164 wxString ext = lfile.GetExt().Lower();
166 if( ext == wxT(
"wrl" ) )
169 if( ext == wxT(
"wrz" ) )
172 if( ext == wxT(
"idf" ) )
175 if( ext == wxT(
"emn" ) )
178 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
192 const int max_line_count = 3;
194 for(
int ii = 0; ii < max_line_count; ii++ )
196 memset( iline, 0, 82 );
197 ifile.getline( iline, 82 );
203 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
209 std::string fstr = iline;
213 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
222 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
229 if( strncmp( iline,
"/*", 2 ) != 0 )
247 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
248 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
249 double det = -b.
x * d.
y + d.
x * b.
y;
253 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
254 center.
y = ( b.
x * cd + d.
x * bc ) * det;
261#define APPROX_DBG( stmt )
269 static const double c_radiusDeviation = 1000.0;
270 static const double c_arcCenterDeviation = 1000.0;
271 static const double c_relLengthDeviation = 0.8;
272 static const int c_last_none = -1000;
292 int last = c_last_none;
298 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
300 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
305 bool defective =
false;
311 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
319 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
320 defective |=
std::abs( a_diff ) < 0.1;
323 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
324 defective |=
std::abs( a_diff ) >= maxAngleDiff;
335 for(
int j = i; j <= jEndIdx; j++ )
340 double rad_test = ( p_test -
center ).EuclideanNorm();
341 double d_tl = ( p_test - p_prev ).EuclideanNorm();
345 << int64_t( rad_test ) <<
" ref " << int64_t(
radius )
348 if( rad_dev > c_radiusDeviation )
351 <<
" Radius deviation too large: " << int64_t( rad_dev )
352 <<
" > " << c_radiusDeviation << std::endl );
357 double maxAngleDiff =
358 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
360 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
361 if(
std::abs( a_diff_test ) >= maxAngleDiff )
363 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
368 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
370 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
371 <<
"; " << d01 << std::endl );
381 if( last != c_last_none )
390 int toRemove = last - ( aSrc.
PointCount() - 3 );
420 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
424 if( last == c_last_none )
441 if( iarc0 != -1 && iarc1 != -1 )
443 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
453 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
471 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
472 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
488static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
490 TDF_LabelSequence theLabels;
491 aShapeTool->GetFreeShapes( theLabels );
495 if( theLabels.Length() == 1 )
496 return aShapeTool->GetShape( theLabels.Value( 1 ) );
498 TopoDS_Compound aCompound;
499 BRep_Builder aBuilder;
500 aBuilder.MakeCompound( aCompound );
502 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
504 TopoDS_Shape aFreeShape;
506 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
509 aBuilder.Add( aCompound, aFreeShape );
512 if( aCompound.NbChildren() > 0 )
521static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
523 if( theLabel.IsNull() )
525 Message::SendFail(
"Null label." );
526 return Standard_False;
529 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
530 || Abs( aScale.Z() ) <= gp::Resolution() )
532 Message::SendFail(
"Scale factor is too small." );
533 return Standard_False;
536 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
537 if( aShapeTool.IsNull() )
539 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
540 return Standard_False;
543 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
546 Message::SendFail(
"Couldn't create assembly graph." );
547 return Standard_False;
550 Standard_Boolean anIsDone = Standard_True;
554 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
556 0, 0, aScale.Z() ) );
559 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
561 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
563 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
565 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
566 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
571 const TDF_Label& aLabel = aG->GetNode( idx );
573 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
575 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
576 aBRepTrsf.Perform( aShape, Standard_True );
577 if( !aBRepTrsf.IsDone() )
579 Standard_SStream aSS;
580 TCollection_AsciiString anEntry;
581 TDF_Tool::Entry( aLabel, anEntry );
582 aSS <<
"Shape " << anEntry <<
" is not scaled!";
583 Message::SendFail( aSS.str().c_str() );
584 anIsDone = Standard_False;
585 return Standard_False;
587 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
588 aShapeTool->SetShape( aLabel, aScaledShape );
591 TDF_LabelSequence aSubshapes;
592 aShapeTool->GetSubShapes( aLabel, aSubshapes );
593 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
595 const TDF_Label& aLSs = anItSs.Value();
596 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
597 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
598 aShapeTool->SetShape( aLSs, aSs1 );
602 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
603 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
604 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
606 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
608 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
609 gp_Trsf aTrsf = aLoc.Transformation();
610 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
611 XCAFDoc_Location::Set( aLabel, aTrsf );
617 return Standard_False;
620 aShapeTool->UpdateAssemblies();
626static bool fuseShapes(
auto& aInputShapes, TopoDS_Shape& aOutShape )
628 BRepAlgoAPI_Fuse mkFuse;
629 TopTools_ListOfShape shapeArguments, shapeTools;
631 for( TopoDS_Shape& sh : aInputShapes )
636 if( shapeArguments.IsEmpty() )
637 shapeArguments.Append( sh );
639 shapeTools.Append( sh );
642 mkFuse.SetRunParallel(
true );
643 mkFuse.SetToFillHistory(
false );
644 mkFuse.SetArguments( shapeArguments );
645 mkFuse.SetTools( shapeTools );
648 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
652 if( mkFuse.HasErrors() )
655 mkFuse.DumpErrors( std::cout );
658 if( mkFuse.HasWarnings() )
661 mkFuse.DumpWarnings( std::cout );
667 if( mkFuse.IsDone() )
669 TopoDS_Shape fusedShape = mkFuse.Shape();
671 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
672 unify.History() =
nullptr;
675 TopoDS_Shape unifiedShapes = unify.Shape();
677 if( unifiedShapes.IsNull() )
679 ReportMessage(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) );
683 aOutShape = unifiedShapes;
694 TopoDS_Compound compound;
695 BRep_Builder builder;
696 builder.MakeCompound( compound );
698 for( TopoDS_Shape& shape : aInputShapes )
699 builder.Add( compound, shape );
708 TopoDS_Shape outShape;
710 if( aInputShapes.Size() == 1 )
711 return aInputShapes.First();
722 const TCollection_ExtendedString& aPrefix )
724 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
728 Message::SendFail(
"Couldn't create assembly graph." );
729 return Standard_False;
732 Standard_Boolean anIsDone = Standard_True;
734 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
736 const TDF_Label& lbl = aG->GetNode( idx );
737 Handle( TDataStd_Name ) nameHandle;
739 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
741 TCollection_ExtendedString
name;
745 name += nameHandle->Get();
748 TDataStd_Name::Set( lbl,
name );
752 TDataStd_Name::Set( lbl, aPrefix );
762 m_app = XCAFApp_Application::GetApplication();
763 m_app->NewDocument(
"MDTV-XCAF", m_doc );
764 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
776 m_outFmt = OUTPUT_FORMAT::FMT_OUT_UNKNOWN;
782 if( m_doc->CanClose() == CDM_CCS_OK )
791 std::vector<TopoDS_Shape> padShapes;
792 bool castellated = aClipPolygon && aPad->
GetProperty() == PAD_PROP::CASTELLATED;
805 double Zpos, thickness;
811 if( pcb_layer ==
F_Cu )
813 else if( pcb_layer ==
B_Cu )
817 TopoDS_Shape testShape;
831 if( testShape.IsNull() )
833 std::vector<TopoDS_Shape> testShapes;
837 if( testShapes.size() > 0 )
838 testShape = testShapes.front();
841 if( !aVia && !testShape.IsNull() )
843 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
849 if( pcb_layer ==
F_Cu )
851 else if( pcb_layer ==
B_Cu )
868 double f_pos, f_thickness;
869 double b_pos, b_thickness;
872 double top = std::max( f_pos, f_pos + f_thickness );
873 double bottom = std::min( b_pos, b_pos + b_thickness );
874 double hole_height = top - bottom;
876 TopoDS_Shape plating;
884 hole_height, bottom, aOrigin ) )
886 padShapes.push_back( plating );
900 if( seg_hole->GetSeg().A == seg_hole->GetSeg().B )
909 seg_hole->GetSeg().A, seg_hole->GetSeg().B,
918 padShapes.push_back( plating );
928 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
933 TopTools_ListOfShape padShapesList;
935 for(
const TopoDS_Shape& shape : padShapes )
936 padShapesList.Append( shape );
942 for(
const TopoDS_Shape& shape : padShapes )
952 const VECTOR2D& aOrigin,
bool aCutCopper,
bool aCutBody )
954 double margin = 0.001;
962 double f_pos, f_thickness;
963 double b_pos, b_thickness;
966 double top = std::max( f_pos, f_pos + f_thickness );
967 double bottom = std::min( b_pos, b_pos + b_thickness );
969 double holeZsize = ( top - bottom ) + ( margin * 2 );
971 double boardDrill = aShape.
GetWidth();
972 double copperDrill = boardDrill - aPlatingThickness * 2;
974 TopoDS_Shape copperHole, boardHole;
979 holeZsize, bottom - margin, aOrigin ) )
992 holeZsize, bottom - margin, aOrigin ) )
1009 double f_pos, f_thickness;
1010 double b_pos, b_thickness;
1013 double top = std::max( f_pos, f_pos + f_thickness );
1014 double bottom = std::min( b_pos, b_pos + b_thickness );
1016 TopoDS_Shape plating;
1019 ( top - bottom ), bottom, aOrigin ) )
1034 double& aThickness )
1037 static const double c_silkscreenAboveCopper = 0.04;
1038 static const double c_soldermaskAboveCopper = 0.015;
1046 double f_pos, f_thickness;
1048 double top = std::max( f_pos, f_pos + f_thickness );
1051 aZPos = top + c_silkscreenAboveCopper;
1053 aZPos = top + c_soldermaskAboveCopper;
1059 double b_pos, b_thickness;
1061 double bottom = std::min( b_pos, b_pos + b_thickness );
1064 aZPos = bottom - c_silkscreenAboveCopper;
1066 aZPos = bottom - c_soldermaskAboveCopper;
1074 double& aThickness )
1078 bool wasPrepreg =
false;
1083 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1089 if( aLayer ==
B_Cu )
1134 double f_pos, f_thickness;
1135 double b_pos, b_thickness;
1138 double top = std::min( f_pos, f_pos + f_thickness );
1139 double bottom = std::max( b_pos, b_pos + b_thickness );
1141 aThickness = ( top - bottom );
1144 wxASSERT( aZPos == 0.0 );
1151 bool success =
true;
1159 double z_pos, thickness;
1170 wxString::Format( wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
1184 if( aFileNameUTF8.empty() )
1186 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
1190 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1191 ReportMessage( wxString::Format( wxT(
"Adding component %s.\n" ), aRefDes ) );
1195 wxString errorMessage;
1197 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1199 if( errorMessage.IsEmpty() )
1200 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
1208 TopLoc_Location toploc;
1210 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1213 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
1218 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1220 if( llabel.IsNull() )
1222 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
1228 TCollection_ExtendedString refdes( aRefDes.c_str() );
1229 TDataStd_Name::Set( llabel, refdes );
1296 double aWidth,
double aThickness,
1297 double aZposition,
const VECTOR2D& aOrigin )
1304 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1305 double h_width = aWidth/2.0;
1307 coords[0] =
VECTOR2D{ 0.0, h_width };
1310 coords[1] =
VECTOR2D{ len, h_width };
1313 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1316 coords[3] =
VECTOR2D{ len, -h_width };
1319 coords[4] =
VECTOR2D{ 0, -h_width };
1322 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1325 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1327 for(
int ii = 0; ii < 6; ii++ )
1330 coords[ii] += aStartPoint;
1335 gp_Pnt coords3D[ 6 ];
1337 for(
int ii = 0; ii < 6; ii++ )
1344 BRepBuilderAPI_MakeWire wire;
1345 bool success =
true;
1357 Handle( Geom_Circle )
circle = GC_MakeCircle( coords3D[1],
1362 edge = BRepBuilderAPI_MakeEdge(
circle );
1367 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1370 Handle( Geom_TrimmedCurve ) arcOfCircle =
1371 GC_MakeArcOfCircle( coords3D[1],
1375 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1378 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1381 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1382 GC_MakeArcOfCircle( coords3D[4],
1386 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1390 catch(
const Standard_Failure& e )
1392 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
1393 e.GetMessageString() ) );
1397 BRepBuilderAPI_MakeFace face;
1401 gp_Pln plane( coords3D[0], gp::DZ() );
1402 face = BRepBuilderAPI_MakeFace( plane, wire );
1404 catch(
const Standard_Failure& e )
1406 ReportMessage( wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
1407 e.GetMessageString() ) );
1411 if( aThickness != 0.0 )
1413 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1415 if( aShape.IsNull() )
1417 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
1433 double aZposition,
const VECTOR2D& aOrigin )
1435 std::vector<TopoDS_Shape> testShapes;
1438 aHeight, aZposition, aOrigin );
1440 if( testShapes.size() > 0 )
1441 aShape = testShapes.front();
1464 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin )
1466 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1479 gp_Pnt start = toPoint( aPt0 );
1480 gp_Pnt
end = toPoint( aPt1 );
1482 BRepBuilderAPI_MakeEdge mkEdge( start,
end );
1484 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1486 ReportMessage( wxString::Format( wxT(
"failed to make segment edge at (%d "
1487 "%d) -> (%d %d), skipping\n" ),
1488 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1492 aMkWire.Add( mkEdge.Edge() );
1494 if( aMkWire.Error() != BRepLib_WireDone )
1496 ReportMessage( wxString::Format( wxT(
"failed to add segment edge "
1497 "at (%d %d) -> (%d %d)\n" ),
1498 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1509 Handle( Geom_Curve ) curve;
1511 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1513 gp_Ax2 axis = gp::XOY();
1514 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1516 curve = GC_MakeCircle( axis,
pcbIUScale.
IUTomm( aArc.GetRadius() ) ).Value();
1520 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1521 toPoint( aArc.GetP1() ) )
1525 if( curve.IsNull() )
1528 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1530 if( !aMkWire.IsDone() )
1533 wxT(
"failed to add arc curve from (%d %d), arc p0 "
1534 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1535 aPt0.
x, aPt0.
y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x,
1536 aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) );
1545 bool isFirstShape =
true;
1558 if( nextShape != -1 )
1564 lastPt = aChain.
CPoint( i );
1574 firstPt = currentArc.
GetP0();
1579 lastPt = currentArc.
GetP0();
1581 if( addArc( lastPt, currentArc ) )
1582 lastPt = currentArc.
GetP1();
1601 isFirstShape =
false;
1604 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1607 wxString::Format( wxT(
"** Failed to close wire at %d, %d -> %d, %d **\n" ),
1608 lastPt.
x, lastPt.
y, firstPt.
x, firstPt.
y ) );
1613 catch(
const Standard_Failure& e )
1615 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
1616 e.GetMessageString() ) );
1625 bool aConvertToArcs,
1626 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
1633 if( aConvertToArcs )
1637 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1641 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1644 polygon[contId] = approxChain;
1648 fallbackPoly = workingPoly;
1649 workingPoly = approximated;
1668 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1675 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1676 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1678 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1682 auto tryMakeWire = [
this, &aZposition,
1686 BRepLib_MakeWire mkWire;
1690 if( mkWire.IsDone() )
1692 wire = mkWire.Wire();
1697 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n" ),
1698 static_cast<int>( aContour.PointCount() ),
1699 static_cast<int>( mkWire.Error() ) ) );
1701 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1705 if( !wire.IsNull() )
1707 BRepAlgoAPI_Check check( wire,
false,
true );
1709 if( !check.IsValid() )
1711 ReportMessage( wxString::Format(
_(
"\nWire self-interference check "
1714 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1724 BRepBuilderAPI_MakeFace mkFace;
1726 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1730 TopoDS_Wire wire = tryMakeWire( polygon[contId] );
1732 if( aConvertToArcs && wire.IsNull() )
1734 ReportMessage( wxString::Format(
_(
"Using non-simplified polygon.\n" ) ) );
1737 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId] );
1742 if( !wire.IsNull() )
1744 if( basePlane.Axis().Direction().Z() < 0 )
1747 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1751 ReportMessage( wxString::Format( wxT(
"\n** Outline skipped **\n" ) ) );
1753 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1762 if( !wire.IsNull() )
1764 if( basePlane.Axis().Direction().Z() > 0 )
1771 ReportMessage( wxString::Format( wxT(
"\n** Hole skipped **\n" ) ) );
1773 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1779 catch(
const Standard_Failure& e )
1782 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
1783 static_cast<int>( contId ), e.GetMessageString() ) );
1788 if( mkFace.IsDone() )
1790 TopoDS_Shape faceShape = mkFace.Shape();
1792 if( aThickness != 0.0 )
1794 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1795 aShapes.push_back( prism );
1797 if( prism.IsNull() )
1805 aShapes.push_back( faceShape );
1810 ReportMessage( wxString::Format(
_(
"** Face skipped **\n" ) ) );
1821 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1822 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1823 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1824 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1825 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1826 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1827 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1828 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1838 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1840 aColorOut =
COLOR4D( aColorStr );
1845 const std::vector<FAB_LAYER_COLOR>& colors =
1852 if( fabColor.GetName() == aColorStr )
1854 aColorOut = fabColor.GetColor( aType );
1874 Handle( XCAFDoc_VisMaterialTool ) visMatTool =
1875 XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1880 ReportMessage( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1883 double boardThickness;
1898 wxT(
"OCC error creating main outline.\n" ) ) );
1904 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1908 polyset.
Append( contour );
1915 ReportMessage( wxT(
"OCC error creating main outline.\n" ) );
1923 ReportMessage( wxT(
"OCC error creating hole in main outline.\n" ) );
1934 BRepBndLib::Add( brdShape, brdBndBox );
1937 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1940 auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1944 Bnd_Box brdWithHolesBndBox = brdBndBox;
1946 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1948 for(
size_t i = 0; i < input.size(); i++ )
1951 BRepBndLib::Add( input[i], bbox );
1952 brdWithHolesBndBox.Add( bbox );
1953 ( *holeBoxSet )[i] = bbox;
1956 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1959 auto subtractShapes = [](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
1960 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
1964 for( TopoDS_Shape& shape : aShapesList )
1967 BRepBndLib::Add( shape, shapeBbox );
1969 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
1971 TopTools_ListOfShape holelist;
1973 for(
const Standard_Integer& index : indices )
1974 holelist.Append( aHolesList[index] );
1977 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
1983 (
int) aShapesList.size(), aWhat ) );
1985 if( holelist.IsEmpty() )
1988 TopTools_ListOfShape cutArgs;
1989 cutArgs.Append( shape );
1991 BRepAlgoAPI_Cut
cut;
1993 cut.SetRunParallel(
true );
1994 cut.SetToFillHistory(
false );
1996 cut.SetArguments( cutArgs );
1997 cut.SetTools( holelist );
2000 if(
cut.HasErrors() ||
cut.HasWarnings() )
2003 _(
"\n** Got problems while cutting %s number %d **\n" ), aWhat, cnt ) );
2006 if(
cut.HasErrors() )
2009 cut.DumpErrors( std::cout );
2012 if(
cut.HasWarnings() )
2015 cut.DumpWarnings( std::cout );
2021 shape =
cut.Shape();
2027 Bnd_BoundSortBox bsbHoles;
2035 Bnd_BoundSortBox bsbHoles;
2046 TopTools_ListOfShape shapesToFuse;
2049 shapesToFuse.Append( shape );
2052 shapesToFuse.Append( shape );
2055 shapesToFuse.Append( shape );
2059 if( !fusedShape.IsNull() )
2079 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_ColorRGBA aColor,
2080 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
2083 if( aShapesList.empty() )
2086 std::vector<TopoDS_Shape> newList;
2091 newList = aShapesList;
2094 for( TopoDS_Shape& shape : newList )
2096 Handle( TDataStd_TreeNode ) node;
2099 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2105 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2106 TDF_Label shpLbl = node->Father()->Label();
2107 if( !shpLbl.IsNull() )
2109 if( visMatTool && !aVisMatLabel.IsNull() )
2110 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2114 if( newList.size() > 1 )
2116 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
2120 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
2124 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2125 TDataStd_Name::Set( shpLbl, partname );
2132 auto makeMaterial = [&](
const TCollection_AsciiString& aName,
2133 const Quantity_ColorRGBA& aBaseColor,
double aMetallic,
2134 double aRoughness ) -> TDF_Label
2136 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2137 XCAFDoc_VisMaterialPBR pbr;
2138 pbr.BaseColor = aBaseColor;
2139 pbr.Metallic = aMetallic;
2140 pbr.Roughness = aRoughness;
2141 vismat->SetPbrMaterial( pbr );
2142 return visMatTool->AddMaterial( vismat, aName );
2149 Quantity_ColorRGBA board_color( 0.3f, 0.3f, 0.3f, 1.0f );
2150 Quantity_ColorRGBA silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2151 Quantity_ColorRGBA mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2161 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2164 mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2167 if( item->GetBrdLayerId() ==
F_SilkS || item->GetBrdLayerId() ==
B_SilkS )
2168 silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2171 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2176 board_color = mask_color;
2177 board_color.SetAlpha( 1.0 );
2180 TDF_Label mask_mat = makeMaterial(
"soldermask", mask_color, 0.0, 0.6 );
2181 TDF_Label silk_mat = makeMaterial(
"silkscreen", silk_color, 0.0, 0.9 );
2182 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2183 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2184 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2186 pushToAssembly(
m_board_copper, copper_color, copper_mat,
"copper",
true );
2193 if( aPushBoardBody )
2196#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2197 m_assy->UpdateAssemblies();
2206bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2210 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2216 m_outFmt = OUTPUT_FORMAT::FMT_OUT_IGES;
2218 wxFileName fn( aFileName );
2219 IGESControl_Controller::Init();
2220 IGESCAFControl_Writer writer;
2221 writer.SetColorMode( Standard_True );
2222 writer.SetNameMode( Standard_True );
2223 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2224 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2225 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2226 header.SetAuthorName(
2227 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2228 header.SetCompanyName(
2229 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2230 writer.Model()->SetGlobalSection( header );
2232 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2244 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2250 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STEP;
2252 wxFileName fn( aFileName );
2254 STEPCAFControl_Writer writer;
2255 writer.SetColorMode( Standard_True );
2256 writer.SetNameMode( Standard_True );
2263 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2264 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
2268 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2269 ReportMessage( wxT(
"Failed to set surface curve mode, but will attempt to continue." ) );
2271 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2274 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2278 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2281 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2282 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2283 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2284 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2286 bool success =
true;
2289 wxString currCWD = wxGetCwd();
2290 wxString workCWD = fn.GetPath();
2292 if( !workCWD.IsEmpty() )
2293 wxSetWorkingDirectory( workCWD );
2295 char tmpfname[] =
"$tempfile$.step";
2297 if( Standard_False == writer.Write( tmpfname ) )
2306 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2308 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2310 fn.GetFullName() ) );
2315 wxSetWorkingDirectory( currCWD );
2325 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2331 m_outFmt = OUTPUT_FORMAT::FMT_OUT_BREP;
2334 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2339 wxFileName fn( aFileName );
2341 wxFFileOutputStream ffStream( fn.GetFullPath() );
2342 wxStdOutputStream stdStream( ffStream );
2344#if OCC_VERSION_HEX >= 0x070600
2345 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2347 BRepTools::Write( shape, stdStream );
2356 wxFileName fn( aFileName );
2358 wxFFileOutputStream ffStream( fn.GetFullPath() );
2359 wxStdOutputStream file( ffStream );
2361 if( !ffStream.IsOk() )
2363 ReportMessage( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ) );
2367 m_outFmt = OUTPUT_FORMAT::FMT_OUT_XAO;
2370 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2375 std::map<wxString, std::vector<int>> groups[4];
2376 std::map<wxString, double> groupAreas;
2377 TopExp_Explorer exp;
2380 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2382 TopoDS_Shape subShape = exp.Current();
2385 BRepBndLib::Add( subShape, bbox );
2389 const auto& [point, padTestShape] = pair;
2391 if( bbox.IsOut( point ) )
2394 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2396 if( surface.GetType() != GeomAbs_Plane )
2399 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2402 if( !dist.IsDone() )
2405 if( dist.Value() < Precision::Approximation() )
2408 groups[2][padKey].push_back( faceIndex );
2410 GProp_GProps system;
2411 BRepGProp::SurfaceProperties( subShape, system );
2413 double surfaceArea = system.Mass() / 1e6;
2414 groupAreas[padKey] = surfaceArea;
2422 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2423 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2424 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2425 file <<
" <shape format=\"BREP\"><![CDATA[";
2426#if OCC_VERSION_HEX < 0x070600
2427 BRepTools::Write( shape, file );
2429 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2431 file <<
"]]></shape>" << std::endl;
2432 file <<
" <topology>" << std::endl;
2434 TopTools_IndexedMapOfShape mainMap;
2435 TopExp::MapShapes( shape, mainMap );
2436 std::set<int> topo[4];
2438 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2441 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2442 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2444 for(
int dim = 0; dim < 4; dim++ )
2446 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2448 TopoDS_Shape subShape = exp.Current();
2449 int idx = mainMap.FindIndex( subShape );
2451 if( idx && !topo[dim].count( idx ) )
2452 topo[dim].insert( idx );
2456 for(
int dim = 0; dim <= 3; dim++ )
2458 std::string labels = c_dimLabels[dim];
2459 std::string label = c_dimLabel[dim];
2461 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2464 for(
auto p : topo[dim] )
2466 std::string
name(
"" );
2467 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2468 <<
"name=\"" <<
name <<
"\" "
2469 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2473 file <<
" </" << labels <<
">" << std::endl;
2476 file <<
" </topology>" << std::endl;
2477 file <<
" </geometry>" << std::endl;
2478 file <<
" <groups count=\""
2479 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2482 int groupNumber = 1;
2487 for(
int dim = 0; dim <= 3; dim++ )
2489 std::string label = c_dimLabel[dim];
2491 for(
auto g : groups[dim] )
2494 wxString
name = g.first;
2498 std::ostringstream gs;
2499 gs <<
"G_" << dim <<
"D_" << g.first;
2502 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2508 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2509 for(
auto index : g.second )
2511 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2513 file <<
" </group>" << std::endl;
2523 file <<
" </groups>" << std::endl;
2524 file <<
" <fields count=\"0\"/>" << std::endl;
2525 file <<
"</XAO>" << std::endl;
2532 bool aSubstituteModels, wxString* aErrorMessage )
2534 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2535 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2537 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2541 aLabel = mm->second;
2547 Handle( TDocStd_Document ) doc;
2548 m_app->NewDocument(
"MDTV-XCAF", doc );
2550 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2556 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2558 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2565 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2567 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2577 wxFFileInputStream ifile( fileName );
2578 wxFileName outFile( fileName );
2580 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2581 outFile.SetExt( wxT(
"step" ) );
2582 wxFileOffset size = ifile.GetLength();
2584 if( size == wxInvalidOffset )
2586 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2592 bool success =
false;
2593 wxFFileOutputStream ofile( outFile.GetFullPath() );
2598 char* buffer =
new char[size];
2600 ifile.Read( buffer, size );
2601 std::string expanded;
2605 expanded = gzip::decompress( buffer, size );
2610 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2614 if( expanded.empty() )
2618 wxZipInputStream izipfile( ifile );
2619 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2621 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2623 izipfile.Read( ofile );
2629 ofile.Write( expanded.data(), expanded.size() );
2637 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2658 if( aSubstituteModels )
2660 wxFileName wrlName( fileName );
2662 wxString basePath = wrlName.GetPath();
2663 wxString baseName = wrlName.GetName();
2671 alts.Add( wxT(
"stp" ) );
2672 alts.Add( wxT(
"step" ) );
2673 alts.Add( wxT(
"STP" ) );
2674 alts.Add( wxT(
"STEP" ) );
2675 alts.Add( wxT(
"Stp" ) );
2676 alts.Add( wxT(
"Step" ) );
2677 alts.Add( wxT(
"stpz" ) );
2678 alts.Add( wxT(
"stpZ" ) );
2679 alts.Add( wxT(
"STPZ" ) );
2680 alts.Add( wxT(
"step.gz" ) );
2681 alts.Add( wxT(
"stp.gz" ) );
2684 alts.Add( wxT(
"iges" ) );
2685 alts.Add( wxT(
"IGES" ) );
2686 alts.Add( wxT(
"igs" ) );
2687 alts.Add( wxT(
"IGS" ) );
2691 for(
const auto& alt : alts )
2693 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2695 if( altFile.IsOk() && altFile.FileExists() )
2697 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2715 if(
m_outFmt == OUTPUT_FORMAT::FMT_OUT_GLTF )
2717 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2719 Handle( XCAFDoc_ShapeTool ) shapeTool =
2720 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2723 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2727 ReportMessage( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2736 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2746 ReportMessage( wxString::Format( wxT(
"Cannot identify actual file type for '%s'.\n" ),
2753 if( aLabel.IsNull() )
2755 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
2762 wxFileName afile( fileName );
2763 std::string pname( afile.GetName().ToUTF8() );
2764 TCollection_ExtendedString partname( pname.c_str() );
2765 TDataStd_Name::Set( aLabel, partname );
2774 TopLoc_Location& aLocation )
2788 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2793 double boardThickness;
2796 double top = std::max( boardZPos, boardZPos + boardThickness );
2797 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2802 double f_pos, f_thickness;
2806 bottom += f_thickness;
2812 aOffset.
z -= bottom;
2813 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2814 lPos.Multiply( lRot );
2815 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
2816 lPos.Multiply( lRot );
2821 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2822 lPos.Multiply( lRot );
2826 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
2827 lPos.Multiply( lOff );
2830 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
2832 lPos.Multiply( lOrient );
2833 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
2835 lPos.Multiply( lOrient );
2836 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
2838 lPos.Multiply( lOrient );
2840 aLocation = TopLoc_Location( lPos );
2847 IGESControl_Controller::Init();
2848 IGESCAFControl_Reader reader;
2849 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2851 if( stat != IFSelect_RetDone )
2855 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2859 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2863 reader.SetColorMode(
true );
2864 reader.SetNameMode(
false );
2865 reader.SetLayerMode(
false );
2867 if( !reader.Transfer( doc ) )
2869 if( doc->CanClose() == CDM_CCS_OK )
2876 if( reader.NbShapes() < 1 )
2878 if( doc->CanClose() == CDM_CCS_OK )
2890 STEPCAFControl_Reader reader;
2891 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2893 if( stat != IFSelect_RetDone )
2897 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2901 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2905 reader.SetColorMode(
true );
2906 reader.SetNameMode(
true );
2907 reader.SetLayerMode(
false );
2909 if( !reader.Transfer( doc ) )
2911 if( doc->CanClose() == CDM_CCS_OK )
2918 if( reader.NbRootsForTransfer() < 1 )
2920 if( doc->CanClose() == CDM_CCS_OK )
2932#if OCC_VERSION_HEX >= 0x070700
2933 VrmlAPI_CafReader reader;
2934 RWMesh_CoordinateSystemConverter conv;
2935 conv.SetInputLengthUnit( 2.54 );
2936 reader.SetCoordinateSystemConverter( conv );
2937 reader.SetDocument( doc );
2939 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
2950 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
2954 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
2957 TDF_LabelSequence frshapes;
2958 s_assy->GetFreeShapes( frshapes );
2961 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
2964 TDF_Label d_targetLabel = d_assy->NewShape();
2966 if( frshapes.Size() == 1 )
2968 TDocStd_XLinkTool link;
2969 link.Copy( d_targetLabel, frshapes.First() );
2974 for( TDF_Label& s_shapeLabel : frshapes )
2976 TDF_Label d_component = d_assy->NewShape();
2978 TDocStd_XLinkTool link;
2979 link.Copy( d_component, s_shapeLabel );
2981 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
2985 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
2988 return d_targetLabel;
2994 TDF_LabelSequence freeShapes;
2995 aShapeTool->GetFreeShapes( freeShapes );
3001 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
3003 TDF_Label label = freeShapes.Value( i );
3005 aShapeTool->GetShape( label, shape );
3010 const Standard_Real linearDeflection = 0.14;
3011 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
3012 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
3024 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
3030 m_outFmt = OUTPUT_FORMAT::FMT_OUT_GLTF;
3034 wxFileName fn( aFileName );
3036 const char* tmpGltfname =
"$tempfile$.glb";
3037 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
3039 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
3040 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3041 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3042 RWMesh_CoordinateSystem_Zup );
3043#if OCC_VERSION_HEX >= 0x070700
3044 cafWriter.SetParallel(
true );
3046 TColStd_IndexedDataMapOfStringString metadata;
3048 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3049 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3050 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3051 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3052 metadata.Add( TCollection_AsciiString(
"generator" ),
3053 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
3054 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3057 bool success =
true;
3060 wxString currCWD = wxGetCwd();
3061 wxString workCWD = fn.GetPath();
3063 if( !workCWD.IsEmpty() )
3064 wxSetWorkingDirectory( workCWD );
3066 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3073 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
3075 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3076 tmpGltfname, fn.GetFullName() ) );
3081 wxSetWorkingDirectory( currCWD );
3089#if OCC_VERSION_HEX < 0x070700
3090 ReportMessage( wxT(
"PLY export is not supported before OCCT 7.7.0\n" ) );
3096 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
3102 m_outFmt = OUTPUT_FORMAT::FMT_OUT_PLY;
3106 wxFileName fn( aFileName );
3108 const char* tmpFname =
"$tempfile$.ply";
3109 RWPly_CafWriter cafWriter( tmpFname );
3111 cafWriter.SetFaceId(
true );
3112 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
3113 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
3114 RWMesh_CoordinateSystem_Zup );
3116 TColStd_IndexedDataMapOfStringString metadata;
3118 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
3119 TCollection_ExtendedString( fn.GetName().wc_str() ) );
3120 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
3121 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
3122 metadata.Add( TCollection_AsciiString(
"generator" ),
3123 TCollection_AsciiString(
3125 metadata.Add( TCollection_AsciiString(
"generated_at" ),
3128 bool success =
true;
3131 wxString currCWD = wxGetCwd();
3132 wxString workCWD = fn.GetPath();
3134 if( !workCWD.IsEmpty() )
3135 wxSetWorkingDirectory( workCWD );
3137 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
3144 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3146 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3147 tmpFname, fn.GetFullName() ) );
3152 wxSetWorkingDirectory( currCWD );
3163 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
3169 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STL;
3173 wxFileName fn( aFileName );
3175 const char* tmpFname =
"$tempfile$.stl";
3178 wxString currCWD = wxGetCwd();
3179 wxString workCWD = fn.GetPath();
3181 if( !workCWD.IsEmpty() )
3182 wxSetWorkingDirectory( workCWD );
3184 bool success = StlAPI_Writer().Write(
getOneShape( m_assy ), tmpFname );
3191 if( !wxRenameFile( tmpFname, fn.GetFullName(),
true ) )
3193 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
3194 tmpFname, fn.GetFullName() ) );
3199 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 ...
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.
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::vector< TopoDS_Shape > m_board_copper_vias
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
void getBoardBodyZPlacement(double &aZPos, double &aThickness)
std::vector< TopoDS_Shape > m_board_copper_fused
std::vector< TopoDS_Shape > m_board_copper
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
void getLayerZPlacement(const PCB_LAYER_ID aLayer, double &aZPos, double &aThickness)
STEP_PCB_MODEL(const wxString &aPcbName)
bool AddBarrel(const SHAPE_SEGMENT &aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin)
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)
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 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 AddPolygonShapes(const SHAPE_POLY_SET *aPolyShapes, PCB_LAYER_ID aLayer, const VECTOR2D &aOrigin)
bool WriteSTEP(const wxString &aFileName, bool aOptimize)
std::vector< TopoDS_Shape > m_copperCutouts
std::vector< TopoDS_Shape > m_board_copper_pads
std::map< wxString, 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)
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
void ReportMessage(const wxString &aMessage)
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 bool colorFromStackup(BOARD_STACKUP_ITEM_TYPE aType, const wxString &aColorStr, COLOR4D &aColorOut)
static TopoDS_Compound makeCompound(auto &aInputShapes)
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)
static std::vector< FAB_LAYER_COLOR > s_soldermaskColors
static TopoDS_Shape fuseShapesOrCompound(TopTools_ListOfShape &aInputShapes)
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
static bool makeWireFromChain(BRepLib_MakeWire &aMkWire, const SHAPE_LINE_CHAIN &aChain, double aMergeOCCMaxDist, double aZposition, const VECTOR2D &aOrigin)
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
void ReportMessage(const wxString &aMessage)
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
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)
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