def __init__(self, iface): # QGIS self.iface = iface self.settings = MySettings() self.linkRubber = QgsRubberBand(self.iface.mapCanvas()) self.featureHighlight = None # Relation management self.relationManager = QgsProject.instance().relationManager() self.relationManager.changed.connect(self.loadRelations) self.relation = QgsRelation() self.referencingFeature = QgsFeature() self.relationWidgetWrapper = None self.editorContext = QgsAttributeEditorContext() self.editorContext.setVectorLayerTools(self.iface.vectorLayerTools()) # GUI QDockWidget.__init__(self) self.setupUi(self) SettingDialog.__init__(self, MySettings(), False, True) self.drawButton.setChecked(self.settings.value("drawEnabled")) self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) self.mapTool = QgsMapToolIdentifyFeature(self.iface.mapCanvas()) self.mapTool.setButton(self.identifyReferencingFeatureButton) # Connect signal/slot self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged) self.mapTool.featureIdentified.connect(self.setReferencingFeature) # load relations at start self.loadRelations()
def sel_oldlim(self): # Selection in the canvas self.hide() self.l_edge.removeSelection() self.identify_oldlim = QgsMapToolIdentifyFeature( self.canvas, self.l_edge) self.identify_oldlim.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_oldlim.featureIdentified.connect(self.oldlim_identified) self.canvas.setMapTool(self.identify_oldlim)
def __init__(self, iface, layer, obj): self.iface = iface self.canvas = self.iface.mapCanvas() self.layer = layer self.nodes = [] self.obj = obj self.field = "" self.deselectedSegmentIndex = False self.buttonValue = False QgsMapToolIdentifyFeature.__init__(self, self.canvas, self.layer)
def __init__(self, canvas): QgsMapToolIdentifyFeature.__init__(self, canvas) self.linkedcanvas = canvas self.activefeature = None self.active = False #TODO: Enable users to set the following: self.brushsize = 0.01 self.brushroundness = 4 self.activelayer = self.linkedcanvas.layer(0)
def __init__(self, parent, utils, parcel_number=None, collected_parcel_t_id=None): QgsPanelWidget.__init__(self, None) self.setupUi(self) self.parent = parent self.utils = utils self.setDockMode(True) self.setPanelTitle( QCoreApplication.translate("ChangesPerParcelPanelWidget", "Change detection per parcel")) self._current_official_substring = "" self._current_substring = "" self.utils.add_layers() self.fill_combos() # Remove selection in plot layers self.utils._layers[PLOT_TABLE][LAYER].removeSelection() self.utils._official_layers[PLOT_TABLE][LAYER].removeSelection() # Map tool before activate map swipe tool self.init_map_tool = self.utils.canvas.mapTool() self.active_map_tool_before_custom = None self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.utils.canvas) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.chk_show_all_plots.toggled.connect(self.show_all_plots) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.panelAccepted.connect(self.initialize_tools_and_layers) self.tbl_changes_per_parcel.itemDoubleClicked.connect( self.call_party_panel) self.initialize_field_values_line_edit() self.initialize_tools_and_layers() if parcel_number is not None: # Do a search! self.txt_alphanumeric_query.setValue(parcel_number) if collected_parcel_t_id is not None: # Search data for a duplicated parcel_number, so, take the t_id into account! self.search_data(parcel_number=parcel_number, collected_parcel_t_id=collected_parcel_t_id) else: self.search_data(parcel_number=parcel_number)
def select_feature(self): self.setVisible(False) # Make wizard disappear # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self.maptool_identify.setLayer(self._current_layer) cursor = QCursor() cursor.setShape(Qt.CrossCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) self.maptool_identify.featureIdentified.connect(self.get_feature_id)
def sel_nwvtxnear_rfu(self): # Selection in the canvas if self.sel_nw_vtx: self.hide() self.identify_rfu_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_rfu_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_rfu_vtx.featureIdentified.connect(partial(self.rfu_vtx_identified, "near")) self.canvas.setMapTool(self.identify_rfu_vtx) # Message if no line selected in the tablview else: QMessageBox.warning(self, tr_vtxplt_sel_nolinesel_msg[0], tr_vtxplt_sel_nolinesel_msg[1])
def __init__(self, iface, controller, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._controller = controller self.logger = Logger() self.app = AppInterface() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self._identify_tool = None self._fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM-COL/resources/images/spatial_unit.png")) self.tab_results.setTabEnabled( TAB_BASIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_PHYSICAL_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_ECONOMIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setCurrentIndex( TAB_LEGAL_INFO_INDEX ) # TODO: Remove when queries support LevCat 1.2 # Set connections self._controller.close_view_requested.connect(self._close_dock_widget) self.btn_alphanumeric_query.clicked.connect(self._alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self._search_field_updated) self.btn_identify_plot.clicked.connect(self._btn_plot_toggled) self.btn_query_informality.clicked.connect(self._query_informality) self.btn_next_informal_parcel.clicked.connect( self._query_next_informal_parcel) self.btn_previous_informal_parcel.clicked.connect( self._query_previous_informal_parcel) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self._initialize_field_values_line_edit() self._update_informal_controls()
def actionIdentifyTriggered(self): # 设置识别工具 self.identifyTool = QgsMapToolIdentifyFeature(self.mapCanvas) self.identifyTool.featureIdentified.connect(self.showFeatures) self.mapCanvas.setMapTool(self.identifyTool) # 设置需要识别的图层 layers = self.mapCanvas.layers() if layers: # 识别画布中第一个图层 self.identifyTool.setLayer(layers[0])
def tool_select_pt_to_plot(self, type_fnc): self.plot_fnc_mode = type_fnc if self.conn and self.rfu and self.rfu.zone: # Prompt message self.iface.messageBar().pushMessage(plot_dif_txt[type_fnc][0], plot_dif_txt[type_fnc][1], Qgis.Info, duration=10) # Pointer to choose the vertex # Set the layer l_vertex current self.iface.setActiveLayer(self.rfu.l_vertex) self.project.layerTreeRoot().findLayer( self.rfu.l_vertex.id()).setItemVisibilityChecked(True) self.canvas.refresh() self.identify_pttoplot = QgsMapToolIdentifyFeature( self.canvas, self.rfu.l_vertex) self.identify_pttoplot.setCursor(QCursor(Qt.WhatsThisCursor)) self.identify_pttoplot.featureIdentified.connect( self.pt_to_plot_identified) self.canvas.setMapTool(self.identify_pttoplot)
def __init__(self, iface, db, qgis_utils, ladm_data, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._db = db self.qgis_utils = qgis_utils self.ladm_data = ladm_data self.logger = Logger() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self.names = self._db.names self.clipboard = QApplication.clipboard() # Required layers self.restart_dict_of_layers() self._identify_tool = None self.add_layers() self.fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self.initialize_field_values_line_edit()
def __init__(self, iface, db, qgis_utils, ladm_data, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self.canvas = iface.mapCanvas() self._db = db self.qgis_utils = qgis_utils self.ladm_data = ladm_data self.selection_color = None self.active_map_tool_before_custom = None self.clipboard = QApplication.clipboard() # Required layers self._plot_layer = None self._parcel_layer = None self._uebaunit_table = None self._identify_tool = None self.add_layers() self.fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.btn_clear_alphanumeric_query.clicked.connect( self.clear_alphanumeric_query) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas)
def __init__(self, id, gtotool, config, debug): super(run, self).__init__() self.debug = debug self.gtotool = gtotool self.gtomain = gtotool.gtomain self.info = gtotool.info self.iface = self.gtotool.iface self.act = self.sender() self.act.setCheckable(True) self.sourcefeat = None self.rubbers = [] try: # create rubberband self.rubber = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.rubber.setColor(QColor(Qt.blue)) self.rubber.setLineStyle(Qt.PenStyle(Qt.DashDotLine)) self.rubber.setWidth(2) # get metadata self.sourcelayer = QgsProject.instance().mapLayersByName(config["sourcelayer"])[0] self.targetlayer = QgsProject.instance().mapLayersByName(config['targetlayer'])[0] self.iface.setActiveLayer(self.targetlayer) # start edit if not self.targetlayer.isEditable(): self.targetlayer.startEditing() if not self.sourcelayer.isEditable(): self.sourcelayer.startEditing() # mouse move self.canvas = self.iface.mapCanvas() self.canvas.xyCoordinates.connect(self.mouse_move) # set maptool self.mapTool = QgsMapToolIdentifyFeature(self.canvas) self.mapTool.setLayer(self.sourcelayer) self.canvas.setMapTool(self.mapTool) self.mapTool.featureIdentified.connect(self.feature_Identified) self.mapTool.deactivated.connect(self.reset_tool) self.act.setChecked(True) except Exception as e: self.info.err(e)
class EditGenericAttributes(QgsMapToolEmitPoint): """ Tool to edit generic attributes by clicking on the map. """ def __init__(self, canvas, layer): QgsMapToolEmitPoint.__init__(self, canvas) self.canvas = canvas self.layer = layer self.identifier = QgsMapToolIdentifyFeature(canvas, layer) self.setCursor(Qt.CrossCursor) def canvasReleaseEvent(self, event): feature = self.identifier.identify( event.x(), event.y(), self.identifier.TopDownStopAtFirst)[0] self.identifier.featureIdentified.emit(feature.mFeature) def deactivate(self): QgsMapTool.deactivate(self) self.deactivated.emit()
class FeatureSelectorWidget(QWidget): feature_identified = pyqtSignal(QgsFeature) def __init__(self, parent): QWidget.__init__(self, parent) edit_layout = QHBoxLayout() edit_layout.setContentsMargins(0, 0, 0, 0) edit_layout.setSpacing(2) self.setLayout(edit_layout) self.line_edit = QLineEdit(self) self.line_edit.setReadOnly(True) edit_layout.addWidget(self.line_edit) self.highlight_feature_button = QToolButton(self) self.highlight_feature_button.setPopupMode(QToolButton.MenuButtonPopup) self.highlight_feature_action = QAction( QgsApplication.getThemeIcon("/mActionHighlightFeature.svg"), "Highlight feature", self) self.scale_highlight_feature_action = QAction( QgsApplication.getThemeIcon("/mActionScaleHighlightFeature.svg"), "Scale and highlight feature", self) self.pan_highlight_feature_action = QAction( QgsApplication.getThemeIcon("/mActionPanHighlightFeature.svg"), "Pan and highlight feature", self) self.highlight_feature_button.addAction(self.highlight_feature_action) self.highlight_feature_button.addAction( self.scale_highlight_feature_action) self.highlight_feature_button.addAction( self.pan_highlight_feature_action) self.highlight_feature_button.setDefaultAction( self.highlight_feature_action) edit_layout.addWidget(self.highlight_feature_button) self.map_identification_button = QToolButton(self) self.map_identification_button.setIcon( QgsApplication.getThemeIcon("/mActionMapIdentification.svg")) self.map_identification_button.setText("Select on map") self.map_identification_button.setCheckable(True) edit_layout.addWidget(self.map_identification_button) self.map_identification_button.clicked.connect(self.map_identification) self.highlight_feature_button.triggered.connect( self.highlight_action_triggered) self.layer = None self.map_tool = None self.canvas = None self.window_widget = None self.highlight = None self.feature = QgsFeature() def set_canvas(self, map_canvas): self.map_tool = QgsMapToolIdentifyFeature(map_canvas) self.map_tool.setButton(self.map_identification_button) self.canvas = map_canvas def set_layer(self, layer): self.layer = layer def set_feature(self, feature, canvas_extent=CanvasExtent.Fixed): self.line_edit.clear() self.feature = feature if self.feature is None or not self.feature.isValid( ) or self.layer is None: return expression = QgsExpression(self.layer.displayExpression()) context = QgsExpressionContext() scope = QgsExpressionContextScope() context.appendScope(scope) scope.setFeature(feature) feature_title = expression.evaluate(context) if feature_title == "": feature_title = feature.id() self.line_edit.setText(str(feature_title)) self.highlight_feature(canvas_extent) def clear(self): self.feature = QgsFeature() self.line_edit.clear() @pyqtSlot() def map_identification(self): if self.layer is None or self.map_tool is None or self.canvas is None: return self.map_tool.setLayer(self.layer) self.canvas.setMapTool(self.map_tool) self.window_widget = QWidget.window(self) self.canvas.window().raise_() self.canvas.activateWindow() self.canvas.setFocus() self.map_tool.featureIdentified.connect( self.map_tool_feature_identified) self.map_tool.deactivated.connect(self.map_tool_deactivated) def map_tool_feature_identified(self, feature): feature = QgsFeature(feature) self.feature_identified.emit(feature) self.unset_map_tool() self.set_feature(feature) def map_tool_deactivated(self): if self.window_widget is not None: self.window_widget.raise_() self.window_widget.activateWindow() def highlight_feature(self, canvas_extent=CanvasExtent.Fixed): if self.canvas is None or not self.feature.isValid(): return geom = self.feature.geometry() if geom is None: return if canvas_extent == CanvasExtent.Scale: feature_bounding_box = geom.boundingBox() feature_bounding_box = self.canvas.mapSettings( ).layerToMapCoordinates(self.layer, feature_bounding_box) extent = self.canvas.extent() if not extent.contains(feature_bounding_box): extent.combineExtentWith(feature_bounding_box) extent.scale(1.1) self.canvas.setExtent(extent) self.canvas.refresh() elif canvas_extent == CanvasExtent.Pan: centroid = geom.centroid() center = centroid.asPoint() center = self.canvas.mapSettings().layerToMapCoordinates( self.layer, center) self.canvas.zoomByFactor(1.0, center) # refresh is done in this method # highlight self.delete_highlight() self.highlight = QgsHighlight(self.canvas, geom, self.layer) settings = QSettings() color = QColor( settings.value("/Map/highlight/color", Qgis.DEFAULT_HIGHLIGHT_COLOR.name())) alpha = int( settings.value("/Map/highlight/colorAlpha", Qgis.DEFAULT_HIGHLIGHT_COLOR.alpha())) buffer = 2 * float( settings.value("/Map/highlight/buffer", Qgis.DEFAULT_HIGHLIGHT_BUFFER_MM)) min_width = 2 * float( settings.value("/Map/highlight/min_width", Qgis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM)) self.highlight.setColor(color) # sets also fill with default alpha color.setAlpha(alpha) self.highlight.setFillColor(color) # sets fill with alpha self.highlight.setBuffer(buffer) self.highlight.setMinWidth(min_width) self.highlight.setWidth(4.0) self.highlight.show() self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.timeout.connect(self.delete_highlight) self.timer.start(3000) def delete_highlight(self): if self.highlight is not None: self.highlight.hide() del self.highlight self.highlight = None def unset_map_tool(self): if self.canvas is not None and self.map_tool is not None: # this will call mapTool.deactivated self.canvas.unsetMapTool(self.map_tool) def highlight_action_triggered(self, action): self.highlight_feature_button.setDefaultAction(action) if action == self.highlight_feature_action: self.highlight_feature() elif action == self.scale_highlight_feature_action: self.highlight_feature(CanvasExtent.Scale) elif action == self.pan_highlight_feature_action: self.highlight_feature(CanvasExtent.Pan)
class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI): zoom_to_features_requested = pyqtSignal(QgsVectorLayer, list, dict, int) # layer, ids, t_ids, duration def __init__(self, iface, db, qgis_utils, ladm_data, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._db = db self.qgis_utils = qgis_utils self.ladm_data = ladm_data self.logger = Logger() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self.names = self._db.names self.clipboard = QApplication.clipboard() # Required layers self.restart_dict_of_layers() self._identify_tool = None self.add_layers() self.fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png")) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self.initialize_field_values_line_edit() def search_field_updated(self, index=None): self.initialize_field_values_line_edit() def initialize_field_values_line_edit(self): self.txt_alphanumeric_query.setLayer( self._layers[self.names.OP_PARCEL_T][LAYER]) idx = self._layers[self.names.OP_PARCEL_T][LAYER].fields().indexOf( self.cbo_parcel_fields.currentData()) self.txt_alphanumeric_query.setAttributeIndex(idx) def _set_context_menus(self): self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_basic.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_legal.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_property_record_card.setContextMenuPolicy( Qt.CustomContextMenu) self.tree_view_property_record_card.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_physical.customContextMenuRequested.connect( self.show_context_menu) self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_economic.customContextMenuRequested.connect( self.show_context_menu) def restart_dict_of_layers(self): self._layers = { self.names.OP_PLOT_T: { 'name': self.names.OP_PLOT_T, 'geometry': QgsWkbTypes.PolygonGeometry, LAYER: None }, self.names.OP_PARCEL_T: { 'name': self.names.OP_PARCEL_T, 'geometry': None, LAYER: None }, self.names.COL_UE_BAUNIT_T: { 'name': self.names.COL_UE_BAUNIT_T, 'geometry': None, LAYER: None } } def add_layers(self): self.qgis_utils.get_layers(self._db, self._layers, load=True) if not self._layers: self.restart_dict_of_layers() # Let it ready for the next call return None # Layer was found, listen to its removal so that we can deactivate the custom tool when that occurs try: self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.disconnect( self.layer_removed) except TypeError as e: pass self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.connect( self.layer_removed) # Layer was found, listen to its removal so that we can update the variable properly try: self._layers[ self.names.OP_PARCEL_T][LAYER].willBeDeleted.disconnect( self.parcel_layer_removed) except TypeError as e: pass self._layers[self.names.OP_PARCEL_T][LAYER].willBeDeleted.connect( self.parcel_layer_removed) # Layer was found, listen to its removal so that we can update the variable properly try: self._layers[ self.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.disconnect( self.uebaunit_table_removed) except TypeError as e: pass self._layers[self.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.connect( self.uebaunit_table_removed) def initialize_tool(self): self._layers[self.names.OP_PLOT_T][LAYER] = None self.initialize_tools(new_tool=None, old_tool=self.maptool_identify) self.btn_plot_toggled() def update_db_connection(self, db, ladm_col_db, db_source): self._db = db self.initialize_tool() if not ladm_col_db: self.setVisible(False) def layer_removed(self): # The required layer was removed, deactivate custom tool self.initialize_tool() def parcel_layer_removed(self): self._layers[self.names.OP_PARCEL_T][LAYER] = None def uebaunit_table_removed(self): self._layers[self.names.COL_UE_BAUNIT_T][LAYER] = None def fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Parcel Number"), self.names.OP_PARCEL_T_PARCEL_NUMBER_F) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Previous Parcel Number"), self.names.OP_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Folio de Matrícula Inmobiliaria"), self.names.OP_PARCEL_T_FMI_F) def initialize_tools(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.canvas.mapToolSet.disconnect(self.initialize_tools) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def btn_plot_toggled(self): if self.btn_identify_plot.isChecked(): self.prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.canvas.setMapTool(self.active_map_tool_before_custom) def prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.canvas.mapToolSet.connect(self.initialize_tools) if self._layers[self.names.OP_PLOT_T][LAYER] is None: self.add_layers() self.maptool_identify.setLayer( self._layers[self.names.OP_PLOT_T][LAYER]) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect(self.get_info_by_plot) def get_info_by_plot(self, plot_feature): plot_t_id = plot_feature[self.names.T_ID_F] self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER], [plot_feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) with OverrideCursor(Qt.WaitCursor): if not self.isVisible(): self.show() self.search_data_by_component(plot_t_id=plot_t_id, zoom_and_select=False) self._layers[self.names.OP_PLOT_T][LAYER].selectByIds( [plot_feature.id()]) def search_data_by_component(self, **kwargs): self._layers[self.names.OP_PLOT_T][LAYER].removeSelection() # Read zoom_and_select parameter and remove it from kwargs bZoom = False if 'zoom_and_select' in kwargs: bZoom = kwargs['zoom_and_select'] del kwargs['zoom_and_select'] records = self._db.get_igac_basic_info(**kwargs) self.setup_tree_view(self.tree_view_basic, records) if bZoom: # Zoom to resulting plots plot_t_ids = self.get_plot_t_ids_from_basic_info(records) if plot_t_ids: features = self.ladm_data.get_features_from_t_ids( self._layers[self.names.OP_PLOT_T][LAYER], self.names.T_ID_F, plot_t_ids, True, True) plot_ids = [feature.id() for feature in features] self.zoom_to_features_requested.emit( self._layers[self.names.OP_PLOT_T][LAYER], plot_ids, dict(), 500) self._layers[self.names.OP_PLOT_T][LAYER].selectByIds(plot_ids) records = self._db.get_igac_legal_info(**kwargs) self.setup_tree_view(self.tree_view_legal, records) records = self._db.get_igac_property_record_card_info(**kwargs) self.setup_tree_view(self.tree_view_property_record_card, records) records = self._db.get_igac_physical_info(**kwargs) self.setup_tree_view(self.tree_view_physical, records) records = self._db.get_igac_economic_info(**kwargs) self.setup_tree_view(self.tree_view_economic, records) def setup_tree_view(self, tree_view, records): """ Configure result tree views :param tree_view: :return: """ tree_view.setModel(TreeModel(self.names, data=records)) tree_view.expandAll() self.add_thumbnails_to_tree_view(tree_view) def add_thumbnails_to_tree_view(self, tree_view): """ Gets a list of model indexes corresponding to extFiles objects to show a preview :param model: :return: """ model = tree_view.model() indexes = model.getPixmapIndexList() for idx in indexes: url = model.data(idx, Qt.UserRole)['url'] res, image = self.download_image("{}{}".format( url, SUFFIX_GET_THUMBNAIL)) if res: pixmap = QPixmap() pixmap.loadFromData(image) label = QLabel() label.setPixmap(pixmap) tree_view.setIndexWidget(idx, label) def get_plot_t_ids_from_basic_info(self, records): res = [] if records: for record in records: if self.names.OP_PLOT_T in record: for element in record[self.names.OP_PLOT_T]: res.append(element['id']) return res def alphanumeric_query(self): """ Alphanumeric query """ option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == self.names.OP_PARCEL_T_FMI_F: self.search_data_by_component(parcel_fmi=query, zoom_and_select=True) elif option == self.names.OP_PARCEL_T_PARCEL_NUMBER_F: self.search_data_by_component(parcel_number=query, zoom_and_select=True) else: # previous_parcel_number self.search_data_by_component(previous_parcel_number=query, zoom_and_select=True) else: self.iface.messageBar().pushMessage( "Asistente LADM_COL", QCoreApplication.translate("DockWidgetQueries", "First enter a query")) def show_context_menu(self, point): tree_view = self.sender() index = tree_view.indexAt(point) context_menu = QMenu("Context menu") index_data = index.data(Qt.UserRole) if index_data is None: return if "value" in index_data: action_copy = QAction( QCoreApplication.translate("DockWidgetQueries", "Copy value")) action_copy.triggered.connect( partial(self.copy_value, index_data["value"])) context_menu.addAction(action_copy) context_menu.addSeparator() if "url" in index_data: action_open_url = QAction( QCoreApplication.translate("DockWidgetQueries", "Open URL")) action_open_url.triggered.connect( partial(self.open_url, index_data["url"])) context_menu.addAction(action_open_url) context_menu.addSeparator() # Configure actions for tables/layers if "type" in index_data and "id" in index_data: table_name = index_data["type"] table_package = LayerConfig.get_dict_table_package(self.names) t_id = index_data["id"] geometry_type = None if table_name in table_package and table_package[ table_name] == LADMNames.SPATIAL_UNIT_PACKAGE: # Layers in Spatial Unit package have double geometry, we need the polygon one geometry_type = QgsWkbTypes.PolygonGeometry if table_name == self.names.OP_PARCEL_T: if self._layers[ self.names.OP_PARCEL_T][LAYER] is None or self._layers[ self.names. OP_PLOT_T][LAYER] is None or self._layers[ self.names.COL_UE_BAUNIT_T][LAYER] is None: self.add_layers() layer = self._layers[self.names.OP_PARCEL_T][LAYER] self.iface.layerTreeView().setCurrentLayer(layer) else: layer = self.qgis_utils.get_layer(self._db, table_name, geometry_type, True) if layer is not None: if layer.isSpatial(): action_zoom_to_feature = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to {} with {}={}").format( table_name, self.names.T_ID_F, t_id)) action_zoom_to_feature.triggered.connect( partial(self.zoom_to_feature, layer, t_id)) context_menu.addAction(action_zoom_to_feature) if table_name == self.names.OP_PARCEL_T: # We show a handy option to zoom to related plots plot_ids = self.ladm_data.get_plots_related_to_parcels( self._db, [t_id], None, self._layers[self.names.OP_PLOT_T][LAYER], self._layers[self.names.COL_UE_BAUNIT_T][LAYER]) if plot_ids: action_zoom_to_plots = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to related plot(s)")) action_zoom_to_plots.triggered.connect( partial(self.zoom_to_plots, plot_ids)) context_menu.addAction(action_zoom_to_plots) action_open_feature_form = QAction( QCoreApplication.translate( "DockWidgetQueries", "Open form for {} with {}={}").format( table_name, self.names.T_ID_F, t_id)) action_open_feature_form.triggered.connect( partial(self.open_feature_form, layer, t_id)) context_menu.addAction(action_open_feature_form) if context_menu.actions(): context_menu.exec_(tree_view.mapToGlobal(point)) def copy_value(self, value): self.clipboard.setText(str(value)) def open_url(self, url): webbrowser.open(url) def zoom_to_feature(self, layer, t_id): feature = self.get_feature_from_t_id(layer, t_id) self.iface.mapCanvas().zoomToFeatureIds(layer, [feature.id()]) self.canvas.flashFeatureIds(layer, [feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) def open_feature_form(self, layer, t_id): feature = self.get_feature_from_t_id(layer, t_id) self.iface.openFeatureForm(layer, feature) def get_feature_from_t_id(self, layer, t_id): field_idx = layer.fields().indexFromName(self.names.T_ID_F) request = QgsFeatureRequest( QgsExpression("{}={}".format(self.names.T_ID_F, t_id))) request.setFlags(QgsFeatureRequest.NoGeometry) iterator = layer.getFeatures(request) feature = QgsFeature() res = iterator.nextFeature(feature) if res: return feature return None def zoom_to_plots(self, plot_ids): self.iface.mapCanvas().zoomToFeatureIds( self._layers[self.names.OP_PLOT_T][LAYER], plot_ids) self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER], plot_ids, QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) def closeEvent(self, event): try: self.canvas.mapToolSet.disconnect(self.initialize_tools) except TypeError as e: pass self.canvas.setMapTool(self.active_map_tool_before_custom) def download_image(self, url): res = False img = None msg = {'text': '', 'level': Qgis.Warning} if url: self.logger.info(__name__, "Downloading file from {}".format(url)) msg = "Downloading image from document repository (this might take a while)..." with ProcessWithStatus(msg): if self.qgis_utils.is_connected(TEST_SERVER): nam = QNetworkAccessManager() request = QNetworkRequest(QUrl(url)) reply = nam.get(request) loop = QEventLoop() reply.finished.connect(loop.quit) loop.exec_() status = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) if status == 200: res = True img = reply.readAll() else: res = False msg['text'] = QCoreApplication.translate( "SettingsDialog", "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL." ) else: res = False msg['text'] = QCoreApplication.translate( "SettingsDialog", "There was a problem connecting to Internet.") else: res = False msg['text'] = QCoreApplication.translate("SettingsDialog", "Not valid URL") if not res: self.logger.log_message(__name__, msg['text'], msg['level']) return (res, img)
class FeatureSelectorWidget(QWidget): featureIdentified = pyqtSignal(QgsFeature) def __init__(self, parent): QWidget.__init__(self, parent) editLayout = QHBoxLayout() editLayout.setContentsMargins(0, 0, 0, 0) editLayout.setSpacing(2) self.setLayout(editLayout) self.lineEdit = QLineEdit(self) self.lineEdit.setReadOnly(True) editLayout.addWidget(self.lineEdit) self.highlightFeatureButton = QToolButton(self) self.highlightFeatureButton.setPopupMode(QToolButton.MenuButtonPopup) self.highlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionHighlightFeature.svg"), "Highlight feature", self) self.scaleHighlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionScaleHighlightFeature.svg"), "Scale and highlight feature", self) self.panHighlightFeatureAction = QAction(QgsApplication.getThemeIcon("/mActionPanHighlightFeature.svg"), "Pan and highlight feature", self) self.highlightFeatureButton.addAction(self.highlightFeatureAction) self.highlightFeatureButton.addAction(self.scaleHighlightFeatureAction) self.highlightFeatureButton.addAction(self.panHighlightFeatureAction) self.highlightFeatureButton.setDefaultAction(self.highlightFeatureAction) editLayout.addWidget(self.highlightFeatureButton) self.mapIdentificationButton = QToolButton(self) self.mapIdentificationButton.setIcon(QgsApplication.getThemeIcon("/mActionMapIdentification.svg")) self.mapIdentificationButton.setText("Select on map") self.mapIdentificationButton.setCheckable(True) editLayout.addWidget(self.mapIdentificationButton) self.mapIdentificationButton.clicked.connect(self.mapIdentification) self.highlightFeatureButton.triggered.connect(self.highlightActionTriggered) self.layer = None self.mapTool = None self.canvas = None self.windowWidget = None self.highlight = None self.feature = QgsFeature() def setCanvas(self, mapCanvas): self.mapTool = QgsMapToolIdentifyFeature(mapCanvas) self.mapTool.setButton(self.mapIdentificationButton) self.canvas = mapCanvas def setLayer(self, layer): self.layer = layer def setFeature(self, feature, canvasExtent = CanvasExtent.Fixed): self.lineEdit.clear() self.feature = feature if not self.feature.isValid() or self.layer is None: return featureTitle = feature.attribute(self.layer.displayField()) if featureTitle == '': featureTitle = feature.id() self.lineEdit.setText(str(featureTitle)) self.highlightFeature(canvasExtent) def clear(self): self.feature = QgsFeature() self.lineEdit.clear() def mapIdentification(self): if self.layer is None or self.mapTool is None or self.canvas is None: return self.mapTool.setLayer(self.layer) self.canvas.setMapTool(self.mapTool) self.windowWidget = QWidget.window(self) self.canvas.window().raise_() self.canvas.activateWindow() self.canvas.setFocus() self.mapTool.featureIdentified.connect(self.mapToolFeatureIdentified) self.mapTool.deactivated.connect(self.mapToolDeactivated) def mapToolFeatureIdentified(self, feature): feature = QgsFeature(feature) self.featureIdentified.emit(feature) self.unsetMapTool() self.setFeature(feature) def mapToolDeactivated(self): if self.windowWidget is not None: self.windowWidget.raise_() self.windowWidget.activateWindow() def highlightFeature(self, canvasExtent = CanvasExtent.Fixed): if self.canvas is None or not self.feature.isValid(): return geom = self.feature.geometry() if geom is None: return if canvasExtent == CanvasExtent.Scale: featBBox = geom.boundingBox() featBBox = self.canvas.mapSettings().layerToMapCoordinates(self.layer, featBBox) extent = self.canvas.extent() if not extent.contains(featBBox): extent.combineExtentWith(featBBox) extent.scale(1.1) self.canvas.setExtent(extent) self.canvas.refresh() elif canvasExtent == CanvasExtent.Pan: centroid = geom.centroid() center = centroid.asPoint() center = self.canvas.mapSettings().layerToMapCoordinates(self.layer, center) self.canvas.zoomByFactor(1.0, center) # refresh is done in this method # highlight self.delete_highlight() self.highlight = QgsHighlight(self.canvas, geom, self.layer) settings = QSettings() color = QColor(settings.value("/Map/highlight/color", QGis.DEFAULT_HIGHLIGHT_COLOR.name())) alpha = int(settings.value("/Map/highlight/colorAlpha", QGis.DEFAULT_HIGHLIGHT_COLOR.alpha())) buffer = 2*float(settings.value("/Map/highlight/buffer", QGis.DEFAULT_HIGHLIGHT_BUFFER_MM)) min_width = 2*float(settings.value("/Map/highlight/min_width", QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM)) self.highlight.setColor(color) # sets also fill with default alpha color.setAlpha(alpha) self.highlight.setFillColor(color) # sets fill with alpha self.highlight.setBuffer(buffer) self.highlight.setMinWidth(min_width) self.highlight.setWidth(4.0) self.highlight.show() self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.timeout.connect(self.delete_highlight) self.timer.start(3000) def delete_highlight(self): if self.highlight is not None: self.highlight.hide() del self.highlight self.highlight = None def unsetMapTool(self): if self.canvas is not None and self.mapTool is not None: # this will call mapToolDeactivated self.canvas.unsetMapTool(self.mapTool) def highlightActionTriggered(self, action): self.highlightFeatureButton.setDefaultAction(action) if action == self.highlightFeatureAction: self.highlightFeature() elif action == self.scaleHighlightFeatureAction: self.highlightFeature(CanvasExtent.Scale) elif action == self.panHighlightFeatureAction: self.highlightFeature(CanvasExtent.Pan)
def setCanvas(self, mapCanvas): self.mapTool = QgsMapToolIdentifyFeature(mapCanvas) self.mapTool.setButton(self.mapIdentificationButton) self.canvas = mapCanvas
def __init__(self, canvas, vlayer, toolbar): QgsMapToolIdentifyFeature.__init__(self, canvas, vlayer) self.canvas = canvas self.vlayer = vlayer self.toolbar = toolbar self.featureIdentified.connect(self.select_rdpoly)
class CandRRedistrict(object): """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgisInterface """ # Save reference to the QGIS interface self.iface = iface # QgsMapTool.__init(self, self.iface.mapCanvas()) self.canvas = self.iface.mapCanvas() self.canvas.setMouseTracking(True) # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'CandRRedistrict_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Arrowsmith Redistricter') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'CandRRedistrict') self.toolbar.setObjectName(u'CandRRedistrict') #print "** INITIALIZING CandRRedistrict" # variables to initialise self.pluginIsActive = False self.dockwidget = None #variable for the main dock self.attrdockwidget = None #variable for the attribute table dock self.dlgparameters = None #variable for the parameters dialog self.dlgtoolbox = None #variable for the toolbox dialog self.dlgelectorates = None #variable for the electorates dialog self.featIdentTool = None #make sure we can use the identify tool in the code self.districts = None #number of districts in the tool self.activedistrict = '1' #which district is active. We use string literals self.activeLayer = None #which layer is active - which layer we're reapportioning self.popfield = None #the population field in the database self.distfield = None #the district field in the database self.totalpop = 0 #the total population self.targetpop = 0 #the target population self.targetpoppct = 0 #target population percentage tolerance self.targetpoplower = 0 #target pop lower bound self.targetpophigher = 0 #target pop upper bound # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('CandRRedistrict', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/CandRRedistricter/icon.png' self.add_action(icon_path, text=self.tr(u'Arrowsmith Redistricter'), callback=self.run, parent=self.iface.mainWindow()) #-------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" #print "** CLOSING CandRRedistrict" # disconnects self.attrdockwidget.closingPlugin.disconnect(self.onClosePlugin) self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) # remove this statement if dockwidget is to remain # for reuse if plugin is reopened # Commented next statement since it causes QGIS crashe # when closing the docked window: # self.dockwidget = None self.pluginIsActive = False def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" #print "** UNLOAD CandRRedistrict" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&Arrowsmith Redistricter'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar #-------------------------------------------------------------------------- def run(self): """Run method that loads and starts the plugin""" if not self.pluginIsActive: self.pluginIsActive = True #print "** STARTING CandRRedistrict" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = CandRRedistrictDockWidget() if self.attrdockwidget == None: self.attrdockwidget = CandRRedistrictAttrDockWidget() if self.dlgparameters == None: self.dlgparameters = CandRRedistrictDlgParameter() if self.dlgtoolbox == None: self.dlgtoolbox = CandRRedistrictDlgToolbox() if self.dlgelectorates == None: self.dlgelectorates = CandRRedistrictDlgElectorates() # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) #provide other gui options self.dockwidget.btnParameters.clicked.connect( self.openParametersDialog) self.dockwidget.btnUpdate.clicked.connect(self.updateAttributes) self.dockwidget.btnEraser.clicked.connect(self.setEraser) self.dockwidget.btnSelect.clicked.connect( self.updateSelectedElectorate) # self.dockwidget.btnCompactness.clicked.connect(self.showCompactness) self.dockwidget.btnToolbox.clicked.connect(self.openToolbox) # self.dockwidget.btnToolbox.clicked.connect(self.enclaveRemover) self.dockwidget.sliderDistricts.valueChanged.connect( self.updateDistrict) self.attrdockwidget.tblPop.itemClicked.connect( self.updateLockedFields) self.dlgparameters.cmbActiveLayer.currentIndexChanged.connect( self.updateFields) self.dlgparameters.boxButton.button( QDialogButtonBox.Ok).clicked.connect(self.saveParameters) self.dlgparameters.btnAddDataField.clicked.connect( self.addDataField) self.dlgparameters.btnRemoveDataField.clicked.connect( self.removeDataField) self.dlgparameters.btnLoadParameters.clicked.connect( self.loadParameters) self.dlgtoolbox.btnExportToCsv.clicked.connect(self.exportToCsv) self.dlgtoolbox.btnRename.clicked.connect(self.renameElectorates) self.dlgelectorates.boxButton.button( QDialogButtonBox.Ok).clicked.connect(self.updateElectorates) # show the dockwidget # TODO: fix to allow choice of dock location self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget) self.dockwidget.show() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.attrdockwidget) self.attrdockwidget.show() def canvasReleaseEvent(self, event): QgsMessageLog.logMessage("released!") with edit(self.activeLayer): selection = self.activeLayer.selectedFeatures() for feature in selection: feature[self.distfield] = self.activedistrict def updateAttributes(self): global locked QgsMessageLog.logMessage("released!") selection = self.activeLayer.selectedFeatures() field_id = self.activeLayer.fieldNameIndex(self.distfield) self.activeLayer.startEditing() for feature in selection: try: if locked[districtId[str(feature[self.distfield])]] == 0: self.updateFeatureValue(feature) except: self.updateFeatureValue(feature) # QgsMessageLog.logMessage(str(feature.id) + " changed to: " + str(self.activedistrict) + " on " + str(field_id)) self.activeLayer.commitChanges() self.activeLayer.removeSelection() self.updateTable() def updateFeatureValue(self, feature): QgsMessageLog.logMessage("updating feature value") global distPop field_id = self.activeLayer.fieldNameIndex(self.distfield) try: distPop[int(districtId[str( feature[self.distfield])])] = distPop[int(districtId[str( feature[self.distfield])])] - feature[ self.popfield] # feature[self.popfield] QgsMessageLog.logMessage( "from: " + str(districtId[str(feature[self.distfield])])) except: try: distPop[0] = distPop[0] - feature[self.popfield] QgsMessageLog.logMessage("from: zer0") except: errors = 1 QgsMessageLog.logMessage(self.distfield + " failed on load") for d in dataFieldList: try: d.field_sum[int(districtId[str( feature[self.distfield])])] = d.field_sum[int( districtId[str( feature[self.distfield])])] - feature[d.name] d.total_sum = d.total_sum - feature[d.name] except: d.field_sum[0] = d.field_sum[0] - feature[d.name] d.total_sum = d.total_sum - feature[d.name] QgsMessageLog.logMessage(districtId[str(feature[self.distfield])]) self.activeLayer.changeAttributeValue( feature.id(), field_id, districtName[self.activedistrict]) newId = int(districtId[str(districtName[self.activedistrict])]) try: distPop[newId] = distPop[newId] + feature[self.popfield] QgsMessageLog.logMessage("to: " + str(newId)) except: try: distPop[0] = distPop[0] + feature[self.popfield] QgsMessageLog.logMessage("to: zer0") except: errors = 1 QgsMessageLog.logMessage(self.distfield + " failed on load") for d in dataFieldList: try: d.field_sum[newId] = d.field_sum[newId] + feature[d.name] d.total_sum = d.total_sum + feature[d.name] except: d.field_sum[0] = d.field_sum[0] + feature[d.name] d.total_sum = d.total_sum + feature[d.name] def openParametersDialog(self): self.dlgparameters.show() layers = self.iface.legendInterface().layers() layer_list = [] for layer in layers: layer_list.append(layer.name()) self.dlgparameters.cmbActiveLayer.clear() self.dlgparameters.cmbActiveLayer.addItems(layer_list) if self.activeLayer != None: self.dlgparameters.cmbActiveLayer.setCurrentIndex( self.dlgparameters.cmbActiveLayer.findText( self.activeLayer.name())) self.setParameters() def openToolbox(self): self.dlgtoolbox.show() def saveParametersToFile(self): # try: f = open(self.activeLayer.source() + '.qgis.red', 'w') f.write(str(self.districts) + '\n') f.write(str(self.totalpop) + '\n') f.write(str(self.targetpop) + '\n') f.write(str(self.targetpoplower) + '\n') f.write(str(self.targetpophigher) + '\n') f.write(str(self.popfield) + '\n') f.write(str(self.distfield) + '\n') counter = 0 for d in dataFieldList: counter = counter + 1 f.write(str(counter) + '\n') for d in dataFieldList: f.write(d.name + '\n') f.write(str(d.type) + '\n') f.write(str(len(districtName)) + '\n') for r in districtName: f.write(str(districtName[r]) + '\n') def updateLockedFields(self): QgsMessageLog.logMessage("Locking...") global locked locked = {} for r in range(0, self.districts + 1): locked[districtId[str(r)]] = 0 if self.attrdockwidget.tblPop.item(r, 1).checkState() == Qt.Checked: #flock QgsMessageLog.logMessage((districtId[str(r)]) + " Locked") locked[districtId[str(r)]] = 1 def loadParameters(self): # try: layers = self.iface.legendInterface().layers() selectedLayerIndex = self.dlgparameters.cmbActiveLayer.currentIndex() selectedLayer = layers[selectedLayerIndex] f = open(selectedLayer.source() + '.qgis.red', 'r') self.districts = f.readline() self.districts = int(self.districts) self.totalpop = f.readline() self.totalpop = int(self.totalpop) self.targetpop = f.readline() self.targetpop = int(self.targetpop) self.targetpoplower = f.readline() self.targetpoplower = int(self.targetpoplower) self.targetpophigher = f.readline() self.targetpophigher = int(self.targetpophigher) self.popfield = f.readline().rstrip() self.distfield = f.readline().rstrip() fieldparams = int(f.readline()) self.setParameters() del dataFieldList[:] for fp in range(0, fieldparams): newfield = f.readline().rstrip() newfieldtype = int(f.readline()) df = DataField([newfield, newfieldtype]) loader = f.readline() loader_int = int(loader) for fn in range(0, loader_int): tmpDistrictName = f.readline().rstrip() districtName[fn] = tmpDistrictName if str(tmpDistrictName) not in districtId: districtId[str(tmpDistrictName)] = str(fn) # self.updateDistricts() self.updateFieldTable() # except: #QgsMessageLog.logMessage("Save file failed to load") def setParameters(self): self.dlgparameters.inpDistricts.setValue(self.districts) self.dlgparameters.cmbPopField.setCurrentIndex( (self.dlgparameters.cmbPopField.findText(self.popfield))) self.dlgparameters.cmbDistField.setCurrentIndex( (self.dlgparameters.cmbDistField.findText(self.distfield))) self.updateFieldTable() def updateDistricts(self): try: if len(districtName) < self.districts: counter = 1 for p in range(len(districtName), self.districts + 1): if str(p) not in districtName: districtName[p] = str(p) else: while (str(self.districts + counter) in districtName) or (counter < 10000): counter = counter + 1 districtName[p] = str(self.districts + counter) if districtName[p] not in districtId: districtId[str(p)] = str(p) QgsMessageLog.logMessage("Updating districts:") QgsMessageLog.logMessage(format(districtName)) QgsMessageLog.logMessage(format(districtId)) except: QgsMessageLog.logMessage("No map loaded") def saveParameters(self): self.updateDistricts() layers = self.iface.legendInterface().layers() selectedLayerIndex = self.dlgparameters.cmbActiveLayer.currentIndex() selectedLayer = layers[selectedLayerIndex] self.activeLayer = selectedLayer self.districts = self.dlgparameters.inpDistricts.value() self.activedistrict = 1 self.dockwidget.lblActiveDistrict.setText("Active District: " + str(self.activedistrict)) self.dockwidget.sliderDistricts.setMinimum(1) self.dockwidget.sliderDistricts.setMaximum(self.districts) self.dockwidget.sliderDistricts.setValue(1) self.popfield = self.dlgparameters.cmbPopField.currentText() self.distfield = self.dlgparameters.cmbDistField.currentText() # self.dispfield1 = self.dlgparameters.cmbDispField1.currentText() # self.dispfield2 = self.dlgparameters.cmbDispField1.currentText() QgsMessageLog.logMessage("Popfield:" + str(self.popfield)) self.totalpop = 0 self.targetpop = 0 for feature in self.activeLayer.getFeatures(): self.totalpop = self.totalpop + feature[self.popfield] self.targetpop = int(self.totalpop / self.districts) self.targetpoppct = self.dlgparameters.inpTolerance.value() targetpoprem = int((self.targetpop / 100) * self.targetpoppct) self.targetpoplower = int(self.targetpop - targetpoprem) self.targetpophigher = int(self.targetpop + targetpoprem + 1) QgsMessageLog.logMessage("TargetPop:" + str(self.targetpop) + "(" + str(self.targetpoplower) + ", " + str(self.targetpophigher) + ")") QgsMessageLog.logMessage("Districts:" + str(self.districts)) self.dockwidget.lblMainInfo.setText("Active Layer: " + self.activeLayer.name() + "\nActive District Field: " + self.distfield + "\nTarget Population: " + str(self.targetpop) + " (" + str(self.targetpoplower) + ", " + str(self.targetpophigher) + ")") self.attrdockwidget.tblPop.setRowCount(self.districts + 1) numDataFields = 0 for d in dataFieldList: numDataFields = numDataFields + 1 self.attrdockwidget.tblPop.setHorizontalHeaderItem( 2 + numDataFields, QTableWidgetItem(d.name)) self.attrdockwidget.tblPop.setColumnCount(4 + numDataFields) for r in range(0, self.districts + 1): chkBoxItem = QTableWidgetItem() chkBoxItem.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) chkBoxItem.setCheckState(Qt.Unchecked) self.attrdockwidget.tblPop.setItem(r, 1, chkBoxItem) self.attrdockwidget.tblPop.setHorizontalHeaderLabels( ['#', 'Lock', 'Population', 'To Target']) numDataFields = 0 for d in dataFieldList: numDataFields = numDataFields + 1 if d.type == 1: self.attrdockwidget.tblPop.setHorizontalHeaderItem( 3 + numDataFields, QTableWidgetItem(d.name)) else: self.attrdockwidget.tblPop.setHorizontalHeaderItem( 3 + numDataFields, QTableWidgetItem(d.name + '%')) if len(districtName) == 0: self.initializeElectorates() try: self.saveParametersToFile() QgsMessageLog.logMessage("Parameters file saved!") except: QgsMessageLog.logMessage("Parameters file could not be saved") if self.dlgparameters.chkStyleMap.isChecked(): categories = [] for cat in range(0, self.districts + 1): symbol = QgsSymbolV2.defaultSymbol( self.activeLayer.geometryType()) layer_style = {} layer_style['color'] = '%d, %d, %d' % (randrange( 0, 256), randrange(0, 256), randrange(0, 256)) layer_style['outline'] = '#000000' symbol_layer = QgsSimpleFillSymbolLayerV2.create(layer_style) # replace default symbol layer with the configured one if symbol_layer is not None: symbol.changeSymbolLayer(0, symbol_layer) # create renderer object category = QgsRendererCategoryV2(cat, symbol, str(cat)) # entry for the list of category items categories.append(category) renderer = QgsCategorizedSymbolRendererV2(self.distfield, categories) # assign the created renderer to the layer if renderer is not None: self.activeLayer.setRendererV2(renderer) self.activeLayer.triggerRepaint() self.updateFieldValues() self.updateTable() self.updateLockedFields() self.updateDistricts() def updateDistrict(self): self.activedistrict = self.dockwidget.sliderDistricts.value() QgsMessageLog.logMessage("Active District:" + str(districtName[self.activedistrict])) self.dockwidget.lblActiveDistrict.setText( "Active district: " + str(districtName[self.activedistrict])) def updateFieldValues(self): global distPop QgsMessageLog.logMessage("Updating Field Values") QgsMessageLog.logMessage(format(districtName)) QgsMessageLog.logMessage(format(districtId)) numDataFields = 0 for d in dataFieldList: del d.field_sum[:] for p in range(0, self.districts + 1): d.field_sum.append(p) d.field_sum[p] = 0 d.total_sum = 0 numDataFields = numDataFields + 1 for p in range(0, self.districts + 1): distPop[p] = 0 for feature in self.activeLayer.getFeatures(): try: distPop[int(districtId[str( feature[self.distfield])])] = distPop[int(districtId[str( feature[self.distfield])])] + feature[self.popfield] except: try: distPop[0] = distPop[0] + feature[self.popfield] except: errors = 1 # QgsMessageLog.logMessage(self.distfield + " failed on load") for d in dataFieldList: try: d.field_sum[int(districtId[str( feature[self.distfield])])] = d.field_sum[int( districtId[str( feature[self.distfield])])] + feature[d.name] d.total_sum = d.total_sum + feature[d.name] except: d.field_sum[0] = d.field_sum[0] + feature[d.name] d.total_sum = d.total_sum + feature[d.name] def updateTable(self): QgsMessageLog.logMessage("Updating Table") global distPop print(distPop) for p in range(0, self.districts + 1): self.attrdockwidget.tblPop.setItem( p, 0, QTableWidgetItem(str(districtName[p]))) self.attrdockwidget.tblPop.setItem( p, 2, QTableWidgetItem(str(distPop[p]))) self.attrdockwidget.tblPop.setItem( p, 3, QTableWidgetItem(str(self.targetpop - distPop[p]))) self.attrdockwidget.tblPop.item(p, 0).setBackground( QColor(255, 255, 255)) self.attrdockwidget.tblPop.item(p, 2).setBackground( QColor(255, 255, 255)) self.attrdockwidget.tblPop.item(p, 3).setBackground( QColor(255, 255, 255)) if distPop[p] >= self.targetpoplower and distPop[ p] <= self.targetpophigher: self.attrdockwidget.tblPop.item(p, 0).setBackground( QColor(0, 200, 0)) self.attrdockwidget.tblPop.item(p, 2).setBackground( QColor(0, 200, 0)) self.attrdockwidget.tblPop.item(p, 3).setBackground( QColor(0, 200, 0)) rowNum = 0 for d in dataFieldList: rowNum = rowNum + 1 if d.type == 1: self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem(str(d.field_sum[p]))) elif d.type == 2: if distPop[p] > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(distPop[p])) self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem( str( round( float( float(d.field_sum[p]) / float(distPop[p])) * 100, 2)) + '%')) else: self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem('0.00%')) elif d.type == 3: if self.totalpop > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(self.totalpop)) self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem( str( round( float( float(d.field_sum[p]) / float(self.totalpop)) * 100, 2)) + '%')) else: self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem('0.00%')) elif d.type == 4: if d.total_sum > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(d.total_sum)) self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem( str( round( float( float(d.field_sum[p]) / float(d.total_sum)) * 100, 2)) + '%')) else: self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem('0.00%')) self.attrdockwidget.tblPop.resizeColumnToContents(0) self.attrdockwidget.tblPop.resizeColumnToContents(1) self.attrdockwidget.tblPop.resizeColumnToContents(2) self.attrdockwidget.tblPop.resizeColumnToContents(3) def addDataField(self): f = DataField([ self.dlgparameters.cmbDataField.currentText(), self.dlgparameters.cmbDataType.currentText() ]) self.updateFieldTable() def removeDataField(self): indexes = self.dlgparameters.tblDataFields.selectionModel( ).selectedRows() counter = 0 for f in dataFieldList: for g in indexes: if counter == g.row(): dataFieldList.remove(f) counter = counter + 1 self.updateFieldTable() def updateFieldTable(self): tblRows = 0 for d in dataFieldList: tblRows = tblRows + 1 self.dlgparameters.tblDataFields.setRowCount(tblRows) self.dlgparameters.tblDataFields.setColumnCount(2) tblRows = 0 for d in dataFieldList: self.dlgparameters.tblDataFields.setItem(tblRows, 0, QTableWidgetItem(d.name)) # QgsMessageLog.logMessage("Districts:" + str(d.type)) if d.type == 1: self.dlgparameters.tblDataFields.setItem( tblRows, 1, QTableWidgetItem('Sum')) elif d.type == 2: self.dlgparameters.tblDataFields.setItem( tblRows, 1, QTableWidgetItem('% of district pop')) elif d.type == 3: self.dlgparameters.tblDataFields.setItem( tblRows, 1, QTableWidgetItem('% of total pop')) elif d.type == 4: self.dlgparameters.tblDataFields.setItem( tblRows, 1, QTableWidgetItem('% of field')) elif d.type == 99: self.dlgparameters.tblDataFields.setItem( tblRows, 1, QTableWidgetItem('population')) tblRows = tblRows + 1 def updateFields(self): print("updateFields") self.dlgparameters.cmbPopField.clear() self.dlgparameters.cmbDistField.clear() self.dlgparameters.cmbDataField.clear() self.dlgparameters.cmbDataType.clear() # self.dlgparameters.cmbDispField1.clear() # self.dlgparameters.cmbDispField2.clear() layers = self.iface.legendInterface().layers() selectedLayerIndex = self.dlgparameters.cmbActiveLayer.currentIndex() selectedLayer = layers[selectedLayerIndex] fields = selectedLayer.pendingFields() field_names = [field.name() for field in fields] self.dlgparameters.cmbPopField.addItems(field_names) self.dlgparameters.cmbDistField.addItems(field_names) # self.dlgparameters.cmbDispField1.addItems(["None"]) # self.dlgparameters.cmbDispField2.addItems(["None"]) self.dlgparameters.cmbDataField.addItems(field_names) self.dlgparameters.cmbDataType.addItems( ['Sum', '% of Dist. Pop', '% of Total Pop', '% of Field']) # self.dlgparameters.cmbDispField2.addItems(field_names) selectedLayerIndex = self.dlgparameters.cmbActiveLayer.currentIndex() selectedLayer = layers[selectedLayerIndex] loadFile = selectedLayer.source() + '.qgis.red' QgsMessageLog.logMessage('loadfile: ' + loadFile) if os.path.isfile(loadFile) == True: self.dlgparameters.btnLoadParameters.setEnabled(True) else: self.dlgparameters.btnLoadParameters.setEnabled(False) def showCompactness(self): field_id = self.activeLayer.fieldNameIndex(self.distfield) QgsMessageLog.logMessage("Starting...") QgsMessageLog.logMessage(self.activeLayer.source()) QgsMessageLog.logMessage(self.activeLayer.name()) ogr2ogr.main([ '', self.activeLayer.name() + '_compactness.shp', self.activeLayer.source(), '-dialect', 'sqlite', '-sql', 'SELECT ST_Union(geometry), ' + self.distfield + ' from ' + self.activeLayer.name() + ' GROUP BY ' + self.distfield ]) QgsMessageLog.logMessage("...done.") # QgsGeometryAnalyzer().dissolve(self.activeLayer, self.activeLayer.name() + "_compactness.shp", onlySelectedFeatures=False,uniqueIdField=field_id, p=True) comp_layer = QgsVectorLayer( self.activeLayer.name() + "_compactness.shp", "Compactness Report", "ogr") if comp_layer.isValid(): QgsMessageLog.logMessage("valid layer!.") comp_layer.startEditing() comp_layer.dataProvider().addAttributes([ QgsField("Area", QVariant.Double), QgsField("Perimeter", QVariant.Double), QgsField("Contiguous", QVariant.Int) ]) comp_layer.updateFields() area = 0 for feature in comp_layer.getFeatures(): calculator = QgsDistanceArea() calculator.setEllipsoid('WGS84') calculator.setEllipsoidalMode(True) calculator.computeAreaInit() geom = gFeat.geometry() landArea = feature['Area'] if geom.isMultipart(): polyg = geom.asPolygon() if len(polyg) > 0: area = calculator.measurePolygon(polyg[0]) landArea = area else: multi = geom.asMultiPolygon() for polyg in multi: area = area + calculator.measurePolygon(polyg[0]) landArea = area comp_layer.commitChanges() def setEraser(self): if self.activedistrict == 0: self.activedistrict = self.dockwidget.sliderDistricts.value() self.dockwidget.lblActiveDistrict.setText("Active District: " + str(self.activedistrict)) else: self.activedistrict = 0 self.dockwidget.lblActiveDistrict.setText("Eraser Active") def exportToCsv(self): saveFileName, __ = QFileDialog.getSaveFileName(None) if saveFileName: with open(saveFileName, 'w') as csvFile: csvWriter = csv.writer(csvFile, delimiter=',', quoting=csv.QUOTE_MINIMAL) headerWriter = ['District', 'Population', 'To Target'] for d in dataFieldList: headerWriter.append(d.name) csvWriter.writerow(headerWriter) for p in range(0, self.districts + 1): rowWriter = [str(p)] rowWriter.append(str(distPop[p])) rowWriter.append(str(self.targetpop - distPop[p])) for d in dataFieldList: if d.type == 1: self.attrdockwidget.tblPop.setItem( p, 3 + rowNum, QTableWidgetItem(str(d.field_sum[p]))) elif d.type == 2: if distPop[p] > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(distPop[p])) rowWriter.append( str( round( float( float(d.field_sum[p]) / float(distPop[p])) * 100, 2)) + '%') else: rowWriter.append('0.00%') elif d.type == 3: if self.totalpop > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(self.totalpop)) rowWriter.append( str( round( float( float(d.field_sum[p]) / float(self.totalpop)) * 100, 2)) + '%') else: rowWriter.append('0.00%') elif d.type == 4: if d.total_sum > 0: QgsMessageLog.logMessage( str(d.field_sum[p]) + " " + str(d.total_sum)) rowWriter.append( str( round( float( float(d.field_sum[p]) / float(d.total_sum)) * 100, 2)) + '%') else: rowWriter.append('0.00%') csvWriter.writerow(rowWriter) def enclaveRemover(self): field_id = self.activeLayer.fieldNameIndex(self.distfield) self.activeLayer.startEditing() # Create a dictionary of all features feature_dict = {f.id(): f for f in self.activeLayer.getFeatures()} QgsMessageLog.logMessage("Building spatial index...") # Build a spatial index index = QgsSpatialIndex() for f in list(feature_dict.values()): index.insertFeature(f) QgsMessageLog.logMessage("Finding neighbors...") # Loop through all features and find features that touch each feature for f in list(feature_dict.values()): geom = f.geometry() # Find all features that intersect the bounding box of the current feature. # We use spatial index to find the features intersecting the bounding box # of the current feature. This will narrow down the features that we need # to check neighboring features. intersecting_ids = index.intersects(geom.boundingBox()) # Initalize neighbors list and sum neighbors = [] neighbors_district = -1 finished = 0 if f[self.distfield] == 0: QgsMessageLog.logMessage("feature " + str(f.id()) + " with null distfield found!") while neighbors_district != -2 and finished == 0: finished = 0 for intersecting_id in intersecting_ids: # Look up the feature from the dictionary intersecting_f = feature_dict[intersecting_id] QgsMessageLog.logMessage("Neighbor found!") # For our purpose we consider a feature as 'neighbor' if it touches or # intersects a feature. We use the 'disjoint' predicate to satisfy # these conditions. So if a feature is not disjoint, it is a neighbor. if (f != intersecting_f and not intersecting_f.geometry().disjoint(geom)): if intersecting_f[self.distfield] > 0: QgsMessageLog.logMessage( "Neighbor found with > 0!") if neighbors_district == -1: neighbors_district = intersecting_f[ self.distfield] QgsMessageLog.logMessage( "neighbors_district set to " + str(neighbors_district)) elif neighbors_district != intersecting_f[ self.distfield]: neighbors_district = -2 QgsMessageLog.logMessage( "neighbors_district set to " + str(neighbors_district) + ", " + str(intersecting_f[self.distfield]) + " not matching") if neighbors_district > 0: QgsMessageLog.logMessage( str(f.id()) + " updating district to " + str(neighbors_district)) self.activeLayer.changeAttributeValue( f.id(), field_id, neighbors_district) # Update the layer with new attribute values. finished = 1 self.activeLayer.commitChanges() def renameElectorates(self): self.dlgelectorates.show() self.dlgtoolbox.hide() txtBox = '' # try: for d, val in list(districtId.items()): if d != '0': # QgsMessageLog.logMessage("looping through " + str(val)) txtBox = txtBox + str(val) + '\n' self.dlgelectorates.txtElectorates.setPlainText(txtBox) # except: # just to give the error checker something to do # txtBox = '' def initializeElectorates(self): global districtId global districtName QgsMessageLog.logMessage("initializeElectorates called") counter = 1 districtId = {} districtName = {} districtName[0] = str("0", "utf-8") districtId[str("0", "utf-8")] = 0 for j in range(counter, self.districts + 1): districtName[counter] = str(str(counter), "utf-8") districtId[str(str(counter), "utf-8")] = counter counter = counter + 1 QgsMessageLog.logMessage(format(districtName)) QgsMessageLog.logMessage(format(districtId)) self.saveParametersToFile() self.updateFieldValues() self.updateTable() def updateElectorates(self): global districtId global districtName QgsMessageLog.logMessage("updateElectorates called") electorates = self.dlgelectorates.txtElectorates.toPlainText() electorateNames = electorates.split('\n') counter = 1 districtId = {} districtName = {} districtName[0] = str(str(0), "utf-8") districtId[str(str(0), "utf-8")] = 0 for i in electorateNames: if counter <= self.districts: districtName[counter] = i districtId[str(str(i), "utf-8")] = counter counter = counter + 1 QgsMessageLog.logMessage(i) if counter > self.districts: for j in range(counter, self.districts): districtName[counter] = str(str(counter), "utf-8") districtId[str(str(counter), "utf-8")] = counter counter = counter + 1 QgsMessageLog.logMessage(format(districtName)) QgsMessageLog.logMessage(format(districtId)) self.saveParametersToFile() self.updateFieldValues() self.updateTable() self.updateLockedFields() def updateSelectedElectorate(self): self.dockwidget.lblActiveDistrict.setText("Click on the map...") self.featIdentTool = QgsMapToolIdentifyFeature(self.canvas) self.featIdentTool.featureIdentified.connect(self.toolbtnSelectAction) self.featIdentTool.setLayer(self.activeLayer) self.canvas.setMapTool(self.featIdentTool) def toolbtnSelectAction(self, feature): #QgsMessageLog.logMessage(str(feature.id()) + " updating district to " + str(feature[self.distfield])) self.activedistrict = feature[self.distfield] self.dockwidget.lblActiveDistrict.setText("Active District: " + str(self.activedistrict)) self.dockwidget.sliderDistricts.setValue( int(districtId[str(self.activedistrict)])) self.canvas.unsetMapTool(self.featIdentTool) self.featIdentTool = None def toolbtnSelectDeselect(self): self.dockwidget.lblActiveDistrict.setText("Active District: " + str(self.activedistrict))
class run(QObject): def __init__(self, id, gtotool, config, debug): super(run, self).__init__() self.debug = debug self.gtotool = gtotool self.gtomain = gtotool.gtomain self.info = gtotool.info self.iface = self.gtotool.iface self.act = self.sender() self.act.setCheckable(True) self.sourcefeat = None self.rubbers = [] try: # create rubberband self.rubber = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.rubber.setColor(QColor(Qt.blue)) self.rubber.setLineStyle(Qt.PenStyle(Qt.DashDotLine)) self.rubber.setWidth(2) # get metadata self.sourcelayer = QgsProject.instance().mapLayersByName(config["sourcelayer"])[0] self.targetlayer = QgsProject.instance().mapLayersByName(config['targetlayer'])[0] self.iface.setActiveLayer(self.targetlayer) # start edit if not self.targetlayer.isEditable(): self.targetlayer.startEditing() if not self.sourcelayer.isEditable(): self.sourcelayer.startEditing() # mouse move self.canvas = self.iface.mapCanvas() self.canvas.xyCoordinates.connect(self.mouse_move) # set maptool self.mapTool = QgsMapToolIdentifyFeature(self.canvas) self.mapTool.setLayer(self.sourcelayer) self.canvas.setMapTool(self.mapTool) self.mapTool.featureIdentified.connect(self.feature_Identified) self.mapTool.deactivated.connect(self.reset_tool) self.act.setChecked(True) except Exception as e: self.info.err(e) def mouse_move(self, pointXY): try: if self.sourcefeat is not None: if self.rubber.numberOfVertices() > 1: self.rubber.removeLastPoint() self.rubber.addPoint(pointXY) except Exception as e: self.info.err(e) def feature_Identified(self, feature): try: if self.sourcefeat is None: self.sourcefeat = feature self.mapTool.setLayer(self.targetlayer) else: # transform geo = self.sourcefeat.geometry() sourceCrs = self.sourcelayer.crs() destCrs = self.targetlayer.crs() tr = QgsCoordinateTransform(sourceCrs, destCrs, QgsProject.instance()) geo.transform(tr) # change geometry self.targetlayer.beginEditCommand("New feature") self.targetlayer.changeGeometry(feature.id(), geo) self.targetlayer.endEditCommand() # cleanup self.rubber.reset() self.iface.mapCanvas().refresh() self.mapTool.setLayer(self.sourcelayer) self.sourcefeat = None print("feature selected : " + str(feature.id())) except Exception as e: self.info.err(e) def reset_tool(self): try: self.act.setChecked(False) self.iface.mapCanvas().scene().removeItem(self.rubber) except Exception as e: self.info.err(e)
def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect(self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex)
def updateSelectedElectorate(self): self.dockwidget.lblActiveDistrict.setText("Click on the map...") self.featIdentTool = QgsMapToolIdentifyFeature(self.canvas) self.featIdentTool.featureIdentified.connect(self.toolbtnSelectAction) self.featIdentTool.setLayer(self.activeLayer) self.canvas.setMapTool(self.featIdentTool)
class ChangesPerParcelPanelWidget(QgsPanelWidget, WIDGET_UI): def __init__(self, parent, utils, parcel_number=None, collected_parcel_t_id=None): QgsPanelWidget.__init__(self, None) self.setupUi(self) self.parent = parent self.utils = utils self.logger = Logger() self.setDockMode(True) self.setPanelTitle( QCoreApplication.translate("ChangesPerParcelPanelWidget", "Change detection per parcel")) self._current_supplies_substring = "" self._current_substring = "" self.utils.add_layers() self.fill_combos() # Remove selection in plot layers self.utils._layers[self.utils._db.names.LC_PLOT_T].removeSelection() self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].removeSelection() # Map tool before activate map swipe tool self.init_map_tool = self.utils.canvas.mapTool() self.active_map_tool_before_custom = None self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM-COL/resources/images/spatial_unit.png")) self.btn_identify_plot.clicked.connect(self.btn_plot_toggled) # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.utils.canvas) # Set connections self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query) self.chk_show_all_plots.toggled.connect(self.show_all_plots) self.cbo_parcel_fields.currentIndexChanged.connect( self.search_field_updated) self.panelAccepted.connect(self.initialize_tools_and_layers) self.tbl_changes_per_parcel.itemDoubleClicked.connect( self.call_party_panel) self.initialize_field_values_line_edit() self.initialize_tools_and_layers() if parcel_number is not None: # Do a search! self.txt_alphanumeric_query.setValue(parcel_number) if collected_parcel_t_id is not None: # Search data for a duplicated parcel_number, so, take the t_id into account! self.search_data(parcel_number=parcel_number, collected_parcel_t_id=collected_parcel_t_id) else: self.search_data(parcel_number=parcel_number) def btn_plot_toggled(self): self.clear_result_table() if self.btn_identify_plot.isChecked(): self.prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.utils.canvas.setMapTool(self.active_map_tool_before_custom) def clear_result_table(self): self.tbl_changes_per_parcel.clearContents() self.tbl_changes_per_parcel.setRowCount(0) def prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.utils.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.utils.canvas.mapToolSet.connect(self.initialize_maptool) if self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T] is None: self.utils.add_layers() self.maptool_identify.setLayer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.utils.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect(self.get_info_by_plot) def get_info_by_plot(self, plot_feature): """ :param plot_feature: from supplies db """ plot_t_id = plot_feature[self.utils._supplies_db.names.T_ID_F] self.utils.canvas.flashFeatureIds(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T], [plot_feature.id()], QColor(255, 0, 0, 255), QColor(255, 0, 0, 0), flashes=1, duration=500) if not self.isVisible(): self.show() self.spatial_query(plot_t_id) self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].selectByIds( [plot_feature.id()]) def spatial_query(self, plot_id): if plot_id: parcel_number = self.utils.ladm_data.get_parcels_related_to_plots_supplies( self.utils._supplies_db, [plot_id], self.utils._supplies_db.names.GC_PARCEL_T_PARCEL_NUMBER_F) if parcel_number: # Delegate handling of duplicates to search_data() method self.search_data(parcel_number=parcel_number[0]) def call_party_panel(self, item): row = item.row() if self.tbl_changes_per_parcel.item(row, 0).text( ) == DICT_ALIAS_KEYS_CHANGE_DETECTION[DICT_KEY_PARTIES]: data = { SUPPLIES_DB_SOURCE: self.tbl_changes_per_parcel.item(row, 1).data(Qt.UserRole), COLLECTED_DB_SOURCE: self.tbl_changes_per_parcel.item(row, 2).data(Qt.UserRole) } self.parent.show_party_panel(data) def search_field_updated(self, index=None): self.initialize_field_values_line_edit() def initialize_field_values_line_edit(self): # We search for alphanumeric data in supplies data source self.txt_alphanumeric_query.setLayer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T]) search_option = self.cbo_parcel_fields.currentData() search_field_supplies = get_supplies_search_options( self.utils._supplies_db.names)[search_option] idx = self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].fields().indexOf( search_field_supplies) self.txt_alphanumeric_query.setAttributeIndex(idx) def fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Parcel Number"), PARCEL_NUMBER_SEARCH_KEY) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Previous Parcel Number"), PREVIOUS_PARCEL_NUMBER_SEARCH_KEY) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetChanges", "Folio de Matrícula Inmobiliaria"), FMI_PARCEL_SEARCH_KEY) @_with_override_cursor def search_data(self, **kwargs): """ Get plot geometries associated with parcels, both collected and supplies, zoom to them, fill comparison table and activate map swipe tool. To fill the comparison table we build two search dicts, one for supplies (already given because the alphanumeric search is on supplies db source), and another one for collected. For the latter, we have 3 cases. We specify them below (inline). :param kwargs: key-value (field name-field value) to search in parcel tables, both collected and supplies Normally, keys are parcel_number, old_parcel_number or FMI, but if duplicates are found, an additional t_id disambiguates only for the collected source. In the supplies source we assume we will not find duplicates, if there are, we will choose the first record found an will not deal with letting the user choose one of the duplicates by hand (as we do for the collected source). """ self.chk_show_all_plots.setEnabled(False) self.chk_show_all_plots.setChecked(True) self.initialize_tools_and_layers() # Reset any filter on layers plots_supplies = list() plots_collected = list() self.clear_result_table() search_option = self.cbo_parcel_fields.currentData() search_field_supplies = get_supplies_search_options( self.utils._supplies_db.names)[search_option] search_field_collected = get_collected_search_options( self.utils._db.names)[search_option] search_value = list(kwargs.values())[0] # Build search criterion for both supplies and collected search_criterion_supplies = {search_field_supplies: search_value} # Get supplies parcel's t_id and get related plot(s) expression_supplies = QgsExpression("{}='{}'".format( search_field_supplies, search_value)) request = QgsFeatureRequest(expression_supplies) field_idx = self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].fields().indexFromName( self.utils._supplies_db.names.T_ID_F) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([field_idx ]) # Note: this adds a new flag supplies_parcels = [ feature for feature in self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].getFeatures(request) ] if len(supplies_parcels) > 1: # We do not expect duplicates in the supplies source! pass # We'll choose the first one anyways elif len(supplies_parcels) == 0: self.logger.info( __name__, "No supplies parcel found! Search: {}={}".format( search_field_supplies, search_value)) supplies_plot_t_ids = [] if supplies_parcels: supplies_plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels_supplies( self.utils._supplies_db, [supplies_parcels[0][self.utils._supplies_db.names.T_ID_F]], self.utils._supplies_db.names.T_ID_F, self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) if supplies_plot_t_ids: self._current_supplies_substring = "\"{}\" IN ('{}')".format( self.utils._supplies_db.names.T_ID_F, "','".join([str(t_id) for t_id in supplies_plot_t_ids])) plots_supplies = self.utils.ladm_data.get_features_from_t_ids( self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T], self.utils._supplies_db.names.T_ID_F, supplies_plot_t_ids, True) # Now get COLLECTED parcel's t_id to build the search dict for collected collected_parcel_t_id = None if 'collected_parcel_t_id' in kwargs: # This is the case when this panel is called and we already know the parcel number is duplicated collected_parcel_t_id = kwargs['collected_parcel_t_id'] search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } # As there are duplicates, we need to use t_ids else: # This is the case when: # + Either this panel was called and we know the parcel number is not duplicated, or # + This panel was shown without knowing about duplicates (e.g., individual parcel search) and we still # need to discover whether we have duplicates for this search criterion search_criterion_collected = {search_field_collected: search_value} expression_collected = QgsExpression("{}='{}'".format( search_field_collected, search_value)) request = QgsFeatureRequest(expression_collected) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes( [self.utils._db.names.T_ID_F], self.utils._layers[self.utils._db.names.LC_PARCEL_T].fields( )) # Note this adds a new flag collected_parcels = self.utils._layers[ self.utils._db.names.LC_PARCEL_T].getFeatures(request) collected_parcels_t_ids = [ feature[self.utils._db.names.T_ID_F] for feature in collected_parcels ] if collected_parcels_t_ids: collected_parcel_t_id = collected_parcels_t_ids[0] if len(collected_parcels_t_ids ) > 1: # Duplicates in collected source after a search QApplication.restoreOverrideCursor( ) # Make sure cursor is not waiting (it is if on an identify) QCoreApplication.processEvents() dlg_select_parcel = SelectDuplicateParcelDialog( self.utils, collected_parcels_t_ids, self.parent) dlg_select_parcel.exec_() if dlg_select_parcel.parcel_t_id: # User selected one of the duplicated parcels collected_parcel_t_id = dlg_select_parcel.parcel_t_id search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } else: return # User just cancelled the dialog, there is nothing more to do self.fill_table(search_criterion_supplies, search_criterion_collected) # Now get related plot(s) for both collected and supplies, if collected_parcel_t_id is not None: plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels( self.utils._db, [collected_parcel_t_id], self.utils._db.names.T_ID_F, plot_layer=self.utils._layers[self.utils._db.names.LC_PLOT_T], uebaunit_table=self.utils._layers[ self.utils._db.names.COL_UE_BAUNIT_T]) if plot_t_ids: self._current_substring = "{} IN ('{}')".format( self.utils._db.names.T_ID_F, "','".join([str(t_id) for t_id in plot_t_ids])) plots_collected = self.utils.ladm_data.get_features_from_t_ids( self.utils._layers[self.utils._db.names.LC_PLOT_T], self.utils._db.names.T_ID_F, plot_t_ids, True) # Zoom to combined extent plot_features = plots_supplies + plots_collected # Feature list plots_extent = QgsRectangle() for plot in plot_features: plots_extent.combineExtentWith(plot.geometry().boundingBox()) if not plots_extent.isEmpty(): self.utils.iface.mapCanvas().zoomToFeatureExtent(plots_extent) if plots_supplies and plots_collected: # Otherwise the map swipe tool doesn't add any value :) # Activate Swipe Tool self.utils.app.gui.activate_layer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) self.parent.activate_map_swipe_tool() # Send a custom mouse move on the map to make the map swipe tool's limit appear on the canvas coord_x = plots_extent.xMaximum() - (plots_extent.xMaximum( ) - plots_extent.xMinimum()) / 9 # 90% coord_y = plots_extent.yMaximum() - (plots_extent.yMaximum( ) - plots_extent.yMinimum()) / 2 # 50% coord_transform = self.utils.iface.mapCanvas( ).getCoordinateTransform() map_point = coord_transform.transform(coord_x, coord_y) widget_point = map_point.toQPointF().toPoint() global_point = self.utils.canvas.mapToGlobal(widget_point) self.utils.canvas.mousePressEvent( QMouseEvent(QEvent.MouseButtonPress, global_point, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseMoveEvent( QMouseEvent(QEvent.MouseMove, widget_point + QPoint(1, 0), Qt.NoButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseReleaseEvent( QMouseEvent(QEvent.MouseButtonRelease, widget_point + QPoint(1, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) # Once the query is done, activate the checkbox to alternate all plots/only selected plot self.chk_show_all_plots.setEnabled(True) def fill_table(self, search_criterion_supplies, search_criterion_collected): """ Shouldn't handle 'inverse' mode as we won't switch table columns at runtime. :param search_criterion_supplies: key-value pair to build an expression to search data in the supplies source :param search_criterion_collected: key-value pair to build an expression to search data in the collected source :return: """ plural = LayerConfig.get_dict_plural(self.utils._db.names) dict_collected_parcels = self.utils.ladm_data.get_parcel_data_to_compare_changes( self.utils._db, search_criterion_collected) # Custom layer modifiers layer_modifiers = { LayerConfig.PREFIX_LAYER_MODIFIERS: LayerConfig.SUPPLIES_DB_PREFIX, LayerConfig.SUFFIX_LAYER_MODIFIERS: LayerConfig.SUPPLIES_DB_SUFFIX, LayerConfig.STYLE_GROUP_LAYER_MODIFIERS: Symbology().get_style_group_layer_modifiers( self.utils._supplies_db.names) } dict_supplies_parcels = self.utils.ladm_data.get_parcel_data_to_compare_changes_supplies( self.utils._supplies_db, search_criterion_supplies, layer_modifiers=layer_modifiers) # Before filling the table we make sure we get one and only one parcel attrs dict collected_attrs = dict() if dict_collected_parcels: collected_parcel_number = list(dict_collected_parcels.keys())[0] collected_attrs = dict_collected_parcels[collected_parcel_number][ 0] del collected_attrs[ self.utils._db.names. T_ID_F] # Remove this line if self.utils._db.names.T_ID_F is somehow needed supplies_attrs = dict() if dict_supplies_parcels: supplies_parcel_number = list(dict_supplies_parcels.keys())[0] supplies_attrs = dict_supplies_parcels[supplies_parcel_number][0] del supplies_attrs[ self.utils._supplies_db.names. T_ID_F] # Remove this line if self.utils._supplies_db.names,T_ID_F is somehow needed number_of_rows = len(collected_attrs) or len(supplies_attrs) self.tbl_changes_per_parcel.setRowCount( number_of_rows) # t_id shouldn't be counted self.tbl_changes_per_parcel.setSortingEnabled(False) field_names = list( collected_attrs.keys()) if collected_attrs else list( supplies_attrs.keys()) if PLOT_GEOMETRY_KEY in field_names: field_names.remove( PLOT_GEOMETRY_KEY) # We'll handle plot geometry separately for row, field_name in enumerate(field_names): supplies_value = supplies_attrs[ field_name] if field_name in supplies_attrs else NULL collected_value = collected_attrs[ field_name] if field_name in collected_attrs else NULL field_alias = DICT_ALIAS_KEYS_CHANGE_DETECTION[ field_name] if field_name in DICT_ALIAS_KEYS_CHANGE_DETECTION else field_name self.fill_row(field_alias, supplies_value, collected_value, row, plural) if number_of_rows: # At least one row in the table? self.fill_geometry_row( PLOT_GEOMETRY_KEY, supplies_attrs[PLOT_GEOMETRY_KEY] if PLOT_GEOMETRY_KEY in supplies_attrs else QgsGeometry(), collected_attrs[PLOT_GEOMETRY_KEY] if PLOT_GEOMETRY_KEY in collected_attrs else QgsGeometry(), number_of_rows - 1) self.tbl_changes_per_parcel.setSortingEnabled(True) def fill_row(self, field_name, supplies_value, collected_value, row, plural): item = QTableWidgetItem(field_name) # item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 0, item) if field_name == DICT_ALIAS_KEYS_CHANGE_DETECTION[DICT_KEY_PARTIES]: item = self.fill_party_item(supplies_value) self.tbl_changes_per_parcel.setItem(row, 1, item) item = self.fill_party_item(collected_value) self.tbl_changes_per_parcel.setItem(row, 2, item) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if supplies_value == collected_value else Qt.red) else: item = QTableWidgetItem( str(supplies_value) if supplies_value != NULL else '') #item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 1, item) item = QTableWidgetItem( str(collected_value) if collected_value != NULL else '') # item.setData(Qt.UserRole, parcel_attrs[self.names.T_ID_F]) self.tbl_changes_per_parcel.setItem(row, 2, item) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if supplies_value == collected_value else Qt.red) def fill_party_item(self, value): # Party's info comes in a list or a list of lists if it's a group party display_value = '' if value != NULL: if type(value) is list and value: display_value = "{} {}".format( len(value), QCoreApplication.translate("DockWidgetChanges", "parties") if len(value) > 1 else QCoreApplication.translate( "DockWidgetChanges", "party")) #else: # display_value = QCoreApplication.translate("DockWidgetChanges", "0 parties") item = QTableWidgetItem(display_value) item.setData(Qt.UserRole, value) return item def fill_geometry_row(self, field_name, supplies_geom, collected_geom, row): self.tbl_changes_per_parcel.setItem( row, 0, QTableWidgetItem( QCoreApplication.translate("DockWidgetChanges", "Geometry"))) self.tbl_changes_per_parcel.setItem( row, 1, QTableWidgetItem(self.get_geometry_type_name(supplies_geom))) self.tbl_changes_per_parcel.setItem( row, 2, QTableWidgetItem(self.get_geometry_type_name(collected_geom))) self.tbl_changes_per_parcel.setItem(row, 3, QTableWidgetItem()) self.tbl_changes_per_parcel.item(row, 3).setBackground( Qt.green if self.utils.compare_features_geometries( collected_geom, supplies_geom) else Qt.red) @staticmethod def get_geometry_type_name(geometry): if geometry is None: return QCoreApplication.translate("DockWidgetChanges", "No associated plot") elif geometry.type() == QgsWkbTypes.UnknownGeometry: return '' elif geometry.type() == QgsWkbTypes.PolygonGeometry: return QCoreApplication.translate("DockWidgetChanges", "Polygon") else: return "Type: {}".format(geometry.type()) def alphanumeric_query(self): """ Alphanumeric query (On supplies db) """ option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == FMI_PARCEL_SEARCH_KEY: self.search_data(parcel_fmi=query) elif option == PARCEL_NUMBER_SEARCH_KEY: self.search_data(parcel_number=query) else: # previous_parcel_number self.search_data(previous_parcel_number=query) else: self.utils.iface.messageBar().pushMessage( "Asistente LADM-COL", QCoreApplication.translate("DockWidgetChanges", "First enter a query")) def show_all_plots(self, state): try: self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T].setSubsetString( self._current_supplies_substring if not state else "") except RuntimeError: # If the layer was previously removed pass try: self.utils._layers[self.utils._db.names.LC_PLOT_T].setSubsetString( self._current_substring if not state else "") except RuntimeError: # If the layer was previously removed pass def initialize_tools_and_layers(self, panel=None): self.parent.deactivate_map_swipe_tool() self.show_all_plots(True) def initialize_maptool(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.utils.canvas.mapToolSet.disconnect( self.initialize_maptool) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def close_panel(self): self.show_all_plots( True ) # Remove filter in plots layers if it was activate and panel is closed # custom identify was deactivated try: self.utils.canvas.mapToolSet.disconnect(self.initialize_maptool) except TypeError as e: pass self.utils.canvas.setMapTool(self.init_map_tool)
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.first_flag = True self.setWindowTitle('PyQGIS') # 调整窗口大小 self.resize(800, 600) # 初始化图层树 vl = QVBoxLayout(self.dockWidgetContents) self.layerTreeView = QgsLayerTreeView(self) vl.addWidget(self.layerTreeView) # 初始化地图画布 self.mapCanvas = QgsMapCanvas(self) hl = QHBoxLayout(self.frame) hl.setContentsMargins(0, 0, 0, 0) hl.addWidget(self.mapCanvas) # 建立桥梁 self.model = QgsLayerTreeModel(PROJECT.layerTreeRoot(), self) self.model.setFlag(QgsLayerTreeModel.AllowNodeRename) self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder) self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility) self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree) self.model.setAutoCollapseLegendNodes(10) self.layerTreeView.setModel(self.model) self.layerTreeBridge = QgsLayerTreeMapCanvasBridge( PROJECT.layerTreeRoot(), self.mapCanvas, self) # 显示经纬度 self.mapCanvas.xyCoordinates.connect(self.showLngLat) # 打开工程 self.actionOpen.triggered.connect(self.actionOpenTriggered) # 退出程序 self.actionQuit.triggered.connect(self.close) # 地图工具 # TODO:放大、缩小没有图标 self.actionPanTriggered() self.actionPan.triggered.connect(self.actionPanTriggered) self.actionZoomin.triggered.connect(self.actionZoomInTriggered) self.actionZoomout.triggered.connect(self.actionZoomOutTriggered) self.actionIdentity.triggered.connect(self.actionIdentifyTriggered) # 图层 self.actionShapefile.triggered.connect(self.actionShapefileTriggered) self.actionCsv.triggered.connect(self.actionCsvTriggered) self.actionPostGIS.triggered.connect(self.actionPostGISTriggered) self.actionWFS.triggered.connect(self.actionWFSTriggered) self.actionGeotiff.triggered.connect(self.actionGeotiffTriggered) self.actionXYZ.triggered.connect(self.actionXYZTriggered) # 绘图工具 self.actionPoint.triggered.connect(self.actionPointTriggered) self.actionLine.triggered.connect(self.actionLineTriggered) self.actionRectangle.triggered.connect(self.actionRectangleTriggered) self.actionPolygon.triggered.connect(self.actionPolygonTriggered) # 关于Qt self.actionAboutQt.triggered.connect( lambda: QMessageBox.aboutQt(self, '关于Qt')) self.actionAbout.triggered.connect( lambda: QMessageBox.about(self, '关于', 'PyQGIS二次开发')) # self.actionPan.triggered.connect(self.actionPanTriggered) # self.actionIdentify.triggered.connect(self.actionIdentifyTriggered) # 图层右键菜单 self.customMenuProvider = CustomMenuProvider(self.layerTreeView, self.mapCanvas) self.layerTreeView.setMenuProvider(self.customMenuProvider) # self.layerTreeRegistryBridge = QgsLayerTreeRegistryBridge(PROJECT.layerTreeRoot(), PROJECT, self) def actionOpenTriggered(self): """打开工程""" data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '工程文件(*.qgs , *.qgz)') if data_file: PROJECT.read(data_file) def actionPanTriggered(self): self.mapTool = QgsMapToolPan(self.mapCanvas) self.mapCanvas.setMapTool(self.mapTool) def actionZoomInTriggered(self): self.mapTool = QgsMapToolZoom(self.mapCanvas, False) self.mapCanvas.setMapTool(self.mapTool) def actionZoomOutTriggered(self): self.mapTool = QgsMapToolZoom(self.mapCanvas, True) self.mapCanvas.setMapTool(self.mapTool) def actionIdentifyTriggered(self): # 设置识别工具 self.identifyTool = QgsMapToolIdentifyFeature(self.mapCanvas) self.identifyTool.featureIdentified.connect(self.showFeatures) self.mapCanvas.setMapTool(self.identifyTool) # 设置需要识别的图层 layers = self.mapCanvas.layers() if layers: # 识别画布中第一个图层 self.identifyTool.setLayer(layers[0]) def showFeatures(self, feature): print(type(feature)) QMessageBox.information(self, '信息', ''.join(feature.attributes())) def actionAddGroupTriggered(self): PROJECT.layerTreeRoot().addGroup('group1') def actionShapefileTriggered(self): """打开shp""" data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.shp') if data_file: layer = QgsVectorLayer( data_file, os.path.splitext(os.path.basename(data_file))[0], "ogr") self.addLayer(layer) def actionCsvTriggered(self): """加载csv数据""" data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.csv') if data_file: # 去掉盘符,否则图层无效 data_file = os.path.splitdrive(data_file)[1] uri = f"file://{data_file}?delimiter=,&xField=x&yField=y" print(uri) layer = QgsVectorLayer(uri, "point", "delimitedtext") self.addLayer(layer) def actionPostGISTriggered(self): """加载postgis图层""" dialog = PostGISDialog(self) if dialog.exec_(): uri = QgsDataSourceUri() uri.setConnection(dialog.lineEditHost.text(), dialog.lineEditPort.text(), dialog.lineEditDatabase.text(), dialog.lineEditUsername.text(), dialog.lineEditPassword.text()) # lineEditGeometryColumn:根据实际情况,可能为:wkb_geometry、geometry、the_geom... uri.setDataSource("public", dialog.lineEditLayer.text(), dialog.lineEditGeometryColumn.text()) layer = QgsVectorLayer(uri.uri(False), dialog.lineEditLayer.text(), "postgres") self.addLayer(layer) def actionWFSTriggered(self): """加载天地图WFS图层""" uri = 'http://gisserver.tianditu.gov.cn/TDTService/wfs?' \ 'srsname=EPSG:4326&typename=TDTService:RESA&version=auto&request=GetFeature&service=WFS' layer = QgsVectorLayer(uri, "RESA", "WFS") self.addLayer(layer) def actionGeotiffTriggered(self): """加载geotiff""" data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.tif') if data_file: layer = QgsRasterLayer(data_file, os.path.basename(data_file)) self.addLayer(layer) def actionXYZTriggered(self): uri = 'type=xyz&' \ 'url=https://www.google.cn/maps/vt?lyrs=s@804%26gl=cn%26x={x}%26y={y}%26z={z}&' \ 'zmax=19&' \ 'zmin=0&' \ 'crs=EPSG3857' layer = QgsRasterLayer(uri, 'google', 'wms') self.addLayer(layer) def addLayer(self, layer): if layer.isValid(): if self.first_flag: self.mapCanvas.setDestinationCrs(layer.crs()) self.mapCanvas.setExtent(layer.extent()) self.first_flag = False PROJECT.addMapLayer(layer) layers = [layer ] + [PROJECT.mapLayer(i) for i in PROJECT.mapLayers()] self.mapCanvas.setLayers(layers) self.mapCanvas.refresh() else: print('图层无效.') def actionPointTriggered(self): self.pointTool = PointMapTool(self.mapCanvas) self.mapCanvas.setMapTool(self.pointTool) def actionLineTriggered(self): self.lineTool = LineMapTool(self.mapCanvas) self.mapCanvas.setMapTool(self.lineTool) def actionRectangleTriggered(self): self.rectangleTool = RectangleMapTool(self.mapCanvas) self.mapCanvas.setMapTool(self.rectangleTool) def actionPolygonTriggered(self): self.polygonTool = PolygonMapTool(self.mapCanvas) self.mapCanvas.setMapTool(self.polygonTool) def showLngLat(self, point): x = point.x() y = point.y() self.statusbar.showMessage(f'经度:{x}, 纬度:{y}')
class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI): def __init__(self, iface, controller, parent=None): super(DockWidgetQueries, self).__init__(None) self.setupUi(self) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface = iface self._controller = controller self.logger = Logger() self.app = AppInterface() self.canvas = iface.mapCanvas() self.active_map_tool_before_custom = None self._identify_tool = None self._fill_combos() self.btn_identify_plot.setIcon( QIcon(":/Asistente-LADM-COL/resources/images/spatial_unit.png")) self.tab_results.setTabEnabled( TAB_BASIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_PHYSICAL_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setTabEnabled( TAB_ECONOMIC_INFO_INDEX, False) # TODO: Remove when queries support LevCat 1.2 self.tab_results.setCurrentIndex( TAB_LEGAL_INFO_INDEX ) # TODO: Remove when queries support LevCat 1.2 # Set connections self._controller.close_view_requested.connect(self._close_dock_widget) self.btn_alphanumeric_query.clicked.connect(self._alphanumeric_query) self.cbo_parcel_fields.currentIndexChanged.connect( self._search_field_updated) self.btn_identify_plot.clicked.connect(self._btn_plot_toggled) self.btn_query_informality.clicked.connect(self._query_informality) self.btn_next_informal_parcel.clicked.connect( self._query_next_informal_parcel) self.btn_previous_informal_parcel.clicked.connect( self._query_previous_informal_parcel) # Context menu self._set_context_menus() # Create maptool self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas) self._initialize_field_values_line_edit() self._update_informal_controls() def _search_field_updated(self, index=None): self._initialize_field_values_line_edit() def _initialize_field_values_line_edit(self): self.txt_alphanumeric_query.setLayer(self._controller.parcel_layer()) idx = self._controller.parcel_layer().fields().indexOf( self.cbo_parcel_fields.currentData()) self.txt_alphanumeric_query.setAttributeIndex(idx) def _set_context_menus(self): self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_basic.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_legal.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_physical.customContextMenuRequested.connect( self._show_context_menu) self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view_economic.customContextMenuRequested.connect( self._show_context_menu) def _close_dock_widget(self): # Deactivate custom tool and close dockwidget self._controller.disconnect_plot_layer() self._controller.disconnect_parcel_layer() self._initialize_tools(new_tool=None, old_tool=self.maptool_identify) self._btn_plot_toggled() self.close( ) # The user needs to use the menus again, which will start everything from scratch def _fill_combos(self): self.cbo_parcel_fields.clear() self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Parcel Number"), self._controller.parcel_number_name()) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Previous Parcel Number"), self._controller.previous_parcel_number_name()) self.cbo_parcel_fields.addItem( QCoreApplication.translate("DockWidgetQueries", "Folio de Matrícula Inmobiliaria"), self._controller.fmi_name()) def _initialize_tools(self, new_tool, old_tool): if self.maptool_identify == old_tool: # custom identify was deactivated try: self.canvas.mapToolSet.disconnect(self._initialize_tools) except TypeError as e: pass self.btn_identify_plot.setChecked(False) else: # custom identify was activated pass def _btn_plot_toggled(self): if self.btn_identify_plot.isChecked(): self._prepare_identify_plot() else: # The button was toggled and deactivated, go back to the previous tool self.canvas.setMapTool(self.active_map_tool_before_custom) def _prepare_identify_plot(self): """ Custom Identify tool was activated, prepare everything for identifying plots """ self.active_map_tool_before_custom = self.canvas.mapTool() self.btn_identify_plot.setChecked(True) self.canvas.mapToolSet.connect(self._initialize_tools) self.maptool_identify.setLayer(self._controller.plot_layer()) cursor = QCursor() cursor.setShape(Qt.PointingHandCursor) self.maptool_identify.setCursor(cursor) self.canvas.setMapTool(self.maptool_identify) try: self.maptool_identify.featureIdentified.disconnect() except TypeError as e: pass self.maptool_identify.featureIdentified.connect( self._search_data_by_plot) def _search_data_by_plot(self, plot_feature): plot_t_id = plot_feature[self._controller.t_id_name()] self.app.gui.flash_features(self._controller.plot_layer(), [plot_feature.id()]) with OverrideCursor(Qt.WaitCursor): if not self.isVisible(): self.show() self._search_data_by_component(plot_t_ids=[plot_t_id], zoom_and_select=False) self._controller.plot_layer().selectByIds([plot_feature.id()]) def _search_data_by_component(self, **kwargs): """ Perform the searches by component and fill tree views :param kwargs: A dict with search criteria. """ self._controller.plot_layer().removeSelection() # Read zoom_and_select parameter and remove it from kwargs bZoom = False if 'zoom_and_select' in kwargs: bZoom = kwargs['zoom_and_select'] del kwargs['zoom_and_select'] if 'parcel_number' in kwargs and kwargs['parcel_number'] == NULL: self.logger.warning( __name__, QCoreApplication.translate( "DockWidgetQueries", "The parcel number is NULL! We cannot retrieve data for parcels with NULL parcel numbers." )) # records = self._controller.search_data_basic_info(**kwargs) # if bZoom: # self._controller.zoom_to_resulting_plots(records) # self._setup_tree_view(self.tree_view_basic, records) records = self._controller.search_data_legal_info(**kwargs) self._setup_tree_view(self.tree_view_legal, records) # records = self._controller.search_data_physical_info(**kwargs) # self._setup_tree_view(self.tree_view_physical, records) # records = self._controller.search_data_economic_info(**kwargs) # self._setup_tree_view(self.tree_view_economic, records) def _setup_tree_view(self, tree_view, records): """ Configure result tree views :param tree_view: Tree view to be updated :param records: List of dicts. A dict per plot: {id: 21, attributes: {...}} """ tree_view.setModel(self._controller.create_model(records)) self._collapse_tree_view_items(tree_view) self._add_thumbnails_to_tree_view(tree_view) def _collapse_tree_view_items(self, tree_view): """ Collapse tree view items based on a property """ tree_view.expandAll() for idx in tree_view.model().getCollapseIndexList(): tree_view.collapse(idx) def _add_thumbnails_to_tree_view(self, tree_view): """ Gets a list of model indexes corresponding to extFiles objects to show a preview """ model = tree_view.model() for idx in model.getPixmapIndexList(): url = model.data(idx, Qt.UserRole)['url'] res, image = self._controller.download_image("{}{}".format( url, SUFFIX_GET_THUMBNAIL)) if res: pixmap = QPixmap() pixmap.loadFromData(image) label = QLabel() label.setPixmap(pixmap) tree_view.setIndexWidget(idx, label) def _alphanumeric_query(self): option = self.cbo_parcel_fields.currentData() query = self.txt_alphanumeric_query.value() if query: if option == self._controller.fmi_name(): self._search_data_by_component(parcel_fmi=query, zoom_and_select=True) elif option == self._controller.parcel_number_name(): self._search_data_by_component(parcel_number=query, zoom_and_select=True) else: # previous_parcel_number self._search_data_by_component(previous_parcel_number=query, zoom_and_select=True) else: self.logger.info_msg( __name__, QCoreApplication.translate("DockWidgetQueries", "First enter a query")) def _show_context_menu(self, point): tree_view = self.sender() index = tree_view.indexAt(point) context_menu = QMenu("Context menu") index_data = index.data(Qt.UserRole) if index_data is None: return if "value" in index_data: action_copy = QAction( QCoreApplication.translate("DockWidgetQueries", "Copy value")) action_copy.triggered.connect( partial(self._controller.copy_value, index_data["value"])) context_menu.addAction(action_copy) context_menu.addSeparator() if "url" in index_data: action_open_url = QAction( QCoreApplication.translate("DockWidgetQueries", "Open URL")) action_open_url.triggered.connect( partial(self._controller.open_url, index_data["url"])) context_menu.addAction(action_open_url) context_menu.addSeparator() # Configure actions for tables/layers if "type" in index_data and "id" in index_data: table_name = index_data["type"] t_id = index_data["id"] if table_name == self._controller.parcel_layer_name(): layer = self._controller.parcel_layer() self.app.core.activate_layer_requested.emit(layer) else: layer = self._controller.get_layer(table_name) if layer is not None: if layer.isSpatial(): action_zoom_to_feature = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to {} with {}={}").format( table_name, self._controller.t_id_name(), t_id)) action_zoom_to_feature.triggered.connect( partial(self._controller.zoom_to_feature, layer, t_id)) context_menu.addAction(action_zoom_to_feature) if table_name == self._controller.parcel_layer_name(): # We show a handy option to zoom to related plots plot_ids = self._controller.get_plots_related_to_parcel( t_id) if plot_ids: action_zoom_to_plots = QAction( QCoreApplication.translate( "DockWidgetQueries", "Zoom to related plot(s)")) action_zoom_to_plots.triggered.connect( partial(self._controller.zoom_to_plots, plot_ids)) context_menu.addAction(action_zoom_to_plots) action_open_feature_form = QAction( QCoreApplication.translate( "DockWidgetQueries", "Open form for {} with {}={}").format( table_name, self._controller.t_id_name(), t_id)) action_open_feature_form.triggered.connect( partial(self._controller.open_feature_form, layer, t_id)) context_menu.addAction(action_open_feature_form) if context_menu.actions(): context_menu.exec_(tree_view.mapToGlobal(point)) def _query_informality(self): first_parcel_number, current, total = self._controller.query_informal_parcels( ) self._search_data_by_component(parcel_number=first_parcel_number, zoom_and_select=True) self._update_informal_controls(first_parcel_number, current, total) if not total: self.logger.info_msg( __name__, QCoreApplication.translate( "DockWidgetQueries", "There are no informal parcels in this database!")) def _update_informal_controls(self, parcel_number='', current=0, total=0): """ Update controls (reset labels, enable buttons if we have informality) """ self._update_informal_labels(parcel_number, current, total) self.btn_query_informality.setText( QCoreApplication.translate("DockWidgetQueries", "Restart" ) if current else QCoreApplication. translate("DockWidgetQueries", "Start")) enable = total > 1 # At least 2 to enable buttons that traverse the parcels self.btn_next_informal_parcel.setEnabled(enable) self.btn_previous_informal_parcel.setEnabled(enable) def _update_informal_labels(self, parcel_number='', current=0, total=0): self.lbl_informal_parcel_number.setText( parcel_number if parcel_number != NULL else 'NULL') out_of = '' if current and total: out_of = QCoreApplication.translate("DockWidgetQueries", "{} out of {}").format( current, total) self.lbl_informal_out_of_total.setText(out_of) def _query_next_informal_parcel(self): parcel_number, current, total = self._controller.get_next_informal_parcel( ) self._search_data_by_component(parcel_number=parcel_number, zoom_and_select=True) self._update_informal_controls(parcel_number, current, total) def _query_previous_informal_parcel(self): parcel_number, current, total = self._controller.get_previous_informal_parcel( ) self._search_data_by_component(parcel_number=parcel_number, zoom_and_select=True) self._update_informal_controls(parcel_number, current, total) def closeEvent(self, event): try: self.canvas.mapToolSet.disconnect(self._initialize_tools) except TypeError as e: pass self.canvas.setMapTool(self.active_map_tool_before_custom)
class LinkerDock(QDockWidget, Ui_linker, SettingDialog): def __init__(self, iface): # QGIS self.iface = iface self.settings = MySettings() self.linkRubber = QgsRubberBand(self.iface.mapCanvas()) self.featureHighlight = None # Relation management self.relationManager = QgsProject.instance().relationManager() self.relationManager.changed.connect(self.loadRelations) self.relation = QgsRelation() self.referencingFeature = QgsFeature() self.relationWidgetWrapper = None self.editorContext = QgsAttributeEditorContext() self.editorContext.setVectorLayerTools(self.iface.vectorLayerTools()) # GUI QDockWidget.__init__(self) self.setupUi(self) SettingDialog.__init__(self, MySettings(), False, True) self.drawButton.setChecked(self.settings.value("drawEnabled")) self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) self.mapTool = QgsMapToolIdentifyFeature(self.iface.mapCanvas()) self.mapTool.setButton(self.identifyReferencingFeatureButton) # Connect signal/slot self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged) self.mapTool.featureIdentified.connect(self.setReferencingFeature) # load relations at start self.loadRelations() def showEvent(self, QShowEvent): self.drawLink() def closeEvent(self, e): self.iface.mapCanvas().unsetMapTool(self.mapTool) self.linkRubber.reset() self.deleteHighlight() self.deleteWrapper() self.disconnectLayer() def disconnectLayer(self): if self.relation.isValid(): self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside) def runForFeature(self, relationId, layer, feature): index = self.relationComboBox.findData(relationId) self.relationComboBox.setCurrentIndex(index) self.setReferencingFeature(feature) self.show() if not layer.isEditable(): self.iface.messageBar().pushMessage("Link It", "Cannot set a new related feature since %s is not editable" % layer.name(), QgsMessageBar.WARNING, 4) else: self.relationReferenceWidget.mapIdentification() @pyqtSlot(name="on_identifyReferencingFeatureButton_clicked") def activateMapTool(self): self.iface.mapCanvas().setMapTool(self.mapTool) def deactivateMapTool(self): self.iface.mapCanvas().unsetMapTool(self.mapTool) def loadRelations(self): self.deleteWrapper() self.disconnectLayer() self.relation = QgsRelation() self.referencingFeature = QgsFeature() self.relationComboBox.currentIndexChanged.disconnect(self.currentRelationChanged) self.relationComboBox.clear() for relation in self.relationManager.referencedRelations(): if relation.referencingLayer().hasGeometryType(): self.relationComboBox.addItem(relation.name(), relation.id()) self.relationComboBox.setCurrentIndex(-1) self.relationComboBox.currentIndexChanged.connect(self.currentRelationChanged) self.currentRelationChanged(-1) def currentRelationChanged(self, index): # disconnect previous relation if self.relation.isValid(): try: self.relation.referencingLayer().editingStarted.disconnect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.disconnect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.disconnect(self.layerValueChangedOutside) except TypeError: pass self.referencingFeatureLayout.setEnabled(index >= 0) relationId = self.relationComboBox.itemData(index) self.relation = self.relationManager.relation(relationId) self.mapTool.setLayer(self.relation.referencingLayer()) self.setReferencingFeature() # connect if self.relation.isValid(): self.relation.referencingLayer().editingStarted.connect(self.relationEditableChanged) self.relation.referencingLayer().editingStopped.connect(self.relationEditableChanged) self.relation.referencingLayer().attributeValueChanged.connect(self.layerValueChangedOutside) def setReferencingFeature(self, feature=QgsFeature()): self.deactivateMapTool() self.referencingFeature = QgsFeature(feature) self.deleteWrapper() # disable relation reference widget if no referencing feature self.referencedFeatureLayout.setEnabled(feature.isValid()) # set line edit if not self.relation.isValid() or not feature.isValid(): self.referencingFeatureLineEdit.clear() return self.referencingFeatureLineEdit.setText("%s" % feature.id()) fieldIdx = self.referencingFieldIndex() widgetConfig = self.relation.referencingLayer().editorWidgetV2Config(fieldIdx) self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create("RelationReference", self.relation.referencingLayer(), fieldIdx, widgetConfig, self.relationReferenceWidget, self, self.editorContext) self.relationWidgetWrapper.setEnabled(self.relation.referencingLayer().isEditable()) self.relationWidgetWrapper.setValue(feature[fieldIdx]) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) # override field definition to allow map identification self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) # update drawn link self.highlightReferencingFeature() self.drawLink() def deleteWrapper(self): if self.relationWidgetWrapper is not None: self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged) self.relationWidgetWrapper.setValue(None) del self.relationWidgetWrapper self.relationWidgetWrapper = None def foreignKeyChanged(self, newKey): if not self.relation.isValid() or not self.relation.referencingLayer().isEditable() or not self.referencingFeature.isValid(): self.drawLink() return if not self.relation.referencingLayer().editBuffer().changeAttributeValue(self.referencingFeature.id(), self.referencingFieldIndex(), newKey): self.iface.messageBar().pushMessage("Link It", "Cannot change attribute value.", QgsMessageBar.CRITICAL) self.drawLink() def relationEditableChanged(self): if self.relationWidgetWrapper is not None: self.relationWidgetWrapper.setEnabled(self.relation.isValid() and self.relation.referencingLayer().isEditable()) def layerValueChangedOutside(self, fid, fieldIdx, value): if not self.relation.isValid() or not self.referencingFeature.isValid() or self.relationWidgetWrapper is None: return # not the correct feature if fid != self.referencingFeature.id(): return # not the correct field if fieldIdx != self.referencingFieldIndex(): return # widget already has this value if value == self.relationWidgetWrapper.value(): return self.relationWidgetWrapper.valueChanged.disconnect(self.foreignKeyChanged) self.relationWidgetWrapper.setValue(value) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) def referencingFieldIndex(self): if not self.relation.isValid(): return -1 fieldName = self.relation.fieldPairs().keys()[0] fieldIdx = self.relation.referencingLayer().fieldNameIndex(fieldName) return fieldIdx @pyqtSlot(bool, name="on_drawButton_toggled") def drawLink(self): self.settings.setValue("drawEnabled", self.drawButton.isChecked()) self.linkRubber.reset() if not self.drawButton.isChecked() or not self.referencingFeature.isValid() or not self.relation.isValid(): return referencedFeature = self.relationReferenceWidget.referencedFeature() if not referencedFeature.isValid(): return p1 = self.centroid(self.relation.referencedLayer(), referencedFeature) p2 = self.centroid(self.relation.referencingLayer(), self.referencingFeature) geom = arc(p1, p2) self.linkRubber.setToGeometry(geom, None) self.linkRubber.setWidth(self.settings.value("rubberWidth")) self.linkRubber.setColor(self.settings.value("rubberColor")) self.linkRubber.setLineStyle(Qt.DashLine) def centroid(self, layer, feature): geom = feature.geometry() if geom.type() == QGis.Line: geom = geom.interpolate(geom.length()/2) else: geom = geom.centroid() return self.iface.mapCanvas().mapSettings().layerToMapCoordinates(layer, geom.asPoint()) @pyqtSlot(name="on_highlightReferencingFeatureButton_clicked") def highlightReferencingFeature(self): self.deleteHighlight() if not self.relation.isValid() or not self.referencingFeature.isValid(): return self.featureHighlight = QgsHighlight(self.iface.mapCanvas(), self.referencingFeature.geometry(), self.relation.referencingLayer()) settings = QSettings() color = QColor( settings.value("/Map/highlight/color", QGis.DEFAULT_HIGHLIGHT_COLOR.name())) alpha = int(settings.value("/Map/highlight/colorAlpha", QGis.DEFAULT_HIGHLIGHT_COLOR.alpha())) bbuffer = float(settings.value("/Map/highlight/buffer", QGis.DEFAULT_HIGHLIGHT_BUFFER_MM)) minWidth = float(settings.value("/Map/highlight/minWidth", QGis.DEFAULT_HIGHLIGHT_MIN_WIDTH_MM)) self.featureHighlight.setColor(color) color.setAlpha(alpha) self.featureHighlight.setFillColor(color) self.featureHighlight.setBuffer(bbuffer) self.featureHighlight.setMinWidth(minWidth) self.featureHighlight.show() timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(self.deleteHighlight) timer.start(3000) def deleteHighlight(self): if self.featureHighlight: del self.featureHighlight self.featureHighlight = None
def __init__(self, canvas, dlg): QgsMapToolIdentifyFeature.__init__(self, canvas) self.canvas = canvas self.dlg = dlg
def __init__(self, canvas): self.canvas = canvas QgsMapToolIdentifyFeature.__init__(self, self.canvas)
class EdgeCreator(QDockWidget, gui_dckwdgt_edge_creator): def __init__(self, canvas, l_vertex, l_edge, user=None, auth_creator=[], parent=None): super(EdgeCreator, self).__init__(parent) self.setupUi(self) # Delete Widget on close event.. self.setAttribute(Qt.WA_DeleteOnClose) self.save = False self.canvas = canvas self.l_edge = l_edge self.l_vertex = l_vertex self.user = user self.auth_creator = auth_creator self.vertices = self.l_vertex.getFeatures() self.vtx_start = None self.vtx_end = None self.selected_vertices = [None, None] self.edge = None for i, vertex in enumerate(self.vertices): self.startVertexComboBox.insertItem(i, str(vertex.id())) self.startVertexComboBox.setItemData(i, vertex, 32) self.startVertexComboBox.setCurrentIndex(-1) self.endVertexComboBox.insertItem(i, str(vertex.id())) self.endVertexComboBox.setItemData(i, vertex, 32) self.endVertexComboBox.setCurrentIndex(-1) # Attribute: `som_createur` for i, e in enumerate(self.auth_creator): self.creatorComboBox.addItem(u"%s (%s)" % (e[1], e[0])) if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.startVertextoolButton.clicked.connect( self.select_start_vertex_on_canvas) self.endVertextoolButton.clicked.connect( self.select_end_vertex_on_canvas) self.startVertexComboBox.highlighted.connect(self.on_vtx_start_pressed) self.endVertexComboBox.highlighted.connect(self.on_vtx_end_pressed) self.startVertexComboBox.currentIndexChanged.connect( self.on_vtx_start_pressed) self.endVertexComboBox.currentIndexChanged.connect( self.on_vtx_end_pressed) self.startVertexComboBox.highlighted.connect(self.create_edge) self.endVertexComboBox.highlighted.connect(self.create_edge) self.startVertexComboBox.currentIndexChanged.connect(self.create_edge) self.endVertexComboBox.currentIndexChanged.connect(self.create_edge) self.buttonBox.accepted.connect(self.on_accepted) self.buttonBox.rejected.connect(self.on_rejected) self.buttonBox.button(QDialogButtonBox.Reset).clicked.connect( self.on_reset) def closeEvent(self, event): if not self.save: self.on_rejected() def select_start_vertex_on_canvas(self): self.identify_start_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_start_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_start_vertex.featureIdentified.connect( self.on_start_vertex_identified) self.canvas.setMapTool(self.identify_start_vertex) def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature( self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect( self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex) def on_start_vertex_identified(self, feature): cb = self.startVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_end_vertex_identified(self, feature): cb = self.endVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_vtx_start_pressed(self, idx): self.vtx_start = self.startVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_start, 0) self.endVertexComboBox.setEnabled(True) self.endVertextoolButton.setEnabled(True) def on_vtx_end_pressed(self, idx): self.vtx_end = self.endVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_end, 1) self.creatorComboBox.setEnabled(True) def select_vertices(self, feature, i): if feature: self.selected_vertices[i] = feature.id() else: self.selected_vertices[i] = None self.l_vertex.setSelectedFeatures(self.selected_vertices) def unselect_vertices(self): self.l_vertex.setSelectedFeatures([]) def create_edge(self): # If edge already exists, delete it.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) # Two vertices are needed.. if not self.vtx_start or not self.vtx_end: return self.canvas.refresh() # Two DIFFERENT vertices.. if self.vtx_start == self.vtx_end: return self.canvas.refresh() # Create line geometry.. line = QgsGeometry.fromPolyline([ self.vtx_start.geometry().asPoint(), self.vtx_end.geometry().asPoint() ]) # Create the feature.. self.edge = QgsFeature() self.edge.setGeometry(line) self.edge.setFields(self.l_edge.pendingFields()) self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), QPyNullVariant(int)]) # Add feature to layer.. self.l_edge.addFeature(self.edge) self.canvas.refresh() def on_accepted(self): if not self.edge: return False self.lim_ge_createur = self.auth_creator[ self.creatorComboBox.currentIndex()][0] self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), self.lim_ge_createur]) self.l_edge.updateFeature(self.edge) self.canvas.refresh() self.save = True self.close() def on_rejected(self): # Do not save the feature.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) self.unselect_vertices() self.canvas.refresh() self.close() def on_reset(self): self.startVertexComboBox.setCurrentIndex(0) # self.startVertexComboBox.setEnabled(True) # self.startVertexLabel.setEnabled(True) self.endVertexComboBox.setCurrentIndex(0) self.endVertexComboBox.setEnabled(False) self.endVertexLabel.setEnabled(False) self.endVertextoolButton.setEnabled(False) for i, e in enumerate(self.auth_creator): if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.creatorComboBox.setEnabled(False) self.creatorLabel.setEnabled(False) self.unselect_vertices() self.canvas.refresh()
def __init__(self, canvas, iface): self.canvas = canvas self.iface = iface QgsMapToolIdentifyFeature.__init__(self, self.canvas)
class EdgeCreator(QDockWidget, gui_dckwdgt_edge_creator): def __init__(self, canvas, l_vertex, l_edge, user=None, auth_creator=[], parent=None): super(EdgeCreator, self).__init__(parent) self.setupUi(self) # Delete Widget on close event.. self.setAttribute(Qt.WA_DeleteOnClose) self.save = False self.canvas = canvas self.l_edge = l_edge self.l_vertex = l_vertex self.user = user self.auth_creator = auth_creator self.vertices = self.l_vertex.getFeatures() self.vtx_start = None self.vtx_end = None self.selected_vertices = [None, None] self.edge = None for i, vertex in enumerate(self.vertices): self.startVertexComboBox.insertItem(i, str(vertex.id())) self.startVertexComboBox.setItemData(i, vertex, 32) self.startVertexComboBox.setCurrentIndex(-1) self.endVertexComboBox.insertItem(i, str(vertex.id())) self.endVertexComboBox.setItemData(i, vertex, 32) self.endVertexComboBox.setCurrentIndex(-1) # Attribute: `som_createur` for i, e in enumerate(self.auth_creator): self.creatorComboBox.addItem(u"%s (%s)" % (e[1], e[0])) if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.startVertextoolButton.clicked.connect(self.select_start_vertex_on_canvas) self.endVertextoolButton.clicked.connect(self.select_end_vertex_on_canvas) self.startVertexComboBox.highlighted.connect(self.on_vtx_start_pressed) self.endVertexComboBox.highlighted.connect(self.on_vtx_end_pressed) self.startVertexComboBox.currentIndexChanged.connect(self.on_vtx_start_pressed) self.endVertexComboBox.currentIndexChanged.connect(self.on_vtx_end_pressed) self.startVertexComboBox.highlighted.connect(self.create_edge) self.endVertexComboBox.highlighted.connect(self.create_edge) self.startVertexComboBox.currentIndexChanged.connect(self.create_edge) self.endVertexComboBox.currentIndexChanged.connect(self.create_edge) self.buttonBox.accepted.connect(self.on_accepted) self.buttonBox.rejected.connect(self.on_rejected) self.buttonBox.button(QDialogButtonBox.Reset).clicked.connect(self.on_reset) def closeEvent(self, event): if not self.save: self.on_rejected() def select_start_vertex_on_canvas(self): self.identify_start_vertex = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_start_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_start_vertex.featureIdentified.connect(self.on_start_vertex_identified) self.canvas.setMapTool(self.identify_start_vertex) def select_end_vertex_on_canvas(self): self.identify_end_vertex = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_end_vertex.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_end_vertex.featureIdentified.connect(self.on_end_vertex_identified) self.canvas.setMapTool(self.identify_end_vertex) def on_start_vertex_identified(self, feature): cb = self.startVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_end_vertex_identified(self, feature): cb = self.endVertexComboBox items = [cb.itemText(i) for i in range(cb.count())] for i, e in enumerate(items): if int(feature.id()) == int(e): cb.setCurrentIndex(i) def on_vtx_start_pressed(self, idx): self.vtx_start = self.startVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_start, 0) self.endVertexComboBox.setEnabled(True) self.endVertextoolButton.setEnabled(True) def on_vtx_end_pressed(self, idx): self.vtx_end = self.endVertexComboBox.itemData(idx, 32) self.select_vertices(self.vtx_end, 1) self.creatorComboBox.setEnabled(True) def select_vertices(self, feature, i): if feature: self.selected_vertices[i] = feature.id() else: self.selected_vertices[i] = None self.l_vertex.setSelectedFeatures(self.selected_vertices) def unselect_vertices(self): self.l_vertex.setSelectedFeatures([]) def create_edge(self): # If edge already exists, delete it.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) # Two vertices are needed.. if not self.vtx_start or not self.vtx_end: return self.canvas.refresh() # Two DIFFERENT vertices.. if self.vtx_start == self.vtx_end: return self.canvas.refresh() # Create line geometry.. line = QgsGeometry.fromPolyline([self.vtx_start.geometry().asPoint(), self.vtx_end.geometry().asPoint()]) # Create the feature.. self.edge = QgsFeature() self.edge.setGeometry(line) self.edge.setFields(self.l_edge.pendingFields()) self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), QPyNullVariant(int)]) # Add feature to layer.. self.l_edge.addFeature(self.edge) self.canvas.refresh() def on_accepted(self): if not self.edge: return False self.lim_ge_createur = self.auth_creator[self.creatorComboBox.currentIndex()][0] self.edge.setAttributes( [QPyNullVariant(int), QPyNullVariant(int), self.lim_ge_createur]) self.l_edge.updateFeature(self.edge) self.canvas.refresh() self.save = True self.close() def on_rejected(self): # Do not save the feature.. if self.edge: self.l_edge.deleteFeature(self.edge.id()) self.unselect_vertices() self.canvas.refresh() self.close() def on_reset(self): self.startVertexComboBox.setCurrentIndex(0) # self.startVertexComboBox.setEnabled(True) # self.startVertexLabel.setEnabled(True) self.endVertexComboBox.setCurrentIndex(0) self.endVertexComboBox.setEnabled(False) self.endVertexLabel.setEnabled(False) self.endVertextoolButton.setEnabled(False) for i, e in enumerate(self.auth_creator): if self.user == e[0]: self.creatorComboBox.setCurrentIndex(i) self.creatorComboBox.setEnabled(False) self.creatorLabel.setEnabled(False) self.unselect_vertices() self.canvas.refresh()
class TransfoPtToPlot(QDialog, gui_dlg_transfo_pttoplot): def __init__(self, canvas, project, l_vertex, l_edge, parent=None): super(TransfoPtToPlot, self).__init__(parent) self.setupUi(self) self.canvas = canvas self.project = project self.l_edge = l_edge self.l_vertex = l_vertex self.sel_nw_vtx = None self.resize_dlg = ResizeDlg(self, "dlg_transfo_pt_to_plots") self.resize_params = self.resize_dlg.load_dlgresize() self.resize_on = self.resize_params["dlg_transfo_pt_to_plots"] self.buttValid.clicked.connect(self.close) self.buttResize.clicked.connect(self.resize_dlg.dlg_ch_resize) self.selrfuvtxnearButt.clicked.connect(self.sel_nwvtxnear_rfu) self.nearvtxvalButt.clicked.connect(self.nwvtx_valid) self.selnwvxtButt.clicked.connect(self.sel_nwvtxfar) self.selrfuvtxfarButt.clicked.connect(self.sel_rfuvtxfar) self.nearvtxTbv.clicked.connect(self.tbv_sel) # Delete Widget on close event self.setAttribute(Qt.WA_DeleteOnClose) # Zoom to 2 new + RFU vertices if a line is selected in the tableview def tbv_sel(self): # Find the selected cell (considering only the first selected cell) idx = self.nearvtxTbv.selectedIndexes()[0].row() # Find the new vertex feature and the near RFU vertex feature self.sel_nw_vtx = self.nr_feats[idx] id_rfu_vtx = self.nr_feats[idx]["point_rfu_proche"] rfu_vtx = feats_by_cond(self.l_vertex, r"@id_noeud", id_rfu_vtx)[0] # Zoom to the 2 features self.canvas.zoomToFeatureIds(self.l_vertex, [self.sel_nw_vtx.id(), rfu_vtx.id()]) # Let the user select the new vertex to transform into a plot def sel_nwvtxfar(self): # Selection in the canvas self.hide() self.identify_nwvtxfar_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_nwvtxfar_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_nwvtxfar_vtx.featureIdentified.connect(self.far_nwvtx_identified) self.canvas.setMapTool(self.identify_nwvtxfar_vtx) def far_nwvtx_identified(self, feat): self.l_vertex.selectByIds([feat.id()]) # Check if the point selected is a new vertex if not feat[r"@id_noeud"]: self.sel_nw_vtx = feat self.canvas.unsetMapTool(self.identify_nwvtxfar_vtx) self.dlg_show() else: QMessageBox.warning(self, tr_vtxplt_notnwvtx_msg[0], tr_vtxplt_notnwvtx_msg[1]) # Let the user select the RFU vertex to use with the far new vertex def sel_rfuvtxfar(self): # Selection in the canvas if self.sel_nw_vtx: self.hide() self.identify_rfuvtxfar_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_rfuvtxfar_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_rfuvtxfar_vtx.featureIdentified.connect(partial(self.rfu_vtx_identified, "far")) self.canvas.setMapTool(self.identify_rfuvtxfar_vtx) # Message if no line selected in the tableview else: QMessageBox.warning(self, tr_vtxplt_sel_nonwvtxsel_msg[0], tr_vtxplt_sel_nonwvtxsel_msg[1]) # Let the user select the RFU vertex near the new vertex def sel_nwvtxnear_rfu(self): # Selection in the canvas if self.sel_nw_vtx: self.hide() self.identify_rfu_vtx = QgsMapToolIdentifyFeature(self.canvas, self.l_vertex) self.identify_rfu_vtx.setCursor(QCursor(Qt.PointingHandCursor)) self.identify_rfu_vtx.featureIdentified.connect(partial(self.rfu_vtx_identified, "near")) self.canvas.setMapTool(self.identify_rfu_vtx) # Message if no line selected in the tablview else: QMessageBox.warning(self, tr_vtxplt_sel_nolinesel_msg[0], tr_vtxplt_sel_nolinesel_msg[1]) def rfu_vtx_identified(self, vtx_type, feat): self.vtx_type = vtx_type self.l_vertex.selectByIds([feat.id()]) if self.vtx_type == "near": self.canvas.unsetMapTool(self.identify_rfu_vtx) else: self.canvas.unsetMapTool(self.identify_rfuvtxfar_vtx) # Check if the point selected is a RFU vertex if feat[r"@id_noeud"]: id_node = feat[r"@id_noeud"] # Tolerance in cm tol = feat[r"som_tolerance"]*100 nw_coord_e = self.sel_nw_vtx["som_coord_est"] nw_coord_n = self.sel_nw_vtx["som_coord_nord"] nw_rep_plane = self.sel_nw_vtx["som_representation_plane"] nw_pt_cc = QgsPointXY(self.sel_nw_vtx["som_coord_est"], self.sel_nw_vtx["som_coord_nord"]) rfu_pt_cc = QgsPointXY(feat["som_coord_est"], feat["som_coord_nord"]) # Distance between the 2 points in cm dist_vtx = dist_2_pts(nw_pt_cc, rfu_pt_cc)*100 if dist_vtx < tol: self.vtx_type = "near" # Check if the 2 points have the same som_representation_plane # Otherwise, cancel the process if nw_rep_plane == feat["som_representation_plane"]: if self.vtx_type == "near": tl_msg = tr_vtxplt_confirm_msg[0] txt_msg = tr_vtxplt_confirm_msg[1].format(nw_coord_e, nw_coord_n, id_node) else: tl_msg = tr_vtxplt_attest_msg[0] txt_msg = tr_vtxplt_attest_msg[1].format(nw_coord_e, nw_coord_n, id_node, dist_vtx, tol) confirm = QMessageBox.question( self, tl_msg, txt_msg, QMessageBox.Yes | QMessageBox.No) if confirm == QMessageBox.Yes: nw_vals = {} for att in tr_toplot_atts: id_att = self.l_vertex.fields().indexFromName(att) nw_vals[id_att] = self.sel_nw_vtx[att] # Change the atteste_qualite value if self.vtx_type == "far": id_att = self.l_vertex.fields().indexFromName("attestation_qualite") nw_vals[id_att] = "true" self.l_vertex.changeAttributeValues(feat.id(), nw_vals) self.l_vertex.deleteFeature(self.sel_nw_vtx.id()) self.tr_edges(self.sel_nw_vtx.geometry(), feat.geometry()) self.canvas.refresh() QMessageBox.information( self, tr_vtxplot_transfok_msg[0], tr_vtxplot_transfok_msg[1].format(nw_coord_e, nw_coord_n, id_node)) # Process canceled by the user else: QMessageBox.information(self, tr_vtxplt_canceld_msg[0], tr_vtxplt_canceld_msg[1]) # Case of no same som_representation_plane else: QMessageBox.warning(self, tr_vtxplot_nosamerp_msg[0], tr_vtxplot_nosamerp_msg[1]) self.nearvtxTbv.clearSelection() self.sel_nw_vtx = None # Deselect point self.l_vertex.selectByIds([]) self.dlg_show() else: QMessageBox.warning(self, tr_vtxplt_notrfuvtx_msg[0], tr_vtxplt_notrfuvtx_msg[1]) if self.vtx_type == "near": self.sel_nwvtxnear_rfu() else: self.sel_rfuvtxfar() # Move edges if they are linked to a new vertex transformed into plot def tr_edges(self, old_geom, nw_geom): # Transformations to obtain the WGS84 or the CC coordinates coords_tr_wgs, coords_tr_cc = crs_trans_params(self.canvas, self.project) old_geom_pt = old_geom.asPoint() nw_geom_pt = nw_geom.asPoint() old_geom_cc = coords_tr_cc.transform(old_geom_pt) # Process only new edges nw_edges = feats_by_cond(self.l_edge, "@id_arc", NULL) if len(nw_edges) > 0: for edge_ft in nw_edges: ch_geom = False edge_ft_line = edge_ft.geometry().asPolyline() start_pt = edge_ft_line[0] end_pt = edge_ft_line[-1] # Comparison done on cc coordinates start_pt_cc = coords_tr_cc.transform(start_pt) end_pt_cc = coords_tr_cc.transform(end_pt) # Case of start point to move if check_identical_pts(old_geom_cc, start_pt_cc, 2): self.l_edge.moveVertex(nw_geom_pt.x(), nw_geom_pt.y(), edge_ft.id(), 0) nw_line_g = QgsGeometry.fromPolylineXY([nw_geom_pt, end_pt]) ch_geom = True # Case of end point to move if check_identical_pts(old_geom_cc, end_pt_cc, 2): self.l_edge.moveVertex(nw_geom_pt.x(), nw_geom_pt.y(), edge_ft.id(), 1) nw_line_g = QgsGeometry.fromPolylineXY([start_pt, nw_geom_pt]) ch_geom = True # Check if new line is the same as an existing edge_ft # In this case, delete the new line if ch_geom: for old_edge_ft in self.l_edge.getFeatures(): if old_edge_ft.id() != edge_ft.id() and \ check_identical_lines(old_edge_ft.geometry().asPolyline(), nw_line_g.asPolyline(), 12): self.l_edge.deleteFeature(edge_ft.id()) # Let the user valid the new vertex def nwvtx_valid(self): # Reset the point_rfu_proche field if self.sel_nw_vtx: self.l_vertex.changeAttributeValue(self.sel_nw_vtx.id(), 10, NULL) # self.l_vertex.commitChanges() self.canvas.refresh() QMessageBox.information(self, tr_vtxplt_valid_msg[0], tr_vtxplt_valid_msg[1].format(self.sel_nw_vtx["som_coord_est"], self.sel_nw_vtx["som_coord_nord"])) self.nearvtxTbv.clearSelection() self.sel_nw_vtx = None self.hide() self.dlg_show() # Message if no line selected in the tablview else: QMessageBox.warning(self, tr_vtxplt_nolinesel_msg[0], tr_vtxplt_nolinesel_msg[1]) # Launch the dlg appearence def dlg_show(self): self.nr_feats = [] # Create the tableview self.tr_vtxtbl_data = [] tr_vtxtbl_hd = [] # Build the header for fld_name in tr_vtx_atts: tr_vtxtbl_hd.append(fld_name) # Build the contents nb_rows = 0 for obj in self.l_vertex.getFeatures(): if obj['point_rfu_proche']: tr_vtxtbl_row = [] for fld_name in tr_vtx_atts: tr_vtxtbl_row.append(str(obj[fld_name])) self.tr_vtxtbl_data.append(tr_vtxtbl_row) self.nr_feats.append(obj) nb_rows += 1 if nb_rows != 0: tr_vtxtbl_model=MyTableModel(self, self.tr_vtxtbl_data, tr_vtxtbl_hd) # Populate data in the tableview self.nearvtxTbv.setModel(tr_vtxtbl_model) self.height_tbv = 0 self.width_tbv = 0 # Set column width to fit contents self.nearvtxTbv.resizeColumnsToContents() # Increase a little bit the width of the columns for id_col, val_col in enumerate(tr_vtxtbl_hd): nw_size = self.nearvtxTbv.columnWidth(id_col) + 5 self.nearvtxTbv.setColumnWidth(id_col, nw_size) self.width_tbv += nw_size # Set row height self.nearvtxTbv.resizeRowsToContents() self.height_tbv = (self.nearvtxTbv.rowHeight(0)) * (nb_rows+1) self.width_tbv += 45 self.height_tbv += 330 self.resize_dlg.wtbv = self.width_tbv self.resize_dlg.htbv = self.height_tbv # Hide vertical header vh = self.nearvtxTbv.verticalHeader() vh.setVisible(False) else: self.nearvtxGp.hide() self.width_tbv = dlg_transfo_pt_to_plots_sw self.height_tbv = 176 self.resize_dlg.wtbv = self.width_tbv self.resize_dlg.htbv = self.height_tbv if self.resize_on: self.resize_dlg.dlg_auto_resize() self.show() def to_close(self): self.close()
class MapWindow(QMainWindow): """This class offers a canvas and tools to select polygons from a vector layer provided by the main app.""" # signal emitted when polygons succesfully selected finished = pyqtSignal() def __init__(self): QMainWindow.__init__(self) #self.setWindowFlags(Qt.CustomizeWindowHint) #self.setWindowFlags(Qt.WindowMinMaxButtonsHint) # creating map canvas, which draws the maplayers # setting up features like canvas color self.canvas = QgsMapCanvas() self.canvas.setMinimumSize(550, 700) self.canvas.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.canvas.setCanvasColor(Qt.white) self.canvas.setSelectionColor(QColor(255,255,26,200)) self.canvas.enableAntiAliasing(True) self.canvas.setParallelRenderingEnabled(True) # empty list for selected polygons self.selected_features = [] # setting up label settings: object below houses all of them self.label_settings = QgsPalLayerSettings() # object for text settings text_format = QgsTextFormat() text_format.setFont(QFont("Helvetica", 12)) text_format.setSize(7) # setting up a white buffer around the labels buffer_settings = QgsTextBufferSettings() buffer_settings.setEnabled(True) buffer_settings.setSize(0.65) buffer_settings.setColor(Qt.white) text_format.setBuffer(buffer_settings) # label settings: # fieldName = which field is shown as the label (currently Finnish name) # placement = labels can be placed differently in relation to one another # - see documentation for details self.label_settings.setFormat(text_format) self.label_settings.fieldName = "namefin" self.label_settings.placement = 0 self.label_settings.enabled = True # Qmainwindow requires a central widget. Canvas is placed self.setCentralWidget(self.canvas) # creating each desired action self.actionGet = QAction("Return selected and close", self) self.actionPan = QAction("Pan tool", self) self.actionSelect = QAction("Select tool", self) self.actionClear = QAction("Clear selection", self) self.actionCancel = QAction("Cancel and close", self) # these two function as on/off. the rest are clickable self.actionPan.setCheckable(True) self.actionSelect.setCheckable(True) # when actions are clicked, do corresponding function self.actionPan.triggered.connect(self.pan) self.actionSelect.triggered.connect(self.select) self.actionClear.triggered.connect(self.clearSelection) self.actionGet.triggered.connect(self.finishedSelection) self.actionCancel.triggered.connect(self.cancel) # toolbar at the top of the screen: houses actions as buttons # change order here to change their placement on window self.toolbar = self.addToolBar("Canvas actions") self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu) self.toolbar.setMovable(False) self.toolbar.addAction(self.actionGet) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionSelect) self.toolbar.addAction(self.actionClear) self.toolbar.addAction(self.actionCancel) # link actions to premade map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolSelect = QgsMapToolIdentifyFeature(self.canvas) self.toolSelect.setAction(self.actionSelect) self.toolSelect.featureIdentified.connect(self.selectFeature) self.blocks_flag = False self.selection_rectangle = False # set select tool as default self.select() def pan(self): """Simply activates the tool""" self.canvas.setMapTool(self.toolPan) def select(self): self.canvas.setMapTool(self.toolSelect) def addLayer(self, layer): """Called when user click button on the main plugin: receives a vector layer, sets up labels & rendering parameters and shows the layer.""" # empty output list in case function is called multiple times self.selected_features.clear() self.selection_rectangle = False # layer into a self variable self.layer = layer # add layer to project: required to show it on screen # False = do not show the layer on the legend listing nor draw on main canvas QgsProject.instance().addMapLayer(self.layer, False) # set up visual stuff self.layer.setLabelsEnabled(True) layer_labeling = QgsVectorLayerSimpleLabeling(self.label_settings) self.layer.setLabeling(layer_labeling) self.layer.renderer().symbol().setColor(QColor(220,220,220)) # select tool needs a vector layer assigned to it self.toolSelect.setLayer(self.layer) self.canvas.setExtent(self.layer.extent()) # set layer to canvas self.canvas.setLayers([self.layer]) # show to user self.show() def addBlocksLayer(self, layer): self.selected_features.clear() self.blocks_flag = True self.layer = layer QgsProject.instance().addMapLayer(self.layer, False) self.layer.renderer().symbol().setColor(Qt.cyan) self.layer.renderer().symbol().setOpacity(0.30) # select tool needs a vector layer assigned to it self.toolSelect.setLayer(self.layer) self.canvas.setExtent(self.layer.extent()) # set layer to canvas """ url = ("https://vm0160.kaj.pouta.csc.fi/geoserver/ows?service=wfs&version=2.0.0"+ "&request=GetFeature&typename=ogiir:maakuntajako_2018_4500k&pagingEnabled=true") self.bg_layer = QgsVectorLayer(url, "BACKGROUND-REMOVE", "WFS") """ self.bg_layer = QgsRasterLayer("url=https://vm0160.kaj.pouta.csc.fi/ogiir_cache/wmts/1.0.0/" + "WMTSCapabilities.xml&crs=EPSG:3067&dpiMode=7&format=image/"+ "png&layers=taustakartta&styles=default&tileMatrixSet=GRIDI-FIN", 'GEOCUBES BG-LAYER - TEMPORARY', 'wms') if self.bg_layer.isValid(): QgsProject.instance().addMapLayer(self.bg_layer, False) self.canvas.setLayers([self.layer, self.bg_layer]) else: self.canvas.setLayers([self.layer]) self.show() def selectFeature(self, feat): """Activated when user clicks something on screen. This returns the clicked feature. The function does 2 things: 1. selects the feature on the map / deselects if already selected 2. adds features to a list in the same format (name, id_code) as they're stored in the 'Admin areas box' in the main file """ idx = feat.id() if self.blocks_flag: xmin = feat[0] ymax = feat[1] label = str(xmin) + "|" + str(ymax) else: code = feat[1] name = feat[2] label = name + "|" + code if label in self.selected_features: self.layer.deselect(idx) self.selected_features.remove(label) else: self.layer.select(idx) self.selected_features.append(label) def clearSelection(self): """Clear map selection and list on button click""" self.layer.removeSelection() self.selected_features.clear() def finishedSelection(self): """Activated when user clicks 'return selection'. Closes window and emits signal to indicate the job is finished""" self.close() self.finished.emit() def cancel(self): """In case user changes their mind. Does the same as above, but doesn't emit signal.""" self.close() def getSelection(self): """Returns list of selected features (polygons)""" return self.selected_features def getSelectionBbox(self): return self.selection_rectangle def closeEvent(self, event): """Activated anytime Mapwindow is closed either by buttons given or if the user finds some other way to close the window. Removes selection and deletes scrap maplayer.""" self.selection_rectangle = self.layer.boundingBoxOfSelected() self.layer.removeSelection() QgsProject.instance().removeMapLayer(self.layer) try: QgsProject.instance().removeMapLayer(self.bg_layer) except Exception: pass self.blocks_flag = False QMainWindow.closeEvent(self, event)
def set_canvas(self, map_canvas): self.map_tool = QgsMapToolIdentifyFeature(map_canvas) self.map_tool.setButton(self.map_identification_button) self.canvas = map_canvas
def __init__(self): QMainWindow.__init__(self) #self.setWindowFlags(Qt.CustomizeWindowHint) #self.setWindowFlags(Qt.WindowMinMaxButtonsHint) # creating map canvas, which draws the maplayers # setting up features like canvas color self.canvas = QgsMapCanvas() self.canvas.setMinimumSize(550, 700) self.canvas.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.canvas.setCanvasColor(Qt.white) self.canvas.setSelectionColor(QColor(255,255,26,200)) self.canvas.enableAntiAliasing(True) self.canvas.setParallelRenderingEnabled(True) # empty list for selected polygons self.selected_features = [] # setting up label settings: object below houses all of them self.label_settings = QgsPalLayerSettings() # object for text settings text_format = QgsTextFormat() text_format.setFont(QFont("Helvetica", 12)) text_format.setSize(7) # setting up a white buffer around the labels buffer_settings = QgsTextBufferSettings() buffer_settings.setEnabled(True) buffer_settings.setSize(0.65) buffer_settings.setColor(Qt.white) text_format.setBuffer(buffer_settings) # label settings: # fieldName = which field is shown as the label (currently Finnish name) # placement = labels can be placed differently in relation to one another # - see documentation for details self.label_settings.setFormat(text_format) self.label_settings.fieldName = "namefin" self.label_settings.placement = 0 self.label_settings.enabled = True # Qmainwindow requires a central widget. Canvas is placed self.setCentralWidget(self.canvas) # creating each desired action self.actionGet = QAction("Return selected and close", self) self.actionPan = QAction("Pan tool", self) self.actionSelect = QAction("Select tool", self) self.actionClear = QAction("Clear selection", self) self.actionCancel = QAction("Cancel and close", self) # these two function as on/off. the rest are clickable self.actionPan.setCheckable(True) self.actionSelect.setCheckable(True) # when actions are clicked, do corresponding function self.actionPan.triggered.connect(self.pan) self.actionSelect.triggered.connect(self.select) self.actionClear.triggered.connect(self.clearSelection) self.actionGet.triggered.connect(self.finishedSelection) self.actionCancel.triggered.connect(self.cancel) # toolbar at the top of the screen: houses actions as buttons # change order here to change their placement on window self.toolbar = self.addToolBar("Canvas actions") self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu) self.toolbar.setMovable(False) self.toolbar.addAction(self.actionGet) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionSelect) self.toolbar.addAction(self.actionClear) self.toolbar.addAction(self.actionCancel) # link actions to premade map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolSelect = QgsMapToolIdentifyFeature(self.canvas) self.toolSelect.setAction(self.actionSelect) self.toolSelect.featureIdentified.connect(self.selectFeature) self.blocks_flag = False self.selection_rectangle = False # set select tool as default self.select()