Repository: PANOimagen/profiletool
Pull request #104: Extension for selection and storage of profile points
Author: login: cxcandid
Created: 2025-03-01T15:19:17Z | Merged: 2025-03-15T11:32:10Z

This PR contains a small extension for the selection and storage of profile points in a “profile_points” layer.


Diff:
diff --git a/metadata.txt b/metadata.txt
index ff2eaea..a92c5dc 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.1
+version=4.3.2
 author=Borys Jurgiel - Patrice Verchere - Etienne Tourigny - Javier Becerra
 email=javier@panoimagen.com
 supportsQt6=True
@@ -13,6 +13,9 @@ experimental=False
 deprecated=False
 
 changelog=
+    4.3.2 : Add support for picking and saving profile points when "Link mouse position" and "Tools Settings > Save seleted points..." are 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.1 : Nothing has changed, just a stable version. Let's see if more issue comes up!
     4.3.0 : Experimental for now as I might have break things...
         - Upgrade pyqtgraph to 0.13.7
diff --git a/profile_points/profile_points.qml b/profile_points/profile_points.qml
new file mode 100644
index 0000000..6810d63
--- /dev/null
+++ b/profile_points/profile_points.qml
@@ -0,0 +1,258 @@
+<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
+<qgis styleCategories="Symbology|Labeling" labelsEnabled="1" version="3.42.0-Münster">
+  <renderer-v2 enableorderby="0" referencescale="-1" forceraster="0" type="singleSymbol" symbollevels="0">
+    <symbols>
+      <symbol alpha="1" is_animated="0" force_rhr="0" type="marker" name="0" frame_rate="10" clip_to_extent="1">
+        <data_defined_properties>
+          <Option type="Map">
+            <Option value="" type="QString" name="name"/>
+            <Option name="properties"/>
+            <Option value="collection" type="QString" name="type"/>
+          </Option>
+        </data_defined_properties>
+        <layer enabled="1" class="SimpleMarker" locked="0" pass="0" id="{507e8ae5-3b69-4c1e-80d5-c44f94a00587}">
+          <Option type="Map">
+            <Option value="0" type="QString" name="angle"/>
+            <Option value="square" type="QString" name="cap_style"/>
+            <Option value="255,255,255,255,rgb:1,1,1,1" type="QString" name="color"/>
+            <Option value="1" type="QString" name="horizontal_anchor_point"/>
+            <Option value="bevel" type="QString" name="joinstyle"/>
+            <Option value="circle" type="QString" name="name"/>
+            <Option value="0,0" type="QString" name="offset"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="offset_map_unit_scale"/>
+            <Option value="MM" type="QString" name="offset_unit"/>
+            <Option value="0,0,0,255,rgb:0,0,0,1" type="QString" name="outline_color"/>
+            <Option value="solid" type="QString" name="outline_style"/>
+            <Option value="0.4" type="QString" name="outline_width"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="outline_width_map_unit_scale"/>
+            <Option value="MM" type="QString" name="outline_width_unit"/>
+            <Option value="area" type="QString" name="scale_method"/>
+            <Option value="3.2" type="QString" name="size"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="size_map_unit_scale"/>
+            <Option value="MM" type="QString" name="size_unit"/>
+            <Option value="1" type="QString" name="vertical_anchor_point"/>
+          </Option>
+          <data_defined_properties>
+            <Option type="Map">
+              <Option value="" type="QString" name="name"/>
+              <Option name="properties"/>
+              <Option value="collection" type="QString" name="type"/>
+            </Option>
+          </data_defined_properties>
+        </layer>
+        <layer enabled="1" class="SimpleMarker" locked="0" pass="0" id="{5d1b8f76-8985-495c-83d4-dd4aedd458d7}">
+          <Option type="Map">
+            <Option value="0" type="QString" name="angle"/>
+            <Option value="square" type="QString" name="cap_style"/>
+            <Option value="0,0,0,255,rgb:0,0,0,1" type="QString" name="color"/>
+            <Option value="1" type="QString" name="horizontal_anchor_point"/>
+            <Option value="bevel" type="QString" name="joinstyle"/>
+            <Option value="circle" type="QString" name="name"/>
+            <Option value="0,0" type="QString" name="offset"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="offset_map_unit_scale"/>
+            <Option value="MM" type="QString" name="offset_unit"/>
+            <Option value="0,0,0,255,rgb:0,0,0,1" type="QString" name="outline_color"/>
+            <Option value="solid" type="QString" name="outline_style"/>
+            <Option value="0.4" type="QString" name="outline_width"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="outline_width_map_unit_scale"/>
+            <Option value="MM" type="QString" name="outline_width_unit"/>
+            <Option value="area" type="QString" name="scale_method"/>
+            <Option value="0.7" type="QString" name="size"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="size_map_unit_scale"/>
+            <Option value="MM" type="QString" name="size_unit"/>
+            <Option value="1" type="QString" name="vertical_anchor_point"/>
+          </Option>
+          <data_defined_properties>
+            <Option type="Map">
+              <Option value="" type="QString" name="name"/>
+              <Option name="properties"/>
+              <Option value="collection" type="QString" name="type"/>
+            </Option>
+          </data_defined_properties>
+        </layer>
+      </symbol>
+    </symbols>
+    <rotation/>
+    <sizescale/>
+    <data-defined-properties>
+      <Option type="Map">
+        <Option value="" type="QString" name="name"/>
+        <Option name="properties"/>
+        <Option value="collection" type="QString" name="type"/>
+      </Option>
+    </data-defined-properties>
+  </renderer-v2>
+  <selection mode="Default">
+    <selectionColor invalid="1"/>
+    <selectionSymbol>
+      <symbol alpha="1" is_animated="0" force_rhr="0" type="marker" name="" frame_rate="10" clip_to_extent="1">
+        <data_defined_properties>
+          <Option type="Map">
+            <Option value="" type="QString" name="name"/>
+            <Option name="properties"/>
+            <Option value="collection" type="QString" name="type"/>
+          </Option>
+        </data_defined_properties>
+        <layer enabled="1" class="SimpleMarker" locked="0" pass="0" id="{d6c5b189-70ac-4c72-a51b-dba56e1fe2d1}">
+          <Option type="Map">
+            <Option value="0" type="QString" name="angle"/>
+            <Option value="square" type="QString" name="cap_style"/>
+            <Option value="255,0,0,255,rgb:1,0,0,1" type="QString" name="color"/>
+            <Option value="1" type="QString" name="horizontal_anchor_point"/>
+            <Option value="bevel" type="QString" name="joinstyle"/>
+            <Option value="circle" type="QString" name="name"/>
+            <Option value="0,0" type="QString" name="offset"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="offset_map_unit_scale"/>
+            <Option value="MM" type="QString" name="offset_unit"/>
+            <Option value="35,35,35,255,rgb:0.13725490196078433,0.13725490196078433,0.13725490196078433,1" type="QString" name="outline_color"/>
+            <Option value="solid" type="QString" name="outline_style"/>
+            <Option value="0" type="QString" name="outline_width"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="outline_width_map_unit_scale"/>
+            <Option value="MM" type="QString" name="outline_width_unit"/>
+            <Option value="diameter" type="QString" name="scale_method"/>
+            <Option value="2" type="QString" name="size"/>
+            <Option value="3x:0,0,0,0,0,0" type="QString" name="size_map_unit_scale"/>
+            <Option value="MM" type="QString" name="size_unit"/>
+            <Option value="1" type="QString" name="vertical_anchor_point"/>
+          </Option>
+          <data_defined_properties>
+            <Option type="Map">
+              <Option value="" type="QString" name="name"/>
+              <Option name="properties"/>
+              <Option value="collection" type="QString" name="type"/>
+            </Option>
+          </data_defined_properties>
+        </layer>
+      </symbol>
+    </selectionSymbol>
+  </selection>
+  <labeling type="simple">
+    <settings calloutType="balloon">
+      <text-style useSubstitutions="0" fontWeight="50" multilineHeight="1" tabStopDistanceUnit="Point" tabStopDistanceMapUnitScale="3x:0,0,0,0,0,0" fontWordSpacing="0" fontUnderline="0" tabStopDistance="80" fieldName="'z: '||&quot;z&quot;||'\n'||'d: '||&quot;d&quot;" legendString="Aa" fontSizeUnit="Point" fontKerning="1" forcedItalic="0" textColor="50,50,50,255,rgb:0.19607843137254902,0.19607843137254902,0.19607843137254902,1" fontItalic="0" fontFamily="Arial" fontSize="10" forcedBold="0" fontLetterSpacing="0" isExpression="1" textOpacity="1" namedStyle="Standard" allowHtml="0" capitalization="0" blendMode="0" fontStrikeout="0" fontSizeMapUnitScale="3x:0,0,0,0,0,0" multilineHeightUnit="Percentage" textOrientation="horizontal" previewBkgrdColor="255,255,255,255,rgb:1,1,1,1">
+        <families/>
+        <text-buffer bufferSizeUnits="MM" bufferSizeMapUnitScale="3x:0,0,0,0,0,0" bufferJoinStyle="128" bufferColor="250,250,250,255,rgb:0.98039215686274506,0.98039215686274506,0.98039215686274506,1" bufferNoFill="1" bufferOpacity="1" bufferBlendMode="0" bufferDraw="0" bufferSize="1"/>
+        <text-mask maskedSymbolLayers="" maskSize2="1.5" maskOpacity="1" maskType="0" maskSizeMapUnitScale="3x:0,0,0,0,0,0" maskJoinStyle="128" maskEnabled="0" maskSize="1.5" maskSizeUnits="MM"/>
+        <background shapeJoinStyle="64" shapeOffsetY="0" shapeSizeX="3" shapeBorderWidthMapUnitScale="3x:0,0,0,0,0,0" shapeDraw="0" shapeFillColor="255,255,255,255,rgb:1,1,1,1" shapeBorderWidth="0.5" shapeOffsetMapUnitScale="3x:0,0,0,0,0,0" shapeSizeMapUnitScale="3x:0,0,0,0,0,0" shapeOffsetX="0" shapeRotationType="0" shapeRadiiMapUnitScale="3x:0,0,0,0,0,0" shapeRadiiUnit="Point" shapeRotation="0" shapeSVGFile="" shapeBorderColor="0,0,0,255,hsv:0,0,0,1" shapeBorderWidthUnit="Point" shapeBlendMode="0" shapeSizeType="0" shapeSizeUnit="Point" shapeSizeY="2" shapeRadiiY="0" shapeRadiiX="0" shapeOffsetUnit="Point" shapeType="0" shapeOpacity="1">
+          <symbol alpha="1" is_animated="0" force_rhr="0" type="marker" name="markerSymbol" frame_rate="10" clip_to_extent="1">
+            <data_defined_properties>
+              <Option type="Map">
+                <Option value="" type="QString" name="name"/>
+                <Option name="properties"/>
+                <Option value="collection" type="QString" name="type"/>
+              </Option>
+            </data_defined_properties>
+            <layer enabled="1" class="SimpleMarker" locked="0" pass="0" id="">
+              <Option type="Map">
+                <Option value="0" type="QString" name="angle"/>
+                <Option value="square" type="QString" name="cap_style"/>
+                <Option value="231,113,72,255,rgb:0.90588235294117647,0.44313725490196076,0.28235294117647058,1" type="QString" name="color"/>
+                <Option value="1" type="QString" name="horizontal_anchor_point"/>
+                <Option value="bevel" type="QString" name="joinstyle"/>
+                <Option value="circle" type="QString" name="name"/>
+                <Option value="0,0" type="QString" name="offset"/>
+                <Option value="3x:0,0,0,0,0,0" type="QString" name="offset_map_unit_scale"/>
+                <Option value="MM" type="QString" name="offset_unit"/>
+                <Option value="35,35,35,255,rgb:0.13725490196078433,0.13725490196078433,0.13725490196078433,1" type="QString" name="outline_color"/>
+                <Option value="solid" type="QString" name="outline_style"/>
+                <Option value="0" type="QString" name="outline_width"/>
+                <Option value="3x:0,0,0,0,0,0" type="QString" name="outline_width_map_unit_scale"/>
+                <Option value="MM" type="QString" name="outline_width_unit"/>
+                <Option value="diameter" type="QString" name="scale_method"/>
+                <Option value="2" type="QString" name="size"/>
+                <Option value="3x:0,0,0,0,0,0" type="QString" name="size_map_unit_scale"/>
+                <Option value="MM" type="QString" name="size_unit"/>
+                <Option value="1" type="QString" name="vertical_anchor_point"/>
+              </Option>
+              <data_defined_properties>
+                <Option type="Map">
+                  <Option value="" type="QString" name="name"/>
+                  <Option name="properties"/>
+                  <Option value="collection" type="QString" name="type"/>
+                </Option>
+              </data_defined_properties>
+            </layer>
+          </symbol>
+          <symbol alpha="1" is_animated="0" force_rhr="0" type="fill" name="fillSymbol" frame_rate="10" clip_to_extent="1">
+            <data_defined_properties>
+              <Option type="Map">
+                <Option value="" type="QString" name="name"/>
+                <Option name="properties"/>
+                <Option value="collection" type="QString" name="type"/>
+              </Option>
+            </data_defined_properties>
+            <layer enabled="1" class="SimpleFill" locked="0" pass="0" id="">
+              <Option type="Map">
+                <Option value="3x:0,0,0,0,0,0" type="QString" name="border_width_map_unit_scale"/>
+                <Option value="255,255,255,255,rgb:1,1,1,1" type="QString" name="color"/>
+                <Option value="bevel" type="QString" name="joinstyle"/>
+                <Option value="0,0" type="QString" name="offset"/>
+                <Option value="3x:0,0,0,0,0,0" type="QString" name="offset_map_unit_scale"/>
+                <Option value="MM" type="QString" name="offset_unit"/>
+                <Option value="0,0,0,255,hsv:0,0,0,1" type="QString" name="outline_color"/>
+                <Option value="solid" type="QString" name="outline_style"/>
+                <Option value="0.5" type="QString" name="outline_width"/>
+                <Option value="Point" type="QString" name="outline_width_unit"/>
+                <Option value="solid" type="QString" name="style"/>
+              </Option>
+              <data_defined_properties>
+                <Option type="Map">
+                  <Option value="" type="QString" name="name"/>
+                  <Option name="properties"/>
+                  <Option value="collection" type="QString" name="type"/>
+                </Option>
+              </data_defined_properties>
+            </layer>
+          </symbol>
+        </background>
+        <shadow shadowRadiusMapUnitScale="3x:0,0,0,0,0,0" shadowRadiusUnit="MM" shadowScale="100" shadowOffsetUnit="MM" shadowOpacity="0.69999999999999996" shadowRadiusAlphaOnly="0" shadowBlendMode="6" shadowColor="0,0,0,255,rgb:0,0,0,1" shadowOffsetAngle="135" shadowRadius="1.5" shadowOffsetMapUnitScale="3x:0,0,0,0,0,0" shadowDraw="0" shadowOffsetDist="1" shadowUnder="0" shadowOffsetGlobal="1"/>
+        <dd_properties>
+          <Option type="Map">
+            <Option value="" type="QString" name="name"/>
+            <Option name="properties"/>
+            <Option value="collection" type="QString" name="type"/>
+          </Option>
+        </dd_properties>
+        <substitutions/>
+      </text-style>
+      <text-format autoWrapLength="0" leftDirectionSymbol="&lt;" useMaxLineLengthForAutoWrap="1" placeDirectionSymbol="0" rightDirectionSymbol=">" decimals="3" reverseDirectionSymbol="0" plussign="0" addDirectionSymbol="0" multilineAlign="3" wrapChar="" formatNumbers="0"/>
+      <placement lineAnchorClipping="0" repeatDistanceMapUnitScale="3x:0,0,0,0,0,0" lineAnchorType="0" maxCurvedCharAngleIn="25" repeatDistance="0" overrunDistance="0" overlapHandling="AllowOverlapIfRequired" priority="10" polygonPlacementFlags="2" layerType="PointGeometry" prioritization="PreferCloser" maximumDistanceUnit="MM" dist="5" geometryGeneratorEnabled="0" lineAnchorPercent="0.5" xOffset="0" maxCurvedCharAngleOut="-25" overrunDistanceUnit="MM" placement="6" offsetType="1" maximumDistanceMapUnitScale="3x:0,0,0,0,0,0" allowDegraded="0" maximumDistance="0" geometryGeneratorType="PointGeometry" labelOffsetMapUnitScale="3x:0,0,0,0,0,0" fitInPolygonOnly="0" centroidWhole="0" centroidInside="0" predefinedPositionOrder="TR,TL,BR,BL,R,L,TSR,BSR" lineAnchorTextPoint="FollowPlacement" distUnits="MM" geometryGenerator="" rotationUnit="AngleDegrees" preserveRotation="1" distMapUnitScale="3x:0,0,0,0,0,0" rotationAngle="0" overrunDistanceMapUnitScale="3x:0,0,0,0,0,0" offsetUnits="MM" quadOffset="4" repeatDistanceUnits="MM" yOffset="0" placementFlags="10"/>
+      <rendering fontMinPixelSize="3" limitNumLabels="0" obstacleFactor="1" minFeatureSize="0" maxNumLabels="2000" scaleMin="0" fontLimitPixelSize="0" obstacleType="1" scaleMax="0" upsidedownLabels="0" labelPerPart="0" unplacedVisibility="0" scaleVisibility="0" mergeLines="0" fontMaxPixelSize="10000" obstacle="1" zIndex="0" drawLabels="1"/>
+      <dd_properties>
+        <Option type="Map">
+          <Option value="" type="QString" name="name"/>
+          <Option name="properties"/>
+          <Option value="collection" type="QString" name="type"/>
+        </Option>
+      </dd_properties>
+      <callout type="balloon">
+        <Option type="Map">
+          <Option value="pole_of_inaccessibility" type="QString" name="anchorPoint"/>
+          <Option value="0" type="int" name="blendMode"/>
+          <Option value="8" type="double" name="cornerRadius"/>
+          <Option value="3x:0,0,0,0,0,0" type="QString" name="cornerRadiusMapUnitScale"/>
+          <Option value="Point" type="QString" name="cornerRadiusUnit"/>
+          <Option type="Map" name="ddProperties">
+            <Option value="" type="QString" name="name"/>
+            <Option name="properties"/>
+            <Option value="collection" type="QString" name="type"/>
+          </Option>
+          <Option value="1" type="QString" name="enabled"/>
+          <Option value="&lt;symbol alpha=&quot;1&quot; is_animated=&quot;0&quot; force_rhr=&quot;0&quot; type=&quot;fill&quot; name=&quot;symbol&quot; frame_rate=&quot;10&quot; clip_to_extent=&quot;1&quot;>&lt;data_defined_properties>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;&quot; type=&quot;QString&quot; name=&quot;name&quot;/>&lt;Option name=&quot;properties&quot;/>&lt;Option value=&quot;collection&quot; type=&quot;QString&quot; name=&quot;type&quot;/>&lt;/Option>&lt;/data_defined_properties>&lt;layer enabled=&quot;1&quot; class=&quot;SimpleFill&quot; locked=&quot;0&quot; pass=&quot;0&quot; id=&quot;{ec1d1d0f-0daa-497d-8985-c7d00ff10ab2}&quot;>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;3x:0,0,0,0,0,0&quot; type=&quot;QString&quot; name=&quot;border_width_map_unit_scale&quot;/>&lt;Option value=&quot;255,255,255,255,rgb:1,1,1,1&quot; type=&quot;QString&quot; name=&quot;color&quot;/>&lt;Option value=&quot;bevel&quot; type=&quot;QString&quot; name=&quot;joinstyle&quot;/>&lt;Option value=&quot;0,0&quot; type=&quot;QString&quot; name=&quot;offset&quot;/>&lt;Option value=&quot;3x:0,0,0,0,0,0&quot; type=&quot;QString&quot; name=&quot;offset_map_unit_scale&quot;/>&lt;Option value=&quot;MM&quot; type=&quot;QString&quot; name=&quot;offset_unit&quot;/>&lt;Option value=&quot;35,35,35,255,rgb:0.13725490196078433,0.13725490196078433,0.13725490196078433,1&quot; type=&quot;QString&quot; name=&quot;outline_color&quot;/>&lt;Option value=&quot;solid&quot; type=&quot;QString&quot; name=&quot;outline_style&quot;/>&lt;Option value=&quot;0.26&quot; type=&quot;QString&quot; name=&quot;outline_width&quot;/>&lt;Option value=&quot;MM&quot; type=&quot;QString&quot; name=&quot;outline_width_unit&quot;/>&lt;Option value=&quot;solid&quot; type=&quot;QString&quot; name=&quot;style&quot;/>&lt;/Option>&lt;data_defined_properties>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;&quot; type=&quot;QString&quot; name=&quot;name&quot;/>&lt;Option name=&quot;properties&quot;/>&lt;Option value=&quot;collection&quot; type=&quot;QString&quot; name=&quot;type&quot;/>&lt;/Option>&lt;/data_defined_properties>&lt;/layer>&lt;/symbol>" type="QString" name="fillSymbol"/>
+          <Option value="point_on_exterior" type="QString" name="labelAnchorPoint"/>
+          <Option value="4,2.20000000000000018,4,2" type="QString" name="margins"/>
+          <Option value="Pixel" type="QString" name="marginsUnit"/>
+          <Option value="&lt;symbol alpha=&quot;1&quot; is_animated=&quot;0&quot; force_rhr=&quot;0&quot; type=&quot;marker&quot; name=&quot;symbol&quot; frame_rate=&quot;10&quot; clip_to_extent=&quot;1&quot;>&lt;data_defined_properties>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;&quot; type=&quot;QString&quot; name=&quot;name&quot;/>&lt;Option name=&quot;properties&quot;/>&lt;Option value=&quot;collection&quot; type=&quot;QString&quot; name=&quot;type&quot;/>&lt;/Option>&lt;/data_defined_properties>&lt;layer enabled=&quot;1&quot; class=&quot;SimpleMarker&quot; locked=&quot;0&quot; pass=&quot;0&quot; id=&quot;{70460173-7878-4cd8-9720-e467738e1064}&quot;>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;0&quot; type=&quot;QString&quot; name=&quot;angle&quot;/>&lt;Option value=&quot;square&quot; type=&quot;QString&quot; name=&quot;cap_style&quot;/>&lt;Option value=&quot;255,255,255,0,rgb:1,1,1,0&quot; type=&quot;QString&quot; name=&quot;color&quot;/>&lt;Option value=&quot;1&quot; type=&quot;QString&quot; name=&quot;horizontal_anchor_point&quot;/>&lt;Option value=&quot;bevel&quot; type=&quot;QString&quot; name=&quot;joinstyle&quot;/>&lt;Option value=&quot;circle&quot; type=&quot;QString&quot; name=&quot;name&quot;/>&lt;Option value=&quot;0,0&quot; type=&quot;QString&quot; name=&quot;offset&quot;/>&lt;Option value=&quot;3x:0,0,0,0,0,0&quot; type=&quot;QString&quot; name=&quot;offset_map_unit_scale&quot;/>&lt;Option value=&quot;MM&quot; type=&quot;QString&quot; name=&quot;offset_unit&quot;/>&lt;Option value=&quot;35,35,35,255,rgb:0.13725490196078433,0.13725490196078433,0.13725490196078433,1&quot; type=&quot;QString&quot; name=&quot;outline_color&quot;/>&lt;Option value=&quot;solid&quot; type=&quot;QString&quot; name=&quot;outline_style&quot;/>&lt;Option value=&quot;0&quot; type=&quot;QString&quot; name=&quot;outline_width&quot;/>&lt;Option value=&quot;3x:0,0,0,0,0,0&quot; type=&quot;QString&quot; name=&quot;outline_width_map_unit_scale&quot;/>&lt;Option value=&quot;MM&quot; type=&quot;QString&quot; name=&quot;outline_width_unit&quot;/>&lt;Option value=&quot;diameter&quot; type=&quot;QString&quot; name=&quot;scale_method&quot;/>&lt;Option value=&quot;0&quot; type=&quot;QString&quot; name=&quot;size&quot;/>&lt;Option value=&quot;3x:0,0,0,0,0,0&quot; type=&quot;QString&quot; name=&quot;size_map_unit_scale&quot;/>&lt;Option value=&quot;Point&quot; type=&quot;QString&quot; name=&quot;size_unit&quot;/>&lt;Option value=&quot;1&quot; type=&quot;QString&quot; name=&quot;vertical_anchor_point&quot;/>&lt;/Option>&lt;data_defined_properties>&lt;Option type=&quot;Map&quot;>&lt;Option value=&quot;&quot; type=&quot;QString&quot; name=&quot;name&quot;/>&lt;Option name=&quot;properties&quot;/>&lt;Option value=&quot;collection&quot; type=&quot;QString&quot; name=&quot;type&quot;/>&lt;/Option>&lt;/data_defined_properties>&lt;/layer>&lt;/symbol>" type="QString" name="markerSymbol"/>
+          <Option value="0" type="double" name="offsetFromAnchor"/>
+          <Option value="3x:0,0,0,0,0,0" type="QString" name="offsetFromAnchorMapUnitScale"/>
+          <Option value="MM" type="QString" name="offsetFromAnchorUnit"/>
+          <Option value="10" type="double" name="wedgeWidth"/>
+          <Option value="3x:0,0,0,0,0,0" type="QString" name="wedgeWidthMapUnitScale"/>
+          <Option value="Point" type="QString" name="wedgeWidthUnit"/>
+        </Option>
+      </callout>
+    </settings>
+  </labeling>
+  <blendMode>0</blendMode>
+  <featureBlendMode>0</featureBlendMode>
+  <layerGeometryType>0</layerGeometryType>
+</qgis>
diff --git a/tools/profiletool_core.py b/tools/profiletool_core.py
index ba9b447..6f16ca5 100644
--- a/tools/profiletool_core.py
+++ b/tools/profiletool_core.py
@@ -27,9 +27,11 @@
 from contextlib import suppress
 
 import numpy as np
