From 34ed1edda0d84a8b46603534c97b8311496829a4 Mon Sep 17 00:00:00 2001 From: alpha-beta-soup Date: Mon, 8 Feb 2016 17:08:21 +1300 Subject: [PATCH 1/3] ui changes for vector layer intersection --- qtilesdialog.py | 19 +++++++++++++++-- tile.py | 8 +++++++ tilingthread.py | 4 ++++ ui/qtilesdialogbase.ui | 48 +++++++++++++++++++++++++++--------------- 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/qtilesdialog.py b/qtilesdialog.py index dff2d24..d8831d8 100644 --- a/qtilesdialog.py +++ b/qtilesdialog.py @@ -68,6 +68,7 @@ def __init__(self, iface): self.grpParameters.setSettings(self.settings) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.rbExtentLayer.toggled.connect(self.__toggleLayerSelector) + self.rbVectorIntersect.toggled.connect(self.__toggleLayerSelector_VectorIntersection) self.chkLockRatio.stateChanged.connect(self.__toggleHeightEdit) self.spnTileWidth.valueChanged.connect(self.__updateTileSize) self.btnBrowse.clicked.connect(self.__select_output) @@ -125,9 +126,11 @@ def manageGui(self): for layer in sorted(layers.iteritems(), cmp=locale.strcoll, key=operator.itemgetter(1)): groupName = utils.getLayerGroup(relations, layer[0]) if groupName == '': - self.cmbLayers.addItem(layer[1], layer[0]) + for cmb in [self.cmbLayers, self.cmbVectorIntersect]: + cmb.addItem(layer[1], layer[0]) else: - self.cmbLayers.addItem('%s - %s' % (layer[1], groupName), layer[0]) + for cmb in [self.cmbLayers, self.cmbVectorIntersect]: + cmb.addItem('%s - %s' % (layer[1], groupName), layer[0]) self.rbOutputZip.setChecked(self.settings.value('outputToZip', True, type=bool)) self.rbOutputDir.setChecked(self.settings.value('outputToDir', False, type=bool)) @@ -151,6 +154,7 @@ def manageGui(self): self.leTilesFroNGM.setText(self.settings.value('outputToNGM_Path', '')) self.cmbLayers.setEnabled(False) + self.cmbVectorIntersect.setEnabled(False) self.leRootDir.setText(self.settings.value('rootDir', 'Mapnik')) self.rbExtentCanvas.setChecked(self.settings.value('extentCanvas', True, type=bool)) self.rbExtentFull.setChecked(self.settings.value('extentFull', False, type=bool)) @@ -235,6 +239,14 @@ def accept(self): else: layer = utils.getLayerById(self.cmbLayers.itemData(self.cmbLayers.currentIndex())) extent = canvas.mapRenderer().layerExtentToOutputExtent(layer, layer.extent()) + # if self.rbVectorIntersect.isChecked(): + # # Only tiles that intersect the chosen vector layer will be rendered and cached + # self.intersect_layer = utils.getLayerById(self.cmbVectorIntersect.itemData(self.cmbVectorIntersect.currentIndex())) + # self.intersect_features = {feature.id(): feature for (feature) in self.intersect_layer.getFeatures()} + # self.intersect_layer_index = QgsSpatialIndex() + # map(self.intersect_layer_index.insertFeature, self.intersect_features.values()) + # else: + # self.intersect_layer_index = None extent = QgsCoordinateTransform(canvas.mapRenderer().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326')).transform(extent) arctanSinhPi = math.degrees(math.atan(math.sinh(math.pi))) extent = extent.intersect(QgsRectangle(-180, -arctanSinhPi, 180, arctanSinhPi)) @@ -356,6 +368,9 @@ def __toggleTarget(self, checked): def __toggleLayerSelector(self, checked): self.cmbLayers.setEnabled(checked) + def __toggleLayerSelector_VectorIntersection(self, checked): + self.cmbVectorIntersect.setEnabled(checked) + def __toggleHeightEdit(self, state): if state == Qt.Checked: self.lblHeight.setEnabled(False) diff --git a/tile.py b/tile.py index 50c422c..1663f4d 100644 --- a/tile.py +++ b/tile.py @@ -46,3 +46,11 @@ def toPoint(self): def toRectangle(self): return QgsRectangle(self.toPoint(), Tile(self.x + 1, self.y + 1, self.z, self.tms).toPoint()) + + # def intersects_spatial_index(self, spatial_index): + # rectangle = self.toRectangle() + # intersect = spatial_index.intersects(rectangle) + # if intersect: + # return True + # else: + # return False diff --git a/tilingthread.py b/tilingthread.py index 03a0e56..bd54161 100644 --- a/tilingthread.py +++ b/tilingthread.py @@ -103,6 +103,7 @@ def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, qual self.settings.setFlag(QgsMapSettings.Antialiasing, True) else: self.settings.setFlag(QgsMapSettings.DrawLabeling, True) + # self.spatialIndex = spatialIndex def run(self): self.mutex.lock() @@ -135,7 +136,10 @@ def run(self): self.tiles = None self.processInterrupted.emit() self.rangeChanged.emit(self.tr('Rendering: %v from %m (%p%)'), len(self.tiles)) + QgsMessageLog.logMessage(str(len(self.tiles))) for t in self.tiles: + # if not self.spatialIndex or t.intersects_spatial_index(self.spatialIndex): + # self.render(t) self.render(t) self.updateProgress.emit() self.mutex.lock() diff --git a/ui/qtilesdialogbase.ui b/ui/qtilesdialogbase.ui index d4ea759..dafe5cd 100644 --- a/ui/qtilesdialogbase.ui +++ b/ui/qtilesdialogbase.ui @@ -49,7 +49,7 @@ 0 0 515 - 619 + 607 @@ -277,20 +277,17 @@ Extent - - 6 - - - + + - Full extent + Canvas extent - - + + - Canvas extent + Full extent @@ -311,6 +308,23 @@ + + + + Feature intersect + + + + + + + + 0 + 0 + + + + @@ -402,10 +416,10 @@ Parameters - + true - + true @@ -631,7 +645,7 @@ QgsCollapsibleGroupBox QGroupBox -
qgis.gui
+
qgscollapsiblegroupbox.h
1
@@ -644,8 +658,8 @@ accept() - 248 - 254 + 257 + 680 157 @@ -660,8 +674,8 @@ reject() - 316 - 260 + 325 + 680 286 From 9330e775cd0085ac06a8eb1f983053682513e463 Mon Sep 17 00:00:00 2001 From: alpha-beta-soup Date: Mon, 8 Feb 2016 21:03:22 +1300 Subject: [PATCH 2/3] conditional rendering with vector layer intersection --- qtilesdialog.py | 39 +++++++++++++++++++++++++-------------- tile.py | 12 +++++------- tilingthread.py | 15 +++++++++------ 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/qtilesdialog.py b/qtilesdialog.py index d8831d8..6507c25 100644 --- a/qtilesdialog.py +++ b/qtilesdialog.py @@ -123,13 +123,13 @@ def formatChanged(self): def manageGui(self): layers = utils.getMapLayers() relations = self.iface.legendInterface().groupLayerRelationship() + combos = [self.cmbLayers, self.cmbVectorIntersect] for layer in sorted(layers.iteritems(), cmp=locale.strcoll, key=operator.itemgetter(1)): groupName = utils.getLayerGroup(relations, layer[0]) - if groupName == '': - for cmb in [self.cmbLayers, self.cmbVectorIntersect]: + for cmb in combos: + if groupName == '': cmb.addItem(layer[1], layer[0]) - else: - for cmb in [self.cmbLayers, self.cmbVectorIntersect]: + else: cmb.addItem('%s - %s' % (layer[1], groupName), layer[0]) self.rbOutputZip.setChecked(self.settings.value('outputToZip', True, type=bool)) @@ -232,22 +232,20 @@ def accept(self): self.settings.setValue('write_viewer', self.chkWriteViewer.isChecked()) self.settings.setValue('renderOutsideTiles', self.chkRenderOutsideTiles.isChecked()) canvas = self.iface.mapCanvas() + geomTransform = QgsCoordinateTransform(canvas.mapRenderer().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326')) + self.spatialIndex = None if self.rbExtentCanvas.isChecked(): extent = canvas.extent() elif self.rbExtentFull.isChecked(): extent = canvas.fullExtent() + elif self.rbVectorIntersect.isChecked(): + layer = utils.getLayerById(self.cmbVectorIntersect.itemData(self.cmbVectorIntersect.currentIndex())) + extent = canvas.mapRenderer().layerExtentToOutputExtent(layer, layer.extent()) + self.spatialIndex = self.__prepare_spatial_index(layer, geomTransform) else: layer = utils.getLayerById(self.cmbLayers.itemData(self.cmbLayers.currentIndex())) extent = canvas.mapRenderer().layerExtentToOutputExtent(layer, layer.extent()) - # if self.rbVectorIntersect.isChecked(): - # # Only tiles that intersect the chosen vector layer will be rendered and cached - # self.intersect_layer = utils.getLayerById(self.cmbVectorIntersect.itemData(self.cmbVectorIntersect.currentIndex())) - # self.intersect_features = {feature.id(): feature for (feature) in self.intersect_layer.getFeatures()} - # self.intersect_layer_index = QgsSpatialIndex() - # map(self.intersect_layer_index.insertFeature, self.intersect_features.values()) - # else: - # self.intersect_layer_index = None - extent = QgsCoordinateTransform(canvas.mapRenderer().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326')).transform(extent) + extent = geomTransform.transform(extent) arctanSinhPi = math.degrees(math.atan(math.sinh(math.pi))) extent = extent.intersect(QgsRectangle(-180, -arctanSinhPi, 180, arctanSinhPi)) layers = canvas.layers() @@ -272,7 +270,8 @@ def accept(self): self.chkWriteOverview.isChecked(), self.chkRenderOutsideTiles.isChecked(), writeMapurl, - writeViewer + writeViewer, + self.spatialIndex ) self.workThread.rangeChanged.connect(self.setProgressRange) @@ -413,3 +412,15 @@ def __select_output(self): outPath += '.ngrc' self.leTilesFroNGM.setText(outPath) self.settings.setValue('outputToNGM_Path', QFileInfo(outPath).absoluteFilePath()) + + def __prepare_spatial_index(self, layer, geomTransform): + '''Returns a QgsSpatialIndex of the features of the layer selected in + self.cmbVectorIntersect. should be a + QgsCoordianteTransform allowing transformation from the source CRS to + EPSG:4326 for ''' + spatialIndex = QgsSpatialIndex() + vals = {feature.id(): feature for (feature) in layer.getFeatures()}.values() + for v in vals: + v.geometry().transform(geomTransform) + map(spatialIndex.insertFeature, vals) + return spatialIndex diff --git a/tile.py b/tile.py index 1663f4d..0491d10 100644 --- a/tile.py +++ b/tile.py @@ -47,10 +47,8 @@ def toPoint(self): def toRectangle(self): return QgsRectangle(self.toPoint(), Tile(self.x + 1, self.y + 1, self.z, self.tms).toPoint()) - # def intersects_spatial_index(self, spatial_index): - # rectangle = self.toRectangle() - # intersect = spatial_index.intersects(rectangle) - # if intersect: - # return True - # else: - # return False + def intersects_spatial_index(self, spatial_index): + if spatial_index.intersects(self.toRectangle()): + return True + else: + return False diff --git a/tilingthread.py b/tilingthread.py index bd54161..7c98a50 100644 --- a/tilingthread.py +++ b/tilingthread.py @@ -42,7 +42,7 @@ class TilingThread(QThread): processFinished = pyqtSignal() processInterrupted = pyqtSignal() - def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, quality, format, outputPath, rootDir, antialiasing, tmsConvention, mbtilesCompression, jsonFile, overview, renderOutsideTiles, mapUrl, viewer): + def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, quality, format, outputPath, rootDir, antialiasing, tmsConvention, mbtilesCompression, jsonFile, overview, renderOutsideTiles, mapUrl, viewer, spatialIndex): QThread.__init__(self, QThread.currentThread()) self.mutex = QMutex() self.stopMe = 0 @@ -103,7 +103,7 @@ def __init__(self, layers, extent, minZoom, maxZoom, width, height, transp, qual self.settings.setFlag(QgsMapSettings.Antialiasing, True) else: self.settings.setFlag(QgsMapSettings.DrawLabeling, True) - # self.spatialIndex = spatialIndex + self.spatialIndex = spatialIndex def run(self): self.mutex.lock() @@ -138,8 +138,6 @@ def run(self): self.rangeChanged.emit(self.tr('Rendering: %v from %m (%p%)'), len(self.tiles)) QgsMessageLog.logMessage(str(len(self.tiles))) for t in self.tiles: - # if not self.spatialIndex or t.intersects_spatial_index(self.spatialIndex): - # self.render(t) self.render(t) self.updateProgress.emit() self.mutex.lock() @@ -232,6 +230,11 @@ def writeLeafletViewer(self): fOut.write(viewer.substitute(substitutions)) templateFile.close() + def append_tile_index_check(self, tile): + if not self.spatialIndex or tile.intersects_spatial_index(self.spatialIndex): + self.tiles.append(tile) + return + def countTiles(self, tile): if self.interrupted or not self.extent.intersects(tile.toRectangle()): return @@ -239,10 +242,10 @@ def countTiles(self, tile): if not self.renderOutsideTiles: for layer in self.layers: if layer.extent().intersects(tile.toRectangle()): - self.tiles.append(tile) + self.append_tile_index_check(tile) break else: - self.tiles.append(tile) + self.append_tile_index_check(tile) if tile.z < self.maxZoom: for x in xrange(2 * tile.x, 2 * tile.x + 2, 1): for y in xrange(2 * tile.y, 2 * tile.y + 2, 1): From 4a53aa768975661f44de3f276705573a536d4e5e Mon Sep 17 00:00:00 2001 From: alpha-beta-soup Date: Mon, 8 Feb 2016 21:25:01 +1300 Subject: [PATCH 3/3] removed log message --- tilingthread.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tilingthread.py b/tilingthread.py index 7c98a50..7db0890 100644 --- a/tilingthread.py +++ b/tilingthread.py @@ -136,10 +136,9 @@ def run(self): self.tiles = None self.processInterrupted.emit() self.rangeChanged.emit(self.tr('Rendering: %v from %m (%p%)'), len(self.tiles)) - QgsMessageLog.logMessage(str(len(self.tiles))) for t in self.tiles: self.render(t) - self.updateProgress.emit() + self.updateProgress.emit() self.mutex.lock() s = self.stopMe self.mutex.unlock()