# QGis-Plugin "Linear Referencing"

This Plugin supports

- the digitizing of "linear referenced" geometries:
  - derived from a referenced linestring-geometry
  - with one (Point-on-Line) ore two (Line-on-Line) numerical stationing
  - stored in a geometry-less data-table
- measurements on line geometries

## Preface

### Linear-referencing principal

#### "PoL" Point-on-Line

Point-features defined by 1:n-reference to linestring-layer and the stationing on the referenced line
Point-on-Line-feature
left-side: PoL-Dialog
right side: attribute form with minimal necessary data for point-on-line-features:

- Feature-Identifier (PK)
- Reference-Line-ID
- stationing = measured distance to start-point of reference line

#### "LoL"Line-on-Line

Line-segment-features defined by 1:n-reference to linestring-layer and two stationing (from...to) to the start-point and the offset to the referenced line.
Line-on-Line-feature
left-side: LoL-Dialog
right side: attribute form with minimal necessary data for line-on-line-features:

- Feature-Identifier (PK)
- Reference-Line-ID
- two measured stationing from...to
- offset = distance to referenced line

### Pre-Requisites

PoL and LoL use three kinds of layer:

#### Reference-Layer

- Mandatory vector-layer with linestring geometries
- geo-referenced basis for calculation of the measured points/segments

See: Reference-Layer

#### Data-Layer

- Optional storage of measured points/segments
- geometry-less

See: Data-Layer
Note: storage is optional, the plugin can be used for measurement purposes only

#### Show-Layer

- Optional presentation/styling of stored points/segments
- usually virtual
- for export and print
- for graphical selection within the plugin

See: Show-Layer
Note: storage and presentation are optional, the plugin can be used for measurement purposes only

### Installation and run

- Install the LinearReferencing-plugin via QGis-Plugin-Dialog (should be done, otherwise you probably would not read this documentation...)
- new toolbar:
- new menu-entries (same functionalities):

## PoL:Point-on-Line-Features

### Measurement

Pre-Requisite: Reference-Layer

1. Start map-tool via toolbar or menu
2. move mouse-cursor over reference-line-features on map
3. click at desired position to finish measurement and freeze results in dialog:

1. PK and Display-Expression of referenced feature
2. call attribute-form for referenced feature
3. zoom to referenced feature
4. cursor-coord-x *1
5. cursor-coord-y *1
6. snapped-coord-x *1
7. snapped-coord-y *1
8. distance to start-point of referenced feature (layer-units *2, changeable via numeric input or spin-buttons, ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000)
9. distance to start-point of referenced feature (percent, changeable via numeric input or spin-buttons)
10. move point to start of referenced line
11. move point towards start of referenced line (ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000)
12. move Point (interactive on canvas)
13. move point towards end of referenced line (ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000)
14. move point to end of referenced line
15. pan to point
16. clear results and resume measurement

*1 *2 See: projections

### Storage

Pre-Requisites: Reference-Layer + Data-Layer
Note 1:
Some screenshots of the following examples are taken from a minimal plugin-created Data-Layer.
You can customize this sample-layer, add/rename fields, design the feature-form...or use any other suitable layer or as long as the minimum requirements are met and the plugin is correct configured (see Data-Layer) .
Note 2:
You can obviously insert/update/delete records in Data-Layer by QGis-means and without plugin/dialog.
Note 3:
Storage is optional, the plugin can be used for measurement purposes only

#### Insert

1. Measure Feature on canvas, if necessary edit the measurement with "move point" or numerical editing of the measurement-value.
2. Hit the "Insert"-Button, which will be enabled, if Data-Layer is configured and measurement is done
3. this opens the insert-form for the Data-Layer already populated with the measurement-metadata (reference-ID, measurement)
4. if necessary edit the data and hit the "OK"-Button

#### Update

1. - Fill feature-selection, see Feature-Selection. From this table select the target-feature via /
   - ...or select feature from attribute-table/form via / see Attribute-Tables
2. Afterwards the selected edit-PK and its measurement-data is shown in dialog, the Update/Insert/Delete-Buttons are enabled.
3. Move the feature on the assigned reference-line with "move point", numerical editing of the measurement-value or digitizing a brand-new geometry with "Resume measurement".
4. Hit the "Update"-Button
5. this opens the update-form for this feature in Data-Layer with the accepted measurement-data of the dialog
6. if necessary edit the data and hit the "OK"-Button

#### Delete

Pre-work almost the same as update::

1. - Fill feature-selection, see Feature-Selection. From this table select the target-feature via /
   - ...or select feature from attribute-table/form via / see Attribute-Tables
2. Afterwards the selected edit-PK and its measurement-data is shown in dialog, the Update/Insert/Delete-Buttons are enabled.
3. Hit the "Delete"-Button

### Feature-Selection

Pre-Requisites: Reference-Layer + Data-Layer (+ Show-Layer)
A table with a selection of features, filled interactive from canvas, from data- or Show-Layer or from attribute-forms and tables. Also contains automatically the plugin-inserted features.
The meta-data of the selected features is shown, single features can be selected to show their calculated measurement-meta-data in dialog for update or delete.

1. select features from Show-Layer (if configured) by point (click) or rect (click and drag) on canvas
2. insert all features from Data-Layer
3. insert currently selected features from Data-Layer
4. insert currently selected features from Show-Layer
5. zoom to feature-selection
6. clear the selection

Icons within the table:

- remove feature from selection
- show measurement and highlight feature
- show measurement and pan to feature
- open attribute form

Note:
The plugin uses the "Display Name"-Expression for the textual-contents inside the table.
You can update these expressions for the selected reference-, -data or Show-Layer with the QGis-Layer-Properties-Dialog or with the
-Icons in the dialogs, section "Settings > Layers and Fields".

## LoL: Line-on-Line-Features

### Measure

if necessary: configure Reference-Layer in "Settings"-area (for convenience the first linestring-layer will be used automatically)

1. Start map-tool via toolbar or menu
2. move mouse-cursor over reference-line-features on map
3. mouse down at desired from-position to begin measurement
4. mouse-up at desired to-position to finish measurement and freeze results in dialog:

1. PK and Display-Expression of referenced feature
2. call attribute-form for referenced feature
3. zoom to referenced feature
4. Offset == distance between segment and referenced line, > 0 left side, < 0 right side (in digitize-direction of referenced line)
5. cursor-coord-x*1
6. cursor-coord-y*1
7. snapped-from-coord-y*1
8. snapped-to-coord-x*1
9. snapped-to-coord-y*1
10. from-point-distance to start-point of referenced feature (layer-units *2)
11. from-point-distance to start-point of referenced feature (percent)
12. to-point-distance to start-point of referenced feature (layer-units *2)
13. to-point-distance to start-point of referenced feature (percent)
14. move to reference-line start
15. flip segment towards reference-line start (maintain length, new to-point = old from-point)
16. move towards reference-line start (ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000)
17. length of segment (layer-units, changeable via numeric input or spin-buttons, ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000, to-point is altered)
18. move towards reference-line end (ctrl/shift/ctrl+shift-modifiers with factors 10, 100, 1000)
19. flip segment towards reference-line end (maintain length, new from-point = old to-point)
20. Buttons to move the segment towards reference-line end (end-point or stepwise 1/10/100/1000m click/ctrl/shift/ctrl+shift)
21. move From-Point (click on canvas and choose new start-point)
22. move To-Point (click on canvas and choose new end-point)

*1 *2 See: projections

### Storage

Pre-Requisites: Reference-Layer + Data-Layer
Note 1:
Some screenshots of the following examples are taken from a minimal plugin-created Data-Layer.
You can customize this sample-layer, add/rename fields, design the feature-form...or use any other suitable layer or as long as the minimum requirements are met and the plugin is correct configured (see Data-Layer) .
Note 2:
You can obviously insert/update/delete records in Data-Layer by QGis-means and without plugin/dialog.
Note 3:
Storage is optional, the plugin can be used for measurement purposes only

#### Insert

1. Measure Feature on canvas, if necessary edit from/to/length-measurements with "move From-Point"/"move To-Point"/"Move segment" or numerical editing of the measurement-from/measurement-to-values.
2. Hit the "Insert"-Button, which will be enabled, if Data-Layer is configured and measurement is done
3. this opens the insert-form for the Data-Layer already populated with the measurement-metadata (reference-ID, measurement-from, measurement-to, offset)
4. if necessary edit the data and hit the "OK"-Button

#### Update

1. - Fill feature-selection, see Feature-Selection. From this table select the target-feature via /
   - ...or select feature from attribute-table/form via / see Attribute-Tables
