1

I have a layer with several line features and a polygon layer which has land ownership information (so thousands of parcels).

I want to append several columns to the line layer attribute table ("Owner_1", "Owner_2", "Owner_3", etc.) and populate those columns with the owner name (from a column in the polygon attribute table), the length of the line that passes through that polygon, and the percent of the line which passes through the polygon. So for example:

Owner_1: "Joe Smith, length = 20m, percent = 20%"

Owner_2: - "Jane Smith, length = 30m, percent = 25% etc.

In the case that a line only passes through one parcel, only "Owner_1" would have data filled into it.

Is this possible? Is there a better way to retrieve and store this information? I have probably 30 line features and the polygon layer has over 80,000 parcels so there is a lot of processing if it goes through each parcel to see if it overlaps with a line feature.

I tried this:

length(intersection($geometry, aggregate('line_layer', 'collect', $geometry)))

to append the intersecting length of the line to the polygon layer in a column I labelled with the line ID, then I would sort by IS NOT NULL and then extract the selected features. I would really prefer to do this all in one step for each line on a layer and append it to the line attribute table

2
  • length(intersection($geometry, aggregate('line_layer', 'collect', $geometry))) I tried this to append the intersecting length of the line to the polygon layer in a column I labeled with the line I.D., then i would sort by IS NOT NULL and then extract the selected features. I would really prefer to do this all in one step for each line on a layer and append it to the line attribute table Jun 8, 2023 at 21:43
  • How many owners are there?
    – BERA
    Jun 9, 2023 at 6:50

1 Answer 1

3

If there could be an arbitrary number of parcels a line can cross, use JSON or a map type field to store your results.

For the JSON formatted string use this expression:

'{' || array_to_string(
    array_foreach(
        overlay_crosses(
            'Polygon layer name/id', -- set inside quotes the polygon layer name/id
            $currentfeature
        ),
        with_variable(
            'ints_len',
            length(intersection(geometry(@element), $geometry)),
            format(
                '"%1":{"length":%2,"percent":%3}',
                attribute(@element, 'owner field name'), -- set inside quotes the field name with the information of the owner (polygon layer field)
                @ints_len,
                100 / length($geometry) * @ints_len
            )
        )
    )
)
|| '}'

there are still some missing functions to manage dictionaries, so the JSON is produced just by formatting strings.
The structure of the JSON will look like this:

{
  "Joe Smith": {
    "length": 20,
    "percent": 20
  },
  "Jane Smith": {
    "length": 30,
    "percent": 25
  }
}

If you want to use the map field just enclose the above expression in the from_json(<expression here>) function.

Notes: The lines and the polygons must be in the same projection, and the units of the length depends on the map projection.
Try to use a projected CRS. To use the generated JSON string use the from_json() function, (e.g the following function retrieves the owner that have the longest distance of a line in its parcel)

with_variable(
    'owners', -- set inside quotes the field name where you stored the json string
    from_json("Owners"), -- here we load the json
    with_variable( -- store the value o the longest portion of line in a variable called max_len
        'max_length',
        array_max(array_foreach(
            map_avals(@owners),
            @element['length']
        )),
        with_variable( -- get the name of the owner of this longest portion of the line
            'm_owner',
            array_filter(
                map_akeys(@owners),
                @owners[@element]['length'] = @max_length,
                limit:=1
            )[0],
            format('%1: %2', @m_owner, @owners[@m_owner]['length']) -- format the result
        )
    )
)
1
  • There is also a function for creating a JSON-like output: to_json()
    – Taras
    Jun 9, 2023 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.