Step exporter: export circular board outlines as cylinder
From master branch, commit 66651327
.
This commit is contained in:
parent
b968bac318
commit
5db9a6af9d
|
@ -657,11 +657,6 @@ void BOARD_ADAPTER::InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningR
|
|||
}
|
||||
|
||||
|
||||
extern bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
|
||||
int aErrorMax, int aChainingEpsilon,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
|
||||
|
||||
|
||||
bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
|
||||
{
|
||||
m_board_poly.RemoveAllContours();
|
||||
|
|
|
@ -2013,13 +2013,14 @@ ZONE* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, PCB_LAYER_
|
|||
|
||||
|
||||
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler )
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler,
|
||||
bool aAllowUseArcsInPolygons )
|
||||
{
|
||||
// max dist from one endPt to next startPt: use the current value
|
||||
int chainingEpsilon = GetOutlinesChainingEpsilon();
|
||||
|
||||
bool success = BuildBoardPolygonOutlines( this, aOutlines, GetDesignSettings().m_MaxError,
|
||||
chainingEpsilon, aErrorHandler );
|
||||
chainingEpsilon, aErrorHandler, aAllowUseArcsInPolygons );
|
||||
|
||||
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
|
||||
aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
|
|
|
@ -664,10 +664,14 @@ public:
|
|||
*
|
||||
* @param aOutlines is the #SHAPE_POLY_SET to fill in with outlines/holes.
|
||||
* @param aErrorHandler is an optional DRC_ITEM error handler.
|
||||
* @param aAllowUseArcsInPolygons = an optional option to allow adding arcs in
|
||||
* SHAPE_LINE_CHAIN polylines/polygons when building outlines from aShapeList
|
||||
* This is mainly for export to STEP files
|
||||
* @return true if success, false if a contour is not valid
|
||||
*/
|
||||
bool GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr,
|
||||
bool aAllowUseArcsInPolygons = false );
|
||||
|
||||
/**
|
||||
* @return a epsilon value that is the max distance between 2 points to see them
|
||||
|
|
|
@ -160,9 +160,7 @@ bool isCopperOutside( const FOOTPRINT* aFootprint, SHAPE_POLY_SET& aShape )
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function ConvertOutlineToPolygon
|
||||
* Build a polygon (with holes) from a PCB_SHAPE list, which is expected to be a closed main
|
||||
/* Build a polygon (with holes) from a PCB_SHAPE list, which is expected to be a closed main
|
||||
* outline with perhaps closed inner outlines. These closed inner outlines are considered as
|
||||
* holes in the main outline.
|
||||
* @param aShapeList the initial list of SHAPEs (only lines, circles and arcs).
|
||||
|
@ -171,10 +169,12 @@ bool isCopperOutside( const FOOTPRINT* aFootprint, SHAPE_POLY_SET& aShape )
|
|||
* @param aChainingEpsilon is the max error distance when polygonizing a curve (internal units)
|
||||
* @param aAllowDisjoint indicates multiple top-level outlines are allowed
|
||||
* @param aErrorHandler = an optional error handler
|
||||
* @param aAllowUseArcsInPolygons = an optional option to allow adding arcs in
|
||||
* SHAPE_LINE_CHAIN polylines/polygons when building outlines from aShapeList
|
||||
*/
|
||||
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_SET& aPolygons,
|
||||
int aErrorMax, int aChainingEpsilon, bool aAllowDisjoint,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler )
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons )
|
||||
{
|
||||
if( aShapeList.size() == 0 )
|
||||
return true;
|
||||
|
@ -249,30 +249,25 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& 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 )
|
||||
// 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 )
|
||||
{
|
||||
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;
|
||||
shapeOwners[ std::make_pair( currContour.CPoint( ii-1 ),
|
||||
currContour.CPoint( ii ) ) ] = graphic;
|
||||
}
|
||||
|
||||
currContour.SetClosed( true );
|
||||
if( !aAllowUseArcsInPolygons )
|
||||
currContour.ClearArcs();
|
||||
}
|
||||
else if( graphic->GetShape() == SHAPE_T::RECT )
|
||||
{
|
||||
|
@ -615,7 +610,8 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_SE
|
|||
* All contours should be closed, i.e. valid closed polygon vertices
|
||||
*/
|
||||
bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aErrorMax,
|
||||
int aChainingEpsilon, OUTLINE_ERROR_HANDLER* aErrorHandler )
|
||||
int aChainingEpsilon, OUTLINE_ERROR_HANDLER* aErrorHandler,
|
||||
bool aAllowUseArcsInPolygons )
|
||||
{
|
||||
PCB_TYPE_COLLECTOR items;
|
||||
bool success = false;
|
||||
|
@ -650,7 +646,7 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aE
|
|||
false,
|
||||
// don't report errors here; the second pass also
|
||||
// gets an opportunity to use these segments
|
||||
nullptr );
|
||||
nullptr, aAllowUseArcsInPolygons );
|
||||
|
||||
// Here, we test to see if we should make holes or outlines. Holes are made if the footprint
|
||||
// has copper outside of a single, closed outline. If there are multiple outlines, we assume
|
||||
|
@ -688,7 +684,7 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, int aE
|
|||
if( segList.size() )
|
||||
{
|
||||
success = ConvertOutlineToPolygon( segList, aOutlines, aErrorMax, aChainingEpsilon,
|
||||
true, aErrorHandler );
|
||||
true, aErrorHandler, aAllowUseArcsInPolygons );
|
||||
}
|
||||
|
||||
if( !success || !aOutlines.OutlineCount() )
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -43,19 +43,47 @@ const std::function<void( const wxString& msg, BOARD_ITEM* itemA, BOARD_ITEM* it
|
|||
* @param aChainingEpsilon is the max distance from one endPt to the next startPt (internal units)
|
||||
* @param aAllowDisjoint indicates multiple top-level outlines are allowed
|
||||
* @param aErrorHandler = an optional error handler
|
||||
* @param aAllowUseArcsInPolygons = an optional option to allow adding arcs in
|
||||
* SHAPE_LINE_CHAIN polylines/polygons when building outlines from aShapeList
|
||||
* This is mainly for export to STEP files
|
||||
* @return true if success, false if a contour is not valid (self intersecting)
|
||||
*/
|
||||
bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_SET& aPolygons,
|
||||
int aErrorMax, int aChainingEpsilon, bool aAllowDisjoint,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler );
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler, bool aAllowUseArcsInPolygons = false );
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the board outlines and build a closed polygon from lines, arcs and circle items on
|
||||
* edge cut layer. Any closed outline inside the main outline is a hole. All contours should be
|
||||
* closed, i.e. are valid vertices for a closed polygon.
|
||||
* @param aBoard is the board to build outlines
|
||||
* @param aOutlines will contain the outlines ( complex polygons ).
|
||||
* @param aErrorMax is the max error distance when polygonizing a curve (internal units)
|
||||
* @param aChainingEpsilon is the max distance from one endPt to the next startPt (internal units)
|
||||
* @param aErrorHandler = an optional error handler
|
||||
* @param aAllowUseArcsInPolygons = an optional option to allow adding arcs in
|
||||
* SHAPE_LINE_CHAIN polylines/polygons when building outlines from aShapeList
|
||||
* This is mainly for export to STEP files
|
||||
* @return true if success, false if a contour is not valid
|
||||
*/
|
||||
extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
|
||||
int aErrorMax, int aChainingEpsilon,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr,
|
||||
bool aAllowUseArcsInPolygons = false );
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to extract a board outline for a footprint view.
|
||||
*
|
||||
* Notes:
|
||||
* * Incomplete outlines will be closed by joining the end of the outline onto the bounding box
|
||||
* (by simply projecting the end points) and then take the area that contains the copper.
|
||||
* * If all copper lies inside a closed outline, than that outline will be treated as an external
|
||||
* board outline.
|
||||
* * If copper is located outside a closed outline, then that outline will be treated as a hole,
|
||||
* and the outer edge will be formed using the bounding box.
|
||||
*/
|
||||
bool BuildFootprintPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
|
||||
int aErrorMax, int aChainingEpsilon,
|
||||
OUTLINE_ERROR_HANDLER* aErrorHandler = nullptr );
|
||||
|
|
|
@ -245,7 +245,9 @@ bool EXPORTER_STEP::composePCB()
|
|||
|
||||
SHAPE_POLY_SET pcbOutlines; // stores the board main outlines
|
||||
|
||||
if( !m_board->GetBoardPolygonOutlines( pcbOutlines ) )
|
||||
if( !m_board->GetBoardPolygonOutlines( pcbOutlines,
|
||||
/* error handler */ nullptr,
|
||||
/* allows use arcs in outlines */ true ) )
|
||||
{
|
||||
wxLogWarning( _( "Board outline is malformed. Run DRC for a full analysis." ) );
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -240,7 +240,7 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
|
|||
|
||||
if( holeOutlines.OutlineCount() > 0 )
|
||||
{
|
||||
if( MakeShape( hole, holeOutlines.COutline( 0 ), m_thickness, aOrigin ) )
|
||||
if( MakeShape( hole, holeOutlines.COutline( 0 ), m_thickness, 0.0, aOrigin ) )
|
||||
{
|
||||
m_cutouts.push_back( hole );
|
||||
}
|
||||
|
@ -343,9 +343,28 @@ 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<SHAPE_ARC>& arcs = aChain.CArcs();
|
||||
|
||||
bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain,
|
||||
double aThickness, const VECTOR2D& aOrigin )
|
||||
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
|
||||
|
@ -353,12 +372,47 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC
|
|||
if( !aChain.IsClosed() )
|
||||
return false; // the loop is not closed
|
||||
|
||||
const std::vector<SHAPE_ARC>& 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 )
|
||||
{
|
||||
if( !aShape.IsNull() )
|
||||
return false; // there is already data in the shape object
|
||||
|
||||
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;
|
||||
TopoDS_Edge edge;
|
||||
bool success = true;
|
||||
|
||||
gp_Pnt start = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( 0 ).x - aOrigin.x ),
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), 0.0 );
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), aZposition );
|
||||
|
||||
for( int j = 0; j < aChain.PointCount(); j++ )
|
||||
{
|
||||
|
@ -369,12 +423,12 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC
|
|||
if( next >= aChain.PointCount() )
|
||||
{
|
||||
end = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( 0 ).x - aOrigin.x ),
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), 0.0 );
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), aZposition );
|
||||
}
|
||||
else
|
||||
{
|
||||
end = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( next ).x - aOrigin.x ),
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( next ).y - aOrigin.y ), 0.0 );
|
||||
-pcbIUScale.IUTomm( aChain.CPoint( next ).y - aOrigin.y ), aZposition );
|
||||
}
|
||||
|
||||
// Do not export very small segments: they can create broken outlines
|
||||
|
@ -460,7 +514,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
|
|||
|
||||
TopoDS_Shape curr_brd;
|
||||
|
||||
if( !MakeShape( curr_brd, outline, m_thickness, aOrigin ) )
|
||||
if( !MakeShape( curr_brd, outline, m_thickness, 0.0, aOrigin ) )
|
||||
{
|
||||
// Error
|
||||
ReportMessage( wxString::Format(
|
||||
|
@ -482,7 +536,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
|
|||
const SHAPE_LINE_CHAIN& holeOutline = aOutline.Hole( cnt, ii );
|
||||
TopoDS_Shape hole;
|
||||
|
||||
if( MakeShape( hole, holeOutline, m_thickness, aOrigin ) )
|
||||
if( MakeShape( hole, holeOutline, m_thickness, 0.0, aOrigin ) )
|
||||
{
|
||||
m_cutouts.push_back( hole );
|
||||
}
|
||||
|
|
|
@ -83,8 +83,29 @@ 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,
|
||||
const VECTOR2D& aOrigin );
|
||||
/**
|
||||
* 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
|
||||
|
|
Loading…
Reference in New Issue