Intersection de lignes pour obtenir des croisements à l'aide de Python avec QGIS?

10

J'ai un ensemble de lignes représentant des lignes de bus. Certaines lignes se chevauchent et empruntent les mêmes routes.

entrez la description de l'image ici

Je peux extraire les nœuds. entrez la description de l'image ici

Cependant, je suis intéressé à extraire uniquement les croisements comme celui-ci: entrez la description de l'image ici

Comment puis-je faire ceci? Je cherche des moyens avec QGIS ou Python.

J'ai essayé la méthode d'intersection de GDAL Python mais cela ne me renvoie essentiellement que les sommets.

La méthode Line Intersections de QGIS me renvoie les croisements si deux lignes se croisent. Cependant, dans le cas où deux lignes de bus parcourent une grande partie de leur itinéraire sur la même route, cela ne me donne pas le point de fusionner.

ustroetz
la source
Avez-vous essayé l'outil d'intersection de lignes dans QGIS: Outil d'analyse vectorielle> Intersections de lignes ... Il ne vous donnera pas les nœuds de fin et de début d'une ligne, mais toutes les intersections.
Jakob
Oui, j'ai écrit à ce sujet dans la question.
ustroetz
Je ne suis pas clair sur ce que vous demandez, en partie parce que toutes les lignes sont symbolisées de la même manière dans vos images - je ne peux pas distinguer les différents itinéraires pour comprendre quels nœuds vous regardez ou pourquoi il y en a tellement dans le deuxième image. Les itinéraires coïncident-ils sur les routes? S'agit-il tous de segments de ligne à deux points ou de polylignes continues? Je note que le comportement que vous décrivez est le même que l' outil Intersection d'ArcGIS - les lignes / lignes avec sortie de lignes vous donnent un chevauchement, mais les lignes / lignes avec sortie de point ne donnent que des croisements.
Chris W
Sur cette base, pour obtenir ce que je pense que vous voulez, vous devrez peut-être utiliser les deux méthodes. Obtenez les croisements (ligne / ligne = point), puis obtenez les chevauchements (ligne / ligne = ligne) et extrayez les nœuds de début / fin pour ces lignes de chevauchement. Ce devraient être tous les points / nœuds que vous recherchez.
Chris W

Réponses:

20

Les nœuds:

Vous voulez deux choses, les points d'extrémité des polylignes (sans nœuds intermédiaires) et les points d'intersection. Il y a un problème supplémentaire, certains points d'extrémité de polylignes sont également des points d'intersection:

entrez la description de l'image ici

Une solution consiste à utiliser Python et les modules Shapely et Fiona

1) Lisez le fichier de formes:

from shapely.geometry import Point, shape
import fiona
lines = [shape(line['geometry']) for line in fiona.open("your_shapefile.shp")]

2) Trouvez les points d'extrémité des lignes ( comment obtenir les points d'extrémité d'une polyligne? ):

endpts = [(Point(list(line.coords)[0]), Point(list(line.coords)[-1])) for line  in lines]
# flatten the resulting list to a simple list of points
endpts= [pt for sublist in endpts  for pt in sublist] 

entrez la description de l'image ici

3) Calculez les intersections (itération à travers des paires de géométries dans la couche avec le module itertools ). Le résultat de certaines intersections est MultiPoints et nous voulons une liste de points:

import itertools
inters = []
for line1,line2 in  itertools.combinations(lines, 2):
  if  line1.intersects(line2):
    inter = line1.intersection(line2)
    if "Point" == inter.type:
        inters.append(inter)
    elif "MultiPoint" == inter.type:
        inters.extend([pt for pt in inter])
    elif "MultiLineString" == inter.type:
        multiLine = [line for line in inter]
        first_coords = multiLine[0].coords[0]
        last_coords = multiLine[len(multiLine)-1].coords[1]
        inters.append(Point(first_coords[0], first_coords[1]))
        inters.append(Point(last_coords[0], last_coords[1]))
    elif "GeometryCollection" == inter.type:
        for geom in inter:
            if "Point" == geom.type:
                inters.append(geom)
            elif "MultiPoint" == geom.type:
                inters.extend([pt for pt in geom])
            elif "MultiLineString" == geom.type:
                multiLine = [line for line in geom]
                first_coords = multiLine[0].coords[0]
                last_coords = multiLine[len(multiLine)-1].coords[1]
                inters.append(Point(first_coords[0], first_coords[1]))
                inters.append(Point(last_coords[0], last_coords[1]))

entrez la description de l'image ici

4) Éliminez les doublons entre les points d'extrémité et les points d'intersection (comme vous pouvez le voir sur les figures)

result = endpts.extend([pt for pt in inters  if pt not in endpts])

5) Enregistrez le fichier de formes résultant

from shapely.geometry import mapping
# schema of the shapefile
schema = {'geometry': 'Point','properties': {'test': 'int'}}
# creation of the shapefile
with fiona.open('result.shp','w','ESRI Shapefile', schema) as output:
    for i, pt in enumerate(result):
        output.write({'geometry':mapping(pt), 'properties':{'test':i}})

Résultat final:

entrez la description de l'image ici

Les segments de ligne

Si vous souhaitez également les segments entre les nœuds, vous devez "planariser" ( graphique planaire , aucune arête ne se croise) votre fichier de formes. Cela peut être fait par la unary_union fonction de Shapely

from shapely.ops import unary_union
graph = unary_union(lines)

entrez la description de l'image ici

gène
la source
Merci @gene pour la réponse détaillée. J'ai édité la partie où elle passe sur les différents types de géométrie. Dans mon cas, l'intersection renvoie également des lignes, des géométries, etc. Mais cela dépend des données d'entrée. Je n'ai pas été assez clair dans ma question.
ustroetz
Très bonne réponse. Puis-je ajouter qu'il n'est pas nécessaire de faire ce qui suit: result = endpts.extend([pt for pt in inters if pt not in endpts])car il semble que la .extendméthode se modifie endpt. Dans mon cas result = Noneaprès cette opération. C'est endptsce qui finit par contenir le résultat sett
user32882