Skip to content

Instantly share code, notes, and snippets.

@TimSC
Last active February 12, 2018 10:35
Show Gist options
  • Save TimSC/2b22f9f41a4d86978501c7cc9b82b224 to your computer and use it in GitHub Desktop.
Save TimSC/2b22f9f41a4d86978501c7cc9b82b224 to your computer and use it in GitHub Desktop.
Test OSM bbox functionality
from __future__ import print_function
import sys
import requests
from requests.auth import HTTPBasicAuth
import xml.etree.ElementTree as ET
PY3 = sys.version_info > (3, 0)
if PY3:
raw_input = input
def GetChangesetBbox(cid):
response = requests.get(baseurl+"/0.6/changeset/"+str(cid))
xml = ET.fromstring(response.text)
changesetEl = xml.find("changeset")
bbox = (changesetEl.attrib["min_lon"], changesetEl.attrib["min_lat"],
changesetEl.attrib["max_lon"], changesetEl.attrib["max_lat"])
return list(map(float, bbox))
def CreateChangeset(userpass, verbose=0):
#Create a changeset
createChangeset = "<?xml version='1.0' encoding='UTF-8'?>\n" +\
"<osm version='0.6' generator='JOSM'>\n" +\
" <changeset id='0' open='false'>\n" +\
" <tag k='comment' v='python test function' />\n" +\
" <tag k='created_by' v='JOSM/1.5 (3592 en_GB)' />\n" +\
" </changeset>\n" +\
"</osm>\n"
response = requests.put(baseurl+"/0.6/changeset/create",data=createChangeset,auth=userpass)
if verbose: print(response.text)
cid = int(response.text)
if response.status_code != 200: return (0,"Error creating changeset")
return (1, cid)
def CloseChangeset(userpass, cid, verbose=0):
#Close the changeset
url = baseurl+"/0.6/changeset/"+str(cid)+"/close"
response = requests.put(url,data="",auth=userpass)
if verbose: print(response.text)
if response.status_code != 200: return (0,"Error closing changeset")
def PtsToBbox(posLi, bboxIn = None):
if bboxIn is None:
bbox = [None, None, None, None]
else:
bbox = bboxIn[:]
for pos in posLi:
if bbox[0] is None or pos[1] < bbox[0]:
bbox[0] = pos[1]
if bbox[1] is None or pos[0] < bbox[1]:
bbox[1] = pos[0]
if bbox[2] is None or pos[1] > bbox[2]:
bbox[2] = pos[1]
if bbox[3] is None or pos[0] > bbox[3]:
bbox[3] = pos[0]
return bbox
def CompareBboxes(bbox1, bbox2):
errVal = None
for v1, v2 in zip(bbox1, bbox2):
ev = abs(v1 - v2)
if errVal is None or ev > errVal:
errVal = ev
return errVal
def ParseDiff(xml):
diff = ET.fromstring(xml)
out = {"node": {}, "way": {}, "relation": {}}
for ch in diff:
out[ch.tag][int(ch.attrib['old_id'])] = (int(ch.attrib['new_id']), int(ch.attrib['new_version']))
return out
def TestCreateWayWithNodes(userpass, verbose=0):
ok, cid = CreateChangeset(userpass)
posLi = [(51.25022331526812, -0.6042092878597837), (51.2419166618214, -0.5910182209303836)]
#Create a way between two nodes
create = "<?xml version='1.0' encoding='UTF-8'?>\n" +\
"<osmChange version='0.6' generator='JOSM'>\n" +\
"<create version='0.6' generator='JOSM'>\n" +\
" <node id='-289' changeset='{}' lat='{}' lon='{}' />\n".format(cid, posLi[0][0], posLi[0][1]) +\
" <node id='-2008' changeset='{}' lat='{}' lon='{}' />\n".format(cid, posLi[1][0], posLi[1][1]) +\
" <way id='-2010' changeset='"+str(cid)+"'>\n"+\
" <nd ref='-289' />\n"+\
" <nd ref='-2008' />\n"+\
" </way>\n"+\
"</create>\n" +\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=create,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error creating node")
diffMapping = ParseDiff(response.text)
wayIdVer = diffMapping["way"][-2010]
chkBbox = GetChangesetBbox(cid)
expectedBbox = PtsToBbox(posLi) #All created nodes used to specify bbox
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
CloseChangeset(userpass, cid, verbose)
chkBbox = GetChangesetBbox(cid)
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
ok, cid = CreateChangeset(userpass)
#Modify way tags
modifyWay = '<osmChange version="0.6" generator="JOSM">'+"\n"+\
"<modify>\n"+\
" <way id='{}' version='{}' changeset='{}'>\n".format(wayIdVer[0], wayIdVer[1], cid)+\
" <nd ref='{}' />\n".format(diffMapping['node'][-289][0])+\
" <nd ref='{}' />\n".format(diffMapping['node'][-2008][0])+\
" <tag k='comment' v='python test function' />\n" +\
" </way>\n"+\
"</modify>\n"+\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=modifyWay,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error deleting node")
diffMapping2 = ParseDiff(response.text)
CloseChangeset(userpass, cid, verbose)
chkBbox = GetChangesetBbox(cid)
expectedBbox = PtsToBbox(posLi) #All nodes in modified way used to specify bbox
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
ok, cid = CreateChangeset(userpass)
#Move node in way
nodeIdVer = diffMapping['node'][-289]
newPos = (51.253, -0.596)
modifyNode = '<osmChange version="0.6" generator="JOSM">'+"\n"+\
"<modify>\n"+\
" <node id='{}' version='{}' changeset='{}' lat='{}' lon='{}' />\n".format(nodeIdVer[0], nodeIdVer[1], cid, newPos[0], newPos[1])+\
"</modify>\n"+\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=modifyNode,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error moving node")
chkBbox = GetChangesetBbox(cid)
expectedBbox = PtsToBbox([posLi[0], newPos]) #Only the affect node (new and old position) is used to define bbox
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
#Add node to way
newPos2 = (51.250, -0.606)
create = "<?xml version='1.0' encoding='UTF-8'?>\n" +\
"<osmChange version='0.6' generator='JOSM'>\n" +\
"<create version='0.6' generator='JOSM'>\n" +\
" <node id='-559' changeset='{}' lat='{}' lon='{}' />\n".format(cid, newPos2[0], newPos2[1]) +\
"</create>\n" +\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=create,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error creating node")
diffMapping3 = ParseDiff(response.text)
newNodeIdVer = diffMapping3["node"][-559]
CloseChangeset(userpass, cid, verbose)
ok, cid = CreateChangeset(userpass)
modifyWay = '<osmChange version="0.6" generator="JOSM">'+"\n"+\
"<modify>\n"+\
" <way id='{}' version='{}' changeset='{}'>\n".format(wayIdVer[0], diffMapping2['way'][wayIdVer[0]][1], cid)+\
" <nd ref='{}' />\n".format(diffMapping['node'][-289][0])+\
" <nd ref='{}' />\n".format(diffMapping['node'][-2008][0])+\
" <nd ref='{}' />\n".format(newNodeIdVer[0])+\
" <tag k='comment' v='foobar' />\n" +\
" </way>\n"+\
"</modify>\n"+\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=modifyWay,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error inserting node")
diffMapping4 = ParseDiff(response.text)
CloseChangeset(userpass, cid, verbose)
#chkBbox = GetChangesetBbox(cid) #This doesn't seem to match any sensible result
#expectedBbox = PtsToBbox([newPos2, posLi[1], newPos])
#maxErr = CompareBboxes(chkBbox, expectedBbox)
#if maxErr > 1e-6:
# print ("While inserting node into way")
# print ("Bbox don't match expected", chkBbox)
# print ("Expected: ", expectedBbox)
#Delete a node
ok, cid = CreateChangeset(userpass)
modifyWay = '<osmChange version="0.6" generator="JOSM">'+"\n"+\
"<modify>\n"+\
" <way id='{}' version='{}' changeset='{}'>\n".format(wayIdVer[0], diffMapping4['way'][wayIdVer[0]][1], cid)+\
" <nd ref='{}' />\n".format(diffMapping['node'][-289][0])+\
" <nd ref='{}' />\n".format(newNodeIdVer[0])+\
" <tag k='comment' v='parrot' />\n" +\
" </way>\n"+\
"</modify>\n"+\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=modifyWay,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error removing node")
CloseChangeset(userpass, cid, verbose)
chkBbox = GetChangesetBbox(cid)
expectedBbox = PtsToBbox([newPos2, posLi[1], newPos]) #All nodes used, plus the deleted node, in way define the bbox
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("While removing node into way")
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
return (1,"OK")
def TestInsertNodeIntoWay(userpass, verbose=0):
ok, cid = CreateChangeset(userpass)
posLi = [(51.25022331526812, -0.6042092878597837), (51.2419166618214, -0.5910182209303836), (51.250, -0.606)]
#Create a way between two nodes
create = "<?xml version='1.0' encoding='UTF-8'?>\n" +\
"<osmChange version='0.6' generator='JOSM'>\n" +\
"<create version='0.6' generator='JOSM'>\n" +\
" <node id='-289' changeset='{}' lat='{}' lon='{}' />\n".format(cid, posLi[0][0], posLi[0][1]) +\
" <node id='-2008' changeset='{}' lat='{}' lon='{}' />\n".format(cid, posLi[1][0], posLi[1][1]) +\
" <node id='-559' changeset='{}' lat='{}' lon='{}' />\n".format(cid, posLi[2][0], posLi[2][1]) +\
" <way id='-2010' changeset='"+str(cid)+"'>\n"+\
" <nd ref='-289' />\n"+\
" <nd ref='-2008' />\n"+\
" </way>\n"+\
"</create>\n" +\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=create,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error creating objects")
diffMapping = ParseDiff(response.text)
CloseChangeset(userpass, cid, verbose)
ok, cid = CreateChangeset(userpass)
modifyWay = '<osmChange version="0.6" generator="JOSM">'+"\n"+\
"<modify>\n"+\
" <way id='{}' version='{}' changeset='{}'>\n".format(diffMapping['way'][-2010][0], diffMapping['way'][-2010][1], cid)+\
" <nd ref='{}' />\n".format(diffMapping['node'][-289][0])+\
" <nd ref='{}' />\n".format(diffMapping['node'][-2008][0])+\
" <nd ref='{}' />\n".format(diffMapping['node'][-559][0])+\
" <tag k='comment' v='parrot' />\n" +\
" </way>\n"+\
"</modify>\n"+\
"</osmChange>\n"
response = requests.post(baseurl+"/0.6/changeset/"+str(cid)+"/upload",data=modifyWay,auth=userpass)
if verbose: print (response.text)
if response.status_code != 200: return (0,"Error modifying way")
CloseChangeset(userpass, cid, verbose)
chkBbox = GetChangesetBbox(cid) #This doesn't seem to match any sensible result
expectedBbox = PtsToBbox(posLi)
maxErr = CompareBboxes(chkBbox, expectedBbox)
if maxErr > 1e-6:
print ("While inserting node into way")
print ("Bbox don't match expected", chkBbox)
print ("Expected: ", expectedBbox)
return (1,"OK")
baseurl = "https://master.apis.dev.openstreetmap.org/api"
username = raw_input("Username:")
password = raw_input("Password:")
userpass = username+":"+password
print (TestCreateWayWithNodes(HTTPBasicAuth(username, password),0))
print (TestInsertNodeIntoWay(HTTPBasicAuth(username, password),0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment