Method with PostgreSql and Pgrouting
Install PostgreSql here for windows : https://www.postgresql.org/download/windows/
you can then connect whatever table as datasource in Qgis to check the data
Explanation of the method :
In order to get real travel distance beetween your points,
we need to set up a graph that materialize what you accept as deplacement
so here :
we add to the graph the nearest line from the point house facade to complete the graph
and we do the same for your waste point collect (but they seems to be on the street already)
the Sql code will look like this :
create extension if not exists postgis
;
create extension if not exists pgrouting
;
create schema ___
;
-- create the table street , (you can also import your data from Qgis with drag&drop)
create table ___.street (
geom geometry(Linestring, $SRID),
id serial primary key,
name varchar,
circulation varchar,
source integer,
target integer
)
;;
create table ___.complete_network (
geom geometry(Linestring, $SRID),
id serial primary key,
name varchar,
circulation varchar,
source integer,
target integer
)
;;
create table ___.house_points (
geom geometry(Point, $SRID),
id serial primary key,
name varchar,
comment varchar,
adresse float
)
;;
create table ___.waste_points(
geom geometry(Point, $SRID),
id serial primary key,
name varchar,
comment varchar
)
;;
-- we add line house-street to the graph
insert into ___.complete_network(geom)
select St_Makeline(St_closestPoint((select St_collect(geom) as geom from ___.street),hp.geom), hp.geom) as geom
from ___.house_points as hp
;;
-- we add line waste-street to the graph
insert into ___.complete_network(geom)
select St_Makeline(St_closestPoint((select St_collect(geom) as geom from ___.street),hp.geom), hp.geom) as geom
from ___.waste_points as hp
;;
-- we add street
insert into ___.complete_network(geom, id , name, source, target)
select geom, id , name, source , target from ___.street
;;
-- we use pg_routing function to generate a correted topology noded for graph
perform pgr_nodenetwork('___.complete_network', 0.001, 'id', 'geom', 'noded')
;;
-- we create topology for graph
perform pgr_createTopology('___.complete_network_noded', 0.001, 'geom', 'id', 'source', 'target')
;;
-- we use a reference to the node in the graph to our raw data information (bonus but useful)
alter table ___.waste_points
add vtx integer
;
alter table ___.waste_points
add constraint vtx_foreign_key_pei
foreign key (vtx)
references ___.complete_network_noded_vertices_pgr(id)
;
alter table ___.house_points
add vtx integer
;
alter table ___.house_points
add constraint vtx_foreign_key_pei
foreign key (vtx)
references ___.complete_network_noded_vertices_pgr(id)
;
-- exemple of shortest path query for node 7 to 12 (change the number to compute path for another set of nodes)
-- here you will get the distance in the return cost of this function and if you use a waste node and house node, you get what you were looking for
SELECT seq, id1 AS node, id2 AS edge, cost
FROM pgr_dijkstra(
'SELECT id, source, target, st_length(geom) FROM ___.complete_network_noded',
7, 12, false, false
);
With this data structure you can also create SQL function that will return the nearest waste point for each house point.
to go further , multiple access to houses ? how many houses use a waste points ?
I tried to produce the easiest "working" sample, but I didn't really check if everything really works , it may have some misprint in the code.
feel free to correct it
docs :
- https://postgis.net/docs
- https://docs.pgrouting.org/2.0/en/src/dijkstra/doc/index.html
You will need the computed distance to classify the output. One option is to create a virtual layer that will compute the distance, record it, buffer the point and that you can style as you wish using the rule based symbology
.
Go to the menu Layer > Add Layer > Add/Edit Virtual Layer...
and enter the following query. Replace myPointLayer
with the real layer name, and you can add other fields from pt1
.
SELECT pt1.id, pt2.id as nerest_pt_id,
MIN(ST_Distance(pt1.geometry, pt2.geometry)) AS distance,
st_buffer(pt1.geometry, MIN(ST_Distance(pt1.geometry, pt2.geometry))) as geometry
FROM myPointLayer AS pt1, myPointLayer AS pt2
WHERE pt1.id != pt2.id
GROUP BY pt1.id
ORDER BY distance DESC
Best Answer
Note that both solutions will only work correctly when you use the same projected CRS on both line layers.
Solution A: Distance to the closest points on the second line:
What it does:
generate_series()
line_interpolate_point()
array_foreach()
and get thedistance()
to the second line by usingaggregate()
or some different function to get another line.distance()
Returns the minimum distance (based on spatial reference) between two geometries in projected units.
array_mean()
.Discussion:
The expression is much easier to implement and to understand, but it has one great disadvantage: It always measures the length to the closest point on the other line. As you can see in the screenshot below, this may not accurate for some usecases. However, it should work without issuses on very curvy lines, changing their main angle often, as well.
Visualized:
Expression for visualization:
Solution B: Distance to line in a specified angle:
What it does:
generate_series()
line_interpolate_point()
array_foreach()
and9999
m (change this value to your needs) in+90°
, we get viamain_angle()
. You may need to change+90
to-90
or something different, depending on your geometries and your personal needs.intersection()
.array_remove_all()
to remove allNULL
values.make_line()
from the points fromgenerate_series()
to the points fromintersection()
length()
of these linesarray_mean()
.Discussion:
The expression is a little more difficult to understand and implement, but it has one great advantage over solution A: It always measures the length to the other line in the same angle. However, this may be tricky to implement, if you have curvy lines changing their main angle a lot. In this case, I can suggest to split the line into different features and instead of using
aggregate()
to get the second layers line, you may useget_feature()
together withgeometry()
, to get only one specific, related line.Visualized:
Expression for visualization: