Skip to content
Permalink
Browse files
[feature] Replace marker/hash line "on vertices" placement option
with "on inner vertices"

This new mode places the symbols on all inner vertices (ie all
vertices except the first or last). (We can safely do this now
that its easy for users to also set the symbols to show on
first/last vertex by clicking those checkboxes too!)

The motivation here is that when the "Vertex" mode puts the
symbols on the first/last vertex as well as inner vertices,
it's basically impossible to style a line with a different
marker on the first/last vertex to the rest of the line's
vertices. (The best you can get is just hiding the unwanted
first/last vertex by overlaying a second symbol layer on
the first/last vertices with a larger symbol)

Sponsored by North Road, thanks to SLYR
  • Loading branch information
nyalldawson committed Nov 12, 2021
1 parent fbfa992 commit 388a72abd855f1fe951fb1cd629ede6ebe793c3e
@@ -1037,7 +1037,10 @@
QgsTemplatedLineSymbolLayerBase.SegmentCenter = Qgis.MarkerLinePlacement.SegmentCenter
QgsTemplatedLineSymbolLayerBase.SegmentCenter.is_monkey_patched = True
QgsTemplatedLineSymbolLayerBase.SegmentCenter.__doc__ = "Place symbols at the center of every line segment"
Qgis.MarkerLinePlacement.__doc__ = 'Defines how/where the symbols should be placed on a line.\n\n.. note::\n\n Prior to QGIS 3.24 this was available as :py:class:`QgsTemplatedLineSymbolLayerBase`.Placement\n\n.. versionadded:: 3.24\n\n' + '* ``Interval``: ' + Qgis.MarkerLinePlacement.Interval.__doc__ + '\n' + '* ``Vertex``: ' + Qgis.MarkerLinePlacement.Vertex.__doc__ + '\n' + '* ``LastVertex``: ' + Qgis.MarkerLinePlacement.LastVertex.__doc__ + '\n' + '* ``FirstVertex``: ' + Qgis.MarkerLinePlacement.FirstVertex.__doc__ + '\n' + '* ``CentralPoint``: ' + Qgis.MarkerLinePlacement.CentralPoint.__doc__ + '\n' + '* ``CurvePoint``: ' + Qgis.MarkerLinePlacement.CurvePoint.__doc__ + '\n' + '* ``SegmentCenter``: ' + Qgis.MarkerLinePlacement.SegmentCenter.__doc__
QgsTemplatedLineSymbolLayerBase.InnerVertices = Qgis.MarkerLinePlacement.InnerVertices
QgsTemplatedLineSymbolLayerBase.InnerVertices.is_monkey_patched = True
QgsTemplatedLineSymbolLayerBase.InnerVertices.__doc__ = "Inner vertices (i.e. all vertices except the first and last vertex)"
Qgis.MarkerLinePlacement.__doc__ = 'Defines how/where the symbols should be placed on a line.\n\n.. note::\n\n Prior to QGIS 3.24 this was available as :py:class:`QgsTemplatedLineSymbolLayerBase`.Placement\n\n.. versionadded:: 3.24\n\n' + '* ``Interval``: ' + Qgis.MarkerLinePlacement.Interval.__doc__ + '\n' + '* ``Vertex``: ' + Qgis.MarkerLinePlacement.Vertex.__doc__ + '\n' + '* ``LastVertex``: ' + Qgis.MarkerLinePlacement.LastVertex.__doc__ + '\n' + '* ``FirstVertex``: ' + Qgis.MarkerLinePlacement.FirstVertex.__doc__ + '\n' + '* ``CentralPoint``: ' + Qgis.MarkerLinePlacement.CentralPoint.__doc__ + '\n' + '* ``CurvePoint``: ' + Qgis.MarkerLinePlacement.CurvePoint.__doc__ + '\n' + '* ``SegmentCenter``: ' + Qgis.MarkerLinePlacement.SegmentCenter.__doc__ + '\n' + '* ``InnerVertices``: ' + Qgis.MarkerLinePlacement.InnerVertices.__doc__
# --
Qgis.MarkerLinePlacement.baseClass = Qgis
Qgis.MarkerLinePlacements.baseClass = Qgis
@@ -667,6 +667,7 @@ The development version
CentralPoint,
CurvePoint,
SegmentCenter,
InnerVertices,
};
typedef QFlags<Qgis::MarkerLinePlacement> MarkerLinePlacements;

