mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
#9480: New option for CentroidFillSymbolLayerV2 to force centroid inside of polygons
This commit is contained in:
parent
cbee3d35ff
commit
72b3d3fe71
@ -3166,7 +3166,7 @@ QSet<QString> QgsPointPatternFillSymbolLayer::usedAttributes() const
|
||||
//////////////
|
||||
|
||||
|
||||
QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( NULL )
|
||||
QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( NULL ), mPointOnSurface( false )
|
||||
{
|
||||
setSubSymbol( new QgsMarkerSymbolV2() );
|
||||
}
|
||||
@ -3178,8 +3178,12 @@ QgsCentroidFillSymbolLayerV2::~QgsCentroidFillSymbolLayerV2()
|
||||
|
||||
QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::create( const QgsStringMap& properties )
|
||||
{
|
||||
Q_UNUSED( properties );
|
||||
return new QgsCentroidFillSymbolLayerV2();
|
||||
QgsCentroidFillSymbolLayerV2* sl = new QgsCentroidFillSymbolLayerV2();
|
||||
|
||||
if ( properties.contains( "point_on_surface" ) )
|
||||
sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
|
||||
|
||||
return sl;
|
||||
}
|
||||
|
||||
QString QgsCentroidFillSymbolLayerV2::layerType() const
|
||||
@ -3208,13 +3212,15 @@ void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList
|
||||
{
|
||||
Q_UNUSED( rings );
|
||||
|
||||
QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
|
||||
QPointF centroid = mPointOnSurface ? QgsSymbolLayerV2Utils::polygonPointOnSurface( points ) : QgsSymbolLayerV2Utils::polygonCentroid( points );
|
||||
mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
|
||||
}
|
||||
|
||||
QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
|
||||
{
|
||||
return QgsStringMap();
|
||||
QgsStringMap map;
|
||||
map["point_on_surface"] = QString::number( mPointOnSurface );
|
||||
return map;
|
||||
}
|
||||
|
||||
QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
|
||||
@ -3223,6 +3229,7 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
|
||||
x->mAngle = mAngle;
|
||||
x->mColor = mColor;
|
||||
x->setSubSymbol( mMarker->clone() );
|
||||
x->setPointOnSurface( mPointOnSurface );
|
||||
return x;
|
||||
}
|
||||
|
||||
@ -3246,9 +3253,9 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::createFromSld( QDomElement &elem
|
||||
layers.append( l );
|
||||
QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
|
||||
|
||||
QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
|
||||
x->setSubSymbol( marker );
|
||||
return x;
|
||||
QgsCentroidFillSymbolLayerV2* sl = new QgsCentroidFillSymbolLayerV2();
|
||||
sl->setSubSymbol( marker );
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -904,8 +904,12 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
|
||||
|
||||
virtual QSet<QString> usedAttributes() const;
|
||||
|
||||
void setPointOnSurface( bool pointOnSurface ) { mPointOnSurface = pointOnSurface; }
|
||||
bool pointOnSurface() const { return mPointOnSurface; }
|
||||
|
||||
protected:
|
||||
QgsMarkerSymbolV2* mMarker;
|
||||
bool mPointOnSurface;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -3179,6 +3179,62 @@ QPointF QgsSymbolLayerV2Utils::polygonCentroid( const QPolygonF& points )
|
||||
return QPointF( cx, cy );
|
||||
}
|
||||
|
||||
QPointF QgsSymbolLayerV2Utils::polygonPointOnSurface( const QPolygonF& points )
|
||||
{
|
||||
QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
|
||||
|
||||
// check if centroid inside in polygon
|
||||
if ( !QgsSymbolLayerV2Utils::pointInPolygon( points, centroid ) )
|
||||
{
|
||||
unsigned int i, pointCount = points.count();
|
||||
|
||||
QgsPolyline polyline( pointCount );
|
||||
for ( i = 0; i < pointCount; ++i ) polyline[i] = QgsPoint( points[i].x(), points[i].y() );
|
||||
|
||||
QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << polyline );
|
||||
if ( geom )
|
||||
{
|
||||
QgsGeometry* pointOnSurfaceGeom = geom->pointOnSurface();
|
||||
|
||||
if ( pointOnSurfaceGeom )
|
||||
{
|
||||
QgsPoint point = pointOnSurfaceGeom->asPoint();
|
||||
delete pointOnSurfaceGeom;
|
||||
delete geom;
|
||||
|
||||
return QPointF( point.x(), point.y() );
|
||||
}
|
||||
delete geom;
|
||||
}
|
||||
}
|
||||
return centroid;
|
||||
}
|
||||
|
||||
bool QgsSymbolLayerV2Utils::pointInPolygon( const QPolygonF &points, const QPointF &point )
|
||||
{
|
||||
bool inside = false;
|
||||
|
||||
double x = point.x();
|
||||
double y = point.y();
|
||||
|
||||
for ( int i = 0, j = points.count() - 1; i < points.count(); i++ )
|
||||
{
|
||||
const QPointF& p1 = points[i];
|
||||
const QPointF& p2 = points[j];
|
||||
|
||||
if ( p1.x() == x && p1.y() == y )
|
||||
return true;
|
||||
|
||||
if ( ( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
|
||||
{
|
||||
if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() )*( p2.x() - p1.x() ) <= x )
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
j = i;
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
QgsExpression* QgsSymbolLayerV2Utils::fieldOrExpressionToExpression( const QString& fieldOrExpression )
|
||||
{
|
||||
|
@ -287,6 +287,12 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
|
||||
//! Calculate the centroid point of a QPolygonF
|
||||
static QPointF polygonCentroid( const QPolygonF& points );
|
||||
|
||||
//! Calculate a point within of a QPolygonF
|
||||
static QPointF polygonPointOnSurface( const QPolygonF& points );
|
||||
|
||||
//! Calculate whether a point is within of a QPolygonF
|
||||
static bool pointInPolygon( const QPolygonF &points, const QPointF &point );
|
||||
|
||||
/** Return a new valid expression instance for given field or expression string.
|
||||
* If the input is not a valid expression, it is assumed that it is a field name and gets properly quoted.
|
||||
* If the string is empty, returns null pointer.
|
||||
|
@ -2794,6 +2794,11 @@ void QgsCentroidFillSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer
|
||||
|
||||
// layer type is correct, we can do the cast
|
||||
mLayer = static_cast<QgsCentroidFillSymbolLayerV2*>( layer );
|
||||
|
||||
// set values
|
||||
mDrawInsideCheckBox->blockSignals( true );
|
||||
mDrawInsideCheckBox->setChecked( mLayer->pointOnSurface() );
|
||||
mDrawInsideCheckBox->blockSignals( false );
|
||||
}
|
||||
|
||||
QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2Widget::symbolLayer()
|
||||
@ -2801,5 +2806,8 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2Widget::symbolLayer()
|
||||
return mLayer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QgsCentroidFillSymbolLayerV2Widget::on_mDrawInsideCheckBox_stateChanged( int state )
|
||||
{
|
||||
mLayer->setPointOnSurface( state == Qt::Checked );
|
||||
emit changed();
|
||||
}
|
||||
|
@ -482,6 +482,9 @@ class GUI_EXPORT QgsCentroidFillSymbolLayerV2Widget : public QgsSymbolLayerV2Wid
|
||||
virtual void setSymbolLayer( QgsSymbolLayerV2* layer );
|
||||
virtual QgsSymbolLayerV2* symbolLayer();
|
||||
|
||||
public slots:
|
||||
void on_mDrawInsideCheckBox_stateChanged( int state );
|
||||
|
||||
protected:
|
||||
QgsCentroidFillSymbolLayerV2* mLayer;
|
||||
};
|
||||
|
@ -16,6 +16,13 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mDrawInsideCheckBox">
|
||||
<property name="text">
|
||||
<string>Force point inside polygon</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
Loading…
x
Reference in New Issue
Block a user