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>
108#include <Geom_Curve.hxx>
109#include <Geom_TrimmedCurve.hxx>
114#include <GC_MakeArcOfCircle.hxx>
115#include <GC_MakeCircle.hxx>
117#include <RWGltf_CafWriter.hxx>
119#if OCC_VERSION_HEX >= 0x070700
120#include <VrmlAPI_CafReader.hxx>
147 wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
149 if( !lfile.FileExists() )
152 msg.Printf( wxT(
" * fileType(): no such file: %s\n" ),
153 wxString::FromUTF8Unchecked( aFileName ) );
159 wxString ext = lfile.GetExt().Lower();
161 if( ext == wxT(
"wrl" ) )
164 if( ext == wxT(
"wrz" ) )
167 if( ext == wxT(
"idf" ) )
170 if( ext == wxT(
"emn" ) )
173 if( ext == wxT(
"stpz" ) || ext == wxT(
"gz" ) )
182 memset( iline, 0, 82 );
183 ifile.getline( iline, 82 );
189 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
192 std::string fstr = iline;
196 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
202 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
217 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
218 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
219 double det = -b.
x * d.
y + d.
x * b.
y;
223 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
224 center.
y = ( b.
x * cd + d.
x * bc ) * det;
231#define APPROX_DBG( stmt )
239 static const double c_radiusDeviation = 1000.0;
240 static const double c_arcCenterDeviation = 1000.0;
241 static const double c_relLengthDeviation = 0.8;
242 static const int c_last_none = -1000;
262 int last = c_last_none;
268 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
270 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
275 bool defective =
false;
281 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
289 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
290 defective |=
std::abs( a_diff ) < 0.1;
293 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
294 defective |=
std::abs( a_diff ) >= maxAngleDiff;
301 double radius = ( p0 - center ).EuclideanNorm();
305 for(
int j = i; j <= jEndIdx; j++ )
310 double rad_test = ( p_test - center ).EuclideanNorm();
311 double d_tl = ( p_test - p_prev ).EuclideanNorm();
312 double rad_dev =
std::abs( radius - rad_test );
315 << int64_t( rad_test ) <<
" ref " << int64_t( radius )
318 if( rad_dev > c_radiusDeviation )
321 <<
" Radius deviation too large: " << int64_t( rad_dev )
322 <<
" > " << c_radiusDeviation << std::endl );
327 double maxAngleDiff =
328 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
330 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
331 if(
std::abs( a_diff_test ) >= maxAngleDiff )
333 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
338 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
340 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
341 <<
"; " << d01 << std::endl );
351 if( last != c_last_none )
360 int toRemove = last - ( aSrc.
PointCount() - 3 );
390 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
394 if( last == c_last_none )
411 if( iarc0 != -1 && iarc1 != -1 )
413 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
423 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
441 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
442 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
458static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
460 TDF_LabelSequence theLabels;
461 aShapeTool->GetFreeShapes( theLabels );
465 if( theLabels.Length() == 1 )
466 return aShapeTool->GetShape( theLabels.Value( 1 ) );
468 TopoDS_Compound aCompound;
469 BRep_Builder aBuilder;
470 aBuilder.MakeCompound( aCompound );
472 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
474 TopoDS_Shape aFreeShape;
476 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
479 aBuilder.Add( aCompound, aFreeShape );
482 if( aCompound.NbChildren() > 0 )
491static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
493 if( theLabel.IsNull() )
495 Message::SendFail(
"Null label." );
496 return Standard_False;
499 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
500 || Abs( aScale.Z() ) <= gp::Resolution() )
502 Message::SendFail(
"Scale factor is too small." );
503 return Standard_False;
506 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
507 if( aShapeTool.IsNull() )
509 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
510 return Standard_False;
513 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
516 Message::SendFail(
"Couldn't create assembly graph." );
517 return Standard_False;
520 Standard_Boolean anIsDone = Standard_True;
524 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
526 0, 0, aScale.Z() ) );
529 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
531 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
533 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
535 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
536 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
541 const TDF_Label& aLabel = aG->GetNode( idx );
543 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
545 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
546 aBRepTrsf.Perform( aShape, Standard_True );
547 if( !aBRepTrsf.IsDone() )
549 Standard_SStream aSS;
550 TCollection_AsciiString anEntry;
551 TDF_Tool::Entry( aLabel, anEntry );
552 aSS <<
"Shape " << anEntry <<
" is not scaled!";
553 Message::SendFail( aSS.str().c_str() );
554 anIsDone = Standard_False;
555 return Standard_False;
557 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
558 aShapeTool->SetShape( aLabel, aScaledShape );
561 TDF_LabelSequence aSubshapes;
562 aShapeTool->GetSubShapes( aLabel, aSubshapes );
563 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
565 const TDF_Label& aLSs = anItSs.Value();
566 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
567 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
568 aShapeTool->SetShape( aLSs, aSs1 );
572 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
573 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
574 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
576 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
578 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
579 gp_Trsf aTrsf = aLoc.Transformation();
580 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
581 XCAFDoc_Location::Set( aLabel, aTrsf );
587 return Standard_False;
590 aShapeTool->UpdateAssemblies();
596static bool fuseShapes(
auto& aInputShapes, TopoDS_Shape& aOutShape )
598 BRepAlgoAPI_Fuse mkFuse;
599 TopTools_ListOfShape shapeArguments, shapeTools;
601 for( TopoDS_Shape& sh : aInputShapes )
606 if( shapeArguments.IsEmpty() )
607 shapeArguments.Append( sh );
609 shapeTools.Append( sh );
612 mkFuse.SetRunParallel(
true );
613 mkFuse.SetToFillHistory(
false );
614 mkFuse.SetArguments( shapeArguments );
615 mkFuse.SetTools( shapeTools );
618 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
622 if( mkFuse.HasErrors() )
625 mkFuse.DumpErrors( std::cout );
628 if( mkFuse.HasWarnings() )
631 mkFuse.DumpWarnings( std::cout );
637 if( mkFuse.IsDone() )
639 TopoDS_Shape fusedShape = mkFuse.Shape();
641 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
642 unify.History() =
nullptr;
645 TopoDS_Shape unifiedShapes = unify.Shape();
647 if( unifiedShapes.IsNull() )
649 ReportMessage(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) );
653 aOutShape = unifiedShapes;
664 TopoDS_Compound compound;
665 BRep_Builder builder;
666 builder.MakeCompound( compound );
668 for( TopoDS_Shape& shape : aInputShapes )
669 builder.Add( compound, shape );
678 TopoDS_Shape outShape;
680 if( aInputShapes.Size() == 1 )
681 return aInputShapes.First();
692 const TCollection_ExtendedString& aPrefix )
694 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
698 Message::SendFail(
"Couldn't create assembly graph." );
699 return Standard_False;
702 Standard_Boolean anIsDone = Standard_True;
704 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
706 const TDF_Label& lbl = aG->GetNode( idx );
707 Handle( TDataStd_Name ) nameHandle;
709 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
711 TCollection_ExtendedString
name;
715 name += nameHandle->Get();
718 TDataStd_Name::Set( lbl,
name );
722 TDataStd_Name::Set( lbl, aPrefix );
732 m_app = XCAFApp_Application::GetApplication();
733 m_app->NewDocument(
"MDTV-XCAF", m_doc );
734 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
751 if( m_doc->CanClose() == CDM_CCS_OK )
771 double Zpos, thickness;
777 if( pcb_layer ==
F_Cu )
779 else if( pcb_layer ==
B_Cu )
783 TopoDS_Shape testShape;
792 if( testShape.IsNull() )
794 std::vector<TopoDS_Shape> testShapes;
798 if( testShapes.size() > 0 )
799 testShape = testShapes.front();
802 if( !aVia && !testShape.IsNull() )
804 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
810 if( pcb_layer ==
F_Cu )
812 else if( pcb_layer ==
B_Cu )
829 double f_pos, f_thickness;
830 double b_pos, b_thickness;
833 double top = std::max( f_pos, f_pos + f_thickness );
834 double bottom = std::min( b_pos, b_pos + b_thickness );
836 TopoDS_Shape plating;
842 ( top - bottom ), bottom, aOrigin ) )
853 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
863 double margin = 0.001;
871 double f_pos, f_thickness;
872 double b_pos, b_thickness;
875 double top = std::max( f_pos, f_pos + f_thickness );
876 double bottom = std::min( b_pos, b_pos + b_thickness );
878 double holeZsize = ( top - bottom ) + ( margin * 2 );
880 double boardDrill = aShape.
GetWidth();
881 double copperDrill = boardDrill - aPlatingThickness * 2;
883 TopoDS_Shape copperHole, boardHole;
886 holeZsize, bottom - margin, aOrigin ) )
896 holeZsize, bottom - margin, aOrigin ) )
912 double f_pos, f_thickness;
913 double b_pos, b_thickness;
916 double top = std::max( f_pos, f_pos + f_thickness );
917 double bottom = std::min( b_pos, b_pos + b_thickness );
919 TopoDS_Shape plating;
922 ( top - bottom ), bottom, aOrigin ) )
940 static const double c_silkscreenAboveCopper = 0.04;
941 static const double c_soldermaskAboveCopper = 0.015;
949 double f_pos, f_thickness;
951 double top = std::max( f_pos, f_pos + f_thickness );
954 aZPos = top + c_silkscreenAboveCopper;
956 aZPos = top + c_soldermaskAboveCopper;
962 double b_pos, b_thickness;
964 double bottom = std::min( b_pos, b_pos + b_thickness );
967 aZPos = bottom - c_silkscreenAboveCopper;
969 aZPos = bottom - c_soldermaskAboveCopper;
981 bool wasPrepreg =
false;
986 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1032 double f_pos, f_thickness;
1033 double b_pos, b_thickness;
1036 double top = std::min( f_pos, f_pos + f_thickness );
1037 double bottom = std::max( b_pos, b_pos + b_thickness );
1039 aThickness = ( top - bottom );
1042 wxASSERT( aZPos == 0.0 );
1049 bool success =
true;
1057 double z_pos, thickness;
1068 wxString::Format( wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
1082 if( aFileNameUTF8.empty() )
1084 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
1088 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1089 ReportMessage( wxString::Format( wxT(
"Adding component %s.\n" ), aRefDes ) );
1093 wxString errorMessage;
1095 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1097 if( errorMessage.IsEmpty() )
1098 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
1106 TopLoc_Location toploc;
1108 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1111 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
1116 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1118 if( llabel.IsNull() )
1120 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
1126 TCollection_ExtendedString refdes( aRefDes.c_str() );
1127 TDataStd_Name::Set( llabel, refdes );
1194 double aWidth,
double aThickness,
1195 double aZposition,
const VECTOR2D& aOrigin )
1202 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1203 double h_width = aWidth/2.0;
1205 coords[0] =
VECTOR2D{ 0.0, h_width };
1208 coords[1] =
VECTOR2D{ len, h_width };
1211 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1214 coords[3] =
VECTOR2D{ len, -h_width };
1217 coords[4] =
VECTOR2D{ 0, -h_width };
1220 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1223 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1225 for(
int ii = 0; ii < 6; ii++ )
1228 coords[ii] += aStartPoint;
1233 gp_Pnt coords3D[ 6 ];
1235 for(
int ii = 0; ii < 6; ii++ )
1242 BRepBuilderAPI_MakeWire wire;
1243 bool success =
true;
1255 Handle( Geom_Circle ) circle = GC_MakeCircle( coords3D[1],
1260 edge = BRepBuilderAPI_MakeEdge( circle );
1265 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1268 Handle( Geom_TrimmedCurve ) arcOfCircle =
1269 GC_MakeArcOfCircle( coords3D[1],
1273 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1276 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1279 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1280 GC_MakeArcOfCircle( coords3D[4],
1284 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1288 catch(
const Standard_Failure& e )
1290 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
1291 e.GetMessageString() ) );
1295 BRepBuilderAPI_MakeFace face;
1299 gp_Pln plane( coords3D[0], gp::DZ() );
1300 face = BRepBuilderAPI_MakeFace( plane, wire );
1302 catch(
const Standard_Failure& e )
1304 ReportMessage( wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
1305 e.GetMessageString() ) );
1309 if( aThickness != 0.0 )
1311 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1313 if( aShape.IsNull() )
1315 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
1333 str <<
"x0: " <<
up.StringFromValue( aBBox.
GetLeft(),
false ) <<
"; ";
1334 str <<
"y0: " <<
up.StringFromValue( aBBox.
GetTop(),
false ) <<
"; ";
1335 str <<
"x1: " <<
up.StringFromValue( aBBox.
GetRight(),
false ) <<
"; ";
1336 str <<
"y1: " <<
up.StringFromValue( aBBox.
GetBottom(),
false );
1343 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin )
1345 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1358 gp_Pnt start = toPoint( aPt0 );
1359 gp_Pnt end = toPoint( aPt1 );
1361 BRepBuilderAPI_MakeEdge mkEdge( start, end );
1363 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1365 ReportMessage( wxString::Format( wxT(
"failed to make segment edge at (%d "
1366 "%d) -> (%d %d), skipping\n" ),
1367 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1371 aMkWire.Add( mkEdge.Edge() );
1373 if( aMkWire.Error() != BRepLib_WireDone )
1375 ReportMessage( wxString::Format( wxT(
"failed to add segment edge "
1376 "at (%d %d) -> (%d %d)\n" ),
1377 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1388 Handle( Geom_Curve ) curve;
1390 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1392 gp_Ax2 axis = gp::XOY();
1393 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1395 curve = GC_MakeCircle( axis,
pcbIUScale.
IUTomm( aArc.GetRadius() ) ).Value();
1399 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1400 toPoint( aArc.GetP1() ) )
1404 if( curve.IsNull() )
1407 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1409 if( !aMkWire.IsDone() )
1412 wxT(
"failed to add arc curve from (%d %d), arc p0 "
1413 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1414 aPt0.
x, aPt0.
y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x,
1415 aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) );
1424 bool isFirstShape =
true;
1437 if( nextShape != -1 )
1443 lastPt = aChain.
CPoint( i );
1453 firstPt = currentArc.
GetP0();
1458 lastPt = currentArc.
GetP0();
1460 if( addArc( lastPt, currentArc ) )
1461 lastPt = currentArc.
GetP1();
1480 isFirstShape =
false;
1483 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1486 wxString::Format( wxT(
"** Failed to close wire at %d, %d -> %d, %d **\n" ),
1487 lastPt.
x, lastPt.
y, firstPt.
x, firstPt.
y ) );
1492 catch(
const Standard_Failure& e )
1494 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
1495 e.GetMessageString() ) );
1504 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
1511 if( aConvertToArcs )
1515 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1519 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1522 polygon[contId] = approxChain;
1526 fallbackPoly = workingPoly;
1527 workingPoly = approximated;
1546 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1553 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1554 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1556 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1560 auto tryMakeWire = [
this, &aZposition,
1564 BRepLib_MakeWire mkWire;
1568 if( mkWire.IsDone() )
1570 wire = mkWire.Wire();
1575 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n" ),
1576 static_cast<int>( aContour.PointCount() ),
1577 static_cast<int>( mkWire.Error() ) ) );
1579 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1583 if( !wire.IsNull() )
1585 BRepAlgoAPI_Check check( wire,
false,
true );
1587 if( !check.IsValid() )
1589 ReportMessage( wxString::Format(
_(
"\nWire self-interference check "
1592 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1602 BRepBuilderAPI_MakeFace mkFace;
1604 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1608 TopoDS_Wire wire = tryMakeWire( polygon[contId] );
1610 if( aConvertToArcs && wire.IsNull() )
1612 ReportMessage( wxString::Format(
_(
"Using non-simplified polygon.\n" ) ) );
1615 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId] );
1620 if( !wire.IsNull() )
1622 if( basePlane.Axis().Direction().Z() < 0 )
1625 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1629 ReportMessage( wxString::Format( wxT(
"\n** Outline skipped **\n" ) ) );
1631 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1640 if( !wire.IsNull() )
1642 if( basePlane.Axis().Direction().Z() > 0 )
1649 ReportMessage( wxString::Format( wxT(
"\n** Hole skipped **\n" ) ) );
1651 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1657 catch(
const Standard_Failure& e )
1660 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
1661 static_cast<int>( contId ), e.GetMessageString() ) );
1666 if( mkFace.IsDone() )
1668 TopoDS_Shape faceShape = mkFace.Shape();
1670 if( aThickness != 0.0 )
1672 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1673 aShapes.push_back( prism );
1675 if( prism.IsNull() )
1683 aShapes.push_back( faceShape );
1688 ReportMessage( wxString::Format(
_(
"** Face skipped **\n" ) ) );
1699 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1700 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1701 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1702 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1703 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1704 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1705 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1706 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1716 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1718 aColorOut =
COLOR4D( aColorStr );
1723 const std::vector<FAB_LAYER_COLOR>& colors =
1730 if( fabColor.GetName() == aColorStr )
1732 aColorOut = fabColor.GetColor( aType );
1752 Handle( XCAFDoc_VisMaterialTool ) visMatTool =
1753 XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1758 ReportMessage( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1761 double boardThickness;
1776 wxT(
"OCC error creating main outline.\n" ) ) );
1782 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1786 polyset.
Append( contour );
1793 ReportMessage( wxT(
"OCC error creating main outline.\n" ) );
1801 ReportMessage( wxT(
"OCC error creating hole in main outline.\n" ) );
1812 BRepBndLib::Add( brdShape, brdBndBox );
1815 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1818 auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1822 Bnd_Box brdWithHolesBndBox = brdBndBox;
1824 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1826 for(
size_t i = 0; i < input.size(); i++ )
1829 BRepBndLib::Add( input[i], bbox );
1830 brdWithHolesBndBox.Add( bbox );
1831 ( *holeBoxSet )[i] = bbox;
1834 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1837 auto subtractShapes = [](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
1838 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
1842 for( TopoDS_Shape& shape : aShapesList )
1845 BRepBndLib::Add( shape, shapeBbox );
1847 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
1849 TopTools_ListOfShape holelist;
1851 for(
const Standard_Integer& index : indices )
1852 holelist.Append( aHolesList[index] );
1855 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
1861 (
int) aShapesList.size(), aWhat ) );
1863 if( holelist.IsEmpty() )
1866 TopTools_ListOfShape cutArgs;
1867 cutArgs.Append( shape );
1869 BRepAlgoAPI_Cut
cut;
1871 cut.SetRunParallel(
true );
1872 cut.SetToFillHistory(
false );
1874 cut.SetArguments( cutArgs );
1875 cut.SetTools( holelist );
1878 if(
cut.HasErrors() ||
cut.HasWarnings() )
1881 _(
"\n** Got problems while cutting %s number %d **\n" ), aWhat, cnt ) );
1884 if(
cut.HasErrors() )
1887 cut.DumpErrors( std::cout );
1890 if(
cut.HasWarnings() )
1893 cut.DumpWarnings( std::cout );
1899 shape =
cut.Shape();
1905 Bnd_BoundSortBox bsbHoles;
1913 Bnd_BoundSortBox bsbHoles;
1924 TopTools_ListOfShape shapesToFuse;
1927 shapesToFuse.Append( shape );
1930 shapesToFuse.Append( shape );
1933 shapesToFuse.Append( shape );
1937 if( !fusedShape.IsNull() )
1957 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_ColorRGBA aColor,
1958 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
1961 if( aShapesList.empty() )
1964 std::vector<TopoDS_Shape> newList;
1969 newList = aShapesList;
1972 for( TopoDS_Shape& shape : newList )
1974 Handle( TDataStd_TreeNode ) node;
1977 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
1983 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
1984 TDF_Label shpLbl = node->Father()->Label();
1985 if( !shpLbl.IsNull() )
1987 if( visMatTool && !aVisMatLabel.IsNull() )
1988 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
1992 if( newList.size() > 1 )
1994 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
1998 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
2002 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2003 TDataStd_Name::Set( shpLbl, partname );
2010 auto makeMaterial = [&](
const TCollection_AsciiString& aName,
2011 const Quantity_ColorRGBA& aBaseColor,
double aMetallic,
2012 double aRoughness ) -> TDF_Label
2014 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2015 XCAFDoc_VisMaterialPBR pbr;
2016 pbr.BaseColor = aBaseColor;
2017 pbr.Metallic = aMetallic;
2018 pbr.Roughness = aRoughness;
2019 vismat->SetPbrMaterial( pbr );
2020 return visMatTool->AddMaterial( vismat, aName );
2027 Quantity_ColorRGBA board_color( 0.3f, 0.3f, 0.3f, 1.0f );
2028 Quantity_ColorRGBA silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2029 Quantity_ColorRGBA mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2039 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2042 mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2045 if( item->GetBrdLayerId() ==
F_SilkS || item->GetBrdLayerId() ==
B_SilkS )
2046 silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2049 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2054 board_color = mask_color;
2055 board_color.SetAlpha( 1.0 );
2058 TDF_Label mask_mat = makeMaterial(
"soldermask", mask_color, 0.0, 0.6 );
2059 TDF_Label silk_mat = makeMaterial(
"silkscreen", silk_color, 0.0, 0.9 );
2060 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2061 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2062 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2064 pushToAssembly(
m_board_copper, copper_color, copper_mat,
"copper",
true );
2071 if( aPushBoardBody )
2074#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2075 m_assy->UpdateAssemblies();
2084bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2088 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2094 wxFileName fn( aFileName );
2095 IGESControl_Controller::Init();
2096 IGESCAFControl_Writer writer;
2097 writer.SetColorMode( Standard_True );
2098 writer.SetNameMode( Standard_True );
2099 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2100 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2101 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2102 header.SetAuthorName(
2103 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2104 header.SetCompanyName(
2105 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2106 writer.Model()->SetGlobalSection( header );
2108 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2120 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2126 wxFileName fn( aFileName );
2128 STEPCAFControl_Writer writer;
2129 writer.SetColorMode( Standard_True );
2130 writer.SetNameMode( Standard_True );
2137 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2138 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
2142 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2143 ReportMessage( wxT(
"Failed to set surface curve mode, but will attempt to continue." ) );
2145 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2148 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2152 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2155 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2156 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2157 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2158 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2160 bool success =
true;
2163 wxString currCWD = wxGetCwd();
2164 wxString workCWD = fn.GetPath();
2166 if( !workCWD.IsEmpty() )
2167 wxSetWorkingDirectory( workCWD );
2169 char tmpfname[] =
"$tempfile$.step";
2171 if( Standard_False == writer.Write( tmpfname ) )
2180 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2182 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2184 fn.GetFullName() ) );
2189 wxSetWorkingDirectory( currCWD );
2199 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2206 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2211 wxFileName fn( aFileName );
2213 wxFFileOutputStream ffStream( fn.GetFullPath() );
2214 wxStdOutputStream stdStream( ffStream );
2216#if OCC_VERSION_HEX >= 0x070600
2217 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2219 BRepTools::Write( shape, stdStream );
2228 wxFileName fn( aFileName );
2230 wxFFileOutputStream ffStream( fn.GetFullPath() );
2231 wxStdOutputStream file( ffStream );
2233 if( !ffStream.IsOk() )
2235 ReportMessage( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ) );
2240 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2245 std::map<wxString, std::vector<int>> groups[4];
2246 TopExp_Explorer exp;
2249 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2251 TopoDS_Shape subShape = exp.Current();
2254 BRepBndLib::Add( subShape, bbox );
2258 const auto& [point, padTestShape] = pair;
2260 if( bbox.IsOut( point ) )
2263 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2265 if( surface.GetType() != GeomAbs_Plane )
2268 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2271 if( !dist.IsDone() )
2274 if( dist.Value() < Precision::Approximation() )
2277 groups[2][padKey].push_back( faceIndex );
2285 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2286 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2287 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2288 file <<
" <shape format=\"BREP\"><![CDATA[";
2289#if OCC_VERSION_HEX < 0x070600
2290 BRepTools::Write( shape, file );
2292 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2294 file <<
"]]></shape>" << std::endl;
2295 file <<
" <topology>" << std::endl;
2297 TopTools_IndexedMapOfShape mainMap;
2298 TopExp::MapShapes( shape, mainMap );
2299 std::set<int> topo[4];
2301 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2304 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2305 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2307 for(
int dim = 0; dim < 4; dim++ )
2309 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2311 TopoDS_Shape subShape = exp.Current();
2312 int idx = mainMap.FindIndex( subShape );
2314 if( idx && !topo[dim].count( idx ) )
2315 topo[dim].insert( idx );
2319 for(
int dim = 0; dim <= 3; dim++ )
2321 std::string labels = c_dimLabels[dim];
2322 std::string label = c_dimLabel[dim];
2324 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2327 for(
auto p : topo[dim] )
2329 std::string
name(
"" );
2330 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2331 <<
"name=\"" <<
name <<
"\" "
2332 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2336 file <<
" </" << labels <<
">" << std::endl;
2339 file <<
" </topology>" << std::endl;
2340 file <<
" </geometry>" << std::endl;
2341 file <<
" <groups count=\""
2342 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2344 for(
int dim = 0; dim <= 3; dim++ )
2346 std::string label = c_dimLabel[dim];
2348 for(
auto g : groups[dim] )
2351 wxString
name = g.first;
2355 std::ostringstream gs;
2356 gs <<
"G_" << dim <<
"D_" << g.first;
2359 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2365 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2366 for(
auto index : g.second )
2368 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2370 file <<
" </group>" << std::endl;
2373 file <<
" </groups>" << std::endl;
2374 file <<
" <fields count=\"0\"/>" << std::endl;
2375 file <<
"</XAO>" << std::endl;
2382 bool aSubstituteModels, wxString* aErrorMessage )
2384 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2385 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2387 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2391 aLabel = mm->second;
2397 Handle( TDocStd_Document ) doc;
2398 m_app->NewDocument(
"MDTV-XCAF", doc );
2400 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2406 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2408 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2415 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2417 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2427 wxFFileInputStream ifile( fileName );
2428 wxFileName outFile( fileName );
2430 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2431 outFile.SetExt( wxT(
"step" ) );
2432 wxFileOffset size = ifile.GetLength();
2434 if( size == wxInvalidOffset )
2436 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2442 bool success =
false;
2443 wxFFileOutputStream ofile( outFile.GetFullPath() );
2448 char* buffer =
new char[size];
2450 ifile.Read( buffer, size );
2451 std::string expanded;
2455 expanded = gzip::decompress( buffer, size );
2460 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2464 if( expanded.empty() )
2468 wxZipInputStream izipfile( ifile );
2469 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2471 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2473 izipfile.Read( ofile );
2479 ofile.Write( expanded.data(), expanded.size() );
2487 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2508 if( aSubstituteModels )
2510 wxFileName wrlName( fileName );
2512 wxString basePath = wrlName.GetPath();
2513 wxString baseName = wrlName.GetName();
2521 alts.Add( wxT(
"stp" ) );
2522 alts.Add( wxT(
"step" ) );
2523 alts.Add( wxT(
"STP" ) );
2524 alts.Add( wxT(
"STEP" ) );
2525 alts.Add( wxT(
"Stp" ) );
2526 alts.Add( wxT(
"Step" ) );
2527 alts.Add( wxT(
"stpz" ) );
2528 alts.Add( wxT(
"stpZ" ) );
2529 alts.Add( wxT(
"STPZ" ) );
2530 alts.Add( wxT(
"step.gz" ) );
2531 alts.Add( wxT(
"stp.gz" ) );
2534 alts.Add( wxT(
"iges" ) );
2535 alts.Add( wxT(
"IGES" ) );
2536 alts.Add( wxT(
"igs" ) );
2537 alts.Add( wxT(
"IGS" ) );
2541 for(
const auto& alt : alts )
2543 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2545 if( altFile.IsOk() && altFile.FileExists() )
2547 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2565 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2567 Handle( XCAFDoc_ShapeTool ) shapeTool =
2568 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2571 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2575 ReportMessage( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2583 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2598 if( aLabel.IsNull() )
2600 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
2607 wxFileName afile( fileName );
2608 std::string pname( afile.GetName().ToUTF8() );
2609 TCollection_ExtendedString partname( pname.c_str() );
2610 TDataStd_Name::Set( aLabel, partname );
2619 TopLoc_Location& aLocation )
2633 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2638 double boardThickness;
2641 double top = std::max( boardZPos, boardZPos + boardThickness );
2642 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2648 aOffset.
z -= bottom;
2649 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2650 lPos.Multiply( lRot );
2651 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
2652 lPos.Multiply( lRot );
2657 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2658 lPos.Multiply( lRot );
2662 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
2663 lPos.Multiply( lOff );
2666 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
2668 lPos.Multiply( lOrient );
2669 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
2671 lPos.Multiply( lOrient );
2672 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
2674 lPos.Multiply( lOrient );
2676 aLocation = TopLoc_Location( lPos );
2683 IGESControl_Controller::Init();
2684 IGESCAFControl_Reader reader;
2685 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2687 if( stat != IFSelect_RetDone )
2691 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2695 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2699 reader.SetColorMode(
true );
2700 reader.SetNameMode(
false );
2701 reader.SetLayerMode(
false );
2703 if( !reader.Transfer( doc ) )
2705 if( doc->CanClose() == CDM_CCS_OK )
2712 if( reader.NbShapes() < 1 )
2714 if( doc->CanClose() == CDM_CCS_OK )
2726 STEPCAFControl_Reader reader;
2727 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2729 if( stat != IFSelect_RetDone )
2733 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2737 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2741 reader.SetColorMode(
true );
2742 reader.SetNameMode(
true );
2743 reader.SetLayerMode(
false );
2745 if( !reader.Transfer( doc ) )
2747 if( doc->CanClose() == CDM_CCS_OK )
2754 if( reader.NbRootsForTransfer() < 1 )
2756 if( doc->CanClose() == CDM_CCS_OK )
2768#if OCC_VERSION_HEX >= 0x070700
2769 VrmlAPI_CafReader reader;
2770 RWMesh_CoordinateSystemConverter conv;
2771 conv.SetInputLengthUnit( 2.54 );
2772 reader.SetCoordinateSystemConverter( conv );
2773 reader.SetDocument( doc );
2775 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
2786 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
2790 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
2793 TDF_LabelSequence frshapes;
2794 s_assy->GetFreeShapes( frshapes );
2797 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
2800 TDF_Label d_targetLabel = d_assy->NewShape();
2802 if( frshapes.Size() == 1 )
2804 TDocStd_XLinkTool link;
2805 link.Copy( d_targetLabel, frshapes.First() );
2810 for( TDF_Label& s_shapeLabel : frshapes )
2812 TDF_Label d_component = d_assy->NewShape();
2814 TDocStd_XLinkTool link;
2815 link.Copy( d_component, s_shapeLabel );
2817 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
2821 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
2824 return d_targetLabel;
2832 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2838 TDF_LabelSequence freeShapes;
2839 m_assy->GetFreeShapes( freeShapes );
2845 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
2847 TDF_Label label = freeShapes.Value( i );
2849 m_assy->GetShape( label, shape );
2854 const Standard_Real linearDeflection = 0.14;
2855 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
2856 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
2860 wxFileName fn( aFileName );
2862 const char* tmpGltfname =
"$tempfile$.glb";
2863 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
2865 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
2866 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
2867 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
2868 RWMesh_CoordinateSystem_Zup );
2869#if OCC_VERSION_HEX >= 0x070700
2870 cafWriter.SetParallel(
true );
2872 TColStd_IndexedDataMapOfStringString metadata;
2874 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
2875 TCollection_ExtendedString( fn.GetName().wc_str() ) );
2876 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
2877 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
2878 metadata.Add( TCollection_AsciiString(
"generator" ),
2879 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
2880 metadata.Add( TCollection_AsciiString(
"generated_at" ),
2883 bool success =
true;
2886 wxString currCWD = wxGetCwd();
2887 wxString workCWD = fn.GetPath();
2889 if( !workCWD.IsEmpty() )
2890 wxSetWorkingDirectory( workCWD );
2892 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
2899 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
2901 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2902 tmpGltfname, fn.GetFullName() ) );
2907 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
coord_type GetTop() const
coord_type GetRight() const
coord_type GetLeft() const
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 PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
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.
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)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
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
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.
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
bool AddHole(const SHAPE_SEGMENT &aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D &aOrigin)
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 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()
void SetStackup(const BOARD_STACKUP &aStackup)
void SetNetFilter(const wxString &aFilter)
bool AddPadShape(const PAD *aPad, const VECTOR2D &aOrigin, bool aVia)
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 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)
void OCCSetMergeMaxDistance(double aDistance=OCC_MAX_DISTANCE_TO_MERGE_POINTS)
bool WriteBREP(const wxString &aFileName)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
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)
Tests 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
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