+import os
 
 # qgis import
-from qgis.core import QgsGeometry, QgsMapLayer, QgsPoint, QgsPointXY, QgsProject
+from qgis.core import QgsGeometry, QgsMapLayer, QgsPoint, QgsPointXY, QgsProject, Qgis
+from qgis.core import QgsVectorLayer, QgsFeature, QgsWkbTypes
 
 # from qgis.gui import *
 from qgis.PyQt.QtCore import QSettings, Qt
@@ -166,6 +168,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 +258,52 @@ 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)
+
+                    provider = self.pointLayer.dataProvider()
+                    feat = QgsFeature(self.pointLayer.fields())
+                    feat.setGeometry(QgsGeometry.fromPointXY(pointprojected))
+                    feat['d'] = x.item()
+                    feat['z'] = y.item()
+                    provider.addFeatures([feat])
+                    self.iface.messageBar().pushMessage("Profile Tool", "Point added to layer \"profile_points\"", level=Qgis.Info)
+                    qmlPath = os.path.dirname(__file__)
+                    qmlPath = os.path.dirname(qmlPath)
+                    self.pointLayer.loadNamedStyle(qmlPath+'/profile_points/profile_points.qml')
+                    self.pointLayer.updateExtents()
+                    self.pointLayer.triggerRepaint()
+
     def updateCursorOnMap(self, x):
         self.x_cursor = x
         if self.pointstoDraw and self.doTracking:
