Point Editor: prevent creation of self-intersecting polygons
This commit is contained in:
parent
fe0e44ba3d
commit
dd97718a50
|
@ -36,6 +36,7 @@ using namespace std::placeholders;
|
|||
#include "point_editor.h"
|
||||
#include <board_commit.h>
|
||||
#include <bitmaps.h>
|
||||
#include <status_popup.h>
|
||||
|
||||
#include <pcb_edit_frame.h>
|
||||
#include <class_edge_mod.h>
|
||||
|
@ -228,6 +229,7 @@ void POINT_EDITOR::Reset( RESET_REASON aReason )
|
|||
m_editPoints.reset();
|
||||
m_altConstraint.reset();
|
||||
getViewControls()->SetAutoPan( false );
|
||||
m_statusPopup.reset( new STATUS_TEXT_POPUP( getEditFrame<PCB_BASE_EDIT_FRAME>() ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -471,13 +473,14 @@ void POINT_EDITOR::updateItem() const
|
|||
|
||||
case S_POLYGON:
|
||||
{
|
||||
SHAPE_POLY_SET* outline = &segment->GetPolyShape();
|
||||
SHAPE_POLY_SET originalPoly = segment->GetPolyShape();
|
||||
SHAPE_POLY_SET& outline = segment->GetPolyShape();
|
||||
|
||||
for( int i = 0; i < outline->TotalVertices(); ++i )
|
||||
{
|
||||
VECTOR2I point = m_editPoints->Point( i ).GetPosition();
|
||||
outline->Vertex( i ) = point;
|
||||
}
|
||||
for( int i = 0; i < outline.TotalVertices(); ++i )
|
||||
outline.Vertex( i ) = m_editPoints->Point( i ).GetPosition();
|
||||
|
||||
validatePolygon( outline, &originalPoly );
|
||||
break;
|
||||
}
|
||||
|
||||
default: // suppress warnings
|
||||
|
@ -495,16 +498,14 @@ void POINT_EDITOR::updateItem() const
|
|||
{
|
||||
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
|
||||
zone->ClearFilledPolysList();
|
||||
SHAPE_POLY_SET* outline = zone->Outline();
|
||||
SHAPE_POLY_SET& outline = *zone->Outline();
|
||||
SHAPE_POLY_SET originalPoly( outline );
|
||||
|
||||
for( int i = 0; i < outline->TotalVertices(); ++i )
|
||||
{
|
||||
VECTOR2I point = m_editPoints->Point( i ).GetPosition();
|
||||
outline->Vertex( i ) = point;
|
||||
}
|
||||
for( int i = 0; i < outline.TotalVertices(); ++i )
|
||||
outline.Vertex( i ) = m_editPoints->Point( i ).GetPosition();
|
||||
|
||||
validatePolygon( outline, &originalPoly );
|
||||
zone->Hatch();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -565,6 +566,7 @@ void POINT_EDITOR::updateItem() const
|
|||
void POINT_EDITOR::finishItem()
|
||||
{
|
||||
auto item = m_editPoints->GetParent();
|
||||
|
||||
if( !item )
|
||||
return;
|
||||
|
||||
|
@ -581,6 +583,28 @@ void POINT_EDITOR::finishItem()
|
|||
}
|
||||
|
||||
|
||||
bool POINT_EDITOR::validatePolygon( SHAPE_POLY_SET& aModified, const SHAPE_POLY_SET* aOriginal ) const
|
||||
{
|
||||
if( !aModified.IsSelfIntersecting() )
|
||||
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<PCB_BASE_FRAME>() );
|
||||
m_statusPopup->Expire( 1500 );
|
||||
}
|
||||
|
||||
if( aOriginal )
|
||||
aModified = *aOriginal;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void POINT_EDITOR::updatePoints()
|
||||
{
|
||||
if( !m_editPoints )
|
||||
|
@ -992,12 +1016,14 @@ int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
|
|||
{
|
||||
const auto& vertexIdx = vertex.second;
|
||||
auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
|
||||
bool valid = true;
|
||||
|
||||
if( outline.PointCount() > 3 )
|
||||
{
|
||||
// the usual case: remove just the corner when there are >3 vertices
|
||||
commit.Modify( item );
|
||||
polygon->RemoveVertex( vertexIdx );
|
||||
valid = validatePolygon( *polygon );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1016,7 +1042,16 @@ int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
setEditedPoint( nullptr );
|
||||
commit.Push( _( "Remove a zone/polygon corner" ) );
|
||||
|
||||
if( valid )
|
||||
commit.Push( _( "Remove a zone/polygon corner" ) );
|
||||
else
|
||||
commit.Revert();
|
||||
|
||||
// Refresh zone hatching
|
||||
if( item->Type() == PCB_ZONE_AREA_T)
|
||||
static_cast<ZONE_CONTAINER*>( item )->Hatch();
|
||||
|
||||
updatePoints();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,11 +27,13 @@
|
|||
|
||||
#include <tool/tool_interactive.h>
|
||||
#include "edit_points.h"
|
||||
#include <status_popup.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
class SELECTION_TOOL;
|
||||
class SHAPE_POLY_SET;
|
||||
|
||||
/**
|
||||
* Class POINT_EDITOR
|
||||
|
@ -78,12 +80,22 @@ private:
|
|||
// EDIT_POINT for alternative constraint mode
|
||||
EDIT_POINT m_altConstrainer;
|
||||
|
||||
std::unique_ptr<STATUS_TEXT_POPUP> m_statusPopup;
|
||||
|
||||
///> Updates item's points with edit points.
|
||||
void updateItem() const;
|
||||
|
||||
///> Applies the last changes to the edited item.
|
||||
void finishItem();
|
||||
|
||||
/**
|
||||
* Validates a polygon and restores it to its original version if available.
|
||||
* @param aModified is the polygon to be checked.
|
||||
* @param aOriginal is the original copy that will be used to restore its state.
|
||||
* @return True if polygon is valid.
|
||||
*/
|
||||
bool validatePolygon( SHAPE_POLY_SET& aModified, const SHAPE_POLY_SET* aOriginal = nullptr ) const;
|
||||
|
||||
///> Updates edit points with item's points.
|
||||
void updatePoints();
|
||||
|
||||
|
|
Loading…
Reference in New Issue