diff --git a/metadata.txt b/metadata.txt index 862ea09..4ffc4e1 100644 --- a/metadata.txt +++ b/metadata.txt @@ -5,7 +5,7 @@ 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=javier@panoimagen.com supportsQt6=True @@ -13,6 +13,9 @@ 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 diff --git a/tools/profiletool_core.py b/tools/profiletool_core.py index ba9b447..d6fc9a2 100644 --- a/tools/profiletool_core.py +++ b/tools/profiletool_core.py @@ -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 @@ -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()): @@ -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: @@ -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] @@ -346,12 +387,55 @@ 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): + if not self.dockwidget.checkBox_addpoint.isChecked(): + return + + 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 + + if xtoplot and ytoplot: + 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) diff --git a/ui/profiletool.ui b/ui/profiletool.ui index e007f8c..18bf692 100644 --- a/ui/profiletool.ui +++ b/ui/profiletool.ui @@ -6,8 +6,8 @@ 0 0 - 921 - 380 + 923 + 422 @@ -445,26 +445,6 @@ on graph with canvas - - - - Show cursor - - - true - - - false - - - - - - - Selection - - - @@ -493,13 +473,16 @@ on graph with canvas - - - - Always keep the same scale for X and Y axis. <br/><br/><i>Only available with PyQtGraph plot library</i> - + + - Same axis scale + Show cursor + + + true + + + false @@ -516,6 +499,37 @@ on graph with canvas + + + + Selection + + + + + + + Always keep the same scale for X and Y axis. <br/><br/><i>Only available with PyQtGraph plot library</i> + + + Same axis scale + + + + + + + + 0 + 0 + + + + Save selected points +in profile_points layer + + + @@ -540,8 +554,8 @@ on graph with canvas 0 0 - 889 - 306 + 98 + 28