@@ -263,10 +312,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 +391,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.cbAddPoint.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..9356a9b 100644
--- a/ui/profiletool.ui
+++ b/ui/profiletool.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>921</width>
-    <height>380</height>
+    <width>803</width>
+    <height>422</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -431,40 +431,6 @@
                <string>Options</string>
               </property>
               <layout class="QGridLayout" name="gridLayout">
-               <item row="1" column="1">
-                <widget class="QCheckBox" name="checkBox_mpl_tracking">
-                 <property name="enabled">
-                  <bool>true</bool>
-                 </property>
-                 <property name="text">
-                  <string>Link mouse position 
-on graph with canvas</string>
-                 </property>
-                 <property name="checked">
-                  <bool>true</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="0">
-                <widget class="QCheckBox" name="checkBox_showcursor">
-                 <property name="text">
-                  <string>Show cursor</string>
-                 </property>
-                 <property name="checked">
-                  <bool>true</bool>
-                 </property>
-                 <property name="tristate">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="0">
-                <widget class="QLabel" name="label">
-                 <property name="text">
-                  <string>Selection</string>
-                 </property>
-                </widget>
-               </item>
                <item row="0" column="1">
                 <widget class="QComboBox" name="comboBox">
                  <property name="sizePolicy">
@@ -493,29 +459,40 @@ on graph with canvas</string>
                  </item>
                 </widget>
                </item>
