class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.snapping = True icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.defaultextent = None self.current_form = None self.last_form = None self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge( QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.snappingutils = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snappingutils) threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) smallmode = roam.config.settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.gpsMarker = GPSMarker(self.canvas) self.gpsMarker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(88, 64, 173, 50)) self.currentfeatureband.setOutlineColour(QColor(88, 64, 173)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.refresh_map.connect(self.refresh_map) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.gpslabelposition = QLabel("") self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addWidget(self.gpslabelposition) self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.update_status_label) self.canvas.scaleChanged.connect(self.update_status_label) self.connectButtons() scalebar_enabled = roam.config.settings.get('scale_bar', False) self.scalebar_enabled = False if scalebar_enabled: roam.utils.warning( "Unsupported feature: Scale bar support not ported to QGIS 3 API yet." ) RoamEvents.raisemessage( "Unsupported feature", "Scale bar support not ported to QGIS 3 API yet", level=RoamEvents.CRITICAL) self.scalebar_enabled = False # self.scalebar = ScaleBarItem(self.canvas) # self.canvas.scene().addItem(self.scalebar) def clear_plugins(self) -> None: """ Clear all the plugin added toolbars from the map interface. """ toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if toolbar.property("plugin_toolbar"): toolbar.unload() self.removeToolBar(toolbar) toolbar.deleteLater() def add_plugins(self, pluginnames) -> None: """ Add the given plugins to to the mapping interface. Adds the toolbars the plugin exposes as new toolbars for the user. :param pluginnames: The names of the plugins to load. Must already be loaded by the plugin loader """ for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'toolbars'): roam.utils.warning( "No toolbars() function found in {}".format(name)) continue toolbars = plugin_mod.toolbars() self.load_plugin_toolbars(toolbars) def load_plugin_toolbars(self, toolbars): """ Load the plugin toolbars into the mapping interface. :param toolbars: The list of toolbars class objects to load. :return: """ for ToolBarClass in toolbars: toolbar = ToolBarClass(plugins.api, self) self.addToolBar(Qt.BottomToolBarArea, toolbar) toolbar.setProperty("plugin_toolbar", True) def snapping_changed(self, snapping): """ Called when the snapping settings have changed. Updates the label in the status bar. :param snapping: """ self.snapping = snapping if snapping: self.snappingbutton.setText("Snapping: On") else: self.snappingbutton.setText("Snapping: Off") def toggle_snapping(self): """ Toggle snapping on or off. """ self.snapping = not self.snapping try: self.canvas.mapTool().toggle_snapping() except AttributeError: pass RoamEvents.snappingChanged.emit(self.snapping) def selectscale(self): """ Show the select scale widget. :return: """ self.scalelist.show() def update_scale_from_item(self, index): """ Update the canvas scale from the selected scale item. :param index: The index of the selected item. """ scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole)) self.canvas.zoomScale(1.0 / scale) def update_gps_fixed_label(self, fixed, gpsinfo): if not fixed: self.gpslabel.setText("GPS: Acquiring fix") self.gpslabelposition.setText("") quality_mappings = { 0: "invalid", 1: "GPS", 2: "DGPS", 3: "PPS", 4: "Real Time Kinematic", 5: "Float RTK", 6: "Estimated", 7: "Manual input mode", 8: "Simulation mode" } def update_gps_label(self, position, gpsinfo): """ Update the GPS label in the status bar with the GPS status. :param position: The current GPS position. :param gpsinfo: The current extra GPS information. """ if not self.gps.connected: return fixtype = self.quality_mappings.get(gpsinfo.quality, "") self.gpslabel.setText( "DOP P:<b>{0:.2f}</b> H:<b>{1:.2f}</b> V:<b>{2:.2f}</b> " "Fix: <b>{3}</b> " "Sats: <b>{4}</b> ".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop, fixtype, gpsinfo.satellitesUsed)) places = roam.config.settings.get("gpsplaces", 8) self.gpslabelposition.setText("X: <b>{x:.{places}f}</b> " "Y: <b>{y:.{places}f}</b> " "Z: <b>{z}m</b> ".format( x=position.x(), y=position.y(), z=gpsinfo.elevation, places=places)) def gps_disconnected(self): self.gpslabel.setText("GPS: Not Active") self.gpslabelposition.setText("") self.gpsMarker.hide() def zoom_to_feature(self, feature): """ Zoom to the given feature in the map. :param feature: :return: """ box = feature.geometry().boundingBox() xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum( ), box.yMaximum() xmin -= 5 xmax += 5 ymin -= 5 ymax += 5 box = QgsRectangle(xmin, ymin, xmax, ymax) self.canvas.setExtent(box) self.canvas.refresh() def update_status_label(self, *args) -> None: """ Update the status bar labels when the information has changed. """ extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) scale = 1.0 / self.canvas.scale() scale = self.scalewidget.toString(scale) self.scalebutton.setText(scale) def refresh_map(self) -> None: """ Refresh the map """ self.canvas.refresh() def updatescale(self) -> None: """ Update the scale of the map with the current scale from the scale widget :return: """ self.canvas.zoomScale(1.0 / self.scalewidget.scale()) @property def crs(self) -> QgsCoordinateReferenceSystem: """ Get the CRS used that is being used in the canvas :return: The QgsCoordinateReferenceSystem that is used by the canvas """ return self.canvas.mapSettings().destinationCrs() def feature_form_loaded(self, form, feature, *args): """ Called when the feature form is loaded. :param form: The Form object. Holds a reference to the forms layer. :param feature: The current capture feature """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): """ Highlight the selection on the canvas. This updates all selected objects based on the result set. :param results: A dict-of-list of layer-features. """ self.clear_selection() for layer, features in results.items(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): """ Update the current active selected feature. :param layer: The layer of the active feature. :param feature: The active feature. :param features: The other features in the set to show as non active selection. :return: """ self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): """ Clear the selection from the canvas. Resets all selection rubber bands. :return: """ # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.values(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): """ Push a feature on the edit stack so the feature can have the geometry edited. :note: This is a big hack and I don't like it! :param form: The form for the current feature :param feature: The active feature. """ def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.currentLayer().startEditing() self.canvas.mapTool().setEditMode(True, feature.geometry(), feature) break self.editfeaturestack.append((form, feature)) self.save_current_form() self.load_form(form) trigger_default_action() def save_current_form(self): self.last_form = self.current_form def restore_last_form(self): self.load_form(self.last_form) def clear_temp_objects(self): """ Clear all temp objects from the canvas. :return: """ def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() if hasattr(tool, "clearBand"): tool.clearBand() self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): """ Called when the settings have been updated in the Roam config. :param settings: A dict of the settings. """ self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging smallmode = settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) def set_gps(self, gps, logging): """ Set the GPS for the map widget. Connects GPS signals """ self.gps = gps self.gpslogging = logging self.gps.gpsfixed.connect(self.update_gps_fixed_label) self.gps.gpsposition.connect(self.update_gps_label) self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) self.gpsMarker.setgps(self.gps) self.actionGPS.setgps(gps) def gps_update_canvas(self, position, gpsinfo): """ Updates the map canvas based on the GPS position. By default if the GPS is outside the canvas extent the canvas will move to center on the GPS. Can be turned off in settings. :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastgpsposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.gpsMarker.show() self.gpsMarker.setCenter(position, gpsinfo) def gps_first_fix(self, postion, gpsinfo): """ Called the first time the GPS gets a fix. If set this will zoom to the GPS after the first fix :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): """ Zoom to ta given position on the map.. """ rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def select_data_entry(self): """ Open the form selection widget to allow the user to pick the active capture form. """ def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format( form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): """ Called when the project is loaded. Main entry point for a loade project. :param project: The Roam project that has been loaded. """ self.snappingutils.setConfig(QgsProject.instance().snappingConfig()) self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = roam.api.utils.layers() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.refresh() projectscales, _ = QgsProject.instance().readBoolEntry( "Scales", "/useProjectScales") if projectscales: projectscales, _ = QgsProject.instance().readListEntry( "Scales", "/ScalesList") self.scalewidget.updateScales(projectscales) else: scales = [ "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000", "1:500", "1:250", "1:200", "1:100" ] scales = roam.config.settings.get('scales', scales) self.scalewidget.updateScales(scales) if self.scalebar_enabled: self.scalebar.update() red = QgsProject.instance().readNumEntry("Gui", "/CanvasColorRedPart", 255)[0] green = QgsProject.instance().readNumEntry("Gui", "/CanvasColorGreenPart", 255)[0] blue = QgsProject.instance().readNumEntry("Gui", "/CanvasColorBluePart", 255)[0] myColor = QColor(red, green, blue) self.canvas.setCanvasColor(myColor) self.actionPan.toggle() self.clear_plugins() self.add_plugins(project.enabled_plugins) def setMapTool(self, tool, *args): """ Set the active map tool in the canvas. :param tool: The QgsMapTool to set. """ if tool == self.canvas.mapTool(): return if hasattr(tool, "setSnapping"): tool.setSnapping(self.snapping) self.canvas.setMapTool(tool) def connectButtons(self): """ Connect the default buttons in the interface. Zoom, pan, etc """ def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = QgsMapToolPan(self.canvas) self.infoTool = InfoTool(self.canvas) self.infoTool.setAction(self.actionInfo) self.zoomInTool.setAction(self.actionZoom_In) self.zoomOutTool.setAction(self.actionZoom_Out) self.panTool.setAction(self.actionPan) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggle_raster_layers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ if self.defaultextent: self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): """ Check if the given form is valid for capture. :param form: The form to check. :return: True if valid form for capture """ return form.has_geometry and self.project.layer_can_capture( form.QGISLayer) def first_capture_form(self): """ Return the first valid form for capture. """ for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): """ Load the given form so it's the active one for capture :param form: The form to load """ self.clear_capture_tools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) self.current_form = form def create_capture_buttons(self, form): """ Create the capture buttons in the toolbar for the given form. :param form: The active form. """ tool = form.getMaptool()(self.canvas, form.settings) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(self.show_invalid_geometry_message) def show_invalid_geometry_message(self, message) -> None: """ Shows the message to the user if the there is a invalid geometry capture. :param message: The message to show the user. """ RoamEvents.raisemessage("Invalid geometry capture", message, level=RoamEvents.CRITICAL) if self.canvas.currentLayer() is not None: self.canvas.currentLayer().rollBack() RoamEvents.editgeometry_invalid.emit() def add_new_feature(self, form, geometry: QgsGeometry): """ Add a new new feature to the given layer :param form: The form to use for the new feature. :param geometry: The new geometry to create the feature for. """ # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if geometry.isMultipart(): geometry.convertToMultiType() # Transform the new geometry back into the map layers geometry if it's needed transform = self.canvas.mapSettings().layerTransform(layer) if transform.isValid(): geometry.transform(transform, QgsCoordinateTransform.ReverseTransform) try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None, None) self.restore_last_form() def clear_capture_tools(self): """ Clear the capture tools from the toolbar. :return: True if the capture button was active at the time of clearing. """ captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggle_raster_layers(self) -> None: """ Toggle all raster layers on or off. """ # Freeze the canvas to save on UI refresh dlg = PickActionDialog(msg="Raster visibility") actions = [ (":/icons/raster_0", "Off", partial(self._set_basemaps_opacity, 0), "photo_off"), (":/icons/raster_25", "25%", partial(self._set_basemaps_opacity, .25), "photo_25"), (":/icons/raster_50", "50%", partial(self._set_basemaps_opacity, .50), "photo_50"), (":/icons/raster_75", "75%", partial(self._set_basemaps_opacity, .75), "photo_75"), (":/icons/raster_100", "100%", partial(self._set_basemaps_opacity, 1), "photo_100"), ] # ":/icons/raster_100"), "100%", self, triggered=partial(self._set_raster_layer_value, 1), # objectName="photo_100") dialog_actions = [] for action in actions: icon = QIcon(action[0]) qaction = QAction(icon, action[1], self, triggered=action[2], objectName=action[3]) dialog_actions.append(qaction) dlg.addactions(dialog_actions) dlg.exec_() def _set_basemaps_opacity(self, value=0) -> None: """ Set the opacity for all basemap raster layers. :param value: The opacity value betwen 0 and 1 """ tree = QgsProject.instance().layerTreeRoot() for node in tree.findLayers(): layer = node.layer() if node.layer().type() == QgsMapLayer.RasterLayer: if value > 0: node.setItemVisibilityChecked(Qt.Checked) renderer = layer.renderer() renderer.setOpacity(value) if value == 0: node.setItemVisibilityChecked(Qt.Unchecked) self.canvas.refresh() def cleanup(self): """ Clean up when the project has changed. :return: """ # TODO Review cleanup # self.bridge.clear() self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clear_capture_tools() for action in self.layerbuttons: self.editgroup.removeAction(action)
def setupUi(self, _): """ Add to the UI the following elements: 1) the selection editor 2) the tabs with the dynamic forms 3) the map 4) the toolbar with the map tools """ super(MainWindow, self).setupUi(self) self.selection_editor = SelectionDialog(self) self.actionUndo.setDisabled(True) # setup dynamic forms self.tabs = ( Tab("declustering", self.declusteringFormLayout, DECLUSTERER_METHODS, [self.declusterButton, self.declusteringPurgeButton]), Tab("completeness", self.completenessFormLayout, COMPLETENESS_METHODS, [self.completenessButton, self.completenessPurgeButton]), Tab("recurrence_model", self.recurrenceModelFormLayout, OCCURRENCE_METHODS, [self.recurrenceModelButton]), Tab("max_magnitude", self.maxMagnitudeFormLayout, MAX_MAGNITUDE_METHODS, [self.maxMagnitudeButton]), Tab("smoothed_seismicity", self.smoothedSeismicityFormLayout, SMOOTHED_SEISMICITY_METHODS, [self.smoothedSeismicityButton]), Tab("histogram", self.catalogueAnalysisFormLayout, CATALOGUE_ANALYSIS_METHODS, [self.catalogueAnalysisButton])) for tab in self.tabs: tab.setup_form(self.on_algorithm_select) self.stackedFormWidget.currentChanged.connect(self.change_tab) # setup Map self.mapWidget.setCanvasColor(Qt.white) self.mapWidget.enableAntiAliasing(True) self.mapWidget.show() #self.message_bar = QgsMessageBar(self.centralWidget) #self.outputVerticalLayout.insertWidget(0, self.message_bar) # setup toolbar group = QtGui.QActionGroup(self) group.addAction(self.actionZoomIn) group.addAction(self.actionZoomOut) group.addAction(self.actionPan) group.addAction(self.actionIdentify) # create the map tools toolPan = QgsMapToolPan(self.mapWidget) toolPan.setAction(self.actionPan) # false = in toolZoomIn = QgsMapToolZoom(self.mapWidget, False) toolZoomIn.setAction(self.actionZoomIn) # true = out toolZoomOut = QgsMapToolZoom(self.mapWidget, True) toolZoomOut.setAction(self.actionZoomOut) toolIdentify = QgsMapToolEmitPoint(self.mapWidget) toolIdentify.setAction(self.actionIdentify) toolIdentify.canvasClicked.connect( lambda point, button: self.catalogue_map.show_tip(point)) self.actionZoomIn.triggered.connect( lambda: self.mapWidget.setMapTool(toolZoomIn)) self.actionZoomOut.triggered.connect( lambda: self.mapWidget.setMapTool(toolZoomOut)) self.actionPan.triggered.connect( lambda: self.mapWidget.setMapTool(toolPan)) self.actionIdentify.triggered.connect( lambda: self.mapWidget.setMapTool(toolIdentify)) self.mapWidget.setMapTool(toolPan) self.stackedFormWidget.setCurrentIndex(0)
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.snapping = True icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.current_form = None self.last_form = None self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge( QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) QgsProject.instance().writeProject.connect(self.bridge.writeProject) QgsProject.instance().readProject.connect(self.bridge.readProject) # self.canvas.setInteractive(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.snappingutils = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snappingutils) QgsProject.instance().readProject.connect( self.snappingutils.readConfigFromProject) if hasattr(self.canvas, 'setParallelRenderingEnabled'): threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) smallmode = roam.config.settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) self.scalebar_enabled = roam.config.settings.get('scale_bar', False) if self.scalebar_enabled: self.scalebar = ScaleBarItem(self.canvas) self.canvas.scene().addItem(self.scalebar) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 50)) self.currentfeatureband.setOutlineColour(QColor(186, 93, 212)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.gpslabelposition = QLabel("") self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addWidget(self.gpslabelposition) self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.updatestatuslabel) self.canvas.scaleChanged.connect(self.updatestatuslabel) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.connectButtons() def clear_plugins(self): toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if toolbar.property("plugin_toolbar"): toolbar.unload() self.removeToolBar(toolbar) toolbar.deleteLater() def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'toolbars'): roam.utils.warning( "No toolbars() function found in {}".format(name)) continue toolbars = plugin_mod.toolbars() self.load_plugin_toolbars(toolbars) def load_plugin_toolbars(self, toolbars): for ToolBarClass in toolbars: toolbar = ToolBarClass(plugins.api, self) self.addToolBar(Qt.BottomToolBarArea, toolbar) toolbar.setProperty("plugin_toolbar", True) def snapping_changed(self, snapping): """ Called when the snapping settings have changed. Updates the label in the status bar. :param snapping: """ if snapping: self.snappingbutton.setText("Snapping: On") else: self.snappingbutton.setText("Snapping: Off") def toggle_snapping(self): """ Toggle snapping on or off. """ self.snapping = not self.snapping try: self.canvas.mapTool().toggle_snapping() except AttributeError: pass RoamEvents.snappingChanged.emit(self.snapping) def selectscale(self): """ Show the select scale widget. :return: """ self.scalelist.show() def update_scale_from_item(self, index): """ Update the canvas scale from the selected scale item. :param index: The index of the selected item. """ scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole)) self.canvas.zoomScale(1.0 / scale) def update_gps_label(self, position, gpsinfo): """ Update the GPS label in the status bar with the GPS status. :param position: The current GPS position. :param gpsinfo: The current extra GPS information. """ self.gpslabel.setText( "GPS: PDOP <b>{0:.2f}</b> HDOP <b>{1:.2f}</b> VDOP <b>{2:.2f}</b>" .format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) places = roam.config.settings.get("gpsplaces", 8) self.gpslabelposition.setText( "X <b>{x:.{places}f}</b> Y <b>{y:.{places}f}</b>".format( x=position.x(), y=position.y(), places=places)) def gps_disconnected(self): """ Called when the GPS is disconnected. Updates the label in the status bar with the message. :return: """ self.gpslabel.setText("GPS Not Active") self.gpslabelposition.setText("") def zoom_to_feature(self, feature): box = feature.geometry().boundingBox() xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum( ), box.yMaximum() xmin -= 5 xmax += 5 ymin -= 5 ymax += 5 box = QgsRectangle(xmin, ymin, xmax, ymax) self.canvas.setExtent(box) self.canvas.refresh() def updatestatuslabel(self, *args): """ Update the status bar labels when the information has changed. """ extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) scale = 1.0 / self.canvas.scale() scale = self.scalewidget.toString(scale) self.scalebutton.setText(scale) def refresh_map(self): """ Refresh the map """ self.canvas.refresh() def updatescale(self): """ Update the scale of the map with the current scale from the scale widget :return: """ self.canvas.zoomScale(1.0 / self.scalewidget.scale()) def init_qgisproject(self, doc): """ Called when the project file is read for the firs time. :param doc: The XML doc. :return: The current canvas CRS :note: This method is old and needs to be refactored into something else. """ return self.canvas.mapSettings().destinationCrs() def showEvent(self, *args, **kwargs): """ Handle the show event of the of the map widget. We have to do a little hack here to make the QGIS map refresh. """ if QGis.QGIS_VERSION_INT == 20200 and self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, *args): """ Called when the feature form is loaded. :param form: The Form object. Holds a reference to the forms layer. :param feature: The current capture feature """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): """ Highlight the selection on the canvas. This updates all selected objects based on the result set. :param results: A dict-of-list of layer-features. """ self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): """ Update the current active selected feature. :param layer: The layer of the active feature. :param feature: The active feature. :param features: The other features in the set to show as non active selection. :return: """ self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): """ Clear the selection from the canvas. Resets all selection rubbber bands. :return: """ # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): """ Push a feature on the edit stack so the feature can have the geometry edited. :note: This is a big hack and I don't like it! :param form: The form for the current feature :param feature: The active feature. """ def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.mapTool().setEditMode(True, feature.geometry()) break self.editfeaturestack.append((form, feature)) self.save_current_form() self.load_form(form) trigger_default_action() def save_current_form(self): self.last_form = self.current_form def restore_last_form(self): self.load_form(self.last_form) def clear_temp_objects(self): """ Clear all temp objects from the canvas. :return: """ def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): """ Called when the settings have been updated in the Roam config. :param settings: A dict of the settings. """ self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): """ Set the GPS for the map widget. Connects GPS signals """ self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): """ Updates the map canvas based on the GPS position. By default if the GPS is outside the canvas extent the canvas will move to center on the GPS. Can be turned off in settings. :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position, gpsinfo) def gps_first_fix(self, postion, gpsinfo): """ Called the first time the GPS gets a fix. If set this will zoom to the GPS after the first fix :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): """ Zoom to ta given position on the map.. """ rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): """ Called when the GPS is disconnected """ self.marker.hide() def select_data_entry(self): """ Open the form selection widget to allow the user to pick the active capture form. """ def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format( form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): """ Called when the project is loaded. Main entry point for a loade project. :param project: The Roam project that has been loaded. """ self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.refresh() projectscales, _ = QgsProject.instance().readBoolEntry( "Scales", "/useProjectScales") if projectscales: projectscales, _ = QgsProject.instance().readListEntry( "Scales", "/ScalesList") self.scalewidget.updateScales(projectscales) else: scales = [ "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000", "1:500", "1:250", "1:200", "1:100" ] scales = roam.config.settings.get('scales', scales) self.scalewidget.updateScales(scales) if self.scalebar_enabled: self.scalebar.update() self.actionPan.toggle() self.clear_plugins() self.add_plugins(project.enabled_plugins) def setMapTool(self, tool, *args): """ Set the active map tool in the canvas. :param tool: The QgsMapTool to set. """ if tool == self.canvas.mapTool(): return if hasattr(tool, "setSnapping"): tool.setSnapping(self.snapping) self.canvas.setMapTool(tool) def connectButtons(self): """ Connect the default buttons in the interface. Zoom, pan, etc """ def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) self.infoTool.setAction(self.actionInfo) self.zoomInTool.setAction(self.actionZoom_In) self.zoomOutTool.setAction(self.actionZoom_Out) self.panTool.setAction(self.actionPan) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): """ Check if the given form is valid for capture. :param form: The form to check. :return: True if valid form for capture """ return form.has_geometry and self.project.layer_can_capture( form.QGISLayer) def first_capture_form(self): """ Return the first valid form for capture. """ for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): """ Load the given form so it's the active one for capture :param form: The form to load """ self.clearCaptureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) self.current_form = form def create_capture_buttons(self, form): """ Create the capture buttons in the toolbar for the given form. :param form: The active form. """ layer = form.QGISLayer tool = form.getMaptool()(self.canvas, form.settings) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(self.show_invalid_geometry_message) def show_invalid_geometry_message(self, message): RoamEvents.raisemessage("Invalid geometry capture", message, level=RoamEvents.CRITICAL) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [ QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon ]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None) self.restore_last_form() def clearCaptureTools(self): """ Clear the capture tools from the toolbar. :return: True if the capture button was active at the time of clearing. """ captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ # Freeze the canvas to save on UI refresh self.canvas.freeze() tree = QgsProject.instance().layerTreeRoot() for node in tree.findLayers(): if node.layer().type() == QgsMapLayer.RasterLayer: if node.isVisible() == Qt.Checked: state = Qt.Unchecked else: state = Qt.Checked node.setVisible(state) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): """ Clean up when the project has changed. :return: """ self.bridge.clear() self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCaptureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class ViewerWnd(QMainWindow): def __init__(self, app, dictOpts): QMainWindow.__init__(self) self.setWindowTitle("PostGIS Layer Viewer - v.1.6.1") self.setTabPosition(Qt.BottomDockWidgetArea, QTabWidget.North) self.canvas = QgsMapCanvas() self.canvas.setCanvasColor(Qt.white) self.canvas.useImageToRender(True) self.canvas.enableAntiAliasing(True) self.setCentralWidget(self.canvas) actionZoomIn = QAction(QIcon(imgs_dir + "mActionZoomIn.png"), QString("Zoom in"), self) actionZoomOut = QAction(QIcon(imgs_dir + "mActionZoomOut.png"), QString("Zoom out"), self) actionPan = QAction(QIcon(imgs_dir + "mActionPan.png"), QString("Pan"), self) actionZoomFullExtent = QAction( QIcon(imgs_dir + "mActionZoomFullExtent.png"), QString("Zoom full"), self) actionZoomIn.setCheckable(True) actionZoomOut.setCheckable(True) actionPan.setCheckable(True) self.connect(actionZoomIn, SIGNAL("triggered()"), self.zoomIn) self.connect(actionZoomOut, SIGNAL("triggered()"), self.zoomOut) self.connect(actionPan, SIGNAL("triggered()"), self.pan) self.connect(actionZoomFullExtent, SIGNAL("triggered()"), self.zoomFullExtent) self.actionGroup = QActionGroup(self) self.actionGroup.addAction(actionPan) self.actionGroup.addAction(actionZoomIn) self.actionGroup.addAction(actionZoomOut) # Create the toolbar self.toolbar = self.addToolBar("Map tools") self.toolbar.addAction(actionPan) self.toolbar.addAction(actionZoomIn) self.toolbar.addAction(actionZoomOut) self.toolbar.addAction(actionZoomFullExtent) # Create the map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in self.toolZoomIn.setAction(actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out self.toolZoomOut.setAction(actionZoomOut) # Create the statusbar self.statusbar = QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.lblXY = QLabel() self.lblXY.setFrameStyle(QFrame.Box) self.lblXY.setMinimumWidth(170) self.lblXY.setAlignment(Qt.AlignCenter) self.statusbar.setSizeGripEnabled(False) self.statusbar.addPermanentWidget(self.lblXY, 0) self.lblScale = QLabel() self.lblScale.setFrameStyle(QFrame.StyledPanel) self.lblScale.setMinimumWidth(140) self.statusbar.addPermanentWidget(self.lblScale, 0) self.createLegendWidget() # Create the legend widget self.connect(app, SIGNAL("loadPgLayer"), self.loadLayer) self.connect(self.canvas, SIGNAL("scaleChanged(double)"), self.changeScale) self.connect(self.canvas, SIGNAL("xyCoordinates(const QgsPoint&)"), self.updateXY) self.pan() # Default self.plugins = Plugins(self, self.canvas, dictOpts['-h'], dictOpts['-p'], dictOpts['-d'], dictOpts['-U'], dictOpts['-W']) self.createAboutWidget() self.layerSRID = '-1' self.loadLayer(dictOpts) def zoomIn(self): self.canvas.setMapTool(self.toolZoomIn) def zoomOut(self): self.canvas.setMapTool(self.toolZoomOut) def pan(self): self.canvas.setMapTool(self.toolPan) def zoomFullExtent(self): self.canvas.zoomToFullExtent() def about(self): pass def createLegendWidget(self): """ Create the map legend widget and associate it to the canvas """ self.legend = Legend(self) self.legend.setCanvas(self.canvas) self.legend.setObjectName("theMapLegend") self.LegendDock = QDockWidget("Layers", self) self.LegendDock.setObjectName("legend") self.LegendDock.setTitleBarWidget(QWidget()) self.LegendDock.setWidget(self.legend) self.LegendDock.setContentsMargins(0, 0, 0, 0) self.addDockWidget(Qt.BottomDockWidgetArea, self.LegendDock) def createAboutWidget(self): self.AboutDock = QDockWidget("About", self) self.AboutDock.setObjectName("about") self.AboutDock.setTitleBarWidget(QWidget()) self.AboutDock.setContentsMargins(0, 0, 0, 0) self.tabifyDockWidget(self.LegendDock, self.AboutDock) self.LegendDock.raise_() # legendDock at the top from PyQt4.QtCore import QRect from PyQt4.QtGui import QSizePolicy, QGridLayout, QFont font = QFont() font.setFamily("Sans Serif") font.setPointSize(8.7) self.AboutWidget = QWidget() self.AboutWidget.setFont(font) self.AboutWidget.setObjectName("AboutWidget") self.AboutDock.setWidget(self.AboutWidget) self.labelAbout = QLabel(self.AboutWidget) self.labelAbout.setAlignment(Qt.AlignCenter) self.labelAbout.setWordWrap(True) self.gridLayout = QGridLayout(self.AboutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.gridLayout.addWidget(self.labelAbout, 0, 1, 1, 1) self.labelAbout.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard | Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse) self.labelAbout.setOpenExternalLinks(True) self.labelAbout.setText("<html><head/><body><a href=\"http://geotux.tuxfamily.org/index.php/en/geo-blogs/item/293-consola-sql-para-plugin-pgadmin-postgis-viewer\">PostGIS Layer Viewer</a> v.1.6.1 (2015.02.24)<br \><br \>" \ "Copyright (c) 2010 Ivan Mincik,<br \>[email protected]<br \>" \ u"Copyright (c) 2011-2015 Germán Carrillo,<br \>[email protected]<br \><br \>" \ "<i>Licensed under the terms of GNU GPL v.2.0</i><br \><br \>" \ "Based on PyQGIS. Plugin Fast SQL Layer by Pablo T. Carreira.</body></html>" ) def loadLayer(self, dictOpts): print 'I: Loading the layer...' self.layerSRID = dictOpts[ 'srid'] # To access the SRID when querying layer properties if not self.isActiveWindow(): self.activateWindow() self.raise_() if dictOpts['type'] == 'vector': # QGIS connection uri = QgsDataSourceURI() uri.setConnection(dictOpts['-h'], dictOpts['-p'], dictOpts['-d'], dictOpts['-U'], dictOpts['-W']) uri.setDataSource(dictOpts['-s'], dictOpts['-t'], dictOpts['-g']) layer = QgsVectorLayer(uri.uri(), dictOpts['-s'] + '.' + dictOpts['-t'], "postgres") elif dictOpts['type'] == 'raster': connString = "PG: dbname=%s host=%s user=%s password=%s port=%s mode=2 " \ "schema=%s column=%s table=%s" % ( dictOpts['-d'], dictOpts['-h'], dictOpts['-U'], dictOpts['-W'], dictOpts['-p'], dictOpts['-s'], dictOpts['col'], dictOpts['-t'] ) layer = QgsRasterLayer(connString, dictOpts['-s'] + '.' + dictOpts['-t']) if layer.isValid(): layer.setContrastEnhancement( QgsContrastEnhancement.StretchToMinimumMaximum) self.addLayer(layer, self.layerSRID) def addLayer(self, layer, srid='-1'): if layer.isValid(): # Only in case that srid != -1, read the layer SRS properties, otherwise don't since it will return 4326 if srid != '-1': self.layerSRID = layer.crs().description() + ' (' + str( layer.crs().postgisSrid()) + ')' else: self.layerSRID = 'Unknown SRS (-1)' if self.canvas.layerCount() == 0: self.canvas.setExtent(layer.extent()) if srid != '-1': print 'I: Map SRS (EPSG): %s' % self.layerSRID self.canvas.setMapUnits(layer.crs().mapUnits()) else: print 'I: Unknown Reference System' self.canvas.setMapUnits(0) # 0: QGis.Meters return QgsMapLayerRegistry.instance().addMapLayer(layer) return False def activeLayer(self): """ Returns the active layer in the layer list widget """ return self.legend.activeLayer() def getLayerProperties(self, l): """ Create a layer-properties string (l:layer)""" print 'I: Generating layer properties...' if l.type() == 0: # Vector wkbType = [ "WKBUnknown", "WKBPoint", "WKBLineString", "WKBPolygon", "WKBMultiPoint", "WKBMultiLineString", "WKBMultiPolygon", "WKBNoGeometry", "WKBPoint25D", "WKBLineString25D", "WKBPolygon25D", "WKBMultiPoint25D", "WKBMultiLineString25D", "WKBMultiPolygon25D" ] properties = "Source: %s\n" \ "Geometry type: %s\n" \ "Number of features: %s\n" \ "Number of fields: %s\n" \ "SRS (EPSG): %s\n" \ "Extent: %s " \ % ( l.source(), wkbType[l.wkbType()], l.featureCount(), l.dataProvider().fields().count(), self.layerSRID, l.extent().toString() ) elif l.type() == 1: # Raster rType = [ "GrayOrUndefined (single band)", "Palette (single band)", "Multiband", "ColorLayer" ] properties = "Source: %s\n" \ "Raster type: %s\n" \ "Width-Height (pixels): %sx%s\n" \ "Bands: %s\n" \ "SRS (EPSG): %s\n" \ "Extent: %s" \ % ( l.source(), rType[l.rasterType()], l.width(), l.height(), l.bandCount(), self.layerSRID, l.extent().toString() ) self.layerSRID = '-1' # Initialize the srid return properties def changeScale(self, scale): self.lblScale.setText("Scale 1:" + formatNumber(scale)) def updateXY(self, p): if self.canvas.mapUnits() == 2: # Degrees self.lblXY.setText( formatToDegrees( p.x() ) + " | " \ + formatToDegrees( p.y() ) ) else: # Unidad lineal self.lblXY.setText( formatNumber( p.x() ) + " | " \ + formatNumber( p.y() ) + "" )
class FeatureOfInterestDefinerConfigurationWidget(StandardModuleConfigurationWidget): """A widget to configure the FeatureOfInterestDefiner Module.""" def __init__(self, module, controller, parent=None): StandardModuleConfigurationWidget.__init__(self, module, controller, parent) self.foi_type = module.name #self.module = module self.setObjectName("FeatureOfInterestDefinerWidget") self.parent_widget = module # FIXME these modules don't exist self.path_png_icon = vistrails.packages.eo4vistrails.geoinf.visual.__path__[0] self.path_bkgimg = vistrails.packages.eo4vistrails.geoinf.visual.__path__[0] self.create_config_window() def create_config_window(self): """TO DO - add docstring""" self.setWindowTitle(self.foi_type) self.setMinimumSize(800, 850) self.center() self.mainLayout = QtGui.QVBoxLayout() self.setLayout(self.mainLayout) #set up Group Box for organising CRS of FOI self.crsGroupBox = QtGui.QGroupBox("Define Projection or Coordinate Reference System") self.crsLayout = QtGui.QHBoxLayout() self.crsProj4Label = QtGui.QLabel('SRS Proj4: ') self.crsTextAsProj4 = QtGui.QLineEdit('4326') self.crsChooseButton = QtGui.QPushButton('&Choose SRS') self.crsChooseButton.setAutoDefault(False) self.crsChooseButton.setToolTip('Choose a Spatial Reference System or Projection') self.crsLayout.addWidget(self.crsProj4Label) self.crsLayout.addWidget(self.crsTextAsProj4) self.crsLayout.addWidget(self.crsChooseButton) self.crsGroupBox.setLayout(self.crsLayout) #set up Group Box for getting coords of Bounding Box self.bbGroupBox = QtGui.QGroupBox("Define Area of Interest via a Bounding Box in units of SRS") self.bbLayout = QtGui.QHBoxLayout() self.bbMinXLabel = QtGui.QLabel('MinX/Left: ') self.bbMinYLabel = QtGui.QLabel('MinY/Bottom: ') self.bbMaxXLabel = QtGui.QLabel('MaxX/Right: ') self.bbMaxYLabel = QtGui.QLabel('MaxY/Top: ') self.bbMinXText = QtGui.QLineEdit('15') self.bbMinYText = QtGui.QLineEdit('-35') self.bbMaxXText = QtGui.QLineEdit('35') self.bbMaxYText = QtGui.QLineEdit('-20') self.bbToMapButton = QtGui.QPushButton('&To Map') self.bbToMapButton.setAutoDefault(False) self.bbToMapButton.setToolTip('Show Bounding Box on Map') self.bbLayout.addWidget(self.bbMinXLabel) self.bbLayout.addWidget(self.bbMinXText) self.bbLayout.addWidget(self.bbMinYLabel) self.bbLayout.addWidget(self.bbMinYText) self.bbLayout.addWidget(self.bbMaxXLabel) self.bbLayout.addWidget(self.bbMaxXText) self.bbLayout.addWidget(self.bbMaxYLabel) self.bbLayout.addWidget(self.bbMaxYText) self.bbLayout.addWidget(self.bbToMapButton) self.bbGroupBox.setLayout(self.bbLayout) #set up Group Box for getting text representation of a geometry self.asTxtGroupBox = QtGui.QGroupBox("Define Area of Interest via a WKT string in units of SRS") self.asTxtLayout = QtGui.QVBoxLayout() self.asTxtLabel = QtGui.QLabel('WKT String: ') self.asTxtText = QtGui.QTextEdit('') self.asTxtToMapButton = QtGui.QPushButton('&To Map') self.asTxtToMapButton.setAutoDefault(False) self.asTxtToMapButton.setToolTip('Show Bounding Box on Map') self.asTxtLayout.addWidget(self.asTxtLabel) self.asTxtLayout.addWidget(self.asTxtText) self.asTxtLayout.addWidget(self.asTxtToMapButton) self.asTxtGroupBox.setLayout(self.asTxtLayout) #set up Group Box for Map self.MapGroupBox = QtGui.QGroupBox("Map Viewer") self.MapLayout = QtGui.QHBoxLayout() #sz = QtCore.QSize(200, 300) #self.MapLayout.setGeometry(QtCore.QRect(300, 700, 780, 680)) self.MapGroupBox.setLayout(self.MapLayout) ## create canvas self.canvas = QgsMapCanvas() self.canvas.setCanvasColor(QtGui.QColor(200, 200, 255)) #self.mainLayout.addWidget(self.canvas) # icons actionAddLayer = QtGui.QAction(QtGui.QIcon(self.path_png_icon + \ "/mActionAddLayer.png"), "Add Layer", self) actionZoomIn = QtGui.QAction(QtGui.QIcon(self.path_png_icon + \ "/mActionZoomIn.png"), "Zoom In", self) actionZoomOut = QtGui.QAction(QtGui.QIcon(self.path_png_icon + \ "/mActionZoomOut.png"), "Zoom Out", self) actionPan = QtGui.QAction(QtGui.QIcon(self.path_png_icon + \ "/mActionPan.png"), "Pan", self) actionIdentify = QtGui.QAction(QtGui.QIcon(self.path_png_icon + \ "/mActionIdentify.png"), "Feature Information", self) # create toolbar self.toolbar = QtGui.QToolBar() # "Canvas actions" self.toolbar.addAction(actionAddLayer) self.toolbar.addAction(actionZoomIn) self.toolbar.addAction(actionZoomOut) self.toolbar.addAction(actionPan) self.toolbar.addAction(actionIdentify) # create layer explorer pane self.explorer = QtGui.QDockWidget("Layers") self.explorer.resize(60, 100) #~self.explorerListWidget = QtGui.QListWidget() #~self.explorerListWidget.setObjectName("listWidget") #~self.explorer.setWidget(self.explorerListWidget) # create map tools self.toolPan = QgsMapToolPan(self.canvas,) self.toolPan.setAction(actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false == in self.toolZoomIn.setAction(actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true == out self.toolZoomOut.setAction(actionZoomOut) self.toolAOI = QgsMapTool(self.canvas) self.toolIdentify = GetFeatureInfoTool(self.canvas, self.gotFeatureForIdentification) self.toolIdentify.setAction(actionIdentify) # layerList explorer self.GroupBoxLyrExplorer = QtGui.QGroupBox("") self.vboxLyrExplorer = QtGui.QVBoxLayout() self.GroupBoxLyrExplorer.setLayout(self.vboxLyrExplorer) self.MapLayout.addWidget(self.GroupBoxLyrExplorer) self.label = QtGui.QLabel("") self.vboxLyrExplorer.addWidget(self.label) self.vboxLyrExplorer.addWidget(self.explorer) # toolbar and canvas layout self.GroupBoxToolBarMapCanvas = QtGui.QGroupBox("") self.vboxToolBarMapCanvas = QtGui.QVBoxLayout() self.vboxToolBarMapCanvas.setGeometry(QtCore.QRect(300, 700, 780, 680)) self.GroupBoxToolBarMapCanvas.setLayout(self.vboxToolBarMapCanvas) self.MapLayout.addWidget(self.GroupBoxToolBarMapCanvas) self.vboxToolBarMapCanvas.addWidget(self.toolbar) self.vboxToolBarMapCanvas.addWidget(self.canvas) #global list to hold inputlayers list -> accessible for toggleLayer self.mylist = [] #finalise/cancel buttons self.finishGroupBox = QtGui.QGroupBox("Finish") self.buttonLayout = QtGui.QHBoxLayout() self.finishGroupBox.setLayout(self.buttonLayout) self.buttonLayout.setGeometry(QtCore.QRect(300, 500, 780, 680)) self.buttonLayout.setMargin(5) self.cancelButton = QtGui.QPushButton('&Cancel', self) self.cancelButton.setAutoDefault(False) self.cancelButton.setShortcut('Esc') self.buttonLayout.addStretch(1) # force buttons to the right self.buttonLayout.addWidget(self.cancelButton) self.okButton = QtGui.QPushButton('&OK', self) self.okButton.setAutoDefault(False) self.buttonLayout.addWidget(self.okButton) self.connect(self.okButton, QtCore.SIGNAL('clicked(bool)'), self.okTriggered) self.connect(self.cancelButton, QtCore.SIGNAL('clicked(bool)'), self.close) self.mainLayout.addWidget(self.crsGroupBox) self.mainLayout.addWidget(self.bbGroupBox) self.mainLayout.addWidget(self.asTxtGroupBox) self.mainLayout.addWidget(self.MapGroupBox) self.mainLayout.addWidget(self.finishGroupBox) # set signals self.connect(self.crsChooseButton, QtCore.SIGNAL('clicked(bool)'), self.getSRS) self.connect(self.bbToMapButton, QtCore.SIGNAL('clicked(bool)'), self.bbToMapBB) self.connect(self.asTxtToMapButton, QtCore.SIGNAL('clicked(bool)'), self.bbToMapTxt) self.connect(actionAddLayer, QtCore.SIGNAL("activated()"), self.addLayer) self.connect(actionZoomIn, QtCore.SIGNAL("activated()"), self.zoomIn) self.connect(actionZoomOut, QtCore.SIGNAL("activated()"), self.zoomOut) self.connect(actionPan, QtCore.SIGNAL("activated()"), self.pan) self.connect(actionIdentify, QtCore.SIGNAL("triggered()"), self.identifyFeature) #load a backdrop layer self.mapCanvasLayers = [] fname = self.path_bkgimg + '/bluemarblemerged.img' fileInfo = QtCore.QFileInfo(fname) baseName = fileInfo.baseName() self.bmLayer = QgsRasterLayer(fname, baseName) QgsMapLayerRegistry.instance().addMapLayer(self.bmLayer) self.cl = QgsMapCanvasLayer(self.bmLayer) self.mapCanvasLayers.append(self.cl) # Set extent to the extent of our layer self.canvas.setExtent(self.bmLayer.extent()) self.canvas.enableAntiAliasing(True) self.canvas.freeze(False) self.canvas.setLayerSet(self.mapCanvasLayers) self.canvas.refresh() #now, add a container layer for our text based/ digitised or selected geoms self.addMemoryLayer() #self.update() def center(self): """TO DO - add docstring""" screen = QtGui.QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) def getSRS(self): # retruns the description and proj4 string of the chosen SRS, from the SRSDialog srsdlg = SRSChooserDialog("Choose SRS") if srsdlg.exec_(): self.crsTextAsProj4.setText(srsdlg.getProjection()) def bbToMapBB(self): self.bbToMap(fullWkt=False) def bbToMapTxt(self): self.bbToMap(fullWkt=True) def bbToMap(self, fullWkt=False): '''takes bounding box coords and puts them on the map''' #if self.foi_type == "AreaOfInterestDefiner": if not fullWkt: ix = self.bbMinXText.text() iy = self.bbMinYText.text() ax = self.bbMaxXText.text() ay = self.bbMaxYText.text() wkt = "POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))" % \ (ix, iy, ix, ay, ax, ay, ax, iy, ix, iy) else: wkt = self.asTxtText.toPlainText() try: errnum = 0 geom = QgsGeometry().fromWkt(wkt) print "gotGeom" if self.foi_type == "AreaOfInterestDefiner" and geom.type() != 2: errnum = 1 elif self.foi_type == "LineOfInterestDefiner" and geom.type() != 1: errnum = 1 elif self.foi_type == "PointOfInterestDefiner" and geom.type() != 0: errnum = 1 else: print "attempting to add geometry to mem layer" self.addGeomToMemoryLayer(geom) if errnum == 1: raise ModuleError(self, "Incorrect Geometry Type chosen") except: raise ModuleError(self, "Could not generate Geometry from text provided") #else: #print "Cannot create a Bounding box feature on a line or point layer" #add to map #map tool functions def addLayer(self): """TO DO: Add doc string""" fileName = QtGui.QFileDialog.getOpenFileName( parent=None, caption="Select Vector Overlay Layer", filter="Vector Files (*.shp *.geojson *.gml)") print fileName info = QtCore.QFileInfo(fileName) print info.filePath() print info.completeBaseName() # create layer layer = QgsVectorLayer(info.filePath(), info.completeBaseName(), "ogr") if not layer.isValid(): print "invalid layer" return # add layer to the registry QgsMapLayerRegistry.instance().addMapLayer(layer) # set extent to the extent of our layer #self.canvas.setExtent(layer.extent()) # set the map canvas layer set cl = QgsMapCanvasLayer(layer) self.mapCanvasLayers.insert(len(self.mapCanvasLayers) - 2, cl) #layers = [cl] self.canvas.setLayerSet(self.mapCanvasLayers) print "added Layer" def addMemoryLayer(self): '''Adds a layer to contain the feature defined by a bounding box, wkt, digitised poly|line|point or selection from other layer. ''' foi_type = self.foi_type.lower() if foi_type == 'areaofinterestdefiner': layer = QgsVectorLayer("Polygon", "Area of Interest", "memory") if foi_type == 'lineofinterestdefiner': layer = QgsVectorLayer("Linestring", "Line of Interest", "memory") if foi_type == 'pointofinterestdefiner': layer = QgsVectorLayer("Point", "Point of Interest", "memory") if foi_type == 'areaofinterestdefiner': sym = QgsSymbol(QGis.Polygon) sym.setColor(QtCore.Qt.black) sym.setFillColor(QtCore.Qt.green) sym.setFillStyle(QtCore.Qt.Dense6Pattern) sym.setLineWidth(0.5) sr = QgsSingleSymbolRenderer(QGis.Polygon) if foi_type == 'lineofinterestdefiner': sym = QgsSymbol(QGis.Line) sym.setColor(QtCore.Qt.black) sym.setFillColor(QtCore.Qt.green) sym.setFillStyle(QtCore.Qt.SolidPattern) sym.setLineWidth(0.5) sr = QgsSingleSymbolRenderer(QGis.Line) if foi_type == 'pointofinterestdefiner': sym = QgsSymbol(QGis.Point) sym.setColor(QtCore.Qt.black) sym.setFillColor(QtCore.Qt.green) sym.setFillStyle(QtCore.Qt.SolidPattern) sym.setLineWidth(0.3) sym.setPointSize(4) sym.setNamedPointSymbol("hard:triangle") sr = QgsSingleSymbolRenderer(QGis.Point) sr.addSymbol(sym) layer.setRenderer(sr) if not layer.isValid(): print "invalid layer" return ml_dp = layer.dataProvider() ml_dp.addAttributes([QgsField("gid", QtCore.QVariant.String)]) # add layer to the registry self.mem_layer_obj = QgsMapLayerRegistry.instance().addMapLayer(layer) # set extent to the extent of our layer #self.canvas.setExtent(layer.extent()) # set the map canvas layer set cl = QgsMapCanvasLayer(layer) self.mapCanvasLayers.insert(0, cl) #layers = [cl] self.canvas.setLayerSet(self.mapCanvasLayers) print "added Layer" def addGeomToMemoryLayer(self, the_geom, origin=0, delete_when_done=False): """TO DO: Add doc string""" foi_type = self.foi_type.lower() print "got foi_type" if self.mem_layer_obj.featureCount() > 0: if origin == 1: # is added by identify operation pass else: print self.mem_layer_obj.featureCount() print "there exists a feature, kill it!" self.mem_layer_obj.select() print "Feature count selcted for deletion:" print self.mem_layer_obj.selectedFeatureCount() self.mem_layer_obj.deleteSelectedFeatures() #self.mem_layer_obj.deleteFeature(0) self.mem_layer_obj.commitChanges() self.mem_layer_obj.triggerRepaint() ml_dp = self.mem_layer_obj.dataProvider() print "got DP" uuid_gid = QtCore.QUuid().createUuid().toString() print "got uuid" fet = QgsFeature() print "got feature with id" fet.setGeometry(the_geom) print "set geometry" fet.addAttribute(0, uuid_gid) print "set attr " ml_dp.addFeatures([fet]) self.mem_layer_obj.commitChanges() print "added layers" #self.mem_layer_obj.updateFeatureAttributes(fet) #self.mem_layer_obj.updateFeatureGeometry(fet) self.mem_layer_obj.updateExtents() print "updated extents" #self.mem_layer_obj.drawFeature(fet) self.mem_layer_obj.triggerRepaint() print "trp" return fet.id() def zoomIn(self): """TO DO: Add doc string""" self.canvas.setMapTool(self.toolZoomIn) def zoomOut(self): """TO DO: Add doc string""" self.canvas.setMapTool(self.toolZoomOut) def pan(self): """TO DO: Add doc string""" self.canvas.setMapTool(self.toolPan) def identifyFeature(self): '''getFeatureInfo functionality''' self.canvas.setMapTool(self.toolIdentify) #print "GFI not yet implemented" def gotFeatureForIdentification(self, pos): """Show a dialog with road information """ #pos is a rectangle self.mem_layer_obj.select() ftr = QgsFeature() ftr_ids = [] while self.mem_layer_obj.nextFeature(ftr): if ftr.geometry().intersects(pos): ftr_ids.append(ftr.id()) self.chosenFOIGeoms = [] self.info = QgsMessageViewer() if ftr_ids != []: f = QgsFeature() foi_type = self.foi_type.lower() if foi_type == 'areaofinterestdefiner': ftrData = "You have selected the following feature(s) for use as an Area of Interest:\n\n" if foi_type == 'lineofinterestdefiner': ftrData = "You have selected the following feature(s) for use as a Line of Interest:\n\n" if foi_type == 'pointofinterestdefiner': ftrData = "You have selected the following feature(s) for use as a Point of Interest:\n\n" for fid in ftr_ids: self.mem_layer_obj.dataProvider().featureAtId(fid, f, True) ftrData += f.attributeMap()[0].toString() ftrData += "\n_____________________________\n" self.chosenFOIGeoms.append(f.geometry()) id_fid = self.addGeomToMemoryLayer(f.geometry()) self.info.setMessageAsPlainText(ftrData) else: self.info.setMessageAsPlainText("no data to show") self.info.show() return def makeAOI(self): pass def makeLOI(self): pass def makePOI(self): pass def okTriggered(self): the_fet = QgsFeature() the_geoms = [] print self.mem_layer_obj.featureCount() self.mem_layer_obj.select() while self.mem_layer_obj.nextFeature(the_fet): #self.mem_layer_obj.featureAtId(0, the_fet) the_geoms.append(str(the_fet.geometry().exportToWkt())) print the_geoms wktstr = WKTString() print wktstr wktstr.setValue(the_geoms[0]) self.controller.update_ports_and_functions( self.module.id, [], [], [("WKTGeometry", the_geoms), ("SRS", [self.crsTextAsProj4.text()])]) self.close()
class ViewerWnd( QMainWindow ): def __init__( self, app, dictOpts ): QMainWindow.__init__( self ) self.setWindowTitle( "PostGIS Layer Viewer - v.1.6.1" ) self.setTabPosition( Qt.BottomDockWidgetArea, QTabWidget.North ) self.canvas = QgsMapCanvas() self.canvas.setCanvasColor( Qt.white ) self.canvas.useImageToRender( True ) self.canvas.enableAntiAliasing( True ) self.setCentralWidget( self.canvas ) actionZoomIn = QAction( QIcon( imgs_dir + "mActionZoomIn.png" ), QString( "Zoom in" ), self ) actionZoomOut = QAction( QIcon( imgs_dir + "mActionZoomOut.png" ), QString( "Zoom out" ), self ) actionPan = QAction( QIcon( imgs_dir + "mActionPan.png" ), QString( "Pan" ), self ) actionZoomFullExtent = QAction( QIcon( imgs_dir + "mActionZoomFullExtent.png" ), QString( "Zoom full" ), self ) actionZoomIn.setCheckable( True ) actionZoomOut.setCheckable( True ) actionPan.setCheckable( True ) self.connect(actionZoomIn, SIGNAL( "triggered()" ), self.zoomIn ) self.connect(actionZoomOut, SIGNAL( "triggered()" ), self.zoomOut ) self.connect(actionPan, SIGNAL( "triggered()" ), self.pan ) self.connect(actionZoomFullExtent, SIGNAL( "triggered()" ), self.zoomFullExtent ) self.actionGroup = QActionGroup( self ) self.actionGroup.addAction( actionPan ) self.actionGroup.addAction( actionZoomIn ) self.actionGroup.addAction( actionZoomOut ) # Create the toolbar self.toolbar = self.addToolBar( "Map tools" ) self.toolbar.addAction( actionPan ) self.toolbar.addAction( actionZoomIn ) self.toolbar.addAction( actionZoomOut ) self.toolbar.addAction( actionZoomFullExtent ) # Create the map tools self.toolPan = QgsMapToolPan( self.canvas ) self.toolPan.setAction( actionPan ) self.toolZoomIn = QgsMapToolZoom( self.canvas, False ) # false = in self.toolZoomIn.setAction( actionZoomIn ) self.toolZoomOut = QgsMapToolZoom( self.canvas, True ) # true = out self.toolZoomOut.setAction( actionZoomOut ) # Create the statusbar self.statusbar = QStatusBar( self ) self.statusbar.setObjectName( "statusbar" ) self.setStatusBar( self.statusbar ) self.lblXY = QLabel() self.lblXY.setFrameStyle( QFrame.Box ) self.lblXY.setMinimumWidth( 170 ) self.lblXY.setAlignment( Qt.AlignCenter ) self.statusbar.setSizeGripEnabled( False ) self.statusbar.addPermanentWidget( self.lblXY, 0 ) self.lblScale = QLabel() self.lblScale.setFrameStyle( QFrame.StyledPanel ) self.lblScale.setMinimumWidth( 140 ) self.statusbar.addPermanentWidget( self.lblScale, 0 ) self.createLegendWidget() # Create the legend widget self.connect( app, SIGNAL( "loadPgLayer" ), self.loadLayer ) self.connect( self.canvas, SIGNAL( "scaleChanged(double)" ), self.changeScale ) self.connect( self.canvas, SIGNAL( "xyCoordinates(const QgsPoint&)" ), self.updateXY ) self.pan() # Default self.plugins = Plugins( self, self.canvas, dictOpts['-h'], dictOpts['-p'], dictOpts['-d'], dictOpts['-U'], dictOpts['-W'] ) self.createAboutWidget() self.layerSRID = '-1' self.loadLayer( dictOpts ) def zoomIn( self ): self.canvas.setMapTool( self.toolZoomIn ) def zoomOut( self ): self.canvas.setMapTool( self.toolZoomOut ) def pan( self ): self.canvas.setMapTool( self.toolPan ) def zoomFullExtent( self ): self.canvas.zoomToFullExtent() def about( self ): pass def createLegendWidget( self ): """ Create the map legend widget and associate it to the canvas """ self.legend = Legend( self ) self.legend.setCanvas( self.canvas ) self.legend.setObjectName( "theMapLegend" ) self.LegendDock = QDockWidget( "Layers", self ) self.LegendDock.setObjectName( "legend" ) self.LegendDock.setTitleBarWidget( QWidget() ) self.LegendDock.setWidget( self.legend ) self.LegendDock.setContentsMargins ( 0, 0, 0, 0 ) self.addDockWidget( Qt.BottomDockWidgetArea, self.LegendDock ) def createAboutWidget( self ): self.AboutDock = QDockWidget( "About", self ) self.AboutDock.setObjectName( "about" ) self.AboutDock.setTitleBarWidget( QWidget() ) self.AboutDock.setContentsMargins( 0, 0, 0, 0 ) self.tabifyDockWidget( self.LegendDock, self.AboutDock ) self.LegendDock.raise_() # legendDock at the top from PyQt4.QtCore import QRect from PyQt4.QtGui import QSizePolicy, QGridLayout, QFont font = QFont() font.setFamily("Sans Serif") font.setPointSize(8.7) self.AboutWidget = QWidget() self.AboutWidget.setFont( font ) self.AboutWidget.setObjectName("AboutWidget") self.AboutDock.setWidget( self.AboutWidget ) self.labelAbout = QLabel( self.AboutWidget ) self.labelAbout.setAlignment(Qt.AlignCenter) self.labelAbout.setWordWrap(True) self.gridLayout = QGridLayout(self.AboutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.gridLayout.addWidget(self.labelAbout, 0, 1, 1, 1) self.labelAbout.setTextInteractionFlags(Qt.LinksAccessibleByMouse|Qt.LinksAccessibleByKeyboard|Qt.TextSelectableByKeyboard|Qt.TextSelectableByMouse) self.labelAbout.setOpenExternalLinks( True ) self.labelAbout.setText("<html><head/><body><a href=\"http://geotux.tuxfamily.org/index.php/en/geo-blogs/item/293-consola-sql-para-plugin-pgadmin-postgis-viewer\">PostGIS Layer Viewer</a> v.1.6.1 (2015.02.24)<br \><br \>" \ "Copyright (c) 2010 Ivan Mincik,<br \>[email protected]<br \>" \ u"Copyright (c) 2011-2015 Germán Carrillo,<br \>[email protected]<br \><br \>" \ "<i>Licensed under the terms of GNU GPL v.2.0</i><br \><br \>" \ "Based on PyQGIS. Plugin Fast SQL Layer by Pablo T. Carreira.</body></html>" ) def loadLayer( self, dictOpts ): print 'I: Loading the layer...' self.layerSRID = dictOpts[ 'srid' ] # To access the SRID when querying layer properties if not self.isActiveWindow(): self.activateWindow() self.raise_() if dictOpts['type'] == 'vector': # QGIS connection uri = QgsDataSourceURI() uri.setConnection( dictOpts['-h'], dictOpts['-p'], dictOpts['-d'], dictOpts['-U'], dictOpts['-W'] ) uri.setDataSource( dictOpts['-s'], dictOpts['-t'], dictOpts['-g'] ) layer = QgsVectorLayer( uri.uri(), dictOpts['-s'] + '.' + dictOpts['-t'], "postgres" ) elif dictOpts['type'] == 'raster': connString = "PG: dbname=%s host=%s user=%s password=%s port=%s mode=2 " \ "schema=%s column=%s table=%s" % ( dictOpts['-d'], dictOpts['-h'], dictOpts['-U'], dictOpts['-W'], dictOpts['-p'], dictOpts['-s'], dictOpts['col'], dictOpts['-t'] ) layer = QgsRasterLayer( connString, dictOpts['-s'] + '.' + dictOpts['-t'] ) if layer.isValid(): layer.setContrastEnhancement( QgsContrastEnhancement.StretchToMinimumMaximum ) self.addLayer( layer, self.layerSRID ) def addLayer( self, layer, srid='-1' ): if layer.isValid(): # Only in case that srid != -1, read the layer SRS properties, otherwise don't since it will return 4326 if srid != '-1': self.layerSRID = layer.crs().description() + ' (' + str( layer.crs().postgisSrid() ) + ')' else: self.layerSRID = 'Unknown SRS (-1)' if self.canvas.layerCount() == 0: self.canvas.setExtent( layer.extent() ) if srid != '-1': print 'I: Map SRS (EPSG): %s' % self.layerSRID self.canvas.setMapUnits( layer.crs().mapUnits() ) else: print 'I: Unknown Reference System' self.canvas.setMapUnits( 0 ) # 0: QGis.Meters return QgsMapLayerRegistry.instance().addMapLayer( layer ) return False def activeLayer( self ): """ Returns the active layer in the layer list widget """ return self.legend.activeLayer() def getLayerProperties( self, l ): """ Create a layer-properties string (l:layer)""" print 'I: Generating layer properties...' if l.type() == 0: # Vector wkbType = ["WKBUnknown","WKBPoint","WKBLineString","WKBPolygon", "WKBMultiPoint","WKBMultiLineString","WKBMultiPolygon", "WKBNoGeometry","WKBPoint25D","WKBLineString25D","WKBPolygon25D", "WKBMultiPoint25D","WKBMultiLineString25D","WKBMultiPolygon25D"] properties = "Source: %s\n" \ "Geometry type: %s\n" \ "Number of features: %s\n" \ "Number of fields: %s\n" \ "SRS (EPSG): %s\n" \ "Extent: %s " \ % ( l.source(), wkbType[l.wkbType()], l.featureCount(), l.dataProvider().fields().count(), self.layerSRID, l.extent().toString() ) elif l.type() == 1: # Raster rType = [ "GrayOrUndefined (single band)", "Palette (single band)", "Multiband", "ColorLayer" ] properties = "Source: %s\n" \ "Raster type: %s\n" \ "Width-Height (pixels): %sx%s\n" \ "Bands: %s\n" \ "SRS (EPSG): %s\n" \ "Extent: %s" \ % ( l.source(), rType[l.rasterType()], l.width(), l.height(), l.bandCount(), self.layerSRID, l.extent().toString() ) self.layerSRID = '-1' # Initialize the srid return properties def changeScale( self, scale ): self.lblScale.setText( "Scale 1:" + formatNumber( scale ) ) def updateXY( self, p ): if self.canvas.mapUnits() == 2: # Degrees self.lblXY.setText( formatToDegrees( p.x() ) + " | " \ + formatToDegrees( p.y() ) ) else: # Unidad lineal self.lblXY.setText( formatNumber( p.x() ) + " | " \ + formatNumber( p.y() ) + "" )
class ViewerWnd(QMainWindow): def __init__(self, app, dictOpts): QMainWindow.__init__(self) self.canvas = QgsMapCanvas() self.canvas.setCanvasColor(Qt.white) self.canvas.useImageToRender(True) self.canvas.enableAntiAliasing(True) self.setCentralWidget(self.canvas) actionZoomIn = QAction(QIcon(imgs_dir + "mActionZoomIn.png"), QString("Zoom in"), self) actionZoomOut = QAction(QIcon(imgs_dir + "mActionZoomOut.png"), QString("Zoom out"), self) actionPan = QAction(QIcon(imgs_dir + "mActionPan.png"), QString("Pan"), self) actionZoomIn.setCheckable(True) actionZoomOut.setCheckable(True) actionPan.setCheckable(True) self.connect(actionZoomIn, SIGNAL("triggered()"), self.zoomIn) self.connect(actionZoomOut, SIGNAL("triggered()"), self.zoomOut) self.connect(actionPan, SIGNAL("triggered()"), self.pan) # Create the toolbar self.toolbar = self.addToolBar("Map tools") self.toolbar.addAction(actionZoomIn) self.toolbar.addAction(actionZoomOut) self.toolbar.addAction(actionPan) # Create the map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in self.toolZoomIn.setAction(actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out self.toolZoomOut.setAction(actionZoomOut) # Create the statusbar self.statusbar = QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.lblXY = QLabel() self.lblXY.setFrameStyle(QFrame.Box) self.lblXY.setMinimumWidth(170) self.lblXY.setAlignment(Qt.AlignCenter) self.statusbar.setSizeGripEnabled(False) self.statusbar.addPermanentWidget(self.lblXY, 0) self.lblScale = QLabel() self.lblScale.setFrameStyle(QFrame.StyledPanel) self.lblScale.setMinimumWidth(140) self.statusbar.addPermanentWidget(self.lblScale, 0) self.createLegendWidget() # Create the legend widget self.connect(app, SIGNAL("loadPgLayer"), self.loadLayer) self.connect(self.canvas, SIGNAL("scaleChanged(double)"), self.changeScale) self.connect(self.canvas, SIGNAL("xyCoordinates(const QgsPoint&)"), self.updateXY) self.pan() self.layerSRID = "" self.loadLayer(dictOpts) def zoomIn(self): self.canvas.setMapTool(self.toolZoomIn) def zoomOut(self): self.canvas.setMapTool(self.toolZoomOut) def pan(self): self.canvas.setMapTool(self.toolPan) def createLegendWidget(self): """ Create the map legend widget and associate to the canvas """ self.legend = Legend(self) self.legend.setCanvas(self.canvas) self.legend.setObjectName("theMapLegend") self.LegendDock = QDockWidget("Layers", self) self.LegendDock.setObjectName("legend") # self.LegendDock.setAllowedAreas( Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea ) self.LegendDock.setWidget(self.legend) self.LegendDock.setContentsMargins(0, 0, 0, 0) self.addDockWidget(Qt.BottomDockWidgetArea, self.LegendDock) def loadLayer(self, dictOpts): print "I: Loading the layer..." self.layerSRID = dictOpts["srid"] # To access the SRID when querying layer properties if not self.isActiveWindow(): self.activateWindow() self.raise_() if dictOpts["type"] == "vector": # QGIS connection uri = QgsDataSourceURI() uri.setConnection(dictOpts["-h"], dictOpts["-p"], dictOpts["-d"], dictOpts["-U"], dictOpts["-W"]) uri.setDataSource(dictOpts["-s"], dictOpts["-t"], dictOpts["-g"]) layer = QgsVectorLayer(uri.uri(), dictOpts["-s"] + "." + dictOpts["-t"], "postgres") elif dictOpts["type"] == "raster": connString = "PG: dbname=%s host=%s user=%s password=%s port=%s schema=%s table=%s" % ( dictOpts["-d"], dictOpts["-h"], dictOpts["-U"], dictOpts["-W"], dictOpts["-p"], dictOpts["-s"], dictOpts["-t"], ) layer = QgsRasterLayer(connString, dictOpts["-s"] + "." + dictOpts["-t"]) layer.setNoDataValue(-32768) layer.rasterTransparency().initializeTransparentPixelList(-32768) if layer.isValid(): if self.canvas.layerCount() == 0: self.canvas.setExtent(layer.extent()) if dictOpts["srid"] != "-1": print "I: Map SRS (EPSG): %s" % dictOpts["srid"] self.canvas.setMapUnits(layer.srs().mapUnits()) else: print "I: Unknown Reference System" self.canvas.setMapUnits(0) # 0: QGis.Meters QgsMapLayerRegistry.instance().addMapLayer(layer) def getLayerProperties(self, l): """ Create a layer-properties string (l:layer)""" print "I: Generating layer properties..." if l.type() == 0: # Vector wkbType = [ "WKBUnknown", "WKBPoint", "WKBLineString", "WKBPolygon", "WKBMultiPoint", "WKBMultiLineString", "WKBMultiPolygon", "WKBNoGeometry", "WKBPoint25D", "WKBLineString25D", "WKBPolygon25D", "WKBMultiPoint25D", "WKBMultiLineString25D", "WKBMultiPolygon25D", ] properties = ( "Source: %s\n" "Geometry type: %s\n" "Number of features: %s\n" "Number of fields: %s\n" "SRS (EPSG): %s\n" "Extent: %s " % ( l.source(), wkbType[l.wkbType()], l.featureCount(), l.dataProvider().fieldCount(), self.layerSRID, l.extent().toString(), ) ) elif l.type() == 1: # Raster rType = ["GrayOrUndefined (single band)", "Palette (single band)", "Multiband"] properties = ( "Source: %s\n" "Raster type: %s\n" "Width-Height (pixels): %sx%s\n" "Bands: %s\n" "SRS (EPSG): %s\n" "Extent: %s" % ( l.source(), rType[l.rasterType()], l.width(), l.height(), l.bandCount(), self.layerSRID, l.extent().toString(), ) ) return properties def changeScale(self, scale): self.lblScale.setText("Scale 1:" + formatNumber(scale)) def updateXY(self, p): if self.canvas.mapUnits() == 2: # Degrees self.lblXY.setText(formatToDegrees(p.x()) + " | " + formatToDegrees(p.y())) else: # Unidad lineal self.lblXY.setText(formatNumber(p.x()) + " | " + formatNumber(p.y()) + "")
class MainWindow(QMainWindow): # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-statements def __init__(self, app, mapLayers, mapLayersCategory): QMainWindow.__init__(self) self.app = app self.mapLayers = mapLayers self.mapLayersCategory = mapLayersCategory self.resize(shared.windowWidth, shared.windowHeight) self.setWindowTitle(shared.progName + ": " + shared.progVer) # Set up the map canvas self.canvas = QgsMapCanvas() self.setCentralWidget(self.canvas) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setCachingEnabled(True) #self.canvas.setMapUpdateInterval(1000) self.canvas.setParallelRenderingEnabled(True) self.canvas.enableMapTileRendering(True) self.canvas.setLayers(self.mapLayers) self.canvas.setExtent(shared.extentRect) self.canvas.setMagnificationFactor(shared.windowMagnification) #mapSet = self.canvas.mapSettings() #print(mapSet.flags()) # Create some actions #self.actionExit = QAction(QIcon('exit.png'), '&Exit', self) self.actionExit = QAction("&Exit", self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setStatusTip("Exit " + shared.progName) self.actionZoomIn = QAction("Zoom in", self) self.actionZoomIn.setCheckable(True) #self.actionExit.setShortcut("Ctrl++") self.actionZoomIn.setStatusTip("Show more detail") self.actionZoomOut = QAction("Zoom out", self) self.actionZoomOut.setCheckable(True) #self.actionExit.setShortcut("Ctrl+-") self.actionZoomOut.setStatusTip("Show less detail") self.actionPan = QAction("Pan", self) self.actionPan.setCheckable(True) self.actionPan.setStatusTip("Move the map laterally") self.actionChangeBackground = QAction("Change background", self) self.actionChangeBackground.setStatusTip( "Change the raster background") if not shared.haveRasterBackground: self.actionChangeBackground.setEnabled(False) self.actionCoords = QAction("Show coordinates", self) self.actionCoords.setCheckable(True) self.actionCoords.setStatusTip("Click to show coordinates") self.actionRun = QAction("Simulate", self) self.actionRun.setStatusTip("Route flow") # Connect the actions self.actionExit.triggered.connect(app.quit) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionPan.triggered.connect(self.pan) self.actionChangeBackground.triggered.connect(self.changeBackground) self.actionCoords.triggered.connect(self.showCoords) self.actionRun.triggered.connect(self.doRun) # Create a menu bar and add menus self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu("&File") self.fileMenu.addAction(self.actionExit) self.editMenu = self.menubar.addMenu("&Edit") #self.editMenu.addAction(self.actionExit) self.viewMenu = self.menubar.addMenu("&View") self.viewMenu.addAction(self.actionZoomIn) self.viewMenu.addAction(self.actionZoomOut) self.viewMenu.addAction(self.actionPan) self.viewMenu.addAction(self.actionChangeBackground) self.viewMenu.addAction(self.actionCoords) self.runMenu = self.menubar.addMenu("&Run") self.runMenu.addAction(self.actionRun) # Create a tool bar and add some actions self.toolbar = self.addToolBar("Default") self.toolbar.setFloatable(True) self.toolbar.addAction(self.actionRun) self.toolbar.addAction(self.actionZoomIn) self.toolbar.addAction(self.actionZoomOut) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionCoords) # Create some map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # False = in self.toolZoomIn.setAction(self.actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # True = out self.toolZoomOut.setAction(self.actionZoomOut) self.toolCoords = PointTool(self.canvas) self.toolCoords.setAction(self.actionCoords) # Put into panning mode self.pan() # Add a status bar self.statusBar = QStatusBar(self.canvas) self.setStatusBar(self.statusBar) # And put a progress indicator on the status bar self.statusBar.progress = QProgressBar(self) self.statusBar.progress.setRange(0, 100) self.statusBar.progress.setMaximumWidth(500) self.statusBar.progress.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.statusBar.addPermanentWidget(self.statusBar.progress) self.myThread = None return #====================================================================================================================== #====================================================================================================================== def doRun(self): # Delete all output features (in case we have some from a previous run) listIDs = [ feat.id() for feat in shared.outFlowMarkerPointLayer.getFeatures() ] prov = shared.outFlowMarkerPointLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowMarkerPointLayer.updateExtents() shared.outFlowMarkerPointLayer.triggerRepaint() listIDs = [feat.id() for feat in shared.outFlowLineLayer.getFeatures()] prov = shared.outFlowLineLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowLineLayer.updateExtents() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.statusBar.progress.setValue(0) self.actionRun.setEnabled(False) # All is now ready, so run the simulation as a separate thread self.myThread = SimulationThread(self.app, self) self.myThread.refresh.connect(self.doRefresh) self.myThread.runDone.connect(self.runDone) self.canvas.freeze(True) #self.canvas.refreshAllLayers() #self.app.processEvents() self.myThread.start() print("\nThread started") return #====================================================================================================================== #====================================================================================================================== def doRefresh(self): self.canvas.freeze(False) if not self.canvas.isDrawing(): shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.canvas.freeze(True) if not isinstance(shared.flowStartPoints, int): doneSoFar = (float(shared.thisStartPoint) / float(len(shared.flowStartPoints) + 1)) * 100.0 #shared.fpOut.write(doneSoFar) self.statusBar.progress.setValue(doneSoFar) return #====================================================================================================================== #====================================================================================================================== def zoomIn(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomIn) return #====================================================================================================================== #====================================================================================================================== def zoomOut(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomOut) return #====================================================================================================================== #====================================================================================================================== def pan(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolPan) return #====================================================================================================================== #====================================================================================================================== def showCoords(self): self.canvas.setMapTool(self.toolCoords) return #====================================================================================================================== #====================================================================================================================== def close(self): if self.myThread: self.myThread.quit() self.myThread = None return #====================================================================================================================== #====================================================================================================================== def runDone(self): self.canvas.freeze(False) shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() print("Thread done") self.myThread.quit() #self.myThread = None self.statusBar.progress.setValue(100) #QMessageBox.information(self, "End of run", shared.progName + ": flow routed") self.statusBar.showMessage("End of run: flow routed", shared.defaultMessageDisplayTime) # To prevent subsequent re-runs # self.actionRun.setEnabled(False) return #====================================================================================================================== #====================================================================================================================== def changeBackground(self): for n in range(len(shared.rasterInputLayersCategory)): if shared.rasterInputLayersCategory[n] == INPUT_RASTER_BACKGROUND: oldOpacity = shared.rasterInputLayers[n].renderer().opacity() if oldOpacity == 0: newOpacity = shared.rasterFileOpacity[n] else: newOpacity = 0 shared.rasterInputLayers[n].renderer().setOpacity(newOpacity) #layerID = shared.rasterInputLayers[n].id() #layerTreeNode = QgsProject.instance().layerTreeRoot().findLayer(layerID) #print(layerTreeNode.dump()) #layerTreeNode.setItemVisibilityChecked(not layerTreeNode.itemVisibilityChecked()) #print(layerTreeNode.dump()) #print("*****************") #for n in range(len(self.mapLayers)): #if self.mapLayersCategory[n] == INPUT_RASTER_BACKGROUND: #self.mapLayers[n].setVisible(not self.mapLayers[n].isVisible()) #self.canvas.setLayers(self.mapLayers) self.doRefresh() return