Skip to content

Commit

Permalink
When the "offset along line" setting for a marker line ori
Browse files Browse the repository at this point in the history
hash line symbol layer is longer then the size of a closed ring,
treat the offset as continuing to loop around the ring

E.g. setting the offset to 150% results in the offset being
treated as 50% of the length of the closed ring
  • Loading branch information
nyalldawson committed Dec 14, 2021
1 parent aac0432 commit e8b9aad
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/core/symbology/qgslinesymbollayer.cpp
Expand Up @@ -1701,6 +1701,14 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval( const QPolygonF &p
painterUnitOffsetAlongLine = offsetAlongLine / 100 * totalLength;
break;
}

if ( points.isClosed() )
{
if ( painterUnitOffsetAlongLine > 0 )
{
painterUnitOffsetAlongLine = std::fmod( painterUnitOffsetAlongLine, totalLength );
}
}
}

if ( offsetAlongLineUnit() == QgsUnitTypes::RenderMetersInMapUnits && rc.flags() & Qgis::RenderContextFlag::RenderSymbolPreview )
Expand Down Expand Up @@ -1872,6 +1880,13 @@ void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &poi
offsetAlongLine = offsetAlongLine / 100 * totalLength;
break;
}
if ( points.isClosed() )
{
if ( offsetAlongLine > 0 )
{
offsetAlongLine = std::fmod( offsetAlongLine, totalLength );
}
}
}

if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
Expand Down
53 changes: 53 additions & 0 deletions tests/src/python/test_qgsmarkerlinesymbollayer.py
Expand Up @@ -703,6 +703,32 @@ def testFirstVertexOffsetPercentage(self):
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_first_offset_percent', 'markerline_first_offset_percent', rendered_image)

def testClosedRingFirstVertexOffsetLarge(self):
"""
Test that an offset larger than the length of a closed line effectively "loops" around the ring
"""
s = QgsLineSymbol()
s.deleteSymbolLayer(0)

marker_line = QgsMarkerLineSymbolLayer(True)
marker_line.setPlacements(Qgis.MarkerLinePlacement.FirstVertex)
marker_line.setOffsetAlongLine(110)
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, 0 0)')
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_first_large_offset', 'markerline_first_large_offset', rendered_image)

def testIntervalOffsetPercentage(self):
s = QgsLineSymbol()
s.deleteSymbolLayer(0)
Expand All @@ -727,6 +753,33 @@ def testIntervalOffsetPercentage(self):
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_interval_offset_percent', 'markerline_interval_offset_percent', rendered_image)

def testClosedRingIntervalOffsetLarge(self):
"""
Test that an offset larger than the length of a closed line effectively "loops" around the ring
"""
s = QgsLineSymbol()
s.deleteSymbolLayer(0)

marker_line = QgsMarkerLineSymbolLayer(True)
marker_line.setPlacements(Qgis.MarkerLinePlacement.Interval)
marker_line.setInterval(6)
marker_line.setOffsetAlongLine(150)
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, 0 0)')
rendered_image = self.renderGeometry(s, g)
assert self.imageCheck('markerline_interval_large_offset', 'markerline_interval_large_offset', 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 e8b9aad

Please sign in to comment.