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
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.
Extract vertices
of you polygons (menu Vector / Geometry tools
), name the created point layer vertices
.
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).
- 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:
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.