Skip to content

Commit

Permalink
[feature] Allow offset along line to be specified in percent for
Browse files Browse the repository at this point in the history
marker line and hash line symbol layer types

Offsets are treated as percent of overall line length
  • Loading branch information
nyalldawson committed Dec 14, 2021
1 parent 0a1731a commit aac0432
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
47 changes: 45 additions & 2 deletions src/core/symbology/qgslinesymbollayer.cpp
Expand Up @@ -1678,7 +1678,31 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval( const QPolygonF &p
if ( painterUnitInterval < 0 )
return;

double painterUnitOffsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
double painterUnitOffsetAlongLine = 0;

// only calculated if we need it!
double totalLength = -1;

if ( !qgsDoubleNear( offsetAlongLine, 0 ) )
{
totalLength = QgsSymbolLayerUtils::polylineLength( points );
switch ( offsetAlongLineUnit() )
{
case QgsUnitTypes::RenderMillimeters:
case QgsUnitTypes::RenderMapUnits:
case QgsUnitTypes::RenderPixels:
case QgsUnitTypes::RenderPoints:
case QgsUnitTypes::RenderInches:
case QgsUnitTypes::RenderUnknownUnit:
case QgsUnitTypes::RenderMetersInMapUnits:
painterUnitOffsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
break;
case QgsUnitTypes::RenderPercentage:
painterUnitOffsetAlongLine = offsetAlongLine / 100 * totalLength;
break;
}
}

if ( offsetAlongLineUnit() == QgsUnitTypes::RenderMetersInMapUnits && rc.flags() & Qgis::RenderContextFlag::RenderSymbolPreview )
{
// rendering for symbol previews -- an offset in meters in map units can't be calculated, so treat the size as millimeters
Expand Down Expand Up @@ -1825,10 +1849,29 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
context.setOriginalValueVariable( mOffsetAlongLine );
offsetAlongLine = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyOffsetAlongLine, context.renderContext().expressionContext(), mOffsetAlongLine );
}

// only calculated if we need it!!
double totalLength = -1;
if ( !qgsDoubleNear( offsetAlongLine, 0.0 ) )
{
totalLength = QgsSymbolLayerUtils::polylineLength( points );

//scale offset along line
offsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
switch ( offsetAlongLineUnit() )
{
case QgsUnitTypes::RenderMillimeters:
case QgsUnitTypes::RenderMapUnits:
case QgsUnitTypes::RenderPixels:
case QgsUnitTypes::RenderPoints:
case QgsUnitTypes::RenderInches:
case QgsUnitTypes::RenderUnknownUnit:
case QgsUnitTypes::RenderMetersInMapUnits:
offsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
break;
case QgsUnitTypes::RenderPercentage:
offsetAlongLine = offsetAlongLine / 100 * totalLength;
break;
}
}

if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
Expand Down
4 changes: 2 additions & 2 deletions src/gui/symbology/qgssymbollayerwidget.cpp
Expand Up @@ -1902,7 +1902,7 @@ QgsMarkerLineSymbolLayerWidget::QgsMarkerLineSymbolLayerWidget( QgsVectorLayer *
mOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mOffsetAlongLineUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches << QgsUnitTypes::RenderPercentage );
mAverageAngleUnit->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );

Expand Down Expand Up @@ -2155,7 +2155,7 @@ QgsHashedLineSymbolLayerWidget::QgsHashedLineSymbolLayerWidget( QgsVectorLayer *
mOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mOffsetAlongLineUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches << QgsUnitTypes::RenderPercentage );
mAverageAngleUnit->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mHashLengthUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
Expand Down
47 changes: 47 additions & 0 deletions tests/src/python/test_qgsmarkerlinesymbollayer.py
Expand Up @@ -680,6 +680,53 @@ def testNoPoint(self):
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_none', 'markerline_none', rendered_image)

def testFirstVertexOffsetPercentage(self):
s = QgsLineSymbol()
s.deleteSymbolLayer(0)

marker_line = QgsMarkerLineSymbolLayer(True)
marker_line.setPlacements(Qgis.MarkerLinePlacement.FirstVertex)
marker_line.setOffsetAlongLine(10)
marker_line.setOffsetAlongLineUnit(QgsUnitTypes.RenderPercentage)
marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 4)
marker.setColor(QColor(255, 0, 0, 100))
marker.setStrokeStyle(Qt.NoPen)
marker_symbol = QgsMarkerSymbol()
marker_symbol.changeSymbolLayer(0, marker)
marker_line.setSubSymbol(marker_symbol)
line_symbol = QgsLineSymbol()
line_symbol.changeSymbolLayer(0, marker_line)

s.appendSymbolLayer(marker_line.clone())

g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)')
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_first_offset_percent', 'markerline_first_offset_percent', rendered_image)

def testIntervalOffsetPercentage(self):
s = QgsLineSymbol()
s.deleteSymbolLayer(0)

marker_line = QgsMarkerLineSymbolLayer(True)
marker_line.setPlacements(Qgis.MarkerLinePlacement.Interval)
marker_line.setInterval(6)
marker_line.setOffsetAlongLine(50)
marker_line.setOffsetAlongLineUnit(QgsUnitTypes.RenderPercentage)
marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 4)
marker.setColor(QColor(255, 0, 0, 100))
marker.setStrokeStyle(Qt.NoPen)
marker_symbol = QgsMarkerSymbol()
marker_symbol.changeSymbolLayer(0, marker)
marker_line.setSubSymbol(marker_symbol)
line_symbol = QgsLineSymbol()
line_symbol.changeSymbolLayer(0, marker_line)

s.appendSymbolLayer(marker_line.clone())

g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)')
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_interval_offset_percent', 'markerline_interval_offset_percent', rendered_image)

def testCenterSegment(self):
s = QgsLineSymbol()
s.deleteSymbolLayer(0)
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit aac0432

Please sign in to comment.