QGIS/python/plugins/osm/OsmImportDlg.py
2011-09-15 21:33:42 +03:00

252 lines
6.7 KiB
Python
Executable File

# -*- coding: utf-8 -*-
"""@package OsmImportDlg
This module is used to import OSM data from standard QGIS vector layer.
"""
from ui_OsmImportDlg import Ui_OsmImportDlg
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
class dummyPoint:
"""A wrapper around QgsPoint which adds hash calculation.
"""
def __init__(self, pt):
"""The constructor."""
self.pt = pt
def __hash__(self):
return int(self.pt.x()*230783 + self.pt.y()*680091)
def __eq__(self, other):
return self.pt.x() == other.pt.x() and self.pt.y() == other.pt.y()
class dummyFeat:
"""A dummy QgsFeature that just returns its feature id.
"""
def __init__(self, fid):
"""The constructor."""
self.fid = fid
def id(self):
return self.fid
class OsmImportDlg(QDialog, Ui_OsmImportDlg):
"""This class provides structures and methods necessary for import OSM data.
Class is direct descendant of OSM Import dialog.
After confirming OSM Import dialog process is immediately 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.dbm = plugin.dbm
self.affected=set()
self.populateLayers()
QObject.connect(self.buttonBox,SIGNAL("accepted()"),self.onOK)
QObject.connect(self.cboLayer,SIGNAL("currentIndexChanged(int)"), self.updateUi)
if self.cboLayer.count() > 0:
self.updateUi(0)
def updateUi(self, index):
"""Function checks whether there is any selection in the layer.
"""
layerId = self.cboLayer.itemData(index).toString()
layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
if layer is None or len(layer.selectedFeaturesIds()) == 0:
self.chkOnlySelection.setChecked(False)
self.chkOnlySelection.setEnabled(False)
def populateLayers(self):
"""Funtion populates layers.
"""
self.cboLayer.clear()
layers = QgsMapLayerRegistry.instance().mapLayers()
for lyrId,lyr in layers.iteritems():
if lyr.type() == QgsMapLayer.VectorLayer and lyr.dataProvider().name() != "osm":
self.cboLayer.addItem(lyr.name(), QVariant(lyrId) )
def onOK(self):
"""Function does OSM data importing.
"""
layerId = self.cboLayer.itemData(self.cboLayer.currentIndex()).toString()
onlySel = self.chkOnlySelection.isChecked()
layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
if layer is None:
QMessageBox.warning(self, self.tr("Layer doesn't exist"), self.tr("The selected layer doesn't exist anymore!"))
return
self.progress = QProgressDialog(self.tr("Importing features..."), self.tr("Cancel"), 0, 100, self)
self.progress.setWindowModality(Qt.WindowModal)
self.nodes = { }
if onlySel:
# only selected features
features = layer.selectedFeatures()
count = len(features)
self.progress.setMaximum(count)
for f in features:
if not self.updateProgress():
break
self.addFeature(f)
else:
# all features from layer
count = layer.featureCount()
self.progress.setMaximum(count)
layer.select()
f = QgsFeature()
while layer.nextFeature(f):
if not self.updateProgress():
break
self.addFeature(f)
self.dbm.commit()
self.progress.setValue(count)
self.dbm.recacheAffectedNow(self.affected)
self.plugin.canvas.refresh()
QMessageBox.information(self, self.tr("Import"), self.tr("Import has been completed."))
self.accept()
def updateProgress(self):
"""Function updates progress dialog.
"""
self.progress.setValue( self.progress.value()+1 )
return not self.progress.wasCanceled()
def addFeature(self,f):
"""Function adds given feature.
@param f feature to be added
"""
g = f.geometry()
if g is None:
return
wkbType = g.wkbType()
if wkbType == QGis.WKBPoint:
self.extractPoint(g.asPoint())
elif wkbType == QGis.WKBLineString:
self.extractLineString(g.asPolyline())
elif wkbType == QGis.WKBPolygon:
self.extractPolygon(g.asPolygon())
elif wkbType == QGis.WKBMultiPoint:
for pnt in g.asMultiPoint():
self.extractPoint(pnt)
elif wkbType == QGis.WKBMultiLineString:
for line in g.asMultiPolyline():
self.extractLineString(line)
elif wkbType == QGis.WKBMultiPolygon:
for polygon in g.asMultiPolygon():
self.extractPolygon(polygon)
def extractPoint(self, pnt):
"""Function extracts a point.
@param pnt point to extract
"""
# TODO: check that another point isn't already at the same position
(node,affected)=self.dbm.createPoint(pnt, None, None, False)
self.affected.update(affected)
def snapPoint(self, pnt):
""" Function checks whether there's already other point with the same position.
If so, it pretends it got snapped to that point.
@param pnt point to snap
"""
dp = dummyPoint(pnt)
if dp in self.nodes:
return (pnt, self.nodes[dp], 'Point')
else:
return (pnt,None,None)
def extractLineString(self, line):
"""Function extracts a line.
@param line line to extract
"""
points = map(self.snapPoint, line)
(feat,affected) = self.dbm.createLine(points, False)
self.affected.update(affected)
# this is a hack that uses the knowledge of inner working of createLine.
# that sucks.
nodeId = feat.id()-1
for p in points:
if p[1] is None:
dp = dummyPoint(p[0])
self.nodes[dp] = dummyFeat(nodeId)
nodeId -= 1
def extractPolygon(self, polygon):
"""Function extracts a polygon.
@param polygon polygon to extract
"""
# TODO: do something with holes?
points=map(self.snapPoint, polygon[0])
if len(points)>0:
points.pop()
(feat,affected)=self.dbm.createPolygon(points, False)
self.affected.update(affected)
# this is a hack that uses the knowledge of inner working of createPolygon.
# that sucks.
nodeId = feat.id()-1
for p in points:
if p[1] is None:
dp = dummyPoint(p[0])
self.nodes[dp] = dummyFeat(nodeId)
nodeId -= 1