2

I have a point layer and I create line between its points (like a graph) through geometry by expression

collect_geometries( 
   array_foreach(
     aggregate('point_layer','array_agg',$geometry),
       make_line($geometry,@element)
   )
 )

But every time geometry of new line layer is not correct and I need to fix it in QGIS. I think it is because my expression allows to create line between the same points and between one point. If I have a lot of point layer fixing requires a lot of time and it is a huge problem. Could somebody help me to improve my expression? I want to add it in my QGIS expression to automate line drawing.

MrXsquared
  • 34,292
  • 21
  • 67
  • 117
redhat
  • 347
  • 6
  • Maybe using overlay_nearest function? And duplicate the point layer so you can refer to this layer and take the 2nd nearest point (to avoid taking the same point)? – Babel Feb 03 '24 at 12:20
  • I need to create line connection with all points except the same point. And also except dublicate lines. Probably overlay_nearest connects point with only the nearest point? – redhat Feb 03 '24 at 12:33
  • Are you talking about pyqgis or qgis expressions? – MrXsquared Feb 03 '24 at 14:35
  • About qgis expression. In future I'm planning write it on pyqgis but I think that I cannot use geometry expression in pyqgis – redhat Feb 03 '24 at 15:06
  • 1
    here is another solution using a virtual layer – JGH Feb 04 '24 at 12:43

1 Answers1

5

You dont need to use geometry by expression if you are going to use PyQGIS anyway.

With itertools.combinations you can generate all pairwise point combinations, then build linestrings between them:

from itertools import combinations
point_layer = QgsProject.instance().mapLayersByName("Vertices")[0]

#Create a line layer vl = QgsVectorLayer(f"LineString?crs={point_layer.crs().authid()}", "linelayer", "memory") provider = vl.dataProvider()

#For each unique combination of two point features for combo in combinations(point_layer.getFeatures(), 2): new_feature = QgsFeature() #Create a new feature #Create its line geometry new_geometry = QgsGeometry.fromPolyline(QgsLineString([f.geometry().asPoint() for f in combo])) new_feature.setGeometry(new_geometry) provider.addFeature(new_feature) #Add the feature to the line layer

QgsProject.instance().addMapLayer(vl)

enter image description here

Another option is to create the lines using SQL. This query joins the point layer to itself on distance shorter than 30000 (adjust) and where the id is not the same, and creates a line between each join pair. You need a unique id column, mine is named id

select row_number() over() as id, a.id as a_id, b.id as b_id, makeline(a.geometry, b.geometry) as geometry
from thepoints as a
join thepoints as b
on st_distance(a.geometry, b.geometry)<30000
where a.id < b.id

Which you can execute using Execute SQL:

layer = QgsProject.instance().mapLayersByName("thepoints")[0]
sql_query = """select row_number() over() as id, 
                        a.id as a_id, 
                        b.id as b_id, 
                        makeline(a.geometry, b.geometry) as geometry
                from thepoints as a
                join thepoints as b
                on st_distance(a.geometry, b.geometry)<30000
                where a.id < b.id"""

sqllayer = processing.run("qgis:executesql", {'INPUT_DATASOURCES':[layer],'INPUT_QUERY':sql_query,'INPUT_UID_FIELD':'', 'INPUT_GEOMETRY_FIELD':'','INPUT_GEOMETRY_TYPE':None,'INPUT_GEOMETRY_CRS':None, 'OUTPUT':'TEMPORARY_OUTPUT'})["OUTPUT"] QgsProject.instance().addMapLayer(sqllayer)

enter image description here

BERA
  • 72,339
  • 13
  • 72
  • 161
  • 1
    Amazing! Thank you! – redhat Feb 05 '24 at 09:02
  • Could you, please, help me with point projection? I cannot project them correctly and I also want to project them through PyQGIS https://gis.stackexchange.com/questions/475384/shortest-path-point-to-point-error?noredirect=1#comment776423_475384 I think it's really because I project line but have no node – redhat Feb 05 '24 at 09:09