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" ) )
187 const int max_line_count = 3;
189 for(
int ii = 0; ii < max_line_count; ii++ )
191 memset( iline, 0, 82 );
192 ifile.getline( iline, 82 );
198 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
204 std::string fstr = iline;
208 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
217 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
224 if( strncmp( iline,
"/*", 2 ) != 0 )
242 double bc = ( b.
x * b.
x + b.
y * b.
y ) / 2.0;
243 double cd = ( -d.
x * d.
x - d.
y * d.
y ) / 2.0;
244 double det = -b.
x * d.
y + d.
x * b.
y;
248 center.
x = ( -bc * d.
y - cd * b.
y ) * det;
249 center.
y = ( b.
x * cd + d.
x * bc ) * det;
256#define APPROX_DBG( stmt )
264 static const double c_radiusDeviation = 1000.0;
265 static const double c_arcCenterDeviation = 1000.0;
266 static const double c_relLengthDeviation = 0.8;
267 static const int c_last_none = -1000;
287 int last = c_last_none;
293 APPROX_DBG( std::cout << i <<
" " << aSrc.
CPoint( i ) <<
" " << ( i - 3 ) <<
" "
295 << ( i - 1 ) <<
" " <<
VECTOR2I( p2 ) << std::endl );
300 bool defective =
false;
306 defective |=
std::abs( d01 - d12 ) > ( std::max( d01, d12 ) * c_relLengthDeviation );
314 double a_diff = ( a01 - a12 ).Normalize180().AsDegrees();
315 defective |=
std::abs( a_diff ) < 0.1;
318 double maxAngleDiff = std::max( d01, d12 ) < c_smallSize ? 46.0 : 30.0;
319 defective |=
std::abs( a_diff ) >= maxAngleDiff;
326 double radius = ( p0 - center ).EuclideanNorm();
330 for(
int j = i; j <= jEndIdx; j++ )
335 double rad_test = ( p_test - center ).EuclideanNorm();
336 double d_tl = ( p_test - p_prev ).EuclideanNorm();
337 double rad_dev =
std::abs( radius - rad_test );
340 << int64_t( rad_test ) <<
" ref " << int64_t( radius )
343 if( rad_dev > c_radiusDeviation )
346 <<
" Radius deviation too large: " << int64_t( rad_dev )
347 <<
" > " << c_radiusDeviation << std::endl );
352 double maxAngleDiff =
353 std::max( std::max( d01, d12 ), d_tl ) < c_smallSize ? 46.0 : 30.0;
355 double a_diff_test = ( a_prev - a_test ).Normalize180().AsDegrees();
356 if(
std::abs( a_diff_test ) >= maxAngleDiff )
358 APPROX_DBG( std::cout <<
" " << j <<
" Angles differ too much " << a_diff_test
363 if(
std::abs( d_tl - d01 ) > ( std::max( d_tl, d01 ) * c_relLengthDeviation ) )
365 APPROX_DBG( std::cout <<
" " << j <<
" Lengths differ too much " << d_tl
366 <<
"; " << d01 << std::endl );
376 if( last != c_last_none )
385 int toRemove = last - ( aSrc.
PointCount() - 3 );
415 APPROX_DBG( std::cout <<
" Self-intersection check failed" << std::endl );
419 if( last == c_last_none )
436 if( iarc0 != -1 && iarc1 != -1 )
438 APPROX_DBG( std::cout <<
"Final arcs " << iarc0 <<
" " << iarc1 << std::endl );
448 if( ( p1 - p0 ).EuclideanNorm() < c_circleCloseGap )
466 if(
std::abs( ar0 - ar1 ) <= c_radiusDeviation
467 && ( ac0 - ac1 ).EuclideanNorm() <= c_arcCenterDeviation )
483static TopoDS_Shape
getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
485 TDF_LabelSequence theLabels;
486 aShapeTool->GetFreeShapes( theLabels );
490 if( theLabels.Length() == 1 )
491 return aShapeTool->GetShape( theLabels.Value( 1 ) );
493 TopoDS_Compound aCompound;
494 BRep_Builder aBuilder;
495 aBuilder.MakeCompound( aCompound );
497 for( TDF_LabelSequence::Iterator anIt( theLabels ); anIt.More(); anIt.Next() )
499 TopoDS_Shape aFreeShape;
501 if( !aShapeTool->GetShape( anIt.Value(), aFreeShape ) )
504 aBuilder.Add( aCompound, aFreeShape );
507 if( aCompound.NbChildren() > 0 )
516static Standard_Boolean
rescaleShapes(
const TDF_Label& theLabel,
const gp_XYZ& aScale )
518 if( theLabel.IsNull() )
520 Message::SendFail(
"Null label." );
521 return Standard_False;
524 if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
525 || Abs( aScale.Z() ) <= gp::Resolution() )
527 Message::SendFail(
"Scale factor is too small." );
528 return Standard_False;
531 Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
532 if( aShapeTool.IsNull() )
534 Message::SendFail(
"Couldn't find XCAFDoc_ShapeTool attribute." );
535 return Standard_False;
538 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( theLabel );
541 Message::SendFail(
"Couldn't create assembly graph." );
542 return Standard_False;
545 Standard_Boolean anIsDone = Standard_True;
549 aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
551 0, 0, aScale.Z() ) );
554 BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
556 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
558 const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
560 if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
561 && ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
566 const TDF_Label& aLabel = aG->GetNode( idx );
568 if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
570 const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
571 aBRepTrsf.Perform( aShape, Standard_True );
572 if( !aBRepTrsf.IsDone() )
574 Standard_SStream aSS;
575 TCollection_AsciiString anEntry;
576 TDF_Tool::Entry( aLabel, anEntry );
577 aSS <<
"Shape " << anEntry <<
" is not scaled!";
578 Message::SendFail( aSS.str().c_str() );
579 anIsDone = Standard_False;
580 return Standard_False;
582 TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
583 aShapeTool->SetShape( aLabel, aScaledShape );
586 TDF_LabelSequence aSubshapes;
587 aShapeTool->GetSubShapes( aLabel, aSubshapes );
588 for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
590 const TDF_Label& aLSs = anItSs.Value();
591 const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
592 const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
593 aShapeTool->SetShape( aLSs, aSs1 );
597 aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
598 aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
599 aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
601 else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
603 TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
604 gp_Trsf aTrsf = aLoc.Transformation();
605 aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
606 XCAFDoc_Location::Set( aLabel, aTrsf );
612 return Standard_False;
615 aShapeTool->UpdateAssemblies();
621static bool fuseShapes(
auto& aInputShapes, TopoDS_Shape& aOutShape )
623 BRepAlgoAPI_Fuse mkFuse;
624 TopTools_ListOfShape shapeArguments, shapeTools;
626 for( TopoDS_Shape& sh : aInputShapes )
631 if( shapeArguments.IsEmpty() )
632 shapeArguments.Append( sh );
634 shapeTools.Append( sh );
637 mkFuse.SetRunParallel(
true );
638 mkFuse.SetToFillHistory(
false );
639 mkFuse.SetArguments( shapeArguments );
640 mkFuse.SetTools( shapeTools );
643 if( mkFuse.HasErrors() || mkFuse.HasWarnings() )
647 if( mkFuse.HasErrors() )
650 mkFuse.DumpErrors( std::cout );
653 if( mkFuse.HasWarnings() )
656 mkFuse.DumpWarnings( std::cout );
662 if( mkFuse.IsDone() )
664 TopoDS_Shape fusedShape = mkFuse.Shape();
666 ShapeUpgrade_UnifySameDomain unify( fusedShape,
true,
true,
false );
667 unify.History() =
nullptr;
670 TopoDS_Shape unifiedShapes = unify.Shape();
672 if( unifiedShapes.IsNull() )
674 ReportMessage(
_(
"** ShapeUpgrade_UnifySameDomain produced a null shape **\n" ) );
678 aOutShape = unifiedShapes;
689 TopoDS_Compound compound;
690 BRep_Builder builder;
691 builder.MakeCompound( compound );
693 for( TopoDS_Shape& shape : aInputShapes )
694 builder.Add( compound, shape );
703 TopoDS_Shape outShape;
705 if( aInputShapes.Size() == 1 )
706 return aInputShapes.First();
717 const TCollection_ExtendedString& aPrefix )
719 Handle( KI_XCAFDoc_AssemblyGraph ) aG =
new KI_XCAFDoc_AssemblyGraph( aLabel );
723 Message::SendFail(
"Couldn't create assembly graph." );
724 return Standard_False;
727 Standard_Boolean anIsDone = Standard_True;
729 for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
731 const TDF_Label& lbl = aG->GetNode( idx );
732 Handle( TDataStd_Name ) nameHandle;
734 if( lbl.FindAttribute( TDataStd_Name::GetID(), nameHandle ) )
736 TCollection_ExtendedString
name;
740 name += nameHandle->Get();
743 TDataStd_Name::Set( lbl,
name );
747 TDataStd_Name::Set( lbl, aPrefix );
757 m_app = XCAFApp_Application::GetApplication();
758 m_app->NewDocument(
"MDTV-XCAF", m_doc );
759 m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
771 m_outFmt = OUTPUT_FORMAT::FMT_OUT_UNKNOWN;
777 if( m_doc->CanClose() == CDM_CCS_OK )
785 std::vector<TopoDS_Shape> padShapes;
798 double Zpos, thickness;
804 if( pcb_layer ==
F_Cu )
806 else if( pcb_layer ==
B_Cu )
810 TopoDS_Shape testShape;
818 if( testShape.IsNull() )
820 std::vector<TopoDS_Shape> testShapes;
824 if( testShapes.size() > 0 )
825 testShape = testShapes.front();
828 if( !aVia && !testShape.IsNull() )
830 if( pcb_layer ==
F_Cu || pcb_layer ==
B_Cu )
836 if( pcb_layer ==
F_Cu )
838 else if( pcb_layer ==
B_Cu )
855 double f_pos, f_thickness;
856 double b_pos, b_thickness;
859 double top = std::max( f_pos, f_pos + f_thickness );
860 double bottom = std::min( b_pos, b_pos + b_thickness );
862 TopoDS_Shape plating;
868 ( top - bottom ), bottom, aOrigin ) )
870 padShapes.push_back( plating );
879 ReportMessage( wxT(
"OCC error adding pad/via polygon.\n" ) );
884 TopTools_ListOfShape padShapesList;
886 for(
const TopoDS_Shape& shape : padShapes )
887 padShapesList.Append( shape );
893 for(
const TopoDS_Shape& shape : padShapes )
905 double margin = 0.001;
913 double f_pos, f_thickness;
914 double b_pos, b_thickness;
917 double top = std::max( f_pos, f_pos + f_thickness );
918 double bottom = std::min( b_pos, b_pos + b_thickness );
920 double holeZsize = ( top - bottom ) + ( margin * 2 );
922 double boardDrill = aShape.
GetWidth();
923 double copperDrill = boardDrill - aPlatingThickness * 2;
925 TopoDS_Shape copperHole, boardHole;
928 holeZsize, bottom - margin, aOrigin ) )
938 holeZsize, bottom - margin, aOrigin ) )
954 double f_pos, f_thickness;
955 double b_pos, b_thickness;
958 double top = std::max( f_pos, f_pos + f_thickness );
959 double bottom = std::min( b_pos, b_pos + b_thickness );
961 TopoDS_Shape plating;
964 ( top - bottom ), bottom, aOrigin ) )
982 static const double c_silkscreenAboveCopper = 0.04;
983 static const double c_soldermaskAboveCopper = 0.015;
991 double f_pos, f_thickness;
993 double top = std::max( f_pos, f_pos + f_thickness );
996 aZPos = top + c_silkscreenAboveCopper;
998 aZPos = top + c_soldermaskAboveCopper;
1004 double b_pos, b_thickness;
1006 double bottom = std::min( b_pos, b_pos + b_thickness );
1009 aZPos = bottom - c_silkscreenAboveCopper;
1011 aZPos = bottom - c_soldermaskAboveCopper;
1019 double& aThickness )
1023 bool wasPrepreg =
false;
1028 for(
auto it = materials.rbegin(); it != materials.rend(); ++it )
1034 if( aLayer ==
B_Cu )
1079 double f_pos, f_thickness;
1080 double b_pos, b_thickness;
1083 double top = std::min( f_pos, f_pos + f_thickness );
1084 double bottom = std::max( b_pos, b_pos + b_thickness );
1086 aThickness = ( top - bottom );
1089 wxASSERT( aZPos == 0.0 );
1096 bool success =
true;
1104 double z_pos, thickness;
1115 wxString::Format( wxT(
"Could not add shape (%d points) to copper layer on %s.\n" ),
1129 if( aFileNameUTF8.empty() )
1131 ReportMessage( wxString::Format( wxT(
"No model defined for component %s.\n" ), aRefDes ) );
1135 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
1136 ReportMessage( wxString::Format( wxT(
"Adding component %s.\n" ), aRefDes ) );
1140 wxString errorMessage;
1142 if( !
getModelLabel( aFileNameUTF8, aScale, lmodel, aSubstituteModels, &errorMessage ) )
1144 if( errorMessage.IsEmpty() )
1145 ReportMessage( wxString::Format( wxT(
"No model for filename '%s'.\n" ), fileName ) );
1153 TopLoc_Location toploc;
1155 if( !
getModelLocation( aBottom, aPosition, aRotation, aOffset, aOrientation, toploc ) )
1158 wxString::Format( wxT(
"No location data for filename '%s'.\n" ), fileName ) );
1163 TDF_Label llabel = m_assy->AddComponent(
m_assy_label, lmodel, toploc );
1165 if( llabel.IsNull() )
1167 ReportMessage( wxString::Format( wxT(
"Could not add component with filename '%s'.\n" ),
1173 TCollection_ExtendedString refdes( aRefDes.c_str() );
1174 TDataStd_Name::Set( llabel, refdes );
1241 double aWidth,
double aThickness,
1242 double aZposition,
const VECTOR2D& aOrigin )
1249 double len = ( aEndPoint - aStartPoint ).EuclideanNorm();
1250 double h_width = aWidth/2.0;
1252 coords[0] =
VECTOR2D{ 0.0, h_width };
1255 coords[1] =
VECTOR2D{ len, h_width };
1258 coords[2] =
VECTOR2D{ len + h_width, 0.0 };
1261 coords[3] =
VECTOR2D{ len, -h_width };
1264 coords[4] =
VECTOR2D{ 0, -h_width };
1267 coords[5] =
VECTOR2D{ -h_width, 0.0 };
1270 EDA_ANGLE seg_angle( aEndPoint - aStartPoint );
1272 for(
int ii = 0; ii < 6; ii++ )
1275 coords[ii] += aStartPoint;
1280 gp_Pnt coords3D[ 6 ];
1282 for(
int ii = 0; ii < 6; ii++ )
1289 BRepBuilderAPI_MakeWire wire;
1290 bool success =
true;
1302 Handle( Geom_Circle ) circle = GC_MakeCircle( coords3D[1],
1307 edge = BRepBuilderAPI_MakeEdge( circle );
1312 edge = BRepBuilderAPI_MakeEdge( coords3D[0], coords3D[1] );
1315 Handle( Geom_TrimmedCurve ) arcOfCircle =
1316 GC_MakeArcOfCircle( coords3D[1],
1320 edge = BRepBuilderAPI_MakeEdge( arcOfCircle );
1323 edge = BRepBuilderAPI_MakeEdge( coords3D[3], coords3D[4] );
1326 Handle( Geom_TrimmedCurve ) arcOfCircle2 =
1327 GC_MakeArcOfCircle( coords3D[4],
1331 edge = BRepBuilderAPI_MakeEdge( arcOfCircle2 );
1335 catch(
const Standard_Failure& e )
1337 ReportMessage( wxString::Format( wxT(
"build shape segment: OCC exception: %s\n" ),
1338 e.GetMessageString() ) );
1342 BRepBuilderAPI_MakeFace face;
1346 gp_Pln plane( coords3D[0], gp::DZ() );
1347 face = BRepBuilderAPI_MakeFace( plane, wire );
1349 catch(
const Standard_Failure& e )
1351 ReportMessage( wxString::Format( wxT(
"MakeShapeThickSegment: OCC exception: %s\n" ),
1352 e.GetMessageString() ) );
1356 if( aThickness != 0.0 )
1358 aShape = BRepPrimAPI_MakePrism( face, gp_Vec( 0, 0, aThickness ) );
1360 if( aShape.IsNull() )
1362 ReportMessage( wxT(
"failed to create a prismatic shape\n" ) );
1380 str <<
"x0: " <<
up.StringFromValue( aBBox.
GetLeft(),
false ) <<
"; ";
1381 str <<
"y0: " <<
up.StringFromValue( aBBox.
GetTop(),
false ) <<
"; ";
1382 str <<
"x1: " <<
up.StringFromValue( aBBox.
GetRight(),
false ) <<
"; ";
1383 str <<
"y1: " <<
up.StringFromValue( aBBox.
GetBottom(),
false );
1390 double aMergeOCCMaxDist,
double aZposition,
const VECTOR2D& aOrigin )
1392 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1405 gp_Pnt start = toPoint( aPt0 );
1406 gp_Pnt end = toPoint( aPt1 );
1408 BRepBuilderAPI_MakeEdge mkEdge( start, end );
1410 if( !mkEdge.IsDone() || mkEdge.Edge().IsNull() )
1412 ReportMessage( wxString::Format( wxT(
"failed to make segment edge at (%d "
1413 "%d) -> (%d %d), skipping\n" ),
1414 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1418 aMkWire.Add( mkEdge.Edge() );
1420 if( aMkWire.Error() != BRepLib_WireDone )
1422 ReportMessage( wxString::Format( wxT(
"failed to add segment edge "
1423 "at (%d %d) -> (%d %d)\n" ),
1424 aPt0.
x, aPt0.
y, aPt1.x, aPt1.y ) );
1435 Handle( Geom_Curve ) curve;
1437 if( aArc.GetCentralAngle() ==
ANGLE_360 )
1439 gp_Ax2 axis = gp::XOY();
1440 axis.SetLocation( toPoint( aArc.GetCenter() ) );
1442 curve = GC_MakeCircle( axis,
pcbIUScale.
IUTomm( aArc.GetRadius() ) ).Value();
1446 curve = GC_MakeArcOfCircle( toPoint( aPt0 ), toPoint( aArc.GetArcMid() ),
1447 toPoint( aArc.GetP1() ) )
1451 if( curve.IsNull() )
1454 aMkWire.Add( BRepBuilderAPI_MakeEdge( curve ) );
1456 if( !aMkWire.IsDone() )
1459 wxT(
"failed to add arc curve from (%d %d), arc p0 "
1460 "(%d %d), mid (%d %d), p1 (%d %d)\n" ),
1461 aPt0.
x, aPt0.
y, aArc.GetP0().x, aArc.GetP0().y, aArc.GetArcMid().x,
1462 aArc.GetArcMid().y, aArc.GetP1().x, aArc.GetP1().y ) );
1471 bool isFirstShape =
true;
1484 if( nextShape != -1 )
1490 lastPt = aChain.
CPoint( i );
1500 firstPt = currentArc.
GetP0();
1505 lastPt = currentArc.
GetP0();
1507 if( addArc( lastPt, currentArc ) )
1508 lastPt = currentArc.
GetP1();
1527 isFirstShape =
false;
1530 if( lastPt != firstPt && !
addSegment( lastPt, firstPt ) )
1533 wxString::Format( wxT(
"** Failed to close wire at %d, %d -> %d, %d **\n" ),
1534 lastPt.
x, lastPt.
y, firstPt.
x, firstPt.
y ) );
1539 catch(
const Standard_Failure& e )
1541 ReportMessage( wxString::Format( wxT(
"makeWireFromChain: OCC exception: %s\n" ),
1542 e.GetMessageString() ) );
1551 double aThickness,
double aZposition,
const VECTOR2D& aOrigin )
1558 if( aConvertToArcs )
1562 for(
size_t polyId = 0; polyId < approximated.
CPolygons().size(); polyId++ )
1566 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1569 polygon[contId] = approxChain;
1573 fallbackPoly = workingPoly;
1574 workingPoly = approximated;
1593 auto toPoint = [&](
const VECTOR2D& aKiCoords ) -> gp_Pnt
1600 gp_Pln basePlane( gp_Pnt( 0.0, 0.0, aZposition ),
1601 std::signbit( aThickness ) ? -gp::DZ() : gp::DZ() );
1603 for(
size_t polyId = 0; polyId < workingPoly.
CPolygons().size(); polyId++ )
1607 auto tryMakeWire = [
this, &aZposition,
1611 BRepLib_MakeWire mkWire;
1615 if( mkWire.IsDone() )
1617 wire = mkWire.Wire();
1622 wxString::Format(
_(
"Wire not done (contour points %d): OCC error %d\n" ),
1623 static_cast<int>( aContour.PointCount() ),
1624 static_cast<int>( mkWire.Error() ) ) );
1626 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1630 if( !wire.IsNull() )
1632 BRepAlgoAPI_Check check( wire,
false,
true );
1634 if( !check.IsValid() )
1636 ReportMessage( wxString::Format(
_(
"\nWire self-interference check "
1639 ReportMessage( wxString::Format(
_(
"z: %g; bounding box: %s\n" ), aZposition,
1649 BRepBuilderAPI_MakeFace mkFace;
1651 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1655 TopoDS_Wire wire = tryMakeWire( polygon[contId] );
1657 if( aConvertToArcs && wire.IsNull() )
1659 ReportMessage( wxString::Format(
_(
"Using non-simplified polygon.\n" ) ) );
1662 wire = tryMakeWire( fallbackPoly.
CPolygon( polyId )[contId] );
1667 if( !wire.IsNull() )
1669 if( basePlane.Axis().Direction().Z() < 0 )
1672 mkFace = BRepBuilderAPI_MakeFace( basePlane, wire );
1676 ReportMessage( wxString::Format( wxT(
"\n** Outline skipped **\n" ) ) );
1678 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1687 if( !wire.IsNull() )
1689 if( basePlane.Axis().Direction().Z() > 0 )
1696 ReportMessage( wxString::Format( wxT(
"\n** Hole skipped **\n" ) ) );
1698 ReportMessage( wxString::Format( wxT(
"z: %g; bounding box: %s\n" ),
1704 catch(
const Standard_Failure& e )
1707 wxString::Format( wxT(
"MakeShapes (contour %d): OCC exception: %s\n" ),
1708 static_cast<int>( contId ), e.GetMessageString() ) );
1713 if( mkFace.IsDone() )
1715 TopoDS_Shape faceShape = mkFace.Shape();
1717 if( aThickness != 0.0 )
1719 TopoDS_Shape prism = BRepPrimAPI_MakePrism( faceShape, gp_Vec( 0, 0, aThickness ) );
1720 aShapes.push_back( prism );
1722 if( prism.IsNull() )
1730 aShapes.push_back( faceShape );
1735 ReportMessage( wxString::Format(
_(
"** Face skipped **\n" ) ) );
1746 {
_HKI(
"Green" ), wxColor( 20, 51, 36 ) },
1747 {
_HKI(
"Red" ), wxColor( 181, 19, 21 ) },
1748 {
_HKI(
"Blue" ), wxColor( 2, 59, 162 ) },
1749 {
_HKI(
"Purple" ), wxColor( 32, 2, 53 ) },
1750 {
_HKI(
"Black" ), wxColor( 11, 11, 11 ) },
1751 {
_HKI(
"White" ), wxColor( 245, 245, 245 ) },
1752 {
_HKI(
"Yellow" ), wxColor( 194, 195, 0 ) },
1753 {
_HKI(
"User defined" ), wxColor( 128, 128, 128 ) }
1763 if( aColorStr.StartsWith( wxT(
"#" ) ) )
1765 aColorOut =
COLOR4D( aColorStr );
1770 const std::vector<FAB_LAYER_COLOR>& colors =
1777 if( fabColor.GetName() == aColorStr )
1779 aColorOut = fabColor.GetColor( aType );
1799 Handle( XCAFDoc_VisMaterialTool ) visMatTool =
1800 XCAFDoc_DocumentTool::VisMaterialTool( m_doc->Main() );
1805 ReportMessage( wxString::Format( wxT(
"Build board outlines (%d outlines) with %d points.\n" ),
1808 double boardThickness;
1823 wxT(
"OCC error creating main outline.\n" ) ) );
1829 for(
size_t contId = 0; contId < polygon.size(); contId++ )
1833 polyset.
Append( contour );
1840 ReportMessage( wxT(
"OCC error creating main outline.\n" ) );
1848 ReportMessage( wxT(
"OCC error creating hole in main outline.\n" ) );
1859 BRepBndLib::Add( brdShape, brdBndBox );
1862 ReportMessage( wxString::Format( wxT(
"Build board cutouts and holes (%d hole(s)).\n" ),
1865 auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
1869 Bnd_Box brdWithHolesBndBox = brdBndBox;
1871 Handle( Bnd_HArray1OfBox ) holeBoxSet =
new Bnd_HArray1OfBox( 0, input.size() - 1 );
1873 for(
size_t i = 0; i < input.size(); i++ )
1876 BRepBndLib::Add( input[i], bbox );
1877 brdWithHolesBndBox.Add( bbox );
1878 ( *holeBoxSet )[i] = bbox;
1881 bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
1884 auto subtractShapes = [](
const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
1885 std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
1889 for( TopoDS_Shape& shape : aShapesList )
1892 BRepBndLib::Add( shape, shapeBbox );
1894 const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
1896 TopTools_ListOfShape holelist;
1898 for(
const Standard_Integer& index : indices )
1899 holelist.Append( aHolesList[index] );
1902 ReportMessage( wxString::Format(
_(
"Build holes for %s\n" ), aWhat ) );
1908 (
int) aShapesList.size(), aWhat ) );
1910 if( holelist.IsEmpty() )
1913 TopTools_ListOfShape cutArgs;
1914 cutArgs.Append( shape );
1916 BRepAlgoAPI_Cut
cut;
1918 cut.SetRunParallel(
true );
1919 cut.SetToFillHistory(
false );
1921 cut.SetArguments( cutArgs );
1922 cut.SetTools( holelist );
1925 if(
cut.HasErrors() ||
cut.HasWarnings() )
1928 _(
"\n** Got problems while cutting %s number %d **\n" ), aWhat, cnt ) );
1931 if(
cut.HasErrors() )
1934 cut.DumpErrors( std::cout );
1937 if(
cut.HasWarnings() )
1940 cut.DumpWarnings( std::cout );
1946 shape =
cut.Shape();
1952 Bnd_BoundSortBox bsbHoles;
1960 Bnd_BoundSortBox bsbHoles;
1971 TopTools_ListOfShape shapesToFuse;
1974 shapesToFuse.Append( shape );
1977 shapesToFuse.Append( shape );
1980 shapesToFuse.Append( shape );
1984 if( !fusedShape.IsNull() )
2004 auto pushToAssembly = [&]( std::vector<TopoDS_Shape>& aShapesList, Quantity_ColorRGBA aColor,
2005 const TDF_Label& aVisMatLabel,
const wxString& aShapeName,
2008 if( aShapesList.empty() )
2011 std::vector<TopoDS_Shape> newList;
2016 newList = aShapesList;
2019 for( TopoDS_Shape& shape : newList )
2021 Handle( TDataStd_TreeNode ) node;
2024 TDF_Label lbl = m_assy->AddComponent(
m_assy_label, shape,
false );
2030 lbl.FindAttribute( XCAFDoc::ShapeRefGUID(), node );
2031 TDF_Label shpLbl = node->Father()->Label();
2032 if( !shpLbl.IsNull() )
2034 if( visMatTool && !aVisMatLabel.IsNull() )
2035 visMatTool->SetShapeMaterial( shpLbl, aVisMatLabel );
2039 if( newList.size() > 1 )
2041 shapeName = wxString::Format( wxT(
"%s_%s_%d" ),
m_pcbName, aShapeName, i );
2045 shapeName = wxString::Format( wxT(
"%s_%s" ),
m_pcbName, aShapeName );
2049 TCollection_ExtendedString partname( shapeName.ToUTF8().data() );
2050 TDataStd_Name::Set( shpLbl, partname );
2057 auto makeMaterial = [&](
const TCollection_AsciiString& aName,
2058 const Quantity_ColorRGBA& aBaseColor,
double aMetallic,
2059 double aRoughness ) -> TDF_Label
2061 Handle( XCAFDoc_VisMaterial ) vismat =
new XCAFDoc_VisMaterial;
2062 XCAFDoc_VisMaterialPBR pbr;
2063 pbr.BaseColor = aBaseColor;
2064 pbr.Metallic = aMetallic;
2065 pbr.Roughness = aRoughness;
2066 vismat->SetPbrMaterial( pbr );
2067 return visMatTool->AddMaterial( vismat, aName );
2074 Quantity_ColorRGBA board_color( 0.3f, 0.3f, 0.3f, 1.0f );
2075 Quantity_ColorRGBA silk_color( 1.0f, 1.0f, 1.0f, 0.9f );
2076 Quantity_ColorRGBA mask_color( 0.08f, 0.2f, 0.14f, 0.83f );
2086 if( item->GetBrdLayerId() ==
F_Mask || item->GetBrdLayerId() ==
B_Mask )
2089 mask_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2092 if( item->GetBrdLayerId() ==
F_SilkS || item->GetBrdLayerId() ==
B_SilkS )
2093 silk_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2096 board_color.SetValues( col.
r, col.
g, col.
b, col.
a );
2101 board_color = mask_color;
2102 board_color.SetAlpha( 1.0 );
2105 TDF_Label mask_mat = makeMaterial(
"soldermask", mask_color, 0.0, 0.6 );
2106 TDF_Label silk_mat = makeMaterial(
"silkscreen", silk_color, 0.0, 0.9 );
2107 TDF_Label copper_mat = makeMaterial(
"copper", copper_color, 1.0, 0.4 );
2108 TDF_Label pad_mat = makeMaterial(
"pad", pad_color, 1.0, 0.4 );
2109 TDF_Label board_mat = makeMaterial(
"board", board_color, 0.0, 0.8 );
2111 pushToAssembly(
m_board_copper, copper_color, copper_mat,
"copper",
true );
2118 if( aPushBoardBody )
2121#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
2122 m_assy->UpdateAssemblies();
2131bool STEP_PCB_MODEL::WriteIGES(
const wxString& aFileName )
2135 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2141 m_outFmt = OUTPUT_FORMAT::FMT_OUT_IGES;
2143 wxFileName fn( aFileName );
2144 IGESControl_Controller::Init();
2145 IGESCAFControl_Writer writer;
2146 writer.SetColorMode( Standard_True );
2147 writer.SetNameMode( Standard_True );
2148 IGESData_GlobalSection header = writer.Model()->GlobalSection();
2149 header.SetFileName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2150 header.SetSendName(
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2151 header.SetAuthorName(
2152 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.author" ) ) );
2153 header.SetCompanyName(
2154 new TCollection_HAsciiString( Interface_Static::CVal(
"write.iges.header.company" ) ) );
2155 writer.Model()->SetGlobalSection( header );
2157 if( Standard_False == writer.Perform( m_doc, aFileName.c_str() ) )
2169 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2175 m_outFmt = OUTPUT_FORMAT::FMT_OUT_STEP;
2177 wxFileName fn( aFileName );
2179 STEPCAFControl_Writer writer;
2180 writer.SetColorMode( Standard_True );
2181 writer.SetNameMode( Standard_True );
2188 if( !Interface_Static::SetCVal(
"write.step.product.name", fn.GetName().ToAscii() ) )
2189 ReportMessage( wxT(
"Failed to set step product name, but will attempt to continue." ) );
2193 if( !Interface_Static::SetIVal(
"write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
2194 ReportMessage( wxT(
"Failed to set surface curve mode, but will attempt to continue." ) );
2196 if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
2199 APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
2203 hdr.SetName(
new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
2206 hdr.SetAuthorValue( 1,
new TCollection_HAsciiString(
"Pcbnew" ) );
2207 hdr.SetOrganizationValue( 1,
new TCollection_HAsciiString(
"Kicad" ) );
2208 hdr.SetOriginatingSystem(
new TCollection_HAsciiString(
"KiCad to STEP converter" ) );
2209 hdr.SetDescriptionValue( 1,
new TCollection_HAsciiString(
"KiCad electronic assembly" ) );
2211 bool success =
true;
2214 wxString currCWD = wxGetCwd();
2215 wxString workCWD = fn.GetPath();
2217 if( !workCWD.IsEmpty() )
2218 wxSetWorkingDirectory( workCWD );
2220 char tmpfname[] =
"$tempfile$.step";
2222 if( Standard_False == writer.Write( tmpfname ) )
2231 if( !wxRenameFile( tmpfname, fn.GetFullName(),
true ) )
2233 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2235 fn.GetFullName() ) );
2240 wxSetWorkingDirectory( currCWD );
2250 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2256 m_outFmt = OUTPUT_FORMAT::FMT_OUT_BREP;
2259 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2264 wxFileName fn( aFileName );
2266 wxFFileOutputStream ffStream( fn.GetFullPath() );
2267 wxStdOutputStream stdStream( ffStream );
2269#if OCC_VERSION_HEX >= 0x070600
2270 BRepTools::Write( shape, stdStream,
false,
false, TopTools_FormatVersion_VERSION_1 );
2272 BRepTools::Write( shape, stdStream );
2281 wxFileName fn( aFileName );
2283 wxFFileOutputStream ffStream( fn.GetFullPath() );
2284 wxStdOutputStream file( ffStream );
2286 if( !ffStream.IsOk() )
2288 ReportMessage( wxString::Format(
"Could not open file '%s'", fn.GetFullPath() ) );
2292 m_outFmt = OUTPUT_FORMAT::FMT_OUT_XAO;
2295 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
2300 std::map<wxString, std::vector<int>> groups[4];
2301 TopExp_Explorer exp;
2304 for( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
2306 TopoDS_Shape subShape = exp.Current();
2309 BRepBndLib::Add( subShape, bbox );
2313 const auto& [point, padTestShape] = pair;
2315 if( bbox.IsOut( point ) )
2318 BRepAdaptor_Surface surface( TopoDS::Face( subShape ) );
2320 if( surface.GetType() != GeomAbs_Plane )
2323 BRepExtrema_DistShapeShape dist( padTestShape, subShape );
2326 if( !dist.IsDone() )
2329 if( dist.Value() < Precision::Approximation() )
2332 groups[2][padKey].push_back( faceIndex );
2340 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
2341 file <<
"<XAO version=\"1.0\" author=\"KiCad\">" << std::endl;
2342 file <<
" <geometry name=\"" << fn.GetName() <<
"\">" << std::endl;
2343 file <<
" <shape format=\"BREP\"><![CDATA[";
2344#if OCC_VERSION_HEX < 0x070600
2345 BRepTools::Write( shape, file );
2347 BRepTools::Write( shape, file, Standard_True, Standard_True, TopTools_FormatVersion_VERSION_1 );
2349 file <<
"]]></shape>" << std::endl;
2350 file <<
" <topology>" << std::endl;
2352 TopTools_IndexedMapOfShape mainMap;
2353 TopExp::MapShapes( shape, mainMap );
2354 std::set<int> topo[4];
2356 static const TopAbs_ShapeEnum c_dimShapeTypes[] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE,
2359 static const std::string c_dimLabel[] = {
"vertex",
"edge",
"face",
"solid" };
2360 static const std::string c_dimLabels[] = {
"vertices",
"edges",
"faces",
"solids" };
2362 for(
int dim = 0; dim < 4; dim++ )
2364 for( exp.Init( shape, c_dimShapeTypes[dim] ); exp.More(); exp.Next() )
2366 TopoDS_Shape subShape = exp.Current();
2367 int idx = mainMap.FindIndex( subShape );
2369 if( idx && !topo[dim].count( idx ) )
2370 topo[dim].insert( idx );
2374 for(
int dim = 0; dim <= 3; dim++ )
2376 std::string labels = c_dimLabels[dim];
2377 std::string label = c_dimLabel[dim];
2379 file <<
" <" << labels <<
" count=\"" << topo[dim].size() <<
"\">" << std::endl;
2382 for(
auto p : topo[dim] )
2384 std::string
name(
"" );
2385 file <<
" <" << label <<
" index=\"" << index <<
"\" "
2386 <<
"name=\"" <<
name <<
"\" "
2387 <<
"reference=\"" << p <<
"\"/>" << std::endl;
2391 file <<
" </" << labels <<
">" << std::endl;
2394 file <<
" </topology>" << std::endl;
2395 file <<
" </geometry>" << std::endl;
2396 file <<
" <groups count=\""
2397 << groups[0].size() + groups[1].size() + groups[2].size() + groups[3].size() <<
"\">"
2399 for(
int dim = 0; dim <= 3; dim++ )
2401 std::string label = c_dimLabel[dim];
2403 for(
auto g : groups[dim] )
2406 wxString
name = g.first;
2410 std::ostringstream gs;
2411 gs <<
"G_" << dim <<
"D_" << g.first;
2414 file <<
" <group name=\"" <<
name <<
"\" dimension=\"" << label;
2420 file <<
"\" count=\"" << g.second.size() <<
"\">" << std::endl;
2421 for(
auto index : g.second )
2423 file <<
" <element index=\"" << index <<
"\"/>" << std::endl;
2425 file <<
" </group>" << std::endl;
2428 file <<
" </groups>" << std::endl;
2429 file <<
" <fields count=\"0\"/>" << std::endl;
2430 file <<
"</XAO>" << std::endl;
2437 bool aSubstituteModels, wxString* aErrorMessage )
2439 std::string model_key = aFileNameUTF8 +
"_" + std::to_string( aScale.
x )
2440 +
"_" + std::to_string( aScale.
y ) +
"_" + std::to_string( aScale.
z );
2442 MODEL_MAP::const_iterator mm =
m_models.find( model_key );
2446 aLabel = mm->second;
2452 Handle( TDocStd_Document ) doc;
2453 m_app->NewDocument(
"MDTV-XCAF", doc );
2455 wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
2461 if( !
readIGES( doc, aFileNameUTF8.c_str() ) )
2463 ReportMessage( wxString::Format( wxT(
"readIGES() failed on filename '%s'.\n" ),
2470 if( !
readSTEP( doc, aFileNameUTF8.c_str() ) )
2472 ReportMessage( wxString::Format( wxT(
"readSTEP() failed on filename '%s'.\n" ),
2482 wxFFileInputStream ifile( fileName );
2483 wxFileName outFile( fileName );
2485 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
2486 outFile.SetExt( wxT(
"step" ) );
2487 wxFileOffset size = ifile.GetLength();
2489 if( size == wxInvalidOffset )
2491 ReportMessage( wxString::Format( wxT(
"getModelLabel() failed on filename '%s'.\n" ),
2497 bool success =
false;
2498 wxFFileOutputStream ofile( outFile.GetFullPath() );
2503 char* buffer =
new char[size];
2505 ifile.Read( buffer, size );
2506 std::string expanded;
2510 expanded = gzip::decompress( buffer, size );
2515 ReportMessage( wxString::Format( wxT(
"failed to decompress '%s'.\n" ),
2519 if( expanded.empty() )
2523 wxZipInputStream izipfile( ifile );
2524 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
2526 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
2528 izipfile.Read( ofile );
2534 ofile.Write( expanded.data(), expanded.size() );
2542 std::string altFileNameUTF8 =
TO_UTF8( outFile.GetFullPath() );
2563 if( aSubstituteModels )
2565 wxFileName wrlName( fileName );
2567 wxString basePath = wrlName.GetPath();
2568 wxString baseName = wrlName.GetName();
2576 alts.Add( wxT(
"stp" ) );
2577 alts.Add( wxT(
"step" ) );
2578 alts.Add( wxT(
"STP" ) );
2579 alts.Add( wxT(
"STEP" ) );
2580 alts.Add( wxT(
"Stp" ) );
2581 alts.Add( wxT(
"Step" ) );
2582 alts.Add( wxT(
"stpz" ) );
2583 alts.Add( wxT(
"stpZ" ) );
2584 alts.Add( wxT(
"STPZ" ) );
2585 alts.Add( wxT(
"step.gz" ) );
2586 alts.Add( wxT(
"stp.gz" ) );
2589 alts.Add( wxT(
"iges" ) );
2590 alts.Add( wxT(
"IGES" ) );
2591 alts.Add( wxT(
"igs" ) );
2592 alts.Add( wxT(
"IGS" ) );
2596 for(
const auto& alt : alts )
2598 wxFileName altFile( basePath, baseName + wxT(
"." ) + alt );
2600 if( altFile.IsOk() && altFile.FileExists() )
2602 std::string altFileNameUTF8 =
TO_UTF8( altFile.GetFullPath() );
2620 if(
m_outFmt == OUTPUT_FORMAT::FMT_OUT_GLTF )
2622 if(
readVRML( doc, aFileNameUTF8.c_str() ) )
2624 Handle( XCAFDoc_ShapeTool ) shapeTool =
2625 XCAFDoc_DocumentTool::ShapeTool( doc->Main() );
2628 TCollection_ExtendedString( baseName.c_str().AsChar() ) );
2632 ReportMessage( wxString::Format( wxT(
"readVRML() failed on filename '%s'.\n" ),
2641 aErrorMessage->Printf( wxT(
"Cannot load any VRML model for this export.\n" ) );
2651 ReportMessage( wxString::Format( wxT(
"Cannot identify actual file type for '%s'.\n" ),
2658 if( aLabel.IsNull() )
2660 ReportMessage( wxString::Format( wxT(
"Could not transfer model data from file '%s'.\n" ),
2667 wxFileName afile( fileName );
2668 std::string pname( afile.GetName().ToUTF8() );
2669 TCollection_ExtendedString partname( pname.c_str() );
2670 TDataStd_Name::Set( aLabel, partname );
2679 TopLoc_Location& aLocation )
2693 lPos.SetTranslation( gp_Vec( aPosition.
x, -aPosition.
y, 0.0 ) );
2698 double boardThickness;
2701 double top = std::max( boardZPos, boardZPos + boardThickness );
2702 double bottom = std::min( boardZPos, boardZPos + boardThickness );
2707 double f_pos, f_thickness;
2711 bottom += f_thickness;
2717 aOffset.
z -= bottom;
2718 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2719 lPos.Multiply( lRot );
2720 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ), M_PI );
2721 lPos.Multiply( lRot );
2726 lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
2727 lPos.Multiply( lRot );
2731 lOff.SetTranslation( gp_Vec( aOffset.
x, aOffset.
y, aOffset.
z ) );
2732 lPos.Multiply( lOff );
2735 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ),
2737 lPos.Multiply( lOrient );
2738 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 1.0, 0.0 ) ),
2740 lPos.Multiply( lOrient );
2741 lOrient.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 1.0, 0.0, 0.0 ) ),
2743 lPos.Multiply( lOrient );
2745 aLocation = TopLoc_Location( lPos );
2752 IGESControl_Controller::Init();
2753 IGESCAFControl_Reader reader;
2754 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2756 if( stat != IFSelect_RetDone )
2760 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2764 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2768 reader.SetColorMode(
true );
2769 reader.SetNameMode(
false );
2770 reader.SetLayerMode(
false );
2772 if( !reader.Transfer( doc ) )
2774 if( doc->CanClose() == CDM_CCS_OK )
2781 if( reader.NbShapes() < 1 )
2783 if( doc->CanClose() == CDM_CCS_OK )
2795 STEPCAFControl_Reader reader;
2796 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
2798 if( stat != IFSelect_RetDone )
2802 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
2806 if( !Interface_Static::SetRVal(
"read.precision.val",
USER_PREC ) )
2810 reader.SetColorMode(
true );
2811 reader.SetNameMode(
true );
2812 reader.SetLayerMode(
false );
2814 if( !reader.Transfer( doc ) )
2816 if( doc->CanClose() == CDM_CCS_OK )
2823 if( reader.NbRootsForTransfer() < 1 )
2825 if( doc->CanClose() == CDM_CCS_OK )
2837#if OCC_VERSION_HEX >= 0x070700
2838 VrmlAPI_CafReader reader;
2839 RWMesh_CoordinateSystemConverter conv;
2840 conv.SetInputLengthUnit( 2.54 );
2841 reader.SetCoordinateSystemConverter( conv );
2842 reader.SetDocument( doc );
2844 if( !reader.Perform( TCollection_AsciiString( fname ), Message_ProgressRange() ) )
2855 Handle( TDocStd_Document ) & dest,
VECTOR3D aScale )
2859 Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
2862 TDF_LabelSequence frshapes;
2863 s_assy->GetFreeShapes( frshapes );
2866 Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
2869 TDF_Label d_targetLabel = d_assy->NewShape();
2871 if( frshapes.Size() == 1 )
2873 TDocStd_XLinkTool link;
2874 link.Copy( d_targetLabel, frshapes.First() );
2879 for( TDF_Label& s_shapeLabel : frshapes )
2881 TDF_Label d_component = d_assy->NewShape();
2883 TDocStd_XLinkTool link;
2884 link.Copy( d_component, s_shapeLabel );
2886 d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
2890 if( aScale.
x != 1.0 || aScale.
y != 1.0 || aScale.
z != 1.0 )
2893 return d_targetLabel;
2901 ReportMessage( wxString::Format( wxT(
"No valid PCB assembly; cannot create output file "
2907 m_outFmt = OUTPUT_FORMAT::FMT_OUT_GLTF;
2909 TDF_LabelSequence freeShapes;
2910 m_assy->GetFreeShapes( freeShapes );
2916 for( Standard_Integer i = 1; i <= freeShapes.Length(); ++i )
2918 TDF_Label label = freeShapes.Value( i );
2920 m_assy->GetShape( label, shape );
2925 const Standard_Real linearDeflection = 0.14;
2926 const Standard_Real angularDeflection =
DEG2RAD( 30.0 );
2927 BRepMesh_IncrementalMesh mesh( shape, linearDeflection, Standard_False, angularDeflection,
2931 wxFileName fn( aFileName );
2933 const char* tmpGltfname =
"$tempfile$.glb";
2934 RWGltf_CafWriter cafWriter( tmpGltfname,
true );
2936 cafWriter.SetTransformationFormat( RWGltf_WriterTrsfFormat_Compact );
2937 cafWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit( 0.001 );
2938 cafWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(
2939 RWMesh_CoordinateSystem_Zup );
2940#if OCC_VERSION_HEX >= 0x070700
2941 cafWriter.SetParallel(
true );
2943 TColStd_IndexedDataMapOfStringString metadata;
2945 metadata.Add( TCollection_AsciiString(
"pcb_name" ),
2946 TCollection_ExtendedString( fn.GetName().wc_str() ) );
2947 metadata.Add( TCollection_AsciiString(
"source_pcb_file" ),
2948 TCollection_ExtendedString( fn.GetFullName().wc_str() ) );
2949 metadata.Add( TCollection_AsciiString(
"generator" ),
2950 TCollection_AsciiString( wxString::Format( wxS(
"KiCad %s" ),
GetSemanticVersion() ).ToAscii() ) );
2951 metadata.Add( TCollection_AsciiString(
"generated_at" ),
2954 bool success =
true;
2957 wxString currCWD = wxGetCwd();
2958 wxString workCWD = fn.GetPath();
2960 if( !workCWD.IsEmpty() )
2961 wxSetWorkingDirectory( workCWD );
2963 success = cafWriter.Perform( m_doc, metadata, Message_ProgressRange() );
2970 if( !wxRenameFile( tmpGltfname, fn.GetFullName(),
true ) )
2972 ReportMessage( wxString::Format( wxT(
"Cannot rename temporary file '%s' to '%s'.\n" ),
2973 tmpGltfname, fn.GetFullName() ) );
2978 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.
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
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.
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