Skip to content

Commit

Permalink
[FEATURE] "Center of segment" placement mode for marker and hash line…
Browse files Browse the repository at this point in the history
… symbol layers

Adds a new placement option to place markers/hash lines at the center
point of individual line segments

Refs #29785
  • Loading branch information
nyalldawson committed Aug 21, 2019
1 parent 8145f8f commit 2ca3029
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 76 deletions.
Expand Up @@ -256,6 +256,7 @@ lines at intervals along the line feature.
FirstVertex,
CentralPoint,
CurvePoint,
SegmentCenter,
};

QgsTemplatedLineSymbolLayerBase( bool rotateSymbol = true,
Expand Down
47 changes: 41 additions & 6 deletions src/core/symbology/qgslinesymbollayer.cpp
Expand Up @@ -791,6 +791,10 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
{
placement = QgsTemplatedLineSymbolLayerBase::CurvePoint;
}
else if ( placementString.compare( QLatin1String( "segmentcenter" ), Qt::CaseInsensitive ) == 0 )
{
placement = QgsTemplatedLineSymbolLayerBase::SegmentCenter;
}
else
{
placement = QgsTemplatedLineSymbolLayerBase::Interval;
Expand Down Expand Up @@ -825,6 +829,7 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
case LastVertex:
case FirstVertex:
case CurvePoint:
case SegmentCenter:
renderPolylineVertex( points, context, placement );
break;
}
Expand Down Expand Up @@ -852,6 +857,7 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
case LastVertex:
case FirstVertex:
case CurvePoint:
case SegmentCenter:
renderPolylineVertex( points2, context, placement );
break;
}
Expand Down Expand Up @@ -971,6 +977,9 @@ QgsStringMap QgsTemplatedLineSymbolLayerBase::properties() const
case Interval:
map[QStringLiteral( "placement" )] = QStringLiteral( "interval" );
break;
case SegmentCenter:
map[QStringLiteral( "placement" )] = QStringLiteral( "segmentcenter" );
break;
}

map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
Expand Down Expand Up @@ -1058,6 +1067,8 @@ void QgsTemplatedLineSymbolLayerBase::setCommonProperties( QgsTemplatedLineSymbo
destLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CentralPoint );
else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "curvepoint" ) )
destLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CurvePoint );
else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "segmentcenter" ) )
destLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::SegmentCenter );
else
destLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::Interval );
}
Expand Down Expand Up @@ -1312,8 +1323,9 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
}

case Vertex:
case SegmentCenter:
{
i = 0;
i = placement == Vertex ? 0 : 1;
maxCount = points.count();
if ( points.first() == points.last() )
isRing = true;
Expand All @@ -1340,6 +1352,11 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
}

int pointNum = 0;
QPointF prevPoint;
if ( placement == SegmentCenter && !points.empty() )
prevPoint = points.at( 0 );

QPointF symbolPoint;
for ( ; i < maxCount; ++i )
{
scope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM, ++pointNum, true ) );
Expand All @@ -1348,14 +1365,32 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
{
continue; // don't draw the last marker - it has been drawn already
}
// rotate marker (if desired)
if ( rotateSymbols() )

if ( placement == SegmentCenter )
{
double angle = markerAngle( points, isRing, i );
setSymbolAngle( origAngle + angle * 180 / M_PI );
QPointF currentPoint = points.at( i );
symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
0.5 * ( currentPoint.y() + prevPoint.y() ) );
if ( rotateSymbols() )
{
double angle = std::atan2( currentPoint.y() - prevPoint.y(),
currentPoint.x() - prevPoint.x() );
setSymbolAngle( origAngle + angle * 180 / M_PI );
}
prevPoint = currentPoint;
}
else
{
symbolPoint = points.at( i );
// rotate marker (if desired)
if ( rotateSymbols() )
{
double angle = markerAngle( points, isRing, i );
setSymbolAngle( origAngle + angle * 180 / M_PI );
}
}

renderSymbol( points.at( i ), context.feature(), rc, -1, context.selected() );
renderSymbol( symbolPoint, context.feature(), rc, -1, context.selected() );
}

// restore original rotation
Expand Down
1 change: 1 addition & 0 deletions src/core/symbology/qgslinesymbollayer.h
Expand Up @@ -266,6 +266,7 @@ class CORE_EXPORT QgsTemplatedLineSymbolLayerBase : public QgsLineSymbolLayer
FirstVertex, //!< Place symbols on the first vertex in the line
CentralPoint, //!< Place symbols at the mid point of the line
CurvePoint, //!< Place symbols at every virtual curve point in the line (used when rendering curved geometry types only)
SegmentCenter, //!< Place symbols at the center of every line segment
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology/qgssymbollayer.cpp
Expand Up @@ -82,7 +82,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>]", 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::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 )},
Expand Down
10 changes: 10 additions & 0 deletions src/gui/symbology/qgssymbollayerwidget.cpp
Expand Up @@ -1777,6 +1777,7 @@ QgsMarkerLineSymbolLayerWidget::QgsMarkerLineSymbolLayerWidget( QgsVectorLayer *
connect( radVertexFirst, &QAbstractButton::clicked, this, &QgsMarkerLineSymbolLayerWidget::setPlacement );
connect( radCentralPoint, &QAbstractButton::clicked, this, &QgsMarkerLineSymbolLayerWidget::setPlacement );
connect( radCurvePoint, &QAbstractButton::clicked, this, &QgsMarkerLineSymbolLayerWidget::setPlacement );
connect( radSegmentCentralPoint, &QAbstractButton::clicked, this, &QgsMarkerLineSymbolLayerWidget::setPlacement );
}

void QgsMarkerLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
Expand Down Expand Up @@ -1810,6 +1811,8 @@ void QgsMarkerLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
radCentralPoint->setChecked( true );
else if ( mLayer->placement() == QgsTemplatedLineSymbolLayerBase::CurvePoint )
radCurvePoint->setChecked( true );
else if ( mLayer->placement() == QgsTemplatedLineSymbolLayerBase::SegmentCenter )
radSegmentCentralPoint->setChecked( true );
else
radVertexFirst->setChecked( true );

Expand Down Expand Up @@ -1893,6 +1896,8 @@ void QgsMarkerLineSymbolLayerWidget::setPlacement()
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::FirstVertex );
else if ( radCurvePoint->isChecked() )
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CurvePoint );
else if ( radSegmentCentralPoint->isChecked() )
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::SegmentCenter );
else
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CentralPoint );

Expand Down Expand Up @@ -2010,6 +2015,7 @@ QgsHashedLineSymbolLayerWidget::QgsHashedLineSymbolLayerWidget( QgsVectorLayer *
connect( radVertexFirst, &QAbstractButton::clicked, this, &QgsHashedLineSymbolLayerWidget::setPlacement );
connect( radCentralPoint, &QAbstractButton::clicked, this, &QgsHashedLineSymbolLayerWidget::setPlacement );
connect( radCurvePoint, &QAbstractButton::clicked, this, &QgsHashedLineSymbolLayerWidget::setPlacement );
connect( radSegmentCentralPoint, &QAbstractButton::clicked, this, &QgsHashedLineSymbolLayerWidget::setPlacement );
}

void QgsHashedLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
Expand Down Expand Up @@ -2045,6 +2051,8 @@ void QgsHashedLineSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
radCentralPoint->setChecked( true );
else if ( mLayer->placement() == QgsTemplatedLineSymbolLayerBase::CurvePoint )
radCurvePoint->setChecked( true );
else if ( mLayer->placement() == QgsTemplatedLineSymbolLayerBase::SegmentCenter )
radSegmentCentralPoint->setChecked( true );
else
radVertexFirst->setChecked( true );

Expand Down Expand Up @@ -2143,6 +2151,8 @@ void QgsHashedLineSymbolLayerWidget::setPlacement()
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::FirstVertex );
else if ( radCurvePoint->isChecked() )
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CurvePoint );
else if ( radSegmentCentralPoint->isChecked() )
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::SegmentCenter );
else
mLayer->setPlacement( QgsTemplatedLineSymbolLayerBase::CentralPoint );

Expand Down
68 changes: 38 additions & 30 deletions src/ui/symbollayer/widget_hashline.ui
Expand Up @@ -41,13 +41,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="3" column="2">
<widget class="QgsPropertyOverrideButton" name="mIntervalDDBtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
Expand Down Expand Up @@ -100,56 +93,70 @@
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="QRadioButton" name="radVertex">
<property name="text">
<string>on every vertex</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QRadioButton" name="radVertexLast">
<property name="text">
<string>on last vertex only</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1">
<widget class="QRadioButton" name="radVertexFirst">
<property name="text">
<string>on first vertex only</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QRadioButton" name="radCentralPoint">
<item row="9" column="1">
<widget class="QRadioButton" name="radCurvePoint">
<property name="text">
<string>on central point</string>
<string>on every curve point</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QRadioButton" name="radCurvePoint">
<item row="3" column="2">
<widget class="QgsPropertyOverrideButton" name="mIntervalDDBtn">
<property name="text">
<string>on every curve point</string>
<string></string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QRadioButton" name="radVertex">
<item row="7" column="1">
<widget class="QRadioButton" name="radCentralPoint">
<property name="text">
<string>on every vertex</string>
<string>on central point</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
<item row="8" column="1">
<widget class="QRadioButton" name="radSegmentCentralPoint">
<property name="text">
<string>on central point of segments</string>
</property>
</spacer>
</widget>
</item>
</layout>
</item>
Expand Down Expand Up @@ -494,6 +501,7 @@
<tabstop>radVertexLast</tabstop>
<tabstop>radVertexFirst</tabstop>
<tabstop>radCentralPoint</tabstop>
<tabstop>radSegmentCentralPoint</tabstop>
<tabstop>radCurvePoint</tabstop>
<tabstop>mSpinOffsetAlongLine</tabstop>
<tabstop>mOffsetAlongLineUnitWidget</tabstop>
Expand Down

0 comments on commit 2ca3029

Please sign in to comment.