Bonjour, Afin de voir où l'on en est sur la qualité des fichiers bâti issus du cadastre, j'en ai récupéré quelques uns sur cleo, et j'ai tenté d'identifier les pb récurrents que le contributeur doit gérer quand il se lance dans l'aventure "import du bati":
1. Des noeuds en doubles ou très proches 2. Des chemins avec un même noeud répété 3. Des bâtiments se croisant eux-mêmes 4. Des bâtiments se chevauchant très faiblement 5. Des bâtiments adjacents, mais qui ne partagent pas leurs noeuds. Topologiquement ils ne sont pas mitoyens, de quelques centimètres. 6. Des bâtiments en double 7. Des bâtiments inclus dans d’autres, ou se superposant franchement 8. Des bâtiments découpés par les limites de parcelle 9. Des bâtiments avec un nombre exubérant de nœuds 10. Validator c’est long et ça rate des anos en plus ! 11. Des bâtiments qui existent déjà dans OSM 12. Des bâtiments sur les highway existantes Vous en avez d’autres ? J'ai écrit 2 scripts python. Ce n’est pas très pythonique, pas très performant, mais cela règle plus d’anos que ça n’en crée (je crois pas que cela en crée :-) ). Ils utilisent OsmSax [1], Rtree, et Shapely : Node_simplifier.py : A partir d’un fichier .osm, crée un autre .osm en éliminant les nœuds en double, ou proches, et nettoie les chemins des nœuds se répétant. Node_join.py : A partir d’un fichier .osm, crée un autre .osm en « J »isant tous les nœuds. Il s’agit de la fonction J de JOSM qui intègre un nœud à un chemin si celui-ci en est suffisamment proche. A noter que cela ne déplace aucun point, et que l’on conserve tous les points. Pour l’instant les paramètres de distance sont en dur (et en angulaire), et tous les objets modifiés se voient ajouter un tag fixme pour visualiser les modifs. Ces deux scripts, passés dans cet ordre, traitent les points 1,2,4,5. Un troisième script est en cours pour le point 9. Je vous laisse juge de leur qualité et de leur intérêt. A vos remarques ! A final je crois qu'il faudra supprimer les dépôts type cléo, et mettre à dispo une interface d’import différentiel tuilé, c'est-à-dire qui n'affiche et ne renvoie qu’une portion des bâtiments à importer et, pour combler les manques de Validator, en ajoutant les tag fixme du type : « bâtiment superposé avec l’existant », « bâtiment superposé au cadastre », « bâtiment sur highway », etc…afin d'aider et d'alerter le contributeur... et peut-être aussi le réfréner ;-) BrunoC [1] https://gitorious.org/osmose/backend/blobs/master/modules/OsmSax.py
#!/usr/bin/python # -*- coding: utf8 -*- from rtree import Rtree import OsmSax, sys DIST_MIN = 1.0e-12 def coords(n): return (n.lat, n.lon) def distance2(a,b): xa, ya = coords(a) xb, yb = coords(b) return (xa-xb)**2 + (ya-yb)**2 class Node(object): def __init__(self, id=None, lon=None, lat=None, tags=None): self.id = id if lon != None: self.lon, self.lat = float(lon), float(lat) if tags: self.tags = tags else: self.tags = {} self.inWay = set() self.inRel = set() class Way(object): def __init__(self, id=None, nodes=None, tags=None): self.id = id if nodes: self.nodes = nodes else: self.nodes = [] if tags: self.tags = tags else: self.tags = {} class Relation(object): def __init__(self, id, members=None, tags=None): self.id = id if members: self.members = members else: self.members = [] if tags: self.tags = tags else: self.tags = {} def __repr__(self): return "Relation(id=%r, members=%r, tags=%r)" % (self.id, self.members, self.tags) class Cache: def __init__(self): self.nods = {} self.ways = {} self.rels = {} def NodeCreate(self, data): self.nods[data["id"]] = Node(id=data["id"],lon=data["lon"],lat=data["lat"],tags=data["tag"]) def WayCreate(self, data): self.ways[data["id"]] = Way(id=data["id"],nodes=data["nd"],tags=data["tag"]) def RelationCreate(self, data): self.rels[data["id"]] = Relation(id=data["id"],tags=data["tag"],members=data["member"]) ########################################################################### fout = sys.argv[2] data = OsmSax.OsmSaxReader(sys.argv[1]) cache = Cache() print 'Parse du fichier...' data.CopyTo(cache) idxNode = Rtree() tabindx = {} print 'Indexation...' i = 0 for k in cache.nods.keys(): i += 1 idxNode.insert(i, coords(cache.nods[k])) tabindx[i] = cache.nods[k] # set des chemins utilisant un noeud for w in cache.ways.values(): for nid in w.nodes: cache.nods[nid].inWay.add(w) # set des relations utilisant un noeud for r in cache.rels.values(): for m in r.members: if m['type'] == 'node': cache.nodes[m['ref']].inRel.add(r) print 'Simplification des noeuds...' # balayage des noeuds à simplifier for noeud in cache.nods.values(): # print 'traitment', noeud.id # le noeud a-t-il déjà été supprimé if not cache.nods.has_key(noeud.id): continue # recherche des noeuds proches for i in idxNode.nearest(coords(noeud),4): np = tabindx[i] if np == noeud: continue if distance2(noeud, np) < DIST_MIN: noeud.tags['fixme']='simplify' #remplacement du np par noeud dans les ways for w in np.inWay: while np.id in w.nodes : ind = w.nodes.index(np.id) w.nodes[ind]=noeud.id #suppression np de l'index idxNode.delete(i,coords(np)) #suppression de la liste des noeuds del cache.nods[np.id] print 'Nettoyage des chemins...' for w in cache.ways.values(): i = 1 # balayage des segments d'un way while (len(w.nodes) > 1) & (i < len(w.nodes)): if w.nodes[i-1] == w.nodes[i]: w.nodes.pop(i) continue i += 1 print 'Ecriture...' out = OsmSax.OsmSaxWriter(fout, "UTF-8") out.startDocument() out.startElement("osm", {'version':'0.6'}) for n in cache.nods.values(): out.NodeCreate({'id':n.id,'lon':n.lon,'lat':n.lat,'tag':n.tags}) for w in cache.ways.values(): out.WayCreate({'id':w.id,'nd':w.nodes,'tag':w.tags}) for r in cache.rels.values(): out.RelationCreate({'id':r.id,'member':r.members,'tag':r.tags}) out.endElement("osm")
#!/usr/bin/python # -*- coding: utf8 -*- from rtree import Rtree import OsmSax, sys from shapely.geometry import Point, LineString DIST_MIN = 2.0e-6 def coords(n): return (n.lat, n.lon) def procheWay(nd, p1, p2): #renvoie vrai si node est pres du segment formé par p1,p2 no=Point(coords(nd)) no1=Point(coords(p1)) no2=Point(coords(p2)) seg = LineString([coords(p1), coords(p2)]) d = no.distance(seg) d1 = no.distance(no1) d2 = no.distance(no2) if (d < DIST_MIN) & (d < d1) & (d < d2) : return True else: return False class Node(object): def __init__(self, id=None, lon=None, lat=None, tags=None): self.id = id if lon != None: self.lon, self.lat = float(lon), float(lat) if tags: self.tags = tags else: self.tags = {} self.inWay = set() self.inRel = set() class Way(object): def __init__(self, id=None, nodes=None, tags=None): self.id = id if nodes: self.nodes = nodes else: self.nodes = [] if tags: self.tags = tags else: self.tags = {} class Relation(object): def __init__(self, id, members=None, tags=None): self.id = id if members: self.members = members else: self.members = [] if tags: self.tags = tags else: self.tags = {} def __repr__(self): return "Relation(id=%r, members=%r, tags=%r)" % (self.id, self.members, self.tags) class Cache: def __init__(self): self.nods = {} self.ways = {} self.rels = {} def NodeCreate(self, data): self.nods[data["id"]] = Node(id=data["id"],lon=data["lon"],lat=data["lat"],tags=data["tag"]) def WayCreate(self, data): self.ways[data["id"]] = Way(id=data["id"],nodes=data["nd"],tags=data["tag"]) def RelationCreate(self, data): self.rels[data["id"]] = Relation(id=data["id"],tags=data["tag"],members=data["member"]) ########################################################################### fout = sys.argv[2] data = OsmSax.OsmSaxReader(sys.argv[1]) cache = Cache() print 'Parse du fichier...' data.CopyTo(cache) idxNode = Rtree() tabindx = {} print 'Indexation...' i = 0 for k in cache.nods.keys(): i += 1 idxNode.insert(i, coords(cache.nods[k])) tabindx[i] = cache.nods[k] print 'Snap...' # balayage des ways for w in cache.ways.values(): i = 1 # balayage des segments d'un way while i < len(w.nodes): # print w.id , ' ',len(w.nodes), ' ', i # recherche des noeuds proches du segment seg = LineString( [ coords(cache.nods[w.nodes[i-1]]), coords(cache.nods[w.nodes[i]]) ] ) for idx in idxNode.nearest(seg.bounds,10): np = tabindx[idx] # si le noeud est déjà dans le way on ne fait rien # print 'id point: ', np.id if np.id in w.nodes: continue # print 'id point: ', np.id, ' ', no.distance(seg) if procheWay(np, cache.nods[w.nodes[i-1]], cache.nods[w.nodes[i]]): np.tags['fixme'] = 'Snaper' w.nodes.insert(i, np.id) i-=1 break i += 1 print 'Ecriture...' out = OsmSax.OsmSaxWriter(fout, "UTF-8") out.startDocument() out.startElement("osm", {'version':'0.6'}) for n in cache.nods.values(): out.NodeCreate({'id':n.id,'lon':n.lon,'lat':n.lat,'tag':n.tags}) for w in cache.ways.values(): out.WayCreate({'id':w.id,'nd':w.nodes,'tag':w.tags}) for r in cache.rels.values(): out.RelationCreate({'id':r.id,'member':r.members,'tag':r.tags}) out.endElement("osm")
_______________________________________________ Talk-fr mailing list Talk-fr@openstreetmap.org http://lists.openstreetmap.org/listinfo/talk-fr