Allow edits to self-intersecting polygons.
1) Intermediate states might be self-intersecting, and we shouldn't
be policing our users on what order to do things in
2) The polygon might already be self-intersecting, at which point we're
preventing the user from fixing it.
Also includes better const management for SHAPE_POLY_SET API.
Fixes: lp:1833831
* https://bugs.launchpad.net/kicad/+bug/1833831
(cherry picked from commit a3c74051c2
)
This commit is contained in:
parent
269f88ee28
commit
16f9e697ab
|
@ -396,12 +396,12 @@ bool SHAPE_POLY_SET::GetNeighbourIndexes( int aGlobalIndex, int* aPrevious, int*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::IsPolygonSelfIntersecting( int aPolygonIndex )
|
bool SHAPE_POLY_SET::IsPolygonSelfIntersecting( int aPolygonIndex ) const
|
||||||
{
|
{
|
||||||
SEGMENT_ITERATOR iterator = IterateSegmentsWithHoles( aPolygonIndex );
|
CONST_SEGMENT_ITERATOR iterator = CIterateSegmentsWithHoles( aPolygonIndex );
|
||||||
SEGMENT_ITERATOR innerIterator;
|
CONST_SEGMENT_ITERATOR innerIterator;
|
||||||
|
|
||||||
for( iterator = IterateSegmentsWithHoles( aPolygonIndex ); iterator; iterator++ )
|
for( iterator = CIterateSegmentsWithHoles( aPolygonIndex ); iterator; iterator++ )
|
||||||
{
|
{
|
||||||
SEG firstSegment = *iterator;
|
SEG firstSegment = *iterator;
|
||||||
|
|
||||||
|
@ -423,7 +423,7 @@ bool SHAPE_POLY_SET::IsPolygonSelfIntersecting( int aPolygonIndex )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::IsSelfIntersecting()
|
bool SHAPE_POLY_SET::IsSelfIntersecting() const
|
||||||
{
|
{
|
||||||
for( unsigned int polygon = 0; polygon < m_polys.size(); polygon++ )
|
for( unsigned int polygon = 0; polygon < m_polys.size(); polygon++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -538,14 +538,14 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
* @return bool - true if the aPolygonIndex-th polygon is self intersecting, false
|
* @return bool - true if the aPolygonIndex-th polygon is self intersecting, false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
bool IsPolygonSelfIntersecting( int aPolygonIndex );
|
bool IsPolygonSelfIntersecting( int aPolygonIndex ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function IsSelfIntersecting
|
* Function IsSelfIntersecting
|
||||||
* Checks whether any of the polygons in the set is self intersecting.
|
* Checks whether any of the polygons in the set is self intersecting.
|
||||||
* @return bool - true if any of the polygons is self intersecting, false otherwise.
|
* @return bool - true if any of the polygons is self intersecting, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool IsSelfIntersecting();
|
bool IsSelfIntersecting() const;
|
||||||
|
|
||||||
///> Returns the number of triangulated polygons
|
///> Returns the number of triangulated polygons
|
||||||
unsigned int TriangulatedPolyCount() const { return m_triangulatedPolys.size(); }
|
unsigned int TriangulatedPolyCount() const { return m_triangulatedPolys.size(); }
|
||||||
|
@ -762,12 +762,35 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///> Returns an iterator object, for iterating between aFirst and aLast outline, with or
|
||||||
|
/// without holes (default: without)
|
||||||
|
CONST_SEGMENT_ITERATOR CIterateSegments( int aFirst, int aLast,
|
||||||
|
bool aIterateHoles = false ) const
|
||||||
|
{
|
||||||
|
CONST_SEGMENT_ITERATOR iter;
|
||||||
|
|
||||||
|
iter.m_poly = const_cast<SHAPE_POLY_SET*>( this );
|
||||||
|
iter.m_currentPolygon = aFirst;
|
||||||
|
iter.m_lastPolygon = aLast < 0 ? OutlineCount() - 1 : aLast;
|
||||||
|
iter.m_currentContour = 0;
|
||||||
|
iter.m_currentSegment = 0;
|
||||||
|
iter.m_iterateHoles = aIterateHoles;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
///> Returns an iterator object, for iterating aPolygonIdx-th polygon edges
|
///> Returns an iterator object, for iterating aPolygonIdx-th polygon edges
|
||||||
SEGMENT_ITERATOR IterateSegments( int aPolygonIdx )
|
SEGMENT_ITERATOR IterateSegments( int aPolygonIdx )
|
||||||
{
|
{
|
||||||
return IterateSegments( aPolygonIdx, aPolygonIdx );
|
return IterateSegments( aPolygonIdx, aPolygonIdx );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///> Returns an iterator object, for iterating aPolygonIdx-th polygon edges
|
||||||
|
CONST_SEGMENT_ITERATOR CIterateSegments( int aPolygonIdx ) const
|
||||||
|
{
|
||||||
|
return CIterateSegments( aPolygonIdx, aPolygonIdx );
|
||||||
|
}
|
||||||
|
|
||||||
///> Returns an iterator object, for all outlines in the set (no holes)
|
///> Returns an iterator object, for all outlines in the set (no holes)
|
||||||
SEGMENT_ITERATOR IterateSegments()
|
SEGMENT_ITERATOR IterateSegments()
|
||||||
{
|
{
|
||||||
|
@ -786,6 +809,12 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
return IterateSegments( aOutline, aOutline, true );
|
return IterateSegments( aOutline, aOutline, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///> Returns an iterator object, for the aOutline-th outline in the set (with holes)
|
||||||
|
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles( int aOutline ) const
|
||||||
|
{
|
||||||
|
return CIterateSegments( aOutline, aOutline, true );
|
||||||
|
}
|
||||||
|
|
||||||
/** operations on polygons use a aFastMode param
|
/** operations on polygons use a aFastMode param
|
||||||
* if aFastMode is PM_FAST (true) the result can be a weak polygon
|
* if aFastMode is PM_FAST (true) the result can be a weak polygon
|
||||||
* if aFastMode is PM_STRICTLY_SIMPLE (false) (default) the result is (theorically) a strictly
|
* if aFastMode is PM_STRICTLY_SIMPLE (false) (default) the result is (theorically) a strictly
|
||||||
|
|
|
@ -780,7 +780,7 @@ void BRDITEMS_PLOTTER::PlotDrawSegment( DRAWSEGMENT* aSeg )
|
||||||
{
|
{
|
||||||
if( !aSeg->IsPolygonFilled() )
|
if( !aSeg->IsPolygonFilled() )
|
||||||
{
|
{
|
||||||
for( auto it = aSeg->GetPolyShape().IterateSegments( 0 ); it; it++ )
|
for( auto it = aSeg->GetPolyShape().CIterateSegments( 0 ); it; it++ )
|
||||||
{
|
{
|
||||||
auto seg = it.Get();
|
auto seg = it.Get();
|
||||||
m_plotter->ThickSegment( wxPoint( seg.A ), wxPoint( seg.B ),
|
m_plotter->ThickSegment( wxPoint( seg.A ), wxPoint( seg.B ),
|
||||||
|
|
|
@ -642,26 +642,26 @@ void POINT_EDITOR::finishItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool POINT_EDITOR::validatePolygon( SHAPE_POLY_SET& aModified, const SHAPE_POLY_SET* aOriginal ) const
|
bool POINT_EDITOR::validatePolygon( SHAPE_POLY_SET& aPoly ) const
|
||||||
{
|
{
|
||||||
if( !aModified.IsSelfIntersecting() )
|
bool valid = !aPoly.IsSelfIntersecting();
|
||||||
{
|
|
||||||
m_statusPopup->Hide();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_statusPopup )
|
if( m_statusPopup )
|
||||||
|
{
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
m_statusPopup->Hide();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 );
|
wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 );
|
||||||
m_statusPopup->Move( p );
|
m_statusPopup->Move( p );
|
||||||
m_statusPopup->Popup( getEditFrame<PCB_BASE_FRAME>() );
|
m_statusPopup->Popup( getEditFrame<PCB_BASE_FRAME>() );
|
||||||
m_statusPopup->Expire( 1500 );
|
m_statusPopup->Expire( 1500 );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( aOriginal )
|
return valid;
|
||||||
aModified = *aOriginal;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1115,14 +1115,13 @@ int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
const auto& vertexIdx = vertex.second;
|
const auto& vertexIdx = vertex.second;
|
||||||
auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
|
auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
|
||||||
bool valid = true;
|
|
||||||
|
|
||||||
if( outline.PointCount() > 3 )
|
if( outline.PointCount() > 3 )
|
||||||
{
|
{
|
||||||
// the usual case: remove just the corner when there are >3 vertices
|
// the usual case: remove just the corner when there are >3 vertices
|
||||||
commit.Modify( item );
|
commit.Modify( item );
|
||||||
polygon->RemoveVertex( vertexIdx );
|
polygon->RemoveVertex( vertexIdx );
|
||||||
valid = validatePolygon( *polygon );
|
validatePolygon( *polygon );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1143,10 +1142,7 @@ int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
|
||||||
setEditedPoint( nullptr );
|
setEditedPoint( nullptr );
|
||||||
updatePoints();
|
updatePoints();
|
||||||
|
|
||||||
if( valid )
|
|
||||||
commit.Push( _( "Remove a zone/polygon corner" ) );
|
commit.Push( _( "Remove a zone/polygon corner" ) );
|
||||||
else
|
|
||||||
commit.Revert();
|
|
||||||
|
|
||||||
// Refresh zone hatching
|
// Refresh zone hatching
|
||||||
if( item->Type() == PCB_ZONE_AREA_T)
|
if( item->Type() == PCB_ZONE_AREA_T)
|
||||||
|
|
|
@ -92,12 +92,11 @@ private:
|
||||||
void finishItem();
|
void finishItem();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a polygon and restores it to its original version if available.
|
* Validates a polygon and displays a popup warning if invalid.
|
||||||
* @param aModified is the polygon to be checked.
|
* @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.
|
* @return True if polygon is valid.
|
||||||
*/
|
*/
|
||||||
bool validatePolygon( SHAPE_POLY_SET& aModified, const SHAPE_POLY_SET* aOriginal = nullptr ) const;
|
bool validatePolygon( SHAPE_POLY_SET& aModified ) const;
|
||||||
|
|
||||||
///> Updates edit points with item's points.
|
///> Updates edit points with item's points.
|
||||||
void updatePoints();
|
void updatePoints();
|
||||||
|
|
|
@ -207,7 +207,7 @@ void ZONE_CREATE_HELPER::commitZone( std::unique_ptr<ZONE_CONTAINER> aZone )
|
||||||
{
|
{
|
||||||
auto outline = aZone->Outline();
|
auto outline = aZone->Outline();
|
||||||
|
|
||||||
for( auto seg = outline->IterateSegments( 0 ); seg; seg++ )
|
for( auto seg = outline->CIterateSegments( 0 ); seg; seg++ )
|
||||||
{
|
{
|
||||||
auto new_seg = m_tool.m_editModules ?
|
auto new_seg = m_tool.m_editModules ?
|
||||||
new EDGE_MODULE( (MODULE *) parent ) :
|
new EDGE_MODULE( (MODULE *) parent ) :
|
||||||
|
|
Loading…
Reference in New Issue