2. Afterwards the selected edit-PK and its measurement-data is shown in dialog, the Update/Insert/Delete-Buttons are enabled.
3. Edit from/to/length-measurement with "move From-Point"/"move To-Point"/"Move segment", numerical editing of the measurement-from/measurement-to-values or even digitize a brand-new segment with "Resume measurement"
4. Hit the "Update"-Button
5. this opens the update-form for this feature in Data-Layer with the accepted measurement-data of the dialog
6. if necessary edit the data and hit the "OK"-Button

#### Delete

Pre-work almost the same as update::

1. - Fill feature-selection, see Feature-Selection. From this table select the target-feature via /
   - ...or select feature from attribute-table/form via / see Attribute-Tables
2. Afterwards the selected edit-PK and its measurement-data is shown in dialog, the Update/Insert/Delete-Buttons are enabled.
3. Hit the "Delete"-Button

### Feature-Selection

Pre-Requisites: Reference-Layer + Data-Layer (+ Show-Layer)
A table with a selection of features, filled interactive from canvas, from data- or Show-Layer or from attribute-forms and tables. Also contains automatically the plugin-inserted features.
The meta-data of the selected features is shown, single features can be selected to show their calculated measurement-meta-data in dialog for update or delete.

1. select features from Show-Layer (if configured) by point (click) or rect (click and drag) on canvas
2. insert all features from Data-Layer
3. insert currently selected features from Data-Layer
4. insert currently selected features from Show-Layer
5. zoom to feature-selection
6. clear the selection

Icons within the table:

- remove feature from selection
- show measurement and highlight feature
- show measurement and zoom to feature
- open attribute form

Note:
The plugin uses the "Display Name"-Expression for the textual-contents inside the table.
You can update these expressions for the selected reference-, -data or Show-Layer with the QGis-Layer-Properties-Dialog or with the
-Icons in the dialogs, section "Settings > Layers and Fields".

## Settings (PoL + LoL)

### Reference-Layer:

- Mandatory linestring-layer
- all QGis-supported vector-layer-sources (shapefile, GeoPackage, SpatiaLite, geo-database...) (WFS not tested so far)
- does not need to be editable
- for convenience: the first linestring-layer will be used automatically

##### Supported geometry-sub-types:

- Linestring
- Linestring-M
- Linestring-Z
- Linestring-MZ
- Multi-Linestring
- Multi-Linestring-M
- Multi-Linestring-Z
- Multi-Linestring-MZ

see Multi-Linestring-Support

##### Mandatory Fields:

- single identify-column (unique, not null, mostly is but need not necessarily be PK or FID-column)

1. ComboBox to choose one of the available linestring-layers in current project
2. open attribute-table of currently selected reference layer
3. define display-expression, which will be shown in other parts of this dialog
4. ComboBox to choose one of the available fields in currently selected reference layer as identify field

### Data-Layer:

- Optional storage of measured points/segments
- geometry-less

#### PoL-Data-Layer

##### Mandatory Fields:

- identify-column (unique, not null, usually PK- or FID-column with auto-incremented integer)
- join-column to Reference-Layer (type matching to its identify-column)
- measurement-column (numeric type)

1. currently selected Data-Layer
2. open attribute-table
3. define display-expression (will be used in this dialog)
4. create a sample-gpkg-Data-Layer
5. identify field
6. join-field to Reference-Layer
7. measurement-field

#### LoL-Data-Layer

##### Mandatory Fields:

- identify-column (unique, not null, usually PK- or FID-column with auto-incremented integer)
- join-column to Reference-Layer (type matching to its identify-column)
- measurement-from-column (numeric type)
- measurement-to-column (numeric type)
- offset-column (numeric type)

1. currently selected Data-Layer
2. open attribute-table
3. define display-expression (will be used in this dialog)
4. create a sample-gpkg-Data-Layer
5. identify field
6. join-field to Reference-Layer
7. measurement-from-field
8. measurement-to-field
9. offset-field

Note: storage is optional, the plugin can be used for measurement purposes only

### Show-Layer:

- Optional presentation of stored points/segments
- usually a virtual-layer with a complex query on Data-Layer and Reference-Layer
  (See SpatiaLite "SQL functions supporting Linear Referencing")
