class trackGps: def __init__(self, iface): # Save reference to the QGIS interface self.globalpath = os.path.dirname(os.path.abspath(__file__)) self.iface = iface self.guiStarted = False # signal to destructor that this isn't actually been displayed yet self.read = ReadGpsd(self.iface) # create dock widget from ui file print os.path.join(self.globalpath,"DockWidget.ui") self.dock = uic.loadUi(os.path.join(self.globalpath,"DockWidget.ui")) self.canvas = self.iface.mapCanvas() # Default options self.GPSSettings = QSettings() # indication that this is the first time for the plugin self.firstTime = self.GPSSettings.value("trackGpsGPSSettings/firstTime", True, type=bool) # index of marker for GPS position (this is the arrow) self.markerNumber = self.GPSSettings.value("trackGpsGPSSettings/markerNumber", 0, type=int) # default is black for marker fill color self.markerFillColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/markerFillColor", QColor(0,0,0))) # default is yellow for marker outline color self.markerOutlineColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/markerOutlineColor", QColor(255,255,0))) # width of tracking line self.trackLineWidth = self.GPSSettings.value("trackGpsGPSSettings/trackLineWidth", 3, type=int) # color of tracking line (default is red) self.lineColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/lineColor", QColor(255,0,0))) self.saveInSHAPEFile = self.GPSSettings.value("trackGpsGPSSettings/saveInSHAPEFile", False, type=bool) # now recover/set the values for the serial port connection self.searchAllConnectionsSpeeds = self.GPSSettings.value("trackGpsGPSSettings/searchAllConnectionsSpeeds", True, type=bool) self.serialPortNumber = self.GPSSettings.value("trackGpsGPSSettings/serialPortNumber", 0, type=int) self.serialPortSpeed = self.GPSSettings.value("trackGpsGPSSettings/serialPortSpeed", 0, type=int) # set GPS connection values if they were recovered from a previous session if not self.searchAllConnectionsSpeeds: self.read.setConnectionValues(self.serialPortNumber, self.serialPortSpeed) # initialize the graphic elements for the GPS position self.positionMarker = PositionMarker(self.canvas, self.markerNumber, self.markerFillColor, self.markerOutlineColor) self.rubberBand = QgsRubberBand(self.canvas) self.rubberBand.setColor(self.lineColor) self.rubberBand.setWidth(self.trackLineWidth) self.rubberBandS = [] self.GPSPositions = [] # array of positions in current track self.GPSTracks = [] # array of all tracks def __del__(self): if self.guiStarted: # time to save plugin options as settings GPSSettings = QSettings() # indication that this is the first time for the plugin GPSSettings.setValue("trackGpsGPSSettings/firstTime", self.firstTime) GPSSettings.setValue("trackGpsGPSSettings/searchAllConnectionsSpeeds", bool(self.searchAllConnectionsSpeeds)) GPSSettings.setValue("trackGpsGPSSettings/markerNumber", self.markerNumber) GPSSettings.setValue("trackGpsGPSSettings/markerFillColor", self.markerFillColor) GPSSettings.setValue("trackGpsGPSSettings/markerOutlineColor", self.markerOutlineColor) GPSSettings.setValue("trackGpsGPSSettings/trackLineWidth", self.trackLineWidth) GPSSettings.setValue("trackGpsGPSSettings/lineColor", self.lineColor) GPSSettings.setValue("trackGpsGPSSettings/saveInSHAPEFile", self.saveInSHAPEFile) GPSSettings.setValue("trackGpsGPSSettings/serialPortNumber", self.serialPortNumber) GPSSettings.setValue("trackGpsGPSSettings/serialPortSpeed", self.serialPortSpeed) GPSSettings.synch() QMessageBox.information(self.iface.mainWindow(),"Class trackGPS Ending","trackGPS is being destroyed!") def initGui(self): self.guiStarted = True # signal that the GPS dialog was displayed if self.firstTime: self.firstTime = False QMessageBox.information(self.iface.mainWindow(),"Track GPS location","Since this is the first time"+\ " that you have used the 'Track GPS location' plugin please consult the help "+\ "in the plugin menu") # Create actions for plugin self.actionStart = QAction(QIcon(":/plugins/trackgps/Satellite-22.png"), "Start GPS Tracking", self.iface.mainWindow()) self.actionStart.setWhatsThis("Open GPS Connection and Start Tracking") self.actionStop = QAction(QIcon(":/plugins/trackgps/Satellite-22.png"), "Stop GPS Tracking", self.iface.mainWindow()) self.actionStop.setWhatsThis("Close the GPS Connection and Stop Tracking") self.actionOptions = QAction(QIcon(":/plugins/trackgps/options.png"),"Set GPS Tracking Options", self.iface.mainWindow()) self.actionOptions.setWhatsThis("Set the various GPS Connection/Tracking Options") # add help menu item self.helpAction = QAction(QIcon(":/plugins/trackgps/images/help-browser.png"), "GPS Tracking Help", self.iface.mainWindow()) # New Track actions set up here self.dock.btnStartNewTrack.setDisabled(True) # Starting New Tracks is disabled at start QObject.connect(self.dock.btnStartNewTrack, SIGNAL("clicked()"), self.startNewTrack) # Connect the actions to its methods QObject.connect(self.actionStart, SIGNAL("activated()"), self.toogleGather) QObject.connect(self.actionStop, SIGNAL("activated()"), self.toogleGather) QObject.connect(self.actionOptions, SIGNAL("activated()"), self.showGPSMenuOptions) QObject.connect(self.dock.btnStart, SIGNAL("clicked()"), self.toogleGather) QObject.connect(self.read, SIGNAL("readCoords(PyQt_PyObject)"), self.setCoords) QObject.connect(self.read, SIGNAL("connectionFailed(PyQt_PyObject)"), self.connectionFailed) QObject.connect(self.read, SIGNAL("connectionMade()"), self.connectionMade) QObject.connect(self.helpAction, SIGNAL("activated()"), self.helpWindow) # Add menu items for action self.iface.addPluginToMenu("beeGPS", self.actionOptions) self.iface.addPluginToMenu("beeGPS", self.actionStart) self.iface.addPluginToMenu("beeGPS", self.helpAction) myPluginMenu = self.iface.pluginMenu() QObject.connect(myPluginMenu, SIGNAL("aboutToShow()"), self.updateTrackGPSMenu) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock) def helpWindow(self): window = HelpForm("TheQGISGPSTrackerPlugin.html",self.iface.mainWindow()) window.show() def updateTrackGPSMenu(self): if self.read.running: self.iface.addPluginToMenu("beeGPS", self.actionStop) self.iface.removePluginMenu("beeGPS", self.actionStart) else: self.iface.addPluginToMenu("beeGPS", self.actionStart) self.iface.removePluginMenu("beeGPS", self.actionStop) def startNewTrack(self): self.read.stop() # close serial port self.rubberBandS.append(self.rubberBand) self.showGPSMenuOptions() # give user opportunity to change display options #if len(self.GPSPositions) > 0: # temporary section to display positional information # QMessageBox.information(self.iface.mainWindow(),"trackGPS","There are: " + str(len(self.GPSPositions)) + " GPS Positions in the current track") # for i in range(len(self.GPSPositions)): # QMessageBox.information(self.iface.mainWindow(),"trackGPS","Position #" + str(i) + ": Latitude=" + str(self.GPSPositions[i].latitude)) self.rubberBand=QgsRubberBand(self.canvas) # start new rubber band if len(self.GPSPositions) > 0 and self.saveInSHAPEFile: self.GPSTracks.append(self.GPSPositions) # save GPSPositions to GPSTracks self.GPSPositions = [] #reset of array contenent the current position self.startGather() # open serial port and record new track def unload(self): # Remove the plugin menu item self.iface.removePluginMenu("beeGPS", self.actionStart) self.iface.removePluginMenu("beeGPS", self.actionStop) self.iface.removePluginMenu("beeGPS", self.actionOptions) def startGather(self): #update all of the GPS display options self.positionMarker.markerNumber = self.markerNumber self.positionMarker.fillColor = self.markerFillColor self.positionMarker.outlineColor = self.markerOutlineColor self.rubberBand.setColor(self.lineColor) self.rubberBand.setWidth(self.trackLineWidth) self.positionMarker.show() # get destination crs of the canvas dest_crs = self.canvas.mapRenderer().destinationCrs() #print "destination crs:",dest_crs.description() # create transform object from WGS84 (GPS) to canvas CRS self.transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(self.read.session.datumEPSG,\ QgsCoordinateReferenceSystem.EpsgCrsId ),dest_crs) self.read.start() self.read.exec_() def setCoords(self, aGPSPosition): boolDistance = True boolTime = True #Controllo se è la prima acquisizione valutando la dimensione di GPSPosition[] a 0, in caso positivo acquisisco. if len(self.GPSPositions) == 0: self.GPSPositions.append(aGPSPosition) else: #Metodo tresholdAcquisition() per l'acquisizione dei punti "live" in base alla soglia di distanza che ritorna #TRUE in caso la soglia sia stata superata, altrimenti FALSE boolDistance = self.tresholdAcquisition(aGPSPosition) #Controllo che tresholdAcquisition() abbia ritornato TRUE altrimenti passo al punto successivo if boolDistance == False: return #Metodo timeIntervals() per l'acquisizione dei punti "live" in base alla soglia di tempo che ritorna TRUE in caso #la soglia sia stata superata e acquisita, altrimenti FALSE boolTime = self.timeIntervals(aGPSPosition) #Controllo che timeIntervals() abbia ritornato TRUE altrimenti passo al punto successivo if boolTime == False: return else: self.GPSPositions.append(aGPSPosition) # display raw values self.dock.date.setText(aGPSPosition.theDateTime) self.dock.lat.setText(str(aGPSPosition.latitude) + ' ' + aGPSPosition.latitudeNS) self.dock.lon.setText(str(aGPSPosition.longitude) + ' ' + aGPSPosition.longitudeEW) self.dock.lineBearing.setText("%5.1i"%aGPSPosition.bearing) self.dock.lineSpeed.setText("%5.1i"%aGPSPosition.speed) self.dock.lineHDOP.setText(str(aGPSPosition.hdop)) if aGPSPosition.fixQuality == 0: self.dock.lineQuality.setText("Fix not available") elif aGPSPosition.fixQuality == 1: self.dock.lineQuality.setText("GPS fix") else: self.dock.lineQuality.setText("Differential GPS fix") # display arrow on the map latitude = aGPSPosition.latitude if aGPSPosition.latitudeNS == 'N' else aGPSPosition.latitude * -1.0 longitude = aGPSPosition.longitude if aGPSPosition.longitudeEW == 'E' else aGPSPosition.longitude * -1.0 p=self.transform.transform(QgsPoint(longitude, latitude)) self.rubberBand.addPoint(p) self.positionMarker.setHasPosition(True) self.positionMarker.newCoords(p,aGPSPosition.bearing) doRefresh = False if doRefresh: # move map to keep marker at center curext = self.canvas.extent() p1 = QgsPoint(p.x() - curext.width()/2, p.y() - curext.height()/2) p2 = QgsPoint(p.x() + curext.width()/2, p.y() + curext.height()/2) self.canvas.setExtent(QgsRectangle (p1,p2)) self.canvas.refresh() def stopGather(self): self.read.stop() self.positionMarker.hide() if len(self.GPSPositions) > 0: # and self.saveInSHAPEFile: self.GPSTracks.append(self.GPSPositions) # save GPSPositions to GPSTracks # if len(self.GPSTracks) > 0 and self.saveInSHAPEFile: if self.saveInSHAPEFile: # this is temporary # option to save SHAPE file is on, prompt for filename and write the tracks to the file self.makeShapeFiles() if len(self.GPSTracks) > 0: answer = QMessageBox.question(self.iface.mainWindow(),"Erase Tracks?","Erase the currently displayed tracks?",\ QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if answer == QMessageBox.Yes: for band in self.rubberBandS: band.reset() self.rubberBand.reset() self.canvas.refresh() self.rubberBandS = [] self.GPSPositions = [] self.GPSTracks = [] def toogleGather(self): if self.read.running: QMessageBox.information(self.iface.mainWindow(),"GPS Tracker","Stopping GPS Tracking",QMessageBox.Ok) self.stopGather() self.dock.btnStart.setText("Start") self.dock.gpsInformation.setText("Gets GPS Receiver Information") self.dock.btnStartNewTrack.setDisabled(True) else: self.dock.btnStart.setText("Connecting, please be patient....") self.startGather() if self.read.session.connected: self.dock.btnStart.setText("Stop") def connectionMade(self): # QMessageBox.information(self.iface.mainWindow(),"trackGps","GPS Receiver Connected on port: %s at %i baud\n"%\ # (self.read.session.portName,self.read.session.baudRate),QMessageBox.Ok,0) self.dock.gpsInformation.setText("GPS Connected on port: %s at %i baud"%(self.read.session.portName,\ self.read.session.baudRate)) self.dock.btnStart.setText("Stop") self.dock.btnStartNewTrack.setDisabled(False) # save connection values in session parameters self.serialPortNumber = self.read.session.port self.serialPortSpeed = self.read.session.baudRates.index(self.read.session.baudRate) self.searchAllConnectionsSpeeds = False def connectionFailed(self, msg): QMessageBox.warning(self.iface.mainWindow(),"beeGPS", "Connection to GPSConnection failed\n%s"%(msg),QMessageBox.Ok,0) if self.read.session.connected: self.read.stop() self.dock.btnStart.setText("Start") self.dock.btnStartNewTrack.setDisabled(True) # Starting New Tracks is disabled at start def showGPSMenuOptions(self): myGPSOptionsDlg = GPSTrackerOptions(self) isOK = myGPSOptionsDlg.exec_() if isOK: if myGPSOptionsDlg.cbxMarkerType.currentIndex() != self.markerNumber: self.markerNumber = myGPSOptionsDlg.cbxMarkerType.currentIndex() if myGPSOptionsDlg.lineColor != self.lineColor: self.lineColor = myGPSOptionsDlg.lineColor if myGPSOptionsDlg.markerFillColor != self.markerFillColor: self.markerFillColor = myGPSOptionsDlg.markerFillColor if myGPSOptionsDlg.markerOutlineColor != self.markerOutlineColor: self.markerOutlineColor = myGPSOptionsDlg.markerOutlineColor if myGPSOptionsDlg.sbxTrackWidth.value() != self.trackLineWidth: self.trackLineWidth = myGPSOptionsDlg.sbxTrackWidth.value() if myGPSOptionsDlg.cbxSaveGPSTrack.isChecked() != self.saveInSHAPEFile: self.saveInSHAPEFile = myGPSOptionsDlg.cbxSaveGPSTrack.isChecked() def makeShapeFiles(self): myFileName = QgsProject.instance().fileName() myFileName = str(myFileName) # if this is a windows OS then the filename needs to have '/' converted to '\' if myFileName.find('windows') != 0 or myFileName.find('Windows') != 0: myFileName = os.path.normpath(myFileName) myFilePath = os.path.dirname(myFileName) myShapeFileNamesDlg = ShapeFileNames(myFilePath) isOK = myShapeFileNamesDlg.exec_() CRS = QgsCoordinateReferenceSystem() crsIsOk = CRS.createFromOgcWmsCrs("EPSG:%d" % self.GPSTracks[0][0].datumEPSG) if not crsIsOk: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating CRS from"+\ " EPSG ID:" + str(self.GPSTracks[0][0].datumEPSG)) if isOK and crsIsOk: if len(myShapeFileNamesDlg.lnePointsFileName.text()) > 0: # set up the fields for the Points SHAPE file box = QgsFields() box.append(QgsField("LATITUDE", QVariant.Double , "Real", 9, 6)) box.append(QgsField("LONGITUDE", QVariant.Double, "Real", 10, 6)) box.append(QgsField("NUMOFSATS", QVariant.Int, "Integer", 2, 0)) box.append(QgsField("HDOP", QVariant.Double, "Real", 4, 2)) box.append(QgsField("DATETIME", QVariant.String, "String", 19, 0)) box.append(QgsField("FIXTYPE", QVariant.String, "String", 1, 0)) box.append(QgsField("BEARING", QVariant.Double, "Real", 6, 2)) box.append(QgsField("SPEED-KPH", QVariant.Double, "Real", 5, 1)) box.append(QgsField("TRACKNUM", QVariant.Int, "Integer", 2, 0)) # set up the CRS # open the points SHAPE file pointsFile, fileOK = self.createSHAPEfile(myShapeFileNamesDlg.lnePointsFileName.text(),box,QGis.WKBPoint,CRS) if fileOK: for j in range(len(self.GPSTracks)): for i in range(len(self.GPSTracks[j])): theFeature = QgsFeature() latitude = self.GPSTracks[j][i].latitude if self.GPSTracks[j][i].latitudeNS == 'S': latitude = -latitude longitude = self.GPSTracks[j][i].longitude if self.GPSTracks[j][i].longitudeEW == 'W': longitude = -longitude theFeature.setGeometry(QgsGeometry.fromPoint(QgsPoint(longitude,latitude))) theFeature.setAttributes([0, latitude]) theFeature.setAttributes([1, longitude]) theFeature.setAttributes([2, self.GPSTracks[j][i].numSatellites]) theFeature.setAttributes([3, self.GPSTracks[j][i].hdop]) theFeature.setAttributes([4, self.GPSTracks[j][i].theDateTime]) theFeature.setAttributes([5, self.GPSTracks[j][i].fixQuality]) theFeature.setAttributes([6, self.GPSTracks[j][i].bearing]) theFeature.setAttributes([7, self.GPSTracks[j][i].speed]) theFeature.setAttributes([8, j+1]) pointsFile.addFeature(theFeature) del pointsFile # del file object to force a flush and close if len(myShapeFileNamesDlg.lneLinesFileName.text()) > 0: # set up the fields for the Lines SHAPE file lines_box = QgsFields() lines_box.append(QgsField("SDATETIME", QVariant.String, "String", 19, 0)) lines_box.append(QgsField("EDATETIME", QVariant.String, "String", 19, 0)) lines_box.append(QgsField("TRACKNUM", QVariant.Int, "Integer", 2, 0)) linesFile, fileOK = self.createSHAPEfile(myShapeFileNamesDlg.lneLinesFileName.text(),lines_box,QGis.WKBLineString,CRS) if fileOK: for j in range(len(self.GPSTracks)): theFeature = QgsFeature() pointsList = [] for i in range(len(self.GPSTracks[j])): latitude = self.GPSTracks[j][i].latitude if self.GPSTracks[j][i].latitudeNS == 'S': latitude = -latitude longitude = self.GPSTracks[j][i].longitude if self.GPSTracks[j][i].longitudeEW == 'W': longitude = -longitude pointsList.append(QgsPoint(longitude,latitude)) theFeature.setGeometry(QgsGeometry.fromPolyline(pointsList)) theFeature.setAttributes([0, self.GPSTracks[j][0].theDateTime]) theFeature.setAttributes([1, self.GPSTracks[j][len(self.GPSTracks[j])-1].theDateTime]) theFeature.setAttributes([2, j+1]) linesFile.addFeature(theFeature) del linesFile # del file object to force a flush and close def createSHAPEfile(self,fileName, fileFields, fileType, crs): ''' this function creates a new, empty shape file for use in writing points or lines Returns: SHAPEfile, status if status == True then SHAPEfile is OK to use, if False then an error occured and cannot use SHAPEFile Input Parameters: fileName = full name of the SHAPE file to be created fileFields = map of QgsFields to use for the attributes of the SHAPE file fileType = QGis.WKBPoint for points file <or> QGis.WKBLine for lines file crs = the QgsCoordinateReferenceSystem to use for the file ''' status = True # default is no error SHAPEfile = QgsVectorFileWriter(fileName,"CP1250",fileFields,fileType,crs) typeName = 'Points' if fileType == QGis.WKBPoint else 'Lines' if SHAPEfile.hasError() != QgsVectorFileWriter.NoError: status = False # report an error if SHAPEfile.hasError() == QgsVectorFileWriter.ErrDriverNotFound: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrDriverNotFound\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrCreateDataSource: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrCreateDataSource\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrCreateLayer: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrCreateLayer\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrAttributeTypeUnsupported: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrAttributeTypeUnsupported\' - saving " + typeName + " is aborted") else: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'UNKOWN ERROR\' saving " + typeName + " is aborted") return SHAPEfile,status #Metodo per l'acquisizione tramite soglia di distanza def tresholdAcquisition(self, aGPSPosition): #Costanti per il calcolo della distanza R_Terra = 6372.795477598 acquisito = False #Acquisisco la soglia di distanza, da input e la converto in float soglia = self.dock.lineTreshold.text() if not soglia.isnumeric(): self.read.stop() self.positionMarker.hide() self.dock.btnStart.setText("Start") self.dock.gpsInformation.setText("Gets GPS Receiver Information") QMessageBox.warning(self.iface.mainWindow(),"ATENZIONE","Inserire solo valori numerici nella soglia di distanza.") else: soglia = float(soglia) soglia = soglia / 1000 #Conversione dei gradi in radianti lat_alfa = math.radians(aGPSPosition.latitude) lat_beta = math.radians(self.GPSPositions[-1].latitude) lon_alfa = math.radians(aGPSPosition.longitude) lon_beta = math.radians(self.GPSPositions[-1].longitude) #Calcolo la differenza di lat e lon dLat = lat_alfa - lat_beta dLon = lon_alfa - lon_beta a = math.sin(dLat/2)*math.sin(dLat/2)+math.sin(dLon/2)*math.sin(dLon/2)* math.cos(lat_alfa) * math.cos(lat_beta) #Calcolo il terzo lato del triangolo sferico c = 2*math.atan2(math.sqrt(a),math.sqrt(1-a)) distanza = c * R_Terra #Controllo con la soglia di distanza e eventualmente acquisisco if distanza > soglia: acquisito = True return acquisito #Metodo timeIntervals() per il controllo della soglia temporale def timeIntervals(self, aGPSPosition): #Variabile booleana di ritorno acquisito = False #Stringa per il formato della data formato = '%Y-%m-%d %H:%M:%S' #Metto le due date, quella dell'ultima acquisizione e quella da valutare in due stringhe dataA = aGPSPosition.theDateTime dataB = self.GPSPositions[-1].theDateTime #Tramite il metodo time.strptime() realizziamo due strutte tempo per le due date struct_A = time.strptime(dataA,formato) struct_B = time.strptime(dataB,formato) #Otteniamo i valori di confronto confrontoA = datetime.datetime.fromtimestamp(time.mktime(struct_A)) confrontoB = datetime.datetime.fromtimestamp(time.mktime(struct_B)) #Otteniamo la differenza differenza = (confrontoA - confrontoB).seconds #Acquisisco la soglia di distanza temporale e gestisco eventualmente l'inserimento di valori non numerici intervalli = self.dock.lineTimeIntervals.text() if not intervalli.isnumeric(): self.read.stop() self.positionMarker.hide() self.dock.btnStart.setText("Start") self.dock.gpsInformation.setText("Gets GPS Receiver Information") QMessageBox.warning(self.iface.mainWindow(),"ATENZIONE","Inserire solo valori numerici nella soglia temporale.") else: intervalli = float(intervalli) #Controllo se la differenza e maggiore della soglia if differenza > intervalli: acquisito = True return acquisito
class trackGps: def __init__(self, iface): # Save reference to the QGIS interface self.globalpath = os.path.dirname(os.path.abspath(__file__)) self.iface = iface self.guiStarted = False # signal to destructor that this isn't actually been displayed yet self.read = ReadGpsd(self.iface) # create dock widget from ui file print os.path.join(self.globalpath,"DockWidget.ui") self.dock = uic.loadUi(os.path.join(self.globalpath,"DockWidget.ui")) self.canvas = self.iface.mapCanvas() # Default options self.GPSSettings = QSettings() # indication that this is the first time for the plugin self.firstTime = self.GPSSettings.value("trackGpsGPSSettings/firstTime",QVariant(bool(True))).toBool() # index of marker for GPS position (this is the arrow) self.markerNumber, isOK = self.GPSSettings.value("trackGpsGPSSettings/markerNumber",QVariant(int(0))).toInt() # default is black for marker fill color self.markerFillColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/markerFillColor",QVariant(QColor(0,0,0)))) # default is yellow for marker outline color self.markerOutlineColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/markerOutlineColor",QVariant(QColor(255,255,0)))) # width of tracking line self.trackLineWidth, isOK = self.GPSSettings.value("trackGpsGPSSettings/trackLineWidth",QVariant(int(3))).toInt() # color of tracking line (default is red) self.lineColor = QColor(self.GPSSettings.value("trackGpsGPSSettings/lineColor",QVariant(QColor(255,0,0)))) self.saveInSHAPEFile = self.GPSSettings.value("trackGpsGPSSettings/saveInSHAPEFile",QVariant(bool(False))).toBool() # now recover/set the values for the serial port connection self.searchAllConnectionsSpeeds = self.GPSSettings.value("trackGpsGPSSettings/searchAllConnectionsSpeeds", QVariant(bool(True))).toBool() self.serialPortNumber, isOK = self.GPSSettings.value("trackGpsGPSSettings/serialPortNumber",QVariant(int(0))).toInt() self.serialPortSpeed, isOK = self.GPSSettings.value("trackGpsGPSSettings/serialPortSpeed",QVariant(int(0))).toInt() # set GPS connection values if they were recovered from a previous session if not self.searchAllConnectionsSpeeds: self.read.setConnectionValues(self.serialPortNumber,self.serialPortSpeed) # initialize the graphic elements for the GPS position self.positionMarker=PositionMarker(self.canvas, self.markerNumber, self.markerFillColor, self.markerOutlineColor) self.rubberBand=QgsRubberBand(self.canvas) self.rubberBand.setColor(self.lineColor) self.rubberBand.setWidth(self.trackLineWidth) self.rubberBandS = [] self.GPSPositions = [] # array of positions in current track self.GPSTracks = [] # array of all tracks def __del__(self): """This method is used to save the settings for use the next time this plugin is used""" if self.guiStarted: # time to save plugin options as settings GPSSettings = QSettings() # indication that this is the first time for the plugin GPSSettings.setValue("trackGpsGPSSettings/firstTime",QVariant(self.firstTime)) GPSSettings.setValue("trackGpsGPSSettings/searchAllConnectionsSpeeds", QVariant(bool(self.searchAllConnectionsSpeeds))) GPSSettings.setValue("trackGpsGPSSettings/markerNumber",QVariant(self.markerNumber)) GPSSettings.setValue("trackGpsGPSSettings/markerFillColor",QVariant(self.markerFillColor)) GPSSettings.setValue("trackGpsGPSSettings/markerOutlineColor",QVariant(self.markerOutlineColor)) GPSSettings.setValue("trackGpsGPSSettings/trackLineWidth",QVariant(self.trackLineWidth)) GPSSettings.setValue("trackGpsGPSSettings/lineColor",QVariant(self.lineColor)) GPSSettings.setValue("trackGpsGPSSettings/saveInSHAPEFile",QVariant(self.saveInSHAPEFile)) GPSSettings.setValue("trackGpsGPSSettings/serialPortNumber",QVariant(self.serialPortNumber)) GPSSettings.setValue("trackGpsGPSSettings/serialPortSpeed",QVariant(self.serialPortSpeed)) GPSSettings.synch() QMessageBox.information(self.iface.mainWindow(),"Class trackGPS Ending","trackGPS is being destroyed!") def initGui(self): self.guiStarted = True # signal that the GPS dialog was displayed if self.firstTime: self.firstTime = False QMessageBox.information(self.iface.mainWindow(),"Track GPS location","Since this is the first time"+\ " that you have used the 'Track GPS location' plugin please consult the help "+\ "in the plugin menu") # Create actions for plugin self.actionStart = QAction(QIcon(":/plugins/trackgps/Satellite-22.png"), "Start GPS Tracking", self.iface.mainWindow()) self.actionStart.setWhatsThis("Open GPS Connection and Start Tracking") self.actionStop = QAction(QIcon(":/plugins/trackgps/Satellite-22.png"), "Stop GPS Tracking", self.iface.mainWindow()) self.actionStop.setWhatsThis("Close the GPS Connection and Stop Tracking") self.actionOptions = QAction(QIcon(":/plugins/trackgps/options.png"),"Set GPS Tracking Options", self.iface.mainWindow()) self.actionOptions.setWhatsThis("Set the various GPS Connection/Tracking Options") # add help menu item self.helpAction = QAction(QIcon(":/plugins/trackgps/images/help-browser.png"), "GPS Tracking Help", self.iface.mainWindow()) # New Track actions set up here self.dock.btnStartNewTrack.setDisabled(True) # Starting New Tracks is disabled at start QObject.connect(self.dock.btnStartNewTrack, SIGNAL("clicked()"), self.startNewTrack) # Connect the actions to its methods QObject.connect(self.actionStart, SIGNAL("activated()"), self.toogleGather) QObject.connect(self.actionStop, SIGNAL("activated()"), self.toogleGather) QObject.connect(self.actionOptions, SIGNAL("activated()"), self.showGPSMenuOptions) QObject.connect(self.dock.btnStart, SIGNAL("clicked()"), self.toogleGather) QObject.connect(self.read, SIGNAL("readCoords(PyQt_PyObject)"), self.setCoords) QObject.connect(self.read, SIGNAL("connectionFailed(PyQt_PyObject)"), self.connectionFailed) QObject.connect(self.read, SIGNAL("connectionMade()"), self.connectionMade) QObject.connect(self.helpAction, SIGNAL("activated()"), self.helpWindow) # Add menu items for action self.iface.addPluginToMenu("Track GPS location", self.actionOptions) self.iface.addPluginToMenu("Track GPS location", self.actionStart) self.iface.addPluginToMenu("Track GPS location", self.helpAction) myPluginMenu = self.iface.pluginMenu() QObject.connect(myPluginMenu, SIGNAL("aboutToShow()"), self.updateTrackGPSMenu) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock) def helpWindow(self): window = HelpForm("TheQGISGPSTrackerPlugin.html",self.iface.mainWindow()) window.show() def updateTrackGPSMenu(self): if self.read.running: self.iface.addPluginToMenu("Track GPS location", self.actionStop) self.iface.removePluginMenu("Track GPS location", self.actionStart) else: self.iface.addPluginToMenu("Track GPS location", self.actionStart) self.iface.removePluginMenu("Track GPS location", self.actionStop) def startNewTrack(self): self.read.stop() # close serial port self.rubberBandS.append(self.rubberBand) self.showGPSMenuOptions() # give user opportunity to change display options #if len(self.GPSPositions) > 0: # temporary section to display positional information # QMessageBox.information(self.iface.mainWindow(),"trackGPS","There are: " + str(len(self.GPSPositions)) + " GPS Positions in the current track") # for i in range(len(self.GPSPositions)): # QMessageBox.information(self.iface.mainWindow(),"trackGPS","Position #" + str(i) + ": Latitude=" + str(self.GPSPositions[i].latitude)) self.rubberBand=QgsRubberBand(self.canvas) # start new rubber band if len(self.GPSPositions) > 0 and self.saveInSHAPEFile: self.GPSTracks.append(self.GPSPositions) # save GPSPositions to GPSTracks self.GPSPositions = [] self.startGather() # open serial port and record new track def unload(self): # Remove the plugin menu item self.iface.removePluginMenu("Track GPS location", self.actionStart) self.iface.removePluginMenu("Track GPS location", self.actionStop) self.iface.removePluginMenu("Track GPS location", self.actionOptions) def startGather(self): #update all of the GPS display options self.positionMarker.markerNumber = self.markerNumber self.positionMarker.fillColor = self.markerFillColor self.positionMarker.outlineColor = self.markerOutlineColor self.rubberBand.setColor(self.lineColor) self.rubberBand.setWidth(self.trackLineWidth) self.positionMarker.show() # get destination crs of the canvas dest_crs = self.canvas.mapRenderer().destinationSrs() print "destination crs:",dest_crs.description() # create transform object from WGS84 (GPS) to canvas CRS self.transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(self.read.session.datumEPSG,\ QgsCoordinateReferenceSystem.EpsgCrsId ),dest_crs) self.read.start() self.read.exec_() def setCoords (self,aGPSPosition): """SLOT: show read coordinates""" # display raw values self.GPSPositions.append(aGPSPosition) self.dock.date.setText(aGPSPosition.theDateTime) self.dock.lat.setText(str(aGPSPosition.latitude) + ' ' + aGPSPosition.latitudeNS) self.dock.lon.setText(str(aGPSPosition.longitude) + ' ' + aGPSPosition.longitudeEW) self.dock.lineBearing.setText("%5.1i"%aGPSPosition.bearing) self.dock.lineSpeed.setText("%5.1i"%aGPSPosition.speed) # display arrow on the map latitude = aGPSPosition.latitude if aGPSPosition.latitudeNS == 'N' else aGPSPosition.latitude * -1.0 longitude = aGPSPosition.longitude if aGPSPosition.longitudeEW == 'E' else aGPSPosition.longitude * -1.0 p=self.transform.transform(QgsPoint(longitude, latitude)) self.rubberBand.addPoint(p) self.positionMarker.setHasPosition(True) self.positionMarker.newCoords(p,aGPSPosition.bearing) # move map to keep marker at center curext = self.canvas.extent() p1 = QgsPoint(p.x()-curext.width()/2,p.y()-curext.height()/2) p2 = QgsPoint(p.x()+curext.width()/2,p.y()+curext.height()/2) self.canvas.setExtent(QgsRectangle (p1,p2)) self.canvas.refresh() def stopGather(self): self.read.stop() self.positionMarker.hide() if len(self.GPSPositions) > 0: # and self.saveInSHAPEFile: self.GPSTracks.append(self.GPSPositions) # save GPSPositions to GPSTracks # if len(self.GPSTracks) > 0 and self.saveInSHAPEFile: if self.saveInSHAPEFile: # this is temporary # option to save SHAPE file is on, prompt for filename and write the tracks to the file # QMessageBox.information(self.iface.mainWindow(),"trackGPS","There are: " + str(len(self.GPSTracks)) + " GPS tracks in the current track") # for j in range(len(self.GPSTracks)): # QMessageBox.information(self.iface.mainWindow(),"trackGPS","In track #" + str(j) + " There are: " + str(len(self.GPSTracks[j])) + " GPS Positions") # for i in range(len(self.GPSTracks[j])): # QMessageBox.information(self.iface.mainWindow(),"trackGPS","Position #" + str(i) + ": Latitude=" + str(self.GPSTracks[j][i].latitude)) self.makeShapeFiles() if len(self.GPSTracks) > 0: answer = QMessageBox.question(self.iface.mainWindow(),"Erase Tracks?","Erase the currently displayed tracks?",\ QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if answer == QMessageBox.Yes: for band in self.rubberBandS: band.reset() self.rubberBand.reset() self.canvas.refresh() self.rubberBandS = [] self.GPSPositions = [] self.GPSTracks = [] def toogleGather(self): if self.read.running: QMessageBox.information(self.iface.mainWindow(),"GPS Tracker","Stopping GPS Tracking",QMessageBox.Ok) self.stopGather() self.dock.btnStart.setText("Start") self.dock.gpsInformation.setText("Gets GPS Receiver Information") self.dock.btnStartNewTrack.setDisabled(True) else: self.dock.btnStart.setText("Connecting, please be patient....") self.startGather() if self.read.session.connected: self.dock.btnStart.setText("Stop") def connectionMade(self): # QMessageBox.information(self.iface.mainWindow(),"trackGps","GPS Receiver Connected on port: %s at %i baud\n"%\ # (self.read.session.portName,self.read.session.baudRate),QMessageBox.Ok,0) self.dock.gpsInformation.setText("GPS Connected on port: %s at %i baud"%(self.read.session.portName,\ self.read.session.baudRate)) self.dock.btnStart.setText("Stop") self.dock.btnStartNewTrack.setDisabled(False) # save connection values in session parameters self.serialPortNumber = self.read.session.port self.serialPortSpeed = self.read.session.baudRates.index(self.read.session.baudRate) self.searchAllConnectionsSpeeds = False def connectionFailed(self,msg): QMessageBox.warning(self.iface.mainWindow(),"trackGps","Connection to GPSConnection failed\n%s"%(msg),QMessageBox.Ok,0) if self.read.session.connected: self.read.stop() self.dock.btnStart.setText("Start") self.dock.btnStartNewTrack.setDisabled(True) # Starting New Tracks is disabled at start def showGPSMenuOptions(self): """ Function to handle all GPS Tracking Options """ # myGPSOptionsDlg = GPSTrackerOptions(self) isOK = myGPSOptionsDlg.exec_() if isOK: if myGPSOptionsDlg.cbxMarkerType.currentIndex() != self.markerNumber: self.markerNumber = \ myGPSOptionsDlg.cbxMarkerType.currentIndex() if myGPSOptionsDlg.lineColor != self.lineColor: self.lineColor = myGPSOptionsDlg.lineColor if myGPSOptionsDlg.markerFillColor != self.markerFillColor: self.markerFillColor = \ myGPSOptionsDlg.markerFillColor if myGPSOptionsDlg.markerOutlineColor != self.markerOutlineColor: self.markerOutlineColor = \ myGPSOptionsDlg.markerOutlineColor if myGPSOptionsDlg.sbxTrackWidth.value() != self.trackLineWidth: self.trackLineWidth = \ myGPSOptionsDlg.sbxTrackWidth.value() if myGPSOptionsDlg.cbxSaveGPSTrack.isChecked() != self.saveInSHAPEFile: self.saveInSHAPEFile =\ myGPSOptionsDlg.cbxSaveGPSTrack.isChecked() def makeShapeFiles(self): """ Function to save data to SHAPE files """ myFileName = QgsProject.instance().fileName() myFileName = str(myFileName) # if this is a windows OS then the filename needs to have '/' converted to '\' if myFileName.find('windows') != 0 or myFileName.find('Windows') != 0: myFileName = os.path.normpath(myFileName) myFilePath = os.path.dirname(myFileName) #mymessage = 'QGIS Project Pathname=\'' + myFilePath + '\'' #QMessageBox.information(self.iface.mainWindow(),"trackGps",mymessage,QMessageBox.Ok) myShapeFileNamesDlg = ShapeFileNames(myFilePath) isOK = myShapeFileNamesDlg.exec_() CRS = QgsCoordinateReferenceSystem() crsIsOk = CRS.createFromEpsg(self.GPSTracks[0][0].datumEPSG) if not crsIsOk: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating CRS from"+\ " EPSG ID:" + str(self.GPSTracks[0][0].datumEPSG)) if isOK and crsIsOk: if len(myShapeFileNamesDlg.lnePointsFileName.text()) > 0: # set up the fields for the Points SHAPE file latf = QgsField ("LATITUDE", QVariant.Double, "Real", 9, 6) lonf = QgsField ("LONGITUDE", QVariant.Double, "Real", 10, 6) nums = QgsField ("NUMOFSATS", QVariant.Int, "Integer", 2, 0) hdop = QgsField ("HDOP", QVariant.Double, "Real", 4, 2) theDateTime = QgsField ("DATETIME", QVariant.String, "String", 19, 0) fixType = QgsField ("FIXTYPE", QVariant.String, "String", 1, 0) #fixType = QgsField ("FIXTYPE", QVariant.String) #fixType.setLength(1) bearing = QgsField ("BEARING", QVariant.Double, "Real", 6, 2) speed = QgsField ("SPEED-KPH", QVariant.Double, "Real", 5, 1) trackNumber = QgsField ("TRACKNUM", QVariant.Int, "Integer", 2, 0) qFields = {} qFields[0] = latf qFields[1] = lonf qFields[2] = nums qFields[3] = hdop qFields[4] = theDateTime qFields[5] = fixType qFields[6] = bearing qFields[7] = speed qFields[8] = trackNumber # set up the CRS # open the points SHAPE file # pointsFile = QgsVectorFileWriter(myShapeFileNamesDlg.lnePointsFileName.text(),"System",qFields,QGis.WKBPoint,CRS) pointsFile, fileOK = self.createSHAPEfile(myShapeFileNamesDlg.lnePointsFileName.text(),qFields,QGis.WKBPoint,CRS) if fileOK: for j in range(len(self.GPSTracks)): for i in range(len(self.GPSTracks[j])): theFeature = QgsFeature() latitude = self.GPSTracks[j][i].latitude if self.GPSTracks[j][i].latitudeNS == 'S': latitude = -latitude longitude = self.GPSTracks[j][i].longitude if self.GPSTracks[j][i].longitudeEW == 'W': longitude = -longitude theFeature.setGeometry(QgsGeometry.fromPoint(QgsPoint(longitude,latitude))) theFeature.addAttribute(0, QVariant(latitude)) theFeature.addAttribute(1, QVariant(longitude)) theFeature.addAttribute(2, QVariant(self.GPSTracks[j][i].numSatellites)) theFeature.addAttribute(3, QVariant(self.GPSTracks[j][i].hdop)) theFeature.addAttribute(4, QVariant(self.GPSTracks[j][i].theDateTime)) theFeature.addAttribute(5, QVariant(self.GPSTracks[j][i].fixQuality)) theFeature.addAttribute(6, QVariant(self.GPSTracks[j][i].bearing)) theFeature.addAttribute(7, QVariant(self.GPSTracks[j][i].speed)) theFeature.addAttribute(8, QVariant(j+1)) pointsFile.addFeature(theFeature) del pointsFile # del file object to force a flush and close if len(myShapeFileNamesDlg.lneLinesFileName.text()) > 0: # set up the fields for the Lines SHAPE file startDateTime = QgsField ("SDATETIME", QVariant.String, "String", 19, 0) endDateTime = QgsField ("EDATETIME", QVariant.String, "String", 19, 0) trackNumber = QgsField ("TRACKNUM", QVariant.Int, "Integer", 2, 0) qFields = {} qFields[0] = startDateTime qFields[1] = endDateTime qFields[2] = trackNumber linesFile, fileOK = self.createSHAPEfile(myShapeFileNamesDlg.lneLinesFileName.text(),qFields,QGis.WKBLineString,CRS) if fileOK: for j in range(len(self.GPSTracks)): theFeature = QgsFeature() pointsList = [] for i in range(len(self.GPSTracks[j])): latitude = self.GPSTracks[j][i].latitude if self.GPSTracks[j][i].latitudeNS == 'S': latitude = -latitude longitude = self.GPSTracks[j][i].longitude if self.GPSTracks[j][i].longitudeEW == 'W': longitude = -longitude pointsList.append(QgsPoint(longitude,latitude)) theFeature.setGeometry(QgsGeometry.fromPolyline(pointsList)) theFeature.addAttribute(0, QVariant(self.GPSTracks[j][0].theDateTime)) theFeature.addAttribute(1, QVariant(self.GPSTracks[j][len(self.GPSTracks[j])-1].theDateTime)) theFeature.addAttribute(2, QVariant(j+1)) linesFile.addFeature(theFeature) del linesFile # del file object to force a flush and close def createSHAPEfile(self,fileName,fileFields,fileType,crs): ''' this function creates a new, empty shape file for use in writing points or lines Returns: SHAPEfile, status if status == True then SHAPEfile is OK to use, if False then an error occured and cannot use SHAPEFile Input Parameters: fileName = full name of the SHAPE file to be created fileFields = map of QgsFields to use for the attributes of the SHAPE file fileType = QGis.WKBPoint for points file <or> QGis.WKBLine for lines file crs = the QgsCoordinateReferenceSystem to use for the file ''' status = True # default is no error SHAPEfile = QgsVectorFileWriter(fileName,"CP1250",fileFields,fileType,crs) typeName = 'Points' if fileType == QGis.WKBPoint else 'Lines' if SHAPEfile.hasError() != QgsVectorFileWriter.NoError: status = False # report an error if SHAPEfile.hasError() == QgsVectorFileWriter.ErrDriverNotFound: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrDriverNotFound\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrCreateDataSource: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrCreateDataSource\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrCreateLayer: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrCreateLayer\' - saving " + typeName + " is aborted") elif SHAPEfile.hasError() == QgsVectorFileWriter.ErrAttributeTypeUnsupported: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'ErrAttributeTypeUnsupported\' - saving " + typeName + " is aborted") else: QMessageBox.warning(self.iface.mainWindow(),"trackGPS - makeShapeFiles","Error creating " + typeName + " SHAPE file" +\ " ERROR=\'UNKOWN ERROR\' saving " + typeName + " is aborted") return SHAPEfile,status