diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index d33e79f880..ac498bc15c 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -138,6 +138,38 @@ double EDA_SHAPE::GetLength() const } +bool EDA_SHAPE::IsClosed() const +{ + switch( m_shape ) + { + case SHAPE_T::CIRCLE: + case SHAPE_T::RECT: + return true; + + case SHAPE_T::ARC: + case SHAPE_T::SEGMENT: + return false; + + case SHAPE_T::POLY: + if( m_poly.IsEmpty() ) + return false; + else + return m_poly.Outline( 0 ).IsClosed(); + + case SHAPE_T::BEZIER: + if( m_bezierPoints.size() < 3 ) + return false; + else + return m_bezierPoints[0] == m_bezierPoints[ m_bezierPoints.size() - 1 ]; + + default: + UNIMPLEMENTED_FOR( SHAPE_T_asString() ); + return false; + } +} + + + void EDA_SHAPE::move( const VECTOR2I& aMoveVector ) { switch ( m_shape ) diff --git a/include/eda_shape.h b/include/eda_shape.h index f93e861d56..7d59a62a8a 100644 --- a/include/eda_shape.h +++ b/include/eda_shape.h @@ -100,6 +100,8 @@ public: void SetFillMode( FILL_T aFill ) { m_fill = aFill; } FILL_T GetFillMode() const { return m_fill; } + bool IsClosed() const; + COLOR4D GetFillColor() const { return m_fillColor; } void SetFillColor( const COLOR4D& aColor ) { m_fillColor = aColor; } diff --git a/pcbnew/pcbnew_settings.h b/pcbnew/pcbnew_settings.h index 8960bb411e..bd1105bba9 100644 --- a/pcbnew/pcbnew_settings.h +++ b/pcbnew/pcbnew_settings.h @@ -34,6 +34,7 @@ namespace PNS // Settings for the CONVERT_TOOL. struct CONVERT_SETTINGS { + bool m_StrokeHulls; bool m_IgnoreLineWidths; bool m_DeleteOriginals; }; diff --git a/pcbnew/tools/convert_tool.cpp b/pcbnew/tools/convert_tool.cpp index 427b78cbaf..5482465a20 100644 --- a/pcbnew/tools/convert_tool.cpp +++ b/pcbnew/tools/convert_tool.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "convert_tool.h" @@ -203,7 +204,6 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) PCB_LAYER_ID destLayer = m_frame->GetActiveLayer(); FOOTPRINT* parentFootprint = nullptr; bool foundChainedSegs = false; - bool foundFilledShape = false; PCB_SELECTION& selection = m_selectionTool->RequestSelection( []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) @@ -219,23 +219,28 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) polys.clear(); for( EDA_ITEM* item : selection ) - { item->ClearTempFlags(); - if( item->Type() == PCB_SHAPE_T || item->Type() == PCB_FP_SHAPE_T ) - foundFilledShape = static_cast( item )->IsFilled(); - } - SHAPE_POLY_SET polySet; + SHAPE_POLY_SET temp; - if( convertSettings.m_IgnoreLineWidths ) + polySet.Append( makePolysFromClosedGraphics( selection.GetItems(), + convertSettings.m_IgnoreLineWidths ) ); + + temp = makePolysFromChainedSegs( selection.GetItems() ); + + if( !temp.IsEmpty() ) { - polySet.Append( makePolysFromChainedSegs( selection.GetItems() ) ); - foundChainedSegs = polySet.OutlineCount() > 0; + polySet.Append( temp ); + foundChainedSegs = true; + } + else + { + for( EDA_ITEM* item : selection ) + item->ClearTempFlags(); } - polySet.Append( makePolysFromGraphics( selection.GetItems(), - convertSettings.m_IgnoreLineWidths ) ); + polySet.Append( makePolysFromOpenGraphics( selection.GetItems() ) ); if( polySet.IsEmpty() ) return false; @@ -257,8 +262,8 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) // to true. // We also use the pre-flight to keep from putting up any of the dialogs if there's nothing // to convert. - convertSettings.m_IgnoreLineWidths = true; - convertSettings.m_DeleteOriginals = false; + convertSettings.m_IgnoreLineWidths = false; + convertSettings.m_DeleteOriginals = true; if( !getPolys() ) return 0; @@ -294,7 +299,6 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent ) PCB_SHAPE* graphic = isFootprint ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE; graphic->SetShape( SHAPE_T::POLY ); - graphic->SetFilled( !convertSettings.m_IgnoreLineWidths || foundFilledShape ); graphic->SetStroke( STROKE_PARAMS( 0, PLOT_DASH_TYPE::SOLID, COLOR4D::UNSPECIFIED ) ); graphic->SetLayer( destLayer ); graphic->SetPolyShape( poly ); @@ -572,8 +576,7 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromChainedSegs( const std::deque& aItems, - bool aIgnoreLineWidths ) +SHAPE_POLY_SET CONVERT_TOOL::makePolysFromOpenGraphics( const std::deque& aItems ) { BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); SHAPE_POLY_SET poly; @@ -590,9 +593,46 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromGraphics( const std::deque& { PCB_SHAPE* temp = static_cast( item->Clone() ); - if( aIgnoreLineWidths ) - temp->SetFilled( true ); + if( temp->IsClosed() ) + continue; + temp->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError, ERROR_INSIDE, + false ); + item->SetFlags( SKIP_STRUCT ); + break; + } + + default: + continue; + } + } + + return poly; +} + + +SHAPE_POLY_SET CONVERT_TOOL::makePolysFromClosedGraphics( const std::deque& aItems, + bool aIgnoreLineWidths ) +{ + BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); + SHAPE_POLY_SET poly; + + for( EDA_ITEM* item : aItems ) + { + if( item->GetFlags() & SKIP_STRUCT ) + continue; + + switch( item->Type() ) + { + case PCB_SHAPE_T: + case PCB_FP_SHAPE_T: + { + PCB_SHAPE* temp = static_cast( item->Clone() ); + + if( !temp->IsClosed() ) + continue; + + temp->SetFilled( true ); temp->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError, ERROR_INSIDE, aIgnoreLineWidths ); item->SetFlags( SKIP_STRUCT ); diff --git a/pcbnew/tools/convert_tool.h b/pcbnew/tools/convert_tool.h index 2c43ef3312..98049f77a2 100644 --- a/pcbnew/tools/convert_tool.h +++ b/pcbnew/tools/convert_tool.h @@ -90,8 +90,9 @@ private: * @param aItems is a list of items to process. * @return a #SHAPE_POLY_SET containing any polygons that were created. */ - SHAPE_POLY_SET makePolysFromGraphics( const std::deque& aItems, - bool aIgnoreLineWidths ); + SHAPE_POLY_SET makePolysFromOpenGraphics( const std::deque& aItems ); + SHAPE_POLY_SET makePolysFromClosedGraphics( const std::deque& aItems, + bool aIgnoreLineWidths ); PCB_SELECTION_TOOL* m_selectionTool; CONDITIONAL_MENU* m_menu;