Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extension for selection and storage of profile points #104

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ qgisMaximumVersion=3.99
description=Plots terrain profile
about=This tool plots profile lines from raster layers or point vector layer with elevation field. Supports multiple lines as well as graph export to svg, pdf, png or csv file. Supports 3D polyline export to dxf.
category=Raster
version=4.3.0
version=4.3.1
author=Borys Jurgiel - Patrice Verchere - Etienne Tourigny - Javier Becerra
[email protected]
supportsQt6=True
experimental=True
deprecated=False

changelog=
4.3.1 : Add support for picking and saving profile points when "Link mouse position" is enabled (by Christoph Candido - github/cxcandid)
- points are stored in layer "profile_points" with fields "d" (horizontal distance from startpoint) and "z" (raster band value)
- if layer "profile_points" does not exist, a memory layer is automatically created
4.3.0 : Experimental for now as I might have break things...
- Upgrade pyqtgraph to 0.13.7
- Compatibility with Qt6
Expand Down
88 changes: 84 additions & 4 deletions tools/profiletool_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

# qgis import
from qgis.core import QgsGeometry, QgsMapLayer, QgsPoint, QgsPointXY, QgsProject
from qgis.core import QgsVectorLayer, QgsFeature, QgsWkbTypes

# from qgis.gui import *
from qgis.PyQt.QtCore import QSettings, Qt
Expand Down Expand Up @@ -166,6 +167,7 @@ def updateProfil(self, points1, removeSelection=True, plotProfil=True):
# points1 = points1 + [points1[-1]]
self.pointstoDraw = points1
self.profiles = []
self.distancesPicked = []

# calculate profiles
for i in range(0, self.dockwidget.mdl.rowCount()):
Expand Down Expand Up @@ -255,6 +257,49 @@ def plotProfil(self, vertline=True):
self.updateCursorOnMap(self.x_cursor)
self.enableMouseCoordonates(self.dockwidget.plotlibrary)

def setPointOnMap(self, x, y):
self.x_cursor = x
if self.pointstoDraw and self.doTracking:
if x is not None:
points = [QgsPointXY(*p) for p in self.pointstoDraw]
geom = QgsGeometry.fromPolylineXY(points)
try:
if len(points) > 1:
pointprojected = geom.interpolate(x).asPoint()
else:
pointprojected = points[0]
except (IndexError, AttributeError, ValueError):
pointprojected = None

if pointprojected:
try:
# test if self.pointLayer does not exist or layer was deleted
if not self.pointLayer:
pass
except:
self.pointLayer = None
layers = QgsProject.instance().mapLayersByName('profile_points')
if layers:
layer = layers[0]
hasFields = all(v in [f.name() for f in layer.fields()] for v in ['d','z'])
if hasFields and layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QgsWkbTypes.PointGeometry:
self.pointLayer = layer

if not self.pointLayer:
# create temporary profile point layer (horizontal distance=d, raster band value=z)
self.pointLayer = QgsVectorLayer("Point?field=z:double&field=d:double&index=yes&crs="+QgsProject.instance().crs().authid(),"profile_points","memory")
QgsProject.instance().addMapLayer(self.pointLayer)

print('D: '+str(x)+',Z: '+str(y)+', '+str(pointprojected))
provider = self.pointLayer.dataProvider()
feat = QgsFeature(self.pointLayer.fields())
feat.setGeometry(QgsGeometry.fromPointXY(pointprojected))
feat['z'] = y.item()
feat['d'] = x.item()
provider.addFeatures([feat])
self.pointLayer.updateExtents()
self.pointLayer.triggerRepaint()

def updateCursorOnMap(self, x):
self.x_cursor = x
if self.pointstoDraw and self.doTracking:
Expand All @@ -263,10 +308,6 @@ def updateCursorOnMap(self, x):
geom = QgsGeometry.fromPolylineXY(points)
try:
if len(points) > 1:
# May crash with a single point in polyline on
# QGis 3.0.2,
# Issue #1 on PANOimagen's repo,
# Bug report #18987 on qgis.
pointprojected = geom.interpolate(x).asPoint()
else:
pointprojected = points[0]
Expand Down Expand Up @@ -346,12 +387,51 @@ def mouseevent_mpl(self, event):
def enableMouseCoordonates(self, library):
if library == "PyQtGraph":
self.dockwidget.plotWdg.scene().sigMouseMoved.connect(self.mouseMovedPyQtGraph)
self.dockwidget.plotWdg.scene().sigMouseClicked.connect(self.mouseClickedPyQtGraph)
self.dockwidget.plotWdg.getViewBox().autoRange(
items=self.dockwidget.plotWdg.getPlotItem().listDataItems()
)
# self.dockwidget.plotWdg.getViewBox().sigRangeChanged.connect(self.dockwidget.plotRangechanged)
self.dockwidget.connectPlotRangechanged()

def mouseClickedPyQtGraph(self, event):
pos = event.scenePos()
if self.dockwidget.plotWdg.sceneBoundingRect().contains(pos) and self.dockwidget.showcursor:
range = self.dockwidget.plotWdg.getViewBox().viewRange()
# récupère le point souris à partir ViewBox
mousePoint = self.dockwidget.plotWdg.getViewBox().mapSceneToView(pos)

datas = []
pitems = self.dockwidget.plotWdg.getPlotItem()
ytoplot = None
xtoplot = None

if len(pitems.listDataItems()) > 0:
# get data and nearest xy from cursor
compt = 0
try:
for item in pitems.listDataItems():
if item.isVisible():
x, y = item.getData()
nearestindex = np.argmin(abs(np.array(x, dtype=float) - mousePoint.x()))
if compt == 0:
xtoplot = np.array(x, dtype=float)[nearestindex]
ytoplot = np.array(y)[nearestindex]
else:
if abs(np.array(y)[nearestindex] - mousePoint.y()) < abs(ytoplot - mousePoint.y()):
ytoplot = np.array(y)[nearestindex]
xtoplot = np.array(x)[nearestindex]
compt += 1
except (IndexError, ValueError):
ytoplot = None
xtoplot = None

xtoplot = round(xtoplot,2)
ytoplot = round(ytoplot,2)
if not xtoplot in self.distancesPicked:
self.setPointOnMap(xtoplot,ytoplot)
self.distancesPicked.append(xtoplot)

def disableMouseCoordonates(self):
with suppress(AttributeError, RuntimeError, TypeError):
self.dockwidget.plotWdg.scene().sigMouseMoved.disconnect(self.mouseMovedPyQtGraph)
Expand Down