From 52fcddf4f448c9c1bbbad3cd02aea437bee3df3c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 2 Mar 2018 10:55:59 +0100 Subject: [PATCH] Allow drawing self-intersecting polygons, just display a warning Fixes: lp:1751654 * https://bugs.launchpad.net/kicad/+bug/1751654 --- common/preview_items/polygon_geom_manager.cpp | 27 ++++++++++++++----- include/preview_items/polygon_geom_manager.h | 7 +++++ pcbnew/tools/drawing_tool.cpp | 24 ++++++++++------- pcbnew/tools/point_editor.cpp | 14 +++++----- pcbnew/tools/zone_create_helper.cpp | 9 ++++--- 5 files changed, 55 insertions(+), 26 deletions(-) diff --git a/common/preview_items/polygon_geom_manager.cpp b/common/preview_items/polygon_geom_manager.cpp index 7c22632d6f..379f535426 100644 --- a/common/preview_items/polygon_geom_manager.cpp +++ b/common/preview_items/polygon_geom_manager.cpp @@ -29,7 +29,7 @@ POLYGON_GEOM_MANAGER::POLYGON_GEOM_MANAGER( CLIENT& aClient ): m_client( aClient ), m_leaderMode( LEADER_MODE::DIRECT ), - m_intersectionsAllowed( false ) + m_intersectionsAllowed( true ) {} @@ -53,12 +53,8 @@ bool POLYGON_GEOM_MANAGER::AddPoint( const VECTOR2I& aPt ) m_lockedPoints.Append( aPt ); } - // check for self-intersections (line chain needs to be set as closed for proper checks) - m_lockedPoints.SetClosed( true ); - bool selfIntersect = !!m_lockedPoints.SelfIntersecting(); - m_lockedPoints.SetClosed( false ); - - if( !m_intersectionsAllowed && selfIntersect ) + // check for self-intersections + if( !m_intersectionsAllowed && IsSelfIntersecting( false ) ) { m_lockedPoints.Remove( m_lockedPoints.PointCount() - 1 ); return false; @@ -81,6 +77,23 @@ void POLYGON_GEOM_MANAGER::SetLeaderMode( LEADER_MODE aMode ) } +bool POLYGON_GEOM_MANAGER::IsSelfIntersecting( bool aIncludeLeaderPts ) const +{ + auto pts( m_lockedPoints ); + + if( aIncludeLeaderPts ) + { + for( int i = 0; i < m_leaderPts.PointCount(); ++i ) + pts.Append( m_leaderPts.CPoint( i ) ); + } + + // line chain needs to be set as closed for proper checks + pts.SetClosed( true ); + + return !!pts.SelfIntersecting(); +} + + void POLYGON_GEOM_MANAGER::SetCursorPosition( const VECTOR2I& aPos, LEADER_MODE aModifier ) { updateLeaderPoints( aPos, aModifier ); diff --git a/include/preview_items/polygon_geom_manager.h b/include/preview_items/polygon_geom_manager.h index 500af71994..101a83181a 100644 --- a/include/preview_items/polygon_geom_manager.h +++ b/include/preview_items/polygon_geom_manager.h @@ -113,6 +113,13 @@ public: return m_intersectionsAllowed; } + /** + * Checks whether the locked points constitute a self-intersecting outline. + * @param aIncludeLeaderPts when true, also the leading points (not placed ones) will be tested. + * @return True when the outline is self-intersecting. + */ + bool IsSelfIntersecting( bool aIncludeLeaderPts ) const; + /** * Set the current cursor position */ diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index b5715c8ea1..1a78a3cb7f 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -1253,7 +1253,10 @@ void DRAWING_TOOL::runPolygonEventLoop( POLYGON_GEOM_MANAGER& polyGeomMgr ) { auto& controls = *getViewControls(); bool started = false; + STATUS_TEXT_POPUP status( m_frame ); + status.SetTextColor( wxColour( 255, 0, 0 ) ); + status.SetText( _( "Self-intersecting polygons are not allowed" ) ); while( OPT_TOOL_EVENT evt = Wait() ) { @@ -1310,15 +1313,6 @@ void DRAWING_TOOL::runPolygonEventLoop( POLYGON_GEOM_MANAGER& polyGeomMgr ) controls.CaptureCursor( true ); } } - else if( started ) - { - status.SetTextColor( wxColour( 255, 0, 0 ) ); - status.SetText( _( "Self-intersecting polygons are not allowed" ) ); - wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 ); - status.Move( p ); - status.Popup( m_frame ); - status.Expire( 1500 ); - } } else if( evt->IsAction( &deleteLastPoint ) ) @@ -1342,6 +1336,18 @@ void DRAWING_TOOL::runPolygonEventLoop( POLYGON_GEOM_MANAGER& polyGeomMgr ) polyGeomMgr.SetCursorPosition( cursorPos, evt->Modifier( MD_CTRL ) ? POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 : POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT ); + + if( polyGeomMgr.IsSelfIntersecting( true ) ) + { + wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 ); + status.Move( p ); + status.Popup( m_frame ); + status.Expire( 1500 ); + } + else + { + status.Hide(); + } } } // end while } diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index f927afc373..b453924390 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -229,7 +229,10 @@ void POINT_EDITOR::Reset( RESET_REASON aReason ) m_editPoints.reset(); m_altConstraint.reset(); getViewControls()->SetAutoPan( false ); + m_statusPopup.reset( new STATUS_TEXT_POPUP( getEditFrame() ) ); + m_statusPopup->SetTextColor( wxColour( 255, 0, 0 ) ); + m_statusPopup->SetText( _( "Self-intersecting polygons are not allowed" ) ); } @@ -473,13 +476,12 @@ void POINT_EDITOR::updateItem() const case S_POLYGON: { - SHAPE_POLY_SET originalPoly = segment->GetPolyShape(); SHAPE_POLY_SET& outline = segment->GetPolyShape(); for( int i = 0; i < outline.TotalVertices(); ++i ) outline.Vertex( i ) = m_editPoints->Point( i ).GetPosition(); - validatePolygon( outline, &originalPoly ); + validatePolygon( outline ); break; } @@ -499,12 +501,11 @@ void POINT_EDITOR::updateItem() const ZONE_CONTAINER* zone = static_cast( item ); zone->ClearFilledPolysList(); SHAPE_POLY_SET& outline = *zone->Outline(); - SHAPE_POLY_SET originalPoly( outline ); for( int i = 0; i < outline.TotalVertices(); ++i ) outline.Vertex( i ) = m_editPoints->Point( i ).GetPosition(); - validatePolygon( outline, &originalPoly ); + validatePolygon( outline ); zone->Hatch(); break; } @@ -586,12 +587,13 @@ void POINT_EDITOR::finishItem() bool POINT_EDITOR::validatePolygon( SHAPE_POLY_SET& aModified, const SHAPE_POLY_SET* aOriginal ) const { if( !aModified.IsSelfIntersecting() ) + { + m_statusPopup->Hide(); return true; + } if( m_statusPopup ) { - m_statusPopup->SetTextColor( wxColour( 255, 0, 0 ) ); - m_statusPopup->SetText( _( "Self-intersecting polygons are not allowed" ) ); wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 ); m_statusPopup->Move( p ); m_statusPopup->Popup( getEditFrame() ); diff --git a/pcbnew/tools/zone_create_helper.cpp b/pcbnew/tools/zone_create_helper.cpp index 88440aebea..d248875a7d 100644 --- a/pcbnew/tools/zone_create_helper.cpp +++ b/pcbnew/tools/zone_create_helper.cpp @@ -65,7 +65,7 @@ std::unique_ptr ZONE_CREATE_HELPER::createNewZone( bool aKeepout zoneInfo.m_NetcodeSelection = board.GetHighLightNetCode(); zoneInfo.SetIsKeepout( m_params.m_keepout ); - if ( m_params.m_mode != DRAWING_TOOL::ZONE_MODE::GRAPHIC_POLYGON ) + if( m_params.m_mode != DRAWING_TOOL::ZONE_MODE::GRAPHIC_POLYGON ) { // Get the current default settings for zones @@ -249,14 +249,15 @@ void ZONE_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) // if m_params.m_mode == DRAWING_TOOL::ZONE_MODE::CUTOUT, m_zone // will be merged to the existing zone as a new hole. m_zone->Outline()->NewOutline(); + auto* outline = m_zone->Outline(); for( int i = 0; i < finalPoints.PointCount(); ++i ) { - m_zone->Outline()->Append( finalPoints.CPoint( i ) ); + outline->Append( finalPoints.CPoint( i ) ); } - m_zone->Outline()->Outline( 0 ).SetClosed( true ); - m_zone->Outline()->RemoveNullSegments(); + outline->Outline( 0 ).SetClosed( true ); + outline->RemoveNullSegments(); // hand the zone over to the committer commitZone( std::move( m_zone ) );