-               <item row="2" column="0">
-                <widget class="QCheckBox" name="cbSameAxisScale">
-                 <property name="toolTip">
-                  <string>Always keep the same scale for X and Y axis. &lt;br/&gt;&lt;br/&gt;&lt;i&gt;Only available with PyQtGraph plot library&lt;/i&gt;</string>
-                 </property>
+               <item row="1" column="0">
+                <widget class="QCheckBox" name="checkBox_showcursor">
                  <property name="text">
-                  <string>Same axis scale</string>
+                  <string>Show cursor</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
+                 </property>
+                 <property name="tristate">
+                  <bool>false</bool>
                  </property>
                 </widget>
                </item>
-               <item row="2" column="1">
-                <widget class="QCheckBox" name="cbLiveUpdate">
-                 <property name="toolTip">
-                  <string>Update graph while capturing. Disable if using huge dataset.</string>
+               <item row="1" column="1">
+                <widget class="QCheckBox" name="checkBox_mpl_tracking">
+                 <property name="enabled">
+                  <bool>true</bool>
                  </property>
                  <property name="text">
-                  <string>Live update</string>
+                  <string>Link mouse position 
+on graph with canvas</string>
                  </property>
                  <property name="checked">
                   <bool>true</bool>
                  </property>
                 </widget>
                </item>