@@ -1065,6 +1065,7 @@ class CORE_EXPORT Qgis
CentralPoint = 1 << 4, //!< Place symbols at the mid point of the line
CurvePoint = 1 << 5, //!< Place symbols at every virtual curve point in the line (used when rendering curved geometry types only)
SegmentCenter = 1 << 6, //!< Place symbols at the center of every line segment
InnerVertices = 1 << 7, //!< Inner vertices (i.e. all vertices except the first and last vertex)
};
Q_ENUM( MarkerLinePlacement )
Q_DECLARE_FLAGS( MarkerLinePlacements, MarkerLinePlacement )
@@ -1284,6 +1284,10 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
{
placements = Qgis::MarkerLinePlacement::Vertex;
}
else if ( placementString.compare( QLatin1String( "innervertices" ), Qt::CaseInsensitive ) == 0 )
{
placements = Qgis::MarkerLinePlacement::InnerVertices;
}
else if ( placementString.compare( QLatin1String( "lastvertex" ), Qt::CaseInsensitive ) == 0 )
{
placements = Qgis::MarkerLinePlacement::LastVertex;
@@ -1329,6 +1333,8 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
renderPolylineCentral( points, context, averageOver );
if ( placements & Qgis::MarkerLinePlacement::Vertex )
renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::Vertex );
if ( placements & Qgis::MarkerLinePlacement::InnerVertices )
renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::InnerVertices );
if ( placements & Qgis::MarkerLinePlacement::LastVertex )
renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::LastVertex );
if ( placements & Qgis::MarkerLinePlacement::FirstVertex )
@@ -1353,6 +1359,8 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
renderPolylineCentral( points2, context, averageOver );
if ( placements & Qgis::MarkerLinePlacement::Vertex )
renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::Vertex );
if ( placements & Qgis::MarkerLinePlacement::InnerVertices )
renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::InnerVertices );
if ( placements & Qgis::MarkerLinePlacement::LastVertex )
renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::LastVertex );
if ( placements & Qgis::MarkerLinePlacement::FirstVertex )
@@ -1556,7 +1564,7 @@ void QgsTemplatedLineSymbolLayerBase::setCommonProperties( QgsTemplatedLineSymbo
if ( properties.contains( QStringLiteral( "placement" ) ) )
{
if ( properties[QStringLiteral( "placement" )] == QLatin1String( "vertex" ) )
destLayer->setPlacements( Qgis::MarkerLinePlacement::Vertex );
destLayer->setPlacements( Qgis::MarkerLinePlacement::InnerVertices | Qgis::MarkerLinePlacement::FirstVertex | Qgis::MarkerLinePlacement::LastVertex );
else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "lastvertex" ) )
destLayer->setPlacements( Qgis::MarkerLinePlacement::LastVertex );
else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "firstvertex" ) )
@@ -1778,7 +1786,9 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
}

if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
&& context.renderContext().geometry()->hasCurvedSegments() && ( placement == Qgis::MarkerLinePlacement::Vertex || placement == Qgis::MarkerLinePlacement::CurvePoint ) )
&& context.renderContext().geometry()->hasCurvedSegments() && ( placement == Qgis::MarkerLinePlacement::Vertex
|| placement == Qgis::MarkerLinePlacement::InnerVertices
|| placement == Qgis::MarkerLinePlacement::CurvePoint ) )
{
QgsCoordinateTransform ct = context.renderContext().coordinateTransform();
const QgsMapToPixel &mtp = context.renderContext().mapToPixel();
@@ -1788,14 +1798,21 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
double x, y, z;
QPointF mapPoint;
int pointNum = 0;
const int numPoints = context.renderContext().geometry()->nCoordinates();
while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
{
if ( context.renderContext().renderingStopped() )
break;

scope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM, ++pointNum, true ) );

