Source code for footprint2graph.pipeline.Topology

# -*- coding: utf-8 -*-

'''
      TOPOLOGIE DU SQUELETTE
'''


import fiona
from shapely.geometry import shape
import os
import progressbar
import time
import matplotlib.pyplot as plt
import sys

import tracklib as tkl

from footprint2graph import skeleton_smoothing, conflateTurnOnTerminalEdge, snap_lines_to_connect
from footprint2graph import log_event


[docs] def addTopologyToNetwork(RESPATH, SEARCH, h=10, NB_OBS_MIN = 10, RESAMPLE_SIZE_FUSION = 5, pipeline_idx = None): t0 = time.time() print("Starting topology creation for the network") idx = int (pipeline_idx) prefix = str(idx) # Pour la construction du réseau tolerance = 0.1 # 0.05 squelettepath = str(RESPATH) + 'network/squelette_' + str(idx) + '.shp' # ========================================================================= # CHARGEMENT DU SQUELETTE collection = tkl.TrackCollection() cptTrack = 1 with fiona.open(squelettepath, 'r') as shapefile: for feature in shapefile: # 1 MultiLineString geom = shape(feature['geometry']) if geom.geom_type == "MultiLineString": for line in geom.geoms: track = tkl.TrackReader().parseWkt(line.wkt) if track.length() < tolerance/2: continue track.tid = cptTrack cptTrack += 1 collection.addTrack(track) elif geom.geom_type == "LineString": print (geom.geom_type) track = tkl.TrackReader().parseWkt(geom.wkt) if track.length() < tolerance/2: continue track.tid = cptTrack cptTrack += 1 collection.addTrack(track) else: print (geom.geom_type) NB_EDGES = collection.size() print (' Number of edges in the skeleton:', collection.size()) print (' Finished loaded skeleton.') if collection.size() == 0: sys.exit("Fin du programme le squelette est vide.") # ========================================================================= # Création d'un réseau surtout pour la fusion des arcs # input_file = str(RESPATH) + 'network/tmp_in.csv' output_file = str(RESPATH) + 'network/tmp_out.csv' try: os.remove(input_file) except FileNotFoundError: print (' ' + input_file + " not exists") try: os.remove(output_file) except FileNotFoundError: print (' ' + output_file + " not exists") with open(input_file, "w") as f: for track in collection: f.write(track.toWKT() + ";" + str(track.tid) + "\n") tkl.Topology.create_topology(input_file, '2154', output_file) fmt = tkl.NetworkFormat({ "pos_edge_id": 0, "pos_source": 1, "pos_target": 2, "pos_wkt": 3, "srid": "ENU", "separator": ",", "header": 1}) network = tkl.NetworkReader.readFromFile(output_file, fmt, verbose=False) collection = tkl.TrackCollection() cptTrack = 1 for edge in network: track = edge.geom.copy() track.tid = cptTrack cptTrack += 1 collection.addTrack(track) network = None # ========================================================================= # Suppression des doublons # tolerance = 0 for track in collection: track = tkl.simplify(track, tolerance, tkl.MODE_SIMPLIFY_REM_POS_DUP, verbose=False) print ('') print (' Finished removing hooked parts of the skeleton.') # ========================================================================= # LISSAGE: SUPPRIME LES parties crochues du squelette # for track in progressbar.progressbar(collection): track = skeleton_smoothing(track, 3, 6) # ========================================================================= # SIMPLIFICATION # tolerance = 3 for track in collection: track = tkl.simplify(track, tolerance, tkl.MODE_SIMPLIFY_DOUGLAS_PEUCKER, verbose=False) print (' Finished simplification of the skeleton.') # ========================================================================= # SNAPPING # tolerance = 1 NB_START = collection.size() collection = snap_lines_to_connect(collection, tolerance) NB_END = collection.size() print (' Number of edges in the skeleton (after snapping):', collection.size()) print (' Edge count difference after snapping : ', NB_END - NB_START) # ========================================================================= # Création de la topologie # input_file = str(RESPATH) + 'network/edgegeom_' + prefix + '.csv' with open(input_file, "w") as f: for track in collection: f.write(track.toWKT() + ";" + str(track.tid) + "\n") output_file = str(RESPATH) + 'network/squelette_topology_simplifie_' + prefix + '.csv' tkl.Topology.create_topology(input_file, '2154', output_file, tbp=0.001) fmt = tkl.NetworkFormat({ "pos_edge_id": 0, "pos_source": 1, "pos_target": 2, "pos_wkt": 3, "srid": "ENU", "separator": ",", "header": 1}) network = tkl.NetworkReader.readFromFile(output_file, fmt, verbose=False) print (' Number of edges in the simplified skeleton:', len(network.getIndexEdges())) print (' Number of nodes:', len(network.getIndexNodes())) # ========================================================================= # Suppression des petits arcs ISOLES # long_min = NB_OBS_MIN * RESAMPLE_SIZE_FUSION print (' Shortest edges limit : ', long_min) CPT_LEN_TOO_SHORT = 0 for edge in network: test1 = edge.geom.length() < long_min test2 = len(network.getIncidentEdges(edge.source.id)) <= 1 test3 = len(network.getIncidentEdges(edge.target.id)) <= 1 if test1 and test2 and test3: network.removeEdge(edge) # pas besoin de supprimer des noeuds puisque isolés CPT_LEN_TOO_SHORT += 1 print (' Number of edges in the skeleton (after removing the shortest edges):', CPT_LEN_TOO_SHORT) TE = list(map(int, network.getIndexEdges())) tkl.NetworkReader.counter = max(TE) + 1 # ========================================================================= # "Déformation des virages s'ils suivent un pattern # sous forme d'un T à l'envers , dont la longeur du tronc pas trop longue # et dont le noeud terminal est 'isolé' # et les deux autres arcs de la base plus longues que le tronc cpt = 0 HC = [] while True and cpt <= len(network.NODES): cpt += 1 # 1. trouver les noeuds de degré 3 nodes_deg3 = [nid for nid in network.getIndexNodes() if network.degree(nid) == 3] nodes_deg3 = [x for x in nodes_deg3 if x not in HC] # print (len(nodes_deg3), "/", len(network.getIndexNodes())) if not nodes_deg3: break # 2. traiter un noeud nid = nodes_deg3[0] # print ('Noeud en cours :', nid) r = conflateTurnOnTerminalEdge(network, nid, SEARCH, h) if r is None: HC.append(nid) # network.simplify(0, tkl.MODE_SIMPLIFY_REM_POS_DUP) print (' Edge count after conflation:', len(network.getIndexEdges())) # ========================================================================= # Sauvegarde dans un fichier # netwokpath = RESPATH + 'network/reseau_' + prefix + '.csv' tkl.NetworkWriter.writeToCsv(network, netwokpath) # ========================================================================= # Journalisation des résultats try: log_event(RESPATH + "topology"+ str(idx) + ".json", { "Number of edges in the skeleton": NB_EDGES, "Number of skeleton edges removed for being too short": CPT_LEN_TOO_SHORT, "Edge count difference after snapping": NB_END - NB_START, "ts": time.time() }) except Exception as e: print (e) print ('Error while logging skeleton topology') print ("Stage 3 completed: adding topology to the skeleton.")