From 09515fe821cf1049e98ab90a0b992b631fbdc648 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Tue, 16 May 2023 08:44:36 +0200 Subject: [PATCH] STEP export: in board outlines, export Circles as Cylinders. Other arcs (not 360 deg arcs) are still exported as polylines --- pcbnew/convert_shape_list_to_polygon.cpp | 30 +++++-------- pcbnew/exporters/step/step_pcb_model.cpp | 54 ++++++++++++++++++++++++ pcbnew/exporters/step/step_pcb_model.h | 23 +++++++++- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/pcbnew/convert_shape_list_to_polygon.cpp b/pcbnew/convert_shape_list_to_polygon.cpp index 85a7a7ee4b..ba52edfc9f 100644 --- a/pcbnew/convert_shape_list_to_polygon.cpp +++ b/pcbnew/convert_shape_list_to_polygon.cpp @@ -238,30 +238,22 @@ bool ConvertOutlineToPolygon( std::vector& aShapeList, SHAPE_POLY_SE } else if( graphic->GetShape() == SHAPE_T::CIRCLE ) { - // make a circle by segments; VECTOR2I center = graphic->GetCenter(); - VECTOR2I start = center; int radius = graphic->GetRadius(); - int steps = GetArcToSegmentCount( radius, aErrorMax, FULL_CIRCLE ); - VECTOR2I nextPt; - + VECTOR2I start = center; start.x += radius; - for( int step = 0; step < steps; ++step ) - { - nextPt = start; - RotatePoint( nextPt, center, ANGLE_360 * step / steps ); - currContour.Append( nextPt ); - - if( firstPt ) - firstPt = false; - else - shapeOwners[ std::make_pair( prevPt, nextPt ) ] = graphic; - - prevPt = nextPt; - } - + // Add 360 deg Arc in currContour + SHAPE_ARC arc360( center, start, ANGLE_360, 0 ); + currContour.Append( arc360, aErrorMax ); currContour.SetClosed( true ); + + // set shapeOwners for currContour points created by appending the arc360: + for( int ii = 1; ii < currContour.PointCount(); ++ii ) + { + shapeOwners[ std::make_pair( currContour.CPoint( ii-1 ), + currContour.CPoint( ii ) ) ] = graphic; + } } else if( graphic->GetShape() == SHAPE_T::RECT ) { diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp index bfb978b6ed..42b2eb7df2 100644 --- a/pcbnew/exporters/step/step_pcb_model.cpp +++ b/pcbnew/exporters/step/step_pcb_model.cpp @@ -415,6 +415,56 @@ bool STEP_PCB_MODEL::isBoardOutlineValid() return m_pcb_labels.size() > 0; } +// A helper function to know if a SHAPE_LINE_CHAIN is encoding a circle +static bool IsChainCircle( const SHAPE_LINE_CHAIN& aChain ) +{ + // If aChain is a circle it + // - contains only one arc + // - this arc has the same start and end point + const std::vector& arcs = aChain.CArcs(); + + if( arcs.size() == 1 ) + { + const SHAPE_ARC& arc = arcs[0]; + + if( arc. GetP0() == arc.GetP1() ) + return true; + } + + return false; +} + +bool STEP_PCB_MODEL::MakeShapeAsCylinder( TopoDS_Shape& aShape, + const SHAPE_LINE_CHAIN& aChain, double aThickness, + double aZposition, const VECTOR2D& aOrigin ) +{ + if( !aShape.IsNull() ) + return false; // there is already data in the shape object + + if( !aChain.IsClosed() ) + return false; // the loop is not closed + + const std::vector& arcs = aChain.CArcs(); + const SHAPE_ARC& arc = arcs[0]; + + TopoDS_Shape base_shape; + base_shape = BRepPrimAPI_MakeCylinder( + pcbIUScale.IUTomm( arc.GetRadius() ), aThickness ).Shape(); + gp_Trsf shift; + shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( arc.GetCenter().x - aOrigin.x ), + -pcbIUScale.IUTomm( arc.GetCenter().y - aOrigin.y ), + aZposition ) ); + BRepBuilderAPI_Transform round_shape( base_shape, shift ); + aShape = round_shape; + + if( aShape.IsNull() ) + { + ReportMessage( wxT( "failed to create a cylinder vertical shape\n" ) ); + return false; + } + + return true; +} bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain, double aThickness, double aZposition, const VECTOR2D& aOrigin ) @@ -425,6 +475,10 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC if( !aChain.IsClosed() ) return false; // the loop is not closed + // a SHAPE_LINE_CHAIN that is in fact a circle (one 360deg arc) is exported as cylinder + if( IsChainCircle( aChain ) ) + return MakeShapeAsCylinder( aShape, aChain, aThickness, aZposition, aOrigin ); + BRepBuilderAPI_MakeWire wire; bool success = true; diff --git a/pcbnew/exporters/step/step_pcb_model.h b/pcbnew/exporters/step/step_pcb_model.h index 0c6db1594b..71c809d2b7 100644 --- a/pcbnew/exporters/step/step_pcb_model.h +++ b/pcbnew/exporters/step/step_pcb_model.h @@ -111,9 +111,30 @@ public: // create the PCB model using the current outlines and drill holes bool CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin ); - bool MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& chain, double aThickness, + /** + * Convert a SHAPE_LINE_CHAIN (closed) to a TopoDS_Shape (polygonal vertical prism) + * @param aShape is the TopoDS_Shape to initialize (must be empty) + * @param aChain is a closed SHAPE_LINE_CHAIN (a polygon) + * @param aThickness is the height of the created prism + * @param aOrigin is the origin of the coordinates + * @return true if success + */ + bool MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain, double aThickness, double aZposition, const VECTOR2D& aOrigin ); + /** + * Convert a SHAPE_LINE_CHAIN containing only one 360 deg arc to a TopoDS_Shape + * ( vertical cylinder) + * it is a specialized version of MakeShape() + * @param aShape is the TopoDS_Shape to initialize (must be empty) + * @param aChain is a closed SHAPE_LINE_CHAIN, image of a circle: containing one 360 deg arc + * @param aThickness is the height of the created cylinder + * @param aOrigin is the origin of the coordinates + * @return true if success + */ + bool MakeShapeAsCylinder( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain, + double aThickness, double aZposition, const VECTOR2D& aOrigin ); + #ifdef SUPPORTS_IGES // write the assembly model in IGES format bool WriteIGES( const wxString& aFileName );