if ( ( placement == Qgis::MarkerLinePlacement::Vertex && vId.type == Qgis::VertexType::Segment )
if ( pointNum == 1 && placement == Qgis::MarkerLinePlacement::InnerVertices )
continue;

if ( pointNum == numPoints && placement == Qgis::MarkerLinePlacement::InnerVertices )
continue;

if ( ( ( placement == Qgis::MarkerLinePlacement::Vertex || placement == Qgis::MarkerLinePlacement::InnerVertices ) && vId.type == Qgis::VertexType::Segment )
|| ( placement == Qgis::MarkerLinePlacement::CurvePoint && vId.type == Qgis::VertexType::Curve ) )
{
//transform
@@ -1837,6 +1854,13 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
break;
}

case Qgis::MarkerLinePlacement::InnerVertices:
{
i = 1;
maxCount = points.count() - 1;
break;
}

case Qgis::MarkerLinePlacement::Vertex:
case Qgis::MarkerLinePlacement::SegmentCenter:
{
@@ -92,7 +92,7 @@ void QgsSymbolLayer::initPropertyDefinitions()
{ QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
{ QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
{ QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
{ QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>|<b>segmentcenter</b>]", origin )},
{ QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>innervertices</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>|<b>segmentcenter</b>]", origin )},
{ QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyAverageAngleLength, QgsPropertyDefinition( "averageAngleLength", QObject::tr( "Average line angles over" ), QgsPropertyDefinition::DoublePositive, origin )},
@@ -1959,9 +1959,12 @@ void QgsMarkerLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
spinOffset->blockSignals( false );

whileBlocking( mCheckInterval )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::Interval );
whileBlocking( mCheckVertex )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexFirst )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::FirstVertex );
whileBlocking( mCheckVertexLast )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::LastVertex );
whileBlocking( mCheckVertex )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::InnerVertices
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexFirst )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::FirstVertex
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexLast )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::LastVertex
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckCentralPoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::CentralPoint );
whileBlocking( mCheckCurvePoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::CurvePoint );
whileBlocking( mCheckSegmentCentralPoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::SegmentCenter );
@@ -2059,7 +2062,7 @@ void QgsMarkerLineSymbolLayerWidget::setPlacement()
if ( mCheckInterval->isChecked() )
placements |= Qgis::MarkerLinePlacement::Interval;
if ( mCheckVertex->isChecked() )
placements |= Qgis::MarkerLinePlacement::Vertex;
placements |= Qgis::MarkerLinePlacement::InnerVertices;
if ( mCheckVertexLast->isChecked() )
placements |= Qgis::MarkerLinePlacement::LastVertex;
if ( mCheckVertexFirst->isChecked() )
@@ -2208,9 +2211,12 @@ void QgsHashedLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
spinOffset->blockSignals( false );

whileBlocking( mCheckInterval )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::Interval );
whileBlocking( mCheckVertex )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexFirst )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::FirstVertex );
whileBlocking( mCheckVertexLast )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::LastVertex );
whileBlocking( mCheckVertex )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::InnerVertices
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexFirst )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::FirstVertex
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckVertexLast )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::LastVertex
|| mLayer->placements() & Qgis::MarkerLinePlacement::Vertex );
whileBlocking( mCheckCentralPoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::CentralPoint );
whileBlocking( mCheckCurvePoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::CurvePoint );
whileBlocking( mCheckSegmentCentralPoint )->setChecked( mLayer->placements() & Qgis::MarkerLinePlacement::SegmentCenter );
@@ -2323,7 +2329,7 @@ void QgsHashedLineSymbolLayerWidget::setPlacement()
if ( mCheckInterval->isChecked() )
placements |= Qgis::MarkerLinePlacement::Interval;
if ( mCheckVertex->isChecked() )
placements |= Qgis::MarkerLinePlacement::Vertex;
placements |= Qgis::MarkerLinePlacement::InnerVertices;
if ( mCheckVertexLast->isChecked() )
placements |= Qgis::MarkerLinePlacement::LastVertex;
if ( mCheckVertexFirst->isChecked() )
@@ -46,7 +46,7 @@
<item>
<widget class="QCheckBox" name="mCheckInterval">
<property name="text">
<string>with interval</string>
<string>With interval</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -118,43 +118,46 @@
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="mCheckVertex">
<property name="toolTip">
<string>Shows symbols on inner vertices, i.e. all vertices except the first or last</string>
</property>
<property name="text">
<string>on every vertex</string>
<string>On inner vertices</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="mCheckVertexLast">
<property name="text">
<string>on last vertex only</string>
<string>On last vertex</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="mCheckVertexFirst">
<property name="text">
<string>on first vertex only</string>
<string>On first vertex</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="mCheckCentralPoint">
<property name="text">
<string>on central point</string>
<string>On central point</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="mCheckSegmentCentralPoint">
<property name="text">
<string>on central point of segments</string>
<string>On central point of segments</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QCheckBox" name="mCheckCurvePoint">
<property name="text">
<string>on every curve point</string>
<string>On every curve point</string>
</property>
</widget>
</item>
@@ -69,7 +69,7 @@
<item>
<widget class="QCheckBox" name="mCheckInterval">
<property name="text">
<string>with interval</string>
<string>With interval</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -118,43 +118,46 @@
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="mCheckVertex">
<property name="toolTip">
<string>Shows symbols on inner vertices, i.e. all vertices except the first or last</string>
</property>
<property name="text">
<string>on every vertex</string>
<string>On inner vertices</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="mCheckVertexLast">
<property name="text">
<string>on last vertex only</string>
<string>On last vertex</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="mCheckVertexFirst">
<property name="text">
<string>on first vertex only</string>
<string>On first vertex</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="mCheckCentralPoint">
<property name="text">
<string>on central point</string>
<string>On central point</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="mCheckSegmentCentralPoint">
<property name="text">
<string>on central point of segments</string>
<string>On central point of segments</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QCheckBox" name="mCheckCurvePoint">
<property name="text">
<string>on every curve point</string>
<string>On every curve point</string>
</property>
</widget>
</item>
Loading

0 comments on commit 388a72a

Please sign in to comment.