+               <item row="0" column="0">
+                <widget class="QLabel" name="label">
+                 <property name="text">
+                  <string>Selection</string>
+                 </property>
+                </widget>
+               </item>
               </layout>
              </widget>
             </item>
@@ -540,8 +517,8 @@ on graph with canvas</string>
             <rect>
              <x>0</x>
              <y>0</y>
-             <width>889</width>
-             <height>306</height>
+             <width>771</width>
+             <height>348</height>
             </rect>
            </property>
           </widget>
@@ -569,9 +546,26 @@ on graph with canvas</string>
         <item row="0" column="0">
          <widget class="QGroupBox" name="groupBox_2">
           <property name="title">
-           <string>Full Resolution</string>
+           <string>Tool Settings</string>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_7">
+           <item>
+            <widget class="QCheckBox" name="cbLiveUpdate">
+             <property name="text">
+              <string>Live update</string>
+             </property>
+             <property name="checked">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QCheckBox" name="cbSameAxisScale">
+             <property name="text">
+              <string>Same axis scale</string>
+             </property>
+            </widget>
+           </item>
            <item>
             <widget class="QCheckBox" name="fullResolutionCheckBox">
              <property name="sizePolicy">
@@ -588,6 +582,13 @@ on graph with canvas</string>
              </property>
             </widget>
            </item>
