def runGCPMainWindow(self, fromVirtual3D): # this QGIS tool emits as QgsPoint after each click on the map canvas self.clickTool = QgsMapToolEmitPoint(self.canvas) self.canvas.setMapTool(self.clickTool) # create main window self.gcpMainWindow = GetGCPMainWindow(self.iface, self.buffers, self.picture_name,self.pathToData,self.isFrameBufferSupported, self.crs) # show the Main Window self.gcpMainWindow.show() # load the picture in the central widget self.load_picture(self.picture_name) # get DEM reference layer self.gcpMainWindow.cLayer = self.cLayer # connect events between getGCPmainWindow and Qgis canvas self.gcpMainWindow.ui.tableView.selectionModel().currentRowChanged.connect(self.resetClickTool) self.gcpMainWindow.resetToolSignal.connect(self.resetClickTool) self.gcpMainWindow.setCanvasExtentSignal.connect(self.setCanvasExtent) self.clickTool.canvasClicked.connect(self.newCanvasGCP) self.gcpMainWindow.GoToMonoplotterButton.triggered.connect(self.goToMonoplotter) self.gcpMainWindow.clearMapTool2.connect(self.clearMapTool) if fromVirtual3D: self.gcpMainWindow.pos = self.ParamPose[0] self.gcpMainWindow.lookat = self.ParamPose[1] self.gcpMainWindow.FOV = self.ParamPose[2] self.gcpMainWindow.roll = self.ParamPose[3]
class Pic2Map: def __init__(self, iface): # save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.u = 0 self.v = 0 def checkRequirments(self): #Check the openGL version ##ex = CheckVersion() ##ex.updateGL() ##self.isSupported = ex.isSupported ex = CheckVersion() ex.updateGL() # Opengl 3.0 is required for Framebuffer self.isFrameBufferSupported =ex.isSupported # Until now, no hard or software, apart from QGis 2.0 version, has showed problem with the plugin self.isSupported = 1 def initGui(self): # create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/Pic2Map/icon.png"), "Pic2Map",self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) # add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Pic2Map", self.action) def unload(self): # remove the plugin menu item and icon self.iface.removePluginMenu("&Pic2Map",self.action) self.iface.removeToolBarIcon(self.action) # disconnect form signal of the canvas def run(self): self.checkRequirments() if not self.isSupported: QMessageBox.critical(QWidget(), "Version - Error","system configuration insufficient" ) return # Run the plug-in when clicked on the icon #Create an initialization window, where is given : # the landscape picture # the DEM # the ortho-image if used # the approach chosen for georeferencing self.ini = Initialization_dialog() self.ini.setWindowModality(Qt.ApplicationModal) result = self.ini.exec_() # The data are all given at the beginning self.picture_name = self.ini.ui.lineEdit.text() self.DEM_name = self.ini.ui.lineEditDEM.text() self.useOrtho = self.ini.ui.checkBox.isChecked() self.pathToData = self.ini.currentPath # See if OK was pressed if result == 1: try: img = QImage(self.picture_name) if img.isNull(): raise IOError a = self.DEM_name.split('.') if len(a) == 1: raise IOError except IOError: QMessageBox.warning(QWidget(), "I/O - Error","Failed to initialize picture or DEM" ) return if self.DEM_name.split('.')[1] != 'tiff' and self.DEM_name.split('.')[1] != 'tif': QMessageBox.warning(QWidget(), "I/O - Error","Unable to load DEM. \nDEM must be in geotiff format.\nIf you use the test data set, copy it outside the plugin folder." ) return #see if orthoimage is used and load it in case it's used if self.useOrtho: #get name entered self.ortho_name = self.ini.ui.lineEdit_2.text() try: #load as image for checking existence img = QImage(self.ortho_name) if img.isNull(): raise IOError img = None #load as raster for getting bounding box fileInfo = QFileInfo(self.ortho_name) baseName = fileInfo.baseName() rlayer = QgsRasterLayer(self.ortho_name, baseName) self.ortho_box = [int(-rlayer.extent().xMinimum()), int(rlayer.extent().yMinimum()), int(-rlayer.extent().xMaximum()), int(rlayer.extent().yMaximum())] except IOError: QMessageBox.warning(QWidget(), "I/O - Error","Failed to load ortho-image" ) return #see if orthoimage is not used and initialize else: self.ortho_name = None self.ortho_box = None result = self.load_dem() #result is 1 if dem is load correctly if result == 1: # the buffer object contains arrays used for openGL self.load_buffer() #Check if the GCP approach is chosen if self.ini.ui.radioButton.isChecked(): self.runGCPMainWindow(False) #Check if the virtual 3D approach is chosen if self.ini.ui.radioButton_2.isChecked(): self.virtual3DMainWindow = Virtual3DMainWindow(self.buffers,self.picture_name, self.crs, self.pathToData) self.virtual3DMainWindow.show() self.virtual3DMainWindow.ui.goToMonoplotterButton.clicked.connect(self.goToMonoplotter) self.virtual3DMainWindow.ui.GoToGCP.clicked.connect(self.runGCPMainWindowFromVirtual3D) def openOrthoWidget(self): # This function is called from the monoplotter for ortho-rectification. # It is located here because some strange behavior were observed # probably because the synchronous work on 2 opengl window. # They may be a more elegant solution, but it works like this... # Get the view parameters from the monoplotter modelview = self.monoplotter.qgl_window.modelview projection = self.monoplotter.qgl_window.projection viewport = self.monoplotter.qgl_window.viewport texture = self.monoplotter.texture # Create the window for ortho-rectification self.drappingInstance = drappingMain(self.buffers, self.picture_name, modelview, projection, viewport, texture, self.crs, self.DEM_name, self.isFrameBufferSupported) self.drappingInstance.setWindowModality(Qt.ApplicationModal) self.drappingInstance.show() def goToMonoplotter(self): # This function is called from both approach (CCP and virtual 3D) # It close the pose estimation window (GetGCPMainWindow or Virtual3DMainWindow) # and launch the monoplotter. It is not possible anymore to change the position of the view # Check if the virtual 3D approach has been used if hasattr(self, 'virtual3DMainWindow'): self.virtual3DMainWindow.close() self.ParamPose = self.virtual3DMainWindow.ParamPose #Check if the GCP approach has been used elif hasattr(self, 'gcpMainWindow'): self.gcpMainWindow.goToMonoplot = True self.gcpMainWindow.close() self.ParamPose = [self.gcpMainWindow.pos, self.gcpMainWindow.lookat, self.gcpMainWindow.FOV, self.gcpMainWindow.roll] else: raise IOError # launch monoplotter self.monoplotter = MonoplotterMainWindow(self.iface, self.buffers, self.picture_name, self.ParamPose, self.dem_box, self.cLayer, self.pathToData, self.crs, self.DEM_name, self.isFrameBufferSupported) self.monoplotter.show() self.monoplotter.qgl_window.updateGL() self.monoplotter.openOrtho.connect(self.openOrthoWidget) self.monoplotter.qgl_window.blow.connect(self.clickOnMonoplotter) self.monoplotter.ui.measureButton.clicked.connect(self.activateMeasurement) self.monoplotter.clearMapTool.connect(self.clearMapTool) self.activeFlackOnMonoplotter() def drawPinkCross(self, pos): if hasattr(self, 'pinkCross'): self.canvas.scene().removeItem(self.pinkCross) if pos[2] == 1: self.pinkCross = QgsVertexMarker(self.canvas) posi = QgsPoint(pos[0],pos[1]) self.pinkCross.setCenter(posi) self.pinkCross.setColor(QColor(255, 122, 255)) self.pinkCross.setIconSize(10) self.pinkCross.setIconType(QgsVertexMarker.ICON_CROSS) self.pinkCross.setPenWidth(10) def clearMapTool(self): #Call when GCP window is closed #Call when the tool "Measure 3D" from monoplotter is activated self.cTool = self.canvas.mapTool() self.canvas.unsetMapTool(self.cTool) if hasattr(self, 'monoplotter'): if hasattr(self.monoplotter.qgl_window, 'lineEditBuffer'): self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() def runGCPMainWindowFromVirtual3D(self): self.virtual3DMainWindow.close() self.ParamPose = self.virtual3DMainWindow.ParamPose self.runGCPMainWindow(True) def runGCPMainWindow(self, fromVirtual3D): # this QGIS tool emits as QgsPoint after each click on the map canvas self.clickTool = QgsMapToolEmitPoint(self.canvas) self.canvas.setMapTool(self.clickTool) # create main window self.gcpMainWindow = GetGCPMainWindow(self.iface, self.buffers, self.picture_name,self.pathToData,self.isFrameBufferSupported, self.crs) # show the Main Window self.gcpMainWindow.show() # load the picture in the central widget self.load_picture(self.picture_name) # get DEM reference layer self.gcpMainWindow.cLayer = self.cLayer # connect events between getGCPmainWindow and Qgis canvas self.gcpMainWindow.ui.tableView.selectionModel().currentRowChanged.connect(self.resetClickTool) self.gcpMainWindow.resetToolSignal.connect(self.resetClickTool) self.gcpMainWindow.setCanvasExtentSignal.connect(self.setCanvasExtent) self.clickTool.canvasClicked.connect(self.newCanvasGCP) self.gcpMainWindow.GoToMonoplotterButton.triggered.connect(self.goToMonoplotter) self.gcpMainWindow.clearMapTool2.connect(self.clearMapTool) if fromVirtual3D: self.gcpMainWindow.pos = self.ParamPose[0] self.gcpMainWindow.lookat = self.ParamPose[1] self.gcpMainWindow.FOV = self.ParamPose[2] self.gcpMainWindow.roll = self.ParamPose[3] def load_dem(self): try: #load dem for info and extent fileName = self.DEM_name fileInfo = QFileInfo(fileName) baseName = fileInfo.baseName() rlayer2 = QgsRasterLayer(fileName, baseName) self.dem_box = rlayer2.extent() # Get coordinate system self.crs = rlayer2.crs() # check if the map units are meter if self.crs.mapUnits() != 0: raise CRSERROR self.iface.addRasterLayer(self.DEM_name) if not rlayer2.isValid(): QMessageBox.warning(QWidget(), "IO - Error", "Raster failed to load") return 0 # DEM is set such that altitude request will be done on it self.cLayer = rlayer2 return 1 except CRSERROR: QMessageBox.warning(QWidget(), "CRS - Error", "DEM must be in projected coordinates, meter units") return 0 def load_picture(self, picName): ##s.setValue( "/Projections/defaultBehaviour", "UseProject" ) fileName = picName fileInfo = QFileInfo(fileName) baseName = fileInfo.baseName() rlayer = QgsRasterLayer(fileName, baseName) resolution = QDesktopWidget().screenGeometry() size = [0,0] size[1] = resolution.height()/2 size[0] = int(float(float(rlayer.width())/float(rlayer.height()))*size[1]) if not rlayer.isValid(): QMessageBox.warning(QWidget(), "IO - Error", "Picture failed to load!") return # Load the image inside the graphicsview self.gcpMainWindow.setImage(fileName, size) # Set the zoom such the picture is almost in full view in the height directon factor = float(self.gcpMainWindow.ui.graphicsView.size().height())/rlayer.height() self.gcpMainWindow.ui.graphicsView.scale(factor, factor) def resetClickTool(self): # This function is used for GCP digitalization. # It resets the click tool for getting altitude on the DEm layer (self.clayer) self.canvas.setMapTool(self.clickTool) QObject.connect(self.clickTool, SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"),self.newCanvasGCP) def newCanvasGCP(self,point): # This function is used for GCP digitalization. # a new GCP is created on canvas self.gcpMainWindow.selectCanvasPoint(point) self.gcpMainWindow.refreshCanvasGCP() def load_buffer(self): # This function is used at initialization. # Arrays are created here for openGL. The normal calculation can take some time (ca. 1sec for 100'000 pixels) self.buffers = Buffers(self.DEM_name, self.dem_box, self.useOrtho, self.ortho_name, self.ortho_box) self.buffers.getBuffer() self.buffers.close() def clickOnMonoplotter(self,customEvent): # This function is called when digitalization or measurement on monoplotter x = customEvent[0] y = customEvent[1] button = customEvent[2] self.monoplotter.qgl_window.notUpdate = False self.cTool = self.canvas.mapTool() # check if a layer is edited if self.cTool != None: currentLayer = self.iface.activeLayer() if currentLayer.type() == 0 and currentLayer.isEditable() and currentLayer.geometryType() < 3: if self.cTool.isEditTool(): if self.iface.actionAddFeature().isEnabled(): u,v = self.WorldToPixelOfCanvasCoordinates(x,y) p = QPoint() p.setX(u) p.setY(v) event = QMouseEvent(QEvent.MouseButtonRelease,p,button,button,Qt.NoModifier) self.cTool.canvasReleaseEvent(event) # check if the edited layer is a point layer if currentLayer.geometryType() == 0: # Since the feature has been added in the layer, it is sufficient to refresh #the monoplotter for displaying the new point self.monoplotter.refreshLayers(boolSymbology = True) # check if the edited layer is a line layer if currentLayer.geometryType() == 1: # a new point is added if the left button is clicked if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() # The line edition ends if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.refreshLayers(boolSymbology = False) if currentLayer.geometryType() == 2: # a new point is added if the left button is clicked if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() # The line edition ends if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.refreshLayers(boolSymbology = False) # check if the measuring tool is being used if self.cTool.action() == self.iface.actionMeasure(): # measurement is done if left button is clicked if button == Qt.LeftButton: #self.cTool.activate() # get the position in canvas coordinates u_previous = self.u v_previous = self.v self.u,self.v = self.WorldToPixelOfCanvasCoordinates(x,y) # create a mouse click at the projected location on canvas # create a line on the monoplotter if u_previous != self.u or v_previous != self.v: p = QPoint() p.setX(self.u) p.setY(self.v) event = QMouseEvent(QEvent.MouseButtonRelease,p,button,button,Qt.NoModifier) self.cTool.canvasReleaseEvent(event) self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() self.cTool.activate() # update window # the line is cleared if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() else: if self.monoplotter.isMeasuring3D: if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() self.monoplotter.dlgMeasure3D.addPoint(x,y) if button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() self.monoplotter.dlgMeasure3D.removePath() def activateMeasurement(self): # This function is used for calling the measuring tool from the monoplotter self.iface.actionMeasure().trigger() self.monoplotter.stopMeasure3D() def disactiveFlackOnMonoplotter(self): self.canvas.mapTool().canvasMoveEvent = None self.canvas.mapTool().deactivate() self.canvas.unsetMapTool(self.canvas.mapTool()) def activeFlackOnMonoplotter(self): self.clickTool2 = QgsMapToolEmitPoint(self.canvas) self.canvas.setMapTool(self.clickTool2) self.canvas.mapTool().canvasMoveEvent = self.test3 self.monoplotter.qgl_window.pinkCrossSignal.connect(self.drawPinkCross) self.monoplotter.closingMonoplot.connect(self.disactiveFlackOnMonoplotter) def test3(self, ev): x,y = self.CanvastoWorldCoordinates(ev.x(), ev.y()) self.monoplotter.preparePurpleCross(x,y) def WorldToPixelOfCanvasCoordinates(self,x,y): # This function is called in "clickOnMonoplotter". # It convert CSR coordinates (world) into the screen coordinates for a given point in the canvas. canvasExtent = self.canvas.extent() canvasBox = [canvasExtent.xMinimum(), canvasExtent.yMinimum(), canvasExtent.xMaximum(), canvasExtent.yMaximum()] UPP = self.canvas.mapUnitsPerPixel() u = int((x-canvasBox[0])/UPP) v = int((canvasBox[3]-y)/UPP) return (u,v) def CanvastoWorldCoordinates(self,u,v): # This function is called in "clickOnMonoplotter". # It convert CSR coordinates (world) into the screen coordinates for a given point in the canvas. canvasExtent = self.canvas.extent() canvasBox = [canvasExtent.xMinimum(), canvasExtent.yMinimum(), canvasExtent.xMaximum(), canvasExtent.yMaximum()] UPP = self.canvas.mapUnitsPerPixel() x = int(u*UPP+canvasBox[0]) y = int(-v*UPP+canvasBox[3]) return (x,y) def setCanvasExtent(self, pos): # This function is used for GCP digitalization. # It zoom on the canvas depending on which GCp is selected. # The zoom extent is set with referenced to the size of the DEM offset = (self.dem_box.xMinimum()-self.dem_box.xMaximum())/50 zoomRectangle = QgsRectangle(pos[0]-offset, pos[1]-offset,pos[0]+offset,pos[1]+offset) self.canvas.setExtent(zoomRectangle) self.canvas.refresh()
class Pic2Map: def __init__(self, iface): # save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.u = 0 self.v = 0 def checkRequirments(self): #Check the openGL version ##ex = CheckVersion() ##ex.updateGL() ##self.isSupported = ex.isSupported ex = CheckVersion() ex.updateGL() # Opengl 3.0 is required for Framebuffer self.isFrameBufferSupported =ex.isSupported # Until now, no hard or software, apart from QGis 2.0 version, has showed problem with the plugin self.isSupported = 1 def initGui(self): # create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/Pic2Map/icon.png"), "Pic2Map",self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) # add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Pic2Map", self.action) def unload(self): # remove the plugin menu item and icon self.iface.removePluginMenu("&Pic2Map",self.action) self.iface.removeToolBarIcon(self.action) # disconnect form signal of the canvas def run(self): self.checkRequirments() if not self.isSupported: QMessageBox.critical(QWidget(), "Version - Error","system configuration insufficient" ) return # Run the plug-in when clicked on the icon #Create an initialization window, where is given : # the landscape picture # the DEM # the ortho-image if used # the approach chosen for georeferencing self.ini = Initialization_dialog() self.ini.setWindowModality(Qt.ApplicationModal) result = self.ini.exec_() # The data are all given at the beginning self.picture_name = self.ini.ui.lineEdit.text() self.DEM_name = self.ini.ui.lineEditDEM.text() self.useOrtho = self.ini.ui.checkBox.isChecked() self.pathToData = self.ini.currentPath # See if OK was pressed if result == 1: try: img = QImage(self.picture_name) if img.isNull(): raise IOError a = self.DEM_name.split('.') if len(a) == 1: raise IOError except IOError: QMessageBox.warning(QWidget(), "I/O - Error","Failed to initialize picture or DEM" ) return if self.DEM_name.split('.')[1] != 'tiff' and self.DEM_name.split('.')[1] != 'tif': QMessageBox.warning(QWidget(), "I/O - Error","Unable to load DEM. \nDEM must be in geotiff format.\nIf you use the test data set, copy it outside the plugin folder." ) return #see if orthoimage is used and load it in case it's used if self.useOrtho: #get name entered self.ortho_name = self.ini.ui.lineEdit_2.text() try: #load as image for checking existence img = QImage(self.ortho_name) if img.isNull(): raise IOError img = None #load as raster for getting bounding box fileInfo = QFileInfo(self.ortho_name) baseName = fileInfo.baseName() rlayer = QgsRasterLayer(self.ortho_name, baseName) self.ortho_box = [int(-rlayer.extent().xMinimum()), int(rlayer.extent().yMinimum()), int(-rlayer.extent().xMaximum()), int(rlayer.extent().yMaximum())] except IOError: QMessageBox.warning(QWidget(), "I/O - Error","Failed to load ortho-image" ) return #see if orthoimage is not used and initialize else: self.ortho_name = None self.ortho_box = None result = self.load_dem() #result is 1 if dem is load correctly if result == 1: # the buffer object contains arrays used for openGL self.load_buffer() #Check if the GCP approach is chosen if self.ini.ui.radioButton.isChecked(): self.runGCPMainWindow(False) #Check if the virtual 3D approach is chosen if self.ini.ui.radioButton_2.isChecked(): self.virtual3DMainWindow = Virtual3DMainWindow(self.buffers,self.picture_name, self.crs, self.pathToData) self.virtual3DMainWindow.show() self.virtual3DMainWindow.ui.goToMonoplotterButton.clicked.connect(self.goToMonoplotter) self.virtual3DMainWindow.ui.GoToGCP.clicked.connect(self.runGCPMainWindowFromVirtual3D) def openOrthoWidget(self): # This function is called from the monoplotter for ortho-rectification. # It is located here because some strange behavior were observed # probably because the synchronous work on 2 opengl window. # They may be a more elegant solution, but it works like this... # Get the view parameters from the monoplotter modelview = self.monoplotter.qgl_window.modelview projection = self.monoplotter.qgl_window.projection viewport = self.monoplotter.qgl_window.viewport texture = self.monoplotter.texture Xmat = self.monoplotter.Xmat Ymat = self.monoplotter.Ymat #20150823 # Create the window for ortho-rectification self.drappingInstance = drappingMain(self.buffers, self.picture_name, modelview, projection, viewport, texture, self.crs, self.DEM_name, self.isFrameBufferSupported, Xmat, Ymat)#20150923 self.drappingInstance.setWindowModality(Qt.ApplicationModal) self.drappingInstance.show() def goToMonoplotter(self): # This function is called from both approach (CCP and virtual 3D) # It close the pose estimation window (GetGCPMainWindow or Virtual3DMainWindow) # and launch the monoplotter. It is not possible anymore to change the position of the view # Check if the virtual 3D approach has been used if hasattr(self, 'virtual3DMainWindow'): self.virtual3DMainWindow.close() self.ParamPose = self.virtual3DMainWindow.ParamPose #Check if the GCP approach has been used elif hasattr(self, 'gcpMainWindow'): self.gcpMainWindow.goToMonoplot = True self.gcpMainWindow.close() self.ParamPose = [self.gcpMainWindow.pos, self.gcpMainWindow.lookat, self.gcpMainWindow.FOV, self.gcpMainWindow.roll] else: raise IOError # launch monoplotter self.monoplotter = MonoplotterMainWindow(self.iface, self.buffers, self.picture_name, self.ParamPose, self.dem_box, self.cLayer, self.pathToData, self.crs, self.DEM_name, self.isFrameBufferSupported, self.demMax, self.demMin)# self.monoplotter.show() self.monoplotter.qgl_window.updateGL() self.monoplotter.openOrtho.connect(self.openOrthoWidget) self.monoplotter.qgl_window.blow.connect(self.clickOnMonoplotter) self.monoplotter.ui.measureButton.clicked.connect(self.activateMeasurement) self.monoplotter.clearMapTool.connect(self.clearMapTool) self.activeFlackOnMonoplotter() def drawPinkCross(self, pos): if hasattr(self, 'pinkCross'): self.canvas.scene().removeItem(self.pinkCross) if pos[2] == 1: self.pinkCross = QgsVertexMarker(self.canvas) posi = QgsPoint(pos[0],pos[1]) self.pinkCross.setCenter(posi) self.pinkCross.setColor(QColor(255, 122, 255)) self.pinkCross.setIconSize(10) self.pinkCross.setIconType(QgsVertexMarker.ICON_CROSS) self.pinkCross.setPenWidth(10) def clearMapTool(self): #Call when GCP window is closed #Call when the tool "Measure 3D" from monoplotter is activated self.cTool = self.canvas.mapTool() self.canvas.unsetMapTool(self.cTool) if hasattr(self, 'monoplotter'): if hasattr(self.monoplotter.qgl_window, 'lineEditBuffer'): self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() def runGCPMainWindowFromVirtual3D(self): self.virtual3DMainWindow.close() self.ParamPose = self.virtual3DMainWindow.ParamPose self.runGCPMainWindow(True) def runGCPMainWindow(self, fromVirtual3D): # this QGIS tool emits as QgsPoint after each click on the map canvas self.clickTool = QgsMapToolEmitPoint(self.canvas) self.canvas.setMapTool(self.clickTool) # create main window self.gcpMainWindow = GetGCPMainWindow(self.iface, self.buffers, self.picture_name,self.pathToData,self.isFrameBufferSupported, self.crs) # show the Main Window self.gcpMainWindow.show() # load the picture in the central widget self.load_picture(self.picture_name) # get DEM reference layer self.gcpMainWindow.cLayer = self.cLayer # connect events between getGCPmainWindow and Qgis canvas self.gcpMainWindow.ui.tableView.selectionModel().currentRowChanged.connect(self.resetClickTool) self.gcpMainWindow.resetToolSignal.connect(self.resetClickTool) self.gcpMainWindow.setCanvasExtentSignal.connect(self.setCanvasExtent) self.clickTool.canvasClicked.connect(self.newCanvasGCP) self.gcpMainWindow.GoToMonoplotterButton.triggered.connect(self.goToMonoplotter) self.gcpMainWindow.clearMapTool2.connect(self.clearMapTool) if fromVirtual3D: self.gcpMainWindow.pos = self.ParamPose[0] self.gcpMainWindow.lookat = self.ParamPose[1] self.gcpMainWindow.FOV = self.ParamPose[2] self.gcpMainWindow.roll = self.ParamPose[3] def load_dem(self): try: #load dem for info and extent fileName = self.DEM_name fileInfo = QFileInfo(fileName) baseName = fileInfo.baseName() rlayer2 = QgsRasterLayer(fileName, baseName) self.dem_box = rlayer2.extent() provider = rlayer2.dataProvider() stats = provider.bandStatistics(1, QgsRasterBandStats.All,self.dem_box, 0) self.demMin = stats.minimumValue self.demMax = stats.maximumValue # Get coordinate system self.crs = rlayer2.crs() # check if the map units are meter if self.crs.mapUnits() != 0: raise CRSERROR self.iface.addRasterLayer(self.DEM_name) if not rlayer2.isValid(): QMessageBox.warning(QWidget(), "IO - Error", "Raster failed to load") return 0 # DEM is set such that altitude request will be done on it self.cLayer = rlayer2 return 1 except CRSERROR: QMessageBox.warning(QWidget(), "CRS - Error", "DEM must be in projected coordinates, meter units") return 0 def load_picture(self, picName): ##s.setValue( "/Projections/defaultBehaviour", "UseProject" ) fileName = picName fileInfo = QFileInfo(fileName) baseName = fileInfo.baseName() rlayer = QgsRasterLayer(fileName, baseName) resolution = QDesktopWidget().screenGeometry() size = [0,0] size[1] = resolution.height()/2 size[0] = int(float(float(rlayer.width())/float(rlayer.height()))*size[1]) if not rlayer.isValid(): QMessageBox.warning(QWidget(), "IO - Error", "Picture failed to load!") return # Load the image inside the graphicsview self.gcpMainWindow.setImage(fileName, size) # Set the zoom such the picture is almost in full view in the height directon factor = float(self.gcpMainWindow.ui.graphicsView.size().height())/rlayer.height() self.gcpMainWindow.ui.graphicsView.scale(factor, factor) def resetClickTool(self): # This function is used for GCP digitalization. # It resets the click tool for getting altitude on the DEm layer (self.clayer) self.canvas.setMapTool(self.clickTool) QObject.connect(self.clickTool, SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"),self.newCanvasGCP) def newCanvasGCP(self,point): # This function is used for GCP digitalization. # a new GCP is created on canvas self.gcpMainWindow.selectCanvasPoint(point) self.gcpMainWindow.refreshCanvasGCP() def load_buffer(self): # This function is used at initialization. # Arrays are created here for openGL. The normal calculation can take some time (ca. 1sec for 100'000 pixels) self.buffers = Buffers(self.DEM_name, self.dem_box, self.useOrtho, self.ortho_name, self.ortho_box) self.buffers.getBuffer() self.buffers.close() def clickOnMonoplotter(self,customEvent): # This function is called when digitalization or measurement on monoplotter x = customEvent[0] y = customEvent[1] button = customEvent[2] self.monoplotter.qgl_window.notUpdate = False self.cTool = self.canvas.mapTool() # check if a layer is edited if self.cTool != None: currentLayer = self.iface.activeLayer() if currentLayer.type() == 0 and currentLayer.isEditable() and currentLayer.geometryType() < 3: if self.cTool.isEditTool(): if self.iface.actionAddFeature().isEnabled(): u,v = self.WorldToPixelOfCanvasCoordinates(x,y) p = QPoint() p.setX(u) p.setY(v) event = QMouseEvent(QEvent.MouseButtonRelease,p,button,button,Qt.NoModifier) event2 = QgsMapMouseEvent(self.canvas, event)#### self.cTool.canvasReleaseEvent(event2) # check if the edited layer is a point layer if currentLayer.geometryType() == 0: # Since the feature has been added in the layer, it is sufficient to refresh #the monoplotter for displaying the new point self.monoplotter.refreshLayers(boolSymbology = True)#True) # check if the edited layer is a line layer if currentLayer.geometryType() == 1: # a new point is added if the left button is clicked if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() # The line edition ends if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.refreshLayers(boolSymbology = False) if currentLayer.geometryType() == 2: # a new point is added if the left button is clicked if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() # The line edition ends if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.refreshLayers(boolSymbology = False) # check if the measuring tool is being used if self.cTool.action() == self.iface.actionMeasure(): # measurement is done if left button is clicked if button == Qt.LeftButton: #self.cTool.activate() # get the position in canvas coordinates u_previous = self.u v_previous = self.v self.u,self.v = self.WorldToPixelOfCanvasCoordinates(x,y) # create a mouse click at the projected location on canvas # create a line on the monoplotter if u_previous != self.u or v_previous != self.v: p = QPoint() p.setX(self.u) p.setY(self.v) event = QMouseEvent(QEvent.MouseButtonRelease,p,button,button,Qt.NoModifier) event2 = QgsMapMouseEvent(self.canvas, event) self.cTool.canvasReleaseEvent(event2) self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() self.cTool.activate() # update window # the line is cleared if the right button is clicked elif button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() else: if self.monoplotter.isMeasuring3D: if button == Qt.LeftButton: self.monoplotter.qgl_window.lineEditBufferAppend() self.monoplotter.qgl_window.updateGL() self.monoplotter.dlgMeasure3D.addPoint(x,y) if button == Qt.RightButton: self.monoplotter.qgl_window.lineEditBuffer = [] self.monoplotter.qgl_window.updateGL() self.monoplotter.dlgMeasure3D.removePath() def activateMeasurement(self): # This function is used for calling the measuring tool from the monoplotter self.iface.actionMeasure().trigger() self.monoplotter.stopMeasure3D() def disactiveFlackOnMonoplotter(self): self.canvas.mapTool().canvasMoveEvent = None self.canvas.mapTool().deactivate() self.canvas.unsetMapTool(self.canvas.mapTool()) def activeFlackOnMonoplotter(self): self.clickTool2 = QgsMapToolEmitPoint(self.canvas) self.canvas.setMapTool(self.clickTool2) self.canvas.mapTool().canvasMoveEvent = self.test3 self.monoplotter.qgl_window.pinkCrossSignal.connect(self.drawPinkCross) self.monoplotter.closingMonoplot.connect(self.disactiveFlackOnMonoplotter) def test3(self, ev): x,y = self.CanvastoWorldCoordinates(ev.x(), ev.y()) self.monoplotter.preparePurpleCross(x,y) def WorldToPixelOfCanvasCoordinates(self,x,y): # This function is called in "clickOnMonoplotter". # It convert CSR coordinates (world) into the screen coordinates for a given point in the canvas. canvasExtent = self.canvas.extent() canvasBox = [canvasExtent.xMinimum(), canvasExtent.yMinimum(), canvasExtent.xMaximum(), canvasExtent.yMaximum()] UPP = self.canvas.mapUnitsPerPixel() u = int((x-canvasBox[0])/UPP) v = int((canvasBox[3]-y)/UPP) return (u,v) def CanvastoWorldCoordinates(self,u,v): # This function is called in "clickOnMonoplotter". # It convert CSR coordinates (world) into the screen coordinates for a given point in the canvas. canvasExtent = self.canvas.extent() canvasBox = [canvasExtent.xMinimum(), canvasExtent.yMinimum(), canvasExtent.xMaximum(), canvasExtent.yMaximum()] UPP = self.canvas.mapUnitsPerPixel() x = int(u*UPP+canvasBox[0]) y = int(-v*UPP+canvasBox[3]) return (x,y) def setCanvasExtent(self, pos): # This function is used for GCP digitalization. # It zoom on the canvas depending on which GCp is selected. # The zoom extent is set with referenced to the size of the DEM offset = (self.dem_box.xMinimum()-self.dem_box.xMaximum())/50 zoomRectangle = QgsRectangle(pos[0]-offset, pos[1]-offset,pos[0]+offset,pos[1]+offset) self.canvas.setExtent(zoomRectangle) self.canvas.refresh()