- can be created manually (Layer > Create Layer > New virtual Layer...) or with support from plugin
- can be used (styled, exported, printed) as any other point rsp. linestring-layer
- enables interactive feature-selection from canvas (PoL-Feature-Selection / LoL-Feature-Selection)

Note 1: storage and presentation are optional, the plugin can be used for measurement purposes only
Note 2: if data- and Reference-Layer are contained in the same geo-database, an equivalent view from that database can be used, which should also be faster than the virtual-layer.

#### Mandatory Fields:

- back-reference-column (join to Data-Layer, typically the queried Data-Layer-ID-field)

1. currently selected Show-Layer
2. open attribute-table
3. define display-expression (will be used in this dialog)
4. create a virtual layer (queries selected data- and Reference-Layer)
5. back-reference-field

#### Enhanced legend for Line-on-Line-Show-Layer

The default-legend created by this plugin is a simple orange line.
Overlapping or lined up segments, each segment starting at the end of previous one, are hard to demarcate without identifiable start- and end-points: But fortunately QGis offers complex symbols with symbol layer type "Geometry Generator" and "Symbol Levels":

1. Original Symbol:
2. Add and style Symbol-Layer for End-Point, type "Geometry Generator", Geometry type "Point/Multipoint", expression end_point($geometry)
3. Same for Start-Point with expression start_point($geometry)
4. Apply Symbol-Levels to ensure, that the start/end-points are not overlapped by the lines

### Styles:

Configure the style of the temporal measurement-shapes.

#### PoL

1. "Measure Point"-symbol (type, size, outline-width, outline-color, fill-color)
2. "Edit Point"-symbol (shows the original position when the currently measured point is about to be moved)
3. "Reference-Line" : mark the selected Reference-Layer-shape (line-style, width, color)

#### LoL

1. "From Point"-symbol (type, size, outline-width, outline-color, fill-color)
2. "To Point"-symbol (type, size, outline-width, outline-color, fill-color)
3. "Segment-Line" (line-style, width, color)
4. "Reference-Line" : mark the selected Reference-Layer-shape (line-style, width, color)

Note: these temporal shapes will not show on export or print. For that purpose create/style a Show-Layer.

### Store/Restore Configurations:

Store or restore configurations (layers + fields + styles, separate for PoL and LoL) within the current project.

1. List of the currently stored configurations
2. store current configuration
3. restore selected configuration from list (availability of layers and fields will be checked on restore)
4. delete selected configuration from project

## Attribute-forms and -tables:

The plugin adds some actions to the attribute-tables and -forms of the configured data- and Show-Layer, from which the affiliated features can be shown on map and/or edited in dialog.

- show measurement-meta-data in dialog, add to feature-selection and highlight on map
- show measurement-meta-data in dialog, add to feature-selection and zoom (LoL) or pan (PoL) on map

See PoL Feature Selection LoL Feature Selection
Note:
These actions are created automatically, the table-layout of data- and Show-Layer are configured to show the action column. They are removed on plugin-unload or if the plugin-configuration assigns other layers.

## Notes:

### "Referenced-Geometry-Problem"

Linear-referenced features have some special characteristics in contrast to "normal" vector-layers, which can lead to unexpected effects.
The most important and the clue of linear referencing: The geometries ar calculated from different sources, a geometry-less Data-Layer and a referenced linestring-layer.
Any change of both sources will propagate to the linear referenced geometries, which can lead to unexpected side-effects:
Imagine a river with some linear-referenced technical buildings.
There is a renaturation-project on that river, the watercourse gets extended, more place for meandering, very useful and welcome.
The river-shape was re-digitized thoroughly in QGis, but afterwards some of the linear referenced buildings had been inexplicably relocated in QGis...
Workaround for that problem:

- restore the previous positions by manual adjusting of the stationing
- let this be done by some magic database-trigger (provided Data-Layer and Reference-Layer stored in the same database)
- Use LinestringM with calibrated measurements (not supported by this plugin, see PostGis Linear_Referencing)
- avoid river-renaturation ;-)

### "Join-Problem"

Another problem using two data-sources is the join between two layers:
Linear-referenced-features suddenly appear in a completely different place, if the reference-id changes, or they vanish, if the referenced linestring-features are deleted/filtered or if the Reference-Layer is inaccessible, or even removed from project by mistake.

### Digitize-Direction:

