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 startFlashFeature(self, featureGeometry, layerCrs): geomType = QgsWkbTypes.geometryType(featureGeometry.wkbType()) rb = QgsRubberBand(iface.mapCanvas(), geomType) rb.addGeometry( featureGeometry, layerCrs ) flashes=3 duration=500 if geomType == QgsWkbTypes.LineGeometry or geomType == QgsWkbTypes.PointGeometry: rb.setWidth( 2 ) rb.setSecondaryStrokeColor( QColor( 255, 255, 255 ) ) if geomType == QgsWkbTypes.PointGeometry : rb.setIcon( QgsRubberBand.ICON_CIRCLE ) startColor = QColor(255, 0, 0, 255) startColor.setAlpha( 255 ) endColor = QColor(255, 0, 0, 0) endColor.setAlpha( 0 ) self.animation = QVariantAnimation( iface.mapCanvas() ) self.animation.finished.connect(lambda a=self.animation, b=rb: self.finishedAnimation(a, b)) self.animation.valueChanged.connect(lambda value, a=self.animation, b=rb, c=geomType: self.valueChangedAnimation(value, a, b, c)) self.animation.setDuration( duration * flashes ) self.animation.setStartValue( endColor ) midStep = 0.2 / flashes for i in range(flashes): start = float(i / flashes) self.animation.setKeyValueAt( start + midStep, startColor ) end = float(( i + 1 ) / flashes) if not(end == 1.0): self.animation.setKeyValueAt( end, endColor ) self.animation.setEndValue( endColor ) self.animation.start()
def getSnapRubberBand(self): rubberBand = QgsRubberBand(self.canvas, geometryType=QgsWkbTypes.PointGeometry) rubberBand.setFillColor(QColor(255, 0, 0, 40)) rubberBand.setSecondaryStrokeColor(QColor(255, 0, 0, 200)) rubberBand.setWidth(2) rubberBand.setIcon(QgsRubberBand.ICON_X) return rubberBand
class Create_points(QgsMapToolEmitPoint): def __init__(self, canvas): super(Create_points, self).__init__(canvas) self.points = QgsRubberBand(canvas, QgsWkbTypes.PointGeometry) def create_points_window(self): self.crt_pts_win = CreatePointsWindow() self.crt_pts_win.show() def canvasClicked(self, przycisk, punkt): print(przycisk, punkt) def deactivate(self): super(Create_points, self).deactivate() def canvasReleaseEvent(self, mouse_event): point = mouse_event.mapPoint() #print(point) dada = self.points.addPoint(point) #print(dada) self.points.setWidth(5) self.points.setIconSize(20) self.points.setIcon(QgsRubberBand.ICON_BOX) self.points.setColor(QColor('red'))
class wincan2qgep(QObject): name = u"&Wincan 2 QGEP" actions = None def __init__(self, iface): QObject.__init__(self) self.iface = iface self.actions = {} self.settings = MySettings() self.dlg = None # translation environment self.plugin_dir = os.path.dirname(__file__) locale = QSettings().value("locale/userLocale")[0:2] localePath = os.path.join(self.plugin_dir, 'i18n', 'wincan2qgep_{0}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) QCoreApplication.installTranslator(self.translator) 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 unload(self): """ Unload plugin """ for action in self.actions.itervalues(): self.iface.removePluginMenu(self.name, action) self.iface.removeToolBarIcon(action) if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber if self.dlg: self.dlg.close() @pyqtSlot(str, QgsMessageBar.MessageLevel) def displayMessage(self, message, level): self.iface.messageBar().pushMessage("Wincan 2 QGEP", message, level) def showSettings(self): if ConfigurationDialog().exec_(): self._reloadFinders() def openInspection(self): xmlPath = self.settings.value('xmlPath') if xmlPath == '': xmlPath = QgsProject.instance().homePath() filepath = QFileDialog.getOpenFileName(None, "Open WIncan inspection data", xmlPath, "Wincan file (*.xml)") #filepath = '/var/run/user/1000/gvfs/smb-share:server=s4laveyre.sige.ch,share=inspection_tv/SIGE_2014/Rapport 2014/SIGE 5004B 14/XML/Project.xml' if filepath: self.settings.set_value('xmlPath', os.path.dirname(os.path.realpath(filepath))) data = ImportData(filepath).data self.dlg = DataBrowserDialog(self.iface, data) self.dlg.show()
class DiviPluginHistoryDialog(QDialog, FORM_CLASS): def __init__(self, plugin, parent=None): """Constructor.""" super(DiviPluginHistoryDialog, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.plugin = plugin #self.iface = plugin.iface self.setupUi(self) self.initGui() 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 show(self, data=[]): model = self.tblHistory.model().sourceModel() model.addItems(data) if data: self.tblHistory.selectionModel().setCurrentIndex( model.index(0,0), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows ) super(DiviPluginHistoryDialog, self).show() def historyChanged(self): """ Reaload data if window is visible """ if self.isVisible(): self.plugin.showHistoryDialog() def currentHistoryChanged(self, current, previous): self.new_geometry.reset() self.old_geometry.reset() self.tblChanges.model().removeRows() if not current.isValid(): return item = current.data(Qt.UserRole) if item is None: data = {} else: data = current.data(Qt.UserRole).getDetails() with SetLocale_CtxDec(): extent = None if data.get('new_geometry'): wkt = CreateGeometryFromJson( json.dumps(data['new_geometry']) ).ExportToWkt() geom = QgsGeometry.fromWkt( wkt ) l = QgsVectorLayer('Point?crs=epsg:4326', 'asd', 'memory') self.new_geometry.setToGeometry( geom, l ) extent = QgsRectangle(geom.boundingBox()) if data.get('old_geometry'): wkt = CreateGeometryFromJson( json.dumps(data['old_geometry']) ).ExportToWkt() geom = QgsGeometry.fromWkt( wkt ) l = QgsVectorLayer('Point?crs=epsg:4326', 'asd', 'memory') self.old_geometry.setToGeometry( geom, l ) if extent is None: extent = QgsRectangle(geom.boundingBox()) else: extent.combineExtentWith( geom.boundingBox() ) if extent is not None: extent.grow(0.01) self.mapCanvas.setExtent( extent ) self.mapCanvas.refresh() if data.get('what_attributes', []): self.tblChanges.model().insertRows( 0, data.get('what_attributes', []) )
class TrackWidget(QWidget, Ui_Track): def __init__(self, parent=None): super(TrackWidget, self).__init__(parent) self.setupUi(self) self.title = "Display track" self.canvas = None self.band = None self.color_btn = None self.center = False self.position = None self.geom_type = None self.marker = None self.hidden = False self.centerButton.setEnabled(False) icon = QIcon(":/resources/mActionSave.svg") self.save_track_pushButton.setIcon(icon) self.save_track_pushButton.setToolTip("Save Track") self.save_track_pushButton.clicked.connect(self.save_track) def init(self, title, canvas, default_color, geom_type, marker): self.canvas = canvas self.geom_type = geom_type self.track_groupBox.setTitle(title) if marker: # Add marker self.marker = marker self.with_marker = True else: self.with_marker = False # Add rubber band self.band = QgsRubberBand(self.canvas, self.geom_type) if self.geom_type == QgsWkbTypes.PointGeometry: self.band.setIcon(QgsRubberBand.ICON_CIRCLE) self.band.setIconSize(12) else: self.band.setWidth(3) # Add color button widget for picking color self.color_btn = QgsColorButton() self.horizontal_layout_color.insertWidget(1, self.color_btn, 0, Qt.AlignLeft) self.color_btn.colorChanged.connect(self.color_changed) self.color_btn.setDefaultColor(default_color) self.color_btn.setColor(default_color) # Set signals self.centerButton.clicked.connect(self.center_to_location) self.clearTrackButton.clicked.connect(self.clear_track) def color_changed(self): transparent_color = QColor(self.color_btn.color()) transparent_color.setAlpha(80) self.band.setColor(transparent_color) if self.with_marker: self.marker.set_color(QColor(self.color_btn.color())) def add_position(self, position): self.band.addPoint(position) def track_update_canvas(self, position, heading): self.centerButton.setEnabled(True) self.position = position self.add_position(position) if self.with_marker: self.marker.set_center(position, heading) if self.isHidden(): if self.with_marker: self.marker.hide() self.band.hide() else: if self.with_marker: self.marker.show() self.band.show() def center_to_location(self): """ Center to last received position on the map. """ rect = QgsRectangle(self.position, self.position) self.canvas.setExtent(rect) self.canvas.zoomScale(400) self.canvas.refresh() def hide_band(self): self.band.hide() def hide_marker(self): if self.with_marker: self.marker.hide() def clear_track(self): self.band.reset(self.geom_type) def save_track(self): """ Save the track to disk """ layer_name, selected_filter = QFileDialog.getSaveFileName(None, 'Save Track', "", 'Shapefile (*.shp);;KML (*.kml);;GPX (*.gpx)') if layer_name != '': if self.geom_type == QgsWkbTypes.PointGeometry: geometric_object = "MultiPoint?crs=epsg:4326" else: geometric_object = "LineString?crs=epsg:4326" layer = QgsVectorLayer( geometric_object, layer_name, "memory") feature = QgsFeature() feature.setGeometry(self.band.asGeometry()) layer.dataProvider().addFeatures([feature]) if selected_filter == "Shapefile (*.shp)": if not layer_name.endswith('.shp'): layer_name = layer_name + '.shp' ret = QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "ESRI Shapefile") if ret == QgsVectorFileWriter.NoError: logger.info(layer.name() + " saved to " + layer_name) elif selected_filter == "KML (*.kml)": if not layer_name.endswith('.kml'): layer_name = layer_name + '.kml' QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "KML") elif selected_filter == "GPX (*.gpx)": if not layer_name.endswith('.gpx'): layer_name = layer_name + '.gpx' ds_options = list() ds_options.append("GPX_USE_EXTENSIONS=TRUE") QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "GPX", datasourceOptions=ds_options) def close(self): self.hide_band() self.hide_marker()
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.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) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon(QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class SwissLocatorFilter(QgsLocatorFilter): HEADERS = { b'User-Agent': b'Mozilla/5.0 QGIS Swiss Geoportal Locator Filter' } message_emitted = pyqtSignal(str, str, Qgis.MessageLevel, QWidget) def __init__(self, filter_type: FilterType, iface: QgisInterface = None, crs: str = None): """" :param filter_type: the type of filter :param locale_lang: the language of the locale. :param iface: QGIS interface, given when on the main thread (which will display/trigger results), None otherwise :param crs: if iface is not given, it shall be provided, see clone() """ super().__init__() self.type = filter_type self.rubber_band = None self.feature_rubber_band = None self.iface = iface self.map_canvas = None self.settings = Settings() self.transform_ch = None self.transform_4326 = None self.map_tip = None self.current_timer = None self.crs = None self.event_loop = None self.result_found = False self.access_managers = {} self.nam_map_tip = None self.nam_fetch_feature = None if crs: self.crs = crs self.lang = get_language() self.searchable_layers = searchable_layers(self.lang, restrict=True) if iface is not None: # happens only in main thread self.map_canvas = iface.mapCanvas() self.map_canvas.destinationCrsChanged.connect( self.create_transforms) self.rubber_band = QgsRubberBand(self.map_canvas, QgsWkbTypes.PointGeometry) self.rubber_band.setColor(QColor(255, 255, 50, 200)) self.rubber_band.setIcon(self.rubber_band.ICON_CIRCLE) self.rubber_band.setIconSize(15) self.rubber_band.setWidth(4) self.rubber_band.setBrushStyle(Qt.NoBrush) self.feature_rubber_band = QgsRubberBand( self.map_canvas, QgsWkbTypes.PolygonGeometry) self.feature_rubber_band.setColor(QColor(255, 50, 50, 200)) self.feature_rubber_band.setFillColor(QColor(255, 255, 50, 160)) self.feature_rubber_band.setBrushStyle(Qt.SolidPattern) self.feature_rubber_band.setLineStyle(Qt.SolidLine) self.feature_rubber_band.setWidth(4) self.create_transforms() def name(self): return '{}_{}'.format(self.__class__.__name__, FilterType(self.type).name) def clone(self): return SwissLocatorFilter(self.type, crs=self.crs) def priority(self): return self.settings.value( '{type}_priority'.format(type=self.type.value)) def displayName(self): if self.type is FilterType.Location: return self.tr('Swiss Geoportal locations') elif self.type is FilterType.WMS: return self.tr('Swiss Geoportal / opendata.swiss WMS layers') elif self.type is FilterType.Feature: return self.tr('Swiss Geoportal features') else: raise NameError('Filter type is not valid.') def prefix(self): if self.type is FilterType.Location: return 'chl' elif self.type is FilterType.WMS: return 'chw' elif self.type is FilterType.Feature: return 'chf' else: raise NameError('Filter type is not valid.') def clearPreviousResults(self): self.rubber_band.reset(QgsWkbTypes.PointGeometry) self.feature_rubber_band.reset(QgsWkbTypes.PolygonGeometry) if self.map_tip is not None: del self.map_tip self.map_tip = None if self.current_timer is not None: self.current_timer.stop() self.current_timer.deleteLater() self.current_timer = None def hasConfigWidget(self): return True def openConfigWidget(self, parent=None): dlg = ConfigDialog(parent) wid = dlg.findChild(QTabWidget, "tabWidget", Qt.FindDirectChildrenOnly) tab = wid.findChild(QWidget, self.type.value) wid.setCurrentWidget(tab) dlg.exec_() def create_transforms(self): # this should happen in the main thread self.crs = self.settings.value('crs') if self.crs == 'project': map_crs = self.map_canvas.mapSettings().destinationCrs() if map_crs.isValid(): self.crs = map_crs.authid().split(':')[1] if self.crs not in AVAILABLE_CRS: self.crs = '2056' assert self.crs in AVAILABLE_CRS src_crs_ch = QgsCoordinateReferenceSystem('EPSG:{}'.format(self.crs)) assert src_crs_ch.isValid() dst_crs = self.map_canvas.mapSettings().destinationCrs() self.transform_ch = QgsCoordinateTransform(src_crs_ch, dst_crs, QgsProject.instance()) src_crs_4326 = QgsCoordinateReferenceSystem('EPSG:4326') self.transform_4326 = QgsCoordinateTransform(src_crs_4326, dst_crs, QgsProject.instance()) def group_info(self, group: str) -> (str, str): groups = { 'zipcode': { 'name': self.tr('ZIP code'), 'layer': 'ch.swisstopo-vd.ortschaftenverzeichnis_plz' }, 'gg25': { 'name': self.tr('Municipal boundaries'), 'layer': 'ch.swisstopo.swissboundaries3d-gemeinde-flaeche.fill' }, 'district': { 'name': self.tr('District'), 'layer': 'ch.swisstopo.swissboundaries3d-bezirk-flaeche.fill' }, 'kantone': { 'name': self.tr('Cantons'), 'layer': 'ch.swisstopo.swissboundaries3d-kanton-flaeche.fill' }, 'gazetteer': { 'name': self.tr('Index'), 'layer': 'ch.swisstopo.swissnames3d' }, # there is also: ch.bav.haltestellen-oev ? 'address': { 'name': self.tr('Address'), 'layer': 'ch.bfs.gebaeude_wohnungs_register' }, 'parcel': { 'name': self.tr('Parcel'), 'layer': None } } if group not in groups: self.info('Could not find group {} in dictionary'.format(group)) return None, None return groups[group]['name'], groups[group]['layer'] @staticmethod def rank2priority(rank) -> float: """ Translate the rank from geoportal to the priority of the result see https://api3.geo.admin.ch/services/sdiservices.html#search :param rank: an integer from 1 to 7 :return: the priority as a float from 0 to 1, 1 being a perfect match """ return float(-rank / 7 + 1) @staticmethod def box2geometry(box: str) -> QgsRectangle: """ Creates a rectangle from a Box definition as string :param box: the box as a string :return: the rectangle """ coords = re.findall(r'\b(\d+(?:\.\d+)?)\b', box) if len(coords) != 4: raise InvalidBox('Could not parse: {}'.format(box)) return QgsRectangle(float(coords[0]), float(coords[1]), float(coords[2]), float(coords[3])) @staticmethod def url_with_param(url, params) -> str: url = QUrl(url) q = QUrlQuery(url) for key, value in params.items(): q.addQueryItem(key, value) url.setQuery(q) return url.url() def fetchResults(self, search: str, context: QgsLocatorContext, feedback: QgsFeedback): try: self.dbg_info("start Swiss locator search...") if len(search) < 2: return if len(search) < 4 and self.type is FilterType.Feature: return self.result_found = False swisstopo_base_url = 'https://api3.geo.admin.ch/rest/services/api/SearchServer' swisstopo_base_params = { 'type': self.type.value, 'searchText': str(search), 'returnGeometry': 'true', 'lang': self.lang, 'sr': self.crs, 'limit': str( self.settings.value( '{type}_limit'.format(type=self.type.value))) # bbox Must be provided if the searchText is not. # A comma separated list of 4 coordinates representing # the bounding box on which features should be filtered (SRID: 21781). } # Locations, WMS layers if self.type is not FilterType.Feature: nam = NetworkAccessManager() feedback.canceled.connect(nam.abort) search_urls = [(swisstopo_base_url, swisstopo_base_params)] if self.settings.value('layers_include_opendataswiss' ) and self.type is FilterType.WMS: search_urls.append( ('https://opendata.swiss/api/3/action/package_search?', { 'q': 'q=WMS+%C3' + str(search) })) for (swisstopo_base_url, swisstopo_base_params) in search_urls: swisstopo_base_url = self.url_with_param( swisstopo_base_url, swisstopo_base_params) self.dbg_info(swisstopo_base_url) try: (response, content) = nam.request(swisstopo_base_url, headers=self.HEADERS, blocking=True) self.handle_response(response, search, feedback) except RequestsExceptionUserAbort: pass except RequestsException as err: self.info(err) # Feature search else: # Feature search is split in several requests # otherwise URL is too long self.access_managers = {} try: layers = list(self.searchable_layers.keys()) assert len(layers) > 0 step = 30 for l in range(0, len(layers), step): last = min(l + step - 1, len(layers) - 1) swisstopo_base_params['features'] = ','.join( layers[l:last]) self.access_managers[self.url_with_param( swisstopo_base_url, swisstopo_base_params)] = None except IOError: self.info( 'Layers data file not found. Please report an issue.', Qgis.Critical) # init event loop # wait for all requests to end self.event_loop = QEventLoop() def reply_finished(response): self.handle_response(response, search, feedback) if response.url in self.access_managers: self.access_managers[response.url] = None for nam in self.access_managers.values(): if nam is not None: return self.event_loop.quit() feedback.canceled.connect(self.event_loop.quit) # init the network access managers, create the URL for swisstopo_base_url in self.access_managers: self.dbg_info(swisstopo_base_url) nam = NetworkAccessManager() self.access_managers[swisstopo_base_url] = nam nam.finished.connect(reply_finished) nam.request(swisstopo_base_url, headers=self.HEADERS, blocking=False) feedback.canceled.connect(nam.abort) # Let the requests end and catch all exceptions (and clean up requests) if len(self.access_managers) > 0: try: self.event_loop.exec_( QEventLoop.ExcludeUserInputEvents) except RequestsExceptionUserAbort: pass except RequestsException as err: self.info(str(err)) if not self.result_found: result = QgsLocatorResult() result.filter = self result.displayString = self.tr('No result found.') result.userData = NoResult().as_definition() self.resultFetched.emit(result) except Exception as e: self.info(e, Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] self.info( '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) self.info( traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def handle_response(self, response, search: str, feedback: QgsFeedback): try: if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info( "Error in main response with status code: {} from {}". format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) # self.dbg_info(data) if self.is_opendata_swiss_response(data): visited_capabilities = [] for loc in data['result']['results']: display_name = loc['title'].get(self.lang, "") if not display_name: # Fallback to german display_name = loc['title']['de'] for res in loc['resources']: url = res['url'] url_components = urlparse(url) wms_url = url_components.scheme + '://' + url_components.netloc + '/' + url_components.path + '?' result = QgsLocatorResult() result.filter = self result.group = 'opendata.swiss' result.icon = QgsApplication.getThemeIcon( "/mActionAddWmsLayer.svg") if 'wms' in url.lower(): if res['media_type'] == 'WMS': result.displayString = display_name result.description = url if res['title']['de'] == 'GetMap': layers = parse_qs( url_components.query)['LAYERS'] result.userData = WMSLayerResult( layer=layers[0], title=display_name, url=wms_url).as_definition() self.result_found = True self.resultFetched.emit(result) elif 'request=getcapabilities' in url.lower( ) and url_components.netloc not in visited_capabilities: visited_capabilities.append( url_components.netloc) def parse_capabilities_result(response): capabilities = ET.fromstring( response.content) # Get xml namespace match = re.match(r'\{.*\}', capabilities.tag) namespace = match.group(0) if match else '' # Search for layers containing the search term in the name or title for layer in capabilities.findall( './/{}Layer'.format(namespace)): layername = self.find_text( layer, '{}Name'.format(namespace)) layertitle = self.find_text( layer, '{}Title'.format(namespace)) if layername and ( search in layername.lower() or search in layertitle.lower()): if not layertitle: layertitle = layername result.displayString = layertitle result.description = '{}?LAYERS={}'.format( url.replace( 'GetCapabilities', 'GetMap'), layername) result.userData = WMSLayerResult( layer=layername, title=layertitle, url=wms_url).as_definition() self.result_found = True self.resultFetched.emit(result) self.event_loop.quit() # Retrieve Capabilities xml self.event_loop = QEventLoop() nam = NetworkAccessManager() nam.finished.connect(parse_capabilities_result) nam.request(url, headers=self.HEADERS, blocking=False) feedback.canceled.connect(self.event_loop.quit) try: self.event_loop.exec_( QEventLoop.ExcludeUserInputEvents) except RequestsExceptionUserAbort: pass except RequestsException as err: self.info(err) else: for loc in data['results']: self.dbg_info("keys: {}".format(loc['attrs'].keys())) result = QgsLocatorResult() result.filter = self result.group = 'Swiss Geoportal' if loc['attrs']['origin'] == 'layer': # available keys: ['origin', 'lang', 'layer', 'staging', 'title', 'topics', 'detail', 'label', 'id'] for key, val in loc['attrs'].items(): self.dbg_info('{}: {}'.format(key, val)) result.displayString = loc['attrs']['title'] result.description = loc['attrs']['layer'] result.userData = WMSLayerResult( layer=loc['attrs']['layer'], title=loc['attrs']['title'], url='http://wms.geo.admin.ch/?VERSION%3D2.0.0' ).as_definition() result.icon = QgsApplication.getThemeIcon( "/mActionAddWmsLayer.svg") self.result_found = True self.resultFetched.emit(result) elif loc['attrs']['origin'] == 'feature': for key, val in loc['attrs'].items(): self.dbg_info('{}: {}'.format(key, val)) layer = loc['attrs']['layer'] point = QgsPointXY(loc['attrs']['lon'], loc['attrs']['lat']) if layer in self.searchable_layers: layer_display = self.searchable_layers[layer] else: self.info( self. tr('Layer {} is not in the list of searchable layers.' ' Please report issue.'.format(layer)), Qgis.Warning) layer_display = layer result.group = layer_display result.displayString = loc['attrs']['detail'] result.userData = FeatureResult( point=point, layer=layer, feature_id=loc['attrs'] ['feature_id']).as_definition() result.icon = QIcon( ":/plugins/swiss_locator/icons/swiss_locator.png") self.result_found = True self.resultFetched.emit(result) else: # locations for key, val in loc['attrs'].items(): self.dbg_info('{}: {}'.format(key, val)) group_name, group_layer = self.group_info( loc['attrs']['origin']) if 'layerBodId' in loc['attrs']: self.dbg_info("layer: {}".format( loc['attrs']['layerBodId'])) if 'featureId' in loc['attrs']: self.dbg_info("feature: {}".format( loc['attrs']['featureId'])) result.displayString = strip_tags( loc['attrs']['label']) # result.description = loc['attrs']['detail'] # if 'featureId' in loc['attrs']: # result.description = loc['attrs']['featureId'] result.group = group_name result.userData = LocationResult( point=QgsPointXY(loc['attrs']['y'], loc['attrs']['x']), bbox=self.box2geometry( loc['attrs']['geom_st_box2d']), layer=group_layer, feature_id=loc['attrs']['featureId'] if 'featureId' in loc['attrs'] else None, html_label=loc['attrs']['label']).as_definition() result.icon = QIcon( ":/plugins/swiss_locator/icons/swiss_locator.png") self.result_found = True self.resultFetched.emit(result) except Exception as e: self.info(str(e), Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] self.info( '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) self.info( traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def triggerResult(self, result: QgsLocatorResult): # this should be run in the main thread, i.e. mapCanvas should not be None # remove any map tip self.clearPreviousResults() user_data = NoResult try: swiss_result = result_from_data(result) except SystemError: self.message_emitted.emit( self.displayName(), self. tr('QGIS Swiss Locator encountered an error. Please <b>update to QGIS 3.16.2</b> or newer.' ), Qgis.Warning, None) if type(swiss_result) == NoResult: return # WMS if type(swiss_result) == WMSLayerResult: url_with_params = 'contextualWMSLegend=0' \ '&crs=EPSG:{crs}' \ '&dpiMode=7' \ '&featureCount=10' \ '&format=image/png' \ '&layers={layer}' \ '&styles=' \ '&url={url}' \ .format(crs=self.crs, layer=swiss_result.layer, url=swiss_result.url) wms_layer = QgsRasterLayer(url_with_params, result.displayString, 'wms') label = QLabel() label.setTextFormat(Qt.RichText) label.setTextInteractionFlags(Qt.TextBrowserInteraction) label.setOpenExternalLinks(True) if 'geo.admin.ch' in swiss_result.url.lower(): label.setText( '<a href="https://map.geo.admin.ch/' '?lang={}&bgLayer=ch.swisstopo.pixelkarte-farbe&layers={}">' 'Open layer in map.geo.admin.ch</a>'.format( self.lang, swiss_result.layer)) if not wms_layer.isValid(): msg = self.tr('Cannot load WMS layer: {} ({})'.format( swiss_result.title, swiss_result.layer)) level = Qgis.Warning self.info(msg, level) else: msg = self.tr('WMS layer added to the map: {} ({})'.format( swiss_result.title, swiss_result.layer)) level = Qgis.Info QgsProject.instance().addMapLayer(wms_layer) self.message_emitted.emit(self.displayName(), msg, level, label) # Feature elif type(swiss_result) == FeatureResult: point = QgsGeometry.fromPointXY(swiss_result.point) point.transform(self.transform_4326) self.highlight(point) if self.settings.value('show_map_tip'): self.show_map_tip(swiss_result.layer, swiss_result.feature_id, point) # Location else: point = QgsGeometry.fromPointXY(swiss_result.point) if swiss_result.bbox.isNull(): bbox = None else: bbox = QgsGeometry.fromRect(swiss_result.bbox) bbox.transform(self.transform_ch) layer = swiss_result.layer feature_id = swiss_result.feature_id if not point: return point.transform(self.transform_ch) self.highlight(point, bbox) if layer and feature_id: self.fetch_feature(layer, feature_id) if self.settings.value('show_map_tip'): self.show_map_tip(layer, feature_id, point) else: self.current_timer = QTimer() self.current_timer.timeout.connect(self.clearPreviousResults) self.current_timer.setSingleShot(True) self.current_timer.start(5000) def highlight(self, point, bbox=None): if bbox is None: bbox = point self.rubber_band.reset(QgsWkbTypes.PointGeometry) self.rubber_band.addGeometry(point, None) rect = bbox.boundingBox() rect.scale(1.1) self.map_canvas.setExtent(rect) self.map_canvas.refresh() def fetch_feature(self, layer, feature_id): # Try to get more info self.nam_fetch_feature = NetworkAccessManager() url_detail = 'https://api3.geo.admin.ch/rest/services/api/MapServer/{layer}/{feature_id}' \ .format(layer=layer, feature_id=feature_id) params = {'lang': self.lang, 'sr': self.crs} url_detail = self.url_with_param(url_detail, params) self.dbg_info(url_detail) self.nam_fetch_feature.finished.connect(self.parse_feature_response) self.nam_fetch_feature.request(url_detail, headers=self.HEADERS, blocking=False) def parse_feature_response(self, response): if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info( "Error in feature response with status code: {} from {}". format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) self.dbg_info(data) if 'feature' not in data or 'geometry' not in data['feature']: return if 'rings' in data['feature']['geometry']: rings = data['feature']['geometry']['rings'] self.dbg_info(rings) for r in range(0, len(rings)): for p in range(0, len(rings[r])): rings[r][p] = QgsPointXY(rings[r][p][0], rings[r][p][1]) geometry = QgsGeometry.fromPolygonXY(rings) geometry.transform(self.transform_ch) self.feature_rubber_band.reset(QgsWkbTypes.PolygonGeometry) self.feature_rubber_band.addGeometry(geometry, None) def show_map_tip(self, layer, feature_id, point): if layer and feature_id: url_html = 'https://api3.geo.admin.ch/rest/services/api/MapServer/{layer}/{feature_id}/htmlPopup' \ .format(layer=layer, feature_id=feature_id) params = {'lang': self.lang, 'sr': self.crs} url_html = self.url_with_param(url_html, params) self.dbg_info(url_html) self.nam_map_tip = NetworkAccessManager() self.nam_map_tip.finished.connect( lambda response: self.parse_map_tip_response(response, point)) self.nam_map_tip.request(url_html, headers=self.HEADERS, blocking=False) def parse_map_tip_response(self, response, point): if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info( "Error in map tip response with status code: {} from {}". format(response.status_code, response.url)) return self.dbg_info(response.content.decode('utf-8')) self.map_tip = MapTip(self.iface, response.content.decode('utf-8'), point.asPoint()) self.map_tip.closed.connect(self.clearPreviousResults) def info(self, msg="", level=Qgis.Info): self.logMessage(str(msg), level) def dbg_info(self, msg=""): if DEBUG: self.info(msg) @staticmethod def break_camelcase(identifier): matches = re.finditer( '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', identifier) return ' '.join([m.group(0) for m in matches]) def is_opendata_swiss_response(self, json): return 'opendata.swiss' in json.get("help", []) def find_text(self, xmlElement, match): node = xmlElement.find(match) return node.text if node is not None else ''
class InterpolateTool(QgsMapToolAdvancedDigitizing): """ Map tool class to interpolate an elevation in the middle of a segment """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/interpolate_icon.png' self.text = QCoreApplication.translate( "VDLTools", "Interpolate the elevation of a vertex and a point in the middle of a line") self.__layer = None self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__lastFeatureId = None self.__layerList = None self.__lastLayer = None self.__confDlg = None self.__mapPoint = None self.__rubber = None self.__selectedFeature = None self.__findVertex = False def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapToolAdvancedDigitizing.activate(self) self.__updateList() self.__rubber = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setWidth(2) self.__rubber.setIconSize(20) self.canvas().layersChanged.connect(self.__updateList) self.canvas().scaleChanged.connect(self.__updateList) self.setMode(self.CaptureLine) def deactivate(self): """ When the action is deselected """ self.__done() self.__cancel() self.__rubber = None Signal.safelyDisconnect(self.canvas().layersChanged, self.__updateList) Signal.safelyDisconnect(self.canvas().scaleChanged, self.__updateList) QgsMapToolAdvancedDigitizing.deactivate(self) def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def __done(self): """ When the edition is finished """ self.__isEditing = False self.__confDlg = None self.__mapPoint = None def __cancel(self): """ To cancel used variables """ self.__findVertex = False if self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastLayer = None if self.__rubber is not None: self.__rubber.reset() self.__lastFeatureId = None self.__selectedFeature = None def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() self.action().setEnabled(False) self.__removeLayer() def __updateList(self): """ To update the line layers list that we can use for interpolation """ self.__layerList = [] for layer in self.canvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType() \ and layer.geometryType() == QGis.Line: self.__layerList.append(QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.All, 10, QgsTolerance.Pixels)) def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__done() self.__cancel() def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and self.__layerList is not None: f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), self.__layerList) if f_l is not None and self.__lastFeatureId != f_l[0].id(): f = f_l[0] self.__lastFeatureId = f.id() if self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastLayer = f_l[1] self.__lastLayer.setSelectedFeatures([f.id()]) if f_l is None and self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: self.__rubber.reset() snap_layers = Finder.getLayersSettings(self.canvas(), [QGis.Line, QGis.Polygon], QgsPointLocator.All) match = Finder.snap(map_point, self.canvas(), snap_layers) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): self.__rubber.setIcon(4) self.__rubber.setToGeometry(QgsGeometry().fromPoint(point), None) else: intersection = Finder.snapCurvedIntersections(point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: if self.__isVertexUnderPoint(intersection, snap_layers): self.__rubber.setIcon(4) else: self.__rubber.setIcon(1) self.__rubber.setToGeometry(QgsGeometry().fromPoint(intersection), None) if match.hasEdge(): intersection = Finder.snapCurvedIntersections(point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: if self.__isVertexUnderPoint(intersection, snap_layers): self.__rubber.setIcon(4) else: self.__rubber.setIcon(1) self.__rubber.setToGeometry(QgsGeometry().fromPoint(intersection), None) elif self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): self.__rubber.setIcon(3) self.__rubber.setToGeometry(QgsGeometry().fromPoint(point), None) def __isVertexUnderPoint(self, point, snap_layers): """ When snapping find a point instead of line/polygon element, we need to check if there is a vertex under it :param point: coordinates :param snap_layers: layers configs :return: True if there is a vertex, False otherwise """ for config in snap_layers: if config.layer.id() == self.__lastLayer.id(): tolerance = config.tolerance if config.unit == QgsTolerance.Pixels: tolerance = Finder.calcCanvasTolerance(self.toCanvasCoordinates(point), config.layer, self, tolerance) elif config.unit == QgsTolerance.ProjectUnits: tolerance = Finder.calcMapTolerance(point, config.layer, self, tolerance) layPoint = self.toLayerCoordinates(config.layer, point) geom = self.__selectedFeature.geometry() dist = geom.closestVertex(layPoint)[4] if dist < (tolerance*tolerance): return True break return False def cadCanvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if self.__lastLayer is not None and not self.__findVertex: found_features = self.__lastLayer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage(QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Select the position for interpolation (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) self.setMode(self.CaptureNone) self.__findVertex = True elif self.__findVertex: self.__rubber.reset() snap_layers = Finder.getLayersSettings(self.canvas(), [QGis.Line, QGis.Polygon], QgsPointLocator.All) match = Finder.snap(event.mapPoint(), self.canvas(), snap_layers) if match.hasVertex() or match.hasEdge(): point = match.point() ok = False noVertex = False if match.hasVertex(): if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): ok = True noVertex = True else: intersection = Finder.snapCurvedIntersections(point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: point = intersection ok = True if self.__isVertexUnderPoint(intersection, snap_layers): noVertex = True if match.hasEdge(): intersection = Finder.snapCurvedIntersections(point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: point = intersection ok = True if self.__isVertexUnderPoint(intersection, snap_layers): noVertex = True elif self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): ok = True if ok: self.__isEditing = True self.__findVertex = False self.__mapPoint = point if noVertex: self.__ok(False, True) else: self.__confDlg = InterpolateConfirmDialog() if self.__lastLayer.isEditable(): self.__confDlg.setMainLabel(QCoreApplication.translate("VDLTools", "What do you want to do ?")) self.__confDlg.setAllLabel(QCoreApplication.translate("VDLTools", "Create point and new vertex")) self.__confDlg.setVtLabel(QCoreApplication.translate("VDLTools", "Create only the vertex")) self.__confDlg.rejected.connect(self.__done) self.__confDlg.okButton().clicked.connect(self.__onConfirmOk) self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel) self.__confDlg.show() else: self.__done() self.__cancel() def __onConfirmCancel(self): """ When the Cancel button in Interpolate Confirm Dialog is pushed """ self.__confDlg.reject() def __onConfirmOk(self): """ When the Ok button in Interpolate Confirm Dialog is pushed """ checkedId = self.__confDlg.getCheckedId() self.__confDlg.accept() withVertex = True withPoint = True if checkedId == 1: withVertex = False else: if not self.__lastLayer.isEditable(): self.__lastLayer.startEditing() if checkedId == 2: withPoint = False self.__ok(withVertex, withPoint) def __ok(self, withVertex, withPoint): """ To apply the interpolation :param withVertex: if we want a new interpolated vertex :param withPoint: if we want a new interpolated point """ line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface) vertex_v2 = QgsPointV2() vertex_id = QgsVertexId() line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2, vertex_id, 0) x0 = line_v2.xAt(vertex_id.vertex-1) y0 = line_v2.yAt(vertex_id.vertex-1) d0 = Finder.sqrDistForCoords(x0, vertex_v2.x(), y0, vertex_v2.y()) x1 = line_v2.xAt(vertex_id.vertex) y1 = line_v2.yAt(vertex_id.vertex) d1 = Finder.sqrDistForCoords(x1, vertex_v2.x(), y1, vertex_v2.y()) z0 = line_v2.zAt(vertex_id.vertex-1) z1 = line_v2.zAt(vertex_id.vertex) z = old_div((d0*z1 + d1*z0), (d0 + d1)) vertex_v2.addZValue(round(z, 2)) if withPoint: pt_feat = QgsFeature(self.__layer.pendingFields()) pt_feat.setGeometry(QgsGeometry(vertex_v2)) for i in range(len(self.__layer.pendingFields())): # default = self.__layer.defaultValue(i, pt_feat) # if default is not None: # print(pt_feat.fields().at(i).name(), pt_feat.fields().at(i).defaultValueExpression(), default) # print(self.__layer.defaultValueExpression(i), self.__layer.expressionField(i)) e = QgsExpression(self.__layer.defaultValueExpression(i)) default = e.evaluate(pt_feat) pt_feat.setAttribute(i, default) if self.__layer.editFormConfig().suppress() == QgsEditFormConfig.SuppressOn: self.__layer.addFeature(pt_feat) else: self.__iface.openFeatureForm(self.__layer, pt_feat) if withVertex: line_v2.insertVertex(vertex_id, vertex_v2) self.__lastLayer.changeGeometry(self.__selectedFeature.id(), QgsGeometry(line_v2)) found_features = self.__lastLayer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage(QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) else: self.__selectedFeature = found_features[0] else: self.__iface.messageBar().pushMessage(QCoreApplication.translate("VDLTools", "No more feature selected"), level=QgsMessageBar.INFO) self.__iface.mapCanvas().refresh() self.__done() self.__findVertex = True
class nominatim_dlg(QDockWidget, FORM_CLASS): """ Gestion de l'évènement "leave", afin d'effacer l'objet sélectionné en sortie du dock """ def eventFilter(self, obj, event): typ = event.type() if typ == event.Leave: try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass return False def __init__(self, parent, plugin): self.plugin = plugin QDockWidget.__init__(self, parent) self.setupUi(self) self.btnApply.setIcon( QIcon(str(DIR_PLUGIN_ROOT / "resources/arrow_green.png"))) self.btnMask.setIcon( QIcon(str(DIR_PLUGIN_ROOT / "resources/add_mask.png"))) self.btnLayer.setIcon( QIcon(str(DIR_PLUGIN_ROOT / "resources/add_layer.png"))) self.btnHelp.setIcon( QIcon(QgsApplication.iconPath("mActionHelpContents.svg"))) self.tableResult.installEventFilter(self) # cf. eventFilter method self.tableResult.cellDoubleClicked.connect(self.onChoose) self.tableResult.cellEntered.connect(self.cellEntered) self.editSearch.returnPressed.connect(self.onReturnPressed) self.btnSearch.clicked.connect(self.onReturnPressed) self.btnApply.clicked.connect(self.onApply) self.btnHelp.clicked.connect( lambda: showPluginHelp(filename="../doc/index")) self.btnLocalize.clicked.connect(self.doLocalize) self.btnMask.clicked.connect(self.onMask) self.btnLayer.clicked.connect(self.onLayer) self.singleLayerId = { QgsWkbTypes.PolygonGeometry: None, QgsWkbTypes.LineGeometry: None, QgsWkbTypes.PointGeometry: None, } self.singleLayerName = { QgsWkbTypes.PolygonGeometry: "OSM Place Search Polygons", QgsWkbTypes.LineGeometry: "OSM Place Search Lines", QgsWkbTypes.PointGeometry: "OSM Place Search Points", } self.memoryLayerType = { QgsWkbTypes.PolygonGeometry: "MultiPolygon", QgsWkbTypes.LineGeometry: "MultiLineString", QgsWkbTypes.PointGeometry: "Point", } try: self.cbExtent.setChecked(tools.limitSearchToExtent) except: self.cbExtent.setChecked(tools.limitSearchToExtent) self.currentExtent = self.plugin.canvas.extent() self.tableResult.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) try: self.editSearch.setText(self.plugin.lastSearch) except: pass def cellEntered(self, row, col): item = self.tableResult.item(row, 0) try: self.plugin.canvas.scene().removeItem(self.rubber) self.showItem(item) except: pass def onLayer(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doLayer(item) def onMask(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doMask(item) def populateRow(self, item, idx): id = item["place_id"] name = item["display_name"] try: className = QApplication.translate("nominatim", item["class"], None) except: className = "" try: typeName = QApplication.translate("nominatim", item["type"], None) except: typeName = "" try: wkt = item["geotext"] except: wkt = None try: osm_type = item["osm_type"] except: osm_type = None bbox = {} if osm_type == "node": lat = item["lat"] lng = item["lon"] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn("id", ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn("name", ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT({} {})".format(lng, lat) ogrGeom = ogr.CreateGeometryFromWkt(wkt) else: try: bbox = item["boundingbox"] poFD = ogr.FeatureDefn("Rectangle") poFD.SetGeomType(ogr.wkbPolygon) oFLD = ogr.FieldDefn("id", ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn("name", ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) if wkt is None: wkt = "POLYGON(({b[2]} {b[0]}, {b[2]} {b[1]}, {b[3]} {b[1]}, {b[3]} {b[0]}, {b[2]} {b[0]}))".format( b=bbox) ogrGeom = ogr.CreateGeometryFromWkt(wkt) except: lat = item["lat"] lng = item["lon"] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn("id", ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn("name", ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT({} {})".format(lng, lat) ogrGeom = ogr.CreateGeometryFromWkt(wkt) ogrFeature.SetGeometry(ogrGeom) ogrFeature.SetFID(int(idx + 1)) ogrFeature.SetField(str("id"), str(id)) ogrFeature.SetField(str("name"), name) item = QTableWidgetItem(name) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) item.setData(Qt.UserRole, ogrFeature) self.tableResult.setItem(idx, 0, item) itemLibelle = QTableWidgetItem(className) itemLibelle.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 1, itemLibelle) itemType = QTableWidgetItem(typeName) itemType.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 2, itemType) def populateTable(self, r): idx = 0 self.tableResult.clearContents() self.tableResult.setRowCount(len(r)) for item in r: self.populateRow(item, idx) idx = idx + 1 def doLocalize(self): try: # center bbox = self.plugin.canvas.extent() sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem("EPSG:4326") xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) bbox = xform.transform(bbox) params = { "lon": str(bbox.center().x()), "lat": str(bbox.center().y()), "zoom": "10", } r = tools.osmFindNearbyJSON(params, tools.gnOptions) if r != None: self.populateTable(r) else: self.tableResult.clearContents() except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, "Extensions") pass def search(self, txt): try: self.plugin.lastSearch = self.editSearch.text() tools.limitSearchToExtent = self.cbExtent.isChecked() return tools.osmSearch(self.plugin.iface.mapCanvas(), txt) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, "Extensions") return None def onReturnPressed(self): txt = self.editSearch.text().strip() r = self.search(txt) if r != None: self.populateTable(r) else: self.tableResult.clearContents() def onChoose(self, row, col): item = self.tableResult.item(row, 0) self.go(item) def onApply(self): for item in self.tableResult.selectedItems(): self.go(item) break def transform(self, geom): sourceSRS = QgsCoordinateReferenceSystem("EPSG:4326") mapCrs = self.plugin.canvas.mapSettings().destinationCrs() trsf = QgsCoordinateTransform(sourceSRS, mapCrs, QgsProject.instance()) try: geom.transform(trsf) except TypeError: QgsMessageLog.logMessage( "Nominatim - transformation error. Check map projection.", "Extensions") def getBBox(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint: mapextent = self.plugin.canvas.extent() ww = mapextent.width() / 100 mapcrs = self.plugin.canvas.mapSettings().destinationCrs() x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() ww = 50.0 if mapcrs.mapUnits() == QgsUnitTypes.DistanceFeet: ww = 150 if mapcrs.mapUnits() == QgsUnitTypes.DistanceDegrees: ww = 0.0005 bbox = QgsRectangle(x - 10 * ww, y - 10 * ww, x + 10 * ww, y + 10 * ww) return bbox else: bbox = geom.boundingBox() rubberRect = QgsRectangle(bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum()) return rubberRect def showItem(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint: self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PointGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(2) self.rubber.setToGeometry(geom, None) else: # dont show if it is larger than the canvas if self.plugin.canvas.extent().contains(geom.boundingBox()): pass else: geom = geom.intersection( QgsGeometry.fromRect(self.plugin.canvas.extent())) self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PolygonGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setWidth(4) self.rubber.setToGeometry(geom, None) def go(self, item, zoom=True): try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass if zoom: bbox = self.getBBox(item) self.plugin.canvas.setExtent(bbox) self.plugin.canvas.refresh() self.showItem(item) def addNewLayer(self, layerName, typ, fields): vl = QgsVectorLayer(self.memoryLayerType[typ], layerName, "memory") if vl: vl.setProviderEncoding("UTF-8") pr = vl.dataProvider() pr.addAttributes(fields.toList()) vl.setCrs(self.plugin.canvas.mapSettings().destinationCrs()) QgsProject.instance().addMapLayer(vl) renderer = vl.renderer() s = renderer.symbol() s.setOpacity(0.85) return vl def doLayer(self, item, singleLayer=None): if singleLayer is None: singleLayer = self.plugin.singleLayer ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setFields(fields) fet.setGeometry(geom) fet.setAttribute("id", (ogrFeature.GetFieldAsString("id"))) fet.setAttribute("name", (ogrFeature.GetFieldAsString("name"))) vl = None if not singleLayer: layerId = self.singleLayerId[geom.type()] layerName = self.singleLayerName[geom.type()] vl = QgsProject.instance().mapLayer(layerId) if vl is None: vl = self.addNewLayer(layerName, geom.type(), fields) if vl: self.singleLayerId[geom.type()] = vl.id() else: layerName = "OSM " + ogrFeature.GetFieldAsString("id") vl = self.addNewLayer(layerName, geom.type(), fields) if vl is not None: pr = vl.dataProvider() vl.startEditing() pr.addFeatures([fet]) vl.commitChanges() # mise a jour etendue de la couche vl.updateExtents() """ layerTree = QgsProject.instance().layerTreeRoot().findLayer(vl) if layerTree: self.plugin.iface.layerTreeView().layerTreeModel().refreshLayerLegend( layerTree ) # Refresh legend """ self.go(item, False) return vl def doMask(self, item): mapcrs = self.plugin.canvas.mapSettings().destinationCrs() ogrFeature = item.data(Qt.UserRole) layerName = "OSM " + ogrFeature.GetFieldAsString("id") geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if geom.type() == QgsWkbTypes.PolygonGeometry: try: try: from mask import aeag_mask except: from mask_plugin import aeag_mask aeag_mask.do(mapcrs, {geom}, "Mask " + layerName) self.go(item) except: maskLayer = self.doLayer(item, True) maskLayer.loadNamedStyle( str(DIR_PLUGIN_ROOT / "resources" / "mask.qml")) maskLayer.triggerRepaint()
class SoLocatorFilter(QgsLocatorFilter): HEADERS = {b'User-Agent': b'Mozilla/5.0 QGIS SoLocator Filter'} message_emitted = pyqtSignal(str, str, Qgis.MessageLevel, QWidget) def __init__(self, iface: QgisInterface = None): """" :param iface: QGIS interface, given when on the main thread (which will display/trigger results), None otherwise """ super().__init__() self.iface = iface self.settings = Settings() # following properties will only be used in main thread self.rubber_band = None self.map_canvas: QgsMapCanvas = None self.transform_ch = None self.current_timer = None self.result_found = False self.nam_fetch_feature = None if iface is not None: # happens only in main thread self.map_canvas = iface.mapCanvas() self.map_canvas.destinationCrsChanged.connect( self.create_transforms) self.rubber_band = QgsRubberBand(self.map_canvas, QgsWkbTypes.PolygonGeometry) self.rubber_band.setColor(QColor(255, 50, 50, 200)) self.rubber_band.setFillColor(QColor(255, 255, 50, 160)) self.rubber_band.setBrushStyle(Qt.SolidPattern) self.rubber_band.setLineStyle(Qt.SolidLine) self.rubber_band.setIcon(self.rubber_band.ICON_CIRCLE) self.rubber_band.setIconSize(15) self.rubber_band.setWidth(4) self.rubber_band.setBrushStyle(Qt.NoBrush) self.create_transforms() def name(self): return 'SoLocator' def clone(self): return SoLocatorFilter() def priority(self): return QgsLocatorFilter.Highest def displayName(self): return 'SoLocator' def prefix(self): return 'sol' def clearPreviousResults(self): if self.rubber_band: self.rubber_band.reset(QgsWkbTypes.PointGeometry) if self.current_timer is not None: self.current_timer.stop() self.current_timer.deleteLater() self.current_timer = None def hasConfigWidget(self): return True def openConfigWidget(self, parent=None): dlg = ConfigDialog(parent) dlg.exec_() def create_transforms(self): # this should happen in the main thread src_crs_ch = QgsCoordinateReferenceSystem('EPSG:2056') assert src_crs_ch.isValid() dst_crs = self.map_canvas.mapSettings().destinationCrs() self.transform_ch = QgsCoordinateTransform(src_crs_ch, dst_crs, QgsProject.instance()) def enabled_dataproducts(self): categories = DATA_PRODUCTS.keys() skipped = self.settings.value('skipped_dataproducts') return ','.join(list(filter(lambda id: id not in skipped, categories))) @staticmethod def url_with_param(url, params) -> str: url = QUrl(url) q = QUrlQuery(url) for key, value in params.items(): q.addQueryItem(key, value) url.setQuery(q) return url.url() def fetchResults(self, search: str, context: QgsLocatorContext, feedback: QgsFeedback): try: self.dbg_info("start solocator search...") if len(search) < 3: return self.result_found = False params = { 'searchtext': str(search), 'filter': self.enabled_dataproducts(), 'limit': str(self.settings.value('results_limit')) } nam = NetworkAccessManager() feedback.canceled.connect(nam.abort) url = self.url_with_param(SEARCH_URL, params) self.dbg_info(url) try: (response, content) = nam.request(url, headers=self.HEADERS, blocking=True) self.handle_response(response, search) except RequestsExceptionUserAbort: pass except RequestsException as err: self.info(err, Qgis.Info) if not self.result_found: result = QgsLocatorResult() result.filter = self result.displayString = self.tr('No result found.') result.userData = NoResult self.resultFetched.emit(result) except Exception as e: self.info(e, Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] self.info( '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) self.info( traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def data_product_qgsresult(self, data: dict, sub_layer: bool, score: float, stacktype) -> QgsLocatorResult: result = QgsLocatorResult() result.filter = self result.displayString = '{prefix}{title}'.format( prefix=' ↳ ' if sub_layer else '', title=data['display']) if stacktype == 'background': result.group = 'Hintergrundkarten' else: loading_mode: LoadingMode = self.settings.value( 'default_layer_loading_mode') result.group = 'Vordergrundkarten (Doppelklick: {normal}, Ctrl-Doppelklick: {alt})'.format( normal=loading_mode, alt=loading_mode.alternate_mode()) result.userData = DataProductResult( type=data['type'], dataproduct_id=data['dataproduct_id'], display=data['display'], dset_info=data['dset_info'], stacktype=stacktype, sublayers=data.get('sublayers', None)) data_product = 'dataproduct' data_type = data['type'] result.icon, result.description = dataproduct2icon_description( data_product, data_type) result.score = score return result def handle_response(self, response, search_text: str): try: if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info("Error in main response with status code: " "{} from {}".format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) # Since results are ordered by score (0 to 1) # we use an ordering score to keep the same order than the one from the remote service score = 1 # sub-filtering # dbg_info(data['result_counts']) if len(data['result_counts']) > 1: for _filter in data['result_counts']: result = QgsLocatorResult() result.filter = self result.group = 'Suche verfeinern' result.displayString = _filter['filterword'] if _filter['count']: result.displayString += ' ({})'.format( _filter['count']) self.dbg_info(_filter) result.icon, _ = dataproduct2icon_description( _filter['dataproduct_id'], 'datasetview') result.userData = FilterResult(_filter['filterword'], search_text) result.score = score self.resultFetched.emit(result) score -= 0.001 for res in data['results']: # dbg_info(res) result = QgsLocatorResult() result.filter = self if 'feature' in res.keys(): f = res['feature'] # dbg_info("feature: {}".format(f)) result.displayString = f['display'] result.group = 'Orte' result.userData = FeatureResult( dataproduct_id=f['dataproduct_id'], id_field_name=f['id_field_name'], id_field_type=f['id_field_type'], feature_id=f['feature_id']) data_product = f['dataproduct_id'] data_type = None result.icon, result.description = dataproduct2icon_description( data_product, data_type) result.score = score self.resultFetched.emit(result) score -= 0.001 elif 'dataproduct' in res.keys(): dp = res['dataproduct'] # self.dbg_info("data_product: {}".format(dp)) result = self.data_product_qgsresult( dp, False, score, dp['stacktype']) self.resultFetched.emit(result) score -= 0.001 # also give sublayers for layer in dp.get('sublayers', []): always_show_sublayers = True if always_show_sublayers or search_text.lower( ) in layer['display'].lower(): result = self.data_product_qgsresult( layer, True, score, dp['stacktype']) self.resultFetched.emit(result) score -= 0.001 else: continue self.result_found = True except Exception as e: self.info(str(e), Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] self.info( '{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) self.info( traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def triggerResult(self, result: QgsLocatorResult): # this is run in the main thread, i.e. map_canvas is not None self.clearPreviousResults() ctrl_clicked = Qt.ControlModifier == QApplication.instance( ).queryKeyboardModifiers() self.dbg_info(("CTRL pressed: {}".format(ctrl_clicked))) user_data = self.get_user_data(result) if type(user_data) == NoResult: pass elif type(user_data) == FilterResult: self.filtered_search(user_data) elif type(user_data) == FeatureResult: self.fetch_feature(user_data) elif type(user_data) == DataProductResult: self.fetch_data_product(user_data, ctrl_clicked) else: self.info('Incorrect result. Please contact support', Qgis.Critical) def filtered_search(self, filter_result: FilterResult): search_text = '{prefix} {filter_word}: {search}'.format( prefix=self.activePrefix(), filter_word=filter_result.filter_word, search=filter_result.search) # Compatibility for QGIS < 3.10 # TODO: remove try: self.iface.locatorSearch(search_text) except AttributeError: for w in self.iface.mainWindow().findChildren(QgsFilterLineEdit): if hasattr(w.parent(), 'search') and hasattr( w.parent(), 'invalidateResults'): w.setText(search_text) w.parent().setFocus(True) return raise NameError('Locator not found') def highlight(self, geometry: QgsGeometry): self.clearPreviousResults() if geometry is None: return self.rubber_band.reset(geometry.type()) self.rubber_band.addGeometry(geometry, None) rect = geometry.boundingBox() if not self.settings.value('keep_scale'): if rect.isEmpty(): current_extent = self.map_canvas.extent() rect = current_extent.scaled( self.settings.value('point_scale') / self.map_canvas.scale(), rect.center()) else: rect.scale(4) self.map_canvas.setExtent(rect) self.map_canvas.refresh() self.current_timer = QTimer() self.current_timer.timeout.connect(self.clearPreviousResults) self.current_timer.setSingleShot(True) self.current_timer.start(5000) def fetch_feature(self, feature: FeatureResult): self.dbg_info(feature) url = '{url}/{dataset}/{id}'.format(url=FEATURE_URL, dataset=feature.dataproduct_id, id=feature.feature_id) self.nam_fetch_feature = NetworkAccessManager() self.dbg_info(url) self.nam_fetch_feature.finished.connect(self.parse_feature_response) self.nam_fetch_feature.request(url, headers=self.HEADERS, blocking=False) def parse_feature_response(self, response): if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info("Error in feature response with status code: " "{} from {}".format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) self.dbg_info(data.keys()) self.dbg_info(data['properties']) self.dbg_info(data['geometry']) self.dbg_info(data['crs']) self.dbg_info(data['type']) assert data['crs']['properties'][ 'name'] == 'urn:ogc:def:crs:EPSG::2056' geometry_type = data['geometry']['type'] geometry = QgsGeometry() if geometry_type.lower() == 'point': geometry = QgsGeometry.fromPointXY( QgsPointXY(data['geometry']['coordinates'][0], data['geometry']['coordinates'][1])) elif geometry_type.lower() == 'polygon': rings = data['geometry']['coordinates'] for r in range(0, len(rings)): for p in range(0, len(rings[r])): rings[r][p] = QgsPointXY(rings[r][p][0], rings[r][p][1]) geometry = QgsGeometry.fromPolygonXY(rings) elif geometry_type.lower() == 'multipolygon': islands = data['geometry']['coordinates'] for i in range(0, len(islands)): for r in range(0, len(islands[i])): for p in range(0, len(islands[i][r])): islands[i][r][p] = QgsPointXY(islands[i][r][p][0], islands[i][r][p][1]) geometry = QgsGeometry.fromMultiPolygonXY(islands) else: # SoLocator does not handle {geometry_type} yet. Please contact support self.info( 'SoLocator unterstützt den Geometrietyp {geometry_type} nicht.' ' Bitte kontaktieren Sie den Support.'.format( geometry_type=geometry_type), Qgis.Warning) geometry.transform(self.transform_ch) self.highlight(geometry) def fetch_data_product(self, product: DataProductResult, alternate_mode: bool): self.dbg_info(product) url = '{url}/{dataproduct_id}'.format( url=DATA_PRODUCT_URL, dataproduct_id=product.dataproduct_id) self.nam_fetch_feature = NetworkAccessManager() self.dbg_info(url) is_background = product.stacktype == 'background' self.dbg_info('is_background {}'.format(is_background)) self.nam_fetch_feature.finished.connect( lambda response: self.parse_data_product_response( response, is_background, alternate_mode)) self.nam_fetch_feature.request(url, headers=self.HEADERS, blocking=False) def parse_data_product_response(self, response, is_background: bool, alternate_mode: bool): if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): self.info("Error in feature response with status code: " "{} from {}".format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) LayerLoader(data, self.iface, is_background, alternate_mode) def info(self, msg="", level=Qgis.Info): self.logMessage(str(msg), level) def dbg_info(self, msg=""): if DEBUG: self.info(msg) def get_user_data(self, result): if hasattr(result, 'getUserData'): return result.getUserData() else: return result.userData
class Geo360Dialog(QWidget, Ui_orbitalDialog): """Geo360 Dialog Class""" def __init__(self, iface, parent=None, featuresId=None, layer=None): QDialog.__init__(self) self.setupUi(self) self.s = QSettings() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent # Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.layer, self.featuresId) # Get image path self.current_image = self.GetImage() # Create Viewer self.CreateViewer() self.RestoreSize() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.resetQgsRubberBand() time.sleep(1) self.ChangeUrlViewer(config.DEFAULT_EMPTY) return # Copy file to local server self.CopyFile(self.current_image) # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() def SetInitialYaw(self): ''' Set Initial Yaw ''' self.bearing = self.selected_features.attribute(config.column_yaw) self.view.browser.GetMainFrame().ExecuteFunction( "InitialYaw", self.bearing) return def CreateViewer(self): ''' Create Viewer ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Create viewer", onlyLog=True) self.view = CefWidget(self) self.ViewerLayout.addWidget(self.view) self.view.embedBrowser() return def RemoveImage(self): ''' Remove Image ''' try: os.remove(self.plugin_path + "\\viewer\\image.jpg") except OSError: pass def CopyFile(self, src): ''' Copy Image File in Local Server ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Copiar imagem", onlyLog=True) src_dir = src dst_dir = self.plugin_path + "\\viewer" # Copy image in local folder # Uncomment for large images if viewer is blank screen img = Image.open(src_dir) newwidth = 8000 dst_dir = dst_dir + "\\image.jpg" try: os.remove(dst_dir) except OSError: pass width, _ = img.size if width > newwidth: wpercent = (newwidth / float(img.size[0])) hsize = int((float(img.size[1]) * float(wpercent))) img = img.resize((newwidth, hsize), Image.ANTIALIAS) img.save(dst_dir, optimize=True, quality=95) # Comment for large images if viewer is blank screen else: shutil.copy(src_dir, dst_dir) return def RestoreSize(self): ''' Restore Dialog Size ''' dw = self.s.value("EquirectangularViewer/width") dh = self.s.value("EquirectangularViewer/height") if dw is None: return size = self.size() anim = QPropertyAnimation(self, b'size', self) anim.setStartValue(size) anim.setEndValue(QSize(int(dw), int(dh))) anim.setDuration(1) anim.start() return def SaveSize(self): ''' Save Dialog Size ''' dw = self.width() dh = self.height() self.s.setValue("EquirectangularViewer/width", dw) self.s.setValue("EquirectangularViewer/height", dh) return def GetImage(self): ''' Get Selected Image ''' try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) if not os.path.isabs(path): # Relative Path to Project path_project = QgsProject.instance().readPath("./") path = os.path.normpath(os.path.join(path_project, path)) except Exception: qgsutils.showUserAndLogMessage(u"Information: ", u"Column not found.") return qgsutils.showUserAndLogMessage(u"Information: ", str(path), onlyLog=True) return path def ChangeUrlViewer(self, new_url): ''' Change Url Viewer ''' self.view.browser.GetMainFrame().ExecuteJavascript( "window.location='%s'" % new_url) return def ReloadView(self, newId): ''' Reaload Image viewer ''' self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) # this will activate the window self.activateWindow() self.selected_features = qgsutils.getToFeature(self.layer, newId) self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.resetQgsRubberBand() return # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() # Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(config.DEFAULT_URL) return def ResizeDialog(self): ''' Expanded/Decreased Dialog ''' sender = QObject.sender(self) w = self.width() h = self.height() size = self.size() anim = QPropertyAnimation(self, b'size', self) anim.setStartValue(size) if sender.objectName() == "btn_ZoomOut": anim.setEndValue(QSize(w - 50, h - 50)) else: anim.setEndValue(QSize(w + 50, h + 50)) anim.setDuration(300) anim.start() return def GetBackNextImage(self): ''' Get to Back Image ''' sender = QObject.sender(self) lys = self.canvas.layers() # Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"There is no superiority that follows.") # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(ac_lordem) + "'")) ] # Update selected feature self.ReloadView(ids[0]) return self.ReloadView(ids[0]) if self.encontrado is False: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return def FullScreen(self, value): ''' FullScreen action button ''' qgsutils.showUserAndLogMessage(u"Information: ", u"Fullscreen.", onlyLog=True) if (value): self.showFullScreen() else: self.showNormal() return @staticmethod def ActualOrientation(yaw): ''' Get Actual yaw ''' geo360Plugin = qgis.utils.plugins["EquirectangularViewer"] if geo360Plugin is not None: geo360Dialog = qgis.utils.plugins["EquirectangularViewer"].dlg if geo360Dialog is not None: geo360Dialog.UpdateOrientation(yaw=float(yaw)) return def UpdateOrientation(self, yaw=None): ''' Update Orientation ''' self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except Exception: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setOrientation(self, yaw=None): ''' Set Orientation in the firt time ''' self.bearing = self.selected_features.attribute(config.column_yaw) self.actualPointDx = self.selected_features.geometry().asPoint() self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() epsg = self.canvas.mapSettings().destinationCrs().authid() self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setPosition(self): ''' Set RubberBand Position ''' self.actualPointDx = self.selected_features.geometry().asPoint() self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) def closeEvent(self, _): ''' Close dialog ''' self.resetQgsRubberBand() self.canvas.refresh() self.iface.actionPan().trigger() self.SaveSize() self.parent.dlg = None self.RemoveImage() return def resetQgsRubberBand(self): ''' Remove RubbeBand ''' try: self.positionSx.reset() self.positionInt.reset() self.positionDx.reset() self.actualPointOrientation.reset() except Exception: None
class ProfileTool(QgsMapTool): """ Tool class for making a line elevation profile """ ALT_TOLERANCE = 0.0005 SEARCH_TOLERANCE = 0.001 def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/profile_icon.png' self.text = QCoreApplication.translate("VDLTools", "Profile of a line") self.__lineLayer = None self.setCursor(Qt.ArrowCursor) self.__isChoosed = False self.__lastFeatureId = None self.__lastFeature = None self.__dockWdg = None self.__layDlg = None self.__msgDlg = None self.__confDlg = None self.__zeroDlg = None self.__points = None self.__layers = None self.__features = None self.__inSelection = False self.__selectedIds = None self.__selectedStarts = None self.__selectedDirections = None self.__startVertex = None self.__endVertex = None self.__rubberSit = None self.__rubberDif = None self.ownSettings = None self.__usedMnts = None self.__isfloating = False self.__dockGeom = None def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__dockWdg = ProfileDockWidget(self.__iface, self.__dockGeom) if self.__isfloating: self.__dockWdg.show() else: self.__iface.addDockWidget(Qt.BottomDockWidgetArea, self.__dockWdg) self.__dockWdg.closeSignal.connect(self.__closed) self.__rubberSit = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberDif = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubberSit.setColor(color) self.__rubberSit.setIcon(4) self.__rubberSit.setIconSize(20) self.__rubberDif.setColor(color) self.__rubberDif.setIcon(2) self.__rubberDif.setIconSize(20) def __closed(self): """ When the dock is closed """ self.__dockGeom = self.__dockWdg.geometry() self.__isfloating = self.__dockWdg.isFloating() self.__cancel() self.__iface.actionPan().trigger() def deactivate(self): """ When the action is deselected """ self.canvas().scene().removeItem(self.__rubberDif) self.__rubberDif = None self.canvas().scene().removeItem(self.__rubberSit) self.__rubberSit = None if self.__dockWdg is not None: self.__dockWdg.close() QgsMapTool.deactivate(self) def __cancel(self): """ To cancel used variables """ if self.__lineLayer is not None: self.__lineLayer.removeSelection() self.__lastFeatureId = None self.__lastFeature = None self.__selectedIds = None self.__selectedDirections = None self.__startVertex = None self.__endVertex = None self.__inSelection = False self.__layDlg = None self.__msgDlg = None self.__confDlg = None self.__zeroDlg = None self.__isChoosed = False def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer and QGis.fromOldWkbType(layer.wkbType()) == \ QgsWKBTypes.LineStringZ: self.__lineLayer = layer self.action().setEnabled(True) return self.action().setEnabled(False) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() if self.__dockWdg is not None: self.__dockWdg.close() self.__lineLayer = None def __setLayerDialog(self): """ To create a Profile Layers Dialog """ otherLayers = self.__lineVertices(True) with_mnt = True if self.ownSettings is None or self.ownSettings.mntUrl is None \ or self.ownSettings.mntUrl == "": with_mnt = False if not with_mnt and len(otherLayers) == 0: self.__layers = [] self.__layOk() else: self.__layDlg = ProfileLayersDialog(otherLayers, with_mnt) self.__layDlg.rejected.connect(self.__cancel) self.__layDlg.okButton().clicked.connect(self.__onLayOk) self.__layDlg.cancelButton().clicked.connect(self.__onLayCancel) self.__layDlg.show() def __setMessageDialog(self, situations, differences, names): """ To create a Profile Message Dialog :param situations: elevation differences between line and points :param differences: elevation differences between lines :param names: layers names """ self.__msgDlg = ProfileMessageDialog(situations, differences, names, self.__points) self.__msgDlg.rejected.connect(self.__checkZeros) self.__msgDlg.passButton().clicked.connect(self.__onMsgPass) self.__msgDlg.onLineButton().clicked.connect(self.__onMsgLine) self.__msgDlg.onPointsButton().clicked.connect(self.__onMsgPoints) def __setConfirmDialog(self, origin): """ To create a Profile Confirm Dialog :param origin: '0' if we copy points elevations to line, '1' if we copy line elevation to points """ self.__confDlg = ProfileConfirmDialog() if origin == 0 and not self.__lineLayer.isEditable(): self.__confDlg.setMessage( QCoreApplication.translate("VDLTools", "Do you really want to edit the LineString layer ?")) self.__confDlg.rejected.connect(self.__checkZeros) self.__confDlg.okButton().clicked.connect(self.__onConfirmLine) self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel) self.__confDlg.show() elif origin != 0: situations = self.__msgDlg.getSituations() case = True for s in situations: layer = self.__layers[s['layer'] - 1] if not layer.isEditable(): case = False break if not case: self.__confDlg.setMessage( QCoreApplication.translate("VDLTools", "Do you really want to edit the Point layer(s) ?")) self.__confDlg.rejected.connect(self.__checkZeros) self.__confDlg.okButton().clicked.connect(self.__onConfirmPoints) self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel) self.__confDlg.show() else: self.__confirmPoints() else: self.__confirmLine() def __getOtherLayers(self): """ To get all points layers that can be used :return: layers list """ layerList = [] types = [QgsWKBTypes.PointZ, QgsWKBTypes.LineStringZ, QgsWKBTypes.CircularStringZ, QgsWKBTypes.CompoundCurveZ, QgsWKBTypes.CurvePolygonZ, QgsWKBTypes.PolygonZ] for layer in self.canvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and QGis.fromOldWkbType(layer.wkbType()) in types: layerList.append(layer) return layerList def __onMsgPass(self): """ When the Pass button in Profile Message Dialog is pushed """ self.__msgDlg.reject() def __onConfirmCancel(self): """ When the Cancel button in Profile Confirm Dialog is pushed """ self.__confDlg.reject() def __onMsgLine(self): """ When the Line button in Profile Message Dialog is pushed """ self.__setConfirmDialog(0) def __onMsgPoints(self): """ When the Points button in Profile Message Dialog is pushed """ self.__setConfirmDialog(1) def __onConfirmLine(self): """ When the Line button in Profile Confirm Dialog is pushed """ self.__confDlg.accept() self.__confirmLine() def __checkZeros(self): """ To check if there are zeros in selected objects """ alts = [] nb_not_none = [] for i in range(len(self.__points)): zz = self.__points[i]['z'] alt = 0 nb = 0 for z in zz: if z is not None: nb += 1 if z > alt: alt = z alts.append(alt) nb_not_none.append(nb) zeros = [] for i in range(len(self.__points)): if alts[i] == 0: if i == 0: ap = None app = None j = 1 while True: if i+j > len(self.__points)-1: break if alts[i+j] != 0: ap = j j += 1 while True: if i+j > len(self.__points)-1: break if alts[i+j] != 0: app = j break j += 1 break j += 1 if ap is None or app is None: zeros.append([i, None, None]) else: big_d = Finder.sqrDistForCoords(self.__points[ap]['x'], self.__points[app]['x'], self.__points[ap]['y'], self.__points[app]['y']) small_d = Finder.sqrDistForCoords(self.__points[i]['x'], self.__points[ap]['x'], self.__points[i]['y'], self.__points[ap]['y']) if small_d < (old_div(big_d, 4)): zextra = alts[app] + (1 + old_div(small_d, big_d)) * (alts[ap] - alts[app]) zeros.append([i, zextra, nb_not_none[i]]) else: zeros.append([i, None, None]) elif i == len(self.__points)-1: av = None avv = None j = 1 while True: if i-j < 0: break if alts[i-j] != 0: av = j j += 1 while True: if i-j < 0: break if alts[i-j] != 0: avv = j break j += 1 break j += 1 if av is None or avv is None: zeros.append([i, None, None]) else: big_d = Finder.sqrDistForCoords(self.__points[i-av]['x'], self.__points[i-avv]['x'], self.__points[i-av]['y'], self.__points[i-avv]['y']) small_d = Finder.sqrDistForCoords(self.__points[i]['x'], self.__points[i-av]['x'], self.__points[i]['y'], self.__points[i-av]['y']) if small_d < (old_div(big_d, 4)): zextra = alts[i-avv] + (1 + old_div(small_d, big_d)) * (alts[i-av] - alts[i-avv]) zeros.append([i, zextra, nb_not_none[i]]) else: zeros.append([i, None, None]) else: av = None j = 1 while True: if i-j < 0: break if alts[i-j] != 0: av = j break j += 1 ap = None j = 1 while True: if i+j > len(self.__points)-1: break if alts[i+j] != 0: ap = j break j += 1 if av is None or ap is None: zeros.append([i, None, None]) else: d0 = Finder.sqrDistForCoords( self.__points[i-av]['x'], self.__points[i]['x'], self.__points[i-av]['y'], self.__points[i]['y']) d1 = Finder.sqrDistForCoords( self.__points[i+ap]['x'], self.__points[i]['x'], self.__points[i+ap]['y'], self.__points[i]['y']) zinter = old_div((d0*alts[i+ap] + d1*alts[i-av]), (d0 + d1)) zeros.append([i, zinter, nb_not_none[i]]) if len(zeros) > 0: self.__zeroDlg = ProfileZerosDialog(zeros) self.__zeroDlg.rejected.connect(self.__cancel) self.__zeroDlg.passButton().clicked.connect(self.__onZeroPass) self.__zeroDlg.applyButton().clicked.connect(self.__onZeroApply) self.__zeroDlg.show() else: self.__cancel() def __onZeroPass(self): """ When the Pass button in Profile Zeros Dialog is pushed """ self.__zeroDlg.reject() def __onZeroApply(self): """ When the Apply button in Profile Zeros Dialog is pushed """ self.__zeroDlg.accept() zeros = self.__zeroDlg.getZeros() num_lines = len(self.__selectedIds) lines = [] for iden in self.__selectedIds: for f in self.__lineLayer.selectedFeatures(): if f.id() == iden: line, curved = GeometryV2.asLineV2(f.geometry(), self.__iface) lines.append(line) break for z in zeros: for i in range(num_lines): if self.__points[z[0]]['z'][i] is not None: index = z[0]-self.__selectedStarts[i] if not self.__selectedDirections[i]: index = lines[i].numPoints()-1-index lines[i].setZAt(index, z[1]) if z[2] > 1: zz = self.__points[z[0]]['z'] for p in range(len(zz)-num_lines): if zz[num_lines+p] is not None: feat = self.__features[z[0]][p] layer = self.__layers[p] self.__changePoint(layer, z[0], feat, z[1]) if not self.__lineLayer.isEditable(): self.__lineLayer.startEditing() for i in range(len(lines)): geom = QgsGeometry(lines[i].clone()) self.__lineLayer.changeGeometry(self.__selectedIds[i], geom) # self.__lineLayer.updateExtents() self.__dockWdg.clearData() self.__lineVertices() self.__createProfile() self.__cancel() def __confirmLine(self): """ To change the elevations of some vertices of the line """ situations = self.__msgDlg.getSituations() num_lines = len(self.__selectedIds) points = {} for s in situations: if s['point'] not in points: points[s['point']] = self.__points[s['point']]['z'][s['layer']+num_lines-1] else: diff = abs(self.__points[s['point']]['z'][s['layer']+num_lines-1] - points[s['point']]) if diff > 0.001: QMessageBox.information( None, QCoreApplication.translate("VDLTools", "Elevation"), QCoreApplication.translate("VDLTools", "There is more than one elevation for the point ") + str(s['point']) ) return self.__msgDlg.accept() lines = [] for iden in self.__selectedIds: for f in self.__lineLayer.selectedFeatures(): if f.id() == iden: line, curved = GeometryV2.asLineV2(f.geometry(), self.__iface) lines.append(line) break for s in situations: z = self.__points[s['point']]['z'][s['layer']+num_lines-1] for i in range(num_lines): if self.__points[s['point']]['z'][i] is not None: index = s['point']-self.__selectedStarts[i] if not self.__selectedDirections[i]: index = lines[i].numPoints()-1-index lines[i].setZAt(index, z) if not self.__lineLayer.isEditable(): self.__lineLayer.startEditing() for i in range(len(lines)): geom = QgsGeometry(lines[i].clone()) self.__lineLayer.changeGeometry(self.__selectedIds[i], geom) self.__dockWdg.clearData() self.__lineVertices() self.__createProfile() self.__checkZeros() def __onConfirmPoints(self): """ When the Points button in Profile Confirm Dialog is pushed """ self.__confDlg.accept() self.__confirmPoints() def __confirmPoints(self): """ To change the elevations of certain points """ self.__msgDlg.accept() situations = self.__msgDlg.getSituations() num_lines = len(self.__selectedIds) for s in situations: layer = self.__layers[s['layer']-1] feat = self.__features[s['point']][s['layer']-1] newZ = 0 for i in range(num_lines): if self.__points[s['point']]['z'][i] is not None: newZ = self.__points[s['point']]['z'][i] break self.__changePoint(layer, s['point'], feat, newZ) self.__dockWdg.clearData() self.__lineVertices() self.__createProfile() self.__checkZeros() def __changePoint(self, layer, pos, feat, newZ): """ To change Vertex elevation :param layer: layer containing the object :param pos: vertex position in the object (if not a point) :param feat: QgsFeature of the object :param newZ: new elevation """ if layer.geometryType() == QGis.Polygon: closest = feat.geometry().closestVertex( QgsPoint(self.__points[pos]['x'], self.__points[pos]['y'])) feat_v2, curved = GeometryV2.asPolygonV2(feat.geometry(), self.__iface) position = GeometryV2.polygonVertexId(feat_v2, closest[1]) vertex = feat_v2.vertexAt(position) feat_v2.deleteVertex(position) vertex.setZ(newZ) feat_v2.insertVertex(position, vertex) elif layer.geometryType() == QGis.Line: closest = feat.geometry().closestVertex( QgsPoint(self.__points[pos]['x'], self.__points[pos]['y'])) feat_v2, curved = GeometryV2.asLineV2(feat.geometry(), self.__iface) feat_v2.setZAt(closest[1], newZ) else: feat_v2 = GeometryV2.asPointV2(feat.geometry(), self.__iface) feat_v2.setZ(newZ) if not layer.isEditable(): layer.startEditing() layer.changeGeometry(feat.id(), QgsGeometry(feat_v2)) def __onLayCancel(self): """ When the Cancel button in Profile Layers Dialog is pushed """ self.__layDlg.reject() self.__isChoosed = False def __lineVertices(self, checkLayers=False): """ To check if vertices of others layers are crossing the displaying line :param checkLayers: if we want to get the list of the other layers in return :return: other layers list if requested """ if checkLayers: availableLayers = self.__getOtherLayers() otherLayers = [] self.__points = [] self.__selectedStarts = [] num = 0 num_lines = len(self.__selectedIds) for iden in self.__selectedIds: self.__selectedStarts.append(max(0, len(self.__points)-1)) direction = self.__selectedDirections[num] selected = None for f in self.__lineLayer.selectedFeatures(): if f.id() == iden: selected = f break if selected is None: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error on selected"), level=QgsMessageBar.CRITICAL, duration=0 ) continue line_v2, curved = GeometryV2.asLineV2(selected.geometry(), self.__iface) if direction: rg = range(line_v2.numPoints()) else: rg = range(line_v2.numPoints()-1, -1, -1) rg_positions = [] for i in rg: pt_v2 = line_v2.pointN(i) x = pt_v2.x() y = pt_v2.y() doublon = False for position in rg_positions: if position['x'] == x and position['y'] == y and position['iden'] == iden: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Beware! the line ") + str(iden) + QCoreApplication.translate("VDLTools", " has 2 identical summits on the vertex ") + str(i-1) + QCoreApplication.translate("VDLTools", " same coordinates (X and Y). " "Please correct the line geometry."), level=QgsMessageBar.CRITICAL, duration=0 ) doublon = True break for item in self.__points: if item['x'] == x and item['y'] == y: item['z'][num] = pt_v2.z() rg_positions.append({'x': x, 'y': y, 'iden': iden}) doublon = True break if not doublon: rg_positions.append({'x': x, 'y': y, 'iden': iden}) z = [] for j in range(num_lines): if j == num: if pt_v2.z() == pt_v2.z(): z.append(pt_v2.z()) else: z.append(0) else: z.append(None) self.__points.append({'x': x, 'y': y, 'z': z}) if checkLayers: for layer in availableLayers: if layer in otherLayers: continue laySettings = QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.Vertex, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) f_l = Finder.findClosestFeatureAt(self.toMapCoordinates(layer, QgsPoint(x, y)), self.canvas(), [laySettings]) if f_l is not None: if layer == self.__lineLayer: other = False if f_l[0].id() not in self.__selectedIds: other = True else: fs = Finder.findFeaturesAt(QgsPoint(x, y), laySettings, self) for f in fs: if f.id() not in self.__selectedIds: vertex = f.geometry().closestVertex(QgsPoint(x, y)) if vertex[4] < self.SEARCH_TOLERANCE: other = True break if other and layer not in otherLayers: otherLayers.append(layer) elif layer not in otherLayers: otherLayers.append(layer) num += 1 if checkLayers: return otherLayers def __onLayOk(self): """ When the Ok button in Profile Layers Dialog is pushed """ self.__layDlg.accept() self.__layers = self.__layDlg.getLayers() self.__usedMnts = self.__layDlg.getUsedMnts() self.__layOk() def __layOk(self): """ To create the profile """ self.__createProfile() self.__checkSituations() self.__isChoosed = False def __createProfile(self): """ Create the profile in the dock """ self.__features = [] for points in self.__points: feat = [] x = points['x'] y = points['y'] z = points['z'] for layer in self.__layers: laySettings = QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.Vertex, self.SEARCH_TOLERANCE, QgsTolerance.LayerUnits) f_l = Finder.findClosestFeatureAt(self.toMapCoordinates(layer, QgsPoint(x, y)), self.canvas(), [laySettings]) if f_l is None: feat.append(None) z.append(None) else: if f_l[1].geometryType() == QGis.Polygon: closest = f_l[0].geometry().closestVertex(QgsPoint(x, y)) polygon_v2, curved = GeometryV2.asPolygonV2(f_l[0].geometry(), self.__iface) zp = polygon_v2.vertexAt(GeometryV2.polygonVertexId(polygon_v2, closest[1])).z() feat.append(f_l[0]) if zp is None or zp != zp: z.append(0) else: z.append(zp) elif f_l[1].geometryType() == QGis.Line: f_ok = None if layer == self.__lineLayer: if f_l[0].id() not in self.__selectedIds: f_ok = f_l[0] else: fs = Finder.findFeaturesAt(QgsPoint(x, y), laySettings, self) for f in fs: if f.id() not in self.__selectedIds: vertex = f.geometry().closestVertex(QgsPoint(x, y)) if vertex[4] < self.SEARCH_TOLERANCE: f_ok = f break else: f_ok = f_l[0] if f_ok is not None: closest = f_ok.geometry().closestVertex(QgsPoint(x, y)) feat.append(f_ok) line, curved = GeometryV2.asLineV2(f_ok.geometry(), self.__iface) zp = line.zAt(closest[1]) if zp is None or zp != zp: z.append(0) else: z.append(zp) else: feat.append(None) z.append(None) else: zp = GeometryV2.asPointV2(f_l[0].geometry(), self.__iface).z() feat.append(f_l[0]) if zp is None or zp != zp: z.append(0) else: z.append(zp) self.__features.append(feat) self.__calculateProfile() def __getNames(self): """ To get the names from connected lines layers :return: the names list """ names = [self.__lineLayer.name()] for layer in self.__layers: if layer.name() == self.__lineLayer.name(): names.append(layer.name() + " conn.") else: names.append(layer.name()) return names @staticmethod def __contains(line, point): """ To check if a position is a line vertex :param line: the line :param point: the position :return: the vertex id in the line, or -1 """ pos = 0 if point is None: return -1 for pt in line: if pt.x() == point.x() and pt.y() == point.y(): return pos pos += 1 return -1 def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__cancel() def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isChoosed: if self.__lineLayer is not None: laySettings = QgsSnappingUtils.LayerConfig(self.__lineLayer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(event.mapPoint(), self.canvas(), [laySettings]) if not self.__inSelection: if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeature = f_l[0] self.__lastFeatureId = f_l[0].id() self.__lineLayer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__cancel() else: if f_l is not None and (self.__selectedIds is None or f_l[0].id() not in self.__selectedIds): line = f_l[0].geometry().asPolyline() if self.__contains(line, self.__endVertex) > -1: self.__lastFeature = f_l[0] self.__lastFeatureId = f_l[0].id() features = self.__selectedIds + [f_l[0].id()] self.__lineLayer.setSelectedFeatures(features) elif self.__contains(line, self.__startVertex) > -1: self.__lastFeature = f_l[0] self.__lastFeatureId = f_l[0].id() features = self.__selectedIds + [f_l[0].id()] self.__lineLayer.setSelectedFeatures(features) else: self.__lineLayer.setSelectedFeatures(self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None if f_l is None: if self.__selectedIds is not None: self.__lineLayer.setSelectedFeatures(self.__selectedIds) self.__lastFeatureId = None self.__lastFeature = None def canvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ self.__rubberSit.reset() self.__rubberDif.reset() if event.button() == Qt.RightButton: if self.__lineLayer.selectedFeatures() is not None and self.__selectedIds is not None: self.__isChoosed = True self.__setLayerDialog() elif event.button() == Qt.LeftButton: if self.__lastFeature is not None and \ (self.__selectedIds is None or self.__lastFeature.id() not in self.__selectedIds): self.__inSelection = True line = self.__lastFeature.geometry().asPolyline() self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Select more lines with click left or process " "with click right (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) if self.__selectedIds is None: self.__selectedIds = [] self.__startVertex = line[0] self.__endVertex = line[-1] self.__selectedDirections = [] self.__selectedDirections.append(True) # direction du premier prime self.__selectedIds.append(self.__lastFeatureId) else: pos = self.__contains(line, self.__startVertex) if pos > -1: self.__selectedIds = [self.__lastFeatureId] + self.__selectedIds if pos == 0: direction = False self.__startVertex = line[-1] else: direction = True self.__startVertex = line[0] self.__selectedDirections = [direction] + self.__selectedDirections else: pos = self.__contains(line, self.__endVertex) self.__selectedIds.append(self.__lastFeatureId) if pos == 0: direction = True self.__endVertex = line[-1] else: direction = False self.__endVertex = line[0] self.__selectedDirections.append(direction) self.__lineLayer.setSelectedFeatures(self.__selectedIds) def __calculateProfile(self): """ To calculate the profile and display it """ if self.__points is None: return self.__dockWdg.clearData() if len(self.__points) == 0: return self.__dockWdg.setProfiles(self.__points, len(self.__selectedIds)) self.__dockWdg.attachCurves(self.__getNames(), self.ownSettings, self.__usedMnts) def __checkSituations(self): """ To check if point with no elevation on line, and one or more elevation from other layers, and if there are different elevations at the same point """ situations = [] differences = [] for p in range(len(self.__points)): pt = self.__points[p] num_lines = len(self.__selectedIds) zz = [] for i in range(num_lines): if pt['z'][i] is not None: zz.append(i) if len(zz) == 0: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "No line z ?!?"), level=QgsMessageBar.WARNING) elif len(zz) == 1: z0 = pt['z'][zz[0]] for i in range(num_lines, len(pt['z'])): if pt['z'][i] is None: continue if abs(pt['z'][i]-z0) > self.ALT_TOLERANCE: situations.append({'point': p, 'layer': (i-num_lines+1), 'vertex': z0}) elif len(zz) == 2: z0 = pt['z'][zz[0]] if abs(pt['z'][zz[1]] - z0) > self.ALT_TOLERANCE: differences.append({'point': p, 'v1': z0, 'v2': pt['z'][zz[1]]}) else: for i in range(num_lines, len(pt['z'])): if pt['z'][i] is None: continue if abs(pt['z'][i]-z0) > self.ALT_TOLERANCE: situations.append({'point': p, 'layer': (i-num_lines+1), 'vertex': z0}) else: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "More than 2 lines z ?!?"), level=QgsMessageBar.WARNING) if (len(situations) > 0) or (len(differences) > 0): self.__setMessageDialog(situations, differences, self.__getNames()) self.__rubberSit.reset() self.__rubberDif.reset() for situation in situations: pt = self.__points[situation['point']] point = QgsPoint(pt['x'], pt['y']) if self.__rubberSit.numberOfVertices() == 0: self.__rubberSit.setToGeometry(QgsGeometry().fromPoint(point), None) else: self.__rubberSit.addPoint(point) for difference in differences: pt = self.__points[difference['point']] point = QgsPoint(pt['x'], pt['y']) if self.__rubberDif.numberOfVertices() == 0: self.__rubberDif.setToGeometry(QgsGeometry().fromPoint(point), None) else: self.__rubberDif.addPoint(point) self.__msgDlg.show() else: self.__checkZeros()
class GeorefRasterBy2PointsMapTool(QgsMapToolEmitPoint): 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 setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = self.firstPoint = None self.isEmittingPoint = False self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def deactivate(self): QgsMapToolEmitPoint.deactivate(self) self.reset() def canvasPressEvent(self, e): if self.firstPoint is None: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.originalCenter = self.layer.center # this tool do the displacement itself TODO update so it is done by # transformed coordinates + new center) self.originalCornerPoints = \ self.layer.transformedCornerCoordinates( *self.layer.transformParameters()) self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) self.showDisplacement(self.startPoint, self.endPoint) self.layer.history.append({"action": "2pointsA", "center": self.layer.center}) else: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.startY = e.pos().y() self.endY = self.startY self.isEmittingPoint = True self.height = self.canvas.height() self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) self.layer.history.append( {"action": "2pointsB", "center": self.layer.center, "xScale": self.layer.xScale, "yScale": self.layer.yScale, "rotation": self.layer.rotation}) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() if self.firstPoint is None: x = (self.originalCenter.x() + self.endPoint.x() - self.startPoint.x()) y = (self.originalCenter.y() + self.endPoint.y() - self.startPoint.y()) self.layer.setCenter(QgsPointXY(x, y)) self.firstPoint = self.endPoint setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() else: rotation = self.computeRotation() xScale = yScale = self.computeScale() self.layer.moveCenterFromPointRotate( self.firstPoint, rotation, xScale, yScale) self.layer.setRotation(self.layer.rotation + rotation) self.layer.setScale(self.layer.xScale * xScale, self.layer.yScale * yScale) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rasterShadow.reset() self.firstPoint = None self.startPoint = self.endPoint = None def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) if self.firstPoint is None: self.showDisplacement(self.startPoint, self.endPoint) else: self.endY = e.pos().y() rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) def computeRotation(self): # The angle is the difference between angle # horizontal/endPoint-firstPoint and horizontal/startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.degrees(math.atan2(-dY, dX) - math.atan2(-dY0, dX0)) def computeScale(self): # The scale is the ratio between endPoint-firstPoint and # startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.sqrt((dX * dX + dY * dY) / (dX0 * dX0 + dY0 * dY0)) def showRotationScale(self, rotation, xScale, yScale): center, _, _, _ = self.layer.transformParameters() # newRotation = rotation + originalRotation cornerPoints = self.layer.transformedCornerCoordinatesFromPoint( self.firstPoint, rotation, xScale, yScale) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show() # Calculate the displacement of the center due to the rotation from # another point. newCenterDX = (cornerPoints[0].x() + cornerPoints[2].x()) / 2 - center.x() newCenterDY = (cornerPoints[0].y() + cornerPoints[2].y()) / 2 - center.y() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement(newCenterDX, newCenterDY, False) self.rasterShadow.setDeltaScale(xScale, yScale, False) self.rasterShadow.setDeltaRotation(rotation, True) self.rasterShadow.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point0 = QgsPointXY(self.startPoint.x(), self.startPoint.y()) point1 = QgsPointXY(self.firstPoint.x(), self.firstPoint.y()) point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y()) self.rubberBandDisplacement.addPoint(point0, False) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint( point2, True) # true to update canvas self.rubberBandDisplacement.show() def showDisplacement(self, startPoint, endPoint): self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandOrigin.addPoint(endPoint, True) self.rubberBandOrigin.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(endPoint.x(), endPoint.y()) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint( point2, True) # true to update canvas self.rubberBandDisplacement.show() self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in self.originalCornerPoints: self._addDisplacementToPoint(self.rubberBandExtent, point, False) # for closing self._addDisplacementToPoint( self.rubberBandExtent, self.originalCornerPoints[0], True) self.rubberBandExtent.show() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement(self.endPoint.x( ) - self.startPoint.x(), self.endPoint.y() - self.startPoint.y(), True) self.rasterShadow.show() def _addDisplacementToPoint(self, rubberBand, point, doUpdate): x = point.x() + self.endPoint.x() - self.startPoint.x() y = point.y() + self.endPoint.y() - self.startPoint.y() self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
class GeomEditorDialog(QDialog, Ui_GeomEditor, SettingDialog): 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 setEditor(self): self.editorLayout.removeWidget(self.editor) geom = self.editor.getGeom() idx = self.displayCombo.currentIndex() if idx == -99999: editor = CellEditor elif idx == 0: editor = WktEditor elif idx == 1: editor = WkbEditor else: self.editor = GeomEditor return self.editor = editor(self.layer, geom, self) self.editorLayout.addWidget(self.editor, 0, 0, 1, 1) self.editor.currentPointChanged.connect(self.drawCurrentPoint) self.editor.geometryChanged.connect(self.geometryChanged) def resetGeometry(self): self.editor.setGeom(self.initialGeometry) def closeEvent(self, e): self.featureRubber.reset() self.currentPointRubber.reset() self.layer.editingStarted.disconnect(self.layerEditable) self.layer.editingStopped.disconnect(self.layerEditable) self.editor.closeEditor() QDialog.closeEvent(self, e) def layerEditable(self): layerIsEditable = self.layer.isEditable() self.resetButton.setEnabled(layerIsEditable) self.applyButton.setEnabled(layerIsEditable) def geometryChanged(self): self.featureRubber.reset() self.currentPointRubber.reset() if self.editor.isGeomValid(): self.displayCombo.setEnabled(True) self.applyButton.setEnabled(self.layer.isEditable()) geomStatus = "Geometry is valid" if self.sketchGeometry.isChecked(): self.featureRubber.setToGeometry(self.editor.getGeom(), self.layer) else: self.applyButton.setEnabled(False) self.displayCombo.setEnabled(False) geomStatus = "Geometry is not valid" self.geomStatusLabel.setText(geomStatus) @pyqtSlot(QgsGeometry) def drawCurrentPoint(self, point): if self.displayPointRubber.isChecked(): self.currentPointRubber.setToGeometry(point, None) self.mapCanvas.refresh() def applyGeometry(self): geometry = self.editor.getGeom() if geometry is not None: self.layer.changeGeometry(self.feature.id(), geometry) self.layer.updateExtents() self.layer.setCacheImage(None) self.layer.triggerRepaint() def updateFeatureRubber(self): self.featureRubber.setColor(self.settings.value("featureRubberColor")) self.featureRubber.setWidth(self.settings.value("featureRubberSize")) self.layer.triggerRepaint() def updateCurrentPointRubber(self): self.currentPointRubber.setIconSize(self.settings.value("currentPointRubberSize")) self.currentPointRubber.setColor(self.settings.value("currentPointRubberColor")) self.currentPointRubber.setIcon(self.settings.value("currentPointRubberIcon")) self.mapCanvas.refresh()
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.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) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) finder.message.connect(self.message) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # create categories in special order and count activated ones for finder in self.finders.values(): if finder.activated(): self.resultModel.addResult(finder.name) bbox = self.mapCanvas.fullExtent() for finder in self.finders.values(): if finder.activated(): finder.start(toFind, bbox=bbox) def stop(self): for finder in self.finders.values(): if finder.isRunning(): finder.stop() def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def message(self, finder, message, level): self.iface.messageBar().pushMessage("Quick Finder", message, level, 3) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() return def transformGeom(self, item): geometry = item.geometry src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = item.geometry geom.transform( QgsCoordinateTransform(src_crs, dest_crs) ) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class IntersectTool(QgsMapTool): """ Map tool class to create temporary circle, with center point """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/intersect_icon.png' self.text = QCoreApplication.translate("VDLTools", "From intersection") self.setCursor(Qt.ArrowCursor) self.__lineLayerID = None self.__pointLayerID = None self.__rubber = None self.ownSettings = None self.__isEditing = False self.__distance = 0 def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__rubber = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setIconSize(20) self.__rubber.setWidth(2) self.__distance = 6.0 def deactivate(self): """ When the action is deselected """ self.__cancel() self.__rubber = None QgsMapTool.deactivate(self) def __cancel(self): """ To cancel used variables """ if self.__rubber is not None: self.__rubber.reset() self.__isEditing = False def __setDistanceDialog(self, mapPoint): """ To create an Intersect Distance Dialog :param mapPoint: radius of the circle """ self.__dstDlg = IntersectDistanceDialog(mapPoint) self.__dstDlg.rejected.connect(self.__cancel) self.__dstDlg.okButton().clicked.connect(self.__onDstOk) self.__dstDlg.cancelButton().clicked.connect(self.__onDstCancel) self.__dstDlg.observation().setValue(self.__distance) self.__dstDlg.observation().selectAll() self.__dstDlg.show() def __onDstOk(self): """ When the Ok button in Intersect Distance Dialog is pushed """ self.__distance = float(self.__dstDlg.observation().text()) circle = QgsCircularStringV2() x = self.__dstDlg.mapPoint().x() y = self.__dstDlg.mapPoint().y() circle.setPoints([QgsPointV2(x + self.__distance * cos(pi / 180 * a), y + self.__distance * sin(pi / 180 * a)) for a in range(0, 361, 90)]) lineLayer = self.__lineLayer() lineLayer.startEditing() feature = QgsFeature() feature.setGeometry(QgsGeometry(circle)) fields = lineLayer.pendingFields() feature.setFields(fields) fieldsNames = [fields.at(pos).name() for pos in range(fields.count())] if "distance" in fieldsNames: feature.setAttribute("distance", self.__distance) if "x" in fieldsNames: feature.setAttribute("x", self.__dstDlg.mapPoint().x()) if "y" in fieldsNames: feature.setAttribute("y", self.__dstDlg.mapPoint().y()) lineLayer.addFeature(feature) # lineLayer.updateExtents() lineLayer.commitChanges() # center pointLayer = self.__pointLayer() pointLayer.startEditing() feature = QgsFeature() feature.setGeometry(QgsGeometry().fromPoint(self.__dstDlg.mapPoint())) fields = pointLayer.pendingFields() feature.setFields(fields) pointLayer.addFeature(feature) pointLayer.commitChanges() self.__dstDlg.accept() self.__cancel() def __onDstCancel(self): """ When the Cancel button in Intersect Distance Dialog is pushed """ self.__dstDlg.reject() def canvasMoveEvent(self, mouseEvent): """ When the mouse is moved :param mouseEvent: mouse event """ if not self.__isEditing: self.__rubber.reset() match = Finder.snap(mouseEvent.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubber.setIcon(4) else: self.__rubber.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections(point, self.canvas(), self) if intersection is not None: self.__rubber.setIcon(1) point = intersection else: self.__rubber.setIcon(3) self.__rubber.setToGeometry(QgsGeometry().fromPoint(point), None) def canvasReleaseEvent(self, mouseEvent): """ When the mouse is clicked :param mouseEvent: mouse event """ if mouseEvent.button() != Qt.LeftButton: return match = Finder.snap(mouseEvent.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasEdge(): intersection = Finder.snapCurvedIntersections(match.point(), self.canvas(), self) if intersection is not None: point = intersection self.__isEditing = True self.__setDistanceDialog(point) def __lineLayer(self): """ To get the line layer to create the circle :return: a line layer """ if self.ownSettings is not None: if self.ownSettings.linesLayer is not None: layer = self.ownSettings.linesLayer self.__lineLayerID = layer.id() return layer layer = QgsMapLayerRegistry.instance().mapLayer(self.__lineLayerID) if layer is None: epsg = self.canvas().mapRenderer().destinationCrs().authid() layer = QgsVectorLayer("LineString?crs=%s&index=yes&field=distance:double&field=x:double&field=y:double" % epsg, "Memory Lines", "memory") QgsMapLayerRegistry.instance().addMapLayer(layer) layer.layerDeleted.connect(self.__lineLayerDeleted) self.__lineLayerID = layer.id() if self.ownSettings is not None: self.ownSettings.linesLayer = layer else: self.__iface.legendInterface().setLayerVisible(layer, True) return layer def __lineLayerDeleted(self): """ To deselect the line layer when it is deleted """ self.lineLayerID = None def __pointLayer(self): """ To get the point layer to create the center :return: a point layer """ if self.ownSettings is not None: if self.ownSettings.pointsLayer is not None: layer = self.ownSettings.pointsLayer self.__pointLayerID = layer.id() return layer layer = QgsMapLayerRegistry.instance().mapLayer(self.__pointLayerID) if layer is None: epsg = self.canvas().mapRenderer().destinationCrs().authid() layer = QgsVectorLayer("Point?crs=%s&index=yes" % epsg, "Memory Points", "memory") QgsMapLayerRegistry.instance().addMapLayer(layer) layer.layerDeleted.connect(self.__pointLayerDeleted) self.__pointLayerID = layer.id() if self.ownSettings is not None: self.ownSettings.pointsLayer = layer else: self.__iface.legendInterface().setLayerVisible(layer, True) return layer def __pointLayerDeleted(self): """ To deselect the point layer when it is deleted """ self.__pointLayerID = None
class MoveTool(QgsMapTool): def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.__canvas = iface.mapCanvas() self.__icon_path = ':/plugins/VDLTools/icons/move_icon.png' self.__text = QCoreApplication.translate("VDLTools", "Move/Copy a feature") self.setCursor(Qt.ArrowCursor) self.__isEditing = 0 self.__findVertex = 0 self.__onMove = 0 self.__counter = 0 self.__layer = None self.__confDlg = None self.__lastFeatureId = None self.__selectedFeature = None self.__rubberBand = None self.__rubberSnap = None self.__newFeature = None self.__selectedVertex = None self.__layerConfig = None def icon_path(self): """ To get the icon path :return: icon path """ return self.__icon_path def text(self): """ To get the menu text :return: menu text """ return self.__text def toolName(self): """ To get the tool name :return: tool name """ return QCoreApplication.translate("VDLTools", "Move/Copy") def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__updateList() self.__canvas.layersChanged.connect(self.__updateList) QgsProject.instance().snapSettingsChanged.connect(self.__updateList) def deactivate(self): """ When the action is deselected """ self.__canvas.layersChanged.disconnect(self.__updateList) QgsProject.instance().snapSettingsChanged.disconnect(self.__updateList) QgsMapTool.deactivate(self) def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) self.__layer.editingStarted.disconnect(self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) self.__layer.editingStopped.disconnect(self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.__canvas.mapTool == self: self.__iface.actionPan().trigger() def setTool(self): """ To set the current tool as this one """ self.__canvas.setMapTool(self) def removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): self.__layer.editingStopped.disconnect(self.stopEditing) else: self.__layer.editingStarted.disconnect(self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None\ and isinstance(layer, QgsVectorLayer): if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): self.__layer.editingStopped.disconnect(self.stopEditing) else: self.__layer.editingStarted.disconnect(self.startEditing) self.__layer = layer if self.__layer.isEditable(): self.action().setEnabled(True) self.__updateList() self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.__canvas.mapTool == self: self.__iface.actionPan().trigger() return self.action().setEnabled(False) self.removeLayer() def __pointPreview(self, point): """ To create a point geometry preview (rubberBand) :param point: new position as mapPoint """ point_v2 = GeometryV2.asPointV2(self.__selectedFeature.geometry()) self.__newFeature = QgsPointV2(point.x(), point.y()) self.__newFeature.addZValue(point_v2.z()) self.__rubberBand = QgsRubberBand(self.__canvas, QGis.Point) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.clone()), None) def __linePreview(self, point): """ To create a line geometry preview (rubberBand) :param point: new position as mapPoint """ line_v2, curved = GeometryV2.asLineV2( self.__selectedFeature.geometry()) print(self.__selectedVertex) vertex = QgsPointV2() line_v2.pointAt(self.__selectedVertex, vertex) self.__rubberBand = QgsRubberBand(self.__canvas, QGis.Line) dx = vertex.x() - point.x() dy = vertex.y() - point.y() if isinstance(curved, (list, tuple)): self.__newFeature = QgsCompoundCurveV2() for pos in xrange(line_v2.nCurves()): curve_v2 = self.__newCurve(curved[pos], line_v2.curveAt(pos), dx, dy) self.__newFeature.addCurve(curve_v2) if pos == 0: self.__rubberBand.setToGeometry( QgsGeometry(curve_v2.curveToLine()), None) else: self.__rubberBand.addGeometry( QgsGeometry(curve_v2.curveToLine()), None) else: self.__newFeature = self.__newCurve(curved, line_v2, dx, dy) self.__rubberBand.setToGeometry( QgsGeometry(self.__newFeature.curveToLine()), None) def __newCurve(self, curved, line_v2, dx, dy): if curved: newCurve = QgsCircularStringV2() else: newCurve = QgsLineStringV2() points = [] for pos in xrange(line_v2.numPoints()): x = line_v2.pointN(pos).x() - dx y = line_v2.pointN(pos).y() - dy pt = QgsPointV2(x, y) pt.addZValue(line_v2.pointN(pos).z()) points.append(pt) newCurve.setPoints(points) return newCurve def __polygonPreview(self, point): """ To create a polygon geometry preview (rubberBand) :param point: new position as mapPoint """ polygon_v2, curved = GeometryV2.asPolygonV2( self.__selectedFeature.geometry()) vertex = polygon_v2.vertexAt(self.__polygonVertexId(polygon_v2)) dx = vertex.x() - point.x() dy = vertex.y() - point.y() self.__newFeature = QgsCurvePolygonV2() self.__rubberBand = QgsRubberBand(self.__canvas, QGis.Line) line_v2 = self.__newLine(polygon_v2.exteriorRing(), dx, dy, curved[0]) self.__newFeature.setExteriorRing(line_v2) self.__rubberBand.setToGeometry(QgsGeometry(line_v2.curveToLine()), None) for num in xrange(polygon_v2.numInteriorRings()): line_v2 = self.__newLine(polygon_v2.interiorRing(num), dx, dy, curved[num + 1]) self.__newFeature.addInteriorRing(line_v2) self.__rubberBand.addGeometry(QgsGeometry(line_v2.curveToLine()), None) def __polygonVertexId(self, polygon_v2): """ To get the id of the selected vertex from a polygon :param polygon_v2: the polygon as polygonV2 :return: id as QgsVertexId """ eR = polygon_v2.exteriorRing() if self.__selectedVertex < eR.numPoints(): return QgsVertexId(0, 0, self.__selectedVertex, 1) else: sel = self.__selectedVertex - eR.numPoints() for num in xrange(polygon_v2.numInteriorRings()): iR = polygon_v2.interiorRing(num) if sel < iR.numPoints(): return QgsVertexId(0, num + 1, sel, 1) sel -= iR.numPoints() def __newLine(self, curve_v2, dx, dy, curved): """ To create a new moved line for a part of a polygon :param curve_v2: the original line :param dx: x translation :param dy: y translation :return: the line as lineV2 """ if curved: new_line_v2 = QgsCircularStringV2() else: new_line_v2 = QgsLineStringV2() points = [] for pos in xrange(curve_v2.numPoints()): x = curve_v2.pointN(pos).x() - dx y = curve_v2.pointN(pos).y() - dy pt = QgsPointV2(x, y) pt.addZValue(curve_v2.pointN(pos).z()) points.append(pt) new_line_v2.setPoints(points) return new_line_v2 def __onConfirmClose(self): """ When the Cancel button in Move Confirm Dialog is pushed """ self.__confDlg.close() self.__rubberBand.reset() self.__rubberSnap.reset() self.__isEditing = 0 self.__lastFeatureId = None self.__selectedFeature = None self.__rubberBand = None self.__rubberSnap = None self.__newFeature = None self.__selectedVertex = None self.__layer.removeSelection() def __onConfirmMove(self): """ When the Move button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL) self.__layer.changeGeometry(self.__selectedFeature.id(), geometry) self.__layer.updateExtents() self.__onConfirmClose() def __onConfirmCopy(self): """ When the Copy button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL) feature = QgsFeature(self.__layer.pendingFields()) feature.setGeometry(geometry) primaryKey = QgsDataSourceURI(self.__layer.source()).keyColumn() for field in self.__selectedFeature.fields(): if field.name() != primaryKey: feature.setAttribute( field.name(), self.__selectedFeature.attribute(field.name())) if len(self.__selectedFeature.fields()) > 0 and \ self.__layer.editFormConfig().suppress() != QgsEditFormConfig.SuppressOn: self.__iface.openFeatureForm(self.__layer, feature) else: self.__layer.addFeature(feature) self.__layer.updateExtents() self.__onConfirmClose() def __updateList(self): """ To update the snapping options of the layer """ noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(self.__layer.id()) self.__layerConfig = QgsSnappingUtils.LayerConfig( self.__layer, QgsPointLocator.Vertex, tolerance, unitType) if not enabled or tolerance == 0: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate( "VDLTools", "This layer has no snapping options"), level=QgsMessageBar.CRITICAL) def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isEditing and not self.__findVertex and not self.__onMove: f = Finder.findClosestFeatureAt(event.mapPoint(), self.__layerConfig, self) if f is not None and self.__lastFeatureId != f.id(): self.__lastFeatureId = f.id() self.__layer.setSelectedFeatures([f.id()]) if f is None: self.__layer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: self.__rubberBand.reset() closest = self.__selectedFeature.geometry().closestVertex( event.mapPoint()) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__rubberBand.setToGeometry( QgsGeometry().fromPoint(closest[0]), None) elif self.__onMove: if self.__rubberBand: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(event.mapPoint()) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(event.mapPoint()) else: self.__pointPreview(event.mapPoint()) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setWidth(2) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) if self.__rubberSnap: self.__rubberSnap.reset() else: self.__rubberSnap = QgsRubberBand(self.__canvas, QGis.Point) self.__rubberSnap.setColor(color) self.__rubberSnap.setWidth(2) self.__rubberSnap.setIconSize(20) match = Finder.snap(event.mapPoint(), self.__canvas, True) if match.hasVertex(): if match.layer(): self.__rubberSnap.setIcon(4) self.__rubberSnap.setToGeometry( QgsGeometry().fromPoint(match.point()), None) else: self.__rubberSnap.setIcon(1) self.__rubberSnap.setToGeometry( QgsGeometry().fromPoint(match.point()), None) if match.hasEdge(): self.__rubberSnap.setIcon(3) self.__rubberSnap.setToGeometry( QgsGeometry().fromPoint(match.point()), None) # if self.__counter > 2: # if self.__rubberSnap: # self.__rubberSnap.reset() # else: # self.__rubberSnap = QgsRubberBand(self.__canvas, QGis.Point) # self.__rubberSnap.setColor(color) # self.__rubberSnap.setWidth(2) # self.__rubberSnap.setIconSize(20) # snappedIntersection = Finder.snapToIntersection(event.mapPoint(), self, self.__layerList) # if snappedIntersection is None: # snappedPoint = Finder.snapToLayers(event.mapPoint(), self.__snapperList) # if snappedPoint is not None: # self.__rubberSnap.setIcon(4) # self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(snappedPoint), None) # else: # self.__rubberSnap.setIcon(1) # self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(snappedIntersection), None) # self.__counter = 0 # else: # self.__counter += 1 def canvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if not self.__isEditing and not self.__findVertex and not self.__onMove: found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) < 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] if self.__layer.geometryType() != QGis.Point: self.__findVertex = 1 self.__rubberBand = QgsRubberBand(self.__canvas, QGis.Point) else: self.__onMove = 1 # self.__snapperList, self.__layerList = Finder.updateSnapperList(self.__iface) elif self.__findVertex: self.__findVertex = 0 closest = self.__selectedFeature.geometry().closestVertex( event.mapPoint()) self.__selectedVertex = closest[1] self.__onMove = 1 # self.__snapperList, self.__layerList = Finder.updateSnapperList(self.__iface) elif self.__onMove: self.__onMove = 0 mapPoint = event.mapPoint() match = Finder.snap(event.mapPoint(), self.__canvas, True) if match.hasVertex() or match.hasEdge(): mapPoint = match.point() # snappedIntersection = Finder.snapToIntersection(event.mapPoint(), self, self.__layerList) # if snappedIntersection is None: # snappedPoint = Finder.snapToLayers(event.mapPoint(), self.__snapperList) # if snappedPoint is not None: # mapPoint = snappedPoint # else: # mapPoint = snappedIntersection self.__isEditing = 1 if self.__rubberBand: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(mapPoint) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(mapPoint) else: self.__pointPreview(mapPoint) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setWidth(2) self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__confDlg = MoveConfirmDialog() self.__confDlg.moveButton().clicked.connect(self.__onConfirmMove) self.__confDlg.copyButton().clicked.connect(self.__onConfirmCopy) self.__confDlg.cancelButton().clicked.connect( self.__onConfirmClose) self.__confDlg.show()
class DistanceMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.lineLayer = MemoryLayers(iface).lineLayer() self.settings = MySettings() QgsMapTool.__init__(self, iface.mapCanvas()) def activate(self): QgsMapTool.activate(self) self.rubber = QgsRubberBand(self.canvas(), QGis.Point) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIcon(self.settings.value("rubberIcon")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.messageWidget = self.iface.messageBar().createMessage( "Intersect It", "Not snapped.") self.messageWidgetExist = True self.messageWidget.destroyed.connect(self.messageWidgetRemoved) def deactivate(self): self.iface.messageBar().popWidget(self.messageWidget) self.rubber.reset() QgsMapTool.deactivate(self) def messageWidgetRemoved(self): self.messageWidgetExist = False def displaySnapInfo(self, match=None): if not self.messageWidgetExist: return if match is None: message = "No snap" else: message = 'Snapped to: <b>{}</b>'.format(match.layer()) self.messageWidget.setText(message) def canvasMoveEvent(self, mouseEvent): match = self.snap_to_vertex(mouseEvent.pos()) self.rubber.reset(QGis.Point) if match.type( ) == QgsPointLocator.Vertex and match.layer() != self.lineLayer: self.rubber.addPoint(match.point()) self.displaySnapInfo(match) def canvasPressEvent(self, mouseEvent): if mouseEvent.button() != Qt.LeftButton: return match = self.snap_to_vertex(mouseEvent.pos()) if match.type() != QgsPointLocator.Vertex and match.layer( ) != self.lineLayer: point = self.toMapCoordinates(mouseEvent.pos()) else: point = match.point() self.rubber.addPoint(point) distance = Distance(self.iface, point, 1) dlg = DistanceDialog(distance, self.canvas()) if dlg.exec_(): distance.save() self.rubber.reset() def snap_to_vertex(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.Vertex) 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
class MoveTool(QgsMapToolAdvancedDigitizing): """ Map tool class to move or copy an object """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/move_icon.png' self.text = QCoreApplication.translate("VDLTools", "Move/Copy a feature") self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__findVertex = False self.__onMove = False self.__layer = None self.__confDlg = None self.__lastFeatureId = None self.__selectedFeature = None self.__rubberBand = None self.__rubberSnap = None self.__newFeature = None self.__selectedVertex = None def activate(self): """ When the action is selected """ QgsMapToolAdvancedDigitizing.activate(self) if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def deactivate(self): """ When the action is deselected """ self.__cancel() QgsMapToolAdvancedDigitizing.deactivate(self) def toolName(self): """ To get the tool name :return: tool name """ return QCoreApplication.translate("VDLTools", "Move/Copy") def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def __cancel(self): """ To cancel used variables """ if self.__rubberBand is not None: self.canvas().scene().removeItem(self.__rubberBand) self.__rubberBand.reset() self.__rubberBand = None if self.__rubberSnap is not None: self.canvas().scene().removeItem(self.__rubberSnap) self.__rubberSnap.reset() self.__rubberSnap = None self.__isEditing = False self.__findVertex = False self.__onMove = False self.__lastFeatureId = None self.__selectedFeature = None self.__confDlg = None self.__newFeature = None self.__selectedVertex = None self.__layer.removeSelection() if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return self.action().setEnabled(False) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() self.__removeLayer() def __pointPreview(self, point): """ To create a point geometry preview (rubberBand) :param point: new position as mapPoint """ point_v2 = GeometryV2.asPointV2(self.__selectedFeature.geometry(), self.__iface) self.__newFeature = QgsPointV2(point.x(), point.y()) self.__newFeature.addZValue(point_v2.z()) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.clone()), None) def __linePreview(self, point): """ To create a line geometry preview (rubberBand) :param point: new position as mapPoint """ line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface) vertex = QgsPointV2() line_v2.pointAt(self.__selectedVertex, vertex) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) dx = vertex.x() - point.x() dy = vertex.y() - point.y() if isinstance(curved, (list, tuple)): self.__newFeature = QgsCompoundCurveV2() for pos in range(line_v2.nCurves()): curve_v2 = self.__newCurve(curved[pos], line_v2.curveAt(pos), dx, dy) self.__newFeature.addCurve(curve_v2) if pos == 0: self.__rubberBand.setToGeometry(QgsGeometry(curve_v2.curveToLine()), None) else: self.__rubberBand.addGeometry(QgsGeometry(curve_v2.curveToLine()), None) else: self.__newFeature = self.__newCurve(curved, line_v2, dx, dy) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.curveToLine()), None) @staticmethod def __newCurve(curved, line_v2, dx, dy): """ To create a new moved line :param curved: if the line is curved :param line_v2: the original line :param dx: x translation :param dy: y translation :return: the new line """ if curved: newCurve = QgsCircularStringV2() else: newCurve = QgsLineStringV2() points = [] for pos in range(line_v2.numPoints()): x = line_v2.pointN(pos).x() - dx y = line_v2.pointN(pos).y() - dy pt = QgsPointV2(x, y) pt.addZValue(line_v2.pointN(pos).z()) points.append(pt) newCurve.setPoints(points) return newCurve def __polygonPreview(self, point): """ To create a polygon geometry preview (rubberBand) :param point: new position as mapPoint """ polygon_v2, curved = GeometryV2.asPolygonV2(self.__selectedFeature.geometry(), self.__iface) vertex = polygon_v2.vertexAt(GeometryV2.polygonVertexId(polygon_v2, self.__selectedVertex)) dx = vertex.x() - point.x() dy = vertex.y() - point.y() self.__newFeature = QgsCurvePolygonV2() self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) line_v2 = self.__newCurve(curved[0], polygon_v2.exteriorRing(), dx, dy) self.__newFeature.setExteriorRing(line_v2) self.__rubberBand.setToGeometry(QgsGeometry(line_v2.curveToLine()), None) for num in range(polygon_v2.numInteriorRings()): line_v2 = self.__newCurve(curved[num+1], polygon_v2.interiorRing(num), dx, dy) self.__newFeature.addInteriorRing(line_v2) self.__rubberBand.addGeometry(QgsGeometry(line_v2.curveToLine()), None) def __onConfirmCancel(self): """ When the Cancel button in Move Confirm Dialog is pushed """ self.__confDlg.reject() def __onConfirmMove(self): """ When the Move button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) self.__layer.changeGeometry(self.__selectedFeature.id(), geometry) self.__confDlg.accept() self.__cancel() def __onConfirmCopy(self): """ When the Copy button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) feature = QgsFeature(self.__layer.pendingFields()) feature.setGeometry(geometry) primaryKey = QgsDataSourceURI(self.__layer.source()).keyColumn() for field in self.__selectedFeature.fields(): if field.name() != primaryKey: feature.setAttribute(field.name(), self.__selectedFeature.attribute(field.name())) if len(self.__selectedFeature.fields()) > 0 and self.__layer.editFormConfig().suppress() != \ QgsEditFormConfig.SuppressOn: self.__iface.openFeatureForm(self.__layer, feature) else: self.__layer.addFeature(feature) self.__confDlg.accept() self.__cancel() def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__cancel() def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and not self.__onMove: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), [laySettings]) if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__layer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: if self.__rubberBand is not None: self.__rubberBand.reset() closest = self.__selectedFeature.geometry().closestVertex(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__rubberBand.setToGeometry(QgsGeometry().fromPoint(closest[0]), None) elif self.__onMove: if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(map_point) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(map_point) else: self.__pointPreview(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setWidth(2) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(8) if self.__rubberSnap is not None: self.__rubberSnap.reset() else: self.__rubberSnap = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberSnap.setColor(color) self.__rubberSnap.setWidth(2) self.__rubberSnap.setIconSize(20) match = Finder.snap(map_point, self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubberSnap.setIcon(4) else: self.__rubberSnap.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections(point, self.canvas(), self) if intersection is not None: self.__rubberSnap.setIcon(1) point = intersection else: self.__rubberSnap.setIcon(3) self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(point), None) def cadCanvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if not self.__isEditing and not self.__findVertex and not self.__onMove: found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] if self.__layer.geometryType() != QGis.Point: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Select vertex for moving (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) self.__findVertex = True self.setMode(self.CaptureLine) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) else: self.setMode(self.CaptureNone) self.__onMove = True elif self.__findVertex: self.__findVertex = False self.setMode(self.CaptureNone) closest = self.__selectedFeature.geometry().closestVertex(event.mapPoint()) self.__selectedVertex = closest[1] self.__onMove = True elif self.__onMove: self.__onMove = False mapPoint = event.mapPoint() match = Finder.snap(event.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): mapPoint = match.point() if match.hasEdge(): intersection = Finder.snapCurvedIntersections(mapPoint, self.canvas(), self) if intersection is not None: mapPoint = intersection self.__isEditing = True if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(mapPoint) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(mapPoint) else: self.__pointPreview(mapPoint) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setWidth(2) self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__confDlg = MoveConfirmDialog() self.__confDlg.rejected.connect(self.__cancel) self.__confDlg.moveButton().clicked.connect(self.__onConfirmMove) self.__confDlg.copyButton().clicked.connect(self.__onConfirmCopy) self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel) self.__confDlg.show()
class nominatim_dlg(QDockWidget, Ui_search): def getHttp(self, uri, params): QgsApplication.setOverrideCursor(Qt.WaitCursor) try: rq = QUrl(uri) q = QUrlQuery() for (k, v) in params.items(): q.addQueryItem(k, v) rq.setQuery(q) req = QNetworkRequest(rq) try: reply = self.nominatim_networkAccessManager.blockingGet(req) resource = reply.content().data().decode('utf8') r = json.loads(resource) if (isinstance(r, list)): self.populateTable(r) else: self.populateTable([r]) except: self.tableResult.clearContents() finally: QgsApplication.restoreOverrideCursor() def searchJson(self, params, user, options, options2): contents = str(options).strip() items = contents.split(' ') for (k, v) in options2.items(): if k in ['viewbox']: params["bounded"] = "1" params[k] = v pairs = [] for item in items: pair = item.split('=', 1) if (pair != [''] and pair != [] and len(pair) > 1): pairs.append(pair) for (k, v) in pairs: if k in ['viewbox', 'countrycodes', 'limit', 'exclude_place_ids', 'addressdetails', 'exclude_place_ids', 'bounded', 'routewidth', 'osm_type', 'osm_id'] and not(k in options2.keys()): params[k] = v if k in ['viewbox']: params["bounded"] = "1" params["polygon_text"] = "1" params["format"] = "json" uri = 'https://nominatim.openstreetmap.org/search' self.getHttp(uri, params) def findNearbyJSON(self, params, user, options): uri = "https://nominatim.openstreetmap.org/reverse" params["format"] = "json" self.getHttp(uri, params) """ Gestion de l'évènement "leave", afin d'effacer l'objet sélectionné en sortie du dock """ def eventFilter(self, obj, event): typ = event.type() if typ == event.Leave: try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass return False def __init__(self, parent, plugin): self.plugin = plugin QDockWidget.__init__(self, parent) self.setupUi(self) self.btnApply.setIcon(QIcon(":plugins/nominatim/arrow_green.png")) self.btnMask.setIcon(QIcon(":plugins/nominatim/add_mask.png")) self.btnLayer.setIcon(QIcon(":plugins/nominatim/add_layer.png")) self.tableResult.installEventFilter(self) # cf. eventFilter method self.tableResult.cellDoubleClicked.connect(self.onChoose) self.tableResult.cellEntered.connect(self.cellEntered) self.editSearch.returnPressed.connect(self.onReturnPressed) self.btnSearch.clicked.connect(self.onReturnPressed) self.btnApply.clicked.connect(self.onApply) self.btnHelp.clicked.connect(self.plugin.do_help) self.btnLocalize.clicked.connect(self.doLocalize) self.btnMask.clicked.connect(self.onMask) self.btnLayer.clicked.connect(self.onLayer) self.MultiPolygonLayerId = None self.LineLayerId = None self.PointLayerId = None try: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) except: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) self.currentExtent = self.plugin.canvas.extent() self.tableResult.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) try: self.editSearch.setText(self.plugin.lastSearch) except: pass try: if self.plugin.localiseOnStartup: self.doLocalize() except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass self.nominatim_networkAccessManager = QgsNetworkAccessManager.instance() def cellEntered(self, row, col): item = self.tableResult.item(row, 0) try: self.plugin.canvas.scene().removeItem(self.rubber) self.showItem(item) except: pass def onLayer(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doLayer(item) def onMask(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doMask(item) def populateRow(self, item, idx): id = item['place_id'] name = item['display_name'] try: className = QApplication.translate("nominatim", item['class'], None) except: className = "" try: typeName = QApplication.translate("nominatim", item['type'], None) except: typeName = "" try: wkt = item['geotext'] except: wkt = None try: osm_type = item['osm_type'] except: osm_type = None bbox = {} if osm_type == "node": lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT({} {})".format(lng, lat) ogrGeom = ogr.CreateGeometryFromWkt(wkt) else: try: bbox = item['boundingbox'] poFD = ogr.FeatureDefn("Rectangle") poFD.SetGeomType(ogr.wkbPolygon) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) if wkt is None: wkt = "POLYGON(({b[2]} {b[0]}, {b[2]} {b[1]}, {b[3]} {b[1]}, {b[3]} {b[0]}, {b[2]} {b[0]}))".format(b=bbox) ogrGeom = ogr.CreateGeometryFromWkt(wkt) except: lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT({} {})".format(lng, lat) ogrGeom = ogr.CreateGeometryFromWkt(wkt) ogrFeature.SetGeometry(ogrGeom) ogrFeature.SetFID(int(idx + 1)) ogrFeature.SetField(str('id'), str(id)) ogrFeature.SetField(str('name'), name) item = QTableWidgetItem(name) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) item.setData(Qt.UserRole, ogrFeature) self.tableResult.setItem(idx, 0, item) itemLibelle = QTableWidgetItem(className) itemLibelle.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 1, itemLibelle) itemType = QTableWidgetItem(typeName) itemType.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 2, itemType) def populateTable(self, r): idx = 0 self.tableResult.clearContents() self.tableResult.setRowCount(len(r)) for item in r: self.populateRow(item, idx) idx = idx + 1 def doLocalize(self): try: # center bbox = self.plugin.canvas.extent() sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) bbox = xform.transform(bbox) params = {"lon": str(bbox.center().x()), "lat": str(bbox.center().y()), "zoom": "10"} self.findNearbyJSON(params, self.plugin.gnUsername, self.plugin.gnOptions) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onReturnPressed(self): try: txt = self.editSearch.text().strip() self.plugin.lastSearch = self.editSearch.text() self.plugin.limitSearchToExtent = (self.cbExtent.isChecked()) options = self.plugin.gnOptions options2 = {} if self.plugin.limitSearchToExtent: sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) geom = xform.transform(self.plugin.canvas.extent()) vb = "{},{},{},{}".format(geom.xMinimum(), geom.yMaximum(), geom.xMaximum(), geom.yMinimum()) options2 = {'viewbox': vb} params = {'q': txt, 'addressdetails': '0'} self.searchJson(params, self.plugin.gnUsername, options, options2) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onChoose(self, row, col): item = self.tableResult.item(row, 0) self.go(item) def onApply(self): for item in self.tableResult.selectedItems(): self.go(item) break def transform(self, geom): sourceSRS = QgsCoordinateReferenceSystem(4326) mapCrs = self.plugin.canvas.mapSettings().destinationCrs() trsf = QgsCoordinateTransform(sourceSRS, mapCrs, QgsProject.instance()) try: geom.transform(trsf) except TypeError: QgsMessageLog.logMessage("Nominatim - transformation error. Check map projection.", "Extensions") def getBBox(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): mapextent = self.plugin.canvas.extent() ww = mapextent.width() / 100 mapcrs = self.plugin.canvas.mapSettings().destinationCrs() x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() ww = 50.0 if mapcrs.mapUnits() == QgsUnitTypes.DistanceFeet: ww = 150 if mapcrs.mapUnits() == QgsUnitTypes.DistanceDegrees: ww = 0.0005 bbox = QgsRectangle(x - 10 * ww, y - 10 * ww, x + 10 * ww, y + 10 * ww) return bbox else: bbox = geom.boundingBox() rubberRect = QgsRectangle(bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum()) return rubberRect def showItem(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PointGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(2) self.rubber.setToGeometry(geom, None) else: # dont show if it is larger than the canvas if self.plugin.canvas.extent().contains(geom.boundingBox()): pass else: geom = geom.intersection(QgsGeometry.fromRect(self.plugin.canvas.extent())) self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PolygonGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setWidth(4) self.rubber.setToGeometry(geom, None) def go(self, item, zoom=True): try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass if zoom: bbox = self.getBBox(item) self.plugin.canvas.setExtent(bbox) self.plugin.canvas.refresh() self.showItem(item) def doMask(self, item): mapcrs = self.plugin.canvas.mapSettings().destinationCrs() ogrFeature = item.data(Qt.UserRole) layerName = "OSM "+ogrFeature.GetFieldAsString('id') geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) if (geom.type() == QgsWkbTypes.PolygonGeometry): try: try: from mask import aeag_mask except: from mask_plugin import aeag_mask aeag_mask.do(mapcrs, {geom}, "Mask "+layerName) except: geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) toCrs = self.plugin.canvas.mapSettings().destinationCrs() larg = max(geom.boundingBox().width(), geom.boundingBox().height()) x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() rect = QgsRectangle(x-larg, y-larg, x+larg, y+larg) # geom.boundingBox() rect.scale(4) mask = QgsGeometry.fromRect(rect) mask = mask.difference(geom) maskLayer = QgsVectorLayer("MultiPolygon", "Mask "+layerName, "memory") maskLayer.setCrs(toCrs) QgsProject.instance().addMapLayer(maskLayer) pr = maskLayer.dataProvider() fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setGeometry(mask) fet.setFields(fields) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) pr.addAttributes(fields.toList()) maskLayer.startEditing() pr.addFeatures([fet]) maskLayer.commitChanges() maskLayer.updateExtents() # transparence, epaisseur renderer = maskLayer.renderer() s = renderer.symbol() s.setOpacity(0.90) s.setColor(QColor(255, 255, 255)) if isinstance(s, QgsLineSymbol): s.setWidth(0) layerTree = QgsProject.instance().layerTreeRoot().findLayer(maskLayer) if layerTree: self.plugin.iface.layerTreeView().layerTreeModel()\ .refreshLayerLegend(layerTree) # Refresh legend self.go(item) def doLayer(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) self.transform(geom) fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setFields(fields) fet.setGeometry(geom) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) vl = None if not self.plugin.singleLayer: if geom.type() == QgsWkbTypes.PolygonGeometry: layerName = "OSMPlaceSearch Polygon" layerId = self.MultiPolygonLayerId if geom.type() == QgsWkbTypes.LineGeometry: layerName = "OSMPlaceSearch Line" layerId = self.LineLayerId if geom.type() == QgsWkbTypes.PointGeometry: layerName = "OSMPlaceSearch Point" layerId = self.PointLayerId vl = QgsProject.instance().mapLayer(layerId) if vl is not None: pr = vl.dataProvider() else: if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") self.MultiPolygonLayerId = vl.id() if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") self.LineLayerId = vl.id() if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") self.PointLayerId = vl.id() if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) QgsProject.instance().addMapLayer(vl) else: layerName = "OSM "+ogrFeature.GetFieldAsString('id') # creer une nouvelle couche si n'existe pas encore if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) vl.setCrs(self.plugin.canvas.mapSettings().destinationCrs()) QgsProject.instance().addMapLayer(vl) if vl is not None: vl.setProviderEncoding('UTF-8') vl.startEditing() pr.addFeatures([fet]) vl.commitChanges() # mise a jour etendue de la couche vl.updateExtents() layerTree = QgsProject.instance().layerTreeRoot().findLayer(vl) if layerTree: self.plugin.iface.layerTreeView()\ .layerTreeModel().refreshLayerLegend(layerTree) # Refresh legend self.go(item, False)
class InterpolateTool(QgsMapToolAdvancedDigitizing): """ Map tool class to interpolate an elevation in the middle of a segment """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/interpolate_icon.png' self.text = QCoreApplication.translate( "VDLTools", "Interpolate the elevation of a vertex and a point in the middle of a line" ) self.__layer = None self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__lastFeatureId = None self.__layerList = None self.__lastLayer = None self.__confDlg = None self.__mapPoint = None self.__rubber = None self.__selectedFeature = None self.__findVertex = False def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapToolAdvancedDigitizing.activate(self) self.__updateList() self.__rubber = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setWidth(2) self.__rubber.setIconSize(20) self.canvas().layersChanged.connect(self.__updateList) self.canvas().scaleChanged.connect(self.__updateList) self.setMode(self.CaptureLine) def deactivate(self): """ When the action is deselected """ self.__done() self.__cancel() self.__rubber = None Signal.safelyDisconnect(self.canvas().layersChanged, self.__updateList) Signal.safelyDisconnect(self.canvas().scaleChanged, self.__updateList) QgsMapToolAdvancedDigitizing.deactivate(self) def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def __done(self): """ When the edition is finished """ self.__isEditing = False self.__confDlg = None self.__mapPoint = None def __cancel(self): """ To cancel used variables """ self.__findVertex = False if self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastLayer = None if self.__rubber is not None: self.__rubber.reset() self.__lastFeatureId = None self.__selectedFeature = None def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type( ) == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() self.action().setEnabled(False) self.__removeLayer() def __updateList(self): """ To update the line layers list that we can use for interpolation """ self.__layerList = [] for layer in self.canvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType() \ and layer.geometryType() == QGis.Line: self.__layerList.append( QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.All, 10, QgsTolerance.Pixels)) def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__done() self.__cancel() def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and self.__layerList is not None: f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), self.__layerList) if f_l is not None and self.__lastFeatureId != f_l[0].id(): f = f_l[0] self.__lastFeatureId = f.id() if self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastLayer = f_l[1] self.__lastLayer.setSelectedFeatures([f.id()]) if f_l is None and self.__lastLayer is not None: self.__lastLayer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: self.__rubber.reset() snap_layers = Finder.getLayersSettings(self.canvas(), [QGis.Line, QGis.Polygon], QgsPointLocator.All) match = Finder.snap(map_point, self.canvas(), snap_layers) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): self.__rubber.setIcon(4) self.__rubber.setToGeometry( QgsGeometry().fromPoint(point), None) else: intersection = Finder.snapCurvedIntersections( point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: self.__rubber.setIcon(1) self.__rubber.setToGeometry( QgsGeometry().fromPoint(intersection), None) if match.hasEdge(): intersection = Finder.snapCurvedIntersections( point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: self.__rubber.setIcon(1) self.__rubber.setToGeometry( QgsGeometry().fromPoint(intersection), None) elif self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): self.__rubber.setIcon(3) self.__rubber.setToGeometry( QgsGeometry().fromPoint(point), None) def cadCanvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if self.__lastLayer is not None and not self.__findVertex: found_features = self.__lastLayer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] self.__iface.messageBar().pushMessage( QCoreApplication.translate( "VDLTools", "Select the position for interpolation (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) self.setMode(self.CaptureNone) self.__findVertex = True elif self.__findVertex: self.__rubber.reset() snap_layers = Finder.getLayersSettings(self.canvas(), [QGis.Line, QGis.Polygon], QgsPointLocator.All) match = Finder.snap(event.mapPoint(), self.canvas(), snap_layers) if match.hasVertex() or match.hasEdge(): point = match.point() ok = False noVertex = False if match.hasVertex(): if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): ok = True noVertex = True else: intersection = Finder.snapCurvedIntersections( point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: point = intersection ok = True if match.hasEdge(): intersection = Finder.snapCurvedIntersections( point, self.canvas(), self, self.__selectedFeature.id()) if intersection is not None: point = intersection ok = True elif self.__selectedFeature.id() == match.featureId() \ and match.layer().id() == self.__lastLayer.id(): ok = True if ok: self.__isEditing = True self.__findVertex = False self.__mapPoint = point if noVertex: self.__ok(False, True) else: self.__confDlg = InterpolateConfirmDialog() if self.__lastLayer.isEditable(): self.__confDlg.setMainLabel( QCoreApplication.translate( "VDLTools", "What do you want to do ?")) self.__confDlg.setAllLabel( QCoreApplication.translate( "VDLTools", "Create point and new vertex")) self.__confDlg.setVtLabel( QCoreApplication.translate( "VDLTools", "Create only the vertex")) self.__confDlg.rejected.connect(self.__done) self.__confDlg.okButton().clicked.connect( self.__onConfirmOk) self.__confDlg.cancelButton().clicked.connect( self.__onConfirmCancel) self.__confDlg.show() else: self.__done() self.__cancel() def __onConfirmCancel(self): """ When the Cancel button in Interpolate Confirm Dialog is pushed """ self.__confDlg.reject() def __onConfirmOk(self): """ When the Ok button in Interpolate Confirm Dialog is pushed """ checkedId = self.__confDlg.getCheckedId() self.__confDlg.accept() withVertex = True withPoint = True if checkedId == 1: withVertex = False else: if not self.__lastLayer.isEditable(): self.__lastLayer.startEditing() if checkedId == 2: withPoint = False self.__ok(withVertex, withPoint) def __ok(self, withVertex, withPoint): """ To realize the interpolation :param withVertex: if we want a new interpolated vertex :param withPoint: if we want a new interpolated point """ line_v2, curved = GeometryV2.asLineV2( self.__selectedFeature.geometry(), self.__iface) vertex_v2 = QgsPointV2() vertex_id = QgsVertexId() line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2, vertex_id, 0) x0 = line_v2.xAt(vertex_id.vertex - 1) y0 = line_v2.yAt(vertex_id.vertex - 1) d0 = Finder.sqrDistForCoords(x0, vertex_v2.x(), y0, vertex_v2.y()) x1 = line_v2.xAt(vertex_id.vertex) y1 = line_v2.yAt(vertex_id.vertex) d1 = Finder.sqrDistForCoords(x1, vertex_v2.x(), y1, vertex_v2.y()) z0 = line_v2.zAt(vertex_id.vertex - 1) z1 = line_v2.zAt(vertex_id.vertex) vertex_v2.addZValue(old_div((d0 * z1 + d1 * z0), (d0 + d1))) if withPoint: pt_feat = QgsFeature(self.__layer.pendingFields()) pt_feat.setGeometry(QgsGeometry(vertex_v2)) for i in range(len(self.__layer.pendingFields())): # default = self.__layer.defaultValue(i, pt_feat) # if default is not None: # print(pt_feat.fields().at(i).name(), pt_feat.fields().at(i).defaultValueExpression(), default) # print(self.__layer.defaultValueExpression(i), self.__layer.expressionField(i)) e = QgsExpression(self.__layer.defaultValueExpression(i)) default = e.evaluate(pt_feat) pt_feat.setAttribute(i, default) if self.__layer.editFormConfig().suppress( ) == QgsEditFormConfig.SuppressOn: self.__layer.addFeature(pt_feat) else: self.__iface.openFeatureForm(self.__layer, pt_feat) if withVertex: line_v2.insertVertex(vertex_id, vertex_v2) self.__lastLayer.changeGeometry(self.__selectedFeature.id(), QgsGeometry(line_v2)) found_features = self.__lastLayer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) else: self.__selectedFeature = found_features[0] else: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "No more feature selected"), level=QgsMessageBar.INFO) self.__iface.mapCanvas().refresh() self.__done() self.__findVertex = True
class GeomapfishLocatorFilter(QgsLocatorFilter): USER_AGENT = b'Mozilla/5.0 QGIS GeoMapFish Locator Filter' changed = pyqtSignal() def __init__(self, service: Service, iface: QgisInterface = None): super().__init__() self.service = service.clone() self.rubberband = None self.iface = None self.map_canvas = None self.current_timer = None self.settings = Settings() self.crs = QgsCoordinateReferenceSystem(self.service.crs) # only get map_canvas on main thread, not when cloning if iface is not None: self.iface = iface self.map_canvas = iface.mapCanvas() self.rubberband = QgsRubberBand(self.map_canvas) self.reset_rubberband() def name(self) -> str: return slugify(self.displayName()) def clone(self): return GeomapfishLocatorFilter(self.service) def displayName(self) -> str: return self.service.name def prefix(self) -> str: return 'gmf' def hasConfigWidget(self) -> bool: return True def openConfigWidget(self, parent=None): cfg = FilterConfigurationDialog(self.service, parent) if cfg.exec_(): self.service = cfg.service.clone() self.crs = QgsCoordinateReferenceSystem(self.service.crs) self.changed.emit() def reset_rubberband(self): # this should happen on main thread only! self.rubberband.setColor(self.settings.value('point_color')) self.rubberband.setIcon(self.rubberband.ICON_CIRCLE) self.rubberband.setIconSize(self.settings.value('point_size')) self.rubberband.setWidth(self.settings.value('line_width')) self.rubberband.setBrushStyle(Qt.NoBrush) @staticmethod def url_with_param(url, params) -> str: url = QUrl(url) q = QUrlQuery(url) for key, value in params.items(): q.addQueryItem(key, value) url.setQuery(q) return url def emit_bad_configuration(self, err=None): result = QgsLocatorResult() result.filter = self result.displayString = self.tr('Locator filter is not configured.') result.description = err if err else self.tr( 'Double-click to configure it.') result.userData = FilterNotConfigured result.icon = QgsApplication.getThemeIcon('mIconWarning.svg') self.resultFetched.emit(result) return @pyqtSlot() def clear_results(self): if self.rubberband: self.rubberband.reset(QgsWkbTypes.PointGeometry) if self.current_timer is not None: self.current_timer.timeout.disconnect(self.clear_results) self.current_timer.stop() self.current_timer.deleteLater() self.current_timer = None def fetchResults(self, search, context, feedback): self.dbg_info("start GMF locator search...") url = self.service.url if not url: self.emit_bad_configuration() return if len(search) < 2: return params = { 'query': search, 'limit': str(self.service.total_limit), 'partitionlimit': str(self.service.category_limit) } url = self.url_with_param(url, params) self.dbg_info(url.url()) _request = QNetworkRequest(url) _request.setRawHeader(b'User-Agent', self.USER_AGENT) request = QgsBlockingNetworkRequest() if self.service.authid: request.setAuthCfg(self.service.authid) response = request.get(_request, False, feedback) if response == QgsBlockingNetworkRequest.NoError: self.handle_response(request.reply().content()) else: error_msg = request.reply().errorString() self.emit_bad_configuration(error_msg) self.info(error_msg, Qgis.Critical) self.finished.emit() def handle_response(self, content: QByteArray): try: data = json.loads(str(content.data(), encoding='utf-8')) # self.dbg_info(data) features = data['features'] for f in features: json_geom = json.dumps(f['geometry']) ogr_geom = ogr.CreateGeometryFromJson(json_geom) wkt = ogr_geom.ExportToWkt() geometry = QgsGeometry.fromWkt(wkt) self.dbg_info('---------') self.dbg_info( QgsWkbTypes.geometryDisplayString(geometry.type())) self.dbg_info(f.keys()) self.dbg_info('{} {}'.format(f['properties']['layer_name'], f['properties']['label'])) self.dbg_info(f['bbox']) self.dbg_info(f['geometry']) if geometry is None: continue result = QgsLocatorResult() result.filter = self result.displayString = f['properties']['label'] result.group = self.beautify_group( f['properties']['layer_name']) result.userData = geometry self.resultFetched.emit(result) except Exception as e: self.info(str(e), Qgis.Critical) # exc_type, exc_obj, exc_traceback = sys.exc_info() # #filename = os.path.split(exc_traceback.tb_frame.f_code.co_filename)[1] # #self.info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) # self.info(traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def triggerResult(self, result): self.clear_results() if result.userData == FilterNotConfigured: self.openConfigWidget() self.iface.invalidateLocatorResults() return # this should be run in the main thread, i.e. mapCanvas should not be None geometry = result.userData # geometry.transform(self.transform) dbg_info(str(geometry.asWkt())) dbg_info(geometry.type()) try: rect = QgsReferencedRectangle(geometry.boundingBox(), self.crs) rect.scale(4) self.map_canvas.setReferencedExtent(rect) except AttributeError: # QGIS < 3.10 handling from qgis.core import QgsCoordinateTransform, QgsProject transform = QgsCoordinateTransform( self.crs, self.map_canvas.mapSettings().destinationCrs(), QgsProject.instance()) geometry.transform(transform) rect = geometry.boundingBox() rect.scale(4) self.map_canvas.setExtent(rect) self.map_canvas.refresh() if geometry.type() == QgsWkbTypes.PolygonGeometry: nflash = 16 color1: QColor = self.settings.value('polygon_color') color2 = color1 color1.setAlpha(200) color2.setAlpha(100) self.map_canvas.flashGeometries( [geometry], self.crs, color1, color2, nflash, self.settings.value('highlight_duration') / nflash * 1000) else: self.rubberband.reset(geometry.type()) self.rubberband.addGeometry(geometry, self.crs) self.current_timer = QTimer() self.current_timer.timeout.connect(self.clear_results) self.current_timer.setSingleShot(True) self.current_timer.start( self.settings.value('highlight_duration') * 1000) def beautify_group(self, group) -> str: if self.service.remove_leading_digits: group = re.sub('^[0-9]+', '', group) if self.service.replace_underscore: group = group.replace("_", " ") if self.service.break_camelcase: group = self.break_camelcase(group) return group def info(self, msg="", level=Qgis.Info): QgsMessageLog.logMessage('{} {}'.format(self.__class__.__name__, msg), 'QgsLocatorFilter', level) def dbg_info(self, msg=""): if DEBUG: self.info(msg) @staticmethod def break_camelcase(identifier) -> str: matches = re.finditer( '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', identifier) return ' '.join([m.group(0) for m in matches])
class FinderBox(QComboBox): running = False to_finish = 0 search_started = pyqtSignal() search_finished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.marker = None self.rubber = QgsRubberBand(self.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) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.result_view = QTreeView() self.result_view.setHeaderHidden(True) self.result_view.setMinimumHeight(300) self.result_view.activated.connect(self.itemActivated) self.result_view.pressed.connect(self.itemPressed) self.setView(self.result_view) self.result_model = ResultModel(self) self.setModel(self.result_model) self.finders = finders for finder in list(self.finders.values()): finder.result_found.connect(self.result_found) finder.limit_reached.connect(self.limit_reached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon( QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) button_size = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = button_size.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber #clear marker that the lonlat seted def clearMarker(self): self.mapCanvas.scene().removeItem(self.marker) self.marker = None def clearSelection(self): self.result_model.setSelected(None, self.result_view.palette()) self.rubber.reset() #self.clearMarker() def clear(self): self.clearSelection() self.result_model.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() self.clearMarker() QComboBox.keyPressEvent(self, event) def lnglatFinder(self, to_find): import re m = re.match(r'(?P<lon>-?\d*(.\d+))\s+(?P<lat>-?\d*(.\d+))', to_find) if not m: return False x = float(m.group('lon')) y = float(m.group('lat')) return self.zoomLnglat(x, y) def zoomLnglat(self, lng, lat): x, y = lng, lat canvas = self.mapCanvas currExt = canvas.extent() canvasCenter = currExt.center() dx = float(x) - canvasCenter.x() dy = float(y) - canvasCenter.y() xMin = currExt.xMinimum() + dx xMax = currExt.xMaximum() + dx yMin = currExt.yMinimum() + dy yMax = currExt.yMaximum() + dy rect = QgsRectangle(xMin, yMin, xMax, yMax) canvas.setExtent(rect) pt = QgsPointXY(float(x), float(y)) self.marker = QgsVertexMarker(canvas) self.marker.setCenter(pt) self.marker.setIconSize(18) self.marker.setPenWidth(2) self.marker.setIconType(QgsVertexMarker.ICON_CROSS) canvas.refresh() return True # def geocodeFinder(self, to_finder): # print(to_finder[:2]) # if not to_finder[:2] == 'b:': # return False # # address = to_finder[2:] # url = MySettings().value("baiduUrl") # url = url + parse.quote(address) # # response = request.urlopen(url) # content = response.read() # data = json.loads(content) # print(data) # lng, lat = (data['result']['location']['lng'], data['result']['location']['lat']) # from .cood_trans import bd09_to_wgs84 # lng, lat = bd09_to_wgs84(lng, lat) # print(f'{lng}-{lat}') # return self.zoomLnglat(lng, lat) def search(self): # self.geocode() if self.running: return to_find = self.lineEdit().text() if not to_find or to_find == '': return # if not (self.lnglatFinder(to_find) or self.geocodeFinder(to_find)): if not self.lnglatFinder(to_find): self.showPopup() self.running = True self.search_started.emit() self.clearSelection() self.result_model.clearResults() self.result_model.truncateHistory(MySettings().value("historyLength")) self.result_model.setLoading(True) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.finders_to_start = [] for finder in list(self.finders.values()): if finder.activated(): self.finders_to_start.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.finders_to_start) > 0: finder = self.finders_to_start[0] self.finders_to_start.remove(finder) self.result_model.addResult(finder.name) finder.start(to_find, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.finders_to_start = [] for finder in list(self.finders.values()): if finder.is_running(): finder.stop() self.finished(None) def result_found(self, finder, layername, value, geometry, srid): self.result_model.addResult(finder.name, layername, value, geometry, srid) self.result_view.expandAll() def limit_reached(self, finder, layername): self.result_model.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.finders_to_start) > 0: return for finder in list(self.finders.values()): if finder.is_running(): return self.running = False self.search_finished.emit() self.result_model.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.result_model.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.result_model.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.result_model.setSelected(item, self.result_view.palette()) geometry = self.transform_geom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoom_to_rubberband() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.result_model.setSelected(item, self.result_view.palette()) self.rubber.reset(child.geometry.type()) for i in range(0, item.rowCount()): geometry = self.transform_geom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoom_to_rubberband() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transform_geom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapSettings().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform( QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance())) return geom def zoom_to_rubberband(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class SelectFeaturesTool(QgsMapTool): selection_clicked = pyqtSignal(list) def __init__(self, mission_track, canvas): QgsMapTool.__init__(self, canvas) self.setCursor(Qt.ArrowCursor) self.mission_track = mission_track self.layer = self.mission_track.get_mission_layer() self.rubber_band = None self.rubber_band_points = None self.selection_polygon = [] self.indexes_within_list = [] self.band_finished = True self.mCtrl = False self.p0, self.p1, self.p2, self.p3 = None, None, None, None self.mission_track.mission_changed.connect(self.update_rubber_band) self.mission_track.step_removed.connect(self.remove_rubber_band) self.wp = self.mission_track.find_waypoints_in_mission() self.layer.startEditing() self.rubber_band_vs_track_indexes = {} self.rubber_band_points = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubber_band_points.setIconSize(10) self.rubber_band_points.setColor(QColor("green")) self.rubber_band_vertex_counter = 0 def keyPressEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = True def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False if event.key() == Qt.Key_Escape: self.p0, self.p1, self.p2, self.p3 = None, None, None, None if self.rubber_band: self.rubber_band.reset(True) self.close_polygon_band() self.band_finished = True self.canvas().refresh() return def canvasPressEvent(self, event): if event.button() == Qt.LeftButton: point = self.toMapCoordinates(event.pos()) # check if we have clicked on a vertex tolerance = self.calc_tolerance() vertex = self.find_vertex_at(event.pos(), tolerance) if self.mCtrl and vertex is not None: # if we have clicked on a vertex, identify which one # check if was already in the selection list if vertex not in self.indexes_within_list: # add it self.indexes_within_list.append(vertex) self.update_rubber_band() else: # remove it self.indexes_within_list.remove(vertex) self.update_rubber_band() self.band_finished = True elif vertex is None: # if we have not clicked on a vertex and there's no polygon band, start it if not len(self.selection_polygon ) and self.band_finished and not self.mCtrl: self.selection_clicked.emit(list()) self.band_finished = False self.rubber_band = QgsRubberBand( self.canvas(), QgsWkbTypes.PolygonGeometry) self.rubber_band.setWidth(2) select_green = QColor("green") select_green.setAlpha(128) self.rubber_band.setColor(select_green) if event.button() == Qt.LeftButton: # Left click -> add vertex self.p0 = QgsPointXY(point.x(), point.y()) self.selection_polygon.append(self.p0) elif len(self.selection_polygon) == 1 and not self.mCtrl: if event.button() == Qt.LeftButton: # Left click -> add vertex self.p2 = QgsPointXY(point.x(), point.y()) self.p1 = QgsPointXY(self.p2.x(), self.p0.y()) self.p3 = QgsPointXY(self.p0.x(), self.p2.y()) self.selection_polygon.append(self.p1) self.selection_polygon.append(self.p2) self.selection_polygon.append(self.p3) self.band_finished = True self.set_selection() self.close_polygon_band() self.selection_clicked.emit(self.indexes_within_list) 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 = [] 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)) vertex = dist_to_vertex.index(min(dist_to_vertex)) if min(dist_to_vertex) > tolerance: return None else: return vertex else: return 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 canvasMoveEvent(self, event): if not self.band_finished and not self.mCtrl: self.p2 = self.toMapCoordinates(event.pos()) self.p1 = QgsPointXY(self.p2.x(), self.p0.y()) self.p3 = QgsPointXY(self.p0.x(), self.p2.y()) self.selection_polygon.append(self.p1) self.selection_polygon.append(self.p2) self.selection_polygon.append(self.p3) self.rubber_band.setToGeometry( QgsGeometry.fromPolygonXY([self.selection_polygon]), None) self.selection_polygon.pop() self.selection_polygon.pop() self.selection_polygon.pop() def set_selection(self): """ Set vertices highlight according to polygon """ # Check which features are within the polygon mission_track = self.layer.getFeatures() # get mission track feature for f in mission_track: # loop although mission layer only has one feature vertices_it = f.geometry().vertices() polygon_geom = QgsGeometry.fromPolygonXY([self.selection_polygon]) vertices_within_list = [] # self.indexes_within_list = [] vertex_index = 0 # Highlight them using a point rubber band self.rubber_band_vertex_counter = 0 for v in vertices_it: point_geom = QgsGeometry.fromPointXY(QgsPointXY(v.x(), v.y())) if point_geom.within(polygon_geom): vertices_within_list.append(v) if not (vertex_index in self.indexes_within_list ): # only add if not already present self.indexes_within_list.append(vertex_index) self.rubber_band_points.addPoint(QgsPointXY(v.x(), v.y())) self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1 self.rubber_band_vs_track_indexes[ vertex_index] = self.rubber_band_vertex_counter - 1 vertex_index = vertex_index + 1 def update_rubber_band(self): if self.rubber_band_points: self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.rubber_band_vs_track_indexes = {} self.rubber_band_vertex_counter = 0 self.wp = self.mission_track.find_waypoints_in_mission() if len(self.indexes_within_list) > 0: selected_vertices = self.mission_track.find_waypoints_in_mission( self.indexes_within_list) for v in selected_vertices: vertex_index = 0 for point in self.wp: if v == point: pc = self.toLayerCoordinates(self.layer, QgsPointXY(v)) self.rubber_band_points.addPoint(pc) self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1 self.rubber_band_vs_track_indexes[ vertex_index] = self.rubber_band_vertex_counter - 1 vertex_index = vertex_index + 1 self.set_geometry() def remove_rubber_band(self, wp): # if self.rubber_band_points: # self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.indexes_within_list.remove(wp) self.update_rubber_band() 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_polygon_band(self): self.selection_polygon = [] if self.rubber_band is not None: self.rubber_band.reset() self.canvas().scene().removeItem(self.rubber_band) self.rubber_band = None def close_highlight_band(self): self.rubber_band_points.reset() self.canvas().scene().removeItem(self.rubber_band_points) self.rubber_band_points = None def deactivate(self): if self.rubber_band: self.close_polygon_band() if self.rubber_band_points: self.close_highlight_band() try: self.mission_track.mission_changed.disconnect( self.update_rubber_band) self.mission_track.step_removed.disconnect(self.remove_rubber_band) except: logger.info("no connected to signal") self.layer.commitChanges()
class GeorefRasterBy2PointsMapTool(QgsMapToolEmitPoint): 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 setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = self.firstPoint = None self.isEmittingPoint = False self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def deactivate(self): QgsMapToolEmitPoint.deactivate(self) self.reset() def canvasPressEvent(self, e): if self.firstPoint is None: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.originalCenter = self.layer.center # this tool do the displacement itself TODO update so it is done by # transformed coordinates + new center) self.originalCornerPoints = \ self.layer.transformedCornerCoordinates( *self.layer.transformParameters()) self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) self.showDisplacement(self.startPoint, self.endPoint) self.layer.history.append({ "action": "2pointsA", "center": self.layer.center }) else: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.startY = e.pos().y() self.endY = self.startY self.isEmittingPoint = True self.height = self.canvas.height() self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) self.layer.history.append({ "action": "2pointsB", "center": self.layer.center, "xScale": self.layer.xScale, "yScale": self.layer.yScale, "rotation": None }) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() if self.firstPoint is None: x = (self.originalCenter.x() + self.endPoint.x() - self.startPoint.x()) y = (self.originalCenter.y() + self.endPoint.y() - self.startPoint.y()) self.layer.setCenter(QgsPointXY(x, y)) self.firstPoint = self.endPoint setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() else: rotation = self.computeRotation() xScale = yScale = self.computeScale() self.layer.moveCenterFromPointRotate(self.firstPoint, rotation, xScale, yScale) self.layer.setScale(self.layer.xScale * xScale, self.layer.yScale * yScale) val = self.layer.rotation + rotation if val > 180: val = val - 360 self.iface.mainWindow().findChild( QDoubleSpinBox, 'FreehandRasterGeoreferencer_spinbox').setValue(val) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rasterShadow.reset() self.firstPoint = None self.startPoint = self.endPoint = None def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) if self.firstPoint is None: self.showDisplacement(self.startPoint, self.endPoint) else: self.endY = e.pos().y() rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) def computeRotation(self): # The angle is the difference between angle # horizontal/endPoint-firstPoint and horizontal/startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.degrees(math.atan2(-dY, dX) - math.atan2(-dY0, dX0)) def computeScale(self): # The scale is the ratio between endPoint-firstPoint and # startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.sqrt((dX * dX + dY * dY) / (dX0 * dX0 + dY0 * dY0)) def showRotationScale(self, rotation, xScale, yScale): center, _, _, _ = self.layer.transformParameters() # newRotation = rotation + originalRotation cornerPoints = self.layer.transformedCornerCoordinatesFromPoint( self.firstPoint, rotation, xScale, yScale) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show() # Calculate the displacement of the center due to the rotation from # another point. newCenterDX = (cornerPoints[0].x() + cornerPoints[2].x()) / 2 - center.x() newCenterDY = (cornerPoints[0].y() + cornerPoints[2].y()) / 2 - center.y() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement(newCenterDX, newCenterDY, False) self.rasterShadow.setDeltaScale(xScale, yScale, False) self.rasterShadow.setDeltaRotation(rotation, True) self.rasterShadow.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point0 = QgsPointXY(self.startPoint.x(), self.startPoint.y()) point1 = QgsPointXY(self.firstPoint.x(), self.firstPoint.y()) point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y()) self.rubberBandDisplacement.addPoint(point0, False) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() def showDisplacement(self, startPoint, endPoint): self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandOrigin.addPoint(endPoint, True) self.rubberBandOrigin.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(endPoint.x(), endPoint.y()) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in self.originalCornerPoints: self._addDisplacementToPoint(self.rubberBandExtent, point, False) # for closing self._addDisplacementToPoint(self.rubberBandExtent, self.originalCornerPoints[0], True) self.rubberBandExtent.show() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement( self.endPoint.x() - self.startPoint.x(), self.endPoint.y() - self.startPoint.y(), True) self.rasterShadow.show() def _addDisplacementToPoint(self, rubberBand, point, doUpdate): x = point.x() + self.endPoint.x() - self.startPoint.x() y = point.y() + self.endPoint.y() - self.startPoint.y() self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
class ExtrapolateTool(QgsMapTool): def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.__canvas = iface.mapCanvas() self.__icon_path = ':/plugins/VDLTools/icons/extrapolate_icon.png' self.__text = QCoreApplication.translate( "VDLTools", "Extrapolate the elevation of a vertex and a " "point at the extremity of a line") # self.__oldTool = None self.__layer = None self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__lastFeatureId = None self.__rubber = None self.__counter = 0 self.__confDlg = None self.__selectedVertex = None self.__elevation = None self.__selectedFeature = None self.__layerConfig = None def icon_path(self): """ To get the icon path :return: icon path """ return self.__icon_path def text(self): """ To get the menu text :return: menu text """ return self.__text def setTool(self): """ To set the current tool as this one """ # self.__oldTool = self.__canvas.mapTool() self.__canvas.setMapTool(self) def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__rubber = QgsRubberBand(self.__canvas, QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setIconSize(20) self.__updateList() self.__canvas.layersChanged.connect(self.__updateList) QgsProject.instance().snapSettingsChanged.connect(self.__updateList) def deactivate(self): """ When the action is deselected """ self.__rubber.reset() self.__canvas.layersChanged.disconnect(self.__updateList) QgsProject.instance().snapSettingsChanged.disconnect(self.__updateList) QgsMapTool.deactivate(self) def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) self.__layer.editingStarted.disconnect(self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) self.__layer.editingStopped.disconnect(self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.__canvas.mapTool == self: self.__iface.actionPan().trigger() # self.__canvas.setMapTool(self.__oldTool) def removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): self.__layer.editingStopped.disconnect(self.stopEditing) else: self.__layer.editingStarted.disconnect(self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None\ and isinstance(layer, QgsVectorLayer)\ and QGis.fromOldWkbType(layer.wkbType()) == QgsWKBTypes.LineStringZ: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): self.__layer.editingStopped.disconnect(self.stopEditing) else: self.__layer.editingStarted.disconnect(self.startEditing) self.__layer = layer if self.__layer.isEditable(): self.action().setEnabled(True) self.__updateList() self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.__canvas.mapTool == self: self.__iface.actionPan().trigger() # self.__canvas.setMapTool(self.__oldTool) return self.action().setEnabled(False) self.removeLayer() def __updateList(self): """ To update the snapping options of the layer """ noUse, enabled, snappingType, unitType, tolerance, avoidIntersection = \ QgsProject.instance().snapSettingsForLayer(self.__layer.id()) self.__layerConfig = QgsSnappingUtils.LayerConfig( self.__layer, QgsPointLocator.Vertex, tolerance, unitType) if not enabled or tolerance == 0: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "Error"), QCoreApplication.translate( "VDLTools", "This layer has no snapping options"), level=QgsMessageBar.CRITICAL) def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isEditing: f = Finder.findClosestFeatureAt(event.mapPoint(), self.__layerConfig, self) if f is not None and self.__lastFeatureId != f.id(): self.__lastFeatureId = f.id() self.__layer.setSelectedFeatures([f.id()]) if self.__counter > 2: self.__rubber.reset() geom = f.geometry() index = geom.closestVertex(event.mapPoint())[1] line_v2, curved = GeometryV2.asLineV2(geom) num_p = line_v2.numPoints() if num_p > 2 and (index == 0 or index == (num_p - 1)): self.__rubber.setIcon(4) self.__rubber.setToGeometry( QgsGeometry(line_v2.pointN(index)), None) self.__counter = 0 else: self.__counter += 1 if f is None: self.__layer.removeSelection() self.__rubber.reset() self.__lastFeatureId = None def canvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) < 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return geom = found_features[0].geometry() self.__selectedVertex = geom.closestVertex(event.mapPoint())[1] line_v2, curved = GeometryV2.asLineV2(geom) num_p = line_v2.numPoints() if num_p > 2 and (self.__selectedVertex == 0 or self.__selectedVertex == (num_p - 1)): pt = line_v2.pointN(self.__selectedVertex) if self.__selectedVertex == 0: pt0 = line_v2.pointN(2) pt1 = line_v2.pointN(1) else: pt0 = line_v2.pointN(num_p - 3) pt1 = line_v2.pointN(num_p - 2) big_d = Finder.sqrDistForPoints(pt0, pt1) small_d = Finder.sqrDistForPoints(pt1, pt) if small_d < (big_d / 4): self.__isEditing = True self.__selectedFeature = found_features[0] self.__elevation = pt0.z() + (1 + small_d / big_d) * ( pt1.z() - pt0.z()) if pt.z() is not None and pt.z() != 0: self.__confDlg = ExtrapolateConfirmDialog( pt.z(), self.__elevation) self.__confDlg.okButton().clicked.connect( self.__onEditOk) self.__confDlg.cancelButton().clicked.connect( self.__onEditCancel) self.__confDlg.show() else: self.__edit() else: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "The segment is too big"), level=QgsMessageBar.INFO) def __onEditOk(self): """ When the Ok button in Extrapolate Confirm Dialog is pushed """ self.__confDlg.close() self.__edit() def __onEditCancel(self): """ When the Cancel button in Extrapolate Confirm Dialog is pushed """ self.__confDlg.close() self.__rubber.reset() self.__lastFeatureId = None self.__selectedFeature = None self.__selectedVertex = None self.__isEditing = False def __edit(self): """ To add the new extrapolate elevation """ line_v2, curved = GeometryV2.asLineV2( self.__selectedFeature.geometry()) line_v2.setZAt(self.__selectedVertex, self.__elevation) self.__layer.changeGeometry(self.__selectedFeature.id(), QgsGeometry(line_v2)) self.__layer.removeSelection() self.__rubber.reset() self.__lastFeatureId = None self.__selectedFeature = None self.__selectedVertex = None self.__isEditing = False
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) # Cursor Canvas Rubberband self.Cursor_Canvas_RubberBand = QgsRubberBand( iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.Cursor_Canvas_RubberBand.setWidth(4) self.Cursor_Canvas_RubberBand.setColor(QColor(255, 100, 100, 250)) self.Cursor_Canvas_RubberBand.setIcon(QgsRubberBand.ICON_FULL_DIAMOND) self.parent = parent.parent() palette = self.palette() palette.setColor(QPalette.Background, Qt.transparent) self.setPalette(palette) self.origin, self.dragPos = QPoint(), QPoint() self.tapTimer = QBasicTimer() self.brush = QBrush(color_black) self.blue_Pen = QPen(color_blue, 3) 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 :type event: QKeyEvent :param event: :return: ''' 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): """ Mouse double click 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 @type value: bool @param value: @return: ''' self._filterSatate.invertColorFilter = value def SetObjectTracking(self, value): '''Set Object Tracking @type value: bool @param value: @return: ''' self._interaction.objectTracking = value def SetMeasureDistance(self, value): '''Set measure Distance @type value: bool @param value: @return: ''' self._interaction.measureDistance = value def SetMeasureArea(self, value): '''Set measure Area @type value: bool @param value: @return: ''' self._interaction.measureArea = value def SetHandDraw(self, value): '''Set Hand Draw @type value: bool @param value: @return: ''' self._interaction.HandDraw = value def SetCensure(self, value): '''Set Censure Video Parts @type value: bool @param value: @return: ''' self._interaction.censure = value def SetMGRS(self, value): '''Set MGRS Cursor Coordinates @type value: bool @param value: @return: ''' self._MGRS = value def SetGray(self, value): '''Set gray scale @type value: bool @param value: @return: ''' self._filterSatate.grayColorFilter = value def SetMirrorH(self, value): '''Set Horizontal Mirror @type value: bool @param value: @return: ''' self._filterSatate.MirroredHFilter = value def SetNDVI(self, value): '''Set NDVI @type value: bool @param value: @return: ''' self._filterSatate.NDVI = value def SetEdgeDetection(self, value): '''Set Canny Edge filter @type value: bool @param value: @return: ''' self._filterSatate.edgeDetectionFilter = value def SetAutoContrastFilter(self, value): '''Set Automatic Contrast filter @type value: bool @param value: @return: ''' self._filterSatate.contrastFilter = value def SetMonoFilter(self, value): '''Set mono filter @type value: bool @param value: @return: ''' 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(QgsWkbTypes.LineGeometry) self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry) def paintEvent(self, event): """ @type event: QPaintEvent @param event: @return: """ if not self.surface.isActive(): return self.painter = QPainter(self) self.painter.setRenderHint(QPainter.HighQualityAntialiasing) region = event.region() self.painter.fillRect(region.boundingRect(), self.brush) # Background painter color try: self.surface.paint(self.painter) SetImageSize(self.currentFrame().width(), self.currentFrame().height()) except Exception: None # Prevent draw on video if not started or finished if self.parent.player.position() == 0: self.painter.end() return 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 _: QMouseEvent @param _: @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 @type values: list @param values: Points list @type Longitude: float @param Longitude: Longitude value @type Latitude: float @param Latitude: Latitude value @type Altitude: float @param Altitude: Altitude value """ 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)) self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry) 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) tr = QgsCoordinateTransform( QgsCoordinateReferenceSystem( 'EPSG:4326' ), iface.mapCanvas().mapSettings().destinationCrs(), QgsProject.instance().transformContext() ) mapPt = tr.transform( QgsPointXY(Longitude, Latitude) ) vertices = self.Cursor_Canvas_RubberBand.numberOfVertices() if vertices > 0: self.Cursor_Canvas_RubberBand.removePoint(0, True, 0) self.Cursor_Canvas_RubberBand.movePoint( mapPt, 0) else: self.Cursor_Canvas_RubberBand.addPoint( mapPt ) if self._MGRS: try: mgrsCoords = mgrs.toMgrs(Latitude, Longitude) except Exception: mgrsCoords = "" txt = "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%s" % mgrsCoords) + "</span>" else: txt = "<span style='font-size:10pt; font-weight:bold;'>Lon : </span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.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 @type value: bool @param value: """ 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 @type value: bool @param value: """ self._interaction.stamp = value def SetPointDrawer(self, value): """Set Point Drawer @type value: bool @param value: """ self._interaction.pointDrawer = value def SetLineDrawer(self, value): """Set Line Drawer @type value: bool @param value: """ self._interaction.lineDrawer = value def SetPolygonDrawer(self, value): """Set Polygon Drawer @type value: bool @param value: """ 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, _): """ @type _: QEvent @param _: @return: """ # Remove coordinates label value self.parent.lb_cursor_coord.setText("") # Change cursor self.setCursor(QCursor(Qt.ArrowCursor)) # Reset mouse rubberband self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry)
class TaskingDockWidget(BASE, WIDGET): def __init__( self, parent=None, ): super().__init__(parent=parent) self.setupUi(self) self.rect = None self.prev_map_tool = None self.btnMapTool.setIcon(TASKING_ICON) self.btnMapTool.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setFillColor(QColor(204, 235, 239, 100)) self.footprint.setWidth(2) self.marker = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.marker.setIcon(QgsRubberBand.ICON_SVG) self.marker.setSvgIcon(SVG_ICON, QPoint(-15, -30)) self.map_tool = AOICaptureMapTool(iface.mapCanvas()) self.map_tool.aoi_captured.connect(self.aoi_captured) self.btnMapTool.toggled.connect(self._set_map_tool) iface.mapCanvas().mapToolSet.connect(self._map_tool_set) self.textBrowserPoint.setHtml("No point selected") self.btnOpenDashboard.setEnabled(False) self.btnOpenDashboard.clicked.connect(self._open_tasking_dashboard) self.btnCancel.clicked.connect(self.cancel_clicked) self.visibilityChanged.connect(self.visibility_changed) self.textBrowserPoint.viewport().setAutoFillBackground(False) def aoi_captured(self, rect, pt): self.pt = pt self.rect = rect self.footprint.setToGeometry(QgsGeometry.fromRect(rect)) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) transformed = transform.transform(pt) self.marker.setToGeometry(QgsGeometry.fromPointXY(transformed)) self._set_map_tool(False) text = f""" <p><b>Selected Point Coordinates</b></p> <p align="center">Latitude : {pt.x():.4f}</p> <p align="center">Longitude : {pt.y():.4f}</p> """ self.textBrowserPoint.setHtml(text) self.btnCancel.setEnabled(True) self.btnOpenDashboard.setEnabled(True) def cancel_clicked(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) self.marker.reset(QgsWkbTypes.PointGeometry) self.btnOpenDashboard.setEnabled(False) self.textBrowserPoint.setHtml("") self.btnCancel.setEnabled(False) self._set_map_tool(False) def _set_map_tool(self, checked): if checked: self.prev_map_tool = iface.mapCanvas().mapTool() iface.mapCanvas().setMapTool(self.map_tool) else: if self.prev_map_tool is not None: iface.mapCanvas().setMapTool(self.prev_map_tool) def _map_tool_set(self, new, old): if new != self.map_tool: self.btnMapTool.blockSignals(True) self.btnMapTool.setChecked(False) self.btnMapTool.blockSignals(False) def visibility_changed(self, visible): if not visible: self.cancel_clicked() def _open_tasking_dashboard(self): dialog = WarningDialog(self.pt) dialog.exec()
class RectangleTemplateWidget(QWidget, Ui_RectangleTemplateWidget): def __init__(self, canvas, msglog, current_missiontrack, parent=None): super(RectangleTemplateWidget, self).__init__(parent) self.setupUi(self) self.canvas = canvas self.msglog = msglog self.current_missiontrack = current_missiontrack self.setAttribute(Qt.WA_DeleteOnClose) self.rubber_band = None self.rubber_band_points = None self.initial_point = None self.template_type = 'rectangle_template' self.wp = list() self.mission = None self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') self.wp_list = [] self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubber_band.setWidth(2) self.rubber_band.setColor(QColor("green")) 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.initial_point = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.initial_point.setColor(QColor("red")) self.initial_point.setIcon(QgsRubberBand.ICON_CIRCLE) self.initial_point.setIconSize(10) self.onTarget = False self.area_points = None self.missionAreaDefined = False # Get the tools self.rectBy3Points_tool = RectBy3PointsTool(self.canvas) self.rectByFixedExtentTool = RectByFixedExtentTool(self.canvas, 0.0, 0.0) self.rect_from_center_tool = RectFromCenterTool(self.canvas) self.rect_from_center_fixed_tool = RectFromCenterFixedTool(self.canvas, 0.0, 0.0) self.drawRectangleButton.clicked.connect(self.draw_mission_area) self.centerOnTargetButton.clicked.connect(self.draw_mission_area) self.rectBy3Points_tool.msgbar.connect(self.pass_message_bar) self.depthButton.setAutoExclusive(False) self.altitudeButton.setAutoExclusive(False) self.depthButton.setChecked(True) self.altitudeButton.setChecked(False) self.alongTrackLabel.setEnabled(False) self.acrossTrackLabel.setEnabled(False) self.alongTLength.setEnabled(False) self.acrossTLength.setEnabled(False) self.fixedExtent.toggled.connect(self.fixed_extend_toggled) self.depthButton.toggled.connect(self.depth_toggled) self.altitudeButton.toggled.connect(self.altitude_toggled) self.initial_point_comboBox.currentIndexChanged.connect(self.change_initial_point) def get_template_mission(self): return self.mission def fixed_extend_toggled(self): is_checked = self.fixedExtent.isChecked() self.alongTrackLabel.setEnabled(is_checked) self.acrossTrackLabel.setEnabled(is_checked) self.alongTLength.setEnabled(is_checked) self.acrossTLength.setEnabled(is_checked) def depth_toggled(self): if self.depthButton.isChecked(): self.altitudeButton.setChecked(False) def altitude_toggled(self): if self.altitudeButton.isChecked(): self.depthButton.setChecked(False) def pass_message_bar(self, msg): self.msglog.logMessage("") self.msglog.logMessage(msg, "Lawn Mower", 0) def draw_mission_area(self): self.onTarget = False sender = self.sender().objectName() if not self.missionAreaDefined: if self.automaticExtent.isChecked(): if sender == self.drawRectangleButton.objectName(): self.msglog.logMessage("Click starting point", "Lawn Mower", 0) # Draw mission area self.rectBy3Points_tool = RectBy3PointsTool(self.canvas) self.canvas.setMapTool(self.rectBy3Points_tool) self.rectBy3Points_tool.msgbar.connect(self.pass_message_bar) self.rectBy3Points_tool.rb_reset_signal.connect(self.clear_initial_point) self.rectBy3Points_tool.rbFinished.connect(self.create_mission_area) elif sender == self.centerOnTargetButton.objectName(): self.onTarget = True self.msglog.logMessage("Click center point", "Lawn Mower", 0) # Draw mission area self.rect_from_center_tool = RectFromCenterTool(self.canvas) self.canvas.setMapTool(self.rect_from_center_tool) self.rect_from_center_tool.msgbar.connect(self.pass_message_bar) self.rect_from_center_tool.rb_reset_signal.connect(self.clear_initial_point) self.rect_from_center_tool.rbFinished.connect(self.create_mission_area) self.missionAreaDefined = True return elif self.fixedExtent.isChecked(): if self.alongTLength.value() != 0.0 and self.acrossTLength.value() != 0.0: if sender == self.drawRectangleButton.objectName(): self.msglog.logMessage("Click starting point", "Lawn Mower", 0) self.rectByFixedExtentTool = RectByFixedExtentTool(self.canvas, self.alongTLength.value(), self.acrossTLength.value()) self.canvas.setMapTool(self.rectByFixedExtentTool) self.rectByFixedExtentTool.msgbar.connect(self.pass_message_bar) self.rectByFixedExtentTool.rb_reset_signal.connect(self.clear_initial_point) self.rectByFixedExtentTool.rbFinished.connect(self.create_mission_area) self.missionAreaDefined = True elif sender == self.centerOnTargetButton.objectName(): self.onTarget = True self.msglog.logMessage("Click center point", "Lawn Mower", 0) self.rect_from_center_fixed_tool = RectFromCenterFixedTool(self.canvas, self.alongTLength.value(), self.acrossTLength.value()) self.canvas.setMapTool(self.rect_from_center_fixed_tool) self.rect_from_center_fixed_tool.msgbar.connect(self.pass_message_bar) self.rect_from_center_fixed_tool.rb_reset_signal.connect(self.clear_initial_point) self.rect_from_center_fixed_tool.rbFinished.connect(self.create_mission_area) return else: QMessageBox.warning(None, "Mission Template", "<center>Track lengths must be different from zero. </center>", QMessageBox.Close) return else: self.deactivate_tool() self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.initial_point.reset(QgsWkbTypes.PointGeometry) self.missionAreaDefined = False self.draw_mission_area() def clear_initial_point(self): """ Reset the initial point rubber band from canvas """ if self.initial_point is not None: self.initial_point.reset(QgsWkbTypes.PointGeometry) def change_initial_point(self): """ Change the initial point """ self.clear_initial_point() if self.area_points is not None: area = self.area_points index = self.initial_point_comboBox.currentIndex() self.initial_point.addPoint(area[index]) def create_mission_area(self, geom): self.pass_message_bar("") self.clear_initial_point() if geom is not None: # Store points to variables self.area_points = [QgsPointXY(geom.vertexAt(0)), QgsPointXY(geom.vertexAt(1)), QgsPointXY(geom.vertexAt(2)), QgsPointXY(geom.vertexAt(3))] self.change_initial_point() self.missionAreaDefined = True def preview_tracks(self): """ preview tracks on the canvas""" if self.missionAreaDefined: if self.altitudeButton.isChecked() and self.depthAltitudeBox.value() == 0: QMessageBox.warning(None, "Mission Template", "<center>Altitude must be different from zero. </center>", QMessageBox.Close) else: self.wp_list = self.compute_tracks(self.get_area_points()) self.track_to_mission(self.wp_list, self.get_z(), self.get_altitude_mode(), self.get_speed(), self.get_x_tolerance(), self.get_y_tolerance(), self.get_z_tolerance()) # show rubber band with temporal tracks self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.initial_point.reset(QgsWkbTypes.PointGeometry) for wp in self.wp_list: self.rubber_band.addPoint(QgsPointXY(wp.x(), wp.y())) self.rubber_band_points.addPoint(QgsPointXY(wp.x(), wp.y())) self.rubber_band_points.show() self.rubber_band.show() self.unset_map_tool() else: QMessageBox.warning(None, "Mission Template", "<center>Define first an area for the mission. </center>", QMessageBox.Close) def get_area_points(self): return self.area_points def get_num_across_tracks(self): return int(self.numAcrossTracks.value()) def get_altitude_mode(self): return self.altitudeButton.isChecked() def get_z(self): return self.depthAltitudeBox.value() def get_speed(self): return self.speed_doubleSpinBox.value() def get_x_tolerance(self): return self.x_tolerance_doubleSpinBox.value() def get_y_tolerance(self): return self.y_tolerance_doubleSpinBox.value() def get_z_tolerance(self): return self.z_tolerance_doubleSpinBox.value() def get_mission_type(self): return self.template_type def compute_tracks(self, area_points): """ Compute rectangle tracks :param area_points: points defining the extent of the tracks, they should be in WGS 84 lat/lon. first two points define the along track direction. :return: list of ordered waypoints of rectangle trajectory """ index = self.initial_point_comboBox.currentIndex() if index == 0: new_area = [area_points[0], area_points[1], area_points[2], area_points[3]] elif index == 1: new_area = [area_points[1], area_points[2], area_points[3], area_points[0]] elif index == 2: new_area = [area_points[2], area_points[3], area_points[0], area_points[1]] elif index == 3: new_area = [area_points[3], area_points[0], area_points[1], area_points[2]] new_area.append(area_points[index]) return new_area def track_to_mission(self, wp_list, z, altitude_mode, speed, tolerance_x, tolerance_y, tolerance_z): self.mission = Mission() for wp in range(len(wp_list)): if wp == 0: # first step type waypoint step = MissionStep() mwp = MissionWaypoint(MissionPosition(wp_list[wp].y(), wp_list[wp].x(), z, altitude_mode), speed, MissionTolerance(tolerance_x, tolerance_y, tolerance_z)) step.add_maneuver(mwp) self.mission.add_step(step) else: # rest of steps type section step = MissionStep() mwp = MissionSection(MissionPosition(wp_list[wp - 1].y(), wp_list[wp - 1].x(), z, altitude_mode), MissionPosition(wp_list[wp].y(), wp_list[wp].x(), z, altitude_mode), speed, MissionTolerance(tolerance_x, tolerance_y, tolerance_z)) step.add_maneuver(mwp) self.mission.add_step(step) def delete_widget(self): self.delete_all(self.layout()) self.deleteLater() self.close() def delete_all(self, layout): """ delete all widget from layout :param layout: layout is a qt layout """ if layout is not None: for i in reversed(range(layout.count())): item = layout.takeAt(i) widget = item.widget() if widget is not None: widget.deleteLater() else: self.delete_all(item.layout()) def unset_map_tool(self): """ Unset map tool from canvas. """ if self.automaticExtent.isChecked(): if self.onTarget: self.canvas.unsetMapTool(self.rect_from_center_tool) else: self.canvas.unsetMapTool(self.rectBy3Points_tool) if self.fixedExtent.isChecked(): if self.onTarget: self.canvas.unsetMapTool(self.rect_from_center_fixed_tool) else: self.canvas.unsetMapTool(self.rectByFixedExtentTool) def deactivate_tool(self): """ Deactivate tool. """ if self.rectBy3Points_tool: self.rectBy3Points_tool.deactivate() elif self.rectByFixedExtentTool: self.rectByFixedExtentTool.deactivate() if self.rect_from_center_tool: self.rect_from_center_tool.deactivate() elif self.rect_from_center_fixed_tool: self.rect_from_center_fixed_tool.deactivate() def close(self): self.unset_map_tool() self.deactivate_tool() if self.rubber_band is not None: self.canvas.scene().removeItem(self.rubber_band) del self.rubber_band self.rubber_band = None if self.rubber_band_points is not None: self.canvas.scene().removeItem(self.rubber_band_points) del self.rubber_band_points self.rubber_band_points = None if self.initial_point is not None: self.canvas.scene().removeItem(self.initial_point) del self.initial_point self.initial_point = None
class quickFinder(QObject): name = u"&Quick Finder" actions = None toolbar = None finders = {} loadingIcon = None def __init__(self, iface): QObject.__init__(self) self.iface = iface self.actions = {} self.finders = {} self.settings = MySettings() self._initFinders() self.iface.projectRead.connect(self._reloadFinders) self.iface.newProjectCreated.connect(self._reloadFinders) # translation environment self.plugin_dir = os.path.dirname(__file__) locale = QSettings().value("locale/userLocale")[0:2] localePath = os.path.join(self.plugin_dir, 'i18n', 'quickfinder_{0}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) QCoreApplication.installTranslator(self.translator) 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("http://3nids.github.io/quickfinder"))) 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) def unload(self): """ Unload plugin """ for key in self.finders.keys(): self.finders[key].close() for action in self.actions.itervalues(): self.iface.removePluginMenu(self.name, action) if self.toolbar: del self.toolbar if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def _initToolbar(self): """setup the plugin toolbar.""" self.toolbar = self.iface.addToolBar(self.name) self.toolbar.setObjectName('mQuickFinderToolBar') self.searchAction = QAction(QIcon(":/plugins/quickfinder/icons/magnifier13.svg"), self.tr("Search"), self.toolbar) self.stopAction = QAction( QIcon(":/plugins/quickfinder/icons/wrong2.svg"), self.tr("Cancel"), self.toolbar) self.finderBox = FinderBox(self.finders, self.iface, self.toolbar) self.finderBox.searchStarted.connect(self.searchStarted) self.finderBox.searchFinished.connect(self.searchFinished) self.finderBoxAction = self.toolbar.addWidget(self.finderBox) self.finderBoxAction.setVisible(True) self.searchAction.triggered.connect(self.finderBox.search) self.toolbar.addAction(self.searchAction) self.stopAction.setVisible(False) self.stopAction.triggered.connect(self.finderBox.stop) self.toolbar.addAction(self.stopAction) self.toolbar.setVisible(True) def _initFinders(self): self.finders['geomapfish'] = GeomapfishFinder(self) self.finders['osm'] = OsmFinder(self) self.finders['project'] = ProjectFinder(self) for key in self.finders.keys(): self.finders[key].message.connect(self.displayMessage) self.refreshProject() def _reloadFinders(self): for key in self.finders.keys(): self.finders[key].close() self.finders[key].reload() self.refreshProject() @pyqtSlot(str, QgsMessageBar.MessageLevel) def displayMessage(self, message, level): self.iface.messageBar().pushMessage("QuickFinder", message, level) def showSettings(self): if ConfigurationDialog().exec_(): self._reloadFinders() def searchStarted(self): self.searchAction.setVisible(False) self.stopAction.setVisible(True) def searchFinished(self): self.searchAction.setVisible(True) self.stopAction.setVisible(False) def refreshProject(self): if not self.finders['project'].activated: return if not self.settings.value("refreshAuto"): return nDays = self.settings.value("refreshDelay") # do not ask more ofen than 3 days askLimit = min(3, nDays) recentlyAsked = self.settings.value("refreshLastAsked") >= nDaysAgoIsoDate(askLimit) if recentlyAsked: return threshDate = nDaysAgoIsoDate(nDays) uptodate = True for search in self.finders['project'].searches.values(): if search.dateEvaluated <= threshDate: uptodate = False break if uptodate: return self.settings.setValue("refreshLastAsked", nDaysAgoIsoDate(0)) ret = QMessageBox(QMessageBox.Warning, "Quick Finder", QCoreApplication.translate("Auto Refresh", "Some searches are outdated. Do you want to refresh them ?"), QMessageBox.Cancel | QMessageBox.Yes).exec_() if ret == QMessageBox.Yes: RefreshDialog(self.finders['project']).exec_()
class GeomapfishLocatorFilter(QgsLocatorFilter): USER_AGENT = b'Mozilla/5.0 QGIS GeoMapFish Locator Filter' def __init__(self, iface: QgisInterface = None): super().__init__() self.rubber_band = None self.settings = Settings() self.iface = None self.map_canvas = None self.current_timer = None self.transform = None # only get map_canvas on main thread, not when cloning if iface is not None: self.iface = iface self.map_canvas = iface.mapCanvas() self.map_canvas.destinationCrsChanged.connect( self.create_transform) self.rubber_band = QgsRubberBand(self.map_canvas) self.rubber_band.setColor(QColor(255, 255, 50, 200)) self.rubber_band.setIcon(self.rubber_band.ICON_CIRCLE) self.rubber_band.setIconSize(15) self.rubber_band.setWidth(4) self.rubber_band.setBrushStyle(Qt.NoBrush) self.create_transform() def name(self) -> str: return self.__class__.__name__ def clone(self): return GeomapfishLocatorFilter() def displayName(self) -> str: name = self.settings.value("filter_name") if name != '': return name return self.tr('Geomapfish service') def prefix(self) -> str: return 'gmf' def hasConfigWidget(self) -> bool: return True def openConfigWidget(self, parent=None): ConfigDialog(parent).exec_() def create_transform(self): srv_crs_authid = self.settings.value('geomapfish_crs') src_crs = QgsCoordinateReferenceSystem(srv_crs_authid) assert src_crs.isValid() dst_crs = self.map_canvas.mapSettings().destinationCrs() self.transform = QgsCoordinateTransform(src_crs, dst_crs, QgsProject.instance()) @staticmethod def url_with_param(url, params) -> str: url = QUrl(url) q = QUrlQuery(url) for key, value in params.items(): q.addQueryItem(key, value) url.setQuery(q) return url.url() def emit_bad_configuration(self, err=None): result = QgsLocatorResult() result.filter = self result.displayString = self.tr('Locator filter is not configured.') result.description = err if err else self.tr( 'Double-click to configure.') result.userData = FilterNotConfigured result.icon = QgsApplication.getThemeIcon('mIconWarning.svg') self.resultFetched.emit(result) return @pyqtSlot() def clear_results(self): if self.rubber_band: self.rubber_band.reset(QgsWkbTypes.PointGeometry) if self.current_timer is not None: self.current_timer.timeout.disconnect(self.clear_results) self.current_timer.stop() self.current_timer.deleteLater() self.current_timer = None def fetchResults(self, search, context, feedback): try: self.dbg_info("start GMF locator search...") url = self.settings.value('geomapfish_url') if url == "": self.emit_bad_configuration() return params = { 'query': search, 'limit': str(self.settings.value('total_limit')), 'partitionlimit': str(self.settings.value('category_limit')) } if len(search) < 2: return headers = {b'User-Agent': self.USER_AGENT} if self.settings.value('geomapfish_user') != '': user = self.settings.value('geomapfish_user') password = self.settings.value('geomapfish_pass') auth_data = "{}:{}".format(user, password) b64 = QByteArray(auth_data.encode()).toBase64() headers[QByteArray('Authorization'.encode())] = QByteArray( 'Basic '.encode()) + b64 url = self.url_with_param(url, params) self.dbg_info(url) nam = NetworkAccessManager() feedback.canceled.connect(nam.abort) (response, content) = nam.request(url, headers=headers, blocking=True) self.handle_response(response, content) except RequestsExceptionUserAbort: pass except RequestsException as err: self.emit_bad_configuration(str(err)) self.info(err) except Exception as e: self.info(str(e), Qgis.Critical) #exc_type, exc_obj, exc_traceback = sys.exc_info() #filename = os.path.split(exc_traceback.tb_frame.f_code.co_filename)[1] #self.info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) #self.info(traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) finally: self.finished.emit() def handle_response(self, response, content): try: if response.status_code != 200: self.info("Error with status code: {}".format( response.status_code)) return data = json.loads(content.decode('utf-8')) #self.dbg_info(data) features = data['features'] for f in features: json_geom = json.dumps(f['geometry']) ogr_geom = ogr.CreateGeometryFromJson(json_geom) wkt = ogr_geom.ExportToWkt() geometry = QgsGeometry.fromWkt(wkt) self.dbg_info('---------') self.dbg_info( QgsWkbTypes.geometryDisplayString(geometry.type())) self.dbg_info(f.keys()) self.dbg_info('{} {}'.format(f['properties']['layer_name'], f['properties']['label'])) self.dbg_info(f['bbox']) self.dbg_info(f['geometry']) if geometry is None: continue result = QgsLocatorResult() result.filter = self result.displayString = f['properties']['label'] if Qgis.QGIS_VERSION_INT >= 30100: result.group = self.beautify_group( f['properties']['layer_name']) result.userData = geometry self.resultFetched.emit(result) except Exception as e: self.info(str(e), Qgis.Critical) #exc_type, exc_obj, exc_traceback = sys.exc_info() #filename = os.path.split(exc_traceback.tb_frame.f_code.co_filename)[1] #self.info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) # self.info(traceback.print_exception(exc_type, exc_obj, exc_traceback), Qgis.Critical) def triggerResult(self, result): self.clear_results() if result.userData == FilterNotConfigured: self.openConfigWidget() if self.iface and hasattr(self.iface, 'invalidateLocatorResults'): # from QGIS 3.2 iface has invalidateLocatorResults self.iface.invalidateLocatorResults() return # this should be run in the main thread, i.e. mapCanvas should not be None geometry = result.userData geometry.transform(self.transform) self.rubber_band.reset(geometry.type()) self.rubber_band.addGeometry(geometry, None) rect = geometry.boundingBox() rect.scale(1.5) self.map_canvas.setExtent(rect) self.map_canvas.refresh() self.current_timer = QTimer() self.current_timer.timeout.connect(self.clear_results) self.current_timer.setSingleShot(True) self.current_timer.start(5000) def beautify_group(self, group) -> str: if self.settings.value("remove_leading_digits"): group = re.sub('^[0-9]+', '', group) if self.settings.value("replace_underscore"): group = group.replace("_", " ") if self.settings.value("break_camelcase"): group = self.break_camelcase(group) return group def info(self, msg="", level=Qgis.Info): QgsMessageLog.logMessage('{} {}'.format(self.__class__.__name__, msg), 'QgsLocatorFilter', level) def dbg_info(self, msg=""): if DEBUG: self.info(msg) @staticmethod def break_camelcase(identifier) -> str: matches = re.finditer( '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', identifier) return ' '.join([m.group(0) for m in matches])
class Geo360Dialog(QDockWidget, Ui_orbitalDialog): """Geo360 Dialog Class""" def __init__(self, iface, parent=None, featuresId=None, layer=None): QDockWidget.__init__(self) self.setupUi(self) self.DEFAULT_URL = ("http://" + config.IP + ":" + str(config.PORT) + "/viewer.html") self.DEFAULT_EMPTY = ("http://" + config.IP + ":" + str(config.PORT) + "/none.html") self.DEFAULT_BLANK = ("http://" + config.IP + ":" + str(config.PORT) + "/blank.html") # Create Viewer self.CreateViewer() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent # Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.layer, self.featuresId) # Get image path self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.resetQgsRubberBand() self.ChangeUrlViewer(self.DEFAULT_EMPTY) return # Copy file to local server self.CopyFile(self.current_image) # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() """Update data from Marzipano Viewer""" def onNewData(self, data): try: newYaw = float(data[0]) self.UpdateOrientation(yaw=newYaw) except: None def CreateViewer(self): """Create Viewer""" qgsutils.showUserAndLogMessage(u"Information: ", u"Create viewer", onlyLog=True) self.cef_widget = QWebView() self.cef_widget.setContextMenuPolicy(Qt.NoContextMenu) self.cef_widget.settings().setAttribute(QWebSettings.JavascriptEnabled, True) pano_view_settings = self.cef_widget.settings() pano_view_settings.setAttribute(QWebSettings.WebGLEnabled, True) # pano_view_settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True) pano_view_settings.setAttribute( QWebSettings.Accelerated2dCanvasEnabled, True) pano_view_settings.setAttribute(QWebSettings.JavascriptEnabled, True) self.page = _ViewerPage() self.page.newData.connect(self.onNewData) self.cef_widget.setPage(self.page) self.cef_widget.load(QUrl(self.DEFAULT_URL)) self.ViewerLayout.addWidget(self.cef_widget, 1, 0) # def SetInitialYaw(self): # """Set Initial Viewer Yaw""" # self.bearing = self.selected_features.attribute(config.column_yaw) # # self.view.browser.GetMainFrame().ExecuteFunction("InitialYaw", # # self.bearing) # return def RemoveImage(self): """Remove Image""" try: os.remove(self.plugin_path + "/viewer/image.jpg") except OSError: pass def CopyFile(self, src): """Copy Image File in Local Server""" qgsutils.showUserAndLogMessage(u"Information: ", u"Copying image", onlyLog=True) src_dir = src dst_dir = self.plugin_path + "/viewer" # Copy image in local folder img = Image.open(src_dir) rgb_im = img.convert("RGB") dst_dir = dst_dir + "/image.jpg" try: os.remove(dst_dir) except OSError: pass rgb_im.save(dst_dir) def GetImage(self): """Get Selected Image""" try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) if not os.path.isabs(path): # Relative Path to Project path_project = QgsProject.instance().readPath("./") path = os.path.normpath(os.path.join(path_project, path)) except Exception: qgsutils.showUserAndLogMessage(u"Information: ", u"Column not found.") return qgsutils.showUserAndLogMessage(u"Information: ", str(path), onlyLog=True) return path def ChangeUrlViewer(self, new_url): """Change Url Viewer""" self.cef_widget.load(QUrl(new_url)) def ReloadView(self, newId): """Reaload Image viewer""" self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) # this will activate the window self.activateWindow() self.selected_features = qgsutils.getToFeature(self.layer, newId) self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.ChangeUrlViewer(self.DEFAULT_EMPTY) self.resetQgsRubberBand() return # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() # Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(self.DEFAULT_URL) def GetBackNextImage(self): """Get to Back Image""" sender = QObject.sender(self) lys = self.canvas.layers() # Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage(u"Information: ", u"You need load the photo layer.") return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"There is no superiority that follows.") # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(ac_lordem) + "'")) ] # Update selected feature self.ReloadView(ids[0]) if self.encontrado is False: qgsutils.showUserAndLogMessage( u"Information: ", u"You need a layer with images and set the name in the config.py file.", ) return def FullScreen(self, value): """FullScreen action button""" qgsutils.showUserAndLogMessage(u"Information: ", u"Fullscreen.", onlyLog=True) if value: self.showFullScreen() else: self.showNormal() def UpdateOrientation(self, yaw=None): """Update Orientation""" self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except Exception: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() rotatePoint = self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle) self.actualPointOrientation.setToGeometry(rotatePoint, self.dumLayer) # Set Azimut value tmpGeom = rotatePoint.asPolyline() azim = tmpGeom[0].azimuth(tmpGeom[1]) if azim < 0: azim += 360 self.yawLbl.setText("Yaw : " + str(round(yaw, 2)) + " Azimut : " + str(round(azim, 2))) def setOrientation(self, yaw=None): """Set Orientation in the firt time""" self.bearing = self.selected_features.attribute(config.column_yaw) originalPoint = self.selected_features.geometry().asPoint() self.actualPointDx = qgsutils.convertProjection( originalPoint.x(), originalPoint.y(), self.layer.crs().authid(), self.canvas.mapSettings().destinationCrs().authid(), ) self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() epsg = self.canvas.mapSettings().destinationCrs().authid() self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setPosition(self): """Set RubberBand Position""" # Transform Point originalPoint = self.selected_features.geometry().asPoint() self.actualPointDx = qgsutils.convertProjection( originalPoint.x(), originalPoint.y(), "EPSG:4326", self.canvas.mapSettings().destinationCrs().authid(), ) self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) def closeEvent(self, _): """Close dialog""" self.resetQgsRubberBand() self.canvas.refresh() self.iface.actionPan().trigger() self.parent.orbitalViewer = None self.RemoveImage() def resetQgsRubberBand(self): """Remove RubbeBand""" try: self.yawLbl.setText("") self.positionSx.reset() self.positionInt.reset() self.positionDx.reset() self.actualPointOrientation.reset() except Exception: None
class ShLocatorFilter(QgsLocatorFilter): HEADERS = {b'User-Agent': b'Mozilla/5.0 QGIS ShLocator Filter'} message_emitted = pyqtSignal(str, str, Qgis.MessageLevel, QWidget) def __init__(self, iface: QgisInterface = None): """" :param iface: QGIS interface, given when on the main thread (which will display/trigger results), None otherwise """ super().__init__() self.iface = iface self.settings = Settings() # following properties will only be used in main thread self.rubber_band = None self.map_canvas: QgsMapCanvas = None self.transform_ch = None self.current_timer = None self.result_found = False self.nam_fetch_feature = None if iface is not None: # happens only in main thread self.map_canvas = iface.mapCanvas() self.map_canvas.destinationCrsChanged.connect( self.create_transforms) self.rubber_band = QgsRubberBand( self.map_canvas, QgsWkbTypes.PolygonGeometry) self.rubber_band.setColor(QColor(255, 50, 50, 200)) self.rubber_band.setFillColor(QColor(255, 255, 50, 160)) self.rubber_band.setBrushStyle(Qt.SolidPattern) self.rubber_band.setLineStyle(Qt.SolidLine) self.rubber_band.setIcon(self.rubber_band.ICON_CIRCLE) self.rubber_band.setIconSize(15) self.rubber_band.setWidth(4) self.rubber_band.setBrushStyle(Qt.NoBrush) self.create_transforms() def name(self): return 'ShLocator' def clone(self): return ShLocatorFilter() def priority(self): return QgsLocatorFilter.Highest def displayName(self): return 'ShLocator' def prefix(self): return 'shl' def clearPreviousResults(self): if self.rubber_band: self.rubber_band.reset(QgsWkbTypes.PointGeometry) if self.current_timer is not None: self.current_timer.stop() self.current_timer.deleteLater() self.current_timer = None def hasConfigWidget(self): return True def openConfigWidget(self, parent=None): dlg = ConfigDialog(parent) dlg.exec_() def create_transforms(self): # this should happen in the main thread src_crs_ch = QgsCoordinateReferenceSystem('EPSG:2056') assert src_crs_ch.isValid() dst_crs = self.map_canvas.mapSettings().destinationCrs() self.transform_ch = QgsCoordinateTransform( src_crs_ch, dst_crs, QgsProject.instance()) @staticmethod def url_with_param(url, params) -> str: url = QUrl(url) q = QUrlQuery(url) for key, value in params.items(): q.addQueryItem(key, value) url.setQuery(q) return url.url() def fetchResults(self, search: str, context: QgsLocatorContext, feedback: QgsFeedback): try: dbg_info("start shlocator search...") if len(search) < 3: return self.result_found = False params = { 'query': str(search), 'maxfeatures': str(self.settings.value('max_features')) } nam = NetworkAccessManager() feedback.canceled.connect(nam.abort) url = self.url_with_param( self.settings.value('service_url'), params) dbg_info(url) try: (response, content) = nam.request( url, headers=self.HEADERS, blocking=True) self.handle_response(response, search) except RequestsExceptionUserAbort: pass except RequestsException as err: info(err, Qgis.Info) if not self.result_found: result = QgsLocatorResult() result.filter = self result.displayString = self.tr('No result found.') result.userData = NoResult self.resultFetched.emit(result) except Exception as e: info(e, Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) info(traceback.print_exception( exc_type, exc_obj, exc_traceback), Qgis.Critical) def data_product_qgsresult(self, data: dict) -> QgsLocatorResult: result = QgsLocatorResult() result.filter = self result.displayString = data['display'] result.group = 'Karten' result.userData = DataProductResult( type=data['type'], dataproduct_id=data['dataproduct_id'], display=data['display'], dset_info=data['dset_info'], sublayers=data.get('sublayers', None) ) data_product = 'dataproduct' data_type = data['type'] result.icon, result.description = dataproduct2icon_description( data_product, data_type) return result def handle_response(self, response, search_text: str): try: if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): info("Error in main response with status code: " "{} from {}".format(response.status_code, response.url)) return display_name_field = QgsField('display_name', QVariant.String) fields = QgsFields() fields.append(display_name_field) features = QgsJsonUtils.stringToFeatureList(response.content.decode('utf-8'), fields, QTextCodec.codecForName('UTF-8')) dbg_info('Found {} features'.format(len(features))) dbg_info('Data {}'.format(response.content.decode('utf-8'))) for feature in features: dbg_info('Adding feature {}'.format(feature['display_name'])) result = QgsLocatorResult() result.filter = self result.group = 'Objekte' result.displayString = feature['display_name'] result.userData = FeatureResult(feature) self.resultFetched.emit(result) self.result_found = True except Exception as e: info(str(e), Qgis.Critical) exc_type, exc_obj, exc_traceback = sys.exc_info() filename = os.path.split( exc_traceback.tb_frame.f_code.co_filename)[1] info('{} {} {}'.format(exc_type, filename, exc_traceback.tb_lineno), Qgis.Critical) info(traceback.print_exception( exc_type, exc_obj, exc_traceback), Qgis.Critical) def triggerResult(self, result: QgsLocatorResult): # this is run in the main thread, i.e. map_canvas is not None self.clearPreviousResults() if type(result.userData) == NoResult: pass elif type(result.userData) == FeatureResult: self.highlight(result.userData.feature.geometry()) else: info('Incorrect result. Please contact support', Qgis.Critical) def highlight(self, geometry: QgsGeometry): self.rubber_band.reset(geometry.type()) self.rubber_band.addGeometry(geometry, None) rect = geometry.boundingBox() if not self.settings.value('keep_scale'): if rect.isEmpty(): current_extent = self.map_canvas.extent() rect = current_extent.scaled(self.settings.value( 'point_scale')/self.map_canvas.scale(), rect.center()) else: rect.scale(4) self.map_canvas.setExtent(rect) self.map_canvas.refresh() # self.current_timer = QTimer() # self.current_timer.timeout.connect(self.clearPreviousResults) # self.current_timer.setSingleShot(True) # self.current_timer.start(5000) def parse_feature_response(self, response): if response.status_code != 200: if not isinstance(response.exception, RequestsExceptionUserAbort): info("Error in feature response with status code: " "{} from {}".format(response.status_code, response.url)) return data = json.loads(response.content.decode('utf-8')) geometry_type = data['geometry']['type'] geometry = QgsGeometry() if geometry_type == 'Point': geometry = QgsGeometry.fromPointXY(QgsPointXY(data['geometry']['coordinates'][0], data['geometry']['coordinates'][1])) elif geometry_type == 'Polygon': rings = data['geometry']['coordinates'] for r in range(0, len(rings)): for p in range(0, len(rings[r])): rings[r][p] = QgsPointXY(rings[r][p][0], rings[r][p][1]) geometry = QgsGeometry.fromPolygonXY(rings) elif geometry_type == 'MultiPolygon': islands = data['geometry']['coordinates'] for i in range(0, len(islands)): for r in range(0, len(islands[i])): for p in range(0, len(islands[i][r])): islands[i][r][p] = QgsPointXY( islands[i][r][p][0], islands[i][r][p][1]) geometry = QgsGeometry.fromMultiPolygonXY(islands) else: # ShLocator does not handle {geometry_type} yet. Please contact support info('ShLocator unterstützt den Geometrietyp {geometry_type} nicht.' ' Bitte kontaktieren Sie den Support.'.format(geometry_type=geometry_type), Qgis.Warning) geometry.transform(self.transform_ch) self.highlight(geometry)
class QuickFinder(QObject): name = u"&Quick Finder" actions = None toolbar = None finders = {} loadingIcon = None def __init__(self, iface): QObject.__init__(self) self.iface = iface self.actions = {} self.finders = {} self.settings = MySettings() self.rubber = None self._init_finders() self.iface.projectRead.connect(self._reload_finders) self.iface.newProjectCreated.connect(self._reload_finders) # translation environment self.plugin_dir = os.path.dirname(__file__) locale = QSettings().value("locale/userLocale")[0:2] localePath = os.path.join(self.plugin_dir, 'i18n', 'quickfinder_{0}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) QCoreApplication.installTranslator(self.translator) 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.show_settings) 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("http://3nids.github.io/quickfinder"))) self.iface.addPluginToMenu(self.name, self.actions['help']) self._init_toolbar() 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 unload(self): """ Unload plugin """ for key in self.finders.keys(): self.finders[key].close() for action in self.actions.itervalues(): self.iface.removePluginMenu(self.name, action) if self.toolbar: del self.toolbar if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def _init_toolbar(self): """setup the plugin toolbar.""" self.toolbar = self.iface.addToolBar(self.name) self.toolbar.setObjectName('mQuickFinderToolBar') self.search_action = QAction(QIcon(":/plugins/quickfinder/icons/magnifier13.svg"), self.tr("Search"), self.toolbar) self.stop_action = QAction(QIcon(":/plugins/quickfinder/icons/wrong2.svg"), self.tr("Cancel"), self.toolbar) self.finder_box = FinderBox(self.finders, self.iface, self.toolbar) self.finder_box.search_started.connect(self.search_started) self.finder_box.search_finished.connect(self.search_finished) self.finder_box_action = self.toolbar.addWidget(self.finder_box) self.finder_box_action.setVisible(True) self.search_action.triggered.connect(self.finder_box.search) self.toolbar.addAction(self.search_action) self.stop_action.setVisible(False) self.stop_action.triggered.connect(self.finder_box.stop) self.toolbar.addAction(self.stop_action) self.toolbar.setVisible(True) def _init_finders(self): self.finders['geomapfish'] = GeomapfishFinder(self) self.finders['osm'] = OsmFinder(self) self.finders['project'] = ProjectFinder(self) for key in self.finders.keys(): self.finders[key].message.connect(self.display_message) self.refresh_project() def _reload_finders(self): for key in self.finders.keys(): self.finders[key].close() self.finders[key].reload() self.refresh_project() @pyqtSlot(str, QgsMessageBar.MessageLevel) def display_message(self, message, level): self.iface.messageBar().pushMessage("QuickFinder", message, level) def show_settings(self): if ConfigurationDialog().exec_(): self._reload_finders() def search_started(self): self.search_action.setVisible(False) self.stop_action.setVisible(True) def search_finished(self): self.search_action.setVisible(True) self.stop_action.setVisible(False) def refresh_project(self): if not self.finders['project'].activated: return if not self.settings.value("refreshAuto"): return n_days = self.settings.value("refreshDelay") # do not ask more ofen than 3 days ask_limit = min(3, n_days) recently_asked = self.settings.value("refreshLastAsked") >= n_days_ago_iso_date(ask_limit) if recently_asked: return thresh_date = n_days_ago_iso_date(n_days) uptodate = True for search in self.finders['project'].searches.values(): if search.dateEvaluated <= thresh_date: uptodate = False break if uptodate: return self.settings.setValue("refreshLastAsked", n_days_ago_iso_date(0)) ret = QMessageBox(QMessageBox.Warning, "Quick Finder", QCoreApplication.translate("Auto Refresh", "Some searches are outdated. Do you want to refresh them ?"), QMessageBox.Cancel | QMessageBox.Yes).exec_() if ret == QMessageBox.Yes: RefreshDialog(self.finders['project']).exec_()
class IntersectionDialog(QDialog, Ui_Intersection, SettingDialog): def __init__(self, iface, observations, initPoint): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() SettingDialog.__init__(self, self.settings, False, False) self.processButton.clicked.connect(self.doIntersection) self.okButton.clicked.connect(self.accept) self.finished.connect(self.resetRubber) self.initPoint = initPoint self.observations = [] self.solution = None self.report = "" self.rubber = QgsRubberBand(iface.mapCanvas(), QGis.Point) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIcon(self.settings.value("rubberIcon")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.observationTableWidget.displayRows(observations) self.observationTableWidget.itemChanged.connect(self.disbaleOKbutton) self.doIntersection() def resetRubber(self, dummy=0): self.rubber.reset() def disbaleOKbutton(self): self.okButton.setDisabled(True) def doIntersection(self): self.observations = [] self.solution = None self.report = "" self.rubber.reset() observations = self.observationTableWidget.getObservations() nObs = len(observations) if nObs < 2: self.reportBrowser.setText(QCoreApplication.translate("IntersectIt", "No intersection can be done " "with less than 2 observations.")) return if nObs == 2: if observations[0]["type"] == "distance" and observations[1]["type"] == "distance": intersection = TwoCirclesIntersection(observations, self.initPoint) elif observations[0]["type"] == "orientation" and observations[1]["type"] == "orientation": intersection = TwoOrientationIntersection(observations) else: intersection = DistanceOrientationIntersection(observations, self.initPoint) else: maxIter = self.advancedIntersecLSmaxIteration.value() threshold = self.advancedIntersecLSconvergeThreshold.value() intersection = LeastSquares(observations, self.initPoint, maxIter, threshold) self.reportBrowser.setText(intersection.report) if intersection.solution is not None: self.solution = intersection.solution self.observations = observations self.report = intersection.report self.okButton.setEnabled(True) self.rubber.setToGeometry(QgsGeometry().fromPoint(self.solution), None)
class DistanceMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.mapCanvas = iface.mapCanvas() self.settings = MySettings() QgsMapTool.__init__(self, self.mapCanvas) def activate(self): QgsMapTool.activate(self) self.rubber = QgsRubberBand(self.mapCanvas, QGis.Point) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIcon(self.settings.value("rubberIcon")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.updateSnapperList() self.mapCanvas.layersChanged.connect(self.updateSnapperList) self.mapCanvas.scaleChanged.connect(self.updateSnapperList) self.messageWidget = self.iface.messageBar().createMessage("Intersect It", "Not snapped.") self.messageWidgetExist = True self.messageWidget.destroyed.connect(self.messageWidgetRemoved) if self.settings.value("obsDistanceSnapping") != "no": self.iface.messageBar().pushWidget(self.messageWidget) def updateSnapperList(self, dummy=None): self.snapperList = [] tolerance = self.settings.value("selectTolerance") units = self.settings.value("selectUnits") scale = self.iface.mapCanvas().mapRenderer().scale() for layer in self.iface.mapCanvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType(): if not layer.hasScaleBasedVisibility() or layer.minimumScale() < scale <= layer.maximumScale(): snapLayer = QgsSnapper.SnapLayer() snapLayer.mLayer = layer snapLayer.mSnapTo = QgsSnapper.SnapToVertex snapLayer.mTolerance = tolerance if units == "map": snapLayer.mUnitType = QgsTolerance.MapUnits else: snapLayer.mUnitType = QgsTolerance.Pixels self.snapperList.append(snapLayer) def deactivate(self): self.iface.messageBar().popWidget(self.messageWidget) self.rubber.reset() self.mapCanvas.layersChanged.disconnect(self.updateSnapperList) self.mapCanvas.scaleChanged.disconnect(self.updateSnapperList) QgsMapTool.deactivate(self) def messageWidgetRemoved(self): self.messageWidgetExist = False def displaySnapInfo(self, snappingResults): if not self.messageWidgetExist: return nSnappingResults = len(snappingResults) if nSnappingResults == 0: message = "No snap" else: message = "Snapped to: <b>%s" % snappingResults[0].layer.name() + "</b>" if nSnappingResults > 1: layers = [] message += " Nearby: " for res in snappingResults[1:]: layerName = res.layer.name() if layerName not in layers: message += res.layer.name() + ", " layers.append(layerName) message = message[:-2] if self.messageWidgetExist: self.messageWidget.setText(message) def canvasMoveEvent(self, mouseEvent): snappedPoint = self.snapToLayers(mouseEvent.pos()) if snappedPoint is None: self.rubber.reset() else: self.rubber.setToGeometry(QgsGeometry().fromPoint(snappedPoint), None) def canvasPressEvent(self, mouseEvent): if mouseEvent.button() != Qt.LeftButton: return pixPoint = mouseEvent.pos() mapPoint = self.toMapCoordinates(pixPoint) #snap to layers mapPoint = self.snapToLayers(pixPoint, mapPoint) self.rubber.setToGeometry(QgsGeometry().fromPoint(mapPoint), None) distance = Distance(self.iface, mapPoint, 1) dlg = DistanceDialog(distance, self.mapCanvas) if dlg.exec_(): distance.save() self.rubber.reset() def snapToLayers(self, pixPoint, initPoint=None): self.snapping = self.settings.value("obsDistanceSnapping") if self.snapping == "no": return initPoint if self.snapping == "project": ok, snappingResults = QgsMapCanvasSnapper(self.mapCanvas).snapToBackgroundLayers(pixPoint, []) self.displaySnapInfo(snappingResults) if ok == 0 and len(snappingResults) > 0: return QgsPoint(snappingResults[0].snappedVertex) else: return initPoint if self.snapping == "all": if len(self.snapperList) == 0: return initPoint snapper = QgsSnapper(self.mapCanvas.mapRenderer()) snapper.setSnapLayers(self.snapperList) snapper.setSnapMode(QgsSnapper.SnapWithResultsWithinTolerances) ok, snappingResults = snapper.snapPoint(pixPoint, []) self.displaySnapInfo(snappingResults) if ok == 0 and len(snappingResults) > 0: return QgsPoint(snappingResults[0].snappedVertex) else: return initPoint
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.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) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon( QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class DistanceMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.line_layer = None self.settings = MySettings() QgsMapTool.__init__(self, iface.mapCanvas()) def activate(self): QgsMapTool.activate(self) self.line_layer = MemoryLayers(self.iface).line_layer self.rubber = QgsRubberBand(self.canvas(), QGis.Point) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIcon(self.settings.value("rubberIcon")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.messageWidget = self.iface.messageBar().createMessage("Intersect It", "Not snapped.") self.messageWidgetExist = True self.messageWidget.destroyed.connect(self.messageWidgetRemoved) def deactivate(self): self.iface.messageBar().popWidget(self.messageWidget) self.rubber.reset() QgsMapTool.deactivate(self) def messageWidgetRemoved(self): self.messageWidgetExist = False def displaySnapInfo(self, match=None): if not self.messageWidgetExist: return if match is None: message = "No snap" else: message = "Snapped to: <b>{}</b>".format(match.layer()) self.messageWidget.setText(message) def canvasMoveEvent(self, mouseEvent): match = self.snap_to_vertex(mouseEvent.pos()) self.rubber.reset(QGis.Point) if match.type() == QgsPointLocator.Vertex and match.layer() != self.line_layer: self.rubber.addPoint(match.point()) self.displaySnapInfo(match) def canvasPressEvent(self, mouseEvent): if mouseEvent.button() != Qt.LeftButton: return match = self.snap_to_vertex(mouseEvent.pos()) if match.type() != QgsPointLocator.Vertex and match.layer() != self.line_layer: point = self.toMapCoordinates(mouseEvent.pos()) else: point = match.point() self.rubber.addPoint(point) distance = Distance(self.iface, point, 1) dlg = DistanceDialog(distance, self.canvas()) if dlg.exec_(): distance.save() self.rubber.reset() def snap_to_vertex(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.Vertex) 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
class MoveTool(QgsMapToolAdvancedDigitizing): """ Map tool class to move or copy an object """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/move_icon.png' self.text = QCoreApplication.translate("VDLTools", "Move/Copy a feature") self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__findVertex = False self.__onMove = False self.__layer = None self.__confDlg = None self.__lastFeatureId = None self.__selectedFeature = None self.__rubberBand = None self.__rubberSnap = None self.__newFeature = None self.__selectedVertex = None def activate(self): """ When the action is selected """ QgsMapToolAdvancedDigitizing.activate(self) if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def deactivate(self): """ When the action is deselected """ self.__cancel() QgsMapToolAdvancedDigitizing.deactivate(self) def toolName(self): """ To get the tool name :return: tool name """ return QCoreApplication.translate("VDLTools", "Move/Copy") def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def __cancel(self): """ To cancel used variables """ if self.__rubberBand is not None: self.canvas().scene().removeItem(self.__rubberBand) self.__rubberBand.reset() self.__rubberBand = None if self.__rubberSnap is not None: self.canvas().scene().removeItem(self.__rubberSnap) self.__rubberSnap.reset() self.__rubberSnap = None self.__isEditing = False self.__findVertex = False self.__onMove = False self.__lastFeatureId = None self.__selectedFeature = None self.__confDlg = None self.__newFeature = None self.__selectedVertex = None self.__layer.removeSelection() if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.geometryType() == QGis.Point: self.setMode(self.CaptureLine) else: self.setMode(self.CaptureNone) if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return self.action().setEnabled(False) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() self.__removeLayer() def __pointPreview(self, point): """ To create a point geometry preview (rubberBand) :param point: new position as mapPoint """ point_v2 = GeometryV2.asPointV2(self.__selectedFeature.geometry(), self.__iface) self.__newFeature = QgsPointV2(point.x(), point.y()) self.__newFeature.addZValue(point_v2.z()) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.clone()), None) def __linePreview(self, point): """ To create a line geometry preview (rubberBand) :param point: new position as mapPoint """ line_v2, curved = GeometryV2.asLineV2( self.__selectedFeature.geometry(), self.__iface) vertex = QgsPointV2() line_v2.pointAt(self.__selectedVertex, vertex) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) dx = vertex.x() - point.x() dy = vertex.y() - point.y() if isinstance(curved, (list, tuple)): self.__newFeature = QgsCompoundCurveV2() for pos in range(line_v2.nCurves()): curve_v2 = self.__newCurve(curved[pos], line_v2.curveAt(pos), dx, dy) self.__newFeature.addCurve(curve_v2) if pos == 0: self.__rubberBand.setToGeometry( QgsGeometry(curve_v2.curveToLine()), None) else: self.__rubberBand.addGeometry( QgsGeometry(curve_v2.curveToLine()), None) else: self.__newFeature = self.__newCurve(curved, line_v2, dx, dy) self.__rubberBand.setToGeometry( QgsGeometry(self.__newFeature.curveToLine()), None) @staticmethod def __newCurve(curved, line_v2, dx, dy): """ To create a new moved line :param curved: if the line is curved :param line_v2: the original line :param dx: x translation :param dy: y translation :return: the new line """ if curved: newCurve = QgsCircularStringV2() else: newCurve = QgsLineStringV2() points = [] for pos in range(line_v2.numPoints()): x = line_v2.pointN(pos).x() - dx y = line_v2.pointN(pos).y() - dy pt = QgsPointV2(x, y) pt.addZValue(line_v2.pointN(pos).z()) points.append(pt) newCurve.setPoints(points) return newCurve def __polygonPreview(self, point): """ To create a polygon geometry preview (rubberBand) :param point: new position as mapPoint """ polygon_v2, curved = GeometryV2.asPolygonV2( self.__selectedFeature.geometry(), self.__iface) vertex = polygon_v2.vertexAt( GeometryV2.polygonVertexId(polygon_v2, self.__selectedVertex)) dx = vertex.x() - point.x() dy = vertex.y() - point.y() self.__newFeature = QgsCurvePolygonV2() self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line) line_v2 = self.__newCurve(curved[0], polygon_v2.exteriorRing(), dx, dy) self.__newFeature.setExteriorRing(line_v2) self.__rubberBand.setToGeometry(QgsGeometry(line_v2.curveToLine()), None) for num in range(polygon_v2.numInteriorRings()): line_v2 = self.__newCurve(curved[num + 1], polygon_v2.interiorRing(num), dx, dy) self.__newFeature.addInteriorRing(line_v2) self.__rubberBand.addGeometry(QgsGeometry(line_v2.curveToLine()), None) def __onConfirmCancel(self): """ When the Cancel button in Move Confirm Dialog is pushed """ self.__confDlg.reject() def __onConfirmMove(self): """ When the Move button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage(QCoreApplication.translate( "VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) self.__layer.changeGeometry(self.__selectedFeature.id(), geometry) self.__confDlg.accept() self.__cancel() def __onConfirmCopy(self): """ When the Copy button in Move Confirm Dialog is pushed """ geometry = QgsGeometry(self.__newFeature) if not geometry.isGeosValid(): self.__iface.messageBar().pushMessage(QCoreApplication.translate( "VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0) feature = QgsFeature(self.__layer.pendingFields()) feature.setGeometry(geometry) primaryKey = QgsDataSourceURI(self.__layer.source()).keyColumn() for field in self.__selectedFeature.fields(): if field.name() != primaryKey: feature.setAttribute( field.name(), self.__selectedFeature.attribute(field.name())) if len(self.__selectedFeature.fields()) > 0 and self.__layer.editFormConfig().suppress() != \ QgsEditFormConfig.SuppressOn: self.__iface.openFeatureForm(self.__layer, feature) else: self.__layer.addFeature(feature) self.__confDlg.accept() self.__cancel() def keyReleaseEvent(self, event): """ When keyboard is pressed :param event: keyboard event """ if event.key() == Qt.Key_Escape: self.__cancel() def cadCanvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if type(event) == QMoveEvent: map_point = self.toMapCoordinates(event.pos()) else: map_point = event.mapPoint() if not self.__isEditing and not self.__findVertex and not self.__onMove: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), [laySettings]) if f_l is not None and self.__lastFeatureId != f_l[0].id(): self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) if f_l is None: self.__layer.removeSelection() self.__lastFeatureId = None elif self.__findVertex: if self.__rubberBand is not None: self.__rubberBand.reset() closest = self.__selectedFeature.geometry().closestVertex( map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__rubberBand.setToGeometry( QgsGeometry().fromPoint(closest[0]), None) elif self.__onMove: if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(map_point) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(map_point) else: self.__pointPreview(map_point) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) self.__rubberBand.setWidth(2) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(8) if self.__rubberSnap is not None: self.__rubberSnap.reset() else: self.__rubberSnap = QgsRubberBand(self.canvas(), QGis.Point) self.__rubberSnap.setColor(color) self.__rubberSnap.setWidth(2) self.__rubberSnap.setIconSize(20) match = Finder.snap(map_point, self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubberSnap.setIcon(4) else: self.__rubberSnap.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections( point, self.canvas(), self) if intersection is not None: self.__rubberSnap.setIcon(1) point = intersection else: self.__rubberSnap.setIcon(3) self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(point), None) def cadCanvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ if not self.__isEditing and not self.__findVertex and not self.__onMove: found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return self.__selectedFeature = found_features[0] if self.__layer.geometryType() != QGis.Point: self.__iface.messageBar().pushMessage( QCoreApplication.translate( "VDLTools", "Select vertex for moving (ESC to undo)"), level=QgsMessageBar.INFO, duration=3) self.__findVertex = True self.setMode(self.CaptureLine) self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point) else: self.setMode(self.CaptureNone) self.__onMove = True elif self.__findVertex: self.__findVertex = False self.setMode(self.CaptureNone) closest = self.__selectedFeature.geometry().closestVertex( event.mapPoint()) self.__selectedVertex = closest[1] self.__onMove = True elif self.__onMove: self.__onMove = False mapPoint = event.mapPoint() match = Finder.snap(event.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): mapPoint = match.point() if match.hasEdge(): intersection = Finder.snapCurvedIntersections( mapPoint, self.canvas(), self) if intersection is not None: mapPoint = intersection self.__isEditing = True if self.__rubberBand is not None: self.__rubberBand.reset() if self.__layer.geometryType() == QGis.Polygon: self.__polygonPreview(mapPoint) elif self.__layer.geometryType() == QGis.Line: self.__linePreview(mapPoint) else: self.__pointPreview(mapPoint) color = QColor("red") color.setAlphaF(0.78) self.__rubberBand.setColor(color) if self.__layer.geometryType() != QGis.Point: self.__rubberBand.setWidth(2) self.__rubberBand.setLineStyle(Qt.DotLine) else: self.__rubberBand.setIcon(4) self.__rubberBand.setIconSize(20) self.__confDlg = MoveConfirmDialog() self.__confDlg.rejected.connect(self.__cancel) self.__confDlg.moveButton().clicked.connect(self.__onConfirmMove) self.__confDlg.copyButton().clicked.connect(self.__onConfirmCopy) self.__confDlg.cancelButton().clicked.connect( self.__onConfirmCancel) self.__confDlg.show()
class IntersectionDialog(QDialog, Ui_Intersection, SettingDialog): def __init__(self, iface, observations, initPoint): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() SettingDialog.__init__(self, self.settings, UpdateMode.NoUpdate) self.processButton.clicked.connect(self.doIntersection) self.okButton.clicked.connect(self.accept) self.finished.connect(self.resetRubber) self.initPoint = initPoint self.observations = [] self.solution = None self.report = "" self.rubber = QgsRubberBand(iface.mapCanvas(), QGis.Point) self.rubber.setColor(self.settings.value("rubberColor")) self.rubber.setIcon(self.settings.value("rubberIcon")) self.rubber.setIconSize(self.settings.value("rubberSize")) self.observationTableWidget.displayRows(observations) self.observationTableWidget.itemChanged.connect(self.disbaleOKbutton) self.doIntersection() def resetRubber(self, dummy=0): self.rubber.reset() def disbaleOKbutton(self): self.okButton.setDisabled(True) def doIntersection(self): self.observations = [] self.solution = None self.report = "" self.rubber.reset() observations = self.observationTableWidget.getObservations() nObs = len(observations) if nObs < 2: self.reportBrowser.setText(QCoreApplication.translate("IntersectIt", "No intersection can be done " "with less than 2 observations.")) return if nObs == 2: if observations[0]["type"] == "distance" and observations[1]["type"] == "distance": intersection = TwoCirclesIntersection(observations, self.initPoint) elif observations[0]["type"] == "orientation" and observations[1]["type"] == "orientation": intersection = TwoOrientationIntersection(observations) else: intersection = DistanceOrientationIntersection(observations, self.initPoint) else: maxIter = self.advancedIntersecLSmaxIteration.value() threshold = self.advancedIntersecLSconvergeThreshold.value() intersection = LeastSquares(observations, self.initPoint, maxIter, threshold) self.reportBrowser.setText(intersection.report) if intersection.solution is not None: self.solution = intersection.solution self.observations = observations self.report = intersection.report self.okButton.setEnabled(True) self.rubber.setToGeometry(QgsGeometry().fromPoint(self.solution), None)
class Geo360Dialog(QWidget, Ui_orbitalDialog): """QGIS Plugin Implementation.""" def __init__(self, iface, parent=None, featuresId=None, layer=None): """Constructor.""" QDialog.__init__(self) self.setupUi(self) self.s = QSettings() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) QTextCodec.setCodecForCStrings(QTextCodec.codecForName("UTF-8")) Gui.loadLatin1Encoding() self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent #Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId #Restore Previous size self.RestoreSize() #defaults self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.canvas, self.layer, self.featuresId) #Get image path self.current_image = self.GetImage() QtGui.qApp.processEvents() #Creamos el visor self.CreateViewer() QtGui.qApp.processEvents() #Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(self, u"Information: ", u"There is no associated image.", QgsMessageBar.INFO) self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.setPosition() return #Set RubberBand self.setOrientation() self.setPosition() QtGui.qApp.processEvents() #Copy file to local server self.CopyFile(self.current_image) QtGui.qApp.processEvents() #Set Initial Yaw def SetInitialYaw(self): self.bearing = self.selected_features.attribute(config.column_yaw) self.view.browser.GetMainFrame().ExecuteFunction( "InitialYaw", self.bearing) return #Create Viewer def CreateViewer(self): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Create viewer", QgsMessageBar.INFO, onlyLog=True) self.view = CefWidget(self) self.m_vbox = QVBoxLayout() self.m_vbox.addWidget(self.view) QtGui.qApp.processEvents() self.frame.setLayout(self.m_vbox) QtGui.qApp.processEvents() self.view.embed() QtGui.qApp.processEvents() return #Copy Image File in Local Server def CopyFile(self, src): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Copiar imagem", QgsMessageBar.INFO, onlyLog=True) pattern = "^(?P<photo_id>\d+)[^\d].*jpg$" src_dir = src dst_dir = self.plugin_path + "\\viewer" #Delete images on first time for root, dirs, files in os.walk(dst_dir): for file in filter(lambda x: re.match(pattern, x), files): os.remove(os.path.join(root, file)) #Copy image in local folder dst_dir = dst_dir + "\\image.jpg" shutil.copy(src_dir, dst_dir) QtGui.qApp.processEvents() return #Restore Dialog Size def RestoreSize(self): dw = self.s.value("EquirectangularViewer/width") dh = self.s.value("EquirectangularViewer/height") if dw == None: return size = self.size() anim = QtCore.QPropertyAnimation(self, 'size', self) anim.setStartValue(size) anim.setEndValue(QtCore.QSize(dw, dh)) anim.setDuration(1) anim.start() QtGui.qApp.processEvents() return #Save Dialog Size def SaveSize(self): dw = self.width() dh = self.height() self.s.setValue("EquirectangularViewer/width", dw) self.s.setValue("EquirectangularViewer/height", dh) QtGui.qApp.processEvents() return #Get Selected Image def GetImage(self): try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) except: qgsutils.showUserAndLogMessage(self, u"Information: ", u"Column not found.", QgsMessageBar.INFO) return qgsutils.showUserAndLogMessage(self, u"Information: ", str(path), QgsMessageBar.INFO, onlyLog=True) return path #Change Url Viewer def ChangeUrlViewer(self, new_url): self.view.browser.GetMainFrame().ExecuteJavascript( "window.location='%s'" % new_url) QtGui.qApp.processEvents() return #Reaload Image viewer def ReloadView(self, newId): self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) # this will activate the window self.activateWindow() QtGui.qApp.processEvents() self.selected_features = qgsutils.getToFeature(self.canvas, self.layer, newId) self.current_image = self.GetImage() #Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage( self, u"Information: ", u"It is not in the associated image.", QgsMessageBar.INFO) self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.setPosition() return #Set RubberBand self.setOrientation() self.setPosition() #Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(config.DEFAULT_URL) QtGui.qApp.processEvents() return #Expanded/Decreased Dialog def ResizeDialog(self): sender = QObject.sender(self) w = self.width() h = self.height() size = self.size() anim = QtCore.QPropertyAnimation(self, 'size', self) anim.setStartValue(size) if sender.objectName() == "btn_ZoomOut": anim.setEndValue(QtCore.QSize(w - 50, h - 50)) else: anim.setEndValue(QtCore.QSize(w + 50, h + 50)) anim.setDuration(300) anim.start() QtGui.qApp.processEvents() return #Get to Back Image def GetBackNextImage(self): qgsutils.removeAllHighlightFeaturesFromCanvasScene(self.canvas) sender = QObject.sender(self) lys = self.canvas.layers() #Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage( self, u"Information: ", u"You need to upload the photo layer.", QgsMessageBar.INFO) return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) QtGui.qApp.processEvents() f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 #Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression("order ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( self, u"Information: ", u"There is no superiority that follows.", QgsMessageBar.INFO) #Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression("order ='" + str(ac_lordem) + "'")) ] #Update selected feature self.ReloadView(ids[0]) return self.ReloadView(ids[0]) QtGui.qApp.processEvents() if self.encontrado == False: qgsutils.showUserAndLogMessage( self, u"Information: ", u"You need to upload the photo layer.", QgsMessageBar.INFO) return #FullScreen action button def FullScreen(self, bool): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Fullscreen.", QgsMessageBar.INFO, onlyLog=True) if (bool): self.showFullScreen() else: self.showNormal() QtGui.qApp.processEvents() return @staticmethod def ActualOrientation(yaw): geo360Plugin = qgis.utils.plugins["EquirectangularViewer"] if geo360Plugin is not None: geo360Dialog = qgis.utils.plugins["EquirectangularViewer"].dlg if geo360Dialog is not None: geo360Dialog.UpdateOrientation(yaw=float(yaw)) return #Update Orientation def UpdateOrientation(self, yaw=None): self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QGis.Line) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) #End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPoint(A1x, A1y)) #Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) QtGui.qApp.processEvents() #Set Orientation in the firt time def setOrientation(self, yaw=None): self.bearing = self.selected_features.attribute(config.column_yaw) self.actualPointDx = self.selected_features.geometry().asPoint() try: self.actualPointOrientation.reset() except: pass QtGui.qApp.processEvents() self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QGis.Line) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) #End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPoint(A1x, A1y)) #Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() self.dumLayer = QgsVectorLayer("Point?crs=EPSG:4326", "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) QtGui.qApp.processEvents() #Set RubberBand Position def setPosition(self): self.actualPointDx = self.selected_features.geometry().asPoint() try: self.positionDx.reset() self.positionSx.reset() self.positionInt.reset() except: pass QtGui.qApp.processEvents() self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) QtGui.qApp.processEvents() self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) QtGui.qApp.processEvents() #Close dialog def closeEvent(self, evt): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Close dialog", QgsMessageBar.INFO, onlyLog=True) qgsutils.removeAllHighlightFeaturesFromCanvasScene(self.canvas) QtGui.qApp.processEvents() self.canvas.refresh() self.iface.actionPan().trigger() self.SaveSize() self.stopTimer() QtGui.qApp.processEvents() return
class ExtrapolateTool(QgsMapTool): """ Map tool class to extrapolate the elevation of a vertex at the end of a line """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/extrapolate_icon.png' self.text = QCoreApplication.translate("VDLTools", "Extrapolate the elevation of a vertex and a " "point at the extremity of a line") self.__layer = None self.setCursor(Qt.ArrowCursor) self.__isEditing = False self.__lastFeatureId = None self.__rubber = None self.__confDlg = None self.__selectedVertex = None self.__elevation = None self.__selectedFeature = None def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__rubber = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setIconSize(20) def deactivate(self): """ When the action is deselected """ self.__cancel() self.__rubber = None QgsMapTool.deactivate(self) def startEditing(self): """ To set the action as enable, as the layer is editable """ self.action().setEnabled(True) Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer.editingStopped.connect(self.stopEditing) def stopEditing(self): """ To set the action as disable, as the layer is not editable """ self.action().setEnabled(False) Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() def __cancel(self): """ To cancel used variables """ self.__layer.removeSelection() if self.__rubber is not None: self.__rubber.reset() self.__lastFeatureId = None self.__confDlg = None self.__selectedFeature = None self.__selectedVertex = None self.__elevation = None self.__isEditing = False def __removeLayer(self): """ To remove the current working layer """ if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = None def setEnable(self, layer): """ To check if we can enable the action for the selected layer :param layer: selected layer """ if layer is not None and layer.type() == QgsMapLayer.VectorLayer\ and QGis.fromOldWkbType(layer.wkbType()) == QgsWKBTypes.LineStringZ: if layer == self.__layer: return if self.__layer is not None: if self.__layer.isEditable(): Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing) else: Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing) self.__layer = layer if self.__layer.isEditable(): self.action().setEnabled(True) self.__layer.editingStopped.connect(self.stopEditing) else: self.action().setEnabled(False) self.__layer.editingStarted.connect(self.startEditing) if self.canvas().mapTool() == self: self.__iface.actionPan().trigger() return self.action().setEnabled(False) self.__removeLayer() def canvasMoveEvent(self, event): """ When the mouse is moved :param event: mouse event """ if not self.__isEditing: laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10, QgsTolerance.Pixels) f_l = Finder.findClosestFeatureAt(event.mapPoint(), self.canvas(), [laySettings]) if f_l is not None: self.__lastFeatureId = f_l[0].id() self.__layer.setSelectedFeatures([f_l[0].id()]) self.__rubber.reset() geom = f_l[0].geometry() index = geom.closestVertex(event.mapPoint())[1] line_v2, curved = GeometryV2.asLineV2(geom, self.__iface) num_p = line_v2.numPoints() if num_p > 2 and (index == 0 or index == (num_p-1)): self.__rubber.setIcon(4) self.__rubber.setToGeometry(QgsGeometry(line_v2.pointN(index)), None) else: self.__layer.removeSelection() self.__rubber.reset() self.__lastFeatureId = None def canvasReleaseEvent(self, event): """ When the mouse is clicked :param event: mouse event """ found_features = self.__layer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) return geom = found_features[0].geometry() self.__selectedVertex = geom.closestVertex(event.mapPoint())[1] line_v2, curved = GeometryV2.asLineV2(geom, self.__iface) num_p = line_v2.numPoints() if num_p > 2 and (self.__selectedVertex == 0 or self.__selectedVertex == (num_p-1)): pt = line_v2.pointN(self.__selectedVertex) if self.__selectedVertex == 0: pt0 = line_v2.pointN(2) pt1 = line_v2.pointN(1) else: pt0 = line_v2.pointN(num_p-3) pt1 = line_v2.pointN(num_p-2) big_d = Finder.sqrDistForPoints(pt0, pt1) small_d = Finder.sqrDistForPoints(pt1, pt) self.__isEditing = True self.__selectedFeature = found_features[0] self.__elevation = round(pt0.z() + (1 + old_div(small_d, big_d)) * (pt1.z() - pt0.z()), 2) if small_d < (old_div(big_d, 4)): if pt.z() is not None and pt.z() != 0: message = QCoreApplication.translate("VDLTools", "This vertex has already an elevation ") + \ "(" + str(pt.z()) + ")" + \ QCoreApplication.translate("VDLTools", " do you really want to change it (new elevation : ") + \ str(self.__elevation) + ") ?" self.__confDlg = ExtrapolateConfirmDialog(message) self.__confDlg.rejected.connect(self.__cancel) self.__confDlg.okButton().clicked.connect(self.__onEditOk) self.__confDlg.cancelButton().clicked.connect(self.__onEditCancel) self.__confDlg.show() else: self.__edit() else: message = QCoreApplication.translate("VDLTools", "The segment is too big, do you really want " "to extrapolate anyway ? (elevation : ") + \ str(self.__elevation) + ") ?" self.__confDlg = ExtrapolateConfirmDialog(message) self.__confDlg.rejected.connect(self.__cancel) self.__confDlg.okButton().clicked.connect(self.__onEditOk) self.__confDlg.cancelButton().clicked.connect(self.__onEditCancel) self.__confDlg.show() def __onEditOk(self): """ When the Ok button in Extrapolate Confirm Dialog is pushed """ self.__confDlg.accept() self.__edit() def __onEditCancel(self): """ When the Cancel button in Extrapolate Confirm Dialog is pushed """ self.__confDlg.reject() def __edit(self): """ To add the new extrapolate elevation """ line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface) line_v2.setZAt(self.__selectedVertex, self.__elevation) self.__layer.changeGeometry(self.__selectedFeature.id(), QgsGeometry(line_v2)) self.__cancel()
class IntersectTool(QgsMapTool): """ Map tool class to create temporary circle, with center point """ def __init__(self, iface): """ Constructor :param iface: interface """ QgsMapTool.__init__(self, iface.mapCanvas()) self.__iface = iface self.icon_path = ':/plugins/VDLTools/icons/intersect_icon.png' self.text = QCoreApplication.translate("VDLTools", "From intersection") self.setCursor(Qt.ArrowCursor) self.__lineLayerID = None self.__pointLayerID = None self.__rubber = None self.ownSettings = None self.__isEditing = False self.__distance = 0 def setTool(self): """ To set the current tool as this one """ self.canvas().setMapTool(self) def activate(self): """ When the action is selected """ QgsMapTool.activate(self) self.__rubber = QgsRubberBand(self.canvas(), QGis.Point) color = QColor("red") color.setAlphaF(0.78) self.__rubber.setColor(color) self.__rubber.setIcon(4) self.__rubber.setIconSize(20) self.__rubber.setWidth(2) self.__distance = 6.0 def deactivate(self): """ When the action is deselected """ self.__cancel() self.__rubber = None QgsMapTool.deactivate(self) def __cancel(self): """ To cancel used variables """ if self.__rubber is not None: self.__rubber.reset() self.__isEditing = False def __setDistanceDialog(self, mapPoint): """ To create an Intersect Distance Dialog :param mapPoint: radius of the circle """ self.__dstDlg = IntersectDistanceDialog(mapPoint) self.__dstDlg.rejected.connect(self.__cancel) self.__dstDlg.okButton().clicked.connect(self.__onDstOk) self.__dstDlg.cancelButton().clicked.connect(self.__onDstCancel) self.__dstDlg.observation().setValue(self.__distance) self.__dstDlg.observation().selectAll() self.__dstDlg.show() def __onDstOk(self): """ When the Ok button in Intersect Distance Dialog is pushed """ self.__distance = float(self.__dstDlg.observation().text()) circle = QgsCircularStringV2() x = self.__dstDlg.mapPoint().x() y = self.__dstDlg.mapPoint().y() circle.setPoints([ QgsPointV2(x + self.__distance * cos(pi / 180 * a), y + self.__distance * sin(pi / 180 * a)) for a in range(0, 361, 90) ]) lineLayer = self.__lineLayer() lineLayer.startEditing() feature = QgsFeature() feature.setGeometry(QgsGeometry(circle)) fields = lineLayer.pendingFields() feature.setFields(fields) fieldsNames = [fields.at(pos).name() for pos in range(fields.count())] if "distance" in fieldsNames: feature.setAttribute("distance", self.__distance) if "x" in fieldsNames: feature.setAttribute("x", self.__dstDlg.mapPoint().x()) if "y" in fieldsNames: feature.setAttribute("y", self.__dstDlg.mapPoint().y()) lineLayer.addFeature(feature) # lineLayer.updateExtents() lineLayer.commitChanges() # center pointLayer = self.__pointLayer() pointLayer.startEditing() feature = QgsFeature() feature.setGeometry(QgsGeometry().fromPoint(self.__dstDlg.mapPoint())) fields = pointLayer.pendingFields() feature.setFields(fields) pointLayer.addFeature(feature) pointLayer.commitChanges() self.__dstDlg.accept() self.__cancel() def __onDstCancel(self): """ When the Cancel button in Intersect Distance Dialog is pushed """ self.__dstDlg.reject() def canvasMoveEvent(self, mouseEvent): """ When the mouse is moved :param mouseEvent: mouse event """ if not self.__isEditing: self.__rubber.reset() match = Finder.snap(mouseEvent.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasVertex(): if match.layer(): self.__rubber.setIcon(4) else: self.__rubber.setIcon(1) if match.hasEdge(): intersection = Finder.snapCurvedIntersections( point, self.canvas(), self) if intersection is not None: self.__rubber.setIcon(1) point = intersection else: self.__rubber.setIcon(3) self.__rubber.setToGeometry(QgsGeometry().fromPoint(point), None) def canvasReleaseEvent(self, mouseEvent): """ When the mouse is clicked :param mouseEvent: mouse event """ if mouseEvent.button() != Qt.LeftButton: return match = Finder.snap(mouseEvent.mapPoint(), self.canvas()) if match.hasVertex() or match.hasEdge(): point = match.point() if match.hasEdge(): intersection = Finder.snapCurvedIntersections( match.point(), self.canvas(), self) if intersection is not None: point = intersection self.__isEditing = True self.__setDistanceDialog(point) def __lineLayer(self): """ To get the line layer to create the circle :return: a line layer """ if self.ownSettings is not None: if self.ownSettings.linesLayer is not None: layer = self.ownSettings.linesLayer self.__lineLayerID = layer.id() return layer layer = QgsMapLayerRegistry.instance().mapLayer(self.__lineLayerID) if layer is None: epsg = self.canvas().mapRenderer().destinationCrs().authid() layer = QgsVectorLayer( "LineString?crs=%s&index=yes&field=distance:double&field=x:double&field=y:double" % epsg, "Memory Lines", "memory") QgsMapLayerRegistry.instance().addMapLayer(layer) layer.layerDeleted.connect(self.__lineLayerDeleted) self.__lineLayerID = layer.id() if self.ownSettings is not None: self.ownSettings.linesLayer = layer else: self.__iface.legendInterface().setLayerVisible(layer, True) return layer def __lineLayerDeleted(self): """ To deselect the line layer when it is deleted """ self.lineLayerID = None def __pointLayer(self): """ To get the point layer to create the center :return: a point layer """ if self.ownSettings is not None: if self.ownSettings.pointsLayer is not None: layer = self.ownSettings.pointsLayer self.__pointLayerID = layer.id() return layer layer = QgsMapLayerRegistry.instance().mapLayer(self.__pointLayerID) if layer is None: epsg = self.canvas().mapRenderer().destinationCrs().authid() layer = QgsVectorLayer("Point?crs=%s&index=yes" % epsg, "Memory Points", "memory") QgsMapLayerRegistry.instance().addMapLayer(layer) layer.layerDeleted.connect(self.__pointLayerDeleted) self.__pointLayerID = layer.id() if self.ownSettings is not None: self.ownSettings.pointsLayer = layer else: self.__iface.legendInterface().setLayerVisible(layer, True) return layer def __pointLayerDeleted(self): """ To deselect the point layer when it is deleted :return: """ self.__pointLayerID = None
class nominatim_dlg(QDockWidget, Ui_search): def getHttp(self, uri, params): QgsApplication.setOverrideCursor(Qt.WaitCursor) try: rq = QUrl(uri) q = QUrlQuery() for (k, v) in params.items(): q.addQueryItem(k, v) rq.setQuery(q) req = QNetworkRequest(rq) try: reply = self.nominatim_networkAccessManager.blockingGet(req) resource = reply.content().data().decode('utf8') r = json.loads(resource) if (isinstance(r, list)): self.populateTable(r) else: self.populateTable([r]) except: self.tableResult.clearContents() finally: QgsApplication.restoreOverrideCursor() def searchJson(self, params, user, options, options2): contents = str(options).strip() items = contents.split(' ') for (k, v) in options2.items(): if k in ['viewbox']: params["bounded"] = "1" params[k] = v pairs = [] for item in items: pair = item.split('=', 1) if (pair != [''] and pair != [] and len(pair) > 1): pairs.append(pair) for (k, v) in pairs: if k in ['viewbox', 'countrycodes', 'limit', 'exclude_place_ids', 'addressdetails', 'exclude_place_ids', 'bounded', 'routewidth', 'osm_type', 'osm_id'] and not(k in options2.keys()): params[k] = v if k in ['viewbox']: params["bounded"] = "1" params["polygon_text"] = "1" params["format"] = "json" uri = 'https://nominatim.openstreetmap.org/search' self.getHttp(uri, params) def findNearbyJSON(self, params, user, options): uri = "https://nominatim.openstreetmap.org/reverse" params["format"] = "json" self.getHttp(uri, params) """ Gestion de l'évènement "leave", afin d'effacer l'objet sélectionné en sortie du dock """ def eventFilter(self, obj, event): typ = event.type() if typ == event.Leave: try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass return False def __init__(self, parent, plugin): self.plugin = plugin QDockWidget.__init__(self, parent) self.setupUi(self) self.btnApply.setIcon(QIcon(":plugins/nominatim/arrow_green.png")) self.btnMask.setIcon(QIcon(":plugins/nominatim/add_mask.png")) self.btnLayer.setIcon(QIcon(":plugins/nominatim/add_layer.png")) self.tableResult.installEventFilter(self) # cf. eventFilter method self.tableResult.cellDoubleClicked.connect(self.onChoose) self.tableResult.cellEntered.connect(self.cellEntered) self.editSearch.returnPressed.connect(self.onReturnPressed) self.btnSearch.clicked.connect(self.onReturnPressed) self.btnApply.clicked.connect(self.onApply) self.btnHelp.clicked.connect(self.plugin.do_help) self.btnLocalize.clicked.connect(self.doLocalize) self.btnMask.clicked.connect(self.onMask) self.btnLayer.clicked.connect(self.onLayer) self.MultiPolygonLayerId = None self.LineLayerId = None self.PointLayerId = None try: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) except: self.cbExtent.setChecked(self.plugin.limitSearchToExtent) self.currentExtent = self.plugin.canvas.extent() self.tableResult.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) try: self.editSearch.setText(self.plugin.lastSearch) except: pass try: if self.plugin.localiseOnStartup: self.doLocalize() except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass self.nominatim_networkAccessManager = QgsNetworkAccessManager.instance() def cellEntered(self, row, col): item = self.tableResult.item(row, 0) try: self.plugin.canvas.scene().removeItem(self.rubber) self.showItem(item) except: pass def onLayer(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doLayer(item) def onMask(self): for r in self.tableResult.selectedRanges(): item = self.tableResult.item(r.topRow(), 0) self.doMask(item) def populateRow(self, item, idx): id = item['place_id'] name = item['display_name'] try: className = QApplication.translate("nominatim", item['class'], None) except: className = "" try: typeName = QApplication.translate("nominatim", item['type'], None) except: typeName = "" try: wkt = item['geotext'] except: wkt = None try: osm_type = item['osm_type'] except: osm_type = None bbox = {} if osm_type == "node": lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT("+str(lng)+" "+str(lat)+")" ogrGeom = ogr.CreateGeometryFromWkt(wkt) else: try: bbox = item['boundingbox'] poFD = ogr.FeatureDefn("Rectangle") poFD.SetGeomType(ogr.wkbPolygon) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) if wkt is None: wkt = "POLYGON(("+str(bbox[2])+" "+str(bbox[0])+", "+str(bbox[2])+" " +\ str(bbox[1])+", "+str(bbox[3])+" "+str(bbox[1])+", "+str(bbox[3])+" " +\ str(bbox[0])+", "+str(bbox[2])+" "+str(bbox[0])+"))" ogrGeom = ogr.CreateGeometryFromWkt(wkt) except: lat = item['lat'] lng = item['lon'] poFD = ogr.FeatureDefn("Point") poFD.SetGeomType(ogr.wkbPoint) oFLD = ogr.FieldDefn('id', ogr.OFTString) poFD.AddFieldDefn(oFLD) oFLD = ogr.FieldDefn('name', ogr.OFTString) poFD.AddFieldDefn(oFLD) ogrFeature = ogr.Feature(poFD) wkt = "POINT("+str(lng)+" "+str(lat)+")" ogrGeom = ogr.CreateGeometryFromWkt(wkt) mapCrsWKT = self.plugin.canvas.mapSettings().destinationCrs().toWkt() sourceSRS = osr.SpatialReference() sourceSRS.ImportFromEPSG(4326) targetSRS = osr.SpatialReference() targetSRS.ImportFromWkt(str(mapCrsWKT)) trsf = osr.CoordinateTransformation(sourceSRS, targetSRS) try: ogrGeom.Transform(trsf) except TypeError as e: QgsMessageLog.logMessage("Nominatim - transformation error. Check map projection.", "Extensions") ogrFeature.SetGeometry(ogrGeom) ogrFeature.SetFID(int(idx+1)) ogrFeature.SetField(str('id'), str(id)) ogrFeature.SetField(str('name'), name) item = QTableWidgetItem(name) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) item.setData(Qt.UserRole, ogrFeature) self.tableResult.setItem(idx, 0, item) itemLibelle = QTableWidgetItem(className) itemLibelle.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 1, itemLibelle) itemType = QTableWidgetItem(typeName) itemType.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableResult.setItem(idx, 2, itemType) def populateTable(self, r): idx = 0 self.tableResult.clearContents() self.tableResult.setRowCount(len(r)) for item in r: self.populateRow(item, idx) idx = idx+1 def doLocalize(self): try: # center bbox = self.plugin.canvas.extent() sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) bbox = xform.transform(bbox) params = {"lon": str(bbox.center().x()), "lat": str(bbox.center().y()), "zoom": "10"} self.findNearbyJSON(params, self.plugin.gnUsername, self.plugin.gnOptions) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onReturnPressed(self): try: txt = self.editSearch.text().strip() self.plugin.lastSearch = self.editSearch.text() self.plugin.limitSearchToExtent = (self.cbExtent.isChecked()) options = self.plugin.gnOptions options2 = {} if self.plugin.limitSearchToExtent: sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) geom = xform.transform(self.plugin.canvas.extent()) options2 = {'viewbox': str(geom.xMinimum()) + ',' + str(geom.yMaximum()) + ',' + str(geom.xMaximum()) + ',' + str(geom.yMinimum())} params = {'q': txt, 'addressdetails': '0'} self.searchJson(params, self.plugin.gnUsername, options, options2) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass def onChoose(self, row, col): item = self.tableResult.item(row, 0) self.go(item) def onApply(self): for item in self.tableResult.selectedItems(): self.go(item) break def getBBox(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): mapextent = self.plugin.canvas.extent() ww = mapextent.width()/100 mapcrs = self.plugin.canvas.mapSettings().destinationCrs() x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() ww = 50.0 if mapcrs.mapUnits() == QgsUnitTypes.DistanceFeet: ww = 150 if mapcrs.mapUnits() == QgsUnitTypes.DistanceDegrees: ww = 0.0005 bbox = QgsRectangle(x-10*ww, y-10*ww, x+10*ww, y+10*ww) return bbox else: bbox = geom.boundingBox() rubberRect = QgsRectangle(bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum()) return rubberRect def showItem(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PointGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(2) self.rubber.setToGeometry(geom, None) else: # dont show if it is larger than the canvas if self.plugin.canvas.extent().contains(geom.boundingBox()): pass else: geom = geom.intersection(QgsGeometry.fromRect(self.plugin.canvas.extent())) self.rubber = QgsRubberBand(self.plugin.canvas, QgsWkbTypes.PolygonGeometry) self.rubber.setColor(QColor(50, 50, 255, 100)) self.rubber.setWidth(4) self.rubber.setToGeometry(geom, None) def go(self, item, zoom=True): try: self.plugin.canvas.scene().removeItem(self.rubber) except: pass if zoom: bbox = self.getBBox(item) self.plugin.canvas.setExtent(bbox) self.plugin.canvas.refresh() self.showItem(item) def doMask(self, item): mapcrs = self.plugin.canvas.mapSettings().destinationCrs() ogrFeature = item.data(Qt.UserRole) layerName = "OSM "+ogrFeature.GetFieldAsString('id') geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (geom.type() == QgsWkbTypes.PolygonGeometry): try: try: from mask import aeag_mask except: from mask_plugin import aeag_mask aeag_mask.do(mapcrs, {geom}, "Mask "+layerName) except: geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) toCrs = self.plugin.canvas.mapSettings().destinationCrs() l = max(geom.boundingBox().width(), geom.boundingBox().height()) x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() rect = QgsRectangle(x-l, y-l, x+l, y+l) # geom.boundingBox() rect.scale(4) mask = QgsGeometry.fromRect(rect) mask = mask.difference(geom) maskLayer = QgsVectorLayer("MultiPolygon", "Mask "+layerName, "memory") maskLayer.setCrs(toCrs) QgsProject.instance().addMapLayer(maskLayer) pr = maskLayer.dataProvider() fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setGeometry(mask) fet.setFields(fields) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) pr.addAttributes(fields.toList()) maskLayer.startEditing() pr.addFeatures([fet]) maskLayer.commitChanges() maskLayer.updateExtents() # transparence, epaisseur renderer = maskLayer.renderer() s = renderer.symbol() s.setOpacity(0.90) s.setColor(QColor(255, 255, 255)) if isinstance(s, QgsLineSymbol): s.setWidth(0) layerTree = QgsProject.instance().layerTreeRoot().findLayer(maskLayer) if layerTree: self.plugin.iface.layerTreeView().layerTreeModel()\ .refreshLayerLegend(layerTree) # Refresh legend self.go(item) def doLayer(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) fields = QgsFields() fields.append(QgsField("id", QVariant.String)) fields.append(QgsField("name", QVariant.String)) fet = QgsFeature() fet.initAttributes(2) fet.setFields(fields) fet.setGeometry(geom) fet.setAttribute("id", (ogrFeature.GetFieldAsString('id'))) fet.setAttribute("name", (ogrFeature.GetFieldAsString('name'))) vl = None if not self.plugin.singleLayer: if geom.type() == QgsWkbTypes.PolygonGeometry: layerName = "OSMPlaceSearch Polygon" layerId = self.MultiPolygonLayerId if geom.type() == QgsWkbTypes.LineGeometry: layerName = "OSMPlaceSearch Line" layerId = self.LineLayerId if geom.type() == QgsWkbTypes.PointGeometry: layerName = "OSMPlaceSearch Point" layerId = self.PointLayerId vl = QgsProject.instance().mapLayer(layerId) if vl is not None: pr = vl.dataProvider() else: if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") self.MultiPolygonLayerId = vl.id() if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") self.LineLayerId = vl.id() if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") self.PointLayerId = vl.id() if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) QgsProject.instance().addMapLayer(vl) else: layerName = "OSM "+ogrFeature.GetFieldAsString('id') # creer une nouvelle couche si n'existe pas encore if geom.type() == QgsWkbTypes.PolygonGeometry: vl = QgsVectorLayer("MultiPolygon", layerName, "memory") if geom.type() == QgsWkbTypes.LineGeometry: vl = QgsVectorLayer("MultiLineString", layerName, "memory") if geom.type() == QgsWkbTypes.PointGeometry: vl = QgsVectorLayer("Point", layerName, "memory") if vl is not None: pr = vl.dataProvider() # ajout de champs pr.addAttributes(fields.toList()) QgsProject.instance().addMapLayer(vl) if vl is not None: vl.setProviderEncoding('UTF-8') vl.startEditing() pr.addFeatures([fet]) vl.commitChanges() # mise a jour etendue de la couche vl.updateExtents() layerTree = QgsProject.instance().layerTreeRoot().findLayer(vl) if layerTree: self.plugin.iface.layerTreeView()\ .layerTreeModel().refreshLayerLegend(layerTree) # Refresh legend self.go(item, False)