mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
460 lines
19 KiB
Python
Executable File
460 lines
19 KiB
Python
Executable File
# -*- coding: utf-8 -*-
|
|
"""@package OsmSaveDlg
|
|
This module is used to save OSM data into XML file.
|
|
|
|
Of course, user is asked where to save the current data first.
|
|
"""
|
|
|
|
|
|
from ui_OsmSaveDlg import Ui_OsmSaveDlg
|
|
|
|
from PyQt4.QtCore import *
|
|
from PyQt4.QtGui import *
|
|
from PyQt4.QtXml import *
|
|
from sip import unwrapinstance
|
|
from qgis.core import QgsVectorLayer, QgsMapLayerRegistry
|
|
|
|
import sqlite3
|
|
|
|
|
|
|
|
class OsmSaveDlg(QDialog, Ui_OsmSaveDlg):
|
|
"""This class provides all structures and methods necessary for current OSM data saving.
|
|
|
|
Saving is done to XML file.
|
|
After XML file selection and confirming the dialog, process is started.
|
|
"""
|
|
|
|
def __init__(self, plugin):
|
|
"""The constructor.
|
|
|
|
@param plugin is pointer to instance of OSM Plugin
|
|
"""
|
|
|
|
QDialog.__init__(self, None)
|
|
self.setupUi(self)
|
|
|
|
self.plugin=plugin
|
|
self.ur=plugin.undoredo
|
|
self.dbm=plugin.dbm
|
|
|
|
self.progressDialog = QProgressDialog(self)
|
|
self.progressDialog.setModal(True)
|
|
self.progressDialog.setAutoClose(False)
|
|
|
|
# variables for identifiers of all objects that will be saved to output file
|
|
self.nodeIds=set()
|
|
|
|
# connecting dialog and progressbar signals
|
|
QObject.connect(self.browseOSMButton,SIGNAL("clicked()"),self.showSaveFileDialog)
|
|
QObject.connect(self.buttonBox,SIGNAL("accepted()"),self.onOK)
|
|
QObject.connect(self.progressDialog, SIGNAL("canceled()"), self.cancelSaving)
|
|
|
|
|
|
def cancelSaving(self):
|
|
"""Function stops the whole OSM Saving process.
|
|
|
|
Destination file is closed and removed.
|
|
"""
|
|
|
|
# writing into output file was canceled, file must be enclosed
|
|
self.outFile.close()
|
|
|
|
# end removed
|
|
self.outFile.remove()
|
|
self.outFile=None
|
|
|
|
# close the whole Save OSM dialog
|
|
self.close()
|
|
|
|
|
|
def showSaveFileDialog(self):
|
|
"""Function opens dialog for selecting XML file.
|
|
|
|
Only files with extension .osm can be selected.
|
|
Default directory for file selection is remembered/reload.
|
|
"""
|
|
|
|
settings = QSettings()
|
|
lastDir = settings.value("/OSM_Plugin/lastDir", QVariant(QString())).toString()
|
|
|
|
# display file open dialog and get absolute path to selected file
|
|
fileSelected = QFileDialog.getSaveFileName(self, self.tr("Choose an Open Street Map file"),lastDir,self.tr("OSM Files (*.osm)") );
|
|
# insert OSM file path into line edit control
|
|
if not fileSelected.isNull():
|
|
self.OSMFileEdit.setText(fileSelected)
|
|
|
|
# remember directory
|
|
fi = QFileInfo(fileSelected)
|
|
settings.setValue("/OSM_Plugin/lastDir", QVariant(fi.path()) )
|
|
|
|
|
|
def onOK(self):
|
|
"""Function is called after clicking on OK button of OSM Save dialog.
|
|
|
|
It performs all actions necessary for OSM data saving.
|
|
"""
|
|
|
|
# prepare data
|
|
|
|
self.fname=self.OSMFileEdit.text()
|
|
self.outFile=QFile(self.fname)
|
|
|
|
if not self.outFile.open(QIODevice.WriteOnly):
|
|
QMessageBox.information(self,self.tr("Save OSM to file"),self.tr("Unable to save the file %1: %2.")
|
|
.arg(self.fname).arg(self.outFile.errorString()))
|
|
self.outFile=None
|
|
return
|
|
|
|
points=self.chkPoints.isChecked()
|
|
lines=self.chkLines.isChecked()
|
|
polys=self.chkPolygons.isChecked()
|
|
rels=self.chkRelations.isChecked()
|
|
tags=self.chkTags.isChecked()
|
|
|
|
self.xml=QXmlStreamWriter(self.outFile)
|
|
self.xml.setCodec(QTextCodec.codecForName("utf-8"))
|
|
self.xml.setAutoFormatting(True)
|
|
|
|
c=self.dbm.getConnection().cursor()
|
|
|
|
cntPoints=cntLines=cntPolys=cntRels=0
|
|
c.execute("select count(*) from node")
|
|
for rec in c:
|
|
cntPoints=rec[0]
|
|
c.execute("select count(*) from way where closed=0")
|
|
for rec in c:
|
|
cntLines=rec[0]
|
|
c.execute("select count(*) from way where closed=1")
|
|
for rec in c:
|
|
cntPolys=rec[0]
|
|
c.execute("select count(*) from relation")
|
|
for rec in c:
|
|
cntRels=rec[0]
|
|
|
|
self.xml.writeStartDocument()
|
|
self.xml.writeStartElement("osm")
|
|
self.xml.writeAttribute("version","0.6")
|
|
self.xml.writeAttribute("generator","OpenStreetMap server")
|
|
|
|
self.progressDialog.setWindowTitle(self.tr("Save OSM to file"))
|
|
self.progressDialog.setLabelText(self.tr("Initializing..."))
|
|
self.progressDialog.setMaximum(1)
|
|
self.progressDialog.setValue(0)
|
|
self.progressDialog.show()
|
|
|
|
# <bounds> element
|
|
dataExtent=self.plugin.canvas.extent()
|
|
self.xml.writeEmptyElement("bounds")
|
|
self.xml.writeAttribute("minlat",str(dataExtent.yMinimum()))
|
|
self.xml.writeAttribute("minlon",str(dataExtent.xMinimum()))
|
|
self.xml.writeAttribute("maxlat",str(dataExtent.yMaximum()))
|
|
self.xml.writeAttribute("maxlon",str(dataExtent.xMaximum()))
|
|
|
|
# todo: uid and changeset attributes are not compulsory! support for them in future!
|
|
|
|
if points:
|
|
self.progressDialog.setLabelText(self.tr("Saving nodes..."))
|
|
self.progressDialog.setMaximum(cntPoints)
|
|
self.progressDialog.setValue(0)
|
|
i=0
|
|
|
|
c.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
|
|
where n.status<>'R' and n.u=1 and v.object_id=n.id and v.object_type='node' \
|
|
and n.lat>=:minLat AND n.lat<=:maxLat AND n.lon>=:minLon AND n.lon<=:maxLon"
|
|
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
|
|
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
|
|
|
|
for (nid,lat,lon,ver,usr,tms) in c:
|
|
anyTags=False
|
|
tagList=[]
|
|
|
|
self.nodeIds.add(nid)
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(nid,'Point')
|
|
if len(tagList)>0:
|
|
anyTags=True
|
|
|
|
if anyTags:
|
|
self.xml.writeStartElement("node")
|
|
else:
|
|
self.xml.writeEmptyElement("node")
|
|
|
|
self.xml.writeAttribute("id",str(nid))
|
|
self.xml.writeAttribute("lat",str(lat))
|
|
self.xml.writeAttribute("lon",str(lon))
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
|
|
if anyTags:
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
self.xml.writeEndElement()
|
|
|
|
i=i+1
|
|
self.progressDialog.setValue(i)
|
|
|
|
if lines:
|
|
self.progressDialog.setLabelText(self.tr("Saving lines..."))
|
|
self.progressDialog.setMaximum(cntLines)
|
|
self.progressDialog.setValue(0)
|
|
i=0
|
|
|
|
c.execute("select w.id,v.version_id,w.user,w.timestamp from way w,version v \
|
|
where w.closed=0 and w.status<>'R' and w.u=1 and v.object_id=w.id and v.object_type='way' \
|
|
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
|
|
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon)))"
|
|
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
|
|
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
|
|
|
|
for (lid,ver,usr,tms) in c:
|
|
|
|
geom=self.dbm.getFeatureGeometry(lid,'Line')
|
|
if not geom.intersects(dataExtent):
|
|
continue
|
|
|
|
self.xml.writeStartElement("way")
|
|
self.xml.writeAttribute("id",str(lid))
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
|
|
d=self.dbm.getConnection().cursor()
|
|
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":lid})
|
|
for r in d:
|
|
self.xml.writeEmptyElement("nd")
|
|
self.xml.writeAttribute("ref",str(r[0]))
|
|
d.close()
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(lid,'Line')
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
|
|
self.xml.writeEndElement()
|
|
|
|
d=self.dbm.getConnection().cursor()
|
|
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":lid})
|
|
for r in d:
|
|
if r[0] not in self.nodeIds:
|
|
|
|
e=self.dbm.getConnection().cursor()
|
|
e.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
|
|
where n.id=:nid",{"nid":r[0]})
|
|
for nodeRec in e:
|
|
nid=nodeRec[0]
|
|
lat=nodeRec[1]
|
|
lon=nodeRec[2]
|
|
ver=nodeRec[3]
|
|
usr=nodeRec[4]
|
|
tms=nodeRec[5]
|
|
e.close()
|
|
|
|
anyTags=False
|
|
tagList=[]
|
|
self.nodeIds.add(nid)
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(nid,'Point')
|
|
if len(tagList)>0:
|
|
anyTags=True
|
|
|
|
if anyTags:
|
|
self.xml.writeStartElement("node")
|
|
else:
|
|
self.xml.writeEmptyElement("node")
|
|
|
|
self.xml.writeAttribute("id",str(nid))
|
|
self.xml.writeAttribute("lat",str(lat))
|
|
self.xml.writeAttribute("lon",str(lon))
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
|
|
if anyTags:
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
self.xml.writeEndElement()
|
|
|
|
d.close()
|
|
i=i+1
|
|
self.progressDialog.setValue(i)
|
|
|
|
if polys:
|
|
self.progressDialog.setLabelText(self.tr("Saving polygons..."))
|
|
self.progressDialog.setMaximum(cntPolys)
|
|
self.progressDialog.setValue(0)
|
|
i=0
|
|
|
|
c.execute("select w.id,v.version_id,w.user,w.timestamp from way w,version v \
|
|
where w.closed=1 and w.status<>'R' and w.u=1 and v.object_id=w.id and v.object_type='way' \
|
|
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
|
|
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon)))"
|
|
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
|
|
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
|
|
|
|
for (pid,ver,usr,tms) in c:
|
|
|
|
geom=self.dbm.getFeatureGeometry(pid,'Polygon')
|
|
if not geom.intersects(dataExtent):
|
|
continue
|
|
|
|
self.xml.writeStartElement("way")
|
|
self.xml.writeAttribute("id",str(pid))
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
|
|
d=self.dbm.getConnection().cursor()
|
|
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":pid})
|
|
first=None
|
|
for r in d:
|
|
self.xml.writeEmptyElement("nd")
|
|
self.xml.writeAttribute("ref",str(r[0]))
|
|
if first==None:
|
|
first=r[0]
|
|
d.close()
|
|
self.xml.writeEmptyElement("nd")
|
|
self.xml.writeAttribute("ref",str(first))
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(pid,'Polygon')
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
|
|
self.xml.writeEndElement()
|
|
|
|
d=self.dbm.getConnection().cursor()
|
|
d.execute("select node_id from way_member where way_id=:wayId",{"wayId":pid})
|
|
for r in d:
|
|
if r[0] not in self.nodeIds:
|
|
|
|
e=self.dbm.getConnection().cursor()
|
|
e.execute("select n.id,n.lat,n.lon,v.version_id,n.user,n.timestamp from node n, version v \
|
|
where n.id=:nid",{"nid":r[0]})
|
|
for nodeRec in e:
|
|
nid=nodeRec[0]
|
|
lat=nodeRec[1]
|
|
lon=nodeRec[2]
|
|
ver=nodeRec[3]
|
|
usr=nodeRec[4]
|
|
tms=nodeRec[5]
|
|
e.close()
|
|
|
|
anyTags=False
|
|
tagList=[]
|
|
self.nodeIds.add(nid)
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(nid,'Point')
|
|
if len(tagList)>0:
|
|
anyTags=True
|
|
|
|
if anyTags:
|
|
self.xml.writeStartElement("node")
|
|
else:
|
|
self.xml.writeEmptyElement("node")
|
|
|
|
self.xml.writeAttribute("id",str(nid))
|
|
self.xml.writeAttribute("lat",str(lat))
|
|
self.xml.writeAttribute("lon",str(lon))
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
|
|
if anyTags:
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
self.xml.writeEndElement()
|
|
|
|
d.close()
|
|
i=i+1
|
|
self.progressDialog.setValue(i)
|
|
|
|
if rels:
|
|
self.progressDialog.setLabelText(self.tr("Saving relations..."))
|
|
self.progressDialog.setMaximum(cntRels)
|
|
self.progressDialog.setValue(0)
|
|
i=0
|
|
|
|
c.execute("select r.id,v.version_id,r.user,r.timestamp from relation r,version v \
|
|
where r.status<>'R' and r.u=1 and v.object_id=r.id and v.object_type='relation' \
|
|
and ( \
|
|
exists ( \
|
|
select 1 from node n, relation_member rm \
|
|
where rm.relation_id=r.id and n.status<>'R' and n.u=1 and rm.member_id=n.id and rm.member_type='node' \
|
|
and n.lat>=:minLat and n.lat<=:maxLat and n.lon>=:minLon and n.lon<=:maxLon ) \
|
|
or exists ( \
|
|
select 1 from way w, relation_member rm \
|
|
where rm.relation_id=r.id and w.status<>'R' and w.u=1 and rm.member_id=w.id and rm.member_type='way' \
|
|
and (((w.max_lat between :minLat and :maxLat) or (w.min_lat between :minLat and :maxLat) or (w.min_lat<:minLat and w.max_lat>:maxLat)) \
|
|
and ((w.max_lon between :minLon and :maxLon) or (w.min_lon between :minLon and :maxLon) or (w.min_lon<:minLon and w.max_lon>:maxLon))) \
|
|
))"
|
|
,{"minLat":dataExtent.yMinimum(),"maxLat":dataExtent.yMaximum()
|
|
,"minLon":dataExtent.xMinimum(),"maxLon":dataExtent.xMaximum()})
|
|
|
|
for (rid,ver,usr,tms) in c:
|
|
|
|
self.xml.writeStartElement("relation")
|
|
self.xml.writeAttribute("id",str(rid))
|
|
self.xml.writeAttribute("visible","true")
|
|
self.xml.writeAttribute("timestamp",tms)
|
|
self.xml.writeAttribute("version",str(ver))
|
|
if usr<>"":
|
|
self.xml.writeAttribute("user",usr)
|
|
|
|
d=self.dbm.getConnection().cursor()
|
|
d.execute("select member_id,member_type,role from relation_member where relation_id=:relId",{"relId":rid})
|
|
for r in d:
|
|
self.xml.writeEmptyElement("member")
|
|
self.xml.writeAttribute("type",r[1])
|
|
self.xml.writeAttribute("ref",str(r[0]))
|
|
self.xml.writeAttribute("role",r[2])
|
|
d.close()
|
|
|
|
if tags:
|
|
tagList=self.dbm.getFeatureTags(rid,'Relation')
|
|
for r in tagList:
|
|
self.xml.writeEmptyElement("tag")
|
|
self.xml.writeAttribute("k",r[0])
|
|
self.xml.writeAttribute("v",r[1])
|
|
self.xml.writeEndElement()
|
|
|
|
i=i+1
|
|
self.progressDialog.setValue(i)
|
|
|
|
|
|
self.xml.writeEndElement() # osm
|
|
self.xml.writeEndDocument()
|
|
|
|
c.close()
|
|
self.disconnect(self.progressDialog, SIGNAL("canceled()"), self.cancelSaving)
|
|
self.progressDialog.close()
|
|
|
|
# writing into output file was finished, file can be enclosed
|
|
if self.outFile and self.outFile.exists():
|
|
self.outFile.close()
|
|
self.close()
|