+           <item>
+            <widget class="QCheckBox" name="cbAddPoint">
+             <property name="text">
+              <string>Save selected points in layer &quot;profile_points&quot;</string>
+             </property>
+            </widget>
+           </item>
           </layout>
          </widget>
         </item>


Reviews:
user: login: nicogodet
body: Could you make the feature deactivable and disable by default ?

User could also choose an existing layer instead of a new memory layer. What do you think ?

Nevertheless good feature!
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-02T01:22:25Z
user: login: cxcandid
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T14:01:32Z
user: login: cxcandid
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T14:02:12Z
user: login: cxcandid
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T14:04:13Z
user: login: cxcandid
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-03T14:06:01Z
user: login: nicogodet
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-04T01:00:20Z
user: login: cxcandid
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-04T07:27:41Z

Review comments:
diff_hunk: @@ -30,6 +30,7 @@
 
 # qgis import
 from qgis.core import QgsGeometry, QgsMapLayer, QgsPoint, QgsPointXY, QgsProject
+from qgis.core import QgsVectorLayer, QgsFeature # added by C.Candido
path: tools/profiletool_core.py
user: login: nicogodet
body: ```suggestion
from qgis.core import QgsVectorLayer, QgsFeature
```

No need, git blame does this for us and it overloads the code.
Could remove all others ?

created_at: 2025-03-02T01:10:47Z
author_association: COLLABORATOR
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
+        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:
+                        # 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()
path: tools/profiletool_core.py
user: login: nicogodet
body: Minimum version is 3.40, is it still needed ?
created_at: 2025-03-02T01:11:27Z
author_association: COLLABORATOR
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
path: tools/profiletool_core.py
user: login: nicogodet
body: Could apply a proper PEP8 format (spaces required after comma) ?
Black is fine 
created_at: 2025-03-02T01:13:21Z
author_association: COLLABORATOR
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
+        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:
+                        # 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]
+                except (IndexError, AttributeError, ValueError):
+                    pointprojected = None
+
+                if pointprojected:
+                    layers = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
+                    if not 'profile_points' in layers:
+                        # create temporary profile point layer (horizontal distance=d, raster band value=z)
+                        layer = QgsVectorLayer("Point?field=z:double&field=d:double&index=yes&crs="+QgsProject.instance().crs().authid(),"profile_points","memory")
+                        QgsProject.instance().addMapLayer(layer)
+                    else:
+                        layer = QgsProject.instance().mapLayersByName('profile_points')[0]
+
path: tools/profiletool_core.py
user: login: nicogodet
body: Could you improve the logic ?
Store `layer` in class attributes
Initialize it to None
Check if self.layer is None, if None creates it and set self.layer accordingly 

Doing so, it avoids to list all project layers each time you add a point.
created_at: 2025-03-02T01:19:29Z
author_association: COLLABORATOR
diff_hunk: @@ -346,12 +385,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) # added by C.Candido
             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): #added by Candido
