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 startCapturing(self): self.clearScene() self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.rubberBand.setWidth(2) self.rubberBand.setFillColor(QColor(220, 0, 0, 120)) self.rubberBand.setBorderColor(QColor(220, 0, 0)) self.rubberBand.setLineStyle(Qt.DotLine) self.rubberBand.show() self.tempRubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.tempRubberBand.setWidth(2) self.tempRubberBand.setFillColor(QColor(0, 0, 0, 0)) self.tempRubberBand.setBorderColor(QColor(220, 0, 0)) self.tempRubberBand.setLineStyle(Qt.DotLine) self.tempRubberBand.show() self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setIconType(1) self.vertexMarker.setColor(QColor(220, 0, 0)) self.vertexMarker.setIconSize(16) self.vertexMarker.setPenWidth(3) self.vertexMarker.show() self.capturing = True
def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.firstPoint = None self.rubberBandOrigin = QgsRubberBand( self.canvas, QgsWkbTypes.PointGeometry) self.rubberBandOrigin.setColor(Qt.red) self.rubberBandOrigin.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubberBandOrigin.setIconSize(7) self.rubberBandOrigin.setWidth(2) self.rubberBandDisplacement = QgsRubberBand( self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.setColor(Qt.red) self.rubberBandDisplacement.setWidth(1) self.rubberBandExtent = QgsRubberBand( self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(2) self.isLayerVisible = True self.reset()
def __init__(self, canvas, iface): """ Tool Behaviours: (all behaviours start edition, except for rectangle one) 1- Left Click: Clears previous selection, selects feature, sets feature layer as active layer. The selection is done with the following priority: Point, Line then Polygon. Selection is only done in visible layer. 2- Control + Left Click: Adds to selection selected feature. This selection follows the priority in item 1. 3- Right Click: Opens feature form 4- Control + Right Click: clears selection and set feature's layer as activeLayer. activeLayer's definition follows priority of item 1; 5- Shift + drag and drop: draws a rectangle, then features that intersect this rectangl'e are added to selection """ self.iface = iface self.canvas = canvas self.toolAction = None QgsMapTool.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.hoverRubberBand = QgsRubberBand(self.canvas, QGis.Polygon) mFillColor = QColor( 254, 178, 76, 63 ) self.rubberBand.setColor(mFillColor) self.hoverRubberBand.setColor(QColor( 255, 0, 0, 90 )) self.rubberBand.setWidth(1) self.reset() self.blackList = self.getBlackList() self.cursorChanged = False self.cursorChangingHotkey = QtCore.Qt.Key_Alt self.menuHovered = False # indicates hovering actions over context menu
class QgepMapTool( QgsMapTool ): ''' Base class for all the map tools ''' highLightedPoints = [] logger = logging.getLogger( __name__ ) def __init__( self, iface, button ): QgsMapTool.__init__( self, iface.mapCanvas() ) self.canvas = iface.mapCanvas() self.cursor = QCursor( Qt.CrossCursor ) self.button = button self.msgBar = iface.messageBar() settings = QSettings() currentProfileColor = settings.value( "/QGEP/CurrentProfileColor", u'#FF9500' ) self.rubberBand = QgsRubberBand( self.canvas ) self.rubberBand.setColor( QColor( currentProfileColor ) ) self.rubberBand.setWidth( 3 ) # Gets called when the tool is activated def activate( self ): QgsMapTool.activate( self ) self.canvas.setCursor( self.cursor ) self.button.setChecked( True ) # Gets called whenever the tool is deactivated directly or indirectly def deactivate( self ): QgsMapTool.deactivate( self ) self.button.setChecked( False ) def isZoomTool( self ): return False def setCursor( self, cursor ): self.cursor = QCursor( cursor ) #=========================================================================== # Events #=========================================================================== def canvasMoveEvent( self, event ): try: self.mouseMoved( event ) except AttributeError: pass def canvasReleaseEvent( self, event ): if event.button() == Qt.RightButton: self.rightClicked ( event ) else: self.leftClicked( event ) def canvasDoubleClickEvent( self, event ): try: self.doubleClicked( event ) except AttributeError: pass
def initGui(self): #Models self.tblChanges.setModel( ChangeModel() ) proxyChanges = HistoryProxyModel() proxyChanges.setSourceModel( HistoryModel() ) self.tblHistory.setModel( proxyChanges ) #Signals self.plugin.tvIdentificationResult.model().sourceModel().on_history.connect( self.historyChanged ) self.tblHistory.selectionModel().currentChanged.connect( self.currentHistoryChanged ) #Widgets settings = QSettings() self.mapCanvas = QgsMapCanvas(self.vSplitter) self.mapCanvas.setDestinationCrs( QgsCoordinateReferenceSystem('EPSG:4326') ) zoomFactor = settings.value( "/qgis/zoom_factor", 2.0, type=float ) action = settings.value( "/qgis/wheel_action", 0, type=int) self.mapCanvas.setWheelFactor( zoomFactor ) self.mapCanvas.enableAntiAliasing( settings.value( "/qgis/enable_anti_aliasing", False, type=bool )) #self.mapCanvas.useImageToRender( settings.value( "/qgis/use_qimage_to_render", False, type=bool )) self.toolPan = QgsMapToolPan( self.mapCanvas ) self.mapCanvas.setMapTool( self.toolPan ) #Canvas items self.new_geometry = QgsRubberBand(self.mapCanvas) self.new_geometry.setWidth(2) self.new_geometry.setIcon( QgsRubberBand.ICON_CIRCLE ) g = QColor(0, 128, 0, 100) self.new_geometry.setColor( g ) self.old_geometry = QgsRubberBand(self.mapCanvas) self.old_geometry.setWidth(2) self.old_geometry.setIcon( QgsRubberBand.ICON_CIRCLE ) r = QColor(255, 0, 0, 100) self.old_geometry.setColor( r )
def __init__(self, iface, couleur): canvas = iface.mapCanvas() QgsMapTool.__init__(self, canvas) self.canvas = canvas self.iface = iface self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setColor(couleur) self.rbSelect = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) return None
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: QgsInterface """ # Save reference to the QGIS interface super(EarthMineQGIS, self).__init__() self.movingfeature = None self.iface = iface self.viewer = None self.canvas = self.iface.mapCanvas() self.settings = QSettings() # 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", "EarthMineQGIS_{}.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) self.pointtool = QgsMapToolEmitPoint(self.canvas) self.pointtool.canvasClicked.connect(self.set_viewer_location) self.settingsdialog = SettingsDialog(self.iface.mainWindow()) self.actions = [] self.menu = self.tr(u"&Earthmine") self.toolbar = self.iface.addToolBar(u"EarthMineQGIS") self.toolbar.setObjectName(u"EarthMineQGIS") self.legend = self.iface.legendInterface() emcolor = QColor(1, 150, 51) self.tempband = QgsRubberBand(self.canvas, QGis.Line) self.tempband.setWidth(5) self.tempband.setColor(emcolor) self.tempbandpoints = QgsRubberBand(self.canvas, QGis.Point) self.tempbandpoints.setWidth(7) self.tempbandpoints.setColor(emcolor) self.movingband = QgsRubberBand(self.canvas, QGis.Point) self.movingband.setWidth(5) self.movingband.setColor(emcolor) self.layersignals = [] self.marker = None
def __init__(self, layer, feature, mapCanvas, parent=None): QDialog.__init__(self, parent) self.setupUi(self) self.settings = MySettings() SettingDialog.__init__(self, self.settings, False, True) self.mapCanvas = mapCanvas self.setAttribute(Qt.WA_DeleteOnClose) self.feature = feature self.initialGeometry = QgsGeometry(feature.geometry()) self.layer = layer # close if no geom, hide "sketch current point" if not needed geomType = layer.geometryType() if not geomType in (QGis.Point, QGis.Line, QGis.Polygon): self.close() return if geomType == QGis.Point: self.pointRubberGroup.hide() # editors management self.editorLayout = QGridLayout(self.editorContainer) self.editor = GeomEditor(layer, feature.geometry()) self.displayCombo.setCurrentIndex(0) self.displayCombo.currentIndexChanged.connect(self.setEditor) self.setEditor() # rubber bands self.featureRubber = QgsRubberBand(mapCanvas) self.currentPointRubber = QgsRubberBand(mapCanvas) self.settings.setting("featureRubberColor").valueChanged.connect(self.updateFeatureRubber) self.settings.setting("featureRubberSize").valueChanged.connect(self.updateFeatureRubber) self.settings.setting("currentPointRubberSize").valueChanged.connect(self.updateCurrentPointRubber) self.settings.setting("currentPointRubberColor").valueChanged.connect(self.updateCurrentPointRubber) self.settings.setting("currentPointRubberIcon").valueChanged.connect(self.updateCurrentPointRubber) self.updateFeatureRubber() self.updateCurrentPointRubber() self.geometryChanged() # GUI signals connection self.applyButton.clicked.connect(self.applyGeometry) self.resetButton.clicked.connect(self.resetGeometry) self.sketchGeometry.clicked.connect(self.geometryChanged) self.displayPointRubber.clicked.connect(self.currentPointRubber.reset) self.layerEditable() layer.editingStopped.connect(self.layerEditable) layer.editingStarted.connect(self.layerEditable) # set texts in UI self.layerLabel.setText(layer.name()) try: featureTitle = unicode(feature[layer.displayField()]) except KeyError: featureTitle = "" if featureTitle == "": featureTitle = str(feature.id()) self.featureEdit.setText(featureTitle)
def zoomAndShowWKT(self, wtk): geom = QgsGeometry.fromWkt(wtk) canvas = self.iface.mapCanvas() self.clear() r = QgsRubberBand(canvas, geom.type() == 3 ) r.setToGeometry(geom, None) r.setColor(QColor(0, 0, 255)) r.setFillColor(QColor(0, 0, 255, 50)) r.setWidth(3) pt = geom.pointOnSurface().asPoint() m = QgsVertexMarker(canvas) m.setCenter( pt ) m.setColor(QColor(0, 0, 255)) m.setIconSize(5) m.setIconType(QgsVertexMarker.ICON_BOX) m.setPenWidth(3) if geom.type() == 3 or geom.type() == 2: rec = geom.boundingBox() canvas.setExtent(rec) else: self.moveMapTo( pt[0], pt[1], 0) self.graphics.append(r) self.graphics.append(m) self._refresh_layers()
def _draw_rubberband(self, geometry, colour, width): """Draw a rubber band on the canvas. .. versionadded: 2.2.0 :param geometry: Extent that the rubber band should be drawn for. :type geometry: QgsGeometry :param colour: Colour for the rubber band. :type colour: QColor :param width: The width for the rubber band pen stroke. :type width: int :returns: Rubber band that should be set to the extent. :rtype: QgsRubberBand """ # noinspection PyArgumentList rubber_band = QgsRubberBand( self._map_canvas, geometryType=QGis.Polygon) rubber_band.setBrushStyle(Qt.NoBrush) rubber_band.setColor(colour) rubber_band.setWidth(width) rubber_band.setToGeometry(geometry, None) return rubber_band
def loadLines(self, lines, points, markers, suffix): no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0] if no: no = int(no) for i in range(no): a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0] a = a.split('~~') b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0] b = b.split('~~') points.clear() for j in range(len(a)): x = float(a[j]) y = float(b[j]) point = QgsPoint(x, y) points.append(point) if i + 1 == no: marker = QgsVertexMarker(self.tuView.canvas) if suffix == 'cs': marker.setColor(Qt.red) marker.setIconSize(10) marker.setIconType(QgsVertexMarker.ICON_BOX) else: # 'q' marker.setColor(Qt.blue) marker.setIconSize(12) marker.setIconType(QgsVertexMarker.ICON_DOUBLE_TRIANGLE) marker.setCenter(QgsPointXY(point)) markers.append(marker) line = QgsRubberBand(self.tuView.canvas, False) line.setWidth(2) if suffix == 'cs': line.setColor(QColor(Qt.red)) else: # 'q' line.setColor(QColor(Qt.blue)) line.setToGeometry(QgsGeometry.fromPolyline(points), None) lines.append(line)
def getSnapRubberBand(self): rubberBand = QgsRubberBand(self.canvas, geometryType = QGis.Point) rubberBand.setFillColor(QColor(255, 0, 0, 40)) rubberBand.setBorderColor(QColor(255, 0, 0, 200)) rubberBand.setWidth(2) rubberBand.setIcon(QgsRubberBand.ICON_X) return rubberBand
def __init__(self, iface, layer): QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.iface = iface self.canvas = iface.mapCanvas() self.layer = layer self.rubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType()) self.rubberband.setColor(QColor("#ee5555")) self.rubberband.setWidth(1) self.tempRubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType()) self.tempRubberband.setColor(QColor("#ee5555")) self.tempRubberband.setWidth(1) self.tempRubberband.setLineStyle(Qt.DotLine)
def __init__(self, iface, layer): QgsMapTool.__init__(self, iface.mapCanvas() ) self.iface = iface self.canvas = iface.mapCanvas() self.layer = layer self.rubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() ) self.rubberband.setColor( QColor( "#ee5555" ) ) self.rubberband.setWidth( 2 ) self.tempRubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() ) self.tempRubberband.setColor( QColor( "#ee5555" ) ) self.tempRubberband.setWidth( 2 ) self.tempRubberband.setLineStyle(Qt.DotLine)
def addGraphic(self, geom ): canvas = self.iface.mapCanvas() rBand = QgsRubberBand(canvas, True) self.graphics.append( rBand ) rBand.setToGeometry( geom, None ) rBand.setColor(QtGui.QColor(0,0,255, 70)) if QGis.QGIS_VERSION_INT >= 20600: rBand.setBorderColor( QtGui.QColor(0,0,250, 220) ) rBand.setWidth(3)
def __init__(self): self.iface = iface self.srs_wgs84 = QgsCoordinateReferenceSystem(4326) self.transformation = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84) self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.rb.setColor(QColor('magenta')) self.rb.setIconSize(12) self.features_rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.features_rb.setColor(QColor('green')) self.features_rb.setIconSize(12) self.features_rb.setWidth(3)
def __init__(self): self.iface = iface self.srs_wgs84 = QgsCoordinateReferenceSystem(4326) self.transform_decorator = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84) self.rb = QgsRubberBand(self.iface.mapCanvas(), QGisGeometryType.Point) self.rb.setColor(QColor('magenta')) self.rb.setIconSize(12) self.features_rb = QgsRubberBand(self.iface.mapCanvas(), QGisGeometryType.Point) magenta_transp = QColor('#3388ff') magenta_transp.setAlpha(120) self.features_rb.setColor(magenta_transp) self.features_rb.setIconSize(12) self.features_rb.setWidth(2)
def __init__(self, canvas, forms, snapradius = 2): MapTool.__init__(self, canvas, []) self.canvas = canvas self.radius = snapradius self.forms = forms self.band = QgsRubberBand(self.canvas) self.band.setColor(QColor.fromRgb(224,162,16)) self.band.setWidth(3) self.selectband = None self.selectrect = QRect() self.dragging = False self.cursor = QCursor(QPixmap(["16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ "]))
def setExtent(): if not self.extent is None: self.canvas.scene().removeItem( self.extent ) self.extent = QgsRubberBand( self.canvas, QGis.Polygon ) self.extent.setBorderColor( QColor( 255, 0 , 0 ) ) self.extent.setWidth( 2 ) self._extent()
def canvasPressEvent(self, event): self.dragging = False self.selectrect.setRect( 0, 0, 0, 0 ) self.selectband = QgsRubberBand(self.canvas, QGis.Polygon ) self.selectband.setColor(QColor.fromRgb(0,0,255, 65)) self.selectband.setWidth(5)
def initGui(self): self.actions['openInspection'] = QAction( QIcon(":/plugins/wincan2qgep/icons/wincan_logo.png"), self.tr(u"Ouvrir une inspection"), self.iface.mainWindow()) self.actions['openInspection'].triggered.connect(self.openInspection) self.iface.addPluginToMenu(self.name, self.actions['openInspection']) self.iface.addToolBarIcon(self.actions['openInspection']) self.actions['showSettings'] = QAction( QIcon(":/plugins/wincan2qgep/icons/settings.svg"), self.tr(u"&Settings"), self.iface.mainWindow()) self.actions['showSettings'].triggered.connect(self.showSettings) self.iface.addPluginToMenu(self.name, self.actions['showSettings']) self.actions['help'] = QAction( QIcon(":/plugins/wincan2qgep/icons/help.svg"), self.tr("Help"), self.iface.mainWindow()) self.actions['help'].triggered.connect(lambda: QDesktopServices().openUrl(QUrl("http://3nids.github.io/wincan2qgep"))) self.iface.addPluginToMenu(self.name, self.actions['help']) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush)
def __init__(self, canvas, drawLineButton, showProfileButton): #buttonShowProf QgsMapTool.__init__(self, canvas) self.canvas = canvas self.cursor = QCursor(Qt.CrossCursor) # Red line self.rubberband = QgsRubberBand(self.canvas) self.rubberband.setWidth(3) self.rubberband.setColor(QColor(231, 28, 35)) # Buttons from main dialog self.drawLineButton = drawLineButton self.buttonShowProf = showProfileButton # Coordinates of drawn line points self.pointsToDraw = [] # Temporary save double clicks self.dblclktemp = None # Drawn line geometry self.drawnLine = None # Point markers on each end of the line self.markers = [] # Backup the last active Tool before the pofile tool became active self.savedTool = self.canvas.mapTool()
def __init__(self, canvas, layerfrom, layerto, mapping, validation_method): """ mapping - A dict of field - field mapping with values to copy to the new layer """ QgsMapTool.__init__(self, canvas) self.layerfrom = layerfrom self.layerto = layerto self.fields = mapping self.validation_method = validation_method self.band = QgsRubberBand(canvas, QGis.Polygon ) self.band.setColor(QColor.fromRgb(255,0,0, 65)) self.band.setWidth(5) self.cursor = QCursor(QPixmap(["16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ "]))
def run(self): logger.debug(u"run, processing name {}".format(self.processing_name)) logger.debug(u"self.arg {}".format(self.arg)) output_filename = "" if "NDVI" in self.processing_name: output_filename = terre_image_processing.ndvi(self.layer, self.working_directory) if "NDTI" in self.processing_name: output_filename = terre_image_processing.ndti(self.layer, self.working_directory) if "Indice de brillance" in self.processing_name: output_filename = terre_image_processing.brightness(self.layer, self.working_directory) if "Angle Spectral" in self.processing_name: self.rubberband = QgsRubberBand(self.canvas, QGis.Point) self.rubberband.setWidth(10) self.rubberband.setColor(QColor(Qt.yellow)) if not self.arg: from spectral_angle import SpectralAngle self.angle_tool = SpectralAngle(self.iface, self.working_directory, self.layer, self.mirrormap_tool, self.rubberband) logger.debug("self.angle_tool {}".format(self.angle_tool)) QObject.connect(self.angle_tool, SIGNAL("anglesComputed(PyQt_PyObject)"), self.display) self.angle_tool.get_point_for_angles(self.layer) # spectral_angles(self.layer, self.working_directory, self.iface) else: output_filename = self.arg if "KMEANS" in self.processing_name: if self.arg: output_filename = terre_image_processing.kmeans(self.layer, self.working_directory, self.arg) else: output_filename = terre_image_processing.kmeans(self.layer, self.working_directory) if "Seuillage" in self.processing_name and self.arg: logger.debug("this is thrshold") output_filename = terre_image_processing.threshold(self.layer, self.working_directory, self.arg) if output_filename: terre_image_gdal_system.compute_overviews(output_filename) logger.debug(output_filename) self.display(output_filename)
def canvasMoveEvent(self, e): super(ArkMapToolInteractive, self).canvasMoveEvent(e) if not self._active: return e.ignore() if (self._panningEnabled and e.buttons() & Qt.LeftButton): # Pan map mode if not self._dragging: self._dragging = True self.setCursor(QCursor(Qt.ClosedHandCursor)) self.canvas().panAction(e) e.accept() elif (self._zoomingEnabled and e.buttons() & Qt.RightButton): # Zoom map mode if not self._dragging: self._dragging = True self.setCursor(QCursor(Qt.ClosedHandCursor)) self._zoomRubberBand = QgsRubberBand(self.canvas(), QGis.Polygon) color = QColor(Qt.blue) color.setAlpha(63) self._zoomRubberBand.setColor(color) self._zoomRect = QRect(0, 0, 0, 0) self._zoomRect.setTopLeft(e.pos()) self._zoomRect.setBottomRight(e.pos()) if self._zoomRubberBand is not None: self._zoomRubberBand.setToCanvasRectangle(self._zoomRect) self._zoomRubberBand.show() e.accept() elif self._snappingEnabled: mapPoint, snapped = self._snapCursorPoint(e.pos()) if (snapped): self._createSnappingMarker(mapPoint) else: self._deleteSnappingMarker()
def __init__(self,iface): self.iface = iface QDockWidget.__init__(self) self.setupUi(self) self.iface.addDockWidget(Qt.BottomDockWidgetArea,self) self.canvas = self.iface.mapCanvas() self.rb = QgsRubberBand(self.canvas, QGis.Point) self.rb.setColor(QColor( 255, 0, 0, 150 )) self.searchCacheLimit = 1000 self.wgs84 = QgsCoordinateReferenceSystem() self.wgs84.createFromSrid(4326) self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) self.bSearch.clicked.connect(self.startSearch) self.eOutput.currentItemChanged.connect(self.itemChanged) self.eOutput.clickedOutsideOfItems.connect(self.itemChanged) self.eText.cleared.connect(self.clearEdit) self.canvas.mapRenderer().destinationSrsChanged.connect(self.crsChanged) self.iface.newProjectCreated.connect(self.clearEdit) self.iface.projectRead.connect(self.clearEdit) self.cbCenter.stateChanged.connect(self.autocenter) db = cacheDB() self.autocompleteList = db.getAutocompleteList() db.closeConnection() self.completer = QCompleter(self.autocompleteList) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.eText.setCompleter(self.completer)
def __init__(self, iface): self.iface = iface self.actions = [] self.panels= [] self.navtoolbar = self.iface.mapNavToolToolBar() self.mainwindow = self.iface.mainWindow() self.iface.projectRead.connect(self.projectOpened) self.iface.initializationCompleted.connect(self.setupUI) self.actionGroup = QActionGroup(self.mainwindow) self.actionGroup.setExclusive(True) self.menuGroup = QActionGroup(self.mainwindow) self.menuGroup.setExclusive(True) self.movetool = MoveTool(self.iface.mapCanvas(), []) self.infotool = InfoTool(self.iface.mapCanvas()) self.infotool.infoResults.connect(self.showInfoResults) self.report = PopDownReport(self.iface.messageBar()) self.dialogprovider = DialogProvider(iface.mapCanvas(), iface) self.dialogprovider.accepted.connect(self.clearToolRubberBand) self.dialogprovider.rejected.connect(self.clearToolRubberBand) self.edittool = EditTool(self.iface.mapCanvas(),[]) self.edittool.finished.connect(self.openForm) self.edittool.featuresfound.connect(self.showFeatureSelection) self.infodock = InfoDock(self.iface.mainWindow()) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.infodock) self.infodock.hide() self.band = QgsRubberBand(self.iface.mapCanvas()) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76))
def __init__(self, canvas, layer, column, bindto, radius ): QgsMapToolEmitPoint.__init__(self, canvas) self.layer = layer self.column = column self.bindto = bindto self.canvas = canvas self.bindto = bindto self.searchradius = radius self.canvasClicked.connect(self.findFeature) self.canvas.setMapTool(self) self.band = QgsRubberBand(self.canvas) self.band.setColor(Qt.blue) self.band.setWidth(3) self.rect = QgsRectangle() self.cursor = QCursor(QPixmap(["16 16 3 1", " c None", ". c #32CD32", "+ c #32CD32", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ "]))
def initGui(self): self.actions['showSettings'] = QAction( QIcon(":/plugins/quickfinder/icons/settings.svg"), self.tr(u"&Settings"), self.iface.mainWindow()) self.actions['showSettings'].triggered.connect(self.showSettings) self.iface.addPluginToMenu(self.name, self.actions['showSettings']) self.actions['help'] = QAction( QIcon(":/plugins/quickfinder/icons/help.svg"), self.tr("Help"), self.iface.mainWindow()) self.actions['help'].triggered.connect( lambda: QDesktopServices().openUrl( QUrl("https://github.com/3nids/quickfinder/wiki"))) self.iface.addPluginToMenu(self.name, self.actions['help']) self._initToolbar() self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush)
class VideoWidget(QVideoWidget): 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.gt = None 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) 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) def removeLastLine(self): ''' Remove Last Line Objects ''' if self.drawLines: try: if self.drawLines[-1][3] == "mouseMoveEvent": del self.drawLines[-1] # Remove mouseMoveEvent element except Exception: None for pt in range(len(self.drawLines) - 1, -1, -1): del self.drawLines[pt] try: if self.drawLines[pt - 1][0] is None: break except Exception: None self.UpdateSurface() AddDrawLineOnMap(self.drawLines) return def removeLastSegmentLine(self): ''' Remove Last Segment Line Objects ''' try: if self.drawLines[-1][3] == "mouseMoveEvent": del self.drawLines[-1] # Remove mouseMoveEvent element except Exception: None if self.drawLines: if self.drawLines[-1][0] is None: del self.drawLines[-1] del self.drawLines[-1] self.UpdateSurface() AddDrawLineOnMap(self.drawLines) return def removeAllLines(self): ''' Resets Line List ''' if self.drawLines: self.drawLines = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawLineOnMap() def ResetDrawMeasureDistance(self): ''' Resets Measure Distance List ''' self.drawMeasureDistance = [] def ResetDrawMeasureArea(self): ''' Resets Measure Area List ''' self.drawMeasureArea = [] def removeAllCensure(self): ''' Remove All Censure Objects ''' if self.drawCesure: self.drawCesure = [] self.UpdateSurface() def removeLastCensured(self): ''' Remove Last Censure Objects ''' if self.drawCesure: del self.drawCesure[-1] self.UpdateSurface() def removeLastPoint(self): ''' Remove All Point Drawer Objects ''' if self.drawPtPos: del self.drawPtPos[-1] self.UpdateSurface() RemoveLastDrawPointOnMap() return def removeAllPoint(self): ''' Remove All Point Drawer Objects ''' if self.drawPtPos: self.drawPtPos = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawPointOnMap() return def removeAllPolygon(self): ''' Remove All Polygon Drawer Objects ''' if self.drawPolygon: self.drawPolygon = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawPolygonOnMap() def removeLastPolygon(self): ''' Remove Last Polygon Drawer Objects ''' if self.drawPolygon: try: if self.drawPolygon[-1][3] == "mouseMoveEvent": del self.drawPolygon[-1] # Remove mouseMoveEvent element except Exception: None for pt in range(len(self.drawPolygon) - 1, -1, -1): del self.drawPolygon[pt] try: if self.drawPolygon[pt - 1][0] is None: break except Exception: None self.UpdateSurface() # remove last index layer RemoveLastDrawPolygonOnMap() def keyPressEvent(self, event): ''' Exit fullscreen ''' if event.key() == Qt.Key_Escape and self.isFullScreen(): self.setFullScreen(False) event.accept() elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt: self.setFullScreen(not self.isFullScreen()) event.accept() else: super().keyPressEvent(event) def mouseDoubleClickEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if GetImageHeight() == 0: return if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): return if self.gt is not None and self._interaction.lineDrawer: self.drawLines.append([None, None, None]) return if self.gt is not None and self._interaction.measureDistance: self.drawMeasureDistance.append([None, None, None]) return if self.gt is not None and self._interaction.measureArea: self.drawMeasureArea.append([None, None, None]) return if self.gt is not None and self._interaction.polygonDrawer: ok = AddDrawPolygonOnMap(self.poly_coordinates) # Prevent invalid geometry (Polygon with 2 points) if not ok: return self.drawPolygon.append([None, None, None]) # Empty RubberBand for _ in range(self.poly_Canvas_RubberBand.numberOfVertices()): self.poly_Canvas_RubberBand.removeLastPoint() # Empty List self.poly_coordinates = [] return self.UpdateSurface() self.setFullScreen(not self.isFullScreen()) event.accept() def videoSurface(self): ''' Return video Surface ''' return self.surface def UpdateSurface(self): ''' Update Video Surface only is is stopped or paused ''' if self.parent.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.update() QApplication.processEvents() def sizeHint(self): ''' This property holds the recommended size for the widget ''' return self.surface.surfaceFormat().sizeHint() def currentFrame(self): ''' Return current frame QImage ''' return self.surface.image def SetInvertColor(self, value): ''' Set Invert color filter ''' self._filterSatate.invertColorFilter = value def SetObjectTracking(self, value): ''' Set Object Tracking ''' self._interaction.objectTracking = value def SetMeasureDistance(self, value): ''' Set measure Distance ''' self._interaction.measureDistance = value def SetMeasureArea(self, value): ''' Set measure Area ''' self._interaction.measureArea = value def SetHandDraw(self, value): ''' Set Hand Draw ''' self._interaction.HandDraw = value def SetCensure(self, value): ''' Set Censure Video Parts ''' self._interaction.censure = value def SetMGRS(self, value): ''' Set MGRS Cursor Coordinates ''' self._MGRS = value def SetGray(self, value): ''' Set gray scale ''' self._filterSatate.grayColorFilter = value def SetMirrorH(self, value): ''' Set Horizontal Mirror ''' self._filterSatate.MirroredHFilter = value def SetNDVI(self, value): ''' Set NDVI ''' self._filterSatate.NDVI = value def SetEdgeDetection(self, value): ''' Set Canny Edge filter ''' self._filterSatate.edgeDetectionFilter = value def SetAutoContrastFilter(self, value): ''' Set Automatic Contrast filter ''' self._filterSatate.contrastFilter = value def SetMonoFilter(self, value): ''' Set mono filter ''' self._filterSatate.monoFilter = value def RestoreFilters(self): ''' Remove and restore all video filters ''' self._filterSatate.clear() def RestoreDrawer(self): ''' Remove and restore all Drawer Options ''' self._interaction.clear() # Magnifier Glass self.dragPos = QPoint() self.tapTimer.stop() def RemoveCanvasRubberbands(self): ''' Remove Canvas Rubberbands ''' self.poly_Canvas_RubberBand.reset() self.Track_Canvas_RubberBand.reset() def paintEvent(self, event): ''' Paint Event ''' if not self.surface.isActive(): return # print("paintEvent : " + str(event.region().boundingRect())) # print("Active : " + str(self.surface.isActive())) 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 self.gt = GetGCPGeoTransform() # Draw On Video draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon, self.drawMeasureDistance, self.drawMeasureArea, self.drawCesure, self.painter, self.surface, self.gt) # Draw On Video Object tracking test 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.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 resizeEvent(self, _): """ :type event: QMouseEvent :param event: :return: """ self.surface.updateVideoRect() self.update() # Magnifier Glass if self._interaction.magnifier and not self.dragPos.isNull(): draw.drawMagnifierOnVideo(self, self.dragPos, self.currentFrame(), self.painter) # QApplication.processEvents() def AddMoveEventValue(self, values, Longitude, Latitude, Altitude): """ Remove and Add move value for fluid drawing """ for idx, pt in enumerate(values): if pt[-1] == "mouseMoveEvent": del values[idx] values.append([Longitude, Latitude, Altitude, "mouseMoveEvent"]) self.UpdateSurface() def mouseMoveEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ # Magnifier mouseMoveEvent # Magnifier can move on black screen for show image borders if self._interaction.magnifier: if event.buttons(): 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)) return # Prevent draw on video if not started or finished if self.parent.player.position() == 0: return # Mouser 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 self.gt is not None: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) 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;'>" + \ ("%.3f" % Longitude) + "</span>" txt += "<span style='font-size:10pt; font-weight:bold;'> Lat : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.3f" % 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>") if not event.buttons(): return # 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 timerEvent(self, _): """ Time Event (Magnifier method)""" if not self._interaction.magnifier: self.activateMagnifier() def mousePressEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if GetImageHeight() == 0: return # Prevent draw on video if not started or finished if self.parent.player.position() == 0: return if event.button() == Qt.LeftButton: # Magnifier Glass if self._interaction.magnifier: self.dragPos = event.pos() self.tapTimer.stop() self.tapTimer.start(10, self) if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): return # point drawer if self.gt is not None and self._interaction.pointDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) pointIndex = len(self.drawPtPos) + 1 AddDrawPointOnMap(pointIndex, Longitude, Latitude, Altitude) self.drawPtPos.append([Longitude, Latitude, Altitude]) # polygon drawer if self.gt is not None and self._interaction.polygonDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.poly_Canvas_RubberBand.addPoint(QgsPointXY(Longitude, Latitude)) self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude)) self.drawPolygon.append([Longitude, Latitude, Altitude]) # line drawer if self.gt is not None and self._interaction.lineDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.drawLines.append([Longitude, Latitude, Altitude]) AddDrawLineOnMap(self.drawLines) self.origin = event.pos() # Object Tracking Interaction if self._interaction.objectTracking: self.Tracking_Video_RubberBand.setGeometry( QRect(self.origin, QSize())) self.Tracking_Video_RubberBand.show() # Censure Interaction if self._interaction.censure: self.Censure_RubberBand.setGeometry( QRect(self.origin, QSize())) self.Censure_RubberBand.show() # Measure Distance drawer if self.gt is not None and self._interaction.measureDistance: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.drawMeasureDistance.append([Longitude, Latitude, Altitude]) # Measure Distance drawer if self.gt is not None and self._interaction.measureArea: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.drawMeasureArea.append([Longitude, Latitude, Altitude]) # if not called, the paint event is not triggered. self.UpdateSurface() def activateMagnifier(self): """ Activate Magnifier Glass """ self.tapTimer.stop() self.UpdateSurface() def SetMagnifier(self, value): """ Set Magnifier Glass """ self._interaction.magnifier = value # We avoid that the second time we activate the tool, save the previous position. # Always keep the same behavior of the tool if not value: self.dragPos = QPoint() self.tapTimer.stop() def SetStamp(self, value): """ Set Stamp """ self._interaction.stamp = value def SetPointDrawer(self, value): """ Set Point Drawer """ self._interaction.pointDrawer = value def SetLineDrawer(self, value): """ Set Line Drawer """ self._interaction.lineDrawer = value def SetPolygonDrawer(self, value): """ Set Polygon Drawer """ self._interaction.polygonDrawer = value def mouseReleaseEvent(self, _): """ :type event: QMouseEvent :param event: :return: """ # Prevent draw on video if not started or finished if self.parent.player.position() == 0: return # Censure Draw Interaction if self._interaction.censure: geom = self.Censure_RubberBand.geometry() self.Censure_RubberBand.hide() self.drawCesure.append([geom]) # Object Tracking Interaction if self._interaction.objectTracking: geom = self.Tracking_Video_RubberBand.geometry() offset = self.surface.videoRect() bbox = (geom.x() - offset.x(), geom.y() - offset.y(), geom.width(), geom.height()) img = self.currentFrame() frame = convertQImageToMat(img) # Remo rubberband on canvas and video self.Tracking_Video_RubberBand.hide() self.Track_Canvas_RubberBand.reset() self.tracker = TrackerMOSSE_create() result = resize(frame, (offset.width(), offset.height())) try: ok = self.tracker.init(result, bbox) except Exception: return if ok: self._isinit = True # Get Traker center xc = bbox[0] + (geom.width() / 2) yc = bbox[1] + (geom.height() / 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 def leaveEvent(self, _): self.parent.lb_cursor_coord.setText("") self.setCursor(QCursor(Qt.ArrowCursor))
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionLegend.triggered.connect(self.updatelegend) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.actionSettings.toggled.connect( self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel( "User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.connectButtons() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.selectdataentry) self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.selectioncleared.connect(self.clearselection) RoamEvents.editgeometry.connect(self.addforedit) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.highlightselection) RoamEvents.selectionchanged.connect(self.showInfoResults) GPS.gpspostion.connect(self.updatecanvasfromgps) GPS.firstfix.connect(self.gpsfirstfix) GPS.gpsdisconnected.connect(self.gpsdisconnected) self.lastgpsposition = None self.marker = GPSMarker(self.canvas) self.marker.hide() self.legendpage.showmap.connect(self.showmap) self.editfeaturestack = [] self.currentselection = {} def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def addforedit(self, form, feature): self.editfeaturestack.append((form, feature)) self.loadform(form) actions = self.getcaptureactions() for action in actions: if action.isdefault: action.trigger() break def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def gpsfirstfix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) def updatecanvasfromgps(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.canvas.setExtent(rect) self.canvas.refresh() self.marker.show() self.marker.setCenter(position) self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format( gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gpsdisconnected(self): self.marker.hide() self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return if sys.platform == 'win32': try: programfiles = os.environ['ProgramW6432'] except KeyError: programfiles = os.environ['ProgramFiles'] cmd = r'{path}\Common Files\Microsoft Shared\ink\TabTip.exe'.format( path=programfiles) try: os.startfile(cmd) except WindowsError: roam.config.settings['keyboard'] = False roam.config.save() else: cmd = 'onboard' Popen(cmd) def selectdataentry(self): forms = self.project.forms formpicker = PickActionDialog(msg="Select data entry form") for form in forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(self.showformerror, form)) else: action.triggered.connect(partial(self.loadform, form)) formpicker.addAction(action) formpicker.exec_() def showformerror(self, form): pass def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.actionGPS.updateGPSPort() def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = self.currentselection[layer] # Update any features that have changed. for updatedfeature in updated: oldfeatures = [ f for f in selectedfeatures if f.id() == updatedfeature.id() ] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightselection(self, results): self.clearselection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentryselection.setCurrentIndex(index.row()) self.createCaptureButtons(form) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError( QApplication.translate( 'MainWindowPy', 'Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def getcaptureactions(self): for action in self.projecttoolbar.actions(): if action.property('dataentry'): yield action def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def loadform(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.createCaptureButtons(form) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self, layer, featureid): self.dataentryfinished() self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.currentfeatureband.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature, editmode): """ Open the form that is assigned to the layer """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project, editmode=editmode) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer if layer.geometryType() in [ QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon ]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name( ) == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature, editmode=False) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() GPS.crs = self.canvas.mapRenderer().destinationCrs() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) try: firstform = self.project.forms[0] self.loadform(self.project.forms[0]) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.infoTool.selectionlayers = self.project.selectlayersmapping() layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() RoamEvents.selectioncleared.emit() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler(self.badLayerHandler) self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format( project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.clearCapatureTools() self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
class Qgis2threejsDialog(QDialog): def __init__(self, iface, pluginManager, exportSettings=None, lastTreeItemData=None): QDialog.__init__(self, iface.mainWindow()) self.iface = iface self.pluginManager = pluginManager self._settings = exportSettings or {} self.lastTreeItemData = lastTreeItemData self.localBrowsingMode = True self.rb_quads = self.rb_point = None self.templateType = None self.currentItem = None self.currentPage = None # Set up the user interface from Designer. self.ui = ui = Ui_Qgis2threejsDialog() ui.setupUi(self) self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint) # output html filename ui.lineEdit_OutputFilename.setText(self._settings.get("OutputFilename", "")) ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]") # settings button icon = QIcon(os.path.join(tools.pluginDir(), "icons", "settings.png")) ui.toolButton_Settings.setIcon(icon) # popup menu displayed when settings button is pressed items = [["Load Settings...", self.loadSettings], ["Save Settings As...", self.saveSettings], [None, None], ["Clear Settings", self.clearSettings], [None, None], ["Plugin Settings...", self.pluginSettings]] self.menu = QMenu() self.menu_actions = [] for text, slot in items: if text: action = QAction(text, iface.mainWindow()) action.triggered.connect(slot) self.menu.addAction(action) self.menu_actions.append(action) else: self.menu.addSeparator() ui.toolButton_Settings.setMenu(self.menu) ui.toolButton_Settings.setPopupMode(QToolButton.InstantPopup) # progress bar and message label ui.progressBar.setVisible(False) ui.label_MessageIcon.setVisible(False) # buttons ui.pushButton_Run.clicked.connect(self.run) ui.pushButton_Close.clicked.connect(self.reject) ui.pushButton_Help.clicked.connect(self.help) # set up map tool self.previousMapTool = None self.mapTool = RectangleMapTool(iface.mapCanvas()) #self.mapTool = PointMapTool(iface.mapCanvas()) # set up the template combo box self.initTemplateList() self.ui.comboBox_Template.currentIndexChanged.connect(self.currentTemplateChanged) # set up the properties pages self.pages = {} self.pages[ppages.PAGE_WORLD] = ppages.WorldPropertyPage(self) self.pages[ppages.PAGE_CONTROLS] = ppages.ControlsPropertyPage(self) self.pages[ppages.PAGE_DEM] = ppages.DEMPropertyPage(self) self.pages[ppages.PAGE_VECTOR] = ppages.VectorPropertyPage(self) container = ui.propertyPagesContainer for page in self.pages.values(): page.hide() container.addWidget(page) # build object tree self.topItemPages = {ObjectTreeItem.ITEM_WORLD: ppages.PAGE_WORLD, ObjectTreeItem.ITEM_CONTROLS: ppages.PAGE_CONTROLS, ObjectTreeItem.ITEM_DEM: ppages.PAGE_DEM} self.initObjectTree() self.ui.treeWidget.currentItemChanged.connect(self.currentObjectChanged) self.ui.treeWidget.itemChanged.connect(self.objectItemChanged) self.currentTemplateChanged() # update item visibility ui.toolButton_Browse.clicked.connect(self.browseClicked) #iface.mapCanvas().mapToolSet.connect(self.mapToolSet) # to show button to enable own map tool def settings(self, clean=False): # save settings of current panel item = self.ui.treeWidget.currentItem() if item and self.currentPage: self.saveProperties(item, self.currentPage) # plugin version self._settings["PluginVersion"] = plugin_version # template and output html file path self._settings["Template"] = self.ui.comboBox_Template.currentText() self._settings["OutputFilename"] = self.ui.lineEdit_OutputFilename.text() if not clean: return self._settings # clean up settings - remove layers that don't exist in the layer registry registry = QgsProject.instance() for itemId in [ObjectTreeItem.ITEM_OPTDEM, ObjectTreeItem.ITEM_POINT, ObjectTreeItem.ITEM_LINE, ObjectTreeItem.ITEM_POLYGON]: parent = self._settings.get(itemId, {}) for layerId in list(parent.keys()): if registry.mapLayer(layerId) is None: del parent[layerId] return self._settings def setSettings(self, settings): self._settings = settings # template and output html file path templateName = settings.get("Template") if templateName: cbox = self.ui.comboBox_Template index = cbox.findText(templateName) if index != -1: cbox.setCurrentIndex(index) filename = settings.get("OutputFilename") if filename: self.ui.lineEdit_OutputFilename.setText(filename) # update object tree self.ui.treeWidget.blockSignals(True) self.initObjectTree() self.ui.treeWidget.blockSignals(False) # update tree item visibility self.templateType = None self.currentTemplateChanged() def loadSettings(self): # file open dialog directory = QgsProject.instance().homePath() if not directory: directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0] if not directory: directory = QDir.homePath() filterString = "Settings files (*.qto3settings);;All files (*.*)" filename, _ = QFileDialog.getOpenFileName(self, "Load Export Settings", directory, filterString) if not filename: return # load settings from file (.qto3settings) import json with open(filename) as f: settings = json.load(f) self.setSettings(settings) def saveSettings(self, filename=None): if not filename: # file save dialog directory = QgsProject.instance().homePath() if not directory: directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0] if not directory: directory = QDir.homePath() filename, _ = QFileDialog.getSaveFileName(self, "Save Export Settings", directory, "Settings files (*.qto3settings)") if not filename: return # append .qto3settings extension if filename doesn't have if os.path.splitext(filename)[1].lower() != ".qto3settings": filename += ".qto3settings" # save settings to file (.qto3settings) import json with open(filename, "w", encoding="UTF-8") as f: json.dump(self.settings(True), f, ensure_ascii=False, indent=2, sort_keys=True) logMessage("Settings saved: {0}".format(filename)) def clearSettings(self): if QMessageBox.question(self, "Qgis2threejs", "Are you sure to clear all export settings?", QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Ok: self.setSettings({}) def pluginSettings(self): from .settingsdialog import SettingsDialog dialog = SettingsDialog(self) if dialog.exec_(): self.pluginManager.reloadPlugins() self.pages[ppages.PAGE_DEM].initLayerComboBox() def showMessageBar(self, text, level=QgsMessageBar.INFO): # from src/gui/qgsmessagebaritem.cpp if level == QgsMessageBar.CRITICAL: msgIcon = "/mIconCritical.png" bgColor = "#d65253" elif level == QgsMessageBar.WARNING: msgIcon = "/mIconWarn.png" bgColor = "#ffc800" else: msgIcon = "/mIconInfo.png" bgColor = "#e7f5fe" stylesheet = "QLabel {{ background-color:{0}; }}".format(bgColor) label = self.ui.label_MessageIcon label.setPixmap(QgsApplication.getThemeIcon(msgIcon).pixmap(24)) label.setStyleSheet(stylesheet) label.setVisible(True) label = self.ui.label_Status label.setText(text) label.setStyleSheet(stylesheet) def clearMessageBar(self): self.ui.label_MessageIcon.setVisible(False) self.ui.label_Status.setText("") self.ui.label_Status.setStyleSheet("QLabel { background-color: rgba(0, 0, 0, 0); }") def initTemplateList(self): cbox = self.ui.comboBox_Template cbox.clear() templateDir = QDir(tools.templateDir()) for i, entry in enumerate(templateDir.entryList(["*.html", "*.htm"])): cbox.addItem(entry) config = tools.getTemplateConfig(entry) # get template type templateType = config.get("type", "plain") cbox.setItemData(i, templateType, Qt.UserRole) # set tool tip text desc = config.get("description", "") if desc: cbox.setItemData(i, desc, Qt.ToolTipRole) # select the template of the settings templatePath = self._settings.get("Template") # if no template setting, select the last used template if not templatePath: templatePath = QSettings().value("/Qgis2threejs/lastTemplate", def_vals.template, type=str) if templatePath: index = cbox.findText(templatePath) if index != -1: cbox.setCurrentIndex(index) return index return -1 def initObjectTree(self): tree = self.ui.treeWidget tree.clear() # add vector and raster layers into tree widget topItems = {} for id, name in zip(ObjectTreeItem.topItemIds, ObjectTreeItem.topItemNames): item = QTreeWidgetItem(tree, [name]) item.setData(0, Qt.UserRole, id) topItems[id] = item optDEMChecked = False for layer in getLayersInProject(): parentId = ObjectTreeItem.parentIdByLayer(layer) if parentId is None: continue item = QTreeWidgetItem(topItems[parentId], [layer.name()]) isVisible = self._settings.get(parentId, {}).get(layer.id(), {}).get("visible", False) check_state = Qt.Checked if isVisible else Qt.Unchecked item.setData(0, Qt.CheckStateRole, check_state) item.setData(0, Qt.UserRole, layer.id()) if parentId == ObjectTreeItem.ITEM_OPTDEM and isVisible: optDEMChecked = True for id, item in topItems.items(): if id != ObjectTreeItem.ITEM_OPTDEM or optDEMChecked: tree.expandItem(item) # disable additional DEM item which is selected as main DEM layerId = self._settings.get(ObjectTreeItem.ITEM_DEM, {}).get("comboBox_DEMLayer") if layerId: self.primaryDEMChanged(layerId) def saveProperties(self, item, page): properties = page.properties() parent = item.parent() if parent is None: # top level item self._settings[item.data(0, Qt.UserRole)] = properties else: # layer item parentId = parent.data(0, Qt.UserRole) if parentId not in self._settings: self._settings[parentId] = {} self._settings[parentId][item.data(0, Qt.UserRole)] = properties def setCurrentTreeItemByData(self, data): it = QTreeWidgetItemIterator(self.ui.treeWidget) while it.value(): if it.value().data(0, Qt.UserRole) == data: self.ui.treeWidget.setCurrentItem(it.value()) return True it += 1 return False def currentTemplateChanged(self, index=None): cbox = self.ui.comboBox_Template templateType = cbox.itemData(cbox.currentIndex(), Qt.UserRole) if templateType == self.templateType: return # hide items unsupported by template tree = self.ui.treeWidget for i, id in enumerate(ObjectTreeItem.topItemIds): hidden = (templateType == "sphere" and id != ObjectTreeItem.ITEM_CONTROLS) tree.topLevelItem(i).setHidden(hidden) # set current tree item if templateType == "sphere": tree.setCurrentItem(tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_CONTROLS))) elif self.lastTreeItemData is None or not self.setCurrentTreeItemByData(self.lastTreeItemData): # restore selection tree.setCurrentItem(tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_DEM))) # default selection for plain is DEM # display messages self.clearMessageBar() if templateType != "sphere": # show message if crs unit is degrees mapSettings = self.iface.mapCanvas().mapSettings() if mapSettings.destinationCrs().mapUnits() in [QgsUnitTypes.DistanceDegrees]: self.showMessageBar("The unit of current CRS is degrees, so terrain may not appear well.", QgsMessageBar.WARNING) self.templateType = templateType def currentObjectChanged(self, currentItem, previousItem): # save properties of previous item if previousItem and self.currentPage: self.saveProperties(previousItem, self.currentPage) self.currentItem = currentItem self.currentPage = None # hide text browser and all pages self.ui.textBrowser.hide() for page in self.pages.values(): page.hide() parent = currentItem.parent() if parent is None: topItemIndex = currentItem.data(0, Qt.UserRole) pageType = self.topItemPages.get(topItemIndex, ppages.PAGE_NONE) page = self.pages.get(pageType, None) if page is None: self.showDescription(topItemIndex) return page.setup(self._settings.get(topItemIndex)) page.show() else: parentId = parent.data(0, Qt.UserRole) layerId = currentItem.data(0, Qt.UserRole) layer = QgsProject.instance().mapLayer(str(layerId)) if layer is None: return layerType = layer.type() if layerType == QgsMapLayer.RasterLayer: page = self.pages[ppages.PAGE_DEM] page.setup(self._settings.get(parentId, {}).get(layerId, None), layer, False) elif layerType == QgsMapLayer.VectorLayer: page = self.pages[ppages.PAGE_VECTOR] page.setup(self._settings.get(parentId, {}).get(layerId, None), layer) else: return page.show() self.currentPage = page def objectItemChanged(self, item, column): parent = item.parent() if parent is None: return # checkbox of optional layer checked/unchecked if item == self.currentItem: if self.currentPage: # update enablement of property widgets self.currentPage.itemChanged(item) else: # select changed item self.ui.treeWidget.setCurrentItem(item) # set visible property #visible = item.data(0, Qt.CheckStateRole) == Qt.Checked #parentId = parent.data(0, Qt.UserRole) #layerId = item.data(0, Qt.UserRole) #self._settings.get(parentId, {}).get(layerId, {})["visible"] = visible def primaryDEMChanged(self, layerId): tree = self.ui.treeWidget parent = tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_OPTDEM)) tree.blockSignals(True) for i in range(parent.childCount()): item = parent.child(i) isPrimary = item.data(0, Qt.UserRole) == layerId item.setDisabled(isPrimary) tree.blockSignals(False) def showDescription(self, topItemIndex): fragment = {ObjectTreeItem.ITEM_OPTDEM: "additional-dem", ObjectTreeItem.ITEM_POINT: "point", ObjectTreeItem.ITEM_LINE: "line", ObjectTreeItem.ITEM_POLYGON: "polygon"}.get(topItemIndex) url = "http://qgis2threejs.readthedocs.org/en/docs-release/ExportSettings.html" if fragment: url += "#" + fragment html = '<a href="{0}">Online Help</a> about this item'.format(url) self.ui.textBrowser.setHtml(html) self.ui.textBrowser.show() def numericFields(self, layer): # get attributes of a sample feature and create numeric field name list numeric_fields = [] f = QgsFeature() layer.getFeatures().nextFeature(f) for field in f.fields(): isNumeric = False try: float(f.attribute(field.name())) isNumeric = True except ValueError: pass if isNumeric: numeric_fields.append(field.name()) return numeric_fields def mapTo3d(self): world = self._settings.get(ObjectTreeItem.ITEM_WORLD, {}) bs = float(world.get("lineEdit_BaseSize", def_vals.baseSize)) ve = float(world.get("lineEdit_zFactor", def_vals.zExaggeration)) vs = float(world.get("lineEdit_zShift", def_vals.zShift)) return MapTo3D(self.iface.mapCanvas().mapSettings(), bs, ve, vs) def progress(self, percentage=None, statusMsg=None): ui = self.ui if percentage is not None: ui.progressBar.setValue(percentage) if percentage == 100: ui.progressBar.setVisible(False) ui.label_Status.setText("") else: ui.progressBar.setVisible(True) if statusMsg is not None: ui.label_Status.setText(statusMsg) ui.label_Status.repaint() QgsApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def run(self): self.endPointSelection() ui = self.ui filename = ui.lineEdit_OutputFilename.text() # ""=Temporary file if filename and os.path.exists(filename): if QMessageBox.question(self, "Qgis2threejs", "Output file already exists. Overwrite it?", QMessageBox.Ok | QMessageBox.Cancel) != QMessageBox.Ok: return # export to web (three.js) export_settings = ExportSettings(self.pluginManager, self.localBrowsingMode) export_settings.loadSettings(self.settings()) export_settings.setMapCanvas(self.iface.mapCanvas()) err_msg = export_settings.checkValidity() if err_msg is not None: QMessageBox.warning(self, "Qgis2threejs", err_msg or "Invalid settings") return ui.pushButton_Run.setEnabled(False) ui.toolButton_Settings.setVisible(False) self.clearMessageBar() self.progress(0) if export_settings.exportMode == ExportSettings.PLAIN_MULTI_RES: # update quads and point on map canvas self.createRubberBands(export_settings.baseExtent, export_settings.quadtree()) # export ret = exportToThreeJS(export_settings, self.progress) self.progress(100) ui.pushButton_Run.setEnabled(True) if not ret: ui.toolButton_Settings.setVisible(True) return self.clearRubberBands() # store last selections settings = QSettings() settings.setValue("/Qgis2threejs/lastTemplate", export_settings.templatePath) settings.setValue("/Qgis2threejs/lastControls", export_settings.controls) # open web browser if not tools.openHTMLFile(export_settings.htmlfilename): ui.toolButton_Settings.setVisible(True) return # close dialog QDialog.accept(self) def reject(self): # save properties of current object item = self.ui.treeWidget.currentItem() if item and self.currentPage: self.saveProperties(item, self.currentPage) self.endPointSelection() self.clearRubberBands() QDialog.reject(self) def help(self): url = "http://qgis2threejs.readthedocs.org/" import webbrowser webbrowser.open(url, new=2) # new=2: new tab if possible def startPointSelection(self): canvas = self.iface.mapCanvas() if self.previousMapTool != self.mapTool: self.previousMapTool = canvas.mapTool() canvas.setMapTool(self.mapTool) self.pages[ppages.PAGE_DEM].toolButton_PointTool.setVisible(False) def endPointSelection(self): self.mapTool.reset() if self.previousMapTool is not None: self.iface.mapCanvas().setMapTool(self.previousMapTool) def mapToolSet(self, mapTool): return #TODO: unstable if mapTool != self.mapTool and self.currentPage is not None: if self.currentPage.pageType == ppages.PAGE_DEM and self.currentPage.isPrimary: self.currentPage.toolButton_PointTool.setVisible(True) def createRubberBands(self, baseExtent, quadtree): self.clearRubberBands() # create quads with rubber band self.rb_quads = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.rb_quads.setColor(Qt.blue) self.rb_quads.setWidth(1) quads = quadtree.quads() for quad in quads: geom = baseExtent.subrectangle(quad.rect).geometry() self.rb_quads.addGeometry(geom, None) self.log("Quad count: %d" % len(quads)) if not quadtree.focusRect: return # create a point with rubber band if quadtree.focusRect.width() == 0 or quadtree.focusRect.height() == 0: npt = quadtree.focusRect.center() self.rb_point = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.rb_point.setColor(Qt.red) self.rb_point.addPoint(baseExtent.point(npt)) def clearRubberBands(self): # clear quads and point if self.rb_quads: self.iface.mapCanvas().scene().removeItem(self.rb_quads) self.rb_quads = None if self.rb_point: self.iface.mapCanvas().scene().removeItem(self.rb_point) self.rb_point = None def browseClicked(self): directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0] if not directory: directory = QDir.homePath() filename, _ = QFileDialog.getSaveFileName(self, self.tr("Output filename"), directory, "HTML file (*.html *.htm)", options=QFileDialog.DontConfirmOverwrite) if not filename: return # append .html extension if filename doesn't have either .html or .htm if filename[-5:].lower() != ".html" and filename[-4:].lower() != ".htm": filename += ".html" self.ui.lineEdit_OutputFilename.setText(filename) def log(self, msg): if debug_mode: qDebug(msg)
class ItemBrowserDock(QDockWidget, Ui_itembrowser): dockRemoved = pyqtSignal(str) def __init__(self, iface, layer, currentFeature): self.iface = iface self.layer = layer self.renderer = self.iface.mapCanvas().mapRenderer() self.settings = MySettings() QDockWidget.__init__(self) self.setupUi(self) self.setWindowTitle("ItemBrowser: %s" % layer.name()) if layer.hasGeometryType() is False: self.panCheck.setChecked(False) self.panCheck.setEnabled(False) self.scaleCheck.setChecked(False) self.scaleCheck.setEnabled(False) self.previousButton.setArrowType(Qt.LeftArrow) self.nextButton.setArrowType(Qt.RightArrow) icon = QIcon(":/plugins/itembrowser/icons/openform.svg") self.editFormButton.setIcon(icon) # actions icon = QIcon(":/plugins/itembrowser/icons/action.svg") self.actionButton.setIcon(icon) self.attrAction = layer.actions() actions = [self.attrAction[i] for i in range(self.attrAction.size())] preferredAction = layer.customProperty("ItemBrowserPreferedAction", "") if preferredAction not in actions: dfltAction = self.attrAction.defaultAction() if dfltAction > len(actions): preferredAction = self.attrAction[dfltAction].name() preferredActionFound = False for i, action in enumerate(actions): qAction = QAction(QIcon(":/plugins/itembrowser/icons/action.svg"), action.name(), self) qAction.triggered.connect(lambda: self.doAction(i)) self.actionButton.addAction(qAction) if action.name() == preferredAction: self.actionButton.setDefaultAction(qAction) preferredActionFound = True if len(actions) == 0: self.actionButton.setEnabled(False) elif not preferredActionFound: self.actionButton.setDefaultAction(self.actionButton.actions()[0]) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.selectionChanged() if currentFeature == self.listCombo.currentIndex(): self.on_listCombo_currentIndexChanged(currentFeature) else: self.listCombo.setCurrentIndex(currentFeature) self.layer.layerDeleted.connect(self.close) self.layer.selectionChanged.connect(self.selectionChanged) def closeEvent(self, e): self.rubber.reset() self.layer.layerDeleted.disconnect(self.close) self.layer.selectionChanged.disconnect(self.selectionChanged) if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserSelection", repr([])) self.dockRemoved.emit(self.layer.id()) def selectionChanged(self): self.cleanBrowserFields() self.rubber.reset() nItems = self.layer.selectedFeatureCount() if nItems < 2: self.close() self.layer.emit(SIGNAL("browserNoItem()")) return self.browseFrame.setEnabled(True) self.subset = self.layer.selectedFeaturesIds() if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserSelection", repr(self.subset)) for fid in self.subset: self.listCombo.addItem("%u" % fid) def cleanBrowserFields(self): self.currentPosLabel.setText('0/0') self.listCombo.clear() def panScaleToItem(self, feature): if self.panCheck.isChecked() is False: return featBobo = feature.geometry().boundingBox() # if scaling and bobo has width and height (i.e. not a point) if self.scaleCheck.isChecked( ) and featBobo.width() != 0 and featBobo.height() != 0: featBobo.scale(self.settings.value("scale")) ul = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMaximum())) ur = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMaximum())) ll = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMinimum())) lr = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMinimum())) x = (ul.x(), ur.x(), ll.x(), lr.x()) y = (ul.y(), ur.y(), ll.y(), lr.y()) x0 = min(x) y0 = min(y) x1 = max(x) y1 = max(y) else: panTo = self.renderer.layerToMapCoordinates( self.layer, featBobo.center()) mapBobo = self.iface.mapCanvas().extent() xshift = panTo.x() - mapBobo.center().x() yshift = panTo.y() - mapBobo.center().y() x0 = mapBobo.xMinimum() + xshift y0 = mapBobo.yMinimum() + yshift x1 = mapBobo.xMaximum() + xshift y1 = mapBobo.yMaximum() + yshift self.iface.mapCanvas().setExtent(QgsRectangle(x0, y0, x1, y1)) self.iface.mapCanvas().refresh() def getCurrentItem(self): i = self.listCombo.currentIndex() if i == -1: return None f = QgsFeature() if self.layer.getFeatures(QgsFeatureRequest().setFilterFid( self.subset[i])).nextFeature(f): return f else: raise NameError("feature not found") def doAction(self, i): f = self.getCurrentItem() self.actionButton.setDefaultAction(self.actionButton.actions()[i]) self.layer.setCustomProperty("ItemBrowserPreferedAction", self.attrAction[i].name()) self.attrAction.doActionFeature(i, f) @pyqtSlot(name="on_previousButton_clicked") def previousFeaature(self): i = self.listCombo.currentIndex() n = max(0, i - 1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(name="on_nextButton_clicked") def nextFeature(self): i = self.listCombo.currentIndex() c = self.listCombo.count() n = min(i + 1, c - 1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(int, name="on_listCombo_activated") def saveCurrentFeature(self, i): if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("itemBrowserCurrentItem", i) @pyqtSlot(int, name="on_listCombo_currentIndexChanged") def on_listCombo_currentIndexChanged(self, i): feature = self.getCurrentItem() if feature is None: return self.rubber.reset() if self.listCombo.count() > 1: width = self.settings.value("rubberWidth") color = self.settings.value("rubberColor") self.rubber.setColor(color) self.rubber.setWidth(width) self.rubber.setToGeometry(feature.geometry(), self.layer) # scale to feature self.panScaleToItem(feature) # Update browser self.currentPosLabel.setText("%u/%u" % (i + 1, len(self.subset))) # emit signal self.layer.emit(SIGNAL("browserCurrentItem(long)"), feature.id()) @pyqtSlot(int, name="on_panCheck_stateChanged") def on_panCheck_stateChanged(self, i): if self.panCheck.isChecked(): self.scaleCheck.setEnabled(True) feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) else: self.scaleCheck.setEnabled(False) @pyqtSlot(int, name="on_scaleCheck_stateChanged") def on_scaleCheck_stateChanged(self, i): if self.scaleCheck.isChecked(): feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) @pyqtSlot(name="on_editFormButton_clicked") def openFeatureForm(self): self.iface.openFeatureForm(self.layer, self.getCurrentItem())
class SimpleIntersectionMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.mapCanvas = iface.mapCanvas() QgsMapTool.__init__(self, self.mapCanvas) self.settings = MySettings() self.rubber = QgsRubberBand(self.mapCanvas, QGis.Point) def deactivate(self): self.rubber.reset() QgsMapTool.deactivate(self) def activate(self): QgsMapTool.activate(self) self.rubber.setWidth(self.settings.value("rubberWidth")) self.rubber.setColor(self.settings.value("rubberColor")) self.checkLayer() def canvasMoveEvent(self, mouseEvent): # put the observations within tolerance in the rubber band self.rubber.reset(QGis.Point) match = self.snap_to_intersection(mouseEvent.pos()) if match.type() == QgsPointLocator.Vertex and match.layer() is None: self.rubber.addPoint(match.point()) def canvasPressEvent(self, mouseEvent): self.rubber.reset() match = self.snap_to_intersection(mouseEvent.pos()) if match.type() != QgsPointLocator.Vertex or match.layer() is not None: return layer = self.checkLayer() if layer is None: return f = QgsFeature() initFields = layer.dataProvider().fields() f.setFields(initFields) f.initAttributes(initFields.size()) f.setGeometry(QgsGeometry().fromPoint(match.point())) layer.editBuffer().addFeature(f) layer.triggerRepaint() def snap_to_intersection(self, pos): """ Temporarily override snapping config and snap to vertices and edges of any editable vector layer, to allow selection of node for editing (if snapped to edge, it would offer creation of a new vertex there). """ map_point = self.toMapCoordinates(pos) tol = QgsTolerance.vertexSearchRadius(self.canvas().mapSettings()) snap_type = QgsPointLocator.Type(QgsPointLocator.Edge) snap_layers = [] for layer in self.canvas().layers(): if not isinstance(layer, QgsVectorLayer): continue snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tol, QgsTolerance.ProjectUnits)) snap_util = self.canvas().snappingUtils() old_layers = snap_util.layers() old_mode = snap_util.snapToMapMode() old_inter = snap_util.snapOnIntersections() snap_util.setLayers(snap_layers) snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) snap_util.setSnapOnIntersections(True) m = snap_util.snapToMap(map_point) snap_util.setLayers(old_layers) snap_util.setSnapToMapMode(old_mode) snap_util.setSnapOnIntersections(old_inter) return m def checkLayer(self): # check output layer is defined layerid = self.settings.value("simpleIntersectionLayer") layer = QgsMapLayerRegistry.instance().mapLayer(layerid) if not self.settings.value( "simpleIntersectionWritePoint") or layer is None: self.iface.messageBar().pushMessage( "Intersect It", "You must define an output layer for simple intersections", QgsMessageBar.WARNING, 3) self.mapCanvas.unsetMapTool(self) return None if not layer.isEditable(): self.iface.messageBar().pushMessage( "Intersect It", "The output layer <b>%s must be editable</b>" % layer.name(), QgsMessageBar.WARNING, 3) self.mapCanvas.unsetMapTool(self) return None return layer
class EditTool(QgsMapTool): wp_clicked = pyqtSignal(int) def __init__(self, mission_track, canvas, msglog): QgsMapTool.__init__(self, canvas) self.setCursor(Qt.CrossCursor) self.mission_track = mission_track self.msglog = msglog self.dragging = False self.feature = None self.vertex = None self.startcoord = None self.layer = self.mission_track.get_mission_layer() logger.info(self.mission_track.get_mission_name()) self.rubber_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry) self.rubber_band.setWidth(2) self.rubber_band.setColor(QColor("green")) self.point_cursor_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry) self.point_cursor_band.setWidth(1) self.point_cursor_band.setLineStyle(Qt.DashLine) self.point_cursor_band.setColor(QColor(255, 0, 0, 100)) self.mid_point_band = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.mid_point_band.setColor(QColor(255, 0, 0, 100)) self.mid_point_band.setIconSize(18) self.rubber_band_points = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.rubber_band_points.setColor(QColor("green")) self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubber_band_points.setIconSize(10) self.mission_track.mission_changed.connect(self.update_rubber_bands) self.vertex_marker = QgsVertexMarker(self.canvas()) self.start_end_marker = StartEndMarker(canvas, self.mission_track.find_waypoints_in_mission(), QColor("green")) self.layer.startEditing() self.wp = [] self.mCtrl = False # handler for mission feature self.update_rubber_bands(0) crs = canvas.mapSettings().destinationCrs() self.distance_calc = QgsDistanceArea() self.distance_calc.setSourceCrs(crs, QgsProject.instance().transformContext()) self.distance_calc.setEllipsoid(crs.ellipsoidAcronym()) def update_rubber_bands(self, current_wp): self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.wp = self.mission_track.find_waypoints_in_mission() self.start_end_marker.update_markers(self.wp) if len(self.wp) > 0: for v in self.wp: pc = self.toLayerCoordinates(self.layer, QgsPointXY(v)) self.rubber_band.addPoint(pc) self.rubber_band_points.addPoint(pc) logger.debug("MISSION UPDATE: now we have {} waypoints".format(len(self.wp))) self.vertex_marker.setCenter(QgsPointXY(self.wp[current_wp].x(), self.wp[current_wp].y())) self.vertex_marker.setColor(QColor(25, 255, 0)) self.vertex_marker.setIconSize(7) self.vertex_marker.setIconType(QgsVertexMarker.ICON_X) # ICON_BOX, ICON_CROSS, ICON_X self.vertex_marker.setPenWidth(2) self.vertex_marker.show() self.set_geometry() else: self.vertex_marker.hide() def set_control_state(self, state): self.mCtrl = state def keyPressEvent(self, event): if event.key() == Qt.Key_Control and not self.dragging: self.mCtrl = True pos = self.canvas().mouseLastXY() if not self.find_on_feature(pos, self.calc_tolerance()): self.show_dist_and_bearing_to_point() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False pos = self.canvas().mouseLastXY() if not self.find_on_feature(pos, self.calc_tolerance()) and not self.dragging: self.show_dist_and_bearing_to_point() return def canvasDoubleClickEvent(self, event): self.canvasPressEvent(event) def canvasPressEvent(self, event): if self.dragging: self.canvasReleaseEvent(event) map_pt, layer_pt = self.transform_coordinates(event.pos()) tolerance = self.calc_tolerance() if not self.find_on_feature(event.pos(), tolerance): if event.button() == Qt.LeftButton: # we have clicked outside the track logger.debug("We have clicked outside the track") self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) if not self.mCtrl: # add step to mission at the end self.mission_track.add_step(len(self.wp), layer_pt) self.show_waypoint_distances(len(self.wp)-1) else: self.mission_track.add_step(0, layer_pt) self.show_waypoint_distances(0) else: logger.debug("We have clicked on the track") vertex = self.find_vertex_at(event.pos(), tolerance) if event.button() == Qt.LeftButton: if vertex is None: logger.debug("We have clicked between vertexs") # we have clicked in between vertex, add intermediate point initial_vertex = self.find_segment_at(event.pos()) # self.mission_track.add_step(initial_vertex + 1, layerPt) intersection = intersect_point_to_line(self.toLayerCoordinates(self.layer, event.pos()), QgsPointXY(self.wp[initial_vertex]), QgsPointXY(self.wp[initial_vertex + 1])) logger.debug("intersection point: {} {}".format(str(intersection.x()), str(intersection.y()))) logger.debug("{} {} {} {}".format(self.wp[initial_vertex].x(), self.wp[initial_vertex].y(), self.wp[initial_vertex + 1].x(), self.wp[initial_vertex + 1].y())) # layerPtIntersection = self.toLayerCoordinates(self.layer,intersection) self.mission_track.add_step(initial_vertex + 1, intersection) self.mid_point_band.reset(QgsWkbTypes.PointGeometry) self.show_waypoint_distances(initial_vertex+1) else: logger.debug("We have clicked on vertex {}".format(vertex)) # we have clicked on a vertex # Left click -> move vertex. self.dragging = True self.vertex = vertex self.startcoord = event.pos() # self.moveVertexTo(layerPt) elif event.button() == Qt.RightButton: if vertex is not None and not self.dragging: # Right click -> delete vertex. self.delete_vertex(vertex) if self.find_on_feature(event.pos(), tolerance): # If cursor still over track vertex = self.find_vertex_at(event.pos(), tolerance) if vertex is None: # Cursor is between vertexes self.show_mid_point(event.pos()) else: # Cursor is over a vertex self.show_waypoint_distances(vertex) else: self.show_dist_and_bearing_to_point() def transform_coordinates(self, canvas_pt): return (self.toMapCoordinates(canvas_pt), self.toLayerCoordinates(self.layer, canvas_pt)) def canvasMoveEvent(self, event): if self.dragging: self.move_vertex_to(self.toLayerCoordinates(self.layer, event.pos())) self.mission_track.hide_start_end_markers() self.vertex_marker.hide() self.start_end_marker.hide_markers() self.show_waypoint_distances(self.vertex) else: tolerance = self.calc_tolerance() if self.find_on_feature(event.pos(), tolerance): # if mouse is over the track self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) self.mid_point_band.reset(QgsWkbTypes.PointGeometry) vertex = self.find_vertex_at(event.pos(), tolerance) if vertex is None: # Cursor is between vertexes self.show_mid_point(event.pos()) else: # Cursor is over a vertex self.show_waypoint_distances(vertex) else: self.mid_point_band.reset(QgsWkbTypes.PointGeometry) self.show_dist_and_bearing_to_point() def show_dist_and_bearing_to_point(self): """ Finds distance and bearing from the last point (first if pressing ctrl) to the specified point and shows them in the message log. Also draws a line between the points. """ bearing = 0.0 self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) point = self.canvas().mouseLastXY() if len(self.wp) > 0: cursor_point = self.toMapCoordinates(point) if self.mCtrl: anchor_point = QgsPointXY(self.wp[0]) else: anchor_point = QgsPointXY(self.wp[len(self.wp) - 1]) self.point_cursor_band.addPoint(cursor_point) self.point_cursor_band.addPoint(anchor_point) distance = self.distance_calc.measureLine([anchor_point, cursor_point]) if distance != 0.0: bearing = self.distance_calc.bearing(anchor_point, cursor_point) self.msglog.logMessage("") if self.mCtrl: msg = "Distance to next point: " else: msg = "Distance to previous point: " self.msglog.logMessage(msg + "{:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)), "Distance and bearing", 0) else: self.msglog.logMessage("") def show_mid_point(self, cursor): """ Finds the projection of the cursor over the track and draws a circle in that point. Finds the distances between this projection point and the previous and next points in the mission and shows them in the message log. :param cursor: position to be projected over the track """ prev_vertex = self.find_segment_at(cursor) prev_point = QgsPointXY(self.wp[prev_vertex]) next_point = QgsPointXY(self.wp[prev_vertex + 1]) cursor_point = self.toMapCoordinates(cursor) intersection = intersect_point_to_line(cursor_point, prev_point, next_point) self.mid_point_band.addPoint(intersection) distance1 = self.distance_calc.measureLine([prev_point, intersection]) distance2 = self.distance_calc.measureLine([intersection, next_point]) self.msglog.logMessage("") self.msglog.logMessage("Distance to previous point: {:.3F} m. Distance to next point: {:.3F} m." .format(distance1, distance2), "Distance between points", 0) def show_waypoint_distances(self, vertex): """ Finds the distances to adjacent waypoints of vertex and shows them in the message log :param vertex: index of the waypoint from the mission """ curr_point = self.rubber_band_points.getPoint(QgsWkbTypes.PointGeometry, vertex) if vertex == 0: if len(self.wp) > 1: next_point = QgsPointXY(self.wp[vertex+1]) distance = self.distance_calc.measureLine([curr_point, next_point]) bearing = self.distance_calc.bearing(next_point, curr_point) msg = "Distance to next point: {:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)) else: msg = "" self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {}) ".format(vertex+1), "Vertex distances", 0) elif vertex == len(self.wp) - 1: prev_point = QgsPointXY(self.wp[vertex-1]) distance = self.distance_calc.measureLine([prev_point, curr_point]) bearing = self.distance_calc.bearing(prev_point, curr_point) msg = "Distance to previous point: {:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)) self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0) else: prev_point = QgsPointXY(self.wp[vertex-1]) next_point = QgsPointXY(self.wp[vertex+1]) distance1 = self.distance_calc.measureLine(prev_point, curr_point) distance2 = self.distance_calc.measureLine(curr_point, next_point) msg = "Distance to previous point: {:.3F} m. Distance to next point: {:.3F} m."\ .format(distance1, distance2) self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0) def hide_point_cursor_band(self): """ Hides the rubber band drawn from last (or first) point to cursor """ self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) def canvasReleaseEvent(self, event): if self.dragging and event.button() == Qt.LeftButton: self.dragging = False self.vertex_marker.show() mapPt, layerPt = self.transform_coordinates(event.pos()) # Check distance with initial point dist = math.sqrt( (self.startcoord.x() - event.pos().x()) ** 2 + (self.startcoord.y() - event.pos().y()) ** 2) tolerance = self.calc_tolerance() if dist > tolerance: self.move_vertex_to(layerPt) self.mission_track.change_position(self.vertex, layerPt) self.wp_clicked.emit(self.vertex) self.feature = None self.vertex = None self.layer.updateExtents() else: # If release point is the same, has been just a click self.move_vertex_to(self.toLayerCoordinates(self.layer, QgsPointXY(self.wp[self.vertex]))) self.wp_clicked.emit(self.vertex) self.feature = None self.vertex = None def calc_tolerance(self): """ Compute the tolerance on canvas :return: tolerance """ # 2% of tolerance width_tolerance = 0.02 * self.canvas().width() height_tolerance = 0.02 * self.canvas().height() if width_tolerance < height_tolerance: tolerance = width_tolerance else: tolerance = height_tolerance return tolerance def move_vertex_to(self, layerPt): """ Move current vertex to layerPt position. :param layerPt: layer point :type: QgsPointXY """ if len(self.wp) > 1: self.rubber_band.movePoint(self.vertex, layerPt) self.rubber_band_points.movePoint(self.vertex, layerPt) elif len(self.wp) == 1: # A rubber band with PointGeometry and only 1 point acts as if it had 2 points, we need to reset it in # order to move the point. self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.rubber_band_points.addPoint(layerPt) def delete_vertex(self, vertex): """ Delete step 'vertex'. :param vertex: step """ self.mission_track.remove_step(vertex) self.dragging = False self.vertex = None def find_on_feature(self, pos, tolerance): """ if clicked point has some segment at a smaller distance than tolerance means that we've clicked on the track :param pos: The point that we've clicked :param tolerance: The tolerance of pos :return: bool """ if len(self.wp) > 1: dist_to_segment = [] for v in range(0, len(self.wp) - 1): # convert layer coordinates to canvas coordinates a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1])) dist_to_segment.append( self.dist_to_segment(a1.x(), a1.y(), b1.x(), b1.y(), pos.x(), pos.y())) logger.debug("dist to segment: {}".format(dist_to_segment)) if dist_to_segment[v] < tolerance: return True return False else: # last waypoint vertex = self.find_vertex_at(pos, tolerance) if vertex is None: return False else: return True def find_segment_at(self, pos): """ get the segment that is closer to the clicked point and return its initial vertex :param pos: the point that we've clicked :return: initial vertex of the segment """ dist_to_segment = [] for v in range(0, len(self.wp) - 1): a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1])) dist_to_segment.append(self.dist_to_segment(a1.x(), a1.y(), b1.x(), b1.y(), pos.x(), pos.y())) vertex = dist_to_segment.index(min(dist_to_segment)) return vertex def find_vertex_at(self, pos, tolerance): """ get the vertex that is closer to the clicked point :param pos: The point that we've clicked :param tolerance: The tolerance of pos :return: vertex or None """ if len(self.wp) > 0: dist_to_vertex = [] logger.debug("tolerance {}".format(tolerance)) for v in range(0, len(self.wp)): a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) dist_to_vertex.append(math.sqrt((pos.x() - a1.x()) ** 2 + (pos.y() - a1.y()) ** 2)) logger.debug("dist to vertex: {}".format(dist_to_vertex)) vertex = dist_to_vertex.index(min(dist_to_vertex)) if min(dist_to_vertex) > tolerance: return None else: logger.debug("ON VERTEX") return vertex else: return None def dist_to_segment(self, ax, ay, bx, by, cx, cy): """ Computes the minimum distance between a point (cx, cy) and a line segment with endpoints (ax, ay) and (bx, by). :param ax: endpoint 1, x-coordinate :param ay: endpoint 1, y-coordinate :param bx: endpoint 2, x-coordinate :param by: endpoint 2, y-coordinate :param cx: point, x-coordinate :param cy: point, x-coordinate :return: minimum distance between point and line segment """ # calculate tolerance tolerance = self.calc_tolerance() # get distance between points c-a and c-b dist_to_a = math.sqrt((cx - ax) ** 2 + (cy - ay) ** 2) dist_to_b = math.sqrt((cx - bx) ** 2 + (cy - by) ** 2) # if distance to point a or distance to point b is smaller than tolerance, return -1 if (dist_to_a < tolerance) or (dist_to_b < tolerance): return -1 # if one coordinate are between a coordinates or b coordinates if is_between(ax, ay, bx, by, cx, cy): y = (by - ay) x = (bx - ax) # line defined by two points formula num = abs((y * cx) - (x * cy) + (bx * ay) - (by * ax)) den = math.sqrt(y ** 2 + x ** 2) dl = num / den return dl else: return tolerance + 1 def set_geometry(self): """ Save rubber band to geometry of the layer """ if self.layer.featureCount() == 0: # no feature yet created f = QgsFeature() if len(self.wp) == 1: f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: f.setGeometry(QgsGeometry.fromPolyline(self.wp)) # self.layer.dataProvider().addFeatures([f]) self.layer.addFeatures([f]) else: # mission feature present, edit geometry feats = self.layer.getFeatures() for f in feats: if len(self.wp) == 1: self.layer.changeGeometry(f.id(), QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: self.layer.changeGeometry(f.id(), QgsGeometry.fromPolyline(self.wp)) self.layer.commitChanges() self.layer.startEditing() def close_band(self): self.start_end_marker.close_markers() self.vertex_marker.hide() self.canvas().scene().removeItem(self.vertex_marker) self.vertex_marker = None self.mission_track.mission_changed.disconnect() self.layer.commitChanges() self.rubber_band.hide() self.mid_point_band.hide() self.rubber_band_points.hide() self.point_cursor_band.hide() self.canvas().scene().removeItem(self.rubber_band) self.canvas().scene().removeItem(self.mid_point_band) self.canvas().scene().removeItem(self.rubber_band_points) self.canvas().scene().removeItem(self.point_cursor_band) self.rubber_band = None self.mid_point_band = None self.rubber_band_points = None self.point_cursor_band = None self.msglog.logMessage("")
def __init__(self, iface, layer, currentFeature): self.iface = iface self.layer = layer self.proj = QgsProject.instance() self.renderer = self.iface.mapCanvas().mapRenderer() self.settings = MySettings() QDockWidget.__init__(self) self.setupUi(self) # Track attr warnings so they are not repeated for multiple items self.warned_attr_values = [] self.setWindowTitle("teamqgis: %s" % layer.name()) if layer.hasGeometryType() is False: self.panCheck.setChecked(False) self.panCheck.setEnabled(False) self.scaleCheck.setChecked(False) self.scaleCheck.setEnabled(False) self.previousButton.setArrowType(Qt.LeftArrow) self.nextButton.setArrowType(Qt.RightArrow) icon = QIcon(":/plugins/teamqgis/icons/openform.svg") self.editFormButton.setIcon(icon) # actions icon = QIcon(":/plugins/teamqgis/icons/action.svg") self.actionButton.setIcon(icon) self.attrAction = layer.actions() actions = [self.attrAction[i] for i in range(self.attrAction.size())] preferredAction = layer.customProperty("teamqgisPreferedAction", "") if preferredAction not in actions: dfltAction = self.attrAction.defaultAction() if dfltAction > len(actions): preferredAction = self.attrAction[dfltAction].name() preferredActionFound = False for i, action in enumerate(actions): qAction = QAction(QIcon(":/plugins/teamqgis/icons/action.svg"), action.name(), self) qAction.triggered.connect(lambda: self.doAction(i)) self.actionButton.addAction(qAction) if action.name() == preferredAction: self.actionButton.setDefaultAction(qAction) preferredActionFound = True if len(actions) == 0: self.actionButton.setEnabled(False) elif not preferredActionFound: self.actionButton.setDefaultAction(self.actionButton.actions()[0]) self.nameComboBoxes = [ self.fieldOneNameComboBox, self.fieldTwoNameComboBox, self.fieldThreeNameComboBox ] self.valueComboBoxes = [ self.fieldOneValueComboBox, self.fieldTwoValueComboBox, self.fieldThreeValueComboBox ] self.updateNameComboBoxes() # Restore saved nameComboBox current indices if they exist for nameComboBox in self.nameComboBoxes: fieldName = self.layer.customProperty("teamqgis" + nameComboBox.objectName()) if fieldName != None: nameComboBox.setCurrentIndex(nameComboBox.findText(fieldName)) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.selectionChanged() if currentFeature == self.listCombo.currentIndex(): self.on_listCombo_currentIndexChanged(currentFeature) else: self.listCombo.setCurrentIndex(currentFeature) self.layer.layerDeleted.connect(self.close) self.layer.selectionChanged.connect(self.selectionChanged) self.layer.layerModified.connect(self.layerChanged) self.layer.editingStopped.connect(self.editingStopped) self.layer.editingStarted.connect(self.editingStarted) QObject.connect(self.proj, SIGNAL("allowedClassesChanged()"), self.updateValueComboBoxes)
class teamqgisDock(QDockWidget, Ui_teamqgis): dockRemoved = pyqtSignal(str) def __init__(self, iface, layer, currentFeature): self.iface = iface self.layer = layer self.proj = QgsProject.instance() self.renderer = self.iface.mapCanvas().mapRenderer() self.settings = MySettings() QDockWidget.__init__(self) self.setupUi(self) # Track attr warnings so they are not repeated for multiple items self.warned_attr_values = [] self.setWindowTitle("teamqgis: %s" % layer.name()) if layer.hasGeometryType() is False: self.panCheck.setChecked(False) self.panCheck.setEnabled(False) self.scaleCheck.setChecked(False) self.scaleCheck.setEnabled(False) self.previousButton.setArrowType(Qt.LeftArrow) self.nextButton.setArrowType(Qt.RightArrow) icon = QIcon(":/plugins/teamqgis/icons/openform.svg") self.editFormButton.setIcon(icon) # actions icon = QIcon(":/plugins/teamqgis/icons/action.svg") self.actionButton.setIcon(icon) self.attrAction = layer.actions() actions = [self.attrAction[i] for i in range(self.attrAction.size())] preferredAction = layer.customProperty("teamqgisPreferedAction", "") if preferredAction not in actions: dfltAction = self.attrAction.defaultAction() if dfltAction > len(actions): preferredAction = self.attrAction[dfltAction].name() preferredActionFound = False for i, action in enumerate(actions): qAction = QAction(QIcon(":/plugins/teamqgis/icons/action.svg"), action.name(), self) qAction.triggered.connect(lambda: self.doAction(i)) self.actionButton.addAction(qAction) if action.name() == preferredAction: self.actionButton.setDefaultAction(qAction) preferredActionFound = True if len(actions) == 0: self.actionButton.setEnabled(False) elif not preferredActionFound: self.actionButton.setDefaultAction(self.actionButton.actions()[0]) self.nameComboBoxes = [ self.fieldOneNameComboBox, self.fieldTwoNameComboBox, self.fieldThreeNameComboBox ] self.valueComboBoxes = [ self.fieldOneValueComboBox, self.fieldTwoValueComboBox, self.fieldThreeValueComboBox ] self.updateNameComboBoxes() # Restore saved nameComboBox current indices if they exist for nameComboBox in self.nameComboBoxes: fieldName = self.layer.customProperty("teamqgis" + nameComboBox.objectName()) if fieldName != None: nameComboBox.setCurrentIndex(nameComboBox.findText(fieldName)) self.rubber = QgsRubberBand(self.iface.mapCanvas()) self.selectionChanged() if currentFeature == self.listCombo.currentIndex(): self.on_listCombo_currentIndexChanged(currentFeature) else: self.listCombo.setCurrentIndex(currentFeature) self.layer.layerDeleted.connect(self.close) self.layer.selectionChanged.connect(self.selectionChanged) self.layer.layerModified.connect(self.layerChanged) self.layer.editingStopped.connect(self.editingStopped) self.layer.editingStarted.connect(self.editingStarted) QObject.connect(self.proj, SIGNAL("allowedClassesChanged()"), self.updateValueComboBoxes) def updateNameComboBoxes(self): fieldNameMap = self.layer.dataProvider().fieldNameMap() allFields = fieldNameMap.keys() if 'ID' in allFields: allFields.remove('ID') if 'FID' in allFields: allFields.remove('FID') for nameComboBox in self.nameComboBoxes: nameComboBox.clear() nameComboBox.addItems(allFields) def updateValueComboBoxes(self): feature = self.getCurrentItem() for (valueComboBox, nameComboBox) in zip(self.valueComboBoxes, self.nameComboBoxes): valueComboBox.clear() allowedClasses, hasAllowedClasses = self.proj.readListEntry( "teamqgis", "allowedClasses") if hasAllowedClasses: valueComboBox.addItems(allowedClasses) attr_value = str(feature[nameComboBox.currentText()]) if (allowedClasses == None) or (attr_value not in allowedClasses) and ( attr_value not in self.warned_attr_values): self.iface.messageBar().pushMessage( "Class name not in allowed class list", 'Assign an allowed class or add "%s" to allowed class list' % attr_value, level=QgsMessageBar.WARNING, duration=3) self.warned_attr_values.append(attr_value) valueComboBox.addItem(attr_value) valueComboBox.setCurrentIndex(valueComboBox.findText(attr_value)) def setRubber(self, feature): self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setWidth(self.settings.value("rubberWidth")) ##self.rubber.setLineStyle(Qt.DotLine) self.rubber.setBrushStyle(Qt.NoBrush) self.rubber.setToGeometry(feature.geometry(), self.layer) def closeEvent(self, e): self.rubber.reset() self.layer.layerDeleted.disconnect(self.close) self.layer.selectionChanged.disconnect(self.selectionChanged) self.layer.layerModified.disconnect(self.layerChanged) self.layer.editingStopped.disconnect(self.editingStopped) self.layer.editingStarted.disconnect(self.editingStarted) if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisSelection", repr([])) self.dockRemoved.emit(self.layer.id()) def selectionChanged(self): self.cleanBrowserFields() self.rubber.reset() nItems = self.layer.selectedFeatureCount() if nItems < 1: self.close() self.layer.emit(SIGNAL("browserNoItem()")) return self.browseFrame.setEnabled(True) self.subset = self.layer.selectedFeaturesIds() if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisSelection", repr(self.subset)) for fid in self.subset: self.listCombo.addItem("%u" % fid) self.setRubber(self.getCurrentItem()) self.updateValueComboBoxes() def layerChanged(self): self.applyChangesButton.setEnabled(True) def editingStarted(self): for valueComboBox in self.valueComboBoxes: valueComboBox.setEnabled(True) self.translateRightButton.setEnabled(True) self.translateLeftButton.setEnabled(True) self.translateUpButton.setEnabled(True) self.translateDownButton.setEnabled(True) self.editFormButton.setDown(True) def editingStopped(self): self.applyChangesButton.setEnabled(False) for valueComboBox in self.valueComboBoxes: valueComboBox.setEnabled(False) self.translateRightButton.setEnabled(False) self.translateLeftButton.setEnabled(False) self.translateUpButton.setEnabled(False) self.translateDownButton.setEnabled(False) self.editFormButton.setDown(False) def cleanBrowserFields(self): self.currentPosLabel.setText('0/0') self.listCombo.clear() def panScaleToItem(self, feature): if self.panCheck.isChecked() is False: return featBobo = feature.geometry().boundingBox() # if scaling and bobo has width and height (i.e. not a point) if self.scaleCheck.isChecked( ) and featBobo.width() != 0 and featBobo.height() != 0: featBobo.scale(self.settings.value("scale")) ul = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMaximum())) ur = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMaximum())) ll = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMinimum())) lr = self.renderer.layerToMapCoordinates( self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMinimum())) x = (ul.x(), ur.x(), ll.x(), lr.x()) y = (ul.y(), ur.y(), ll.y(), lr.y()) x0 = min(x) y0 = min(y) x1 = max(x) y1 = max(y) else: panTo = self.renderer.layerToMapCoordinates( self.layer, featBobo.center()) mapBobo = self.iface.mapCanvas().extent() xshift = panTo.x() - mapBobo.center().x() yshift = panTo.y() - mapBobo.center().y() x0 = mapBobo.xMinimum() + xshift y0 = mapBobo.yMinimum() + yshift x1 = mapBobo.xMaximum() + xshift y1 = mapBobo.yMaximum() + yshift self.iface.mapCanvas().setExtent(QgsRectangle(x0, y0, x1, y1)) self.iface.mapCanvas().refresh() def getCurrentItem(self): i = self.listCombo.currentIndex() if i == -1: return None f = QgsFeature() if self.layer.getFeatures(QgsFeatureRequest().setFilterFid( self.subset[i])).nextFeature(f): return f else: raise NameError("feature not found") def doAction(self, i): f = self.getCurrentItem() self.actionButton.setDefaultAction(self.actionButton.actions()[i]) self.layer.setCustomProperty("teamqgisPreferedAction", self.attrAction[i].name()) self.attrAction.doActionFeature(i, f) def doTranslate(self, trans): # Based on the "doaffine" function in the qgsAffine plugin if (self.layer.geometryType() == 2): start = 1 else: start = 0 if (not self.layer.isEditable()): self.iface.messageBar().pushMessage( "Layer not in edit mode", 'Select a vector layer and choose "Toggle Editing"', level=QgsMessageBar.WARNING) else: feature = self.getCurrentItem() result = feature.geometry() i = start vertex = result.vertexAt(i) fid = feature.id() while (vertex != QgsPoint(0, 0)): newx = vertex.x() + trans[0] * float( self.settings.value("xres")) newy = vertex.y() + trans[1] * float( self.settings.value("yres")) result.moveVertex(newx, newy, i) i += 1 vertex = result.vertexAt(i) self.layer.changeGeometry(fid, result) self.iface.mapCanvas().refresh() self.rubber.reset() self.setRubber(feature) def changeAttribute(self, i, fieldNameComboBox, fieldValueComboBox): fieldValueComboBox.setCurrentIndex(i) feature = self.getCurrentItem() attr_index = self.layer.dataProvider().fieldNameMap()[ fieldNameComboBox.currentText()] self.layer.changeAttributeValue(feature.id(), attr_index, fieldValueComboBox.currentText()) self.iface.mapCanvas().refresh() self.updateValueComboBoxes() def nameComboBox_activated(self, i, nameComboBox): self.layer.setCustomProperty('teamqgis' + nameComboBox.objectName(), nameComboBox.currentText()) @pyqtSlot(name="on_previousButton_clicked") def previousFeature(self): i = self.listCombo.currentIndex() n = max(0, i - 1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(name="on_nextButton_clicked") def nextFeature(self): self.warned_attr_values = [] # Reset attr warnings i = self.listCombo.currentIndex() c = self.listCombo.count() n = min(i + 1, c - 1) self.listCombo.setCurrentIndex(n) self.saveCurrentFeature(n) @pyqtSlot(int, name="on_listCombo_activated") def saveCurrentFeature(self, i): if self.settings.value("saveSelectionInProject"): self.layer.setCustomProperty("teamqgisCurrentItem", i) @pyqtSlot(int, name="on_fieldOneNameComboBox_activated") def fieldOneNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldOneNameComboBox) @pyqtSlot(int, name="on_fieldTwoNameComboBox_activated") def fieldTwoNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldTwoNameComboBox) @pyqtSlot(int, name="on_fieldThreeNameComboBox_activated") def fieldThreeNameComboBox_activated(self, i): self.nameComboBox_activated(i, self.fieldThreeNameComboBox) @pyqtSlot(int, name="on_listCombo_currentIndexChanged") def on_listCombo_currentIndexChanged(self, i): feature = self.getCurrentItem() if feature is None: return self.rubber.reset() if self.listCombo.count() > 1: self.setRubber(feature) self.updateValueComboBoxes() # scale to feature self.panScaleToItem(feature) # Update browser self.currentPosLabel.setText("%u/%u" % (i + 1, len(self.subset))) # emit signal self.layer.emit(SIGNAL("browserCurrentItem(long)"), feature.id()) @pyqtSlot(int, name="on_panCheck_stateChanged") def on_panCheck_stateChanged(self, i): if self.panCheck.isChecked(): self.scaleCheck.setEnabled(True) feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) else: self.scaleCheck.setEnabled(False) @pyqtSlot(int, name="on_scaleCheck_stateChanged") def on_scaleCheck_stateChanged(self, i): if self.scaleCheck.isChecked(): feature = self.getCurrentItem() if feature is None: return self.panScaleToItem(feature) @pyqtSlot(name="on_editFormButton_clicked") def openFeatureForm(self): if (self.layer.isEditable()): self.layer.commitChanges() else: self.layer.startEditing() @pyqtSlot(name="on_translateRightButton_clicked") def doTranslateRight(self): self.doTranslate((1, 0)) @pyqtSlot(name="on_translateLeftButton_clicked") def doTranslateLeft(self): self.doTranslate((-1, 0)) @pyqtSlot(name="on_translateUpButton_clicked") def doTranslateUp(self): self.doTranslate((0, 1)) @pyqtSlot(name="on_translateDownButton_clicked") def doTranslateDown(self): self.doTranslate((0, -1)) @pyqtSlot(name="on_applyChangesButton_clicked") def applyChanges(self): self.layer.commitChanges() self.layer.startEditing() self.layer.updateExtents() self.iface.mapCanvas().refresh() @pyqtSlot(int, name="on_fieldOneValueComboBox_activated") def on_fieldOneValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldOneNameComboBox, self.fieldOneValueComboBox) @pyqtSlot(int, name="on_fieldTwoValueComboBox_activated") def on_fieldTwoValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldTwoNameComboBox, self.fieldTwoValueComboBox) @pyqtSlot(int, name="on_fieldThreeValueComboBox_activated") def on_fieldThreeValueComboBox_activated(self, i): self.changeAttribute(i, self.fieldThreeNameComboBox, self.fieldThreeValueComboBox)
class GeodesicMeasureDialog(QDialog, FORM_CLASS): def __init__(self, iface, parent): super(GeodesicMeasureDialog, self).__init__(parent) self.setupUi(self) self.iface = iface self.canvas = iface.mapCanvas() self.pointDigitizerDialog = AddMeasurePointWidget(self, iface, parent) qset = QSettings() self.manualEntryButton.setIcon( QIcon(os.path.dirname(__file__) + "/images/manualpoint.png")) self.manualEntryButton.clicked.connect(self.showManualEntryDialog) self.restoreGeometry( qset.value("ShapeTools/MeasureDialogGeometry", QByteArray(), type=QByteArray)) self.closeButton.clicked.connect(self.closeDialog) self.newButton.clicked.connect(self.newDialog) self.saveToLayerButton.clicked.connect(self.saveToLayer) self.saveToLayerButton.setEnabled(False) self.unitsComboBox.addItems(DISTANCE_LABELS) self.tableWidget.setColumnCount(3) self.tableWidget.setSortingEnabled(False) self.tableWidget.setHorizontalHeaderLabels( [tr('Heading To'), tr('Heading From'), tr('Distance')]) self.unitsComboBox.activated.connect(self.unitsChanged) self.capturedPoints = [] self.distances = [] self.activeMeasuring = True self.lastMotionPt = None self.unitsChanged() self.currentDistance = 0.0 self.pointRb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.pointRb.setColor(settings.rubberBandColor) self.pointRb.setIconSize(10) self.lineRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.lineRb.setColor(settings.rubberBandColor) self.lineRb.setWidth(3) self.tempRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.tempRb.setColor(settings.rubberBandColor) self.tempRb.setWidth(3) def showManualEntryDialog(self): self.pointDigitizerDialog.show() def ready(self): return self.activeMeasuring def stop(self): self.activeMeasuring = False self.lastMotionPt = None def closeEvent(self, event): self.closeDialog() def closeDialog(self): self.clear() QSettings().setValue("ShapeTools/MeasureDialogGeometry", self.saveGeometry()) self.close() self.pointDigitizerDialog.closeDialog() def newDialog(self): self.clear() self.initGeodLabel() def initGeodLabel(self): label = tr('Ellipsoid: ') + settings.ellipseDescription self.geodLabel.setText(label) def keyPressed(self, key): index = len(self.capturedPoints) if index <= 0: return if key == Qt.Key_Escape: self.endRubberband() if self.motionReady(): if self.lastMotionPt is None: return (distance, startAngle, endAngle) = self.calcParameters(self.capturedPoints[index - 1], self.lastMotionPt) else: if index < 2: return (distance, startAngle, endAngle) = self.calcParameters(self.capturedPoints[index - 2], self.capturedPoints[index - 1]) distance = self.unitDistance(distance) clipboard = QApplication.clipboard() if key == Qt.Key_1 or key == Qt.Key_F: s = '{:.{prec}f}'.format(startAngle, prec=settings.measureSignificantDigits) clipboard.setText(s) self.iface.messageBar().pushMessage( "", "Heading to {} copied to the clipboard".format(s), level=Qgis.Info, duration=3) elif key == Qt.Key_2 or key == Qt.Key_T: s = '{:.{prec}f}'.format(endAngle, prec=settings.measureSignificantDigits) clipboard.setText(s) self.iface.messageBar().pushMessage( "", "Heading from {} copied to the clipboard".format(s), level=Qgis.Info, duration=3) elif key == Qt.Key_3 or key == Qt.Key_D: s = '{:.{prec}f}'.format(distance, prec=settings.measureSignificantDigits) clipboard.setText(s) self.iface.messageBar().pushMessage( "", "Distance {} copied to the clipboard".format(s), level=Qgis.Info, duration=3) elif key == Qt.Key_4 or key == Qt.Key_A: total = 0.0 num = len(self.capturedPoints) for i in range(1, num): (d, startA, endA) = self.calcParameters(self.capturedPoints[i - 1], self.capturedPoints[i]) total += d total = self.unitDistance(total) # Add in the motion distance if self.motionReady(): total += distance s = '{:.{prec}f}'.format(total, prec=settings.measureSignificantDigits) clipboard.setText(s) self.iface.messageBar().pushMessage( "", "Total distance {} copied to the clipboard".format(s), level=Qgis.Info, duration=3) else: return def unitsChanged(self): label = "Distance [{}]".format( DISTANCE_LABELS[self.unitsComboBox.currentIndex()]) item = QTableWidgetItem(label) self.tableWidget.setHorizontalHeaderItem(2, item) ptcnt = len(self.capturedPoints) if ptcnt >= 2: i = 0 while i < ptcnt - 1: item = QTableWidgetItem('{:.4f}'.format( self.unitDistance(self.distances[i]))) self.tableWidget.setItem(i, 2, item) i += 1 self.formatTotal() def motionReady(self): if len(self.capturedPoints) > 0 and self.activeMeasuring: return True return False def addPoint(self, pt, button): self.currentDistance = 0 index = len(self.capturedPoints) if index > 0 and pt == self.capturedPoints[index - 1]: # the clicked point is the same as the previous so just ignore it return self.capturedPoints.append(pt) # Add rubber band points canvasCrs = self.canvas.mapSettings().destinationCrs() transform = QgsCoordinateTransform(epsg4326, canvasCrs, QgsProject.instance()) ptCanvas = transform.transform(pt.x(), pt.y()) self.pointRb.addPoint(ptCanvas, True) # If there is more than 1 captured point add it to the table if index > 0: self.saveToLayerButton.setEnabled(True) (distance, startAngle, endAngle) = self.calcParameters(self.capturedPoints[index - 1], self.capturedPoints[index]) self.distances.append(distance) self.insertParams(index, distance, startAngle, endAngle) # Add Rubber Band Line linePts = self.getLinePts(distance, self.capturedPoints[index - 1], self.capturedPoints[index]) self.lineRb.addGeometry(QgsGeometry.fromPolylineXY(linePts), None) self.formatTotal() def endRubberband(self): index = len(self.capturedPoints) if index <= 0: return if index == 1: self.newDialog() return if self.motionReady(): if self.lastMotionPt is not None: self.lastMotionPt = None self.tempRb.reset(QgsWkbTypes.LineGeometry) self.tableWidget.setRowCount(self.tableWidget.rowCount() - 1) self.stop() self.currentDistance = 0 self.formatTotal() def inMotion(self, pt): index = len(self.capturedPoints) if index <= 0: return (self.currentDistance, startAngle, endAngle) = self.calcParameters(self.capturedPoints[index - 1], pt) self.insertParams(index, self.currentDistance, startAngle, endAngle) self.formatTotal() linePts = self.getLinePts(self.currentDistance, self.capturedPoints[index - 1], pt) self.lastMotionPt = pt self.tempRb.setToGeometry(QgsGeometry.fromPolylineXY(linePts), None) def calcParameters(self, pt1, pt2): gline = geod.Inverse(pt1.y(), pt1.x(), pt2.y(), pt2.x()) az2 = (gline['azi2'] + 180) % 360.0 if az2 > 180: az2 = az2 - 360.0 az1 = gline['azi1'] # Check to see if the azimuth values should be in the range or 0 to 360 # The default is -180 to 180 if settings.mtAzMode: if az1 < 0: az1 += 360.0 if az2 < 0: az2 += 360 return (gline['s12'], az1, az2) def getLinePts(self, distance, pt1, pt2): canvasCrs = self.canvas.mapSettings().destinationCrs() transform = QgsCoordinateTransform(epsg4326, canvasCrs, QgsProject.instance()) pt1c = transform.transform(pt1.x(), pt1.y()) pt2c = transform.transform(pt2.x(), pt2.y()) if distance < 10000: return [pt1c, pt2c] gline = geod.InverseLine(pt1.y(), pt1.x(), pt2.y(), pt2.x()) n = int(math.ceil(distance / 10000.0)) if n > 20: n = 20 seglen = distance / n pts = [pt1c] for i in range(1, n): s = seglen * i g = gline.Position( s, Geodesic.LATITUDE | Geodesic.LONGITUDE | Geodesic.LONG_UNROLL) ptc = transform.transform(g['lon2'], g['lat2']) pts.append(ptc) pts.append(pt2c) return pts def saveToLayer(self): units = self.unitDesignator() canvasCrs = self.canvas.mapSettings().destinationCrs() fields = QgsFields() fields.append(QgsField("label", QVariant.String)) fields.append(QgsField("value", QVariant.Double)) fields.append(QgsField("units", QVariant.String)) fields.append(QgsField("heading_to", QVariant.Double)) fields.append(QgsField("heading_from", QVariant.Double)) fields.append(QgsField("total_dist", QVariant.Double)) layer = QgsVectorLayer("LineString?crs={}".format(canvasCrs.authid()), "Measurements", "memory") dp = layer.dataProvider() dp.addAttributes(fields) layer.updateFields() num = len(self.capturedPoints) total = 0.0 for i in range(1, num): (distance, startA, endA) = self.calcParameters(self.capturedPoints[i - 1], self.capturedPoints[i]) total += distance total = self.unitDistance(total) for i in range(1, num): (distance, startA, endA) = self.calcParameters(self.capturedPoints[i - 1], self.capturedPoints[i]) pts = self.getLinePts(distance, self.capturedPoints[i - 1], self.capturedPoints[i]) distance = self.unitDistance(distance) feat = QgsFeature(layer.fields()) feat.setAttribute(0, "{:.2f} {}".format(distance, units)) feat.setAttribute(1, distance) feat.setAttribute(2, units) feat.setAttribute(3, startA) feat.setAttribute(4, endA) feat.setAttribute(5, total) feat.setGeometry(QgsGeometry.fromPolylineXY(pts)) dp.addFeatures([feat]) label = QgsPalLayerSettings() label.fieldName = 'label' try: label.placement = QgsPalLayerSettings.Line except Exception: label.placement = QgsPalLayerSettings.AboveLine format = label.format() format.setColor(settings.measureTextColor) format.setNamedStyle('Bold') label.setFormat(format) labeling = QgsVectorLayerSimpleLabeling(label) layer.setLabeling(labeling) layer.setLabelsEnabled(True) renderer = layer.renderer() renderer.symbol().setColor(settings.measureLineColor) renderer.symbol().setWidth(0.5) layer.updateExtents() QgsProject.instance().addMapLayer(layer) def insertParams(self, position, distance, startAngle, endAngle): if position > self.tableWidget.rowCount(): self.tableWidget.insertRow(position - 1) item = QTableWidgetItem('{:.4f}'.format(self.unitDistance(distance))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableWidget.setItem(position - 1, 2, item) item = QTableWidgetItem('{:.4f}'.format(startAngle)) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableWidget.setItem(position - 1, 0, item) item = QTableWidgetItem('{:.4f}'.format(endAngle)) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableWidget.setItem(position - 1, 1, item) def formatTotal(self): total = self.currentDistance ptcnt = len(self.capturedPoints) if ptcnt >= 2: i = 0 while i < ptcnt - 1: total += self.distances[i] i += 1 self.distanceLineEdit.setText('{:.2f}'.format( self.unitDistance(total))) def updateRBColor(self): self.pointRb.setColor(settings.rubberBandColor) self.lineRb.setColor(settings.rubberBandColor) self.tempRb.setColor(settings.rubberBandColor) def clear(self): self.tableWidget.setRowCount(0) self.capturedPoints = [] self.distances = [] self.activeMeasuring = True self.currentDistance = 0.0 self.distanceLineEdit.setText('') self.pointRb.reset(QgsWkbTypes.PointGeometry) self.lineRb.reset(QgsWkbTypes.LineGeometry) self.tempRb.reset(QgsWkbTypes.LineGeometry) self.saveToLayerButton.setEnabled(False) self.updateRBColor() def unitDistance(self, distance): units = self.unitsComboBox.currentIndex() if units == 0: # kilometers return distance / 1000.0 elif units == 1: # meters return distance elif units == 2: # centimeters return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceCentimeters) elif units == 3: # miles return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceMiles) elif units == 4: # yards return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceYards) elif units == 5: # feet return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet) elif units == 6: # inches return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet) * 12 elif units == 7: # nautical miles return distance * QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceNauticalMiles) def unitDesignator(self): units = self.unitsComboBox.currentIndex() return unitsAbbr[units]
class QgepMapToolConnectNetworkElements(QgsMapTool): """ This map tool connects wastewater networkelements. It works on two lists of layers: source layers with fields with a foreign key to a networkelement target layers which depict networkelements (reaches and network nodes) The tool will snap to source layers first and once one is chosen to a target layer. It will then ask which field(s) should be connected and perform the update on the database """ def __init__(self, iface, action): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.action = action self.rbline = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.rbline.setColor(QColor('#f4530e')) self.rbline.setWidth(3) self.rbmarkers = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.rbmarkers.setColor(QColor('#f4530e')) self.rbmarkers.setIconSize(6) self.source_snapper = QgepAreaSnapper(self.iface.mapCanvas()) self.target_snapper = QgepAreaSnapper(self.iface.mapCanvas()) self.source_feature = QgsFeature() self.rb_source_feature = QgsRubberBand(self.iface.mapCanvas()) self.rb_source_feature.setColor(QColor('#88f49e79')) self.rb_source_feature.setWidth(3) self.target_feature = QgsFeature() self.rb_target_feature = QgsRubberBand(self.iface.mapCanvas()) self.rb_target_feature.setColor(QColor('#f49e79')) self.rb_target_feature.setWidth(3) def activate(self): """ Called by QGIS whenever the tool is activated. """ # A dict of layers # and for each layer the fields to use as foreign key # as well as the possible target layers # Reaches can be connected to reaches and nodes # Catchment areas only to nodes self.network_element_sources = { QgepLayerManager.layer('vw_qgep_reach'): { 'fields': [('rp_to_fk_wastewater_networkelement', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Reach Point To')), ('rp_from_fk_wastewater_networkelement', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Reach Point From'))], 'target_layers': [ QgepLayerManager.layer('vw_wastewater_node'), QgepLayerManager.layer('vw_qgep_reach') ] }, QgepLayerManager.layer('catchment_area'): { 'fields': [('fk_wastewater_networkelement_rw_current', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Rainwater current')), ('fk_wastewater_networkelement_rw_planned', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Rainwater planned')), ('fk_wastewater_networkelement_ww_current', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Wastewater current')), ('fk_wastewater_networkelement_ww_planned', QCoreApplication.translate( 'QgepMapToolConnectNetworkElements', 'Wastewater planned'))], 'target_layers': [QgepLayerManager.layer('vw_wastewater_node')] } } self.setSnapLayers(self.source_snapper, list(self.network_element_sources.keys())) self.reset() self.action.setChecked(True) self.iface.mapCanvas().setCursor(QCursor(Qt.CrossCursor)) def setSnapLayers(self, snapper, layers): config = QgsSnappingConfig() config.setMode(QgsSnappingConfig.AdvancedConfiguration) config.setEnabled(True) for layer in layers: if layer: ils = QgsSnappingConfig.IndividualLayerSettings( True, QgsSnappingConfig.VertexAndSegment, 16, QgsTolerance.Pixels) config.setIndividualLayerSettings(layer, ils) snapper.setConfig(config) def canvasMoveEvent(self, event): """ When the mouse moves, update the rubberbands. """ pt = event.originalMapPoint() snap_match = self.snapper.snapToMap(pt) if snap_match.isValid(): if snap_match.type() != QgsPointLocator.Area: pt = snap_match.point() self.matchpoint = pt if self.source_match: # There is already a source feature : snap to target feature # candidates if self.target_feature.id() != snap_match.featureId(): self.target_feature = self.get_feature_for_match( snap_match) self.rb_target_feature.setToGeometry( self.target_feature.geometry(), snap_match.layer()) self.rb_target_feature.show() self.rbmarkers.movePoint(pt) else: # Snapped to source feature, update source feature rubber band # and target layer snapper if self.source_feature.id() != snap_match.featureId(): self.source_feature = self.get_feature_for_match( snap_match) self.rb_source_feature.setToGeometry( self.source_feature.geometry(), snap_match.layer()) self.setSnapLayers( self.target_snapper, self.network_element_sources[ snap_match.layer()]['target_layers']) self.rb_source_feature.show() self.rbmarkers.movePoint(pt, 0) self.rbmarkers.show() else: self.rbmarkers.hide() if self.source_match: self.rb_target_feature.hide() else: self.rb_source_feature.hide() self.rbline.movePoint(pt) self.snapresult = snap_match def canvasReleaseEvent(self, event): """ On a click update the rubberbands and the snapping results if it's a left click. Reset if it's a right click. """ if event.button() == Qt.LeftButton: if self.snapresult.isValid(): if self.source_match: self.connect_features(self.source_match, self.snapresult) else: self.rbline.show() self.rbline.addPoint(self.matchpoint) self.source_match = self.snapresult self.snapper = self.target_snapper else: self.reset() def deactivate(self): """ Called by QGIS whenever this tool is deactivated. """ self.reset() self.action.setChecked(False) def reset(self): """ Resets the tool to a pristine state """ self.source_match = None self.rbline.hide() self.rbline.reset() self.rbmarkers.hide() self.rbmarkers.reset(QgsWkbTypes.PointGeometry) self.rbmarkers.addPoint(QgsPointXY()) self.snapresult = None self.source_match = None self.snapper = self.source_snapper self.source_feature = QgsFeature() self.target_feature = QgsFeature() self.rb_source_feature.reset() self.rb_target_feature.reset() def get_feature_for_match(self, match): """ Get the feature for a snapping result @param match: The QgsPointLocator.SnapMatch object @return: A feature """ return next(match.layer().getFeatures(QgsFeatureRequest().setFilterFid( match.featureId()))) def connect_features(self, source, target): """ Connects the source feature with the target feature. @param source: A QgsPointLocator.Match object. Its foreign key will be updated. A dialog will be opened which asks the user for which foreign key(s) he wants to update. @param target: A QgsPointLocator.Match object. This feature will be used as link target. Its obj_id attribute will be used as primary key. """ dlg = QDialog(self.iface.mainWindow()) dlg.setWindowTitle(self.tr('Select properties to connect')) dlg.setLayout(QFormLayout()) properties = list() for prop in self.network_element_sources[source.layer()]['fields']: cbx = QCheckBox(prop[1]) cbx.setObjectName(prop[0]) properties.append(cbx) dlg.layout().addWidget(cbx) btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) dlg.layout().addWidget(btn_box) btn_box.accepted.connect(dlg.accept) btn_box.rejected.connect(dlg.reject) source_feature = self.get_feature_for_match(source) target_feature = self.get_feature_for_match(target) if dlg.exec_(): for cbx in properties: if cbx.isChecked(): source_feature[cbx.objectName()] = target_feature['obj_id'] if not source.layer().isEditable(): self.iface.messageBar().pushMessage( 'QGEP', self.tr('Layer "{layername}" is not in edit mode').format( layername=source.layer().name()), Qgis.Warning, 5) elif source.layer().updateFeature(source_feature): self.iface.messageBar().pushMessage( 'QGEP', self.tr('Connected {} to {}').format( source_feature['identifier'], target_feature['identifier']), Qgis.Info, 5) else: self.iface.messageBar().pushMessage( 'QGEP', self.tr('Error connecting features'), Qgis.Warning, 5) self.reset()
def __init__(self, iface): self.iface = iface self.mapCanvas = iface.mapCanvas() QgsMapTool.__init__(self, self.mapCanvas) self.settings = MySettings() self.rubber = QgsRubberBand(self.mapCanvas, QGis.Point)
def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionLegend.triggered.connect(self.updatelegend) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.actionSettings.toggled.connect( self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel( "User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.connectButtons() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.selectdataentry) self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.selectioncleared.connect(self.clearselection) RoamEvents.editgeometry.connect(self.addforedit) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.highlightselection) RoamEvents.selectionchanged.connect(self.showInfoResults) GPS.gpspostion.connect(self.updatecanvasfromgps) GPS.firstfix.connect(self.gpsfirstfix) GPS.gpsdisconnected.connect(self.gpsdisconnected) self.lastgpsposition = None self.marker = GPSMarker(self.canvas) self.marker.hide() self.legendpage.showmap.connect(self.showmap) self.editfeaturestack = [] self.currentselection = {}
class QgepMapTool(QgsMapTool): """ Base class for all the map tools """ highlightedPoints = [] logger = logging.getLogger(__name__) snapper = None def __init__(self, iface: QgisInterface, button, network_analyzer: QgepGraphManager = None): QgsMapTool.__init__(self, iface.mapCanvas()) self.canvas = iface.mapCanvas() self.cursor = QCursor(Qt.CrossCursor) self.button = button self.msgBar = iface.messageBar() self.network_analyzer = network_analyzer settings = QSettings() current_profile_color = settings.value("/QGEP/CurrentProfileColor", '#FF9500') self.rubberBand = QgsRubberBand(self.canvas) self.rubberBand.setColor(QColor(current_profile_color)) self.rubberBand.setWidth(3) def activate(self): """ Gets called when the tool is activated """ QgsMapTool.activate(self) self.canvas.setCursor(self.cursor) self.button.setChecked(True) def deactivate(self): """ Gets called whenever the tool is deactivated directly or indirectly """ QgsMapTool.deactivate(self) self.button.setChecked(False) # pylint: disable=no-self-use def isZoomTool(self): """ Will return if this is a zoom tool """ return False def setCursor(self, cursor): """ Set the cursor for this maptool """ self.cursor = QCursor(cursor) # =========================================================================== # Events # =========================================================================== def canvasReleaseEvent(self, event): """ Issues rightClicked and leftClicked events """ if event.button() == Qt.RightButton: self.rightClicked(event) else: self.leftClicked(event) def canvasDoubleClickEvent(self, event): """ Forwards to doubleClicked """ try: self.doubleClicked(event) except AttributeError: pass # =========================================================================== # Snapping # =========================================================================== def init_snapper(self): """ Initialize snapper """ if not self.snapper: self.node_layer = self.network_analyzer.getNodeLayer() self.snapper = QgsMapCanvasSnappingUtils(self.canvas) config = QgsSnappingConfig() config.setMode(QgsSnappingConfig.AdvancedConfiguration) config.setEnabled(True) ils = QgsSnappingConfig.IndividualLayerSettings( True, QgsSnappingConfig.VertexAndSegment, 16, QgsTolerance.Pixels) config.setIndividualLayerSettings(self.node_layer, ils) self.snapper.setConfig(config) def snap_point(self, event, show_menu: bool = True) -> QgsPointLocator.Match: """ Snap to a point on this network :param event: A QMouseEvent :param show_menu: determines if a menu shall be shown on a map if several matches are available """ clicked_point = event.pos() if not self.snapper: self.init_snapper() class CounterMatchFilter(QgsPointLocator.MatchFilter): def __init__(self): super().__init__() self.matches = list() def acceptMatch(self, match): self.matches.append(match) return True match_filter = CounterMatchFilter() match = self.snapper.snapToMap(clicked_point, match_filter) if not match.isValid() or len(match_filter.matches) == 1: return match elif len(match_filter.matches) > 1: point_ids = [match.featureId() for match in match_filter.matches] node_features = self.network_analyzer.getFeaturesById( self.network_analyzer.getNodeLayer(), point_ids) # Filter wastewater nodes filtered_features = { fid: node_features.featureById(fid) for fid in node_features.asDict() if node_features.attrAsUnicode(node_features.featureById(fid), 'type') == 'wastewater_node' } # Only one wastewater node left: return this if len(filtered_features) == 1: matches = (match for match in match_filter.matches if match.featureId() == next( iter(filtered_features.keys()))) return next(matches) # Still not sure which point to take? # Are there no wastewater nodes filtered? Let the user choose from the reach points if not filtered_features: filtered_features = node_features.asDict() # Ask the user which point he wants to use if not show_menu: return QgsPointLocator.Match() actions = dict() menu = QMenu(self.canvas) for _, feature in list(filtered_features.items()): try: title = feature.attribute( 'description') + " (" + feature.attribute( 'obj_id') + ")" except TypeError: title = " (" + feature.attribute('obj_id') + ")" action = QAction(title, menu) actions[action] = match menu.addAction(action) clicked_action = menu.exec_(self.canvas.mapToGlobal(event.pos())) if clicked_action is not None: return actions[clicked_action] return QgsPointLocator.Match()
class PipelinePlanner: """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: QgsInterface """ # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale self.addPipelinePoint = QgsMapToolEmitPoint(self.canvas) self.rbPipeline = QgsRubberBand(self.canvas) self.rbPipeline.setColor(Qt.red) self.rbPipeline.setWidth(4) locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'PipelinePlanner_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Pipeline Planner') # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None self.dlg = PipelinePlannerDialog() self.dlg.tblImpacts.setColumnWidth(1, 75) self.dlg.tblImpacts.setColumnWidth(2, 250) self.dlg.tblImpacts.setColumnWidth(3, 75) # 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('PipelinePlanner', 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: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToVectorMenu(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/pipeline_planner/icon.png' self.add_action(icon_path, text=self.tr(u'Pipeline Planner'), callback=self.run, parent=self.iface.mainWindow()) # will be set False in run() self.first_start = True self.addPipelinePoint.canvasClicked.connect(self.evaluatePipeline) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginVectorMenu(self.tr(u'&Pipeline Planner'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" self.canvas.setMapTool(self.addPipelinePoint) def evaluatePipeline(self, point, button): if button == Qt.LeftButton: self.rbPipeline.addPoint(point) self.rbPipeline.show() elif button == Qt.RightButton: pipeline = self.rbPipeline.asGeometry() self.dlg.tblImpacts.setRowCount(0) lyrRaptor = QgsProject.instance().mapLayersByName( "Raptor Buffer")[0] raptors = lyrRaptor.getFeatures(pipeline.boundingBox()) for raptor in raptors: valConstraint = raptor.attribute("recentspec") valID = raptor.attribute("Nest_ID") valStatus = raptor.attribute("recentstat") valDistance = pipeline.distance(raptor.geometry().centroid()) if raptor.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) self.dlg.tblImpacts.setItem( row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem( row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) lyrEagle = QgsProject.instance().mapLayersByName("BAEA Buffer")[0] eagles = lyrEagle.getFeatures(pipeline.boundingBox()) for eagle in eagles: valConstraint = "BAEA Nest" valID = eagle.attribute("nest_id") valStatus = eagle.attribute("status") valDistance = pipeline.distance(eagle.geometry().centroid()) if eagle.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) self.dlg.tblImpacts.setItem( row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem( row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) lyrBUOWL = QgsProject.instance().mapLayersByName("BUOWL Buffer")[0] buowls = lyrBUOWL.getFeatures(pipeline.boundingBox()) for buowl in buowls: valConstraint = "BUOWL Habitat" valID = buowl.attribute("habitat_id") valStatus = buowl.attribute("recentstat") valDistance = pipeline.distance(buowl.geometry().buffer( -0.001, 5)) if buowl.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) self.dlg.tblImpacts.setItem( row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem( row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) self.dlg.show() self.rbPipeline.reset()
class QgepProfileMapTool(QgepMapTool): """ The map tool used for PROFILE Allows to find the shortest path between several nodes. """ profileChanged = pyqtSignal(object) profile = QgepProfile() segmentOffset = 0 selectedPathPoints = [] pathPolyline = [] def __init__(self, canvas, button, network_analyzer): QgepMapTool.__init__(self, canvas, button, network_analyzer) settings = QSettings() helper_line_color = settings.value("/QGEP/HelperLineColor", '#FFD900') highlight_color = settings.value("/QGEP/HighlightColor", '#40FF40') # Init rubberband to visualize current status self.rbHelperLine = QgsRubberBand(self.canvas) self.rbHelperLine.setColor(QColor(helper_line_color)) self.rbHelperLine.setWidth(2) self.rbHighlight = QgsRubberBand(self.canvas) self.rbHighlight.setColor(QColor(highlight_color)) self.rbHighlight.setWidth(5) self.profile.setRubberband(self.rbHighlight) self.saveTool = None def setActive(self): """ activates this map tool """ self.saveTool = self.canvas.mapTool() self.canvas.setMapTool(self) def deactivate(self): """ Called whenever this map tool is deactivated. Used to clean up code """ QgepMapTool.deactivate(self) self.rubberBand.reset() self.rbHelperLine.reset() self.selectedPathPoints = [] self.pathPolyline = [] def findPath(self, start_point, end_point): """ Tries to find the shortest path between pStart and pEnd. If it finds a path: * The path is visualized with a QgsRubberband * The profile plot is updated to represent the current path @param start_point: The id of the start point of the path @param end_point: The id of the end point of the path """ QApplication.setOverrideCursor(Qt.WaitCursor) # try: (vertices, edges) = self.network_analyzer.shortestPath(start_point, end_point) self.appendProfile(vertices, edges) # except: # pass QApplication.restoreOverrideCursor() if len(vertices) > 0: return True else: return False # pylint: disable=too-many-locals def appendProfile(self, vertices, edges): """ Appends to the current profile @param vertices: A collection of vertices to append @param edges: A collection of edges which connect the vertices """ self.logger.debug('Append profile') self.logger.info(' * ' + repr(len(vertices)) + ' vertices') for v in vertices: self.logger.debug(' *' + repr(v)) self.logger.info(' * ' + repr(len(edges)) + ' edges') for e in edges: self.logger.debug(' *' + repr(e)) # Fetch all the needed edges in one batch edge_layer = self.network_analyzer.getEdgeLayer() edge_ids = [edge['feature'] for p1, p2, edge in edges] edge_features = self.network_analyzer.getFeaturesById( edge_layer, edge_ids) # We need some additional nodes, where we need to interpolate... interpolate_nodes_from = [ edge_features.attrAsUnicode(feat, 'from_obj_id_interpolate') for feat in list(edge_features.asDict().values()) ] interpolate_nodes_to = [ edge_features.attrAsUnicode(feat, 'to_obj_id_interpolate') for feat in list(edge_features.asDict().values()) ] additional_ids = [ self.network_analyzer.vertexIds[node] for node in interpolate_nodes_from ] additional_ids += [ self.network_analyzer.vertexIds[node] for node in interpolate_nodes_to ] # Now, fetch the nodes we need node_layer = self.network_analyzer.getNodeLayer() node_ids = vertices + additional_ids node_features = self.network_analyzer.getFeaturesById( node_layer, node_ids) if len(vertices) > 1: self.rubberBand.reset() elem = QgepProfileNodeElement(vertices[0], node_features, 0) self.profile.addElement(vertices[0], elem) for p1, p2, edge in edges: from_offset = self.segmentOffset to_offset = self.segmentOffset + edge['weight'] if 'reach' == edge['objType']: if self.profile.hasElement(edge['baseFeature']): self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], node_features, edge_features, from_offset, to_offset) else: elem = QgepProfileReachElement(p1, p2, edge['feature'], node_features, edge_features, from_offset, to_offset) self.profile.addElement(elem.obj_id, elem) elif 'special_structure' == edge['objType']: if self.profile.hasElement(edge['baseFeature']): self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], node_features, edge_features, from_offset, to_offset) else: elem = QgepProfileSpecialStructureElement( p1, p2, edge['feature'], node_features, edge_features, from_offset, to_offset) self.profile.addElement(elem.obj_id, elem) elem = QgepProfileNodeElement(p2, node_features, to_offset) self.profile.addElement(p2, elem) self.segmentOffset = to_offset self.profileChanged.emit(self.profile) # Create rubberband geometry for featId in edge_ids: self.pathPolyline.extend( edge_features[featId].geometry().asPolyline()) self.rubberBand.addGeometry( QgsGeometry.fromPolylineXY(self.pathPolyline), node_layer) self.profileChanged.emit(self.profile) return True else: return False def canvasMoveEvent(self, event): """ Mouse moved: update helper line @param event: The mouse event with coordinates and all """ if self.selectedPathPoints: self.rbHelperLine.reset() for point in self.selectedPathPoints: self.rbHelperLine.addPoint(point[1]) mouse_pos = self.canvas.getCoordinateTransform() \ .toMapCoordinates(event.pos().x(), event.pos().y()) self.rbHelperLine.addPoint(mouse_pos) def rightClicked(self, _): """ Cancel any ongoing path selection @param event: The mouse event with coordinates and all """ self.selectedPathPoints = [] self.pathPolyline = [] self.rbHelperLine.reset() self.profile.reset() self.segmentOffset = 0 def leftClicked(self, event): """ Select startpoint / intermediate point / endpoint @param event: The mouse event with coordinates and all """ match = self.snap_point(event) if match.isValid(): if self.selectedPathPoints: pf = self.findPath(self.selectedPathPoints[-1][0], match.featureId()) if pf: self.selectedPathPoints.append( (match.featureId(), QgsPointXY(match.point()))) else: msg = self.msgBar.createMessage('No path found') self.msgBar.pushWidget(msg, Qgis.Info) else: self.selectedPathPoints.append( (match.featureId(), QgsPointXY(match.point())))
class DivisionFusion: """QGIS Plugin Implementation.""" def __init__(self, iface, ACA): """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: QgsInterface """ # Save reference to the QGIS interface self.iface = iface self.CFG = None self.UTI = None self.DFS = None self.DBJ = None self.ELM = None self.ACA = ACA self.TPG = None # 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', 'DivisionFusion_{}.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) # Create the dialog (after translation) and keep reference self.dlg = DivisionFusionDialog(parent=iface.mainWindow(), DIV=self) # Declare instance attributes ''' self.actions = [] self.menu = self.tr(u'&DivisionFusion') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'DivisionFusion') self.toolbar.setObjectName(u'DivisionFusion') ''' self.eventos = EventoDivision(iface.mapCanvas(), self, iface.cadDockWidget()) iface.mapCanvas().setMapTool(self.eventos) self.VentanaAreas = VentanaAreas(self) self.VentanaFusion = VentanaFusionV3(iface, self) self.VentanaClaves = VentanaClavesV3(iface, self) self.rubberMarca = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.rubberMarca.setFillColor(QColor(255, 255, 0, 12)) self.rubberMarca.setStrokeColor(QColor(255, 150, 0, 255)) self.rubberMarca.setWidth(2) self.listaNuevosPredios = [] self.cargoPredio = False self.listaColores = [] self.rubbersAreas = [] self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(False) self.dlg.btnDeshacerTodo.setEnabled(False) self.dlg.btnCancelarSub.setEnabled(False) self.dlg.btnDeshacerCortes.setEnabled(False) self.dlg.btnLlamarCalcular.setEnabled(False) self.dlg.btnFusionar.clicked.connect(self.preguntarFusion) self.dlg.btnCargarPredio.clicked.connect(self.pasarAModoDivision) self.dlg.btnConfirmarCortes.clicked.connect(self.confirmarCortes) self.dlg.btnDibujarCortes.clicked.connect(self.encenderModoDividir) self.dlg.btnEliminarCortes.clicked.connect(self.encenderModoEliminar) self.dlg.btnApagarHerramientas.clicked.connect(self.apagarHerramientas) self.dlg.btnDeshacerTodo.clicked.connect(self.rollBack) self.dlg.btnCancelarSub.clicked.connect(self.cancelarSubdivision) self.dlg.btnDeshacerCortes.clicked.connect(self.vaciarLineasCorte) self.dlg.btnLlamarCalcular.clicked.connect(self.irAreas) self.dlg.btnEditarCortes.clicked.connect(self.encenderModoEditar) self.dlg.btnDeshacerTodo.hide() self.enClaves = False self.enSubdivision = False self.enFusion = False self.headers = {'Content-Type': 'application/json'} self.geomsAreas = [] # 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('DivisionFusion', 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/DivisionFusion/icon.png' self.add_action(icon_path, text=self.tr(u'DivisionFusion'), callback=self.run, parent=self.iface.mainWindow()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&DivisionFusion'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar def run(self): """Run method that performs all the real work""" # show the dialog for x in iface.mapNavToolToolBar().actions(): if x.objectName() == 'mActionPan': x.trigger() for x in iface.advancedDigitizeToolBar().actions(): if x.objectName() == 'mEnableAction': x.trigger() self.dlg.show() # Run the dialog event loop iface.mapCanvas().setMapTool(self.eventos) result = self.dlg.exec_() # See if OK was pressed self.dlg.btnFusionar.setEnabled(True) self.dlg.comboPredios.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(True) self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(False) self.dlg.btnDeshacerTodo.setEnabled(False) # llena los predios en el combo self.dlg.comboPredios.clear() lista = [] capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) if capaPredios is None: return # lista de features for predio in capaPredios.getFeatures(): lista.append(str(predio['clave'])) lista.sort() for elemento in lista: self.dlg.comboPredios.addItem(elemento) if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass '''def consumirPredios(self): listaPredio =[] if iface.activeLayer() != None: seleccion = self.iface.activeLayer().selectedFeatures() for i in seleccion: self.id = self.consumeWSGeneral(url_cons = self.CFG.url_AU_getAllfactures + str(i['id']) ) if not self.id: return listaPredio.append(self.id) print(listaPredio)''' #------------------------------------------------------------------------------ #Preguntamos si quiere fusionar def preguntarFusion(self): listaPredio = [] #self.consumirPredios() if iface.activeLayer() != None: seleccion = self.iface.activeLayer().selectedFeatures() #self.VentanaFusion.dlg.close() if self.validarCuentaSeleccion(): #Si la seleccion es valida for i in seleccion: self.id = self.consumeWSGeneral( url_cons=self.CFG.url_AU_getAllfactures + str(i['id'])) if not self.id: return listaPredio.append(self.id) #print(listaPredio) self.enFusion = True #self.VentanaFusion.dlg.show() #self.VentanaFusion.llenarTablaComp(listaPredio[0], listaPredio[1]) self.dlg.btnCargarPredio.setEnabled(False) #else: #self.UTI.mostrarAlerta('La fusion requiere la seleccion de exactamente 2 predios contiguos', QMessageBox().Critical, 'Error de fusion') #------------------------------------------------------------------ #Validamosla seleccion def validarCuentaSeleccion(self): seleccion = self.iface.activeLayer().selectedFeatures() for i in seleccion: if str(i['id']) == '': self.UTI.mostrarAlerta( 'El predio ' + str(i['clave']) + ' no se puede fusionar, guarde los cambios antes de continuar', QMessageBox().Critical, 'Error de fusion') return False if len(seleccion) != 2: #Cuando tenemos seleccionados no 2 elementos self.UTI.mostrarAlerta( 'La fusion requiere la seleccion de exactamente 2 predios contiguos', QMessageBox().Critical, 'Error de fusion') return False else: if not self.validarContiguedad(): self.UTI.mostrarAlerta( 'Los predios seleccionados no son contiguos', QMessageBox().Critical, 'Error de fusion') return False else: return True #----------------------------------------------------------------------------- def validarContiguedad(self): #Aqui checamos si dos predios son contiguos seleccion = self.iface.activeLayer().selectedFeatures() pred1 = seleccion[0].geometry().buffer(0.0000001, 1) pred2 = seleccion[1].geometry().buffer(0.0000001, 1) #Checamos que el area de interseccion sea un valor considerable area = pred1.intersection(pred2).area() return area > 0.0000000001 #----------------------------------------------------------------------------------- def fusionarPredios(self, eleccion): #Aqui fusionamos los predios #OBtener las capas capaManzana = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('manzana')) capaPuntos = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.num')) capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) capaConstru = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('construcciones')) capaCondH = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('horizontales.geom')) #Puntos y eleccion de victima seleccion = self.iface.activeLayer().selectedFeatures() if seleccion == None: self.pluginFD.UTI.mostrarAlerta( 'Debes seleccionar un predio destino', QMessageBox().Critical, 'Error de seleccion') return listaPuntos = [None, None] #Definimos el predio 'victima if eleccion == 0: victima = 1 else: victima = 0 #eliminamos el predio no elegido self.eliminarNoElegido(seleccion[victima]) #Eliminar punto del predio no elegido for punto in capaPuntos.getFeatures(): if punto.geometry().intersects(seleccion[victima].geometry( )): #Bsucamos el punto del predio victima capaPuntos.startEditing() capaPuntos.dataProvider().deleteFeatures([punto.id()]) capaPuntos.triggerRepaint() capaPuntos.commitChanges() break #Generar geometria del predio fusionado rango = len(seleccion) geomFusion = seleccion[0].geometry() featFusion = QgsFeature() capaPredios.startEditing() #Generar geometria del predio fusionado for i in range(0, rango): self.iface.activeLayer().dataProvider().deleteFeatures( [seleccion[i].id()]) geomFusion = geomFusion.combine(seleccion[i].geometry()) #self.geom listaFinal = [] listaPrimera = [] featFusion.setGeometry(geomFusion) #Renombrar construcciones cuentaConstruccion = 1 capaConstru.startEditing() #--------Renombrar construcciones---- for construccion in capaConstru.getFeatures(): geomConstru = construccion.geometry() if geomConstru.buffer(-0.0000001, 1).intersects( geomFusion ): #Sacamos las construcciones dentro del predio fusionado listaPrimera.append(construccion) else: if self.contarIntegraciones( geomConstru.buffer(-0.0000001, 1), 'predios.geom' ) == 0: #Obtenemos los aleros del predio fusionado if geomConstru.buffer( 0.0000001, 1).intersection(geomFusion).area() > 0.000000001: listaPrimera.append(construccion) for construccion in listaPrimera: geomConstru = construccion.geometry() seIncluye = True for condominio in capaCondH.getFeatures(): geomHori = condominio.geometry() if geomConstru.buffer(-0.0000001, 1).intersects(geomHori): seIncluye = False break if seIncluye: listaFinal.append(construccion) supConst = 0 #Renombramos ls volumenes for construccion in listaFinal: geomConstru = construccion.geometry() construccion['nom_volumen'] = 'V' + str(cuentaConstruccion) niveles = construccion['num_niveles'] if niveles <= 0: niveles = 1 capaConstru.updateFeature(construccion) cuentaConstruccion += 1 supConst += (geomConstru.area() * niveles) capaConstru.commitChanges() #---------------------------------------------- #Estableer atributos del predio fusionado idx1 = capaPredios.fields().lookupField('sup_terr') idx2 = capaPredios.fields().lookupField('sup_contruccion') attr = seleccion[eleccion].attributes() attr[idx1] = geomFusion.area() attr[idx2] = supConst featFusion.setAttributes(attr) capaPredios.updateFeature(featFusion) capaPredios.dataProvider().addFeatures([featFusion]) capaPredios.triggerRepaint() capaPredios.commitChanges() self.UTI.mostrarAlerta('Fusion completada con exito', QMessageBox().Information, 'Fusion de predios') self.enFusion = False self.dlg.close() #----------------------------------------------------------------------------------- #Aqui contmaos cuantas geometrias de una capa toca una geomtrias especifica def contarIntegraciones(self, geometria, nombreCapa): capa = QgsProject.instance().mapLayersByName(nombreCapa)[0] cuenta = 0 for feat in capa.getFeatures(): if geometria.intersects(feat.geometry()): cuenta += 1 return cuenta #--------------------------------------------------------------------------- #Poinemos en lista de eliminados el predio no elegido def eliminarNoElegido(self, feat): campos = {} campos['wkt'] = feat.geometry().asWkt() campos['srid'] = 32614 campos['tabla'] = 'e_predio' atributos = {} capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) nombresAtrbutos = capaPredios.fields() nombres = [campo.name() for campo in nombresAtrbutos] for x in range(0, len(nombres)): atributo = feat.attributes()[x] if str(feat.attributes()[x]) == "NULL": atributo = None atributos[str(nombres[x])] = atributo campos['attr'] = atributos campos['nuevo'] = False campos['eliminado'] = True listaTemp = QSettings().value('listaEliminada') listaTemp.append(campos) QSettings().setValue('listaEliminada', listaTemp) #-------------------------------------------------------------------------- #Activamos el modo de division def pasarAModoDivision(self, predio): #clave = self.dlg.comboPredios.currentText() #Obtenemos la clave del predio a editar clave = predio if clave == '': self.UTI.mostrarAlerta( 'Primero debes cargar una manzana de la seccion de consulta', QMessageBox().Critical, 'Error de cargado de predio') return capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) #capaPredios.setReadOnly(False) #capaPredios.startEditing() self.predioEnDivision = None for predio in capaPredios.getFeatures( ): #Obtenemos el feature a dividr con base en la clave elegida if predio.attributes()[0] == clave: self.predioEnDivision = predio break if self.predioEnDivision != None: self.atributosAHeredar = self.predioEnDivision.attributes( ) #Obtenemos los atributos a heredar self.atributosAHeredar[1] = None #Ponemos le id como vacio self.rubberMarca.reset( QgsWkbTypes.PolygonGeometry) #Borramos la geometria amarillita self.UTI.mostrarAlerta( "Dibuja las lineas de corte sobre el predio indicado.\nRecuerda que los cortes no pueden estar sobre construcciones o condiminios.\nAsegurate que las lineas atraviesen el predio por completo\nNOTA: Las lineas solo afectaran al predio seleccionado.", QMessageBox().Information, "Subdivision de predios") self.cargoPredio = True self.encenderModoDividir() #Encendemos modo dividir # marca de amarillo el poligono del predio a subdividir self.geomEnDivision = self.predioEnDivision.geometry() self.pintarAreaPredioSubdiv() # zoom al predio a subdividir geometria = self.geomEnDivision bbox = geometria.boundingBox() iface.mapCanvas().setExtent(bbox) iface.mapCanvas().refresh() # comportamiento de botones self.dlg.btnFusionar.setEnabled(False) self.dlg.btnCancelarSub.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(False) self.dlg.comboPredios.setEnabled(False) self.dlg.comboPredios.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(True) self.dlg.btnDeshacerTodo.setEnabled(True) self.dlg.btnDeshacerCortes.setEnabled(True) self.dlg.btnLlamarCalcular.setEnabled(True) self.enSubdivision = True else: self.UTI.mostrarAlerta('El predio no fue encontrado', QMessageBox().Critical, 'Error de cargado de predio') #------------------------------------------------------------------------- def cancelarSubdivision(self): mensaje = "El modo de division se apagara, el progreso se perdera\nDeseas continuar?" respuesta = QMessageBox.question(iface.mainWindow(), "Cancelar subdivision", mensaje, QMessageBox.Yes, QMessageBox.No) #Si el usuario acepta.... if respuesta == QMessageBox.Yes: self.vaciarRubbers() self.predioEnDivision = None self.geomEnDivision = None self.modoDividir = False self.modoEliminar = False self.apagarHerramientas() self.dlg.btnCancelarSub.setEnabled(False) self.dlg.btnCargarPredio.setEnabled(True) self.dlg.comboPredios.setEnabled(True) self.dlg.btnFusionar.setEnabled(True) self.dlg.btnConfirmarCortes.setEnabled(False) self.dlg.btnDeshacerCortes.setEnabled(False) self.dlg.btnLlamarCalcular.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnDeshacerTodo.setEnabled(False) self.enSubdivision = False #----------------------------------------------------------------------------------- #-------------------------------------------- def confirmarCortes(self): #Aqui cehcamos que los cortes esten en orden print(self.eventos.relaciones) #cuentaCortes = 0 #rango = corte rango = len(self.eventos.relaciones) - 1 #geoTemp = geo geoTemp = QgsGeometry.fromWkt(self.geomEnDivision.asWkt()) print('------------------------------') print(geoTemp) print('------------------------------') cuentaSalida = self.subdividirPredio( geoTemp, True ) - 1 #Aqui enviamos una geomtria temporal, para ven en cuantos cortes quedara print(cuentaSalida) if cuentaSalida >= 2: listaNoTocar = [] capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) capaCondH = QgsProject.instance().mapLayersByName( 'horizontales.geom')[0] capaCondV = QgsProject.instance().mapLayersByName('verticales')[0] capaConstru = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('construcciones')) #Obtenemos los features que no deben tocarse for feat in capaConstru.getFeatures(): geom = feat.geometry().buffer(-0.0000002, 1) if geom.intersects(self.geomEnDivision): listaNoTocar.append(geom) for feat in capaCondH.getFeatures(): geom = feat.geometry().buffer(-0.0000002, 1) if geom.intersects(self.geomEnDivision): listaNoTocar.append(geom) for feat in capaCondV.getFeatures(): geom = feat.geometry().buffer(-0.0000002, 1) if geom.intersects(self.geomEnDivision): listaNoTocar.append(geom) bandera = True #Aqui checamos que cada linea no toque lo no tocable for i in range(0, rango): for comp in listaNoTocar: geom = self.eventos.relaciones[i].geom if geom != None: if geom.buffer(0.0000001, 1).intersects(comp): bandera = False self.eventos.relaciones[i].rubber.setStrokeColor( QColor(255, 0, 0, 255)) else: self.eventos.relaciones[i].rubber.setStrokeColor( QColor(0, 61, 240, 255)) iface.mapCanvas().refresh() if bandera: #Si todo esta en orden self.eventos.rubberPunto.reset(QgsWkbTypes.PointGeometry) self.apagarHerramientas() #mostramos mensaje de confirmacion mensaje = "La cantidad de predios que quedaran como resultado, es de: " + str( cuentaSalida) + "\nDeseas continua?" respuesta = QMessageBox.question( iface.mainWindow(), "Nota de subdivision de predio", mensaje, QMessageBox.Yes, QMessageBox.No) #Si el usuario acepta.... if respuesta == QMessageBox.Yes: self.subdividirPredio(self.geomEnDivision, False) self.rubberMarca.reset( QgsWkbTypes.PolygonGeometry) #Quitamos lo amarillito for i in range(0, rango): self.eventos.relaciones[i].rubber.reset( QgsWkbTypes.LineGeometry) self.eventos.relaciones[i].vaciarMarcadores() self.eventos.recargarRelaciones() capaPredios.startEditing() capaPredios.dataProvider().deleteFeatures( [self.predioEnDivision.id()]) capaPredios.triggerRepaint() capaPredios.commitChanges() self.VentanaAreas.close() self.limpiarAreas() self.vaciarRubbers() self.UTI.mostrarAlerta( "La division ha sido realizada con exito\nLos cambios se guardaran hasta que asignes las claves.", QMessageBox().Information, "Subdivision completa, Parte 1 de 2") self.irAClaves( ) #Mostramos la ventana que llena las claves iface.actionSelect().trigger() else: self.UTI.mostrarAlerta( "Las lineas de division no deben atravesar construcciones ni condominios\nLas lineas rojas presentan un corte invalido", QMessageBox().Critical, "Error en subdivision") else: self.UTI.mostrarAlerta( "Primero debes dibujar las lineas de corte\nAsegurate que las lineas atraviesen por completo el predio", QMessageBox().Critical, "Error en subdivision") #print(cuentaSalida) ################################################################################## def vaciarLineasCorte(self): rango = len(self.eventos.relaciones) - 1 for i in range(0, rango): self.eventos.relaciones[i].rubber.reset(QgsWkbTypes.LineGeometry) self.eventos.relaciones[i].vaciarMarcadores() self.eventos.recargarRelaciones() #------------------------------------------------------------------------------------- def subdividirPredio(self, geometria, modoPre): #Subdividir capaHori = QgsProject.instance().mapLayersByName( 'horizontales.geom')[0] capaPredio = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) capaVert = QgsProject.instance().mapLayersByName('verticales')[0] self.listaNuevosPredios = [] self.geomsAreas = [] listaParam = [] #La lista que llega al fileteo #rango = corte rango = len(self.eventos.relaciones) - 1 #print('**********************************************') #print(self.eventos.relaciones) #print(rango) #print('**********************************************') for i in range(0, rango): geom = self.eventos.relaciones[i].geom print('-----------------*****------------------------') print(self.eventos.relaciones[i]) print(geom) print('-----------------*****------------------------') if geom != None: listaParam.append( geom.asPolyline()) #Generamos los polyline van a partir #print('aaaaaaaaaaa', listaParam) salida = self.filetear( geometria, listaParam) #Mandamos filetear el poligono con las lineas if modoPre: #Si es modoPre, es solo para visaulizar cuantos poligonos quedarian... for cadaUno in salida: self.geomsAreas.append(cadaUno) return len(salida) else: #Si no, efectuamos realmente el corte for cadaUno in salida: if cadaUno.isEmpty(): continue nuevoFeat = QgsFeature() nuevoFeat.setGeometry(cadaUno) #Agregamos cada predio a la capa y le ponemos sus atributos self.asignarAtributos(nuevoFeat) capaPredio.startEditing() capaPredio.dataProvider().addFeatures([nuevoFeat]) capaPredio.triggerRepaint() capaPredio.commitChanges() self.listaNuevosPredios.append(nuevoFeat.geometry().asWkt()) self.apagarHerramientas() self.dlg.btnCargarPredio.setEnabled(True) ################################################################################## #Metodo para filetear los predios con lineas def filetear(self, poligono, lineas): listaActuales = [] #Lista de las geometrias en espera de ser cortadas listaActuales.append( poligono) #Agregamos el poligono a cortar en la lista de espera listaSiguiente = [ poligono ] #Agregamos le poligono a cortar en la lista de la siguiente interacion for linea in lineas: #Iteramos cada linea de corte listaActuales = listaSiguiente #Igualamos la lista de corte a la iteracion anterior listaSiguiente = [ ] #Vaciamos la lista que dara lugar a la siguiente iteracion de corte for actual in listaActuales: #Checamos cada geometria en espera partida = actual.splitGeometry( linea, True ) #Aplicamos el split geometry de qgis, vamos partiendo el poligono if len(partida[1] ) == 0: #Esto ocurre cuando el corte no hizo nada listaSiguiente.append( actual ) #Asi que nos quedamos con la geometria tal cual esta else: #Cuando si hubo corte parte1 = partida[1][ 0] #obtenemos la geometria resultante del corte, VER DOCUMENTACION DE SPLITGEOMETRY PARA ENTENDER parte2 = actual.difference( parte1 ) #Al poligono que se corto, le quitamos la parte previa al corte anterior #De esta forma nos quedamos con la geometria partida en 2 if parte1.area( ) > 0.0: #Checamos que el area de esta parte sea mayor que 0, por motivos de los decimales listaSiguiente.append( parte1 ) #Si es asi, significa un fragmento que puede ser cortado por otra linea if parte2.area() > 0.0: #Lo mismo listaSiguiente.append(parte2) temporal = poligono #Obtenemos una geometria igualita al poligono entrannte for geomSal in listaSiguiente: #Obtenemos las diferencia respeto a los poligonos obtenidos y el entrante, lo que resulte, tambien es parte del corte temporal = temporal.difference(geomSal.buffer(0.0000001, 1)) listaSiguiente.append(temporal) #Aqui ponemos todas las geometrias return listaSiguiente #Retornamos la lista #------------------------------------------------------------------------- def encenderModoDividir(self): #Activamos el modo de dividir self.eventos.modoDividir = True self.eventos.modoEliminar = False self.eventos.modoEditar = False self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(True) self.dlg.btnEliminarCortes.setEnabled(True) self.dlg.btnApagarHerramientas.setEnabled(True) self.dlg.btnConfirmarCortes.setEnabled(True) self.dlg.btnDeshacerTodo.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(False) #iface.mapCanvas().setCursor(self.DBJ.eventos.cursorRedondo) iface.mapCanvas().setCursor(self.UTI.cursorRedondo) if not self.eventos.botonAD.isChecked(): self.eventos.botonAD.trigger() #---------------------------------------------------------------------------- def encenderModoEditar(self): #Activamos el modo de dividir self.eventos.modoDividir = False self.eventos.modoEliminar = False self.eventos.modoEditar = True self.dlg.btnDibujarCortes.setEnabled(True) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(True) self.dlg.btnApagarHerramientas.setEnabled(True) self.dlg.btnConfirmarCortes.setEnabled(True) self.dlg.btnDeshacerTodo.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(False) #iface.mapCanvas().setCursor(self.DBJ.eventos.cursorRedondo) iface.mapCanvas().setCursor(self.UTI.cursorRedondo) if not self.eventos.botonAD.isChecked(): self.eventos.botonAD.trigger() #---------------------------------------------------------------------------- def encenderModoEliminar(self): #Activamos el modo de eliminar self.eventos.modoDividir = False self.eventos.modoEliminar = True self.eventos.modoEditar = False self.dlg.btnDibujarCortes.setEnabled(True) self.dlg.btnEditarCortes.setEnabled(True) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(True) self.dlg.btnConfirmarCortes.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(False) #iface.mapCanvas().setCursor(self.DBJ.eventos.cursorCuadro) iface.mapCanvas().setCursor(self.UTI.cursorCuadro) if self.eventos.botonAD.isChecked(): self.eventos.botonAD.trigger() #---------------------------------------------------------------------------- def apagarHerramientas(self): #Apagamos las herramientas self.eventos.modoDividir = False self.eventos.modoEliminar = False self.eventos.modoEditar = False self.dlg.btnDibujarCortes.setEnabled(True) self.dlg.btnEliminarCortes.setEnabled(True) self.dlg.btnEditarCortes.setEnabled(True) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(True) self.dlg.btnCargarPredio.setEnabled(False) #iface.mapCanvas().setCursor(self.DBJ.eventos.cursorCruz) iface.mapCanvas().setCursor(self.UTI.cursorCruz) if self.eventos.botonAD.isChecked(): self.eventos.botonAD.trigger() #----------------------------------------------------------------- def rollBack(self): #Deshacemos cambios mensaje = "Todos los cambio se perderan, el area de trabajo se limpiara... deseas continuar?" respuesta = QMessageBox.question(iface.mainWindow(), "Cancelar cambios", mensaje, QMessageBox.Yes, QMessageBox.No) #Si el usuario acepta.... if respuesta == QMessageBox.Yes: self.eventos.modoDividir = False self.eventos.modoEliminar = False self.dlg.close() self.VentanaClaves.dlg.close() self.vaciarRubbers() self.predioEnDivision = None self.geomEnDivision = None self.VentanaAreas.close() self.UTI.limpiarCanvas() #------------------------------------------------------------ def vaciarRubbers(self): rango = len(self.eventos.relaciones) - 1 for i in range(0, rango): self.eventos.relaciones[i].rubber.reset(QgsWkbTypes.LineGeometry) #self.eventos.relaciones[i].geom = None self.eventos.relaciones[i].vaciarMarcadores() self.eventos.recargarRelaciones() self.rubberMarca.reset(QgsWkbTypes.PolygonGeometry) #self.eventos.vaciarMarcadores() #----------------------------------------------------------------- def asignarAtributos(self, feat): #Asignamos los atributos capaPredios = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('predios.geom')) campos = capaPredios.fields() nombres = [campo.name() for campo in campos] listaAsignacion = [] for nombre in nombres: idx = capaPredios.fields().lookupField(nombre) if nombre == 'sup_terr': attr = feat.geometry().area() elif nombre == 'sup_contruccion': attr = self.calcularSupConst(feat) elif nombre == 'clave': attr = '' elif nombre == 'cve_cat': attr = '' elif nombre == 'id': attr = '' elif nombre == 'cve_usuario': attr = self.UTI.decodeRot13(QSettings().value('usuario')) else: attr = self.predioEnDivision.attributes()[idx] listaAsignacion.append(attr) capaPredios.startEditing() feat.setAttributes(listaAsignacion) capaPredios.triggerRepaint() capaPredios.commitChanges() #------------------------------------------------------------ def calcularSupConst(self, feat): #calculamos superficie de construccion capaConstru = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('construcciones')) capaCondH = QgsProject.instance().mapLayer( self.ACA.obtenerIdCapa('horizontales.geom')) listaFinal = [] listaPrimera = [] #Renombrar construcciones cuentaConstruccion = 1 capaConstru.startEditing() geomFeat = feat.geometry() #--------Renombrar construcciones---- for construccion in capaConstru.getFeatures(): geomConstru = construccion.geometry() if geomConstru.buffer(-0.0000001, 1).intersects( geomFeat ): #Sacamos las construcciones dentro del predio fusionado listaPrimera.append(construccion) else: if self.contarIntegraciones( geomConstru.buffer(-0.0000001, 1), 'predios.geom' ) == 0: #Obtenemos los aleros del predio fusionado if geomConstru.buffer( 0.0000001, 1).intersection(geomFeat).area() > 0.000000001: listaPrimera.append(construccion) for construccion in listaPrimera: geomConstru = construccion.geometry() seIncluye = True for condominio in capaCondH.getFeatures(): geomHori = condominio.geometry() if geomConstru.buffer(-0.0000001, 1).intersects(geomHori): seIncluye = False break if seIncluye: listaFinal.append(construccion) supConst = 0 #Renombramos ls volumenes for construccion in listaFinal: geomConstru = construccion.geometry() construccion['nom_volumen'] = 'V' + str(cuentaConstruccion) niveles = construccion['num_niveles'] if niveles <= 0: niveles = 1 capaConstru.updateFeature(construccion) cuentaConstruccion += 1 supConst += (geomConstru.area() * niveles) capaConstru.triggerRepaint() capaConstru.commitChanges() return supConst #-------------------------------------------------------------------------------------------------- def irAClaves(self): #Pintamos la ventanita de asignar clavees self.VentanaClaves.predioOriginal = self.predioEnDivision self.VentanaClaves.obtieneCapaPredios() self.VentanaClaves.dlg.show() self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(False) self.dlg.btnCargarPredio.setEnabled(False) self.dlg.btnDeshacerCortes.setEnabled(False) self.dlg.btnLlamarCalcular.setEnabled(False) self.dlg.btnCancelarSub.setEnabled(False) self.dlg.comboPredios.setEnabled(False) self.enClaves = True #------------------------------------------------------------------------- def irAreas(self): self.limpiarAreas() self.rubberMarca.reset(QgsWkbTypes.PolygonGeometry) geoTemp = QgsGeometry.fromWkt(self.geomEnDivision.asWkt()) self.subdividirPredio(geoTemp, True) self.listaColores = [] for geom in self.geomsAreas: if geom.area() <= 0: continue newRub = self.eventos.crearNuevoRubberPoly() # obtener una lista de vertices del tipo QgsPointXY listaVertices = self.UTI.obtenerVerticesPoligono(geom) listaVertices.append(listaVertices[0]) rangoVertices = len(listaVertices) for x in range(0, rangoVertices - 2): newRub.addPoint(listaVertices[x], True) newRub.show() self.rubbersAreas.append(newRub) self.VentanaAreas.mostrarAreas() #-------------------------------------------------------------------- def limpiarAreas(self): for rub in self.rubbersAreas: rub.reset(QgsWkbTypes.PolygonGeometry) self.rubbersAreas = [] #------------------------------------------------------------------ def quitarAreas(self): self.limpiarAreas() n = 0 #Obtenemos todos los vertices de la geometria en division if self.geomEnDivision == None: return self.pintarAreaPredioSubdiv() ''' ver = self.geomEnDivision.vertexAt(0) listaVertices = [] while(ver != QgsPoint(0,0)): n +=1 ver=self.geomEnDivision.vertexAt(n) listaVertices.append(ver) listaVertices.append(listaVertices[0]) rangoVertices = len(listaVertices) for x in range(0, rangoVertices-2): vertice = listaVertices[x] self.rubberMarca.addPoint(QgsPointXY(vertice.x(), vertice.y()), True) self.rubberMarca.show() #Aqui pintamos de amarillito la geometria en division ''' #-------------------------------------------------------------------------- def pintarAreaPredioSubdiv(self, geom=None): if geom is None: geom = self.geomEnDivision polygon = geom.asPolygon() listaVertices = [] n = len(polygon[0]) for i in range(n): listaVertices.append(polygon[0][i]) listaVertices.append(listaVertices[0]) rangoVertices = len(listaVertices) for x in range(0, rangoVertices - 2): self.rubberMarca.addPoint(listaVertices[x], True) self.rubberMarca.show( ) #Aqui pintamos de amarillito la geometria en division def consumeWSGeneral(self, url_cons=""): url = url_cons data = "" try: self.headers['Authorization'] = self.UTI.obtenerToken() response = requests.get(url, headers=self.headers) except requests.exceptions.RequestException as e: self.createAlert( "Error de servidor--, 'consumeWSGeneral()' '" + str(e) + "'", QMessageBox().Critical, "Error de servidor") return if response.status_code == 200: data = response.content elif response.status_code == 403: self.createAlert('Sin Permisos para ejecutar la acción', QMessageBox().Critical, "Usuarios") return None else: self.createAlert( 'Error en peticion "consumeWSGeneral()":\n' + response.text, QMessageBox().Critical, "Error de servidor") return return json.loads(data) def createAlert(self, mensaje, icono=QMessageBox().Critical, titulo='Operaciones'): #Create QMessageBox self.msg = QMessageBox() #Add message self.msg.setText(mensaje) #Add icon of critical error self.msg.setIcon(icono) #Add tittle self.msg.setWindowTitle(titulo) #Show of message dialog self.msg.show() # Run the dialog event loop result = self.msg.exec_()
class InstantPrintTool(QgsMapTool, InstantPrintDialog): def __init__(self, iface, populateCompositionFz=None): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface projectInstance = QgsProject.instance() self.projectLayoutManager = projectInstance.layoutManager() self.rubberband = None self.oldrubberband = None self.pressPos = None self.printer = QPrinter() self.mapitem = None self.populateCompositionFz = populateCompositionFz self.dialog = InstantPrintDialog(self.iface.mainWindow()) self.dialogui = Ui_InstantPrintDialog() self.dialogui.setupUi(self.dialog) self.dialogui.addScale.setIcon( QIcon(":/images/themes/default/mActionAdd.svg")) self.dialogui.deleteScale.setIcon( QIcon(":/images/themes/default/symbologyRemove.svg")) self.dialog.hidden.connect(self.__onDialogHidden) self.exportButton = self.dialogui.buttonBox.addButton( self.tr("Export"), QDialogButtonBox.ActionRole) self.printButton = self.dialogui.buttonBox.addButton( self.tr("Print"), QDialogButtonBox.ActionRole) self.helpButton = self.dialogui.buttonBox.addButton( self.tr("Help"), QDialogButtonBox.HelpRole) self.dialogui.comboBox_fileformat.addItem( "PDF", self.tr("PDF Document (*.pdf);;")) self.dialogui.comboBox_fileformat.addItem( "JPG", self.tr("JPG Image (*.jpg);;")) self.dialogui.comboBox_fileformat.addItem( "BMP", self.tr("BMP Image (*.bmp);;")) self.dialogui.comboBox_fileformat.addItem( "PNG", self.tr("PNG Image (*.png);;")) self.iface.layoutDesignerOpened.connect( lambda view: self.__reloadLayouts()) self.iface.layoutDesignerWillBeClosed.connect(self.__reloadLayouts) self.dialogui.comboBox_layouts.currentIndexChanged.connect( self.__selectLayout) self.dialogui.comboBox_scale.lineEdit().textChanged.connect( self.__changeScale) self.dialogui.comboBox_scale.scaleChanged.connect(self.__changeScale) self.exportButton.clicked.connect(self.__export) self.printButton.clicked.connect(self.__print) self.helpButton.clicked.connect(self.__help) self.dialogui.buttonBox.button( QDialogButtonBox.Close).clicked.connect(lambda: self.dialog.hide()) self.dialogui.addScale.clicked.connect(self.add_new_scale) self.dialogui.deleteScale.clicked.connect(self.remove_scale) self.deactivated.connect(self.__cleanup) self.setCursor(Qt.OpenHandCursor) settings = QSettings() if settings.value("instantprint/geometry") is not None: self.dialog.restoreGeometry( settings.value("instantprint/geometry")) if settings.value("instantprint/scales") is not None: for scale in settings.value("instantprint/scales").split(";"): if scale: self.retrieve_scales(scale) self.check_scales() def __onDialogHidden(self): self.setEnabled(False) self.iface.mapCanvas().unsetMapTool(self) QSettings().setValue("instantprint/geometry", self.dialog.saveGeometry()) list = [] for i in range(self.dialogui.comboBox_scale.count()): list.append(self.dialogui.comboBox_scale.itemText(i)) QSettings().setValue("instantprint/scales", ";".join(list)) def retrieve_scales(self, checkScale): if self.dialogui.comboBox_scale.findText(checkScale) == -1: self.dialogui.comboBox_scale.addItem(checkScale) def add_new_scale(self): new_layout = self.dialogui.comboBox_scale.currentText() if self.dialogui.comboBox_scale.findText(new_layout) == -1: self.dialogui.comboBox_scale.addItem(new_layout) self.check_scales() def remove_scale(self): layout_to_delete = self.dialogui.comboBox_scale.currentIndex() self.dialogui.comboBox_scale.removeItem(layout_to_delete) self.check_scales() def setEnabled(self, enabled): if enabled: self.dialog.setVisible(True) self.__reloadLayouts() self.iface.mapCanvas().setMapTool(self) else: self.dialog.setVisible(False) self.iface.mapCanvas().unsetMapTool(self) def __changeScale(self): if not self.mapitem: return newscale = self.dialogui.comboBox_scale.scale() if abs(newscale) < 1E-6: return extent = self.mapitem.extent() center = extent.center() newwidth = extent.width() / self.mapitem.scale() * newscale newheight = extent.height() / self.mapitem.scale() * newscale x1 = center.x() - 0.5 * newwidth y1 = center.y() - 0.5 * newheight x2 = center.x() + 0.5 * newwidth y2 = center.y() + 0.5 * newheight self.mapitem.setExtent(QgsRectangle(x1, y1, x2, y2)) self.__createRubberBand() self.check_scales() def __selectLayout(self): if not self.dialog.isVisible(): return activeIndex = self.dialogui.comboBox_layouts.currentIndex() if activeIndex < 0: return layoutView = self.dialogui.comboBox_layouts.itemData(activeIndex) maps = [] layout_name = self.dialogui.comboBox_layouts.currentText() layout = self.projectLayoutManager.layoutByName(layout_name) for item in layoutView.items(): if isinstance(item, QgsLayoutItemMap): maps.append(item) if len(maps) != 1: QMessageBox.warning( self.iface.mainWindow(), self.tr("Invalid layout"), self.tr("The layout must have exactly one map item.")) self.exportButton.setEnabled(False) self.iface.mapCanvas().scene().removeItem(self.rubberband) self.rubberband = None self.dialogui.comboBox_scale.setEnabled(False) return self.dialogui.comboBox_scale.setEnabled(True) self.exportButton.setEnabled(True) self.layoutView = layoutView self.mapitem = layout.referenceMap() self.dialogui.comboBox_scale.setScale(self.mapitem.scale()) self.__createRubberBand() def __createRubberBand(self): self.__cleanup() extent = self.mapitem.extent() center = self.iface.mapCanvas().extent().center() self.corner = QPointF(center.x() - 0.5 * extent.width(), center.y() - 0.5 * extent.height()) self.rect = QRectF(self.corner.x(), self.corner.y(), extent.width(), extent.height()) self.mapitem.setExtent(QgsRectangle(self.rect)) self.rubberband = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.rubberband.setToCanvasRectangle(self.__canvasRect(self.rect)) self.rubberband.setColor(QColor(127, 127, 255, 127)) self.pressPos = None def __cleanup(self): if self.rubberband: self.iface.mapCanvas().scene().removeItem(self.rubberband) if self.oldrubberband: self.iface.mapCanvas().scene().removeItem(self.oldrubberband) self.rubberband = None self.oldrubberband = None self.pressPos = None def canvasPressEvent(self, e): if not self.rubberband: return r = self.__canvasRect(self.rect) if e.button() == Qt.LeftButton and self.__canvasRect( self.rect).contains(e.pos()): self.oldrect = QRectF(self.rect) self.oldrubberband = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.oldrubberband.setToCanvasRectangle( self.__canvasRect(self.oldrect)) self.oldrubberband.setColor(QColor(127, 127, 255, 31)) self.pressPos = (e.x(), e.y()) self.iface.mapCanvas().setCursor(Qt.ClosedHandCursor) def canvasMoveEvent(self, e): if not self.pressPos: return mup = self.iface.mapCanvas().mapSettings().mapUnitsPerPixel() x = self.corner.x() + (e.x() - self.pressPos[0]) * mup y = self.corner.y() + (self.pressPos[1] - e.y()) * mup snaptol = 10 * mup # Left edge matches with old right if abs(x - (self.oldrect.x() + self.oldrect.width())) < snaptol: x = self.oldrect.x() + self.oldrect.width() # Right edge matches with old left elif abs(x + self.rect.width() - self.oldrect.x()) < snaptol: x = self.oldrect.x() - self.rect.width() # Left edge matches with old left elif abs(x - self.oldrect.x()) < snaptol: x = self.oldrect.x() # Bottom edge matches with old top if abs(y - (self.oldrect.y() + self.oldrect.height())) < snaptol: y = self.oldrect.y() + self.oldrect.height() # Top edge matches with old bottom elif abs(y + self.rect.height() - self.oldrect.y()) < snaptol: y = self.oldrect.y() - self.rect.height() # Bottom edge matches with old bottom elif abs(y - self.oldrect.y()) < snaptol: y = self.oldrect.y() self.rect = QRectF(x, y, self.rect.width(), self.rect.height()) self.rubberband.setToCanvasRectangle(self.__canvasRect(self.rect)) def canvasReleaseEvent(self, e): if e.button() == Qt.LeftButton and self.pressPos: self.corner = QPointF(self.rect.x(), self.rect.y()) self.pressPos = None self.iface.mapCanvas().setCursor(Qt.OpenHandCursor) self.iface.mapCanvas().scene().removeItem(self.oldrubberband) self.oldrect = None self.oldrubberband = None self.mapitem.setExtent(QgsRectangle(self.rect)) def __canvasRect(self, rect): mtp = self.iface.mapCanvas().mapSettings().mapToPixel() p1 = mtp.transform(QgsPoint(rect.left(), rect.top())) p2 = mtp.transform(QgsPoint(rect.right(), rect.bottom())) return QRect(p1.x(), p1.y(), p2.x() - p1.x(), p2.y() - p1.y()) def __export(self): settings = QSettings() format = self.dialogui.comboBox_fileformat.itemData( self.dialogui.comboBox_fileformat.currentIndex()) filepath = QFileDialog.getSaveFileName( self.iface.mainWindow(), self.tr("Export Layout"), settings.value("/instantprint/lastfile", ""), format) if not all(filepath): return # Ensure output filename has correct extension filename = os.path.splitext( filepath[0] )[0] + "." + self.dialogui.comboBox_fileformat.currentText().lower() settings.setValue("/instantprint/lastfile", filepath[0]) if self.populateCompositionFz: self.populateCompositionFz(self.layoutView.composition()) success = False layout_name = self.dialogui.comboBox_layouts.currentText() layout_item = self.projectLayoutManager.layoutByName(layout_name) exporter = QgsLayoutExporter(layout_item) if filename[-3:].lower() == u"pdf": success = exporter.exportToPdf( filepath[0], QgsLayoutExporter.PdfExportSettings()) else: success = exporter.exportToImage( filepath[0], QgsLayoutExporter.ImageExportSettings()) if success != 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Export Failed"), self.tr("Failed to export the layout.")) def __print(self): layout_name = self.dialogui.comboBox_layouts.currentText() layout_item = self.projectLayoutManager.layoutByName(layout_name) actual_printer = QgsLayoutExporter(layout_item) printdialog = QPrintDialog(self.printer) if printdialog.exec_() != QDialog.Accepted: return success = actual_printer.print(self.printer, QgsLayoutExporter.PrintExportSettings()) if success != 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Print Failed"), self.tr("Failed to print the layout.")) def __reloadLayouts(self, removed=None): if not self.dialog.isVisible(): # Make it less likely to hit the issue outlined in https://github.com/qgis/QGIS/pull/1938 return self.dialogui.comboBox_layouts.blockSignals(True) prev = None if self.dialogui.comboBox_layouts.currentIndex() >= 0: prev = self.dialogui.comboBox_layouts.currentText() self.dialogui.comboBox_layouts.clear() active = 0 for layout in self.projectLayoutManager.layouts(): if layout != removed and layout.name(): cur = layout.name() self.dialogui.comboBox_layouts.addItem(cur, layout) if prev == cur: active = self.dialogui.comboBox_layouts.count() - 1 self.dialogui.comboBox_layouts.setCurrentIndex( -1) # Ensure setCurrentIndex below actually changes an index self.dialogui.comboBox_layouts.blockSignals(False) if self.dialogui.comboBox_layouts.count() > 0: self.dialogui.comboBox_layouts.setCurrentIndex(active) self.dialogui.comboBox_scale.setEnabled(True) self.exportButton.setEnabled(True) else: self.exportButton.setEnabled(False) self.dialogui.comboBox_scale.setEnabled(False) def __help(self): manualPath = os.path.join(os.path.dirname(__file__), "help", "documentation.pdf") QDesktopServices.openUrl(QUrl.fromLocalFile(manualPath)) def scaleFromString(self, scaleText): locale = QLocale() parts = [locale.toInt(part) for part in scaleText.split(":")] try: if len(parts) == 2 and parts[0][1] and parts[1][ 1] and parts[0][0] != 0 and parts[1][0] != 0: return float(parts[0][0]) / float(parts[1][0]) else: return None except ZeroDivisionError: return def check_scales(self): predefScalesStr = QSettings().value("Map/scales", PROJECT_SCALES).split(",") predefScales = [ self.scaleFromString(scaleString) for scaleString in predefScalesStr ] comboScalesStr = [ self.dialogui.comboBox_scale.itemText(i) for i in range(self.dialogui.comboBox_scale.count()) ] comboScales = [ self.scaleFromString(scaleString) for scaleString in comboScalesStr ] currentScale = self.scaleFromString( self.dialogui.comboBox_scale.currentText()) if not currentScale: self.dialogui.comboBox_scale.lineEdit().setStyleSheet( "background: #FF7777; color: #FFFFFF;") self.dialogui.addScale.setVisible(True) self.dialogui.addScale.setEnabled(False) self.dialogui.deleteScale.setVisible(False) else: self.dialogui.comboBox_scale.lineEdit().setStyleSheet("") if currentScale in comboScales: # If entry scale is already in the list, allow removing it unless it is a predefined scale self.dialogui.addScale.setVisible(False) self.dialogui.deleteScale.setVisible(True) self.dialogui.deleteScale.setEnabled( currentScale not in predefScales) else: # Otherwise, show button to add it self.dialogui.addScale.setVisible(True) self.dialogui.addScale.setEnabled(True) self.dialogui.deleteScale.setVisible(False)
def __init__(self, iface, ACA): """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: QgsInterface """ # Save reference to the QGIS interface self.iface = iface self.CFG = None self.UTI = None self.DFS = None self.DBJ = None self.ELM = None self.ACA = ACA self.TPG = None # 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', 'DivisionFusion_{}.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) # Create the dialog (after translation) and keep reference self.dlg = DivisionFusionDialog(parent=iface.mainWindow(), DIV=self) # Declare instance attributes ''' self.actions = [] self.menu = self.tr(u'&DivisionFusion') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'DivisionFusion') self.toolbar.setObjectName(u'DivisionFusion') ''' self.eventos = EventoDivision(iface.mapCanvas(), self, iface.cadDockWidget()) iface.mapCanvas().setMapTool(self.eventos) self.VentanaAreas = VentanaAreas(self) self.VentanaFusion = VentanaFusionV3(iface, self) self.VentanaClaves = VentanaClavesV3(iface, self) self.rubberMarca = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.rubberMarca.setFillColor(QColor(255, 255, 0, 12)) self.rubberMarca.setStrokeColor(QColor(255, 150, 0, 255)) self.rubberMarca.setWidth(2) self.listaNuevosPredios = [] self.cargoPredio = False self.listaColores = [] self.rubbersAreas = [] self.dlg.btnDibujarCortes.setEnabled(False) self.dlg.btnEditarCortes.setEnabled(False) self.dlg.btnEliminarCortes.setEnabled(False) self.dlg.btnApagarHerramientas.setEnabled(False) self.dlg.btnConfirmarCortes.setEnabled(False) self.dlg.btnDeshacerTodo.setEnabled(False) self.dlg.btnCancelarSub.setEnabled(False) self.dlg.btnDeshacerCortes.setEnabled(False) self.dlg.btnLlamarCalcular.setEnabled(False) self.dlg.btnFusionar.clicked.connect(self.preguntarFusion) self.dlg.btnCargarPredio.clicked.connect(self.pasarAModoDivision) self.dlg.btnConfirmarCortes.clicked.connect(self.confirmarCortes) self.dlg.btnDibujarCortes.clicked.connect(self.encenderModoDividir) self.dlg.btnEliminarCortes.clicked.connect(self.encenderModoEliminar) self.dlg.btnApagarHerramientas.clicked.connect(self.apagarHerramientas) self.dlg.btnDeshacerTodo.clicked.connect(self.rollBack) self.dlg.btnCancelarSub.clicked.connect(self.cancelarSubdivision) self.dlg.btnDeshacerCortes.clicked.connect(self.vaciarLineasCorte) self.dlg.btnLlamarCalcular.clicked.connect(self.irAreas) self.dlg.btnEditarCortes.clicked.connect(self.encenderModoEditar) self.dlg.btnDeshacerTodo.hide() self.enClaves = False self.enSubdivision = False self.enFusion = False self.headers = {'Content-Type': 'application/json'} self.geomsAreas = []
class RectangleMapTool(QgsMapToolEmitPoint): def __init__(self, canvas): QgsMapToolEmitPoint.__init__(self, canvas) self.canvas = canvas self.rubberBand = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry) self.rubberBand.setColor(QColor(255, 0, 0, 180)) self.rubberBand.setWidth(1) self.reset() def reset(self): self.startPoint = self.endPoint = None self.isDrawing = False self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint mapSettings = self.canvas.mapSettings() self.mupp = mapSettings.mapUnitsPerPixel() self.rotation = mapSettings.rotation() self.isDrawing = True self.showRect(self.startPoint, self.endPoint) def canvasReleaseEvent(self, e): self.isDrawing = False self.emit(SIGNAL("rectangleCreated()")) #TODO: new style signal def canvasMoveEvent(self, e): if not self.isDrawing: return self.endPoint = self.toMapCoordinates(e.pos()) self.showRect(self.startPoint, self.endPoint) def showRect(self, startPoint, endPoint): self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) if startPoint.x() == endPoint.x() and startPoint.y() == endPoint.y(): return for i, pt in enumerate(self._rect(startPoint, endPoint).vertices()): self.rubberBand.addPoint(pt, bool(i == 3)) self.rubberBand.show() def _rect(self, startPoint, endPoint): if startPoint is None or endPoint is None: return None p0 = self.toCanvasCoordinates(startPoint) p1 = self.toCanvasCoordinates(endPoint) canvas_rect = QgsRectangle(QgsPoint(p0.x(), p0.y()), QgsPoint(p1.x(), p1.y())) center = QgsPoint((startPoint.x() + endPoint.x()) / 2, (startPoint.y() + endPoint.y()) / 2) return RotatedRect(center, self.mupp * canvas_rect.width(), self.mupp * canvas_rect.height()).rotate(self.rotation, center) def rectangle(self): return self._rect(self.startPoint, self.endPoint) def setRectangle(self, rect): if rect == self._rect(self.startPoint, self.endPoint): return False v = rect.vertices() self.startPoint = v[3] self.endPoint = v[1] self.showRect(self.startPoint, self.endPoint) return True
def create(self, canvas, line_width=2, rbs_in="main_dialog"): """Create the tile as a rubber band inside the canvas given""" rubber_band = QgsRubberBand(canvas) points = [QgsPointXY(self.xmin, self.ymax), QgsPointXY(self.xmax, self.ymax), QgsPointXY(self.xmax, self.ymin), QgsPointXY(self.xmin, self.ymin)] rubber_band.setToGeometry(QgsGeometry.fromPolygonXY([points]), None) if rbs_in == "highlight": rubber_band.setColor(QColor("yellow")) else: rubber_band.setColor(self.tile_color) rubber_band.setFillColor(QColor(0, 0, 0, 0)) rubber_band.setWidth(line_width) rubber_band.show() if rbs_in == "main_dialog": self.rbs_in_main_dialog.append(rubber_band) if rbs_in == "nav_dialog": self.rbs_in_nav_dialog.append(rubber_band) if rbs_in == "highlight": return rubber_band
class GeomFilterEPSG(): def __init__(self, iface): self.iface = iface def initGui(self): # cria uma ação que iniciará a configuração do plugin #self.myMapTool = QgsMapToolEmitPoint( self.iface.mapCanvas() ) self.initVariables() self.initSignals() def initVariables(self): self.coordinates = [] # Criação da action e da toolbar self.toolbar = self.iface.addToolBar("My_ToolBar") pai = self.iface.mainWindow() icon_path = ':/plugins/GeomFilterEPSG/icon.png' self.action = QAction(QIcon(icon_path), u"Filtro EPSG.", pai) self.action.setObjectName("Filtro EPSG.") self.action.setStatusTip(None) self.action.setWhatsThis(None) self.action.setCheckable(True) self.toolbar.addAction(self.action) self.previousMapTool = self.iface.mapCanvas().mapTool() self.myMapTool = QgsMapToolEmitPoint(self.iface.mapCanvas()) self.isEditing = 0 def initSignals(self): self.action.toggled.connect(self.RubberBand) self.myMapTool.canvasClicked.connect(self.mouseClick) def RubberBand(self, bolean): if bolean: self.myRubberBand = QgsRubberBand(self.iface.mapCanvas(), QGis.Polygon) color = QColor(78, 97, 114) color.setAlpha(190) self.myRubberBand.setColor(color) self.myRubberBand.setFillColor(QColor(255, 0, 0, 40)) self.myRubberBand.setBorderColor(QColor(255, 0, 0, 200)) # Set MapTool self.iface.mapCanvas().setMapTool(self.myMapTool) self.iface.mapCanvas().xyCoordinates.connect(self.mouseMove) else: self.disconnect() def disconnect(self): self.iface.mapCanvas().unsetMapTool(self.myMapTool) try: self.iface.mapCanvas().xyCoordinates.disconnect(self.mouseMove) except: pass try: self.myRubberBand.reset() except: pass def unChecked(self): self.action.setCheckable(False) self.action.setCheckable(True) def unload(self): self.disconnect() def mouseClick(self, currentPos, clickedButton): if clickedButton == Qt.LeftButton: # and myRubberBand.numberOfVertices() == 0: self.myRubberBand.addPoint(QgsPoint(currentPos)) self.coordinates.append(QgsPoint(currentPos)) self.isEditing = 1 elif clickedButton == Qt.RightButton and self.myRubberBand.numberOfVertices( ) > 2: self.isEditing = 0 # create feature and set geometry. poly = QgsFeature() geomP = self.myRubberBand.asGeometry() poly.setGeometry(geomP) g = geomP.exportToWkt() # Get WKT coordenates. #print g canvas = self.iface.mapCanvas() c = canvas.mapRenderer().destinationCrs().authid() # Get EPSG. rep = c.replace("EPSG:", "") string = U"st_intersects(geom,st_geomfromewkt('SRID=" + rep + ";" + g + "'))" self.layers = self.iface.mapCanvas().layers() for layer in self.layers: layer.setSubsetString(string) self.myRubberBand.reset(QGis.Polygon) self.disconnect() self.unChecked() def mouseMove(self, currentPos): if self.isEditing == 1: self.myRubberBand.movePoint(QgsPoint(currentPos))
class MetaSearchDialog(QDialog, BASE_CLASS): """main dialogue""" def __init__(self, iface): """init window""" QDialog.__init__(self) self.setupUi(self) self.iface = iface self.map = iface.mapCanvas() self.settings = QSettings() self.catalog = None self.catalog_url = None self.context = StaticContext() version = self.context.metadata.get('general', 'version') self.setWindowTitle('MetaSearch %s' % version) self.rubber_band = QgsRubberBand(self.map, True) # True = a polygon self.rubber_band.setColor(QColor(255, 0, 0, 75)) self.rubber_band.setWidth(5) # form inputs self.startfrom = 0 self.maxrecords = 10 self.timeout = 10 self.constraints = [] # Servers tab self.cmbConnectionsServices.activated.connect(self.save_connection) self.cmbConnectionsSearch.activated.connect(self.save_connection) self.btnServerInfo.clicked.connect(self.connection_info) self.btnAddDefault.clicked.connect(self.add_default_connections) self.btnCapabilities.clicked.connect(self.show_xml) self.tabWidget.currentChanged.connect(self.populate_connection_list) # server management buttons self.btnNew.clicked.connect(self.add_connection) self.btnEdit.clicked.connect(self.edit_connection) self.btnDelete.clicked.connect(self.delete_connection) self.btnLoad.clicked.connect(self.load_connections) self.btnSave.clicked.connect(save_connections) # Search tab self.treeRecords.itemSelectionChanged.connect(self.record_clicked) self.treeRecords.itemDoubleClicked.connect(self.show_metadata) self.btnSearch.clicked.connect(self.search) self.leKeywords.returnPressed.connect(self.search) # prevent dialog from closing upon pressing enter self.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) # launch help from button self.buttonBox.helpRequested.connect(self.help) self.btnCanvasBbox.setAutoDefault(False) self.btnCanvasBbox.clicked.connect(self.set_bbox_from_map) self.btnGlobalBbox.clicked.connect(self.set_bbox_global) # navigation buttons self.btnFirst.clicked.connect(self.navigate) self.btnPrev.clicked.connect(self.navigate) self.btnNext.clicked.connect(self.navigate) self.btnLast.clicked.connect(self.navigate) self.btnAddToWms.clicked.connect(self.add_to_ows) self.btnAddToWfs.clicked.connect(self.add_to_ows) self.btnAddToWcs.clicked.connect(self.add_to_ows) self.btnShowXml.clicked.connect(self.show_xml) # settings self.radioTitleAsk.clicked.connect(self.set_ows_save_title_ask) self.radioTitleNoAsk.clicked.connect(self.set_ows_save_title_no_ask) self.radioTempName.clicked.connect(self.set_ows_save_temp_name) self.manageGui() def manageGui(self): """open window""" self.tabWidget.setCurrentIndex(0) self.populate_connection_list() self.btnCapabilities.setEnabled(False) self.spnRecords.setValue( self.settings.value('/MetaSearch/returnRecords', 10, int)) key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText() self.catalog_url = self.settings.value('%s/url' % key) self.set_bbox_global() self.reset_buttons() # get preferred connection save strategy from settings and set it save_strat = self.settings.value('/MetaSearch/ows_save_strategy', 'title_ask') if save_strat == 'temp_name': self.radioTempName.setChecked(True) elif save_strat == 'title_no_ask': self.radioTitleNoAsk.setChecked(True) else: self.radioTitleAsk.setChecked(True) # install proxy handler if specified in QGIS settings self.install_proxy() # Servers tab def populate_connection_list(self): """populate select box with connections""" self.settings.beginGroup('/MetaSearch/') self.cmbConnectionsServices.clear() self.cmbConnectionsServices.addItems(self.settings.childGroups()) self.cmbConnectionsSearch.clear() self.cmbConnectionsSearch.addItems(self.settings.childGroups()) self.settings.endGroup() self.set_connection_list_position() if self.cmbConnectionsServices.count() == 0: # no connections - disable various buttons state_disabled = False self.btnSave.setEnabled(state_disabled) # and start with connection tab open self.tabWidget.setCurrentIndex(1) # tell the user to add services msg = self.tr('No services/connections defined. To get ' 'started with MetaSearch, create a new ' 'connection by clicking \'New\' or click ' '\'Add default services\'.') self.textMetadata.setHtml('<p><h3>%s</h3></p>' % msg) else: # connections - enable various buttons state_disabled = True self.btnServerInfo.setEnabled(state_disabled) self.btnEdit.setEnabled(state_disabled) self.btnDelete.setEnabled(state_disabled) def set_connection_list_position(self): """set the current index to the selected connection""" to_select = self.settings.value('/MetaSearch/selected') conn_count = self.cmbConnectionsServices.count() if conn_count == 0: self.btnDelete.setEnabled(False) self.btnServerInfo.setEnabled(False) self.btnEdit.setEnabled(False) # does to_select exist in cmbConnectionsServices? exists = False for i in range(conn_count): if self.cmbConnectionsServices.itemText(i) == to_select: self.cmbConnectionsServices.setCurrentIndex(i) self.cmbConnectionsSearch.setCurrentIndex(i) exists = True break # If we couldn't find the stored item, but there are some, default # to the last item (this makes some sense when deleting items as it # allows the user to repeatidly click on delete to remove a whole # lot of items) if not exists and conn_count > 0: # If to_select is null, then the selected connection wasn't found # by QSettings, which probably means that this is the first time # the user has used CSWClient, so default to the first in the list # of connetions. Otherwise default to the last. if not to_select: current_index = 0 else: current_index = conn_count - 1 self.cmbConnectionsServices.setCurrentIndex(current_index) self.cmbConnectionsSearch.setCurrentIndex(current_index) def save_connection(self): """save connection""" caller = self.sender().objectName() if caller == 'cmbConnectionsServices': # servers tab current_text = self.cmbConnectionsServices.currentText() elif caller == 'cmbConnectionsSearch': # search tab current_text = self.cmbConnectionsSearch.currentText() self.settings.setValue('/MetaSearch/selected', current_text) key = '/MetaSearch/%s' % current_text if caller == 'cmbConnectionsSearch': # bind to service in search tab self.catalog_url = self.settings.value('%s/url' % key) if caller == 'cmbConnectionsServices': # clear server metadata self.textMetadata.clear() self.btnCapabilities.setEnabled(False) def connection_info(self): """show connection info""" current_text = self.cmbConnectionsServices.currentText() key = '/MetaSearch/%s' % current_text self.catalog_url = self.settings.value('%s/url' % key) # connect to the server if not self._get_csw(): return QApplication.restoreOverrideCursor() if self.catalog: # display service metadata self.btnCapabilities.setEnabled(True) metadata = render_template('en', self.context, self.catalog, 'service_metadata.html') style = QgsApplication.reportStyleSheet() self.textMetadata.clear() self.textMetadata.document().setDefaultStyleSheet(style) self.textMetadata.setHtml(metadata) def add_connection(self): """add new service""" conn_new = NewConnectionDialog() conn_new.setWindowTitle(self.tr('New Catalogue service')) if conn_new.exec_() == QDialog.Accepted: # add to service list self.populate_connection_list() self.textMetadata.clear() def edit_connection(self): """modify existing connection""" current_text = self.cmbConnectionsServices.currentText() url = self.settings.value('/MetaSearch/%s/url' % current_text) conn_edit = NewConnectionDialog(current_text) conn_edit.setWindowTitle(self.tr('Edit Catalogue service')) conn_edit.leName.setText(current_text) conn_edit.leURL.setText(url) if conn_edit.exec_() == QDialog.Accepted: # update service list self.populate_connection_list() def delete_connection(self): """delete connection""" current_text = self.cmbConnectionsServices.currentText() key = '/MetaSearch/%s' % current_text msg = self.tr('Remove service %s?') % current_text result = QMessageBox.information(self, self.tr('Confirm delete'), msg, QMessageBox.Ok | QMessageBox.Cancel) if result == QMessageBox.Ok: # remove service from list self.settings.remove(key) index_to_delete = self.cmbConnectionsServices.currentIndex() self.cmbConnectionsServices.removeItem(index_to_delete) self.cmbConnectionsSearch.removeItem(index_to_delete) self.set_connection_list_position() def load_connections(self): """load services from list""" ManageConnectionsDialog(1).exec_() self.populate_connection_list() def add_default_connections(self): """add default connections""" filename = os.path.join(self.context.ppath, 'resources', 'connections-default.xml') doc = get_connections_from_file(self, filename) if doc is None: return self.settings.beginGroup('/MetaSearch/') keys = self.settings.childGroups() self.settings.endGroup() for server in doc.findall('csw'): name = server.attrib.get('name') # check for duplicates if name in keys: msg = self.tr('%s exists. Overwrite?') % name res = QMessageBox.warning(self, self.tr('Loading connections'), msg, QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: continue # no dups detected or overwrite is allowed key = '/MetaSearch/%s' % name self.settings.setValue('%s/url' % key, server.attrib.get('url')) self.populate_connection_list() # Settings tab def set_ows_save_title_ask(self): """save ows save strategy as save ows title, ask if duplicate""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask') def set_ows_save_title_no_ask(self): """save ows save strategy as save ows title, do NOT ask if duplicate""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask') def set_ows_save_temp_name(self): """save ows save strategy as save with a temporary name""" self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name') # Search tab def set_bbox_from_map(self): """set bounding box from map extent""" crs = self.map.mapRenderer().destinationCrs() crsid = int(crs.authid().split(':')[1]) extent = self.map.extent() if crsid != 4326: # reproject to EPSG:4326 src = QgsCoordinateReferenceSystem(crsid) dest = QgsCoordinateReferenceSystem(4326) xform = QgsCoordinateTransform(src, dest) minxy = xform.transform(QgsPoint(extent.xMinimum(), extent.yMinimum())) maxxy = xform.transform(QgsPoint(extent.xMaximum(), extent.yMaximum())) minx, miny = minxy maxx, maxy = maxxy else: # 4326 minx = extent.xMinimum() miny = extent.yMinimum() maxx = extent.xMaximum() maxy = extent.yMaximum() self.leNorth.setText(unicode(maxy)[0:9]) self.leSouth.setText(unicode(miny)[0:9]) self.leWest.setText(unicode(minx)[0:9]) self.leEast.setText(unicode(maxx)[0:9]) def set_bbox_global(self): """set global bounding box""" self.leNorth.setText('90') self.leSouth.setText('-90') self.leWest.setText('-180') self.leEast.setText('180') def search(self): """execute search""" self.catalog = None self.constraints = [] # clear all fields and disable buttons self.lblResults.clear() self.treeRecords.clear() self.reset_buttons() # save some settings self.settings.setValue('/MetaSearch/returnRecords', self.spnRecords.cleanText()) # set current catalogue current_text = self.cmbConnectionsSearch.currentText() key = '/MetaSearch/%s' % current_text self.catalog_url = self.settings.value('%s/url' % key) # start position and number of records to return self.startfrom = 0 self.maxrecords = self.spnRecords.value() # set timeout self.timeout = self.spnTimeout.value() # bbox minx = self.leWest.text() miny = self.leSouth.text() maxx = self.leEast.text() maxy = self.leNorth.text() bbox = [minx, miny, maxx, maxy] # only apply spatial filter if bbox is not global # even for a global bbox, if a spatial filter is applied, then # the CSW server will skip records without a bbox if bbox != ['-180', '-90', '180', '90']: self.constraints.append(BBox(bbox)) # keywords if self.leKeywords.text(): # TODO: handle multiple word searches keywords = self.leKeywords.text() self.constraints.append(PropertyIsLike('csw:AnyText', keywords)) if len(self.constraints) > 1: # exclusive search (a && b) self.constraints = [self.constraints] # build request if not self._get_csw(): return # TODO: allow users to select resources types # to find ('service', 'dataset', etc.) try: self.catalog.getrecords2(constraints=self.constraints, maxrecords=self.maxrecords, esn='full') except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Search error'), self.tr('Search error: %s') % err) return except Exception as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Connection error'), self.tr('Connection error: %s') % err) return if self.catalog.results['matches'] == 0: QApplication.restoreOverrideCursor() self.lblResults.setText(self.tr('0 results')) return QApplication.restoreOverrideCursor() self.display_results() def display_results(self): """display search results""" self.treeRecords.clear() position = self.catalog.results['returned'] + self.startfrom msg = self.tr('Showing %d - %d of %n result(s)', 'number of results', self.catalog.results['matches']) % (self.startfrom + 1, position) self.lblResults.setText(msg) for rec in self.catalog.records: item = QTreeWidgetItem(self.treeRecords) if self.catalog.records[rec].type: item.setText(0, normalize_text(self.catalog.records[rec].type)) else: item.setText(0, 'unknown') if self.catalog.records[rec].title: item.setText(1, normalize_text(self.catalog.records[rec].title)) if self.catalog.records[rec].identifier: set_item_data(item, 'identifier', self.catalog.records[rec].identifier) self.btnShowXml.setEnabled(True) if self.catalog.results["matches"] < self.maxrecords: disabled = False else: disabled = True self.btnFirst.setEnabled(disabled) self.btnPrev.setEnabled(disabled) self.btnNext.setEnabled(disabled) self.btnLast.setEnabled(disabled) def record_clicked(self): """record clicked signal""" # disable only service buttons self.reset_buttons(True, False, False) if not self.treeRecords.selectedItems(): return item = self.treeRecords.currentItem() if not item: return identifier = get_item_data(item, 'identifier') try: record = self.catalog.records[identifier] except KeyError as err: QMessageBox.warning(self, self.tr('Record parsing error'), 'Unable to locate record identifier') return # if the record has a bbox, show a footprint on the map if record.bbox is not None: points = bbox_to_polygon(record.bbox) if points is not None: src = QgsCoordinateReferenceSystem(4326) dst = self.map.mapRenderer().destinationCrs() geom = QgsGeometry.fromPolygon(points) if src.postgisSrid() != dst.postgisSrid(): ctr = QgsCoordinateTransform(src, dst) try: geom.transform(ctr) except Exception as err: QMessageBox.warning( self, self.tr('Coordinate Transformation Error'), unicode(err)) self.rubber_band.setToGeometry(geom, None) # figure out if the data is interactive and can be operated on self.find_services(record, item) def find_services(self, record, item): """scan record for WMS/WMTS|WFS|WCS endpoints""" links = record.uris + record.references services = {} for link in links: if 'scheme' in link: link_type = link['scheme'] elif 'protocol' in link: link_type = link['protocol'] else: link_type = None if link_type is not None: link_type = link_type.upper() wmswmst_link_types = map(str.upper, link_types.WMSWMST_LINK_TYPES) wfs_link_types = map(str.upper, link_types.WFS_LINK_TYPES) wcs_link_types = map(str.upper, link_types.WCS_LINK_TYPES) # if the link type exists, and it is one of the acceptable # interactive link types, then set if all([link_type is not None, link_type in wmswmst_link_types + wfs_link_types + wcs_link_types]): if link_type in wmswmst_link_types: services['wms'] = link['url'] self.btnAddToWms.setEnabled(True) if link_type in wfs_link_types: services['wfs'] = link['url'] self.btnAddToWfs.setEnabled(True) if link_type in wcs_link_types: services['wcs'] = link['url'] self.btnAddToWcs.setEnabled(True) set_item_data(item, 'link', json.dumps(services)) def navigate(self): """manage navigation / paging""" caller = self.sender().objectName() if caller == 'btnFirst': self.startfrom = 0 elif caller == 'btnLast': self.startfrom = self.catalog.results['matches'] - self.maxrecords elif caller == 'btnNext': self.startfrom += self.maxrecords if self.startfrom >= self.catalog.results["matches"]: msg = self.tr('End of results. Go to start?') res = QMessageBox.information(self, self.tr('Navigation'), msg, (QMessageBox.Ok | QMessageBox.Cancel)) if res == QMessageBox.Ok: self.startfrom = 0 else: return elif caller == "btnPrev": self.startfrom -= self.maxrecords if self.startfrom <= 0: msg = self.tr('Start of results. Go to end?') res = QMessageBox.information(self, self.tr('Navigation'), msg, (QMessageBox.Ok | QMessageBox.Cancel)) if res == QMessageBox.Ok: self.startfrom = (self.catalog.results['matches'] - self.maxrecords) else: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: self.catalog.getrecords2(constraints=self.constraints, maxrecords=self.maxrecords, startposition=self.startfrom, esn='full') except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Search error'), self.tr('Search error: %s') % err) return except Exception as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('Connection error'), self.tr('Connection error: %s') % err) return QApplication.restoreOverrideCursor() self.display_results() def add_to_ows(self): """add to OWS provider connection list""" conn_name_matches = [] item = self.treeRecords.currentItem() if not item: return item_data = json.loads(get_item_data(item, 'link')) caller = self.sender().objectName() # stype = human name,/Qgis/connections-%s,providername if caller == 'btnAddToWms': stype = ['OGC:WMS/OGC:WMTS', 'wms', 'wms'] data_url = item_data['wms'] elif caller == 'btnAddToWfs': stype = ['OGC:WFS', 'wfs', 'WFS'] data_url = item_data['wfs'] elif caller == 'btnAddToWcs': stype = ['OGC:WCS', 'wcs', 'wcs'] data_url = item_data['wcs'] QApplication.restoreOverrideCursor() sname = '%s from MetaSearch' % stype[1] # store connection # check if there is a connection with same name self.settings.beginGroup('/Qgis/connections-%s' % stype[1]) keys = self.settings.childGroups() self.settings.endGroup() for key in keys: if key.startswith(sname): conn_name_matches.append(key) if conn_name_matches: sname = conn_name_matches[-1] # check for duplicates if sname in keys: # duplicate found if self.radioTitleAsk.isChecked(): # ask to overwrite msg = self.tr('Connection %s exists. Overwrite?') % sname res = QMessageBox.warning(self, self.tr('Saving server'), msg, QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: # assign new name with serial sname = serialize_string(sname) elif self.radioTitleNoAsk.isChecked(): # don't ask to overwrite pass elif self.radioTempName.isChecked(): # use temp name sname = serialize_string(sname) # no dups detected or overwrite is allowed self.settings.beginGroup('/Qgis/connections-%s' % stype[1]) self.settings.setValue('/%s/url' % sname, data_url) self.settings.endGroup() # open provider window ows_provider = QgsProviderRegistry.instance().selectWidget(stype[2], self) service_type = stype[0] # connect dialog signals to iface slots if service_type == 'OGC:WMS/OGC:WMTS': ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') connect = 'on_btnConnect_clicked' elif service_type == 'OGC:WFS': ows_provider.addWfsLayer.connect(self.iface.mainWindow().addWfsLayer) conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') connect = 'connectToServer' elif service_type == 'OGC:WCS': ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox') connect = 'on_mConnectButton_clicked' ows_provider.setModal(False) ows_provider.show() # open provider dialogue against added OWS index = conn_cmb.findText(sname) if index > -1: conn_cmb.setCurrentIndex(index) # only for wfs if service_type == 'OGC:WFS': ows_provider.on_cmbConnections_activated(index) getattr(ows_provider, connect)() def show_metadata(self): """show record metadata""" if not self.treeRecords.selectedItems(): return item = self.treeRecords.currentItem() if not item: return identifier = get_item_data(item, 'identifier') try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) cat = CatalogueServiceWeb(self.catalog_url, timeout=self.timeout) cat.getrecordbyid( [self.catalog.records[identifier].identifier]) except ExceptionReport as err: QApplication.restoreOverrideCursor() QMessageBox.warning(self, self.tr('GetRecords error'), self.tr('Error getting response: %s') % err) return except KeyError as err: QMessageBox.warning(self, self.tr('Record parsing error'), 'Unable to locate record identifier') QApplication.restoreOverrideCursor() return QApplication.restoreOverrideCursor() record = cat.records[identifier] record.xml_url = cat.request crd = RecordDialog() metadata = render_template('en', self.context, record, 'record_metadata_dc.html') style = QgsApplication.reportStyleSheet() crd.textMetadata.document().setDefaultStyleSheet(style) crd.textMetadata.setHtml(metadata) crd.exec_() def show_xml(self): """show XML request / response""" crd = XMLDialog() request_html = highlight_xml(self.context, self.catalog.request) response_html = highlight_xml(self.context, self.catalog.response) style = QgsApplication.reportStyleSheet() crd.txtbrXMLRequest.clear() crd.txtbrXMLResponse.clear() crd.txtbrXMLRequest.document().setDefaultStyleSheet(style) crd.txtbrXMLResponse.document().setDefaultStyleSheet(style) crd.txtbrXMLRequest.setHtml(request_html) crd.txtbrXMLResponse.setHtml(response_html) crd.exec_() def reset_buttons(self, services=True, xml=True, navigation=True): """Convenience function to disable WMS/WMTS|WFS|WCS buttons""" if services: self.btnAddToWms.setEnabled(False) self.btnAddToWfs.setEnabled(False) self.btnAddToWcs.setEnabled(False) if xml: self.btnShowXml.setEnabled(False) if navigation: self.btnFirst.setEnabled(False) self.btnPrev.setEnabled(False) self.btnNext.setEnabled(False) self.btnLast.setEnabled(False) def help(self): """launch help""" open_url(get_help_url()) def reject(self): """back out of dialogue""" QDialog.reject(self) self.rubber_band.reset() def _get_csw(self): """convenience function to init owslib.csw.CatalogueServiceWeb""" # connect to the server try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.catalog = CatalogueServiceWeb(self.catalog_url, timeout=self.timeout) return True except ExceptionReport as err: msg = self.tr('Error connecting to service: %s') % err except ValueError as err: msg = self.tr('Value Error: %s') % err except Exception as err: msg = self.tr('Unknown Error: %s') % err QMessageBox.warning(self, self.tr('CSW Connection error'), msg) QApplication.restoreOverrideCursor() return False def install_proxy(self): """set proxy if one is set in QGIS network settings""" # initially support HTTP for now if self.settings.value('/proxy/proxyEnabled') == 'true': if self.settings.value('/proxy/proxyType') == 'HttpProxy': ptype = 'http' else: return user = self.settings.value('/proxy/proxyUser') password = self.settings.value('/proxy/proxyPassword') host = self.settings.value('/proxy/proxyHost') port = self.settings.value('/proxy/proxyPort') proxy_up = '' proxy_port = '' if all([user != '', password != '']): proxy_up = '%s:%s@' % (user, password) if port != '': proxy_port = ':%s' % port conn = '%s://%s%s%s' % (ptype, proxy_up, host, proxy_port) install_opener(build_opener(ProxyHandler({ptype: conn})))
class MeasureTool(QgsMapTool): ''' classdocs ''' def __init__(self, canvas, txtBearing, disType = DistanceUnits.M): ''' Constructor ''' self.canvas = canvas self.txtBearing = txtBearing QgsMapTool.__init__(self, self.canvas) self.mSnapper = QgsMapCanvasSnapper(self.canvas) self.rubberBand = QgsRubberBand(self.canvas,QGis.Line) self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(1) self.rubberBandPt = QgsRubberBand(canvas, QGis.Point) self.rubberBandPt.setColor(Qt.red) self.rubberBandPt.setWidth(10) self.type = disType self.reset() def reset(self): self.startPoint = None self.endPoint = None self.isDrawing = False self.distance = 0.0 def canvasReleaseEvent(self, e): if ( e.button() == Qt.RightButton ): self.reset() self.emit(SIGNAL("captureFinished")) else: self.rubberBandPt.reset(QGis.Point) snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) if self.startPoint == None: self.rubberBand.reset(QGis.Line) if snapPoint == None: self.startPoint = self.toMapCoordinates(e.pos()) else: self.startPoint = snapPoint self.rubberBand.addPoint(self.startPoint) self.isDrawing = True else: if snapPoint == None: self.endPoint = self.toMapCoordinates(e.pos()) else: self.endPoint = snapPoint self.rubberBand.addPoint(self.endPoint) dist = MathHelper.calcDistance(self.startPoint, self.endPoint) self.distance = self.distance + dist if self.type == DistanceUnits.M: self.txtBearing.setText("%f"%round(self.distance, 4)) elif self.type == DistanceUnits.NM: self.txtBearing.setText("%f"%round(Unit.ConvertMeterToNM(self.distance), 4)) elif self.type == DistanceUnits.FT: self.txtBearing.setText("%f"%round(Unit.ConvertMeterToFeet(self.distance), 4)) elif self.type == DistanceUnits.KM: self.txtBearing.setText("%f"%round((self.distance / 1000), 4)) elif self.type == DistanceUnits.MM: self.txtBearing.setText(str(int(self.distance * 1000))) self.startPoint = self.endPoint def canvasMoveEvent(self, e): self.rubberBandPt.reset(QGis.Point) snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) if snapPoint != None: self.rubberBandPt.addPoint(snapPoint) self.rubberBandPt.show() if self.isDrawing: if self.isDrawing: if snapPoint == None: self.endPoint = self.toMapCoordinates(e.pos()) else: self.endPoint = snapPoint self.rubberBand.movePoint(self.endPoint) dist1 = MathHelper.calcDistance(self.startPoint, self.endPoint) dist1 = self.distance + dist1 if self.type == DistanceUnits.M: self.txtBearing.setText("%f"%round(dist1, 4)) elif self.type == DistanceUnits.NM: self.txtBearing.setText("%f"%round(Unit.ConvertMeterToNM(dist1), 4)) elif self.type == DistanceUnits.FT: self.txtBearing.setText("%f"%round(Unit.ConvertMeterToFeet(dist1), 4)) elif self.type == DistanceUnits.KM: self.txtBearing.setText("%f"%round((dist1 / 1000), 4)) elif self.type == DistanceUnits.MM: self.txtBearing.setText(str(int(dist1 * 1000))) def deactivate(self): self.rubberBandPt.reset(QGis.Point) QgsMapTool.deactivate(self) self.emit(SIGNAL("deactivated()"))
def __init__(self, iface): """init window""" QDialog.__init__(self) self.setupUi(self) self.iface = iface self.map = iface.mapCanvas() self.settings = QSettings() self.catalog = None self.catalog_url = None self.context = StaticContext() version = self.context.metadata.get('general', 'version') self.setWindowTitle('MetaSearch %s' % version) self.rubber_band = QgsRubberBand(self.map, True) # True = a polygon self.rubber_band.setColor(QColor(255, 0, 0, 75)) self.rubber_band.setWidth(5) # form inputs self.startfrom = 0 self.maxrecords = 10 self.timeout = 10 self.constraints = [] # Servers tab self.cmbConnectionsServices.activated.connect(self.save_connection) self.cmbConnectionsSearch.activated.connect(self.save_connection) self.btnServerInfo.clicked.connect(self.connection_info) self.btnAddDefault.clicked.connect(self.add_default_connections) self.btnCapabilities.clicked.connect(self.show_xml) self.tabWidget.currentChanged.connect(self.populate_connection_list) # server management buttons self.btnNew.clicked.connect(self.add_connection) self.btnEdit.clicked.connect(self.edit_connection) self.btnDelete.clicked.connect(self.delete_connection) self.btnLoad.clicked.connect(self.load_connections) self.btnSave.clicked.connect(save_connections) # Search tab self.treeRecords.itemSelectionChanged.connect(self.record_clicked) self.treeRecords.itemDoubleClicked.connect(self.show_metadata) self.btnSearch.clicked.connect(self.search) self.leKeywords.returnPressed.connect(self.search) # prevent dialog from closing upon pressing enter self.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) # launch help from button self.buttonBox.helpRequested.connect(self.help) self.btnCanvasBbox.setAutoDefault(False) self.btnCanvasBbox.clicked.connect(self.set_bbox_from_map) self.btnGlobalBbox.clicked.connect(self.set_bbox_global) # navigation buttons self.btnFirst.clicked.connect(self.navigate) self.btnPrev.clicked.connect(self.navigate) self.btnNext.clicked.connect(self.navigate) self.btnLast.clicked.connect(self.navigate) self.btnAddToWms.clicked.connect(self.add_to_ows) self.btnAddToWfs.clicked.connect(self.add_to_ows) self.btnAddToWcs.clicked.connect(self.add_to_ows) self.btnShowXml.clicked.connect(self.show_xml) # settings self.radioTitleAsk.clicked.connect(self.set_ows_save_title_ask) self.radioTitleNoAsk.clicked.connect(self.set_ows_save_title_no_ask) self.radioTempName.clicked.connect(self.set_ows_save_temp_name) self.manageGui()
class PolygonMapTool(QgsMapToolEmitPoint): """This class holds a map tool to create a polygon from points got by clicking on the map window. Points are stored in a list of point geometries, which is returned to the main plugin for use.""" def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) # rubberband class gives the user visual feedback of the drawing self.rubberBand = QgsRubberBand(self.canvas, True) # setting up outline and fill color: both red self.rubberBand.setColor(QColor(235, 36, 21)) # RGB color values, last value indicates transparency (0-255) self.rubberBand.setFillColor(QColor(255, 79, 66, 140)) self.rubberBand.setWidth(3) self.points = [] # a flag indicating when a single polygon is finished self.finished = False self.poly_bbox = False self.double_click_flag = False self.reset() def reset(self): """Empties the canvas and the points gathered thus far""" self.rubberBand.reset(True) self.poly_bbox = False self.points.clear() def keyPressEvent(self, e): """Pressing ESC resets the canvas. Pressing enter connects the polygon""" if (e.key() == 16777216): self.reset() if (e.key() == 16777220): self.finishPolygon() def canvasDoubleClickEvent(self, e): self.double_click_flag = True self.finishPolygon() def canvasReleaseEvent(self, e): """Activated when user clicks on the canvas. Gets coordinates, draws them on the map and adds to the list of points.""" if self.double_click_flag: self.double_click_flag = False return # if the finished flag is activated, the canvas will be must be reset # for a new polygon if self.finished: self.reset() self.finished = False self.click_point = self.toMapCoordinates(e.pos()) self.rubberBand.addPoint(self.click_point, True) self.points.append(self.click_point) self.rubberBand.show() def finishPolygon(self): """Activated when by user or when the map window is closed without connecting the polygon. Makes the polygon valid by making first and last point the same. This is reflected visually. Up until now the user has been drawing a line: a polygon is created and shown on the map.""" # nothing will happen if the code below has already been ran if self.finished: return # connecting the polygon is valid if there's already at least 3 points elif len(self.points) > 2: first_point = self.points[0] self.points.append(first_point) self.rubberBand.closePoints() self.rubberBand.addPoint(first_point, True) self.finished = True # a polygon is created and added to the map for visual purposes map_polygon = QgsGeometry.fromPolygonXY([self.points]) self.rubberBand.setToGeometry(map_polygon) # get the bounding box of this new polygon self.poly_bbox = self.rubberBand.asGeometry().boundingBox() else: self.finished = True def getPoints(self): """Returns list of PointXY geometries, i.e. the polygon in list form""" self.rubberBand.reset(True) return self.points def getPolyBbox(self): return self.poly_bbox
class EventoDivision(QgsMapToolAdvancedDigitizing): def __init__(self, canvas, pluginM, cadDockWidget): QgsMapToolAdvancedDigitizing.__init__(self, canvas, cadDockWidget) #Asignacion inicial self.canvas = canvas self.pluginM = pluginM self.modoDividir = False self.modoEliminar = False self.modoEditar = False self.moviendoVertice = False self.activate() for x in iface.advancedDigitizeToolBar().actions(): if x.objectName() == 'mEnableAction': self.botonAD = x self.relaciones = {} self.punteroRelaciones = 0 self.relaciones[self.punteroRelaciones] = RelacionRubberGeom( self.crearNuevoRubberLinea(), None) self.rubberPunto = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rubberPunto.setFillColor(QColor(0, 0, 0, 0)) self.rubberPunto.setStrokeColor(QColor(255, 0, 0, 255)) self.rubberPunto.setWidth(6) self.primerClick = False self.snapper = self.canvas.snappingUtils() self.listaPuntosLineaTemp = [] self.cuentaClickLinea = 0 self.relacionEnEdicion = -1 #-------------------------------------------------------------------------------------------- def cadCanvasPressEvent(self, event): print('canvasPressEvent') x = event.pos().x() y = event.pos().y() startingPoint = QtCore.QPoint(x, y) trans = self.canvas.getCoordinateTransform().toMapCoordinates(x, y) posTemp = self.canvas.getCoordinateTransform().toMapCoordinates(x, y) toAdvanced = (self.cadDockWidget().constraintAngle().isLocked() or self.cadDockWidget().constraintDistance().isLocked() or self.cadDockWidget().constraintX().isLocked() or self.cadDockWidget().constraintY().isLocked()) puntoSnap = self.snapCompleto(startingPoint, toAdvanced) if not toAdvanced: if puntoSnap != None: self.cadDockWidget().setX(str(puntoSnap.x()), 2) self.cadDockWidget().setY(str(puntoSnap.y()), 2) else: self.cadDockWidget().setX(str(x), 2) self.cadDockWidget().setY(str(y), 2) if self.modoDividir: # ----- Modo Dividir ---- # if event.buttons() == Qt.LeftButton: self.puntoLineaTemp = self.toMapCoordinates(event.pos()) geoTemp = QgsPoint(trans.x(), trans.y()) self.cuentaClickLinea += 1 if puntoSnap != None: #Cuando tenemos snap ------------# self.listaPuntosLineaTemp.append(puntoSnap) self.isEmittingPoint = True marcador = self.crearNuevoMarcaVert() self.relaciones[self.punteroRelaciones].marcadores.append( marcador) marcador.setCenter(puntoSnap) else: #Cuando no tenemos snap ------------- # self.listaPuntosLineaTemp.append(self.puntoLineaTemp) self.isEmittingPoint = True marcador = self.crearNuevoMarcaVert() self.relaciones[self.punteroRelaciones].marcadores.append( marcador) marcador.setCenter(self.puntoLineaTemp) if not self.primerClick: self.primerClick = True if event.buttons() == Qt.RightButton: #Click derecho self.primerClick = False print(self.relaciones) if self.cuentaClickLinea >= 2: #Cuando son mas de dos puntos self.isEmittingPoint = False self.cuentaClickLinea = 0 self.primerClick = False self.relaciones[self.punteroRelaciones].rubber.reset( QgsWkbTypes.LineGeometry) #Vaciamos el rubber rango = len( self.listaPuntosLineaTemp ) - 1 #Agregamos todos los puntos al rubber excepto el ultimo for x in range(0, rango): punto = self.listaPuntosLineaTemp[x] self.relaciones[ self.punteroRelaciones].rubber.addPoint( punto, True) geometriaR = QgsGeometry( self.relaciones[self.punteroRelaciones].rubber. asGeometry()) #Ponemos la geometria en la relacion self.relaciones[self.punteroRelaciones].geom = geometriaR vertices = self.obtenerVerticesLinea( geometriaR) #Obtenemos los vertices de la geometria self.relaciones[self.punteroRelaciones].rubber.reset( QgsWkbTypes.LineGeometry) #Vaciamos el rubber for vertice in vertices: #Ponemos los vertices en el rubber #self.relaciones[self.punteroRelaciones].rubber.addPoint(QgsPointXY(vertice.x(), vertice.y()), True) self.relaciones[ self.punteroRelaciones].rubber.addPoint( vertice, True) self.relaciones[self.punteroRelaciones].rubber.show() self.listaPuntosLineaTemp = [] self.punteroRelaciones += 1 #Agregamos otro Rubber self.relaciones[ self.punteroRelaciones] = RelacionRubberGeom( self.crearNuevoRubberLinea(), None) else: self.relaciones[self.punteroRelaciones].rubber.reset( QgsWkbTypes.LineGeometry) self.listaPuntosLineaTemp = [] self.relaciones[self.punteroRelaciones].geom = None elif self.modoEliminar: #-------Modo Elimina-------------# if event.buttons() == Qt.LeftButton: geomClick = QgsGeometry(QgsGeometry.fromPointXY(posTemp)) bufferClick = geomClick.buffer(0.25, 1) relacion = self.obtenerRelacionCercana(bufferClick) if relacion != None: relacion.rubber.reset(QgsWkbTypes.LineGeometry) relacion.geom = None relacion.vaciarMarcadores() elif self.modoEditar: #--------------Modo Editar---------# print('un clic') geomClick = QgsGeometry(QgsGeometry.fromPointXY(posTemp)) bufferClick = geomClick.buffer(0.25, 1) relacion = self.obtenerRelacionCercana(bufferClick) if event.buttons( ) == Qt.LeftButton: #---------Click Izquierdo ------# if not self.moviendoVertice: #Cuando NO estamos moviendo un vertice y buscamos mover uno print('moviendoVertice') if relacion != None: print('relacion') relacion.rubber.setStrokeColor(QColor( 255, 170, 0, 255)) iface.mapCanvas().refresh() vertices = self.obtenerVerticesLinea(relacion.geom) verticeSeleccionado = None for vertice in vertices: #Aqui buscamos el vertice cercano al click geomVertice = QgsGeometry( QgsGeometry.fromPointXY(vertice)).buffer( 2.25, 1) if geomVertice.intersects(bufferClick): verticeSeleccionado = vertice break if verticeSeleccionado != None: #aqui tenemos ya un vertice jalando para arrastrase print('verticeSeleccionado') self.listaPuntosLineaTemp = [] self.indiceSeleccionado = vertices.index(vertice) self.moviendoVertice = True for vertice in vertices: self.listaPuntosLineaTemp.append(vertice) else: #Cuando estamos moviendo un vertice y queremos soltarlo print('moviendoVertice else') self.moviendoVertice = False rel = self.relaciones[self.relacionEnEdicion] rel.geom = rel.rubber.asGeometry() rel.rubber.setStrokeColor(QColor(0, 62, 240, 255)) self.punteroRelaciones = len(self.relaciones) self.relaciones[ self.punteroRelaciones] = RelacionRubberGeom( self.crearNuevoRubberLinea(), None) self.listaPuntosLineaTemp = [] print('///////////////////////////////////') print(self.pluginM.VentanaAreas, type(self.pluginM.VentanaAreas)) print(self.pluginM, type(self.pluginM)) print('///////////////////////////////////') #self.pluginM.VentanaAreas.close() iface.mapCanvas().refresh() elif event.buttons( ) == Qt.RightButton: #--------Click Derecho -----# Para agregar vertices personales if relacion != None: inter = bufferClick.intersection( relacion.geom.buffer(0.000004, 1) ) #Checamos la interseccion con la linea a editar c = inter.centroid().asPoint( ) #Obtenemos el centroide, aqui se pintara el vertice vertices1 = self.obtenerVerticesLinea( relacion.geom) #Obtenemos todos los vertices acutales rango = len(vertices1) posiblesX = [] for x in range(0, rango - 1): #Recorremos todos los vertices v1 = vertices1[x] #Punto izqueirdo v2 = vertices1[x + 1] #punto derecho par = (v1, v2) if v1.x() <= v2.x( ): #Cuando el primer punto esta a la izquierda if c.x() >= v1.x() and c.x() <= v2.x(): posiblesX.append(par) else: #Cuando el primer punto esta a la derecha if c.x() <= v1.x() and c.x() >= v2.x(): posiblesX.append(par) for pa in posiblesX: #Checamos todos los posibles que se encuentren en el eje X v1 = pa[0] v2 = pa[1] if v1.y() <= v2.y( ): #Cuando el primer punto esta abajo if c.y() >= v1.y() and c.y() <= v2.y(): salidaY = pa break else: #Cuando esta arriba if c.y() <= v1.y() and c.y() >= v2.y(): salidaY = pa break indiceI = vertices1.index(salidaY[0]) indiceD = vertices1.index(salidaY[1]) vertices2 = [] relacion.vaciarMarcadores() for x in range( 0, rango ): #Generamos lista d epuntos que incluyan el nuevo if x == indiceD: vertices2.append(c) nuevo = self.crearNuevoMarcaVert() centroM = QgsPointXY(c.x(), c.y()) nuevo.setCenter(centroM) relacion.marcadores.append(nuevo) vertices2.append(vertices1[x]) nuevo = self.crearNuevoMarcaVert() centroM = QgsPointXY(vertices1[x].x(), vertices1[x].y()) nuevo.setCenter(centroM) relacion.marcadores.append(nuevo) else: vertices2.append(vertices1[x]) nuevo = self.crearNuevoMarcaVert() centroM = QgsPointXY(vertices1[x].x(), vertices1[x].y()) nuevo.setCenter(centroM) relacion.marcadores.append(nuevo) relacion.rubber.reset(QgsWkbTypes.LineGeometry) for punto in vertices2: #Regeneramos el rubber puntoXY = QgsPointXY(punto.x(), punto.y()) relacion.rubber.addPoint(puntoXY, True) relacion.geom = relacion.rubber.asGeometry() #----------------------------------------------------------------------- def cadCanvasMoveEvent(self, event): x = event.pos().x() y = event.pos().y() startingPoint = QtCore.QPoint(x, y) posTemp = self.canvas.getCoordinateTransform().toMapCoordinates(x, y) toAdvanced = (self.cadDockWidget().constraintAngle().isLocked() or self.cadDockWidget().constraintDistance().isLocked() or self.cadDockWidget().constraintX().isLocked() or self.cadDockWidget().constraintY().isLocked()) puntoSnap = self.snapCompleto(startingPoint, toAdvanced) if not toAdvanced: if puntoSnap != None: self.cadDockWidget().setX(str(puntoSnap.x()), 2) self.cadDockWidget().setY(str(puntoSnap.y()), 2) else: self.cadDockWidget().setX(str(x), 2) self.cadDockWidget().setY(str(y), 2) if self.modoDividir: self.relaciones[self.punteroRelaciones].rubber.reset( QgsWkbTypes.LineGeometry) self.rubberPunto.reset(QgsWkbTypes.PointGeometry) if puntoSnap != None: puntoSnapXY = QgsPointXY(puntoSnap.x(), puntoSnap.y()) self.rubberPunto.addPoint(puntoSnapXY, True) self.rubberPunto.show() if self.primerClick: if (len(self.listaPuntosLineaTemp) > 1): if puntoSnap != None: self.listaPuntosLineaTemp[-1] = puntoSnapXY else: self.listaPuntosLineaTemp[-1] = posTemp for punto in self.listaPuntosLineaTemp[:-1]: self.relaciones[ self.punteroRelaciones].rubber.addPoint( punto, False) self.relaciones[self.punteroRelaciones].rubber.addPoint( self.listaPuntosLineaTemp[-1], True) self.relaciones[self.punteroRelaciones].rubber.show() else: if puntoSnap != None: self.listaPuntosLineaTemp.append(puntoSnapXY) else: self.listaPuntosLineaTemp.append(posTemp) self.relaciones[self.punteroRelaciones].rubber.addPoint( self.listaPuntosLineaTemp[0], True) self.relaciones[self.punteroRelaciones].rubber.show() elif self.modoEditar: #-modo editar if self.moviendoVertice: #Arrastrando un vertice self.rubberPunto.reset(QgsWkbTypes.PointGeometry) if puntoSnap != None: puntoSnapXY = QgsPointXY(puntoSnap.x(), puntoSnap.y()) self.rubberPunto.addPoint(puntoSnapXY, True) self.rubberPunto.show() self.listaPuntosLineaTemp[ self.indiceSeleccionado] = puntoSnapXY self.relaciones[self.relacionEnEdicion].marcadores[ self.indiceSeleccionado].setCenter(puntoSnapXY) else: self.listaPuntosLineaTemp[ self.indiceSeleccionado] = posTemp self.relaciones[self.relacionEnEdicion].marcadores[ self.indiceSeleccionado].setCenter(posTemp) self.relaciones[self.relacionEnEdicion].rubber.reset( QgsWkbTypes.LineGeometry) for punto in self.listaPuntosLineaTemp: self.relaciones[self.relacionEnEdicion].rubber.addPoint( punto, True) self.relaciones[self.relacionEnEdicion].rubber.show() #-------------------------------------------------------------------------------------# def snapVertice(self, startingPoint, nombreCapa): layer = QgsProject.instance().mapLayer( self.pluginM.ACA.obtenerIdCapa(nombreCapa)) self.snapper.setCurrentLayer(layer) snapMatch = self.snapper.snapToCurrentLayer(startingPoint, QgsPointLocator.Vertex) if snapMatch.hasVertex(): return snapMatch.point() #------------------------------------------------------------------------------------# def snapArista(self, startingPoint, nombreCapa): layer = QgsProject.instance().mapLayer( self.pluginM.ACA.obtenerIdCapa(nombreCapa)) self.snapper.setCurrentLayer(layer) snapMatch = self.snapper.snapToCurrentLayer(startingPoint, QgsPointLocator.Edge) if snapMatch.hasEdge(): return snapMatch.point() #----------------------------------------------------------------------------------- def snapCompleto(self, startingPoint, toAdvanced): # Si obedeceremos la herramienta de digitalizacion avanzada... if toAdvanced: cadWidget = self.cadDockWidget() return cadWidget.currentPoint()[0] snap = self.snapVertice(startingPoint, 'predios.geom') #----vertices -----# if snap != None: return snap else: snap = self.snapVertice(startingPoint, 'construcciones') if snap != None: return snap else: snap = self.snapVertice(startingPoint, 'horizontales.geom') if snap != None: return snap else: snap = self.snapVertice( startingPoint, 'verticales') #-----Hasta aqui son vertices -----# if snap != None: return snap else: snap = self.snapArista(startingPoint, 'predios.geom') if snap != None: return snap else: snap = self.snapArista(startingPoint, 'construcciones') if snap != None: return snap else: snap = self.snapArista(startingPoint, 'horizontales.geom') if snap != None: return snap else: snap = self.snapArista( startingPoint, 'verticales' ) #-------- hasta aqui aristas-----------# if snap != None: return snap else: return None #---------------------------------------------------------------------------------------------- def crearNuevoRubberLinea(self): nuevoRubber = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) nuevoRubber.setFillColor(QColor(0, 0, 0, 0)) nuevoRubber.setStrokeColor(QColor(0, 62, 240, 255)) nuevoRubber.setWidth(2) #penStyle = Qt.PenStyle() nuevoRubber.setLineStyle(Qt.PenStyle(3)) return nuevoRubber #------------------------------------------------------------------------------------------ def crearNuevoRubberPoly(self): nuevoRubber = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) color = QColor(r, g, b, 36) colorAg = QColor(r, g, b, 87) self.pluginM.listaColores.append(colorAg) nuevoRubber.setFillColor(color) nuevoRubber.setStrokeColor(QColor(r, g, b, 255)) nuevoRubber.setWidth(2) return nuevoRubber #------------------------------------------------------------------------------------- def recargarRelaciones(self): self.relaciones = {} self.punteroRelaciones = 0 self.relaciones[self.punteroRelaciones] = RelacionRubberGeom( self.crearNuevoRubberLinea(), None) #----------------------------------------------------------------------------------------- def prueba(self, e): print(e) #---------------------------------------------------------------------------------- def obtenerRelacionCercana(self, punto): rango = len(self.relaciones) - 1 for i in range(0, rango): relacion = self.relaciones[i] geom = relacion.geom if geom != None: if geom.buffer(0.000004, 1).intersects(punto): self.relacionEnEdicion = i return relacion #----------------------------------------------------------------------------------- def obtenerVertices(self, geom): n = 0 ver = geom.vertexAt(0) vertices = [] while (ver != QgsPoint(0, 0)): n += 1 vertices.append(ver) ver = geom.vertexAt(n) return vertices def obtenerVerticesLinea(self, geom): return geom.asPolyline() def crearNuevoMarcaVert(self): marcador = QgsVertexMarker(iface.mapCanvas()) marcador.setColor(QColor(0, 255, 0)) marcador.setIconSize(5) marcador.setIconType(QgsVertexMarker.ICON_BOX) marcador.setPenWidth(3) return marcador
class RectangleMapTool(QgsMapToolEmitPoint): rectangleCreated = pyqtSignal() def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rubberBand.setColor(QColor(255, 0, 0, 100)) self.rubberBand.setWidth(2) self.reset() def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.showRect(self.startPoint, self.endPoint) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rectangleCreated.emit() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) self.showRect(self.startPoint, self.endPoint) def showRect(self, startPoint, endPoint): self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y(): return point1 = QgsPoint(startPoint.x(), startPoint.y()) point2 = QgsPoint(startPoint.x(), endPoint.y()) point3 = QgsPoint(endPoint.x(), endPoint.y()) point4 = QgsPoint(endPoint.x(), startPoint.y()) self.rubberBand.addPoint(point1, False) self.rubberBand.addPoint(point2, False) self.rubberBand.addPoint(point3, False) self.rubberBand.addPoint(point4, True) # true to update canvas self.rubberBand.show() def rectangle(self): if self.startPoint is None or self.endPoint is None: return None elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y( ) == self.endPoint.y(): return None return QgsRectangle(self.startPoint, self.endPoint) def setRectangle(self, rect): if rect == self.rectangle(): return False if rect is None: self.reset() else: self.startPoint = QgsPoint(rect.xMaximum(), rect.yMaximum()) self.endPoint = QgsPoint(rect.xMinimum(), rect.yMinimum()) self.showRect(self.startPoint, self.endPoint) return True def deactivate(self): QgsMapTool.deactivate(self) self.deactivated.emit()
class EditTool(MapTool): """ Inspection tool which copies the feature to a new layer and copies selected data from the underlying feature. """ finished = pyqtSignal(QgsVectorLayer, QgsFeature) def __init__(self, canvas, layers, snapradius=2): MapTool.__init__(self, canvas, layers) self.canvas = canvas self.radius = snapradius self.band = QgsRubberBand(self.canvas) self.band.setColor(QColor.fromRgb(224, 162, 16)) self.band.setWidth(3) self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) def getFeatures(self, point): searchRadius = (QgsTolerance.toleranceInMapUnits( self.radius, self.layers[0], self.canvas.mapRenderer(), QgsTolerance.Pixels)) point = self.toMapCoordinates(point) rect = QgsRectangle() rect.setXMinimum(point.x() - searchRadius) rect.setXMaximum(point.x() + searchRadius) rect.setYMinimum(point.y() - searchRadius) rect.setYMaximum(point.y() + searchRadius) rq = QgsFeatureRequest().setFilterRect(rect) self.band.reset() for layer in self.layers: rq = QgsFeatureRequest().setFilterRect(rect) for feature in layer.getFeatures(rq): if feature.isValid(): yield feature, layer def canvasMoveEvent(self, event): for feature, _ in self.getFeatures(point=event.pos()): self.band.addGeometry(feature.geometry(), None) def canvasReleaseEvent(self, event): features = list(self.getFeatures(point=event.pos())) if len(features) == 1: feature = features[0] self.finished.emit(feature[1], feature[0]) elif len(features) > 0: listUi = ListFeaturesForm() listUi.loadFeatureList(features) listUi.openFeatureForm.connect(self.finished) listUi.exec_() def activate(self): """ Set the tool as the active tool in the canvas. @note: Should be moved out into qmap.py and just expose a cursor to be used """ self.canvas.setCursor(self.cursor) def deactivate(self): """ Deactive the tool. """ pass def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True
class Dialog(QDialog, Ui_nbEditor_dialog): def __init__(self, iface, ml, mc): """Constructor for the dialog. Args: iface: QgsInterface instance. """ QDialog.__init__(self, iface.mainWindow()) self.setupUi(self) self.ml = ml self.mCanvas = mc self.mRubberBand = QgsRubberBand(self.mCanvas, True) self.mRubberBand.reset(QgsWkbTypes.PolygonGeometry) self.mRubberBand.setColor(Qt.red) self.mRubberBand.setWidth(2) self.ids = [] self.ini(0) self.pushCancel.clicked.connect(self.close) self.pushOK.clicked.connect(self.convert) self.comboBox.addItems( ['', 'Intersections', 'Touches', 'Within distance']) self.comboBox.currentIndexChanged.connect(self.nbMethod) self.ml.selectionChanged.connect(self.map2tab) def ini(self, n): self.model = QStandardItemModel(n, 1) self.tableView.setModel(self.model) self.model.setHeaderData(0, Qt.Horizontal, 'Neighbouring IDs') self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.selectionModel = QItemSelectionModel(self.model) self.tableView.setSelectionModel(self.selectionModel) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.selectionModel().selectionChanged.connect(self.tab2map) self.progressBar.setValue(0) def settings(self): self.mod = min(self.ids) self.p = 1 if self.mod == 1: self.p = 0 def map2tab(self): s = '' idx = self.tableView.selectionModel().selectedIndexes()[0] ts = str(self.model.itemData(idx)[0]) for fid in sorted(self.ml.selectedFeatureIds()): s += '%s,' % str(int(fid) + self.p) s = s[:-1] if s != ts: self.model.setData(idx, s) # in order to handle the symmetry if len(s) > len(ts): iLst = s.strip().replace(' ', '').split(',') jLst = ts.strip().replace(' ', '').split(',') else: iLst = ts.strip().replace(' ', '').split(',') jLst = s.strip().replace(' ', '').split(',') cent = str(idx.row() + self.p) dLst = list(set(iLst) - set(jLst)) for d in dLst: row = int(d) - self.p sor = str(self.model.itemData(self.model.index(row, 0))[0]) eLst = sor.strip().replace(' ', '').split(',') res = '' if cent in set(eLst): ii = eLst.index(cent) del eLst[ii] eLst = sorted(map(int, eLst)) for e in eLst: res += '%s,' % e res = res[:-1] else: u = sor + ',%s' % cent eLst = sorted(map(int, u.strip().replace(' ', '').split(','))) for e in eLst: res += '%s,' % e res = res[:-1] self.model.setData(self.model.index(row, 0, QModelIndex()), res) def nbWithinDist(self): dlg = xdist.Dialog() dlg.setModal(True) dlg.setWindowTitle("Between two objects") if dlg.exec_() == QDialog.Accepted: lDist = float(dlg.lineEdit.text()) if lDist == 0: return feat = QgsFeature() provider = self.ml.dataProvider() e = provider.featureCount() self.settings() for ne in range(self.mod, e + self.mod): feat = QgsFeature() geom = QgsGeometry() fiter = self.ml.getFeatures(QgsFeatureRequest(ne)) if fiter.nextFeature(feat): geom = QgsGeometry(feat.geometry()) neighbours = self.hdist(feat, lDist) row = feat.id() - self.mod self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours) self.progressBar.setValue(100 * ne / e) def hdist(self, feata, lDist): geoma = QgsGeometry(feata.geometry()) feat = QgsFeature() provider = self.ml.dataProvider() feats = provider.getFeatures() #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0) #self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) ne = 0 neighbours = "" while feats.nextFeature(feat): ne += 1 #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne) geomb = QgsGeometry(feat.geometry()) if feata.id() != feat.id(): if geoma.distance(geomb) <= lDist: neighbours = neighbours + '%s,' % (feat.id() + self.p) return neighbours[:-1] def tab2map(self): QApplication.setOverrideCursor(Qt.WaitCursor) self.ml.selectionChanged.disconnect(self.map2tab) idx = self.tableView.selectionModel().selectedIndexes()[0] featureId = idx.row() + self.p s = self.model.itemData(idx) lst = s[0].strip().replace(' ', '').split(',') self.ml.removeSelection() for sid in lst: self.ml.select(int(sid) - self.p) provider = self.ml.dataProvider() feat = QgsFeature() layer = QgsVectorLayerCache(self.ml, provider.featureCount()) layer.featureAtId(idx.row() + self.mod, feat) geom = QgsGeometry(feat.geometry()) self.mRubberBand.setToGeometry(geom, self.ml) self.mRubberBand.show() self.ml.selectionChanged.connect(self.map2tab) QApplication.restoreOverrideCursor() def closeEvent(self, event): QApplication.setOverrideCursor(Qt.WaitCursor) self.ml.selectionChanged.disconnect(self.map2tab) self.ml.removeSelection() self.mRubberBand.hide() self.close() QApplication.restoreOverrideCursor() def convert(self): dlg = editordlg() dlg.setModal(True) dlg.setWindowTitle("Neighbour list in BUGS format") num = "" adj = "" sumNumNeigh = 0 for row in range(0, self.model.rowCount()): ts = self.model.itemData(self.model.index(row, 0)) lst = ts[0].strip().replace(' ', '').split(',') num += '%s, ' % len(lst) sumNumNeigh += len(lst) lst.reverse() sor = ', '.join(lst) + ',' adj = adj + str(sor) + '\n' num = num[:-2] adj = adj[:-2] nblist = 'list(\nnum = c(%s),\nadj = c(%s),\nsumNumNeigh=%s)' % ( num, adj, sumNumNeigh) dlg.plainTextEdit.appendPlainText(nblist) dlg.exec_() def nbMethod(self): QApplication.setOverrideCursor(Qt.WaitCursor) self.ml.selectionChanged.disconnect(self.map2tab) self.model.removeRows(0, self.model.rowCount(QModelIndex()), QModelIndex()) n = self.ml.dataProvider().featureCount() self.ini(n) self.ids = [] provider = self.ml.dataProvider() feats = provider.getFeatures() #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0) #self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, n)) ne = 0 feat = QgsFeature() while feats.nextFeature(feat): ne += 1 #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne) self.ids.append(feat.id()) if self.comboBox.currentText() == "Touches": if self.ml.geometryType() == 0: return else: self.nbTouches() if self.comboBox.currentText() == "Intersections": if self.ml.geometryType() == 0: return else: self.nbIntersects() if self.comboBox.currentText() == "Within distance": self.nbWithinDist() self.ml.selectionChanged.connect(self.map2tab) QApplication.restoreOverrideCursor() def nbTouches(self): feat = QgsFeature() provider = self.ml.dataProvider() e = provider.featureCount() self.settings() for ne in range(self.mod, e + self.mod): feat = QgsFeature() geom = QgsGeometry() fiter = self.ml.getFeatures(QgsFeatureRequest(ne)) if fiter.nextFeature(feat): geom = QgsGeometry(feat.geometry()) neighbours = self.htouch(feat) row = feat.id() - self.mod self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours) self.progressBar.setValue(100 * ne / e) def htouch(self, feata): geoma = QgsGeometry(feata.geometry()) feat = QgsFeature() provider = self.ml.dataProvider() feats = provider.getFeatures() #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0) #self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) ne = 0 neighbours = "" while feats.nextFeature(feat): ne += 1 #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne) geomb = QgsGeometry(feat.geometry()) if feata.id() != feat.id(): if geoma.touches(geomb) == True: neighbours = neighbours + '%s,' % (feat.id() + self.p) return neighbours[:-1] def nbIntersects(self): feat = QgsFeature() provider = self.ml.dataProvider() e = provider.featureCount() self.settings() for ne in range(self.mod, e + self.mod): feat = QgsFeature() geom = QgsGeometry() fiter = self.ml.getFeatures(QgsFeatureRequest(ne)) if fiter.nextFeature(feat): geom = QgsGeometry(feat.geometry()) neighbours = self.hintersect(feat) row = feat.id() - self.mod self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours) self.progressBar.setValue(100 * ne / e) def hintersect(self, feata): geoma = QgsGeometry(feata.geometry()) feat = QgsFeature() provider = self.ml.dataProvider() feats = provider.getFeatures() #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0) #self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) ne = 0 neighbours = "" while feats.nextFeature(feat): ne += 1 #self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne) geomb = QgsGeometry(feat.geometry()) if feata.id() != feat.id(): if geoma.intersects(geomb) == True: neighbours = neighbours + '%s,' % (feat.id() + self.p) return neighbours[:-1]
class OneSideBuffer_tool(QgsMapToolIdentify): deact = pyqtSignal() def __init__(self, iface, action, plugin_dir, spinbox): self.canvas = iface.mapCanvas() self.iface = iface self.action = action self.icon_path = os.path.join(plugin_dir,"icons") self.spinbox = spinbox self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.GeometryType(3)) self.rubberBand.setWidth(3) self.rubberBand.setStrokeColor(QColor(254,0,0)) self.snap_mark = QgsVertexMarker(self.canvas) self.snap_mark.setColor(QColor(0, 0, 255)) self.snap_mark.setPenWidth(2) self.snap_mark.setIconType(QgsVertexMarker.ICON_BOX) self.snap_mark.setIconSize(10) QgsMapToolIdentify.__init__(self, self.canvas) self.selectFeatureMode = True self.firstPointMode = False self.secondPointMode = False self.objectSizeMode = False self.firstPoint_locate = None self.linestring = None self.dist = self.spinbox.value() self.canvas.layersChanged.connect(self.setPolygonLayers) def activate(self): self.setCursor(Qt.CrossCursor) self.setPolygonLayers() def addMenu(self): menu = QMenu() self.setPolygonLayers() for i in self.getVisibleLayers(): action = menu.addAction(i.name()) action.triggered.connect(lambda ch, i=i: self.addFeature(i)) menu.exec_(QCursor.pos()) def addFeature(self, dest_layer): geometry_canvas = self.geom_poly for l in self.getVisibleLayers(): geometry_canvas = self.getDifferenceGeometry(geometry_canvas, l) # dump geom if it s multipart geometry_parts = [p for p in geometry_canvas.parts()] for part in geometry_parts: part_wkt = part.asWkt() part_geom = QgsGeometry.fromWkt(part_wkt) if part_geom.isGeosValid() == False: part_geom = part_geom.makeValid() if part_geom.isGeosValid() == True and part_geom.area() > 0.1: self.addTopologicalPointsForActiveLayers(part_geom) feature = QgsVectorLayerUtils.createFeature(dest_layer) feature.setGeometry(part_geom) height_col_idx = dest_layer.fields().indexFromName('SZEROKOSC') if height_col_idx != -1: feature.setAttribute(height_col_idx, self.dist) if not dest_layer.isEditable(): dest_layer.startEditing() dest_layer.addFeature(feature) self.iface.openFeatureForm(dest_layer, feature, False) def addTopologicalPointsForActiveLayers(self, geometry): geometry = QgsGeometry(geometry) layers = self.getVisibleLayers() for layer in layers: if not layer.isEditable(): layer.startEditing() topology = QgsVectorLayerEditUtils(layer) vertices = [v for v in geometry.vertices()] for v in vertices: point = v.asWkt() point = QgsGeometry.fromWkt(point) point = point.asPoint() topology.addTopologicalPoints(point) return True def calculateSide(self , linestring, point): segment = linestring.closestSegmentWithContext(point.asPoint()) if segment[3] < 0: return 2 else: return 1 def canvasMoveEvent(self, e ): if self.firstPointMode == True or self.secondPointMode == True: self.snapPoint = self.checkSnapToPoint(e.pos()) if self.snapPoint[0]: self.snap_mark.setCenter(self.snapPoint[1]) self.snap_mark.show() self.point = QgsGeometry.fromPointXY (self.snapPoint[1]) else: self.snap_mark.hide() self.point = QgsGeometry.fromPointXY (self.toMapCoordinates(e.pos())) if self.secondPointMode: self.secondPoint_locate = self.linestring.lineLocatePoint(self.point) self.output_geom = self.lineSubstring(self.linestring,self.firstPoint_locate,self.secondPoint_locate) if self.output_geom != None: self.rubberBand.setToGeometry(self.output_geom, None) self.rubberBand.show() if self.objectSizeMode: s_point = QgsGeometry.fromPointXY (self.toMapCoordinates(e.pos())) #if round(abs(self.output_geom.distance(s_point) - self.dist),1) >= self.spinbox.value(): #self.dist = round(self.output_geom.distance(s_point)/self.spinbox.value(),1) self.dist = int(self.output_geom.distance(s_point)/self.spinbox.value()) self.dist = self.dist * self.spinbox.value() QToolTip.showText( self.canvas.mapToGlobal( self.canvas.mouseLastXY() ), str(round(self.dist,2)), self.canvas ) left_or_right = self.calculateSide(self.output_geom, s_point) self.geom_poly = self.output_geom.singleSidedBuffer(self.dist,20,left_or_right,2) self.rubberBand.setToGeometry(self.geom_poly, None) self.rubberBand.show() def canvasPressEvent (self, e): if e.button() == Qt.LeftButton: layerType = getattr(QgsMapToolIdentify,'VectorLayer') results = self.identify(e.x(), e.y(), self.TopDownStopAtFirst ,layerType) if self.selectFeatureMode: if len(results) == 0 or results[0].mLayer not in [l for l in self.polygonLayers]: for l in self.polygonLayers: l.removeSelection() elif len(results) > 0: for l in self.polygonLayers: try: l.removeSelection() except: pass self.current_layer = self.cur_lyr = results[0].mLayer self.current_feature = QgsFeature(results[0].mFeature) self.current_layer.select(self.current_feature.id()) self.iface.setActiveLayer(self.current_layer) self.selectFeatureMode = False self.firstPointMode = True elif self.firstPointMode: self.linestring = self.polygon2Linestring(self.current_feature.geometry(), e.pos()) self.firstPoint_locate = self.linestring.lineLocatePoint(self.point) self.firstPointMode = False self.secondPointMode = True elif self.secondPointMode: self.secondPointMode = False self.objectSizeMode = True self.dist = self.spinbox.value() elif self.objectSizeMode: self.objectSizeMode = False self.addMenu() self.reset() def checkSnapToPoint(self, point): snapped = False snap_point = self.toMapCoordinates(point) snapper = self.canvas.snappingUtils() snapMatch = snapper.snapToMap(point) if snapMatch.hasVertex(): snap_point = snapMatch.point() snapped = True return snapped, snap_point def deactivate(self): self.action.setChecked(False) self.rubberBand.hide() self.deact.emit() def getDifferenceGeometry(self, geometry, layer): geometry = QgsGeometry(geometry) bbox = geometry.boundingBox() for f in layer.getFeatures(bbox): f_geom = f.geometry() if f_geom.isGeosValid() == False: f_geom = f_geom.makeValid() if f_geom.isGeosValid() == True: if geometry.intersects(f_geom): geometry = geometry.difference(f_geom) return geometry def getVisibleLayers(self): array = [] root = QgsProject.instance().layerTreeRoot() for l in self.polygonLayers: node = root.findLayer(l.id()) if node: visible = node.isVisible () if visible: array.append(l) return array def keyPressEvent (self,e): if e.key() == Qt.Key_Escape: self.reset() def lineSubstring(self, linestring, start, end): array = [linestring.lineLocatePoint(QgsGeometry.fromWkt(i.asWkt())) for i in linestring.vertices()] one_array = [] second_array = [] # 1 Geom if start < end: one_array.append(start) for i in array: if i > start and i < end: one_array.append(i) one_array.append(end) else: one_array.append(start) for i in array: if i > start: one_array.append(i) one_array.append(0.0) for i in array: if i < end and i > 0: one_array.append(i) one_array.append(end) # 2 Geom if start < end: second_array.append(end) for i in array: if i > end: second_array.append(i) second_array.append(0.0) for i in array: if i < start and i > 0: second_array.append(i) second_array.append(start) else: second_array.append(end) for i in array: if i > end and i < start: second_array.append(i) second_array.append(start) one_geom = QgsGeometry.fromPolylineXY([linestring.interpolate(i).asPoint() for i in one_array]) second_geom = QgsGeometry.fromPolylineXY([linestring.interpolate(i).asPoint() for i in second_array]) if second_geom.length() < one_geom.length(): self.linestring_rev = True return (second_geom) else: self.linestring_rev = False return(one_geom) def point2LayerCoordinate(self, pos, layer): layer_crs = layer.crs().authid() canvas_crs = self.canvas.mapSettings().destinationCrs().authid() point = self.toMapCoordinates(pos) point = QgsGeometry.fromPointXY(point) point = self.geometryCrs2Crs(point, canvas_crs, layer_crs) return point def polygon2Linestring(self, poly_geom, pos): geom_parts = [p for p in poly_geom.parts()] pos_geom = QgsGeometry.fromPointXY (self.toMapCoordinates(pos)) cur_dist = None cur_geom = None for p in geom_parts: p_geom = QgsGeometry.fromWkt(p.asWkt()) p_geom = QgsGeometry.fromPolyline([p for p in p_geom.vertices()]) p_geom_dist = p_geom.distance(pos_geom) if cur_dist == None or p_geom_dist < cur_dist: cur_geom = p_geom cur_dist = p_geom_dist return cur_geom def reset(self): self.current_layer.removeSelection() self.selectFeatureMode = True self.firstPointMode = False self.secondPointMode = False self.firstPoint_locate = None self.linestring = None self.objectSizeMode = False self.snap_mark.hide() self.rubberBand.hide() self.dist = self.spinbox.value() def setPolygonLayers(self): self.polygonLayers = [] for l in QgsProject.instance().mapLayers(): layer = QgsProject.instance().mapLayer(l) if layer.type() == 0: # 0 = Vector layer if layer.geometryType() == 2: # 2 = Polygon layer self.polygonLayers.append(layer)