def _get_layers_from_coordinates(self, point, rb_list, tab_type=None): cursor = QCursor() x = cursor.pos().x() y = cursor.pos().y() click_point = QPoint(x + 5, y + 5) visible_layers = tools_qgis.get_visible_layers(as_str_list=True) scale_zoom = self.iface.mapCanvas().scale() # Get layers under mouse clicked extras = f'"pointClickCoords":{{"xcoord":{point.x()}, "ycoord":{point.y()}}}, ' extras += f'"visibleLayers":{visible_layers}, ' extras += f'"zoomScale":{scale_zoom} ' body = tools_gw.create_body(extras=extras) json_result = tools_gw.execute_procedure( 'gw_fct_getlayersfromcoordinates', body, rubber_band=self.rubber_band) if not json_result or json_result['status'] == 'Failed': return False # hide QMenu identify if no feature under mouse len_layers = len(json_result['body']['data']['layersNames']) if len_layers == 0: return False self.icon_folder = self.plugin_dir + '/icons/' # Right click main QMenu main_menu = QMenu() # Create one menu for each layer for layer in json_result['body']['data']['layersNames']: layer_name = tools_qgis.get_layer_by_tablename(layer['layerName']) icon_path = self.icon_folder + layer['icon'] + '.png' if os.path.exists(str(icon_path)): icon = QIcon(icon_path) sub_menu = main_menu.addMenu(icon, layer_name.name()) else: sub_menu = main_menu.addMenu(layer_name.name()) # Create one QAction for each id for feature in layer['ids']: if 'label' in feature: label = str(feature['label']) else: label = str(feature['id']) action = QAction(label, None) action.setProperty('feature_id', str(feature['id'])) sub_menu.addAction(action) action.triggered.connect( partial(self._get_info_from_selected_id, action, tab_type)) action.hovered.connect( partial(self._draw_by_action, feature, rb_list)) main_menu.addSeparator() # Identify all cont = 0 for layer in json_result['body']['data']['layersNames']: cont += len(layer['ids']) action = QAction(f'Identify all ({cont})', None) action.hovered.connect( partial(self._identify_all, json_result, rb_list)) main_menu.addAction(action) main_menu.addSeparator() main_menu.exec_(click_point)
def mouseMoveEvent(self, event, useLast=False): """ @type event: QMouseEvent @param event: @return: """ if event is not None: self.lastMouseX = event.x() self.lastMouseY = event.y() if useLast is False and self.lastMouseX != -1 and self.lastMouseY != -1: # generates an event that simulates a mouse move, because even if # mouse is still, video is running and mouse lat/lon must be # updated. event = QMouseEvent( QEvent.MouseMove, QPoint( self.lastMouseX, self.lastMouseY), Qt.NoButton, Qt.NoButton, Qt.NoModifier) else: return # Magnifier can move on black screen for show image borders if self._interaction.magnifier: self.dragPos = event.pos() self.UpdateSurface() # check if the point is on picture (not in black borders) if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): self.setCursor(QCursor(Qt.ArrowCursor)) self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry) return # Prevent draw on video if not started or finished # if self.parent.player.position() == 0: # return # Mouse cursor drawing if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.measureDistance or self._interaction.measureArea or self._interaction.censure or self._interaction.objectTracking: self.setCursor(QCursor(Qt.CrossCursor)) # Cursor Coordinates if GetGCPGeoTransform() is not None: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) tr = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:4326'), iface.mapCanvas().mapSettings().destinationCrs(), QgsProject.instance().transformContext()) mapPt = tr.transform(QgsPointXY(Longitude, Latitude)) vertices = self.Cursor_Canvas_RubberBand.numberOfVertices() if vertices > 0: self.Cursor_Canvas_RubberBand.removePoint(0, True, 0) self.Cursor_Canvas_RubberBand.movePoint(mapPt, 0) else: self.Cursor_Canvas_RubberBand.addPoint(mapPt) if self._MGRS: try: mgrsCoords = mgrs.toMgrs(Latitude, Longitude) except Exception: mgrsCoords = "" txt = "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%s" % mgrsCoords) + "</span>" else: txt = "<span style='font-size:10pt; font-weight:bold;'>Lon : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.5f" % Longitude) + "</span>" txt += "<span style='font-size:10pt; font-weight:bold;'> Lat : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.5f" % Latitude) + "</span>" if hasElevationModel(): txt += "<span style='font-size:10pt; font-weight:bold;'> Alt : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.0f" % Altitude) + "</span>" else: txt += "<span style='font-size:10pt; font-weight:bold;'> Alt : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>" self.parent.lb_cursor_coord.setText(txt) # Polygon drawer mouseMoveEvent if self._interaction.polygonDrawer: self.AddMoveEventValue( self.drawPolygon, Longitude, Latitude, Altitude) # Line drawer mouseMoveEvent if self._interaction.lineDrawer: self.AddMoveEventValue( self.drawLines, Longitude, Latitude, Altitude) # Measure Distance drawer mouseMoveEvent if self._interaction.measureDistance and self.drawMeasureDistance: self.AddMoveEventValue( self.drawMeasureDistance, Longitude, Latitude, Altitude) # Measure Area drawer mouseMoveEvent if self._interaction.measureArea and self.drawMeasureArea: self.AddMoveEventValue( self.drawMeasureArea, Longitude, Latitude, Altitude) else: self.parent.lb_cursor_coord.setText( "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>" + "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>" + "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>") # Object tracking rubberband if not self.Tracking_Video_RubberBand.isHidden(): self.Tracking_Video_RubberBand.setGeometry( QRect(self.origin, event.pos()).normalized()) # Censure rubberband if not self.Censure_RubberBand.isHidden(): self.Censure_RubberBand.setGeometry( QRect(self.origin, event.pos()).normalized())
def drawHistogram(self): #if self.inputlayer is None: # return self.showInfo("Drawing histogram...") viewprect = QRectF(self.histoGraphicsView.viewport().rect()) self.histoGraphicsView.setSceneRect(viewprect) self.setupScene.clear() self.setupScene.update() histbottom = self.histoGraphicsView.sceneRect().bottom() histtop = self.histoGraphicsView.sceneRect().top() left = self.histoGraphicsView.sceneRect().left() + self.histopadding right = self.histoGraphicsView.sceneRect().right() - self.histopadding histheight = histbottom - histtop histwidth = right - left step = 1.0 * histwidth / self.histobins maxlength = histheight padding = 1 ll = QPoint(self.histopadding - 1, histheight - padding) start = QPointF(self.histoGraphicsView.mapToScene(ll)) # Check if there is only one value #myrange = (self.minValueSpinBox.value(),self.maxValueSpinBox.value()) if self.histogramAvailable: maxvalue = 0.0 for i in range(len(self.histo[0])): if self.histo[0][i] > maxvalue: maxvalue = self.histo[0][i] if maxvalue == 0: return self.maxBinNumber.setText(str(maxvalue)) # Create the histogram: #self.showInfo("maxvalue: " + str(maxvalue)) #self.showInfo("maxlength: " + str(maxlength)) #self.showInfo("step: " + str(step)) for i in range(self.histobins): binnumber = self.histo[0][i] if binnumber == 0: continue height = (1.0 * self.histo[0][i] / maxvalue * (maxlength - padding)) rectangle = QGraphicsRectItem(start.x() + step * i, start.y(), step, -height) rectangle.setPen(QPen(QColor(102, 102, 102))) rectangle.setBrush(QBrush(QColor(240, 240, 240))) self.setupScene.addItem(rectangle) #self.showInfo(str(i) + ": " + str(height)) #if self.levelsListView.model().rowCount() > 0: # Add lines for the levels minvalue = float(self.histMinValue.text()) maxvalue = float(self.histMaxValue.text()) datarange = maxvalue - minvalue if datarange == 0: return i = 0 while self.levelsListView.model().item(i): #self.showInfo("Element: " + # str(self.levelsListView.model().item(i).text())) #continue value = float(self.levelsListView.model().item(i).text()) xvalue = start.x() + histwidth * (value - minvalue) / datarange line = QGraphicsLineItem(xvalue, 0, xvalue, histheight) if i == 0 or i == (self.levelsListView.model().rowCount() - 1): line.setPen(QPen(QColor(204, 0, 0))) else: line.setPen(QPen(QColor(0, 204, 0))) self.setupScene.addItem(line) i = i + 1
def canvasMoveEvent(self, event): self.moved.emit(QPoint(event.pos().x(), event.pos().y()))
def paintEvent(self, event): """ @type event: QPaintEvent @param event: @return: """ if not self.surface.isActive(): return self.painter = QPainter(self) self.painter.setRenderHint(QPainter.HighQualityAntialiasing) region = event.region() self.painter.fillRect( region.boundingRect(), self.brush) # Background painter color try: self.surface.paint(self.painter) SetImageSize(self.currentFrame().width(), self.currentFrame().height()) except Exception: None # Prevent draw on video if not started or finished # if self.parent.player.position() == 0: # self.painter.end() # return # Draw On Video draw.drawOnVideo( self.drawPtPos, self.drawLines, self.drawPolygon, self.drawMeasureDistance, self.drawMeasureArea, self.drawCesure, self.painter, self.surface, GetGCPGeoTransform()) # Draw On Video Object tracking Object if self._interaction.objectTracking and self._isinit: frame = convertQImageToMat(self.currentFrame()) offset = self.surface.videoRect() # Update tracker result = resize(frame, (offset.width(), offset.height())) ok, bbox = self.tracker.update(result) # Draw bounding box if ok: # check negative values x = bbox[0] + offset.x() y = bbox[1] + offset.y() if vut.IsPointOnScreen(x, y, self.surface): self.painter.setPen(self.blue_Pen) self.painter.setBrush(Qt.transparent) self.painter.drawRect(x, y, bbox[2], bbox[3]) # Get Track object center xc = x + (bbox[2] / 2) yc = y + (bbox[3] / 2) p = QPoint(xc, yc) Longitude, Latitude, _ = vut.GetPointCommonCoords( p, self.surface) # Draw Rubber Band on canvas self.Track_Canvas_RubberBand.addPoint( QgsPointXY(Longitude, Latitude)) else: self._isinit = False del self.tracker # Magnifier Glass if self._interaction.magnifier and not self.dragPos.isNull(): draw.drawMagnifierOnVideo( self, self.dragPos, self.currentFrame(), self.painter) # Stamp On Video if self._interaction.stamp: draw.drawStampOnVideo(self, self.painter) self.painter.end() return
def __init__(self, iface: QgisInterface, version: str, plugin_dir: str, isBatch: bool, isHUC: bool=False, logFile: Optional[str]=None) -> None: """Initialise class variables.""" settings = QSettings() if settings.contains('/QSWATPlus/SWATPlusDir'): SWATPlusDir = settings.value('/QSWATPlus/SWATPlusDir') if not os.path.isdir(SWATPlusDir): SWATPlusDir = Parameters._SWATPLUSDEFAULTDIR else: SWATPlusDir = Parameters._SWATPLUSDEFAULTDIR if not os.path.isdir(SWATPlusDir): QSWATUtils.error('''Cannot find SWATPlus directory, expected to be {0}. Please use the Parameters form to set its location.'''.format(SWATPlusDir), isBatch) else: settings.setValue('/QSWATPlus/SWATPlusDir', SWATPlusDir) ## SWATPlus directory self.SWATPlusDir = SWATPlusDir ## Directory containing QSWAT plugin self.plugin_dir = plugin_dir ## Databases directory: part of plugin # containing template project and reference databases, plus soil database for STATSGO and SSURGO self.dbPath = QSWATUtils.join(self.SWATPlusDir, Parameters._DBDIR) ## Path of template project database self.dbProjTemplate = QSWATUtils.join(self.dbPath, Parameters._DBPROJ) ## Path of template reference database self.dbRefTemplate = QSWATUtils.join(self.dbPath, Parameters._DBREF) ## Directory of TauDEM executables self.TauDEMDir = TauDEMUtils.findTauDEMDir(settings, not isBatch)[0] ## Path of mpiexec self.mpiexecPath = TauDEMUtils.findMPIExecPath(settings) proj: QgsProject = QgsProject.instance() title = proj.title() ## QGIS interface self.iface = iface ## project projection (set from DEM) self.crsProject: Optional[QgsCoordinateReferenceSystem] = None ## Stream burn-in depth self.burninDepth: int = proj.readNumEntry(title, 'params/burninDepth', Parameters._BURNINDEPTH)[0] ## Channel width multiplier self.channelWidthMultiplier: float = proj.readDoubleEntry(title, 'params/channelWidthMultiplier', Parameters._CHANNELWIDTHMULTIPLIER)[0] ## Channel width exponent self.channelWidthExponent: float = proj.readDoubleEntry(title, 'params/channelWidthExponent', Parameters._CHANNELWIDTHEXPONENT)[0] ## Channel depth multiplier self.channelDepthMultiplier: float = proj.readDoubleEntry(title, 'params/channelDepthMultiplier', Parameters._CHANNELDEPTHMULTIPLIER)[0] ## Channel depth exponent self.channelDepthExponent: float = proj.readDoubleEntry(title, 'params/channelDepthExponent', Parameters._CHANNELDEPTHEXPONENT)[0] ## reach slope multiplier self.reachSlopeMultiplier: float = proj.readDoubleEntry(title, 'params/reachSlopeMultiplier', Parameters._MULTIPLIER)[0] ## tributary slope multiplier self.tributarySlopeMultiplier: float = proj.readDoubleEntry(title, 'params/tributarySlopeMultiplier', Parameters._MULTIPLIER)[0] ## mean slope multiplier self.meanSlopeMultiplier: float = proj.readDoubleEntry(title, 'params/meanSlopeMultiplier', Parameters._MULTIPLIER)[0] ## main length multiplier self.mainLengthMultiplier: float = proj.readDoubleEntry(title, 'params/mainLengthMultiplier', Parameters._MULTIPLIER)[0] ## tributary length multiplier self.tributaryLengthMultiplier: float = proj.readDoubleEntry(title, 'params/tributaryLengthMultiplier', Parameters._MULTIPLIER)[0] ## upslope HRU drain percent self.upslopeHRUDrain: int = proj.readNumEntry(title, 'params/upslopeHRUDrain', Parameters._UPSLOPEHRUDRAIN)[0] ## Index of slope group in Layers panel self.slopeGroupIndex = -1 ## Index of landuse group in Layers panel self.landuseGroupIndex = -1 ## Index of soil group in Layers panel self.soilGroupIndex = -1 ## Index of watershed group in Layers panel self.watershedGroupIndex = -1 ## Index of results group in Layers panel self.resultsGroupIndex = -1 ## Index of animation group in Layers panel self.animationGroupIndex = -1 ## Flag showing if using existing watershed self.existingWshed = False ## Flag showing if using grid model self.useGridModel = False ## flag to show if using landscape units self.useLandscapes = False ## flag to show if dividing into left/right/headwater landscape units self.useLeftRight = False ## Path of DEM raster self.demFile = '' ## Path of filled DEM raster self.felFile = '' ## Path of stream burn-in shapefile self.burnFile = '' ## Path of DEM after burning-in self.burnedDemFile = '' ## Path of D8 flow direction raster self.pFile = '' ## Path of D8 flow accumulation raster self.ad8File = '' ## Path of subbasins raster self.basinFile = '' ## path of channel basins raster self.channelBasinFile = '' ## path of channel basins file with lakes masked out self.chBasinNoLakeFile = '' ## Path of channel raster self.srcChannelFile = '' ## Path of valleyDepthsFile # value at each point in this raster is the drop in metres # from the point to where its D8 flow path meets a channel # Channel elevations are measured at points adjacent to the channel # to avoid problems caused by burning-in self.valleyDepthsFile = '' ## Path of outlets shapefile self.outletFile = '' ## path of snapped outlets file self.snapFile = '' ## Path of outlets shapefile for extra reservoirs and point sources self.extraOutletFile = '' ## Path of stream shapefile self.streamFile = '' ## Path of stream shapefile calculated by delineation # since streamFile is set to streams from grid when using a grid model self.delinStreamFile = '' ## Path of channel shapefile self.channelFile = '' ## Path of subbasins shapefile or grid file when using grids self.subbasinsFile = '' ## Path of subbasins shapefile before lakes removed. Not used with grid models. self.subsNoLakesFile = '' ## Path of watershed shapefile: shows channel basins. Not used with grid models. self.wshedFile = '' ## Path of file like D8 contributing area but with heightened values at subbasin outlets self.hd8File = '' ## Path of distance to stream outlets raster self.distStFile = '' ## Path of distance to channel raster self.distChFile = '' ## Path of slope raster self.slopeFile = '' ## path of lakes shapefile self.lakeFile = '' ## Path of slope bands raster self.slopeBandsFile = '' ## Path of landuse raster self.landuseFile = '' ## Path of soil raster self.soilFile = '' ## path of floodplain raster self.floodFile = '' ## path of raster generated from playa lakes self.playaFile = '' ## Nodata value for DEM self.elevationNoData = 0.0 ## DEM horizontal block size self.xBlockSize = 0 ## DEM vertical block size self.yBlockSize = 0 ## Nodata value for basins raster self.basinNoData = 0 ## Nodata value for distance to outlets raster self.distStNoData = 0.0 ## Nodata value for distance to channel raster self.distChNoData = 0.0 ## Nodata value for slope raster self.slopeNoData = 0 ## Nodata value for landuse raster self.cropNoData = 0 ## Nodata value for soil raster self.soilNoData = 0 ## Nodata value for floodplain raster self.floodNoData = -1 ## Area of DEM cell in square metres self.cellArea = 0.0 ## channel threshold in square metres self.channelThresholdArea = 10000000.0 # 1000 hectares default ## gridSize as count of DEM cells per side (grid model only) self.gridSize = 0 ## list of landuses exempt from HRU removal self.exemptLanduses: List[str] = [] ## table of landuses being split self.splitLanduses: Dict[str, Dict[str, float]] = dict() ## Elevation bands threshold in metres self.elevBandsThreshold = 0 ## Number of elevation bands self.numElevBands = 0 ## Topology object self.topo: QSWATTopology = QSWATTopology(isBatch, isHUC) projFile: str = proj.fileName() projPath: str = QFileInfo(projFile).canonicalFilePath() pdir, base = os.path.split(projPath) ## Project name self.projName = os.path.splitext(base)[0] ## Project directory self.projDir = pdir ## QSWAT+ version self.version = version ## DEM directory self.demDir = '' ## Landuse directory self.landuseDir = '' ## Soil directory self.soilDir = '' ## Landscape directory self.landscapeDir = '' ## Floodplain directory self.floodDir = '' ## text directory self.textDir = '' ## Rasters directory self.rastersDir = '' ## Shapes directory self.shapesDir = '' ## Scenarios directory self.scenariosDir = '' ## Results directory self.resultsDir = '' ## Plots directory self.plotsDir = '' ## png directory for storing png images used to create animation videos self.pngDir = '' ## animation directory for storing animation files self.animationDir = '' self.createSubDirectories() ## path of full lsus shapefile self.fullLSUsFile = QSWATUtils.join(self.shapesDir, Parameters._LSUS1 + '.shp') ## path of actual lsus shapefile (after channel mergers self.actLSUsFile = QSWATUtils.join(self.shapesDir, Parameters._LSUS2 + '.shp') ## Path of FullHRUs shapefile self.fullHRUsFile = QSWATUtils.join(self.shapesDir, Parameters._HRUS1 + '.shp') ## Path of ActHRUs shapefile self.actHRUsFile = QSWATUtils.join(self.shapesDir, Parameters._HRUS2 + '.shp') ## Flag to show if running in batch mode self.isBatch = isBatch ## flag for HUC projects self.isHUC = isHUC ## log file for message output for HUC projects self.logFile = logFile ## Path of project database self.db: DBUtils = DBUtils(self.projDir, self.projName, self.dbProjTemplate, self.dbRefTemplate, self.isHUC, self.logFile, self.isBatch) ## multiplier to turn DEM distances to metres self.horizontalFactor = 1 ## multiplier to turn elevations to metres self.verticalFactor = 1 ## vertical units self.verticalUnits = Parameters._METRES # positions of sub windows ## Position of delineation form self.delineatePos = QPoint(0, 100) ## Position of HRUs form self.hrusPos = QPoint(0, 100) ## Position of parameters form self.parametersPos = QPoint(50, 100) ## Position of landscape form self.landscapePos = QPoint(50, 80) ## Position of select subbasins form self.selectSubsPos = QPoint(50, 100) ## Position of select reservoirs form self.selectResPos = QPoint(50, 100) ## Position of about form self.aboutPos = QPoint(50, 100) ## Position of elevation bands form self.elevationBandsPos = QPoint(50, 100) ## Position of split landuses form self.splitPos = QPoint(50, 100) ## Position of select landuses form self.selectLuPos = QPoint(50, 100) ## Position of exempt landuses form self.exemptPos = QPoint(50, 100) ## Position of outlets form self.outletsPos = QPoint(50, 100) ## Position of select outlets file form self.selectOutletFilePos = QPoint(50, 100) ## Position of select outlets form self.selectOutletPos = QPoint(50, 100) ## Position of visualise form self.visualisePos = QPoint(0, 100) ## rasters open that need to be closed if memory exception occurs self.openRasters: Set[Raster] = set() ## options for creating shapefiles self.vectorFileWriterOptions = QgsVectorFileWriter.SaveVectorOptions() self.vectorFileWriterOptions.ActionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile self.vectorFileWriterOptions.driverName = "ESRI Shapefile" self.vectorFileWriterOptions.fileEncoding = "UTF-8" ## will set to choice made when converting from ArcSWAT, if that was how the project file was created # 0: Full # 1: Existing # 2: No GIS # NB These values are defined in convertFromArc.py self.fromArcChoice = -1
def test_signalConnection(self): # remove all layers QgsProject.instance().removeAllMapLayers() # set dependencies and add back layers self.pointsLayer = QgsVectorLayer( "dbname='%s' table=\"node\" (geom) sql=" % self.fn, "points", "spatialite") assert (self.pointsLayer.isValid()) self.linesLayer = QgsVectorLayer( "dbname='%s' table=\"section\" (geom) sql=" % self.fn, "lines", "spatialite") assert (self.linesLayer.isValid()) self.pointsLayer2 = QgsVectorLayer( "dbname='%s' table=\"node2\" (geom) sql=" % self.fn, "_points2", "spatialite") assert (self.pointsLayer2.isValid()) self.pointsLayer.setDependencies( [QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies( [QgsMapLayerDependency(self.pointsLayer.id())]) # this should update connections between layers QgsProject.instance().addMapLayers([self.pointsLayer]) QgsProject.instance().addMapLayers([self.linesLayer]) QgsProject.instance().addMapLayers([self.pointsLayer2]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setEnabled(True) cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings( self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) cfg.setIndividualLayerSettings( self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(4) geom = QgsGeometry.fromWkt("LINESTRING(0.5 0.2,0.6 0)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is OK m = u.snapToMap(QPoint(75, 100 - 0)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.8, 0.0)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
def canvasReleaseEvent(self, event): if not self.mouse_clicked: return if event.button() == Qt.LeftButton: self.mouse_clicked = False # No pipe snapped: notify user if self.snapped_pipe_id is None: self.iface.messageBar().pushMessage(Parameters.plug_in_name, 'You need to snap the cursor to a pipe to add a valve.', Qgis.Info, 5) # A pipe has been snapped else: request = QgsFeatureRequest().setFilterFid(self.snapped_pipe_id) feats = self.params.pipes_vlay.getFeatures(request) features = [feat for feat in feats] if len(features) == 1: # Check whether the pipe has a start and an end node (start_node, end_node) = NetworkUtils.find_start_end_nodes(self.params, features[0].geometry()) if not start_node or not end_node: self.iface.messageBar().pushMessage(Parameters.plug_in_name, 'The pipe is missing the start or end nodes.', Qgis.Warning, 5) # TODO: softcode return # Find endnode closest to valve position dist_1 = start_node.geometry().distance(QgsGeometry.fromPointXY(self.snapped_vertex)) dist_2 = end_node.geometry().distance(QgsGeometry.fromPointXY(self.snapped_vertex)) # Get the attributes of the closest junction (start_node, end_node) = NetworkUtils.find_start_end_nodes(self.params, features[0].geometry(), False, True, True) if dist_1 < dist_2: closest_junction_ft = start_node else: closest_junction_ft = end_node # Create the valve diameter = features[0].attribute(Pipe.field_name_diameter) # diameter = self.data_dock.txt_valve_diameter.text() minor_loss = self.data_dock.txt_valve_minor_loss.text() selected_type = self.data_dock.cbo_valve_type.itemData(self.data_dock.cbo_valve_type.currentIndex()) if selected_type != Valve.type_gpv: setting = self.data_dock.txt_valve_setting.text() else: valve_curve = self.data_dock.cbo_valve_curve.itemData(self.data_dock.cbo_valve_curve.currentIndex()) if valve_curve is not None: setting = valve_curve.id else: setting = None # Pump status valve_status = self.data_dock.cbo_valve_status.itemData( self.data_dock.cbo_valve_status.currentIndex()) # Valve description valve_desc = self.data_dock.txt_valve_desc.text() # Valve tag valve_tag = self.data_dock.cbo_valve_tag.currentText() try: LinkHandler.create_new_pumpvalve( self.params, self.data_dock, features[0], closest_junction_ft, self.snapped_vertex, self.params.valves_vlay, {Valve.field_name_diameter: diameter, Valve.field_name_minor_loss: minor_loss, Valve.field_name_setting: setting, Valve.field_name_type: selected_type, Valve.field_name_status: valve_status, Valve.field_name_description: valve_desc, Valve.field_name_tag: valve_tag}) except PumpValveCreationException as ex: self.iface.messageBar().pushMessage( Parameters.plug_in_name, ', '.join(ex.args), Qgis.Info, 5) elif event.button() == Qt.RightButton: self.mouse_clicked = False # Check whether it clicked on a valve vertex if len(NetworkUtils.find_adjacent_links(self.params, self.snapped_vertex)['valves']) == 0 or self.snapped_pipe_id is None: return menu = QMenu() diameter_action = menu.addAction('Change diameter...') # TODO: softcode invert_action = menu.addAction('Flip orientation') # TODO: softcode action = menu.exec_(self.iface.mapCanvas().mapToGlobal(QPoint(event.pos().x(), event.pos().y()))) request = QgsFeatureRequest().setFilterFid(self.snapped_pipe_id) feats = self.params.pipes_vlay.getFeatures(request) features = [feat for feat in feats] if len(features) == 1: adj_links = NetworkUtils.find_links_adjacent_to_link( self.params, self.params.pipes_vlay, features[0], True, True, False) for valve_ft in adj_links['valves']: if action == diameter_action: old_diam = valve_ft.attribute(Valve.field_name_diameter) self.diameter_dialog = DiameterDialog(self.iface.mainWindow(), self.params, old_diam) self.diameter_dialog.exec_() # Exec creates modal dialog new_diameter = self.diameter_dialog.get_diameter() if new_diameter is None: return # Update valve diameter vector_utils.update_attribute(self.params.valves_vlay, valve_ft, Valve.field_name_diameter, new_diameter) # Modify pipes diameters adj_pipes_fts = NetworkUtils.find_links_adjacent_to_link( self.params, self.params.valves_vlay, valve_ft, False, True, True) if adj_pipes_fts: for adj_pipe_ft in adj_pipes_fts['pipes']: vector_utils.update_attribute(self.params.pipes_vlay, adj_pipe_ft, Pipe.field_name_diameter, new_diameter) self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Diameters of pipes adjacent to valve updated.', Qgis.Info, 5) # TODO: softcode elif action == invert_action: request = QgsFeatureRequest().setFilterFid(self.snapped_pipe_id) feats = self.params.pipes_vlay.getFeatures(request) features = [feat for feat in feats] if len(features) == 1: adj_links = NetworkUtils.find_links_adjacent_to_link( self.params, self.params.pipes_vlay, features[0], True, True, False) for adj_link in adj_links['valves']: adj_link_pts = adj_link.geometry().asPolyline() for adj_link_pt in adj_link_pts: if NetworkUtils.points_overlap(adj_link_pt, self.snapped_vertex, self.params.tolerance): geom = adj_link.geometry() if geom.wkbType() == QgsWkbTypes.MultiLineString: nodes = geom.asMultiPolyline() for line in nodes: line.reverse() newgeom = QgsGeometry.fromMultiPolylineXY(nodes) self.params.valves_vlay.changeGeometry(adj_link.id(), newgeom) if geom.wkbType() == QgsWkbTypes.LineString: nodes = geom.asPolyline() nodes.reverse() newgeom = QgsGeometry.fromPolylineXY(nodes) self.params.valves_vlay.changeGeometry(adj_link.id(), newgeom) self.iface.mapCanvas().refresh() break self.iface.mapCanvas().refresh()
def testInteraction(self): # pylint: disable=too-many-statements """ Test tool interaction """ canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") f = QgsFeature() f.setAttributes(['a']) f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 32, 15, 45))) f2 = QgsFeature() f2.setAttributes(['b']) f2.setGeometry(QgsGeometry.fromRect(QgsRectangle(15, 25, 18, 45))) success, (f, f2) = layer.dataProvider().addFeatures([f, f2]) self.assertTrue(success) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() handler = RedistrictHandler(layer, 'fldtxt') factory = DecoratorFactory() registry = DistrictRegistry(districts=['a', 'b']) tool = InteractiveRedistrictingTool(canvas, handler, district_registry=registry, decorator_factory=factory) # mouse over a feature's interior point = canvas.mapSettings().mapToPixel().transform(20, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertFalse(tool.is_active) self.assertFalse(tool.snap_indicator.match().isValid()) # mouse over a single feature's boundary (not valid district boundary) point = canvas.mapSettings().mapToPixel().transform(5, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertFalse(tool.is_active) self.assertFalse(tool.snap_indicator.match().isValid()) # mouse over a two feature's boundary (valid district boundary) point = canvas.mapSettings().mapToPixel().transform(15, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertFalse(tool.is_active) self.assertTrue(tool.snap_indicator.match().isValid()) # avoid segfault tool.snap_indicator.setMatch(QgsPointLocator.Match()) # clicks to ignore point = canvas.mapSettings().mapToPixel().transform(10, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.MidButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.RightButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) # click over bad area point = canvas.mapSettings().mapToPixel().transform(10, 30) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.LeftButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) # click over feature area layer.startEditing() point = canvas.mapSettings().mapToPixel().transform(10, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.LeftButton) tool.canvasPressEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.click_point.x(), 10) self.assertEqual(tool.click_point.y(), 33) self.assertEqual(tool.districts, {'a'}) self.assertFalse(tool.modified) # now move over current feature - should do nothing! point = canvas.mapSettings().mapToPixel().transform(10, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertFalse(tool.modified) # move over other feature self.assertEqual(layer.getFeature(f2.id())[0], 'b') point = canvas.mapSettings().mapToPixel().transform(16, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.modified, {f2.id()}) self.assertEqual(tool.current_district, 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'a') # move over nothing point = canvas.mapSettings().mapToPixel().transform(26, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.modified, {f2.id()}) # left click - commit changes event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.LeftButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) layer.rollBack() layer.startEditing() # add a decorator tool.decorator_factory = TestDecoratorFactory() # now try with clicks over boundary point = canvas.mapSettings().mapToPixel().transform(15, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.LeftButton) tool.canvasPressEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.click_point.x(), 15) self.assertEqual(tool.click_point.y(), 33) self.assertEqual(tool.districts, {'a', 'b'}) self.assertFalse(tool.modified) # move left self.assertEqual(layer.getFeature(f.id())[0], 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'b') point = canvas.mapSettings().mapToPixel().transform(10, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.modified, {f.id()}) self.assertEqual(tool.current_district, 'b') self.assertEqual(layer.getFeature(f.id())[0], 'b') self.assertEqual(layer.getFeature(f2.id())[0], 'b') # move over nothing point = canvas.mapSettings().mapToPixel().transform(26, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.modified, {f.id()}) # right click - discard changes event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.RightButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) self.assertEqual(layer.getFeature(f.id())[0], 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'b') # try again, move right point = canvas.mapSettings().mapToPixel().transform(15, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.LeftButton) tool.canvasPressEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.click_point.x(), 15) self.assertEqual(tool.click_point.y(), 33) self.assertEqual(tool.districts, {'a', 'b'}) self.assertFalse(tool.modified) # move right self.assertEqual(layer.getFeature(f.id())[0], 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'b') point = canvas.mapSettings().mapToPixel().transform(17, 33) event = QgsMapMouseEvent(canvas, QEvent.MouseMove, QPoint(point.x(), point.y())) tool.canvasMoveEvent(event) self.assertTrue(tool.is_active) self.assertEqual(tool.modified, {f2.id()}) self.assertEqual(tool.current_district, 'a') self.assertEqual(layer.getFeature(f.id())[0], 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'a') event = QgsMapMouseEvent(canvas, QEvent.MouseButtonPress, QPoint(point.x(), point.y()), Qt.RightButton) tool.canvasPressEvent(event) self.assertFalse(tool.is_active) self.assertEqual(layer.getFeature(f.id())[0], 'a') self.assertEqual(layer.getFeature(f2.id())[0], 'b') layer.rollBack()
def zoomActual(self): point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) self.view.resetTransform() self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) self.view.centerOn(point)
def popup(self, pos, action = None): newPos = QPoint(pos.x() + self.offset, pos.y() + self.offset) QMenu.popup(self, newPos, action)
def canvasPressEvent(self, e): self.drugging = True point = QPoint(e.pos().x(), e.pos().y()) self.callback(point) return None
def search_data(self, **kwargs): """ Get plot geometries associated with parcels, both collected and official, zoom to them, activate map swipe tool and fill comparison table. :param kwargs: key-value (field name-field value) to search in parcel tables, both collected and official 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 Official 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 already_zoomed_in = False self.clear_result_table() search_field = self.cbo_parcel_fields.currentData() search_value = list(kwargs.values())[0] # Get OFFICIAL parcel's t_id and get related plot(s) expression = QgsExpression("{}='{}'".format(search_field, search_value)) request = QgsFeatureRequest(expression) field_idx = self.utils._official_layers[PARCEL_TABLE][LAYER].fields( ).indexFromName(ID_FIELD) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([field_idx ]) # Note: this adds a new flag official_parcels = [ feature for feature in self.utils._official_layers[PARCEL_TABLE] [LAYER].getFeatures(request) ] if len(official_parcels) > 1: # We do not expect duplicates in the official source! pass # We'll choose the first one anyways elif len(official_parcels) == 0: print("No parcel found!", search_field, search_value) official_plot_t_ids = [] if official_parcels: official_plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels( self.utils._official_db, [official_parcels[0][ID_FIELD]], field_name=ID_FIELD, plot_layer=self.utils._official_layers[PLOT_TABLE][LAYER], uebaunit_table=self.utils._official_layers[UEBAUNIT_TABLE] [LAYER]) if official_plot_t_ids: self._current_official_substring = "\"{}\" IN ('{}')".format( ID_FIELD, "','".join([str(t_id) for t_id in official_plot_t_ids])) self.parent.request_zoom_to_features( self.utils._official_layers[PLOT_TABLE][LAYER], list(), official_plot_t_ids) already_zoomed_in = True # Now get COLLECTED parcel's t_id and get related plot(s) 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 = { ID_FIELD: 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: search_value} request = QgsFeatureRequest(expression) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes( [ID_FIELD], self.utils._layers[PARCEL_TABLE] [LAYER].fields()) # Note this adds a new flag collected_parcels = self.utils._layers[PARCEL_TABLE][ LAYER].getFeatures(request) collected_parcels_t_ids = [ feature[ID_FIELD] 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 = { ID_FIELD: collected_parcel_t_id } else: return # User just cancelled the dialog, there is nothing more to do search_criterion_official = {search_field: search_value} self.fill_table(search_criterion_official, search_criterion_collected) 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], field_name=ID_FIELD, plot_layer=self.utils._layers[PLOT_TABLE][LAYER], uebaunit_table=self.utils._layers[UEBAUNIT_TABLE][LAYER]) if plot_t_ids: self._current_substring = "{} IN ('{}')".format( ID_FIELD, "','".join([str(t_id) for t_id in plot_t_ids])) if not already_zoomed_in: self.parent.request_zoom_to_features( self.utils._layers[PLOT_TABLE][LAYER], list(), plot_t_ids) # Send a custom mouse move on the map to make the map swipe tool's limit appear on the canvas # Activate Swipe Tool self.utils.qgis_utils.activate_layer_requested.emit( self.utils._official_layers[PLOT_TABLE][LAYER]) if official_plot_t_ids: # Otherwise the map swipe tool doesn't add any value :) self.parent.activate_map_swipe_tool() plots = self.utils.ladm_data.get_features_from_t_ids( self.utils._layers[PLOT_TABLE][LAYER], plot_t_ids, True) plots_extent = QgsRectangle() for plot in plots: plots_extent.combineExtentWith( plot.geometry().boundingBox()) 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 canvasPressEvent(self, event): self.pressed.emit(QPoint(event.pos().x(), event.pos().y()))
def dock_pos(cls): settings = cls.get_settings() return settings.value('/ui/dockWidgetPos', QPoint(500, 500), type=QPoint)
def updateVideoRect(self): ''' Update video rectangle ''' size = self.surfaceFormat().sizeHint() size.scale(self.widget.size().boundedTo(size), Qt.KeepAspectRatio) self._targetRect = QRect(QPoint(0, 0), size) self._targetRect.moveCenter(self.widget.rect().center())
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][LAYER].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][LAYER].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][LAYER]) 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][LAYER], 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.OP_PARCEL_T][LAYER].fields()) # Note this adds a new flag collected_parcels = self.utils._layers[self.utils._db.names.OP_PARCEL_T][LAYER].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.OP_PLOT_T][LAYER], uebaunit_table=self.utils._layers[self.utils._db.names.COL_UE_BAUNIT_T][LAYER]) 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.OP_PLOT_T][LAYER], 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.qgis_utils.activate_layer_requested.emit(self.utils._supplies_layers[self.utils._supplies_db.names.GC_PLOT_T][LAYER]) 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 __init__(self, parent=None): ''' Constructor ''' super().__init__(parent) self.surface = VideoWidgetSurface(self) self.setAttribute(Qt.WA_OpaquePaintEvent) self.Tracking_Video_RubberBand = QRubberBand( QRubberBand.Rectangle, self) self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self) color_blue = QColor(Qt.blue) color_black = QColor(Qt.black) color_amber = QColor(252, 215, 108) pal_blue = QPalette() pal_blue.setBrush(QPalette.Highlight, QBrush(color_blue)) self.Tracking_Video_RubberBand.setPalette(pal_blue) pal_black = QPalette() pal_black.setBrush(QPalette.Highlight, QBrush(color_black)) self.Censure_RubberBand.setPalette(pal_black) self._interaction = InteractionState() self._filterSatate = FilterState() self._isinit = False self._MGRS = False self.drawCesure = [] self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawMeasureDistance, self.drawMeasureArea, self.drawPolygon = [], [], [], [], [], [] # Draw Polygon Canvas Rubberband self.poly_Canvas_RubberBand = QgsRubberBand( iface.mapCanvas(), True) # Polygon type # set rubber band style self.poly_Canvas_RubberBand.setColor(color_amber) self.poly_Canvas_RubberBand.setWidth(3) # Tracking Canvas Rubberband self.Track_Canvas_RubberBand = QgsRubberBand( iface.mapCanvas(), QgsWkbTypes.LineGeometry) # set rubber band style self.Track_Canvas_RubberBand.setColor(color_blue) self.Track_Canvas_RubberBand.setWidth(5) # Cursor Canvas Rubberband self.Cursor_Canvas_RubberBand = QgsRubberBand( iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.Cursor_Canvas_RubberBand.setWidth(4) self.Cursor_Canvas_RubberBand.setColor(QColor(255, 100, 100, 250)) self.Cursor_Canvas_RubberBand.setIcon(QgsRubberBand.ICON_FULL_DIAMOND) self.parent = parent.parent() palette = self.palette() palette.setColor(QPalette.Background, Qt.transparent) self.setPalette(palette) self.origin, self.dragPos = QPoint(), QPoint() self.tapTimer = QBasicTimer() self.brush = QBrush(color_black) self.blue_Pen = QPen(color_blue, 3) self.lastMouseX = -1 self.lastMouseY = -1
def zoomActual(self): point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) self.view.resetTransform() self.view.centerOn(point)
def RestoreDrawer(self): ''' Remove and restore all Drawer Options ''' self._interaction.clear() # Magnifier Glass self.dragPos = QPoint() self.tapTimer.stop()
def test_resetSnappingIndex(self): self.pointsLayer.setDependencies([]) self.linesLayer.setDependencies([]) self.pointsLayer2.setDependencies([]) ms = QgsMapSettings() ms.setOutputSize(QSize(100, 100)) ms.setExtent(QgsRectangle(0, 0, 1, 1)) self.assertTrue(ms.hasValidSettings()) u = QgsSnappingUtils() u.setMapSettings(ms) cfg = u.config() cfg.setEnabled(True) cfg.setMode(QgsSnappingConfig.AdvancedConfiguration) cfg.setIndividualLayerSettings(self.pointsLayer, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) m = u.snapToMap(QPoint(95, 100)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(1, 0)) f = QgsFeature(self.linesLayer.fields()) f.setId(1) geom = QgsGeometry.fromWkt("LINESTRING(0 0,1 1)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() l1 = len([f for f in self.pointsLayer.getFeatures()]) self.assertEqual(l1, 4) m = u.snapToMap(QPoint(95, 0)) # snapping not updated self.pointsLayer.setDependencies([]) self.assertEqual(m.isValid(), False) # set layer dependencies self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(2) geom = QgsGeometry.fromWkt("LINESTRING(0 0,0.5 0.5)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the snapped point is OK m = u.snapToMap(QPoint(45, 50)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.5, 0.5)) self.pointsLayer.setDependencies([]) # test chained layer dependencies A -> B -> C cfg.setIndividualLayerSettings(self.pointsLayer2, QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels)) u.setConfig(cfg) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(3) geom = QgsGeometry.fromWkt("LINESTRING(0 0.2,0.5 0.8)") f.setGeometry(geom) self.linesLayer.startEditing() self.linesLayer.addFeatures([f]) self.linesLayer.commitChanges() # check the second snapped point is OK m = u.snapToMap(QPoint(75, 100 - 80)) self.assertTrue(m.isValid()) self.assertTrue(m.hasVertex()) self.assertEqual(m.point(), QgsPointXY(0.7, 0.8)) self.pointsLayer.setDependencies([]) self.pointsLayer2.setDependencies([])
def test_tool(self): """ Test some plot tool logic """ canvas = QgsElevationProfileCanvas() canvas.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setProject(QgsProject.instance()) canvas.show() self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) ls = QgsLineString() ls.fromWkt('LineString(0 2, 10 2, 10 4)') canvas.setProfileCurve(ls) canvas.setVisiblePlotRange(0, ls.length(), 0, 100) self.assertFalse(canvas.tool()) tool = TestTool(canvas) self.assertFalse(tool.isActive()) canvas.setTool(tool) self.assertEqual(canvas.tool(), tool) key_press_event = QKeyEvent(QEvent.KeyPress, 54, Qt.ShiftModifier) canvas.keyPressEvent(key_press_event) self.assertEqual(tool.events[-1].type(), QEvent.KeyPress) key_release_event = QKeyEvent(QEvent.KeyRelease, 54, Qt.ShiftModifier) canvas.keyReleaseEvent(key_release_event) self.assertEqual(tool.events[-1].type(), QEvent.KeyRelease) mouse_dbl_click_event = QMouseEvent(QEvent.MouseButtonDblClick, QPointF(300, 200), Qt.LeftButton, Qt.MouseButtons(), Qt.ShiftModifier) canvas.mouseDoubleClickEvent(mouse_dbl_click_event) self.assertEqual(tool.events[-1].type(), QEvent.MouseButtonDblClick) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) self.assertAlmostEqual(tool.events[-1].mapPoint().x(), 5.92, 1) self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, 0) mouse_move_event = QMouseEvent(QEvent.MouseMove, QPointF(300, 200), Qt.LeftButton, Qt.MouseButtons(), Qt.ShiftModifier) canvas.mouseMoveEvent(mouse_move_event) self.assertEqual(tool.events[-1].type(), QEvent.MouseMove) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) self.assertAlmostEqual(tool.events[-1].mapPoint().x(), 5.92, 1) self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, 0) mouse_press_event = QMouseEvent(QEvent.MouseButtonPress, QPointF(300, 200), Qt.LeftButton, Qt.MouseButtons(), Qt.ShiftModifier) canvas.mousePressEvent(mouse_press_event) self.assertEqual(tool.events[-1].type(), QEvent.MouseButtonPress) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) self.assertAlmostEqual(tool.events[-1].mapPoint().x(), 5.927, 1) self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, 0) mouse_release_event = QMouseEvent(QEvent.MouseButtonRelease, QPointF(300, 200), Qt.LeftButton, Qt.MouseButtons(), Qt.ShiftModifier) canvas.mouseReleaseEvent(mouse_release_event) self.assertEqual(tool.events[-1].type(), QEvent.MouseButtonRelease) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) self.assertAlmostEqual(tool.events[-1].mapPoint().x(), 5.927, 1) self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, 0) wheel_event = QWheelEvent(QPointF(300, 200), QPointF(300, 200), QPoint(1, 2), QPoint(3, 4), Qt.NoButton, Qt.NoModifier, Qt.ScrollBegin, False) canvas.wheelEvent(wheel_event) self.assertEqual(tool.events[-1].type(), QEvent.Wheel)