You can achieve this using a virtual layer.
It would compute what 5km means in terms of fraction of the line length. Then, it will identify at which fraction of the line length is the point located. It will look at the difference between 1.0 (full length) and the expected line fraction for the extrapolated point after the point. If less than 1, the ending fraction (point) is kept. If more than 1, the endpoint is kept and the difference is added to the start point, which is now located at current point fraction - fraction of 5km - difference between 1 and end point fraction
. To avoid going before the start (0.0), another comparison is done.
At last, once the starting and ending fractions have been identified, a line substring is created. The resulting line will always be 10km long, centered on the mid point as much as possible (except if there are less than 5km from the start, though this can be changed easily)
go to the menu Layer > Add Layer > Add/Edit Virtual Layer...
and enter the following query. Replace pointloc
and river
by your true layer name, and feel free to keep any field from either layer (like p.id
and l.id
).
The 2 first computed fields (fromPC and toPC) and here for information only, you can safely remove them.
select p.id, l.id,
ST_Line_Locate_Point(l.geometry,p.geometry) - 5000.0/ st_length(l.geometry) + min(0,1.0-(ST_Line_Locate_Point(l.geometry,p.geometry) + 5000.0/ st_length(l.geometry))) fromPC,
min(1.0,ST_Line_Locate_Point(l.geometry,p.geometry) + 5000.0/ st_length(l.geometry)) toPC,
st_line_substring(l.geometry,ST_Line_Locate_Point(l.geometry,p.geometry) - 5000.0/ st_length(l.geometry) + min(0,1.0-(ST_Line_Locate_Point(l.geometry,p.geometry) + 5000.0/ st_length(l.geometry))),min(1.0,ST_Line_Locate_Point(l.geometry,p.geometry) + 5000.0/ st_length(l.geometry))) as geometry
from pointloc p
join river l
on st_intersects(l.geometry,p.geometry)