Prevent creation of invalid polyline / polygon

This commit is contained in:
Yoann Quenach de Quivillic 2024-10-20 21:53:09 +02:00 committed by Nyall Dawson
parent c354ed5000
commit ca2688a977
12 changed files with 81 additions and 5 deletions

View File

@ -111,6 +111,14 @@ Deselects any selected nodes.
virtual double estimatedFrameBleed() const;
virtual bool isValid() const;
%Docstring
Can be reimplemented in subclasses. Typically a polyline is valid if it has at least 2 distinct nodes, while
a polygon is valid if it has at least 3 distinct nodes.
.. versionadded:: 3.40
%End
protected:
QgsLayoutNodesItem( QgsLayout *layout );

View File

@ -53,6 +53,8 @@ The caller takes responsibility for deleting the returned object.
virtual QgsGeometry clipPath() const;
virtual bool isValid() const;
QgsFillSymbol *symbol();
%Docstring

View File

@ -55,6 +55,8 @@ The caller takes responsibility for deleting the returned object.
virtual QPainterPath shape() const;
virtual bool isValid() const;
QgsLineSymbol *symbol();
%Docstring

View File

@ -111,6 +111,14 @@ Deselects any selected nodes.
virtual double estimatedFrameBleed() const;
virtual bool isValid() const;
%Docstring
Can be reimplemented in subclasses. Typically a polyline is valid if it has at least 2 distinct nodes, while
a polygon is valid if it has at least 3 distinct nodes.
.. versionadded:: 3.40
%End
protected:
QgsLayoutNodesItem( QgsLayout *layout );

View File

@ -53,6 +53,8 @@ The caller takes responsibility for deleting the returned object.
virtual QgsGeometry clipPath() const;
virtual bool isValid() const;
QgsFillSymbol *symbol();
%Docstring

View File

@ -55,6 +55,8 @@ The caller takes responsibility for deleting the returned object.
virtual QPainterPath shape() const;
virtual bool isValid() const;
QgsLineSymbol *symbol();
%Docstring

View File

@ -113,6 +113,15 @@ class CORE_EXPORT QgsLayoutNodesItem: public QgsLayoutItem
// rather than the item's pen
double estimatedFrameBleed() const override;
/**
* Can be reimplemented in subclasses. Typically a polyline is valid if it has at least 2 distinct nodes, while
* a polygon is valid if it has at least 3 distinct nodes.
*
* \since QGIS 3.40
*/
virtual bool isValid() const { return true; };
protected:
/**

View File

@ -129,6 +129,23 @@ QgsGeometry QgsLayoutItemPolygon::clipPath() const
return QgsGeometry::fromQPolygonF( path );
}
bool QgsLayoutItemPolygon::isValid() const
{
QList<QPointF> uniquePoints;
int seen = 0;
for ( QPointF point : mPolygon )
{
if ( !uniquePoints.contains( point ) )
{
uniquePoints.append( point );
if ( ++seen > 2 )
return true;
}
}
return false;
}
QgsFillSymbol *QgsLayoutItemPolygon::symbol()
{
return mPolygonStyleSymbol.get();

View File

@ -58,6 +58,7 @@ class CORE_EXPORT QgsLayoutItemPolygon: public QgsLayoutNodesItem
bool accept( QgsStyleEntityVisitorInterface *visitor ) const override;
QgsLayoutItem::Flags itemFlags() const override;
QgsGeometry clipPath() const override;
bool isValid() const override;
/**
* Returns the fill symbol used to draw the shape.

View File

@ -85,17 +85,17 @@ bool QgsLayoutItemPolyline::_removeNode( const int index )
{
if ( index < 0 || index >= mPolygon.size() )
return false;
mPolygon.remove( index );
if ( mPolygon.size() < 2 )
mPolygon.clear();
else
{
int newSelectNode = index;
if ( index >= mPolygon.size() )
newSelectNode = mPolygon.size() - 1;
setSelectedNode( newSelectNode );
int newSelectNode = index;
if ( index >= mPolygon.size() )
newSelectNode = mPolygon.size() - 1;
setSelectedNode( newSelectNode );
}
return true;
@ -344,6 +344,22 @@ QPainterPath QgsLayoutItemPolyline::shape() const
return strokedOutline;
}
bool QgsLayoutItemPolyline::isValid() const
{
QList<QPointF> uniquePoints;
int seen = 0;
for (QPointF point: mPolygon)
{
if( !uniquePoints.contains( point ) )
{
uniquePoints.append( point );
if (++seen > 1)
return true;
}
}
return false;
}
QgsLineSymbol *QgsLayoutItemPolyline::symbol()
{
return mPolylineStyleSymbol.get();

View File

@ -66,6 +66,7 @@ class CORE_EXPORT QgsLayoutItemPolyline: public QgsLayoutNodesItem
QIcon icon() const override;
QString displayName() const override;
QPainterPath shape() const override;
bool isValid() const override;
/**
* Returns the line symbol used to draw the shape.

View File

@ -74,7 +74,15 @@ void QgsLayoutViewToolAddNodeItem::layoutPressEvent( QgsLayoutViewMouseEvent *ev
return;
if ( QgsLayoutNodesItem *nodesItem = qobject_cast< QgsLayoutNodesItem * >( item ) )
{
nodesItem->setNodes( mPolygon );
if ( !nodesItem->isValid() )
{
nodesItem->deleteLater();
mRubberBand.reset();
return;
}
}
layout()->addLayoutItem( item );
layout()->setSelectedItem( item );