4

I have a layer with polygons that describe road damages. I have then another layer with road network lines. The layers are shown in the picture.

enter image description here

I need to project the polygons as lines to the road network. How can I iterate over each polygon, find its two extreme points in relation to the nearest road line and project the line connecting the two extreme vertices onto the road line? Are there any tools for achieving the result in QGIS or is necessary to make an own Python script?

The final output is supposed to be something like the picture below. The colored lines represent the polygons and cover the road network.

enter image description here

Following the steps from the answer, I end up with the points being in a way randomly placed on different roads as shown on picture below (the projected_vertices layer is marked with yellow)

enter image description here

5
  • 2
    What do you mean by "find its two extreme points"?
    – Erik
    Commented Jan 13, 2021 at 9:20
  • I mean to represent a polygon as a line that can be projected onto a road network line (center line of a road), so that it is visible what section of the road is affected by the damage. It is not important to know the extent of the damage on the surface, but only to know the road section.
    – krltos
    Commented Jan 13, 2021 at 9:52
  • 1
    I suppose the "start" and "end" points of the polygon were it represented as a centre line.
    – MarcM
    Commented Jan 13, 2021 at 9:53
  • By looking at data, how inhomogeneous your features in the data, I am afraid that there won't be one solution that fits all. I did not entirely understand how the final output should look like. An image may helpful if you could add the question as expected output?
    – Nil
    Commented Jan 13, 2021 at 10:06
  • 2
    Added a picture visualizing the desired final output. Each of the lines corresponds to a polygon from the original data layer. The new lines are projected onto the road network lines.
    – krltos
    Commented Jan 13, 2021 at 10:26

1 Answer 1

4

First an algorithmic description how this solution works. Afterwards the implementation in QGIS, using expressions to create new geometries.

Description

You can create for each vertex of your polygons the closest point on the line representing the street: make a perpendicular line on the streetline going through each vertex and where this connecting line crosses the streetline, create a point. Like this, you project the polygon's vertices on the street line. You than just have to connect all projected points based a common attribute that groups together points/vertices belonging to the same polygon.

Implementation in QGIS

  1. Preparation of the data: On the polygon layer, create new attribute nearest_line (if using Shapefiles: nearest - Shapefiles have a limit of 10 characters in fieldnames) using this expression: array_to_string ( overlay_nearest( 'line',$id)). This assigns the streetline the polygon should be projected to (if you have more than one streetline). Also make sure you have a unique field 'id' in the attributes of the polygons. Using a field 'fid' creates some issues if you want to save the vertices in the next step as Geopackage (you have to delete the fid field before as it will be no longer unique: every vertex will have the fid of the polygon it belongs to). So just create a new field 'id' and copy the fid value there.

  2. Extract vertices of you polygons (menu Vector / Geometry tools), name the created point layer vertices.

  3. Project these vertices to the line using the following expression with Menu / Processing / Toolbox / Geometry by expression to get an output layer projected_vertices:


intersection( 
    extend (
        make_line (
            $geometry, 
            closest_point ( 
                geometry (
                    get_feature_by_id (
                        'line',
                         "nearest_line" 
                    )
                ), 
                $geometry
            )
        ),
        1,
        1
    ),
    geometry (
        get_feature_by_id(
            'line',
             "nearest_line" 
        )
    )
)

As you might notice, one of the vertices in every polygon is a duplicate. That's because a polygon to be valid, it must be closed. That means that start- and endpoint must be identical (same coordinates).

enter image description here

  1. Now you can connect the projected vertices with a line using the points to path tool. Use the id field to sort and group (see screenshot) to get a separate feature (line) for each polygon. In the screenshot, the projected line can be seen in red:

enter image description here

UPDATE

Using your data, I re-created the solution. As you can see, in some places a manual decision has to be taken as to where a polygon should belong to. See polygon 4455 in the next screenshot: it is projected to the road running east-west because the polygon intersects this road and thus is assigned to this line.

Depending on what you use the data for, you would possibly prefer this polygon to be projected to the road in the east, parallel to it. I checked the output and there are very few such cases. You could manually change the field nearest_line you created automatically in step 1 for this polygon and assign the roadline you want it be projected to.

For large datasets, of course you could refine the automatization process and add additional criteria as for which line the polygon should be projected to. As your polygons often have a very thin, long shape, an idea would be using main_angle ($geometry) and then to compare this with the azimuth of the nearest streets to assign the polygon to that steet where the street's azimuth and the polygons main_angle correspond best - thus where the polygons are more or less "parallel" to the street. For polygon 4455 on the screenshot, this for sure would work well.

enter image description here

14
  • Thank you for outlining the solution. I got stuck in point 2. When I create a projected vertices layer, they are all on one street which should not be the case. The layer has the same amount of features as the vertices layer. Also, all layers are in the same CRS. Do I need to change anything else in the expression you provided except for the 'line' parameter?
    – krltos
    Commented Jan 13, 2021 at 12:47
  • The expression contains get_feature_by_id ('line',1). It refers to the other layer (line) and takes feature no. 1. If you add a line, it will not be refered as it has another feature no.: 2, 3 or whatever. What you could do (for simple cases): create a multiline layer, thus merge all your line features to one multipart feature that you can refer to with the expression as above, see: i.sstatic.net/MZWVu.png However, as you can see, if polygons are too close to a crossroads, it can happen that they will have their vertices on different lines, as is the case with polygon 1 and 2.
    – Babel
    Commented Jan 13, 2021 at 13:48
  • So what you should do is to assign first every polygon to the line section you want to project it to and than process as described.
    – Babel
    Commented Jan 13, 2021 at 13:48
  • Changed my solution so that it works also with multiple lines. Hope that works?
    – Babel
    Commented Jan 13, 2021 at 14:54
  • I'm afraid it still doesn't work. In step 1 I assign the id of a road to each polygon in the nearest_line attribute. I have 42 roads and the nearest_line gets values in the range of 1 to 42. Could actually another attribute be used? Each road has an UniqueID. Anyway, in the step 3, the projected vertices appear in kinda random places on the roads. I added a picture to my question to visualize the results.
    – krltos
    Commented Jan 14, 2021 at 7:29

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.