+       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
path: tools/profiletool_core.py
user: login: nicogodet
body: Translate in English 
created_at: 2025-03-02T01:20:10Z
author_association: COLLABORATOR
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
+        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:
+                        # 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]
+                except (IndexError, AttributeError, ValueError):
+                    pointprojected = None
+
+                if pointprojected:
+                    layers = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
+                    if not 'profile_points' in layers:
+                        # create temporary profile point layer (horizontal distance=d, raster band value=z)
+                        layer = QgsVectorLayer("Point?field=z:double&field=d:double&index=yes&crs="+QgsProject.instance().crs().authid(),"profile_points","memory")
+                        QgsProject.instance().addMapLayer(layer)
+                    else:
+                        layer = QgsProject.instance().mapLayersByName('profile_points')[0]
+
path: tools/profiletool_core.py
user: login: cxcandid
body: I have adapted the code accordingly. The static layer name “profile_points” simplifies the extension, as we can dispense with the layer selection and the selection of the columns “d” and “z”. To make the layer permanent, it can be exported and reloaded at any time, e.g. in GPKG. The memory layer must then be removed. I have added a few more checks: Layer is vector layer, geometry type is point, contains the fields “d” and “z”
created_at: 2025-03-03T14:01:32Z
author_association: NONE
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
path: tools/profiletool_core.py
user: login: cxcandid
body: see code changes
created_at: 2025-03-03T14:02:12Z
author_association: NONE
diff_hunk: @@ -255,6 +257,43 @@ def plotProfil(self, vertline=True):
         self.updateCursorOnMap(self.x_cursor)
         self.enableMouseCoordonates(self.dockwidget.plotlibrary)
 
+    def setPointOnMap(self,x,y): #added by C.Candido
+        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:
+                        # 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()
path: tools/profiletool_core.py
user: login: cxcandid
body: I have simply taken over existing code here.
created_at: 2025-03-03T14:04:13Z
author_association: NONE
diff_hunk: @@ -30,6 +30,7 @@
 
 # qgis import
 from qgis.core import QgsGeometry, QgsMapLayer, QgsPoint, QgsPointXY, QgsProject
+from qgis.core import QgsVectorLayer, QgsFeature # added by C.Candido
path: tools/profiletool_core.py
user: login: cxcandid
body: This was just internally for me to track the code changes. I have removed these comments.
created_at: 2025-03-03T14:06:01Z
author_association: NONE
diff_hunk: @@ -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)
path: tools/profiletool_core.py
user: login: nicogodet
body: It could be a single if/else
created_at: 2025-03-04T00:42:57Z
author_association: COLLABORATOR
diff_hunk: @@ -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))
path: tools/profiletool_core.py
user: login: nicogodet
body: ```suggestion
```

created_at: 2025-03-04T00:58:26Z
author_association: COLLABORATOR
diff_hunk: @@ -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)
path: tools/profiletool_core.py
user: login: cxcandid
body: No, `if not self.pointLayer` throws an exception when the layer is deleted. During exception handling, we search for an already loaded "profile_points" layer. If no layer exists, we create a new one.
created_at: 2025-03-04T07:27:41Z
author_association: NONE

PR comments:
user: login: cxcandid
created_at: 2025-03-03T14:10:06Z
body: @nicogodet do we really need to make this feature deactivable? ...there is no other function that would be in conflict here. 
author_association: NONE
user: login: nicogodet
created_at: 2025-03-04T01:41:48Z
body: > @nicogodet do we really need to make this feature deactivable? ...there is no other function that would be in conflict here. 

People can miss click on Canvas and create an unwanted layer.
author_association: COLLABORATOR
user: login: cxcandid
created_at: 2025-03-04T08:25:16Z
body: Added a checkbox for activating/deactivating point storage.
author_association: NONE
user: login: nicogodet
created_at: 2025-03-08T05:19:52Z
body: Could you rebase and update plugin version ?

Could you provide user a feedback that point has been added to profile_points layer using `self.iface.mainWindow().statusBar().showMessage("your_message")` ?

The "Options" group box is getting more and more crowded and I don't like that, it reduces the layer tree above. I might move most of checkboxes to Settings tab in full resolution groupbox (and rename this groupbox). If you are motivated, you can do this moves. Otherwise I will do it but it might delayed the release of new version...
author_association: COLLABORATOR
user: login: cxcandid
created_at: 2025-03-10T08:24:09Z
body: > Could you provide user a feedback that point has been added to profile_points layer using self.iface.mainWindow().statusBar().showMessage("your_message") ?

Should we offer default labels for the created points as well?


> The "Options" group box is getting more and more crowded ...

Good idea! We should rename `Full Resolution`: do you have a favorite name? (i.e. `Tool Settings`)
author_association: NONE
user: login: nicogodet
created_at: 2025-03-10T08:33:12Z
body: > Should we offer default labels for the created points as well?

As you want :)

> Good idea! We should rename `Full Resolution`: do you have a favorite name? (i.e. `Tool Settings`)

No strong opinion. Tool Settings is fine

author_association: COLLABORATOR
user: login: cxcandid
created_at: 2025-03-15T10:30:50Z
body: @nicogodet I have incorporated all changes, i's time to publish :)
author_association: NONE
user: login: nicogodet
created_at: 2025-03-15T11:36:17Z
body: Published! Waiting for approval...
author_association: COLLABORATOR