The direction of digitization must be considered in two places:

1. Reference-Layer:
   The stationing always refers to the starting point of the referenced line, therfore all lines in the Reference-Layer must be digitized in the same direction.
   Note: in the above examples, a river-network, the usual direction is against flow direction, from mouth to source
2. LoL-Stationing:
   The internal used SpatiaLite-function "ST_Line_Substring" requires two numerical values:

       ST_Line_Substring( line Curve , start_fraction Double precision , end_fraction Double precision )

       Return a Linestring being a substring of the input one starting and ending at the given fractions of total 2d length.
       Second and third arguments are expected to be in the range between 0.0 and 1.0.
       NULL is returned for invalid arguments

   The above function requires "Start_fraction" less than "end_fraction", else NULL is returned for invalid arguments. Nevertheless, the plugin allows the storage of "reverse"-stationed measurements, because of a complex expression in the virtual-Show-Layer-query. But this can lead to problems, if these values are used in less complex virtual-layer-query or externally, f.e. inside a PostGIS-View.

### "fraction vs. stationing":

The internal used SpatiaLite-functions "ST_Line_Interpolate_Point" and "ST_Line_Substring" require values in range 0..1:

    ST_Line_Interpolate_Point( line Curve , fraction Double precision )

    return a point interpolated along a line.
    Second argument (between 0.0 and 1.0) representing fraction of total length of linestring the point has to be located.
    NULL is returned for invalid arguments

    ST_Line_Substring( line Curve , start_fraction Double precision , end_fraction Double precision )

    Return a Linestring being a substring of the input one starting and ending at the given fractions of total 2d length.
    Second and third arguments are expected to be in the range between 0.0 and 1.0.
    NULL is returned for invalid arguments

Nevertheless the plugin does not store fractions, but real measured distances, because these ar better understandable for humans. Additionally, all referenced features on a reference-line would relocate, if the line-length should change. (Note: The virtual-layer-query created by this plugin internally calculates the required fractions using measurement/length_of_referenced_line)

### Projections and measurements:

- The projection for the displayed values of the cursor- and snap-coordinates is the current selected project-CRS.
- The measurements are calculated, displayed and stored in the projection of Reference-Layer.
- Geographic CRS (lat/lon, f.e. WGS 84/EPSG 4326) are possible.
- Show- and Reference-Layer have the same projection.

### Snapping

QGis built-in snapping-mechanism is an indispensable help for stationing-measurement. Therefore, the following snap-settings are automatically applied to the configured Reference-Layer:

- "Advanced configuration"
- "snap to segment and line-endpoints"
- "10px tolerance"

Note: These snap-settings are maintained/restored/reapplied on configuration-change or plugin-unload.

### Multi-Linestring-Support

Only single-type-features are supported by this plugin, because the measurement-to-geometry-calculation is indefinite on multi-linestring-geometries.
Actually, the plugin accepts linestring-layers in shape-format, which allways is multi-type (does not distinguish between single- and multi-part-shapes), but only supports their single-part shapes.

### LinestringM-Support

Conventional linestring-layer store their vertices with x- and y-coordinates. LinestringM-layer store an additional m-value, which contains the measured distance to the start-point of the linestring. LinestringZ-layer store an additional z-value, which is the geodesic height of this vertex. LinestringMZ-layer store both additional vertex-coordinates.
The plugin accepts these types, but the m-values are ignored for the geometry-by-measurement-calculation, because the internally used SpatiaLite-Functions (ST_Line_Substring, ST_Line_Interpolate_Point) do not support m-values. See SpatiaLite "SQL functions supporting Linear Referencing".
Note:
PostGis offers possibilities to calculate points/segments on linestring-m-geometries with calibrated m-values (compressed/stretched/not starting at 0)
See PostGis Linear_Referencing.

### Development and support

- The Plugin was developed on QGis Versions 3.32 'Lima' and 3.28 'Firence' (LTR), perhaps runnable on older versions, but not tested so far.
- Source-Code and issue-tracker can be found under https://github.com/Ludwig-K/QGisLinearReference/, please file any found bugs or suggestions for improvement there.
- Translation support (Qt-Linguist) would be nice, the source language is English, a full translation into German is implemented, a translation attempt into French was aborted (pardon...).
- You can contact me by mail at: ludwig@kni-online.de

TOC...