def getInstructionsToWaypoint(waypoint, gpsinfo): point = QgsPointXY(gpsinfo.longitude, gpsinfo.latitude) qgsdistance = QgsDistanceArea() qgsdistance.setSourceCrs( QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext() ) qgsdistance.setEllipsoid(qgsdistance.sourceCrs().ellipsoidAcronym()) wpangle = math.degrees(qgsdistance.bearing(point, waypoint)) dist = qgsdistance.convertLengthMeasurement( qgsdistance.measureLine(waypoint, point), QgsUnitTypes.DistanceMeters ) timeleft = dist / 1000 / gpsinfo.speed * 3600 delta = datetime.timedelta(seconds=timeleft) eta = datetime.datetime.now() + delta eta_string = eta.strftime("%H:%M") return { "heading": gpsinfo.direction, "wpangle": wpangle, "distleft": formatdist(dist), "raw_distleft": dist, "speed": gpsinfo.speed, "eta": eta_string, }
def by_seconds(self, seconds): """move by variable distance""" def iterations(distance,h): FIe1=0 LAMe1=0 FI=100 LAM=100 # iterations while fabs(FI-FIe1)>0.0000000001 and fabs(LAM -LAMe1)>0.0000000001: FI=FIe1 LAM=LAMe1 for i in range(0,int(ceil(distance/h))): kfi=[] klam=[] kazi=[] kfi.append(cos(azi[i])/(a*(1-(e2))/(pow((sqrt(1-(e2)*pow(sin(fi[i]),2))),3)))) klam.append(sin(azi[i])/((a/(sqrt(1-(e2)*pow(sin(fi[i]),2))))*cos(fi[i]))) kazi.append(sin(azi[i])*tan(fi[i])/(a/(sqrt(1-(e2)*pow(sin(fi[i]),2))))) for j in range(1,3): kfi.append(cos(azi[i]+kazi[j-1]*h/2)/(a*(1-(e2))/(pow(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2)),3)))) klam.append(sin(azi[i]+kazi[j-1]*h/2)/((a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2))))*cos(fi[i]+kfi[j-1]*h/2))) kazi.append(sin(azi[i]+kazi[j-1]*h/2)*tan(fi[i]+kfi[j-1]*h/2)/(a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2))))) kfi.append(cos(azi[i]+kazi[2]*h)/(a*(1-(e2))/(pow(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2)),3)))) klam.append(sin(azi[i]+kazi[2]*h)/((a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2))))*cos(fi[i]+kfi[2]*h))) kazi.append(sin(azi[i]+kazi[2]*h)*tan(fi[i]+kfi[2]*h)/(a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2))))) fi.append(fi[i]+(h/6.0)*(kfi[0]+2*kfi[1]+2*kfi[2]+kfi[3])) lam.append(lam[i]+(h/6.0)*(klam[0]+2*klam[1]+2*klam[2]+klam[3])) azi.append(azi[i]+(h/6.0)*(kazi[0]+2*kazi[1]+2*kazi[2]+kazi[3])) FIe1=fi[i+1] LAMe1=lam[i+1] h=h/2 fi[1:]=[] lam[1:]=[] azi[1:]=[] return FIe1,LAMe1 self._check() header=self.inputfile.readline() beforeLat=header.split('Lat_deg') numberOfLatColumn=beforeLat[0].split(',') beforeLong=header.split('Lon_deg') numberOfLonColumn=beforeLong[0].split(',') beforeSec=header.split('Gtm_sec') numberOfSecColumn=beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1=self.inputfile.readline() if seconds>0: linePos=self.inputfile.tell() line1=line1.split(',') while line1: self.inputfile.seek(linePos) line2=self.inputfile.readline() linePos=self.inputfile.tell() moveTime=1*seconds outline=1*line1 inline=line2.split(',') while moveTime>0: # for case of more than 1 second if line2: line2=line2.split(',') p1=QgsPoint(float(line1[len(numberOfLonColumn)-1]),float(line1[len(numberOfLatColumn)-1])) p2=QgsPoint(float(line2[len(numberOfLonColumn)-1]),float(line2[len(numberOfLatColumn)-1])) if p1!=p2: aziA = d.bearing(p1,p2) l = d.computeDistanceBearing(p1,p2)[0] if moveTime>(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime=moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) elif moveTime!=0 and moveTime!=(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): #first geodetic problem distance=l/(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1]))*moveTime h=distance/2.0 fi=[float(line1[len(numberOfLatColumn)-1])*pi/180] lam=[float(line1[len(numberOfLonColumn)-1])*pi/180] azi=[aziA] FIe1,LAMe1 = iterations(distance,h) moveTime=0 else: FIe1=float(line2[len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line2[len(numberOfLonColumn)-1])*pi/180 moveTime=0 break else: if moveTime>(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime=moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) else: FIe1=float(line2[len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line2[len(numberOfLonColumn)-1])*pi/180 moveTime=0 break else:break line1=1*line2 line2=self.inputfile.readline() line1=1*inline if moveTime==0: outline[len(numberOfLatColumn)-1]=str(FIe1*180/pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn)-1]=str(LAMe1*180/pi) outline=','.join(outline) self.outputfile.write(outline) else:break elif seconds<0: line=[] line.append(line1) line[0]=line[0].split(',') line.append(self.inputfile.readline()) line[1]=line[1].split(',') allSecs=(float(line[1][len(numberOfSecColumn)-1])-float(line[0][len(numberOfSecColumn)-1])) i=1 moveTime=1*seconds while fabs(moveTime)>allSecs: line.append(self.inputfile.readline().split(',')) i=i+1 if line[len(line)-1]==['']: break allSecs=allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) while line[len(line)-1]!=['']: allSecs=0 for i in reversed(range(1,len(line))): allSecs=allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) if fabs(moveTime)<=allSecs: for x in range(i-1): del line[0] break for i in reversed(range(len(line))): p1=QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]),float(line[i-1][len(numberOfLatColumn)-1])) p2=QgsPoint(float(line[i][len(numberOfLonColumn)-1]),float(line[i][len(numberOfLatColumn)-1])) if p1!=p2: aziA = d.bearing(p2,p1) l = d.computeDistanceBearing(p1,p2)[0] if moveTime<-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime=moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) elif moveTime!=0 and moveTime!=-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): #first geodetic problem distance=l/(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1]))*fabs(moveTime) h=distance/2.0 fi=[float(line[i][len(numberOfLatColumn)-1])*pi/180] lam=[float(line[i][len(numberOfLonColumn)-1])*pi/180] azi=[aziA] FIe1,LAMe1 = iterations(distance,h) break else: FIe1=float(line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveTime<-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime=moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) else: FIe1=float(line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline=1*line[len(line)-1] outline[len(numberOfLatColumn)-1]=str(FIe1*180/pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn)-1]=str(LAMe1*180/pi) outline=','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1]=line[len(line)-1].split(',') moveTime=1*seconds else: while line1: self.outputfile.write(line1) line1=self.inputfile.readline() self._close()
class GuidanceDock(QtGui.QDockWidget, FORM_CLASS): ''' classdocs ''' def __init__(self, parent=None): ''' Constructor ''' super(GuidanceDock, self).__init__(parent) self.setupUi(self) self.compass = CompassWidget() self.compass.setMinimumHeight(80) self.verticalLayout.addWidget(self.compass) self.verticalLayout.setStretch(5, 8) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setEllipsoidalMode(True) self.distArea.setSourceCrs(3452L) self.fontSize = 11 self.source = None self.target = None self.srcPos = [None, 0.0] self.trgPos = [None, 0.0] self.srcHeading = 0.0 self.trgHeading = 0.0 s = QSettings() self.format = s.value('PosiView/Guidance/Format', defaultValue=1, type=int) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.timer = 0 self.setUtcClock() def setUtcClock(self): if self.showUtc: if not self.timer: self.timer = self.startTimer(1000) self.frameUtcClock.show() else: self.frameUtcClock.hide() self.killTimer(self.timer) self.timer = 0 def setMobiles(self, mobiles): self.reset() self.mobiles = mobiles self.comboBoxSource.blockSignals(True) self.comboBoxTarget.blockSignals(True) self.comboBoxSource.clear() self.comboBoxSource.addItems(sorted(mobiles.keys())) self.comboBoxSource.setCurrentIndex(-1) self.comboBoxTarget.clear() self.comboBoxTarget.addItems(sorted(mobiles.keys())) self.comboBoxTarget.setCurrentIndex(-1) self.comboBoxSource.blockSignals(False) self.comboBoxTarget.blockSignals(False) s = QSettings() m = s.value('PosiView/Guidance/Source') if m in self.mobiles: self.comboBoxSource.setCurrentIndex(self.comboBoxSource.findText(m)) m = s.value('PosiView/Guidance/Target') if m in self.mobiles: self.comboBoxTarget.setCurrentIndex(self.comboBoxTarget.findText(m)) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.setUtcClock() @pyqtSlot(name='on_pushButtonFormat_clicked') def switchCoordinateFormat(self): self.format = (self.format + 1) % 3 s = QSettings() s.setValue('PosiView/Guidance/Format', self.format) if self.trgPos[0]: lon, lat = self.posToStr(self.trgPos[0]) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) if self.srcPos[0]: lon, lat = self.posToStr(self.srcPos[0]) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) def posToStr(self, pos): if self.format == 0: return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y()) if self.format == 1: return pos.toDegreesMinutes(4, True, True).split(',') if self.format == 2: return pos.toDegreesMinutesSeconds(2, True, True).split(',') @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged') def sourceChanged(self, mob): if self.source is not None: try: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) except TypeError: pass try: self.source = self.mobiles[mob] self.source.newPosition.connect(self.onNewSourcePosition) self.source.newAttitude.connect(self.onNewSourceAttitude) s = QSettings() s.setValue('PosiView/Guidance/Source', mob) except KeyError: self.source = None self.resetSource() @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged') def targetChanged(self, mob): if self.target is not None: try: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass try: self.target = self.mobiles[mob] self.target.newPosition.connect(self.onNewTargetPosition) self.target.newAttitude.connect(self.onNewTargetAttitude) s = QSettings() s.setValue('PosiView/Guidance/Target', mob) except KeyError: self.target = None self.resetTarget() @pyqtSlot(float, QgsPoint, float, float) def onNewSourcePosition(self, fix, pos, depth, altitude): if [pos, depth] != self.srcPos: lon, lat = self.posToStr(pos) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) self.labelSourceDepth.setText(str(depth)) if self.trgPos[0] is not None: self.labelVertDistance.setText(str(self.trgPos[1] - depth)) dist = self.distArea.measureLine(self.trgPos[0], pos) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.srcPos = [pos, depth] @pyqtSlot(float, QgsPoint, float, float) def onNewTargetPosition(self, fix, pos, depth, altitude): if [pos, depth] != self.trgPos: lon, lat = self.posToStr(pos) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) self.labelTargetDepth.setText(str(depth)) if self.srcPos[0] is not None: self.labelVertDistance.setText(str(depth - self.srcPos[1])) dist = self.distArea.measureLine(pos, self.srcPos[0]) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.trgPos = [pos, depth] @pyqtSlot(float, float, float) def onNewTargetAttitude(self, heading, pitch, roll): if self.trgHeading != heading: self.trgHeading = heading self.labelTargetHeading.setText(str(heading)) self.compass.setAngle2(heading) @pyqtSlot(float, float, float) def onNewSourceAttitude(self, heading, pitch, roll): if self.srcHeading != heading: self.srcHeading = heading self.labelSourceHeading.setText(str(heading)) self.compass.setAngle(heading) def reset(self): try: if self.source is not None: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) if self.target is not None: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass self.source = None self.target = None self.resetSource() self.resetTarget() self.resetDistBearing() def resetSource(self): self.srcPos = [None, 0.0] self.srcHeading = -720.0 self.labelSourceLat.setText('---') self.labelSourceLon.setText('---') self.labelSourceHeading.setText('---') self.labelSourceDepth.setText('---') self.compass.reset(1) self.resetDistBearing() def resetTarget(self): self.trgPos = [None, 0.0] self.trgHeading = -720.0 self.labelTargetLat.setText('---') self.labelTargetLon.setText('---') self.labelTargetHeading.setText('---') self.labelTargetDepth.setText('---') self.compass.reset(2) self.resetDistBearing() def resetDistBearing(self): self.labelDirection.setText('---') self.labelDistance.setText('---') self.labelVertDistance.setText('---') def resizeEvent(self, event): fsize = event.size().width() / 40 if fsize != self.fontSize: self.fontSize = fsize self.dockWidgetContents.setStyleSheet("font-weight: bold; font-size: {}pt".format(self.fontSize)) return QtGui.QDockWidget.resizeEvent(self, event) def timerEvent(self, event): dt = QDateTime.currentDateTimeUtc() self.labelTimeUtc.setText(dt.time().toString(u'hh:mm:ss'))
def by_distance(self, distance): """ shift by constant distance :param distance: distance used to shift in meters """ self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if distance > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveDistance = 1*distance outline = 1*line1 inline = line2.split(',') if line2: line2 = line2.split(',') p1 = QgsPoint(float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.computeDistanceBearing(p1, p2)[0] while moveDistance > l: if line2: moveDistance = moveDistance-l line1 = 1*line2 line2 = self.inputfile.readline() if line2: line2 = line2.split(',') p1 = QgsPoint( float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPoint( float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.computeDistanceBearing(p1, p2)[0] else: break if line2: if moveDistance != l: if p1 != p2: aziA = d.bearing(p1, p2) h = moveDistance/2.0 fi = [float( line1[len(numberOfLatColumn)-1])*pi/180] lam = [float( line1[len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line1 = inline else: break else: break elif distance < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') i = 1 distance = fabs(distance) moveDistance = fabs(distance) p1 = QgsPoint(float(line[0][len(numberOfLonColumn)-1]), float(line[0][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[1][len(numberOfLonColumn)-1]), float(line[1][len(numberOfLatColumn)-1])) allDist = d.computeDistanceBearing(p1, p2)[0] while moveDistance > allDist: line.append(self.inputfile.readline().split(',')) i = i+1 if line[len(line)-1] == ['']: break p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.computeDistanceBearing(p1, p2)[0] while line[len(line)-1] != ['']: allDist = 0 for i in reversed(range(1, len(line))): p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.computeDistanceBearing(p1, p2)[0] if fabs(moveDistance) <= allDist: for x in range(i-1): del line[0] break for i in reversed(range(len(line))): p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.computeDistanceBearing(p1, p2)[0] if moveDistance > l: moveDistance = moveDistance-l elif moveDistance != 0 and moveDistance != l: # first geodetic problem h = moveDistance/2.0 fi = [float( line[i][len(numberOfLatColumn)-1])*pi/180] lam = [float( line[i][len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) break else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveDistance > l: moveDistance = moveDistance-l else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline = 1*line[len(line)-1] # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1] = line[len(line)-1].split(',') moveDistance = fabs(distance) else: while line1: self.outputfile.write(line1) line1 = self.inputfile.readline() self._close()
class GuidanceDock(QDockWidget, FORM_CLASS): ''' classdocs ''' def __init__(self, parent=None): ''' Constructor ''' super(GuidanceDock, self).__init__(parent) self.setupUi(self) self.setStyleSheet("QLabel { padding-left: 5px; padding-right: 5px; }") self.compass = CompassWidget() self.compass.setMinimumHeight(80) self.verticalLayout.addWidget(self.compass) self.verticalLayout.setStretch(5, 8) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance().transformContext()) self.fontSize = 11 self.source = None self.target = None self.srcPos = [None, 0.0] self.trgPos = [None, 0.0] self.srcHeading = 0.0 self.trgHeading = 0.0 s = QSettings() self.format = s.value('PosiView/Guidance/Format', defaultValue=1, type=int) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.timer = 0 self.setUtcClock() self.layer = None def setUtcClock(self): if self.showUtc: if not self.timer: self.timer = self.startTimer(1000) self.frameUtcClock.show() else: self.frameUtcClock.hide() self.killTimer(self.timer) self.timer = 0 def setMobiles(self, mobiles): self.reset() self.mobiles = mobiles self.comboBoxSource.blockSignals(True) self.comboBoxTarget.blockSignals(True) mobs = sorted(mobiles.keys()) self.comboBoxSource.clear() self.comboBoxSource.addItems(mobs) self.comboBoxSource.setCurrentIndex(-1) self.comboBoxTarget.clear() self.comboBoxTarget.addItems(mobs) self.comboBoxTarget.setCurrentIndex(-1) self.comboBoxSource.blockSignals(False) self.comboBoxTarget.blockSignals(False) s = QSettings() m = s.value('PosiView/Guidance/Source') if m in self.mobiles: self.comboBoxSource.setCurrentText( m) # Index(self.comboBoxSource.findText(m)) m = s.value('PosiView/Guidance/Target') if m in self.mobiles: self.comboBoxTarget.setCurrentText( m) # Index(self.comboBoxTarget.findText(m)) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.setUtcClock() @pyqtSlot(name='on_pushButtonFormat_clicked') def switchCoordinateFormat(self): self.format = (self.format + 1) % 3 s = QSettings() s.setValue('PosiView/Guidance/Format', self.format) if self.trgPos[0]: lon, lat = self.posToStr(self.trgPos[0]) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) if self.srcPos[0]: lon, lat = self.posToStr(self.srcPos[0]) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) def posToStr(self, pos): if self.format == 0: return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y()) if self.format == 1: return QgsCoordinateFormatter.format( pos, QgsCoordinateFormatter.FormatDegreesMinutes, 4).split(',') if self.format == 2: return QgsCoordinateFormatter.format( pos, QgsCoordinateFormatter.FormatDegreesMinutesSeconds, 2).split(',') @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged') def sourceChanged(self, mob): if self.source is not None: try: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) except TypeError: pass if mob in self.mobiles: try: self.source = self.mobiles[mob] self.source.newPosition.connect(self.onNewSourcePosition) self.source.newAttitude.connect(self.onNewSourceAttitude) s = QSettings() s.setValue('PosiView/Guidance/Source', mob) except KeyError: self.source = None self.resetSource() elif self.layer: for f in self.layer.getFeatures(): if f['name'] == mob[:-2]: pos = f.geometry().asPoint() self.resetSource() self.onNewSourcePosition(None, pos, -9999, -9999) @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged') def targetChanged(self, mob): if self.target is not None: try: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass if mob in self.mobiles: try: self.target = self.mobiles[mob] self.target.newPosition.connect(self.onNewTargetPosition) self.target.newAttitude.connect(self.onNewTargetAttitude) s = QSettings() s.setValue('PosiView/Guidance/Target', mob) except KeyError: self.target = None self.resetTarget() elif self.layer: for f in self.layer.getFeatures(): if f['name'] == mob[:-2]: pos = f.geometry().asPoint() self.resetTarget() self.onNewTargetPosition(None, pos, -9999, -9999) @pyqtSlot(float, QgsPointXY, float, float) def onNewSourcePosition(self, fix, pos, depth, altitude): if [pos, depth] != self.srcPos: lon, lat = self.posToStr(pos) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) if depth > -9999: self.labelSourceDepth.setText('{:.1f}'.format(depth)) if self.trgPos[0] is not None: if depth > -9999 and self.trgPos[1] > -9999: self.labelVertDistance.setText( '{:.1f}'.format(self.trgPos[1] - depth)) dist = self.distArea.measureLine(self.trgPos[0], pos) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.srcPos = [pos, depth] @pyqtSlot(float, QgsPointXY, float, float) def onNewTargetPosition(self, fix, pos, depth, altitude): if [pos, depth] != self.trgPos: lon, lat = self.posToStr(pos) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) if depth > -9999: self.labelTargetDepth.setText('{:.1f}'.format(depth)) if self.srcPos[0] is not None: if depth > -9999 and self.srcPos[1] > -9999: self.labelVertDistance.setText( '{:.1f}'.format(depth - self.srcPos[1])) dist = self.distArea.measureLine(pos, self.srcPos[0]) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.trgPos = [pos, depth] @pyqtSlot(float, float, float) def onNewTargetAttitude(self, heading, pitch, roll): if self.trgHeading != heading: self.trgHeading = heading self.labelTargetHeading.setText('{:.1f}'.format(heading)) self.compass.setAngle2(heading) @pyqtSlot(float, float, float) def onNewSourceAttitude(self, heading, pitch, roll): if self.srcHeading != heading: self.srcHeading = heading self.labelSourceHeading.setText('{:.1f}'.format(heading)) self.compass.setAngle(heading) @pyqtSlot(QgsMapLayer) def onActiveLayerChanged(self, layer): if self.cleanComboBox(self.comboBoxSource): self.resetSource() if self.cleanComboBox(self.comboBoxTarget): self.resetTarget() self.layer = None if not layer: return if layer.type() == QgsMapLayer.VectorLayer and layer.wkbType( ) == QgsWkbTypes.Point: if layer.fields().indexOf('name') != -1: self.layer = layer self.comboBoxSource.blockSignals(True) self.comboBoxTarget.blockSignals(True) items = sorted( [str(f['name']) + ' ' for f in layer.getFeatures()]) self.comboBoxSource.addItems(items) self.comboBoxTarget.addItems(items) self.comboBoxSource.blockSignals(False) self.comboBoxTarget.blockSignals(False) def reset(self): try: if self.source is not None: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) if self.target is not None: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass self.source = None self.target = None self.resetSource() self.resetTarget() self.resetDistBearing() def resetSource(self): self.srcPos = [None, 0.0] self.srcHeading = -9999.0 self.labelSourceLat.setText('---') self.labelSourceLon.setText('---') self.labelSourceHeading.setText('---') self.labelSourceDepth.setText('---') self.compass.reset(1) self.resetDistBearing() def resetTarget(self): self.trgPos = [None, 0.0] self.trgHeading = -9999.0 self.labelTargetLat.setText('---') self.labelTargetLon.setText('---') self.labelTargetHeading.setText('---') self.labelTargetDepth.setText('---') self.compass.reset(2) self.resetDistBearing() def cleanComboBox(self, comboBox): comboBox.blockSignals(True) ct = comboBox.currentText() for _ in range(comboBox.count() - len(self.mobiles)): comboBox.removeItem(len(self.mobiles)) if ct not in self.mobiles: comboBox.setCurrentIndex(-1) res = True else: res = False comboBox.blockSignals(False) return res def resetDistBearing(self): self.labelDirection.setText('---') self.labelDistance.setText('---') self.labelVertDistance.setText('---') def resizeEvent(self, event): fsize = max(8, event.size().width() / 50) if fsize != self.fontSize: self.fontSize = fsize self.dockWidgetContents.setStyleSheet( "font-weight: bold; font-size: {}pt;".format(self.fontSize)) return QDockWidget.resizeEvent(self, event) def timerEvent(self, event): dt = datetime.now(tz=timezone.utc) self.labelTimeUtc.setText(dt.strftime("%H:%M:%S"))
class GuidanceDock(QDockWidget, FORM_CLASS): ''' classdocs ''' def __init__(self, parent=None): ''' Constructor ''' super(GuidanceDock, self).__init__(parent) self.setupUi(self) self.compass = CompassWidget() self.compass.setMinimumHeight(80) self.verticalLayout.addWidget(self.compass) self.verticalLayout.setStretch(5, 8) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance().transformContext()) self.fontSize = 11 self.source = None self.target = None self.srcPos = [None, 0.0] self.trgPos = [None, 0.0] self.srcHeading = 0.0 self.trgHeading = 0.0 s = QSettings() self.format = s.value('PosiView/Guidance/Format', defaultValue=1, type=int) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.timer = 0 self.setUtcClock() def setUtcClock(self): if self.showUtc: if not self.timer: self.timer = self.startTimer(1000) self.frameUtcClock.show() else: self.frameUtcClock.hide() self.killTimer(self.timer) self.timer = 0 def setMobiles(self, mobiles): self.reset() self.mobiles = mobiles self.comboBoxSource.blockSignals(True) self.comboBoxTarget.blockSignals(True) self.comboBoxSource.clear() self.comboBoxSource.addItems(sorted(mobiles.keys())) self.comboBoxSource.setCurrentIndex(-1) self.comboBoxTarget.clear() self.comboBoxTarget.addItems(sorted(mobiles.keys())) self.comboBoxTarget.setCurrentIndex(-1) self.comboBoxSource.blockSignals(False) self.comboBoxTarget.blockSignals(False) s = QSettings() m = s.value('PosiView/Guidance/Source') if m in self.mobiles: self.comboBoxSource.setCurrentIndex( self.comboBoxSource.findText(m)) m = s.value('PosiView/Guidance/Target') if m in self.mobiles: self.comboBoxTarget.setCurrentIndex( self.comboBoxTarget.findText(m)) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.setUtcClock() @pyqtSlot(name='on_pushButtonFormat_clicked') def switchCoordinateFormat(self): self.format = (self.format + 1) % 3 s = QSettings() s.setValue('PosiView/Guidance/Format', self.format) if self.trgPos[0]: lon, lat = self.posToStr(self.trgPos[0]) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) if self.srcPos[0]: lon, lat = self.posToStr(self.srcPos[0]) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) def posToStr(self, pos): if self.format == 0: return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y()) if self.format == 1: return ', '.join( QgsCoordinateFormatter.format( pos, QgsCoordinateFormatter.FormatDegreesMinutes, 4).rsplit(',')[::-1]).split(',') if self.format == 2: return ', '.join( QgsCoordinateFormatter.format( pos, QgsCoordinateFormatter.FormatDegreesMinutesSeconds, 2).rsplit(',')[::-1]).split(',') @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged') def sourceChanged(self, mob): if self.source is not None: try: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) except TypeError: pass try: self.source = self.mobiles[mob] self.source.newPosition.connect(self.onNewSourcePosition) self.source.newAttitude.connect(self.onNewSourceAttitude) s = QSettings() s.setValue('PosiView/Guidance/Source', mob) except KeyError: self.source = None self.resetSource() @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged') def targetChanged(self, mob): if self.target is not None: try: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass try: self.target = self.mobiles[mob] self.target.newPosition.connect(self.onNewTargetPosition) self.target.newAttitude.connect(self.onNewTargetAttitude) s = QSettings() s.setValue('PosiView/Guidance/Target', mob) except KeyError: self.target = None self.resetTarget() @pyqtSlot(float, QgsPointXY, float, float) def onNewSourcePosition(self, fix, pos, depth, altitude): if [pos, depth] != self.srcPos: lon, lat = self.posToStr(pos) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) self.labelSourceDepth.setText('{:.1f}'.format(depth)) if self.trgPos[0] is not None: self.labelVertDistance.setText('{:.1f}'.format(self.trgPos[1] - depth)) dist = self.distArea.measureLine(self.trgPos[0], pos) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.srcPos = [pos, depth] @pyqtSlot(float, QgsPointXY, float, float) def onNewTargetPosition(self, fix, pos, depth, altitude): if [pos, depth] != self.trgPos: lon, lat = self.posToStr(pos) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) self.labelTargetDepth.setText('{:.1f}'.format(depth)) if self.srcPos[0] is not None: self.labelVertDistance.setText('{:.1f}'.format(depth - self.srcPos[1])) dist = self.distArea.measureLine(pos, self.srcPos[0]) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.trgPos = [pos, depth] @pyqtSlot(float, float, float) def onNewTargetAttitude(self, heading, pitch, roll): if self.trgHeading != heading: self.trgHeading = heading self.labelTargetHeading.setText('{:.1f}'.format(heading)) self.compass.setAngle2(heading) @pyqtSlot(float, float, float) def onNewSourceAttitude(self, heading, pitch, roll): if self.srcHeading != heading: self.srcHeading = heading self.labelSourceHeading.setText('{:.1f}'.format(heading)) self.compass.setAngle(heading) def reset(self): try: if self.source is not None: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) if self.target is not None: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass self.source = None self.target = None self.resetSource() self.resetTarget() self.resetDistBearing() def resetSource(self): self.srcPos = [None, 0.0] self.srcHeading = -720.0 self.labelSourceLat.setText('---') self.labelSourceLon.setText('---') self.labelSourceHeading.setText('---') self.labelSourceDepth.setText('---') self.compass.reset(1) self.resetDistBearing() def resetTarget(self): self.trgPos = [None, 0.0] self.trgHeading = -720.0 self.labelTargetLat.setText('---') self.labelTargetLon.setText('---') self.labelTargetHeading.setText('---') self.labelTargetDepth.setText('---') self.compass.reset(2) self.resetDistBearing() def resetDistBearing(self): self.labelDirection.setText('---') self.labelDistance.setText('---') self.labelVertDistance.setText('---') def resizeEvent(self, event): fsize = event.size().width() / 40 if fsize != self.fontSize: self.fontSize = fsize self.dockWidgetContents.setStyleSheet( "font-weight: bold; font-size: {}pt".format(self.fontSize)) return QDockWidget.resizeEvent(self, event) def timerEvent(self, event): dt = QDateTime.currentDateTimeUtc() self.labelTimeUtc.setText(dt.time().toString(u'hh:mm:ss'))
class MeasureDistanceTool(QgsMapTool): finished = pyqtSignal() def __init__(self, canvas, msglog): super().__init__(canvas) self.canvas = canvas self.msglog = msglog self.start_point = self.end_point = None self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubber_band.setColor(QColor(255, 0, 0, 100)) self.rubber_band.setWidth(3) 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(255, 0, 0, 150)) crs = self.canvas.mapSettings().destinationCrs() self.distance_calc = QgsDistanceArea() self.distance_calc.setSourceCrs( crs, QgsProject.instance().transformContext()) self.distance_calc.setEllipsoid(crs.ellipsoidAcronym()) self.reset() def reset(self): self.msglog.logMessage("") self.start_point = self.end_point = None self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) def canvasPressEvent(self, event): pass def canvasReleaseEvent(self, event): transform = self.canvas.getCoordinateTransform() point = transform.toMapCoordinates(event.pos().x(), event.pos().y()) if self.start_point: self.end_point = point self.rubber_band.addPoint(self.end_point) self.rubber_band_points.addPoint(self.end_point) distance = self.distance_calc.measureLine( [self.start_point, self.end_point]) bearing = self.distance_calc.bearing(self.start_point, point) distancemsg = QMessageBox(self.parent()) distancemsg.finished.connect(self.deactivate) distancemsg.setWindowTitle("Measure tool") distancemsg.setText("Distance: {:.3F} m. Bearing: {:.3F} º".format( distance, degrees(bearing))) distancemsg.exec() self.finish() else: self.start_point = point self.rubber_band.addPoint(self.start_point) self.rubber_band_points.addPoint(self.start_point) def canvasMoveEvent(self, e): if self.start_point and not self.end_point: transform = self.canvas.getCoordinateTransform() point = transform.toMapCoordinates(e.pos().x(), e.pos().y()) self.rubber_band.movePoint(point) distance = self.distance_calc.measureLine( [self.start_point, point]) bearing = self.distance_calc.bearing(self.start_point, point) self.msglog.logMessage("") self.msglog.logMessage( "Current distance: {:.3F} m. Bearing: {:.3F} º".format( distance, degrees(bearing)), "Measure distance:", 0) def keyPressEvent(self, event): """ When escape key is pressed, line is restarted """ if event.key() == Qt.Key_Escape: self.reset() def finish(self): self.reset() self.finished.emit()
def by_distance(self, distance): """ shift by constant distance :param distance: distance used to shift in meters """ self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid(self.ellipsoid) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() #logfile = open("/tmp/log.txt", "w") if distance > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: #print(line1, self.abort) if self.abort is True: break self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveDistance = 1*distance outline = 1*line1 inline = line2.split(',') #print(inline, line2, linePos) if line2: line2 = line2.split(',') p1 = QgsPointXY(float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.measureLine(p1, p2) #print("MD, L", moveDistance, l) while moveDistance > l: #logfile.write(str(moveDistance) + " " + str(l) + "\n") #print("MD, L, 2", moveDistance, l) if line2: moveDistance = moveDistance-l line1 = 1*line2 line2 = self.inputfile.readline() #print(inline, line1, line2, linePos) if line2: line2 = line2.split(',') p1 = QgsPointXY( float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPointXY( float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.measureLine(p1, p2) else: #print("BREAK") #logfile.close() break if line2: if moveDistance != l: if p1 != p2: aziA = d.bearing(p1, p2) h = moveDistance/2.0 fi = [float( line1[len(numberOfLatColumn)-1])*pi/180] lam = [float( line1[len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line1 = inline else: break self.progress.emit( float(linePos) / float(self.length) * 100) else: break elif distance < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') i = 1 distance = fabs(distance) moveDistance = fabs(distance) p1 = QgsPointXY(float(line[0][len(numberOfLonColumn)-1]), float(line[0][len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line[1][len(numberOfLonColumn)-1]), float(line[1][len(numberOfLatColumn)-1])) allDist = d.measureLine(p1, p2) while moveDistance > allDist: line.append(self.inputfile.readline().split(',')) i = i+1 if line[len(line)-1] == ['']: break p1 = QgsPointXY(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.measureLine(p1, p2) while line[len(line)-1] != ['']: if self.abort is True: break allDist = 0 for i in reversed(list(range(1, len(line)))): p1 = QgsPointXY(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.measureLine(p1, p2) if fabs(moveDistance) <= allDist: for x in range(i-1): del line[0] break for i in reversed(list(range(len(line)))): p1 = QgsPointXY(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.measureLine(p1, p2) if moveDistance > l: moveDistance = moveDistance-l elif moveDistance != 0 and moveDistance != l: # first geodetic problem h = moveDistance/2.0 fi = [float( line[i][len(numberOfLatColumn)-1])*pi/180] lam = [float( line[i][len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) break else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveDistance > l: moveDistance = moveDistance-l else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline = 1*line[len(line)-1] # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1] = line[len(line)-1].split(',') moveDistance = fabs(distance) self.progress.emit( float(self.outputfile.tell()) / float(self.length) * 100) else: while line1: if self.abort is True: break self.outputfile.write(line1) line1 = self.inputfile.readline() self.progress.emit( float(self.outputfile.tell()) / float(self.length) * 100) self._close()
class RectByFixedExtentTool(QgsMapTool): msgbar = pyqtSignal(str) rbFinished = pyqtSignal(object) rb_reset_signal = pyqtSignal() def __init__(self, canvas, x_length, y_length): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.nbPoints = 0 self.rb = None self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3, self.x_p4, self.y_p4 = None, None, None, None, None, None, None, None self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') self.fixed_p2, self.fixed_p3 = QgsPointXY(0, 0), QgsPointXY(0, 0) self.length = 0 self.mCtrl = None self.x_length = x_length self.y_length = y_length self.bearing = 0.0 # our own fancy cursor self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #FF0000", "+ c #1210f3", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) self.rectangle = Rectangle() 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.nbPoints = 0 self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None self.fixed_p2, self.fixed_p3 = None, None if self.rb: self.rb.reset(True) self.rb = None self.canvas.refresh() self.rb_reset_signal.emit() return def canvasPressEvent(self, event): layer = self.canvas.currentLayer() if self.nbPoints == 0: color = QColor(255, 0, 0, 128) if self.rb: self.rb.reset() self.rb = None self.rb = QgsRubberBand(self.canvas, True) self.rb.setColor(color) self.rb.setWidth(1) self.msgbar.emit("Define bearing along track") self.rb_reset_signal.emit() elif self.nbPoints == 2: self.canvas.refresh() point = self.toLayerCoordinates(layer, event.pos()) point_map = self.toMapCoordinates(layer, point) if self.nbPoints == 0: self.x_p1 = point_map.x() self.y_p1 = point_map.y() elif self.nbPoints == 1: self.x_p2 = point_map.x() self.y_p2 = point_map.y() self.bearing = self.distance.bearing( QgsPointXY(self.x_p1, self.y_p1), QgsPointXY(self.x_p2, self.y_p2)) self.msgbar.emit("Define across track direction") else: self.x_p3 = point_map.x() self.y_p3 = point_map.y() self.nbPoints += 1 if self.nbPoints == 3: geom = self.rectangle.get_rect_by3_points( QgsPointXY(self.x_p1, self.y_p1), self.fixed_p2, self.fixed_p3, self.y_length) self.rb.setToGeometry(geom, None) self.nbPoints = 0 self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None self.fixed_p2, self.fixed_p3 = None, None self.msgbar.emit("") self.rbFinished.emit(geom) if self.rb: return def canvasMoveEvent(self, event): if not self.rb: return currpoint = self.toMapCoordinates(event.pos()) if self.nbPoints == 1: self.bearing = self.distance.bearing( QgsPointXY(self.x_p1, self.y_p1), currpoint) self.fixed_p2 = self.distance.computeSpheroidProject( QgsPointXY(self.x_p1, self.y_p1), self.x_length, self.bearing) self.rb.setToGeometry( QgsGeometry.fromPolyline( [QgsPoint(self.x_p1, self.y_p1), QgsPoint(self.fixed_p2)]), None) curr_bearing = degrees(self.bearing) if curr_bearing < 0.0: curr_bearing = 360 + curr_bearing self.msgbar.emit( "Current distance: {:.3F} m, Current bearing: {:.3F} degrees". format(self.x_length, curr_bearing)) if self.nbPoints >= 2: # test if currpoint is left or right of the line defined by p1 and p2 side = calc_is_collinear(QgsPointXY(self.x_p1, self.y_p1), self.fixed_p2, currpoint) if side == 0: return None self.fixed_p3 = self.distance.computeSpheroidProject( QgsPointXY(self.x_p2, self.y_p2), self.y_length, self.bearing + radians(90) * side) geom = self.rectangle.get_rect_by3_points( QgsPointXY(self.x_p1, self.y_p1), self.fixed_p2, self.fixed_p3, self.y_length) self.rb.setToGeometry(geom, None) curr_bearing = degrees(self.bearing + radians(90) * side) if curr_bearing < 0.0: curr_bearing = 360 + curr_bearing self.msgbar.emit( "Current distance: {:.3F} m, Current bearing: {:.3F} degrees". format(self.y_length, curr_bearing)) def activate(self): self.canvas.setCursor(self.cursor) def deactivate(self): self.nbPoints = 0 self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None self.fixed_p2, self.fixed_p3 = None, None if self.rb: self.rb.reset(True) self.rb.hide() self.rb = None self.canvas.refresh() def is_zoom_tool(self): return False def is_transient(self): return False def is_edit_tool(self): return True
class MoveFeatureTool(QgsMapTool): def __init__(self, mission_track, canvas): QgsMapTool.__init__(self, canvas) self.band = None self.feature = None self.startcoord = None self.mission_track = mission_track self.layer = mission_track.get_mission_layer() self.clicked_outside_layer = False self.mCtrl = False self.rot_center = None self.rot_center_rb = None self.ini_rot_point = None self.last_rot_angle = 0.0 self.curr_angle = 0.0 self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') self.ini_geom = next(self.layer.dataProvider().getFeatures()).geometry() logger.info(mission_track.get_mission_name()) def canvasMoveEvent(self, event): """ Override of QgsMapTool mouse move event """ if self.band and not self.mCtrl: point = self.toMapCoordinates(event.pos()) offset_x = point.x() - self.startcoord.x() offset_y = point.y() - self.startcoord.y() self.band.setTranslationOffset(offset_x, offset_y) self.band.updatePosition() self.band.update() if self.band and self.mCtrl: end_rot_point = self.toMapCoordinates(event.pos()) self.curr_angle = self.distance.bearing(self.rot_center, end_rot_point) \ - self.distance.bearing(self.rot_center, self.ini_rot_point)\ + self.last_rot_angle self.rotate_and_project_band(self.curr_angle) def canvasPressEvent(self, event): """ Override of QgsMapTool mouse press event """ if event.button() == Qt.LeftButton and not self.mCtrl: if self.band: self.band.hide() self.band = None self.feature = None logger.info("layer feature count {}".format(self.layer.featureCount())) if not self.layer: return logger.info("Trying to find feature in layer") point = self.toLayerCoordinates(self.layer, event.pos()) search_radius = (QgsTolerance.toleranceInMapUnits(10, self.layer, self.canvas().mapSettings(), QgsTolerance.Pixels)) rect = QgsRectangle() rect.setXMinimum(point.x() - search_radius) rect.setXMaximum(point.x() + search_radius) rect.setYMinimum(point.y() - search_radius) rect.setYMaximum(point.y() + search_radius) rq = QgsFeatureRequest().setFilterRect(rect) f = QgsFeature() self.layer.getFeatures(rq).nextFeature(f) if f.geometry(): self.band = self.create_rubber_band() self.band.setToGeometry(f.geometry(), self.layer) self.band.show() self.startcoord = self.toMapCoordinates(event.pos()) self.feature = f self.clicked_outside_layer = False return else: self.clicked_outside_layer = True def canvasReleaseEvent(self, event): """ Override of QgsMapTool mouse release event """ if event.button() == Qt.LeftButton and not self.mCtrl: if not self.band: if self.clicked_outside_layer and len(self.mission_track.find_waypoints_in_mission()) > 0: confirmation_msg = "Do you want to move the mission ? \n\n" \ "First waypoint will set on the marked point." reply = QMessageBox.question(self.parent(), 'Movement Confirmation', confirmation_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: feats = self.layer.getFeatures() for f in feats: # will be only one if self.layer.geometryType() == QgsWkbTypes.LineGeometry: list_wp = f.geometry().asPolyline() self.startcoord = self.toLayerCoordinates(self.layer, list_wp[0]) elif self.layer.geometryType() == QgsWkbTypes.PointGeometry: wp = f.geometry().asPoint() self.startcoord = self.toLayerCoordinates(self.layer, wp) self.feature = f self.move_position(event.pos()) return if not self.layer: return if not self.feature: return self.move_position(event.pos()) def keyPressEvent(self, event): if event.key() == Qt.Key_Control and self.band is None \ and len(self.mission_track.find_waypoints_in_mission()) > 1: self.mCtrl = True self.show_rotation_center() self.show_rubber_band() self.rotate_and_project_band(self.last_rot_angle) self.ini_rot_point = self.toMapCoordinates(self.canvas().mouseLastXY()) def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control and self.mCtrl: self.mCtrl = False self.rotate_and_project_mission() self.hide_rotation_center() self.hide_rubber_band() self.last_rot_angle = self.curr_angle def move_position(self, pos): start_point = self.toLayerCoordinates(self.layer, self.startcoord) end_point = self.toLayerCoordinates(self.layer, pos) # Find vertical distance to be translated a = self.distance.bearing(start_point, end_point) d = self.distance.measureLine(start_point, end_point) vertical_dist = abs(cos(a) * d) # If translating a point or if translation is small, # do a simple translation (very small error, proportional to vertical dist) if vertical_dist < 9000 or self.layer.geometryType() == QgsWkbTypes.PointGeometry: dx = end_point.x() - start_point.x() dy = end_point.y() - start_point.y() self.layer.startEditing() self.layer.translateFeature(self.feature.id(), dx, dy) self.layer.commitChanges() # If translation is big, translate and project (small and constant error due to approximations in calculations) else: ini_coords = next(self.layer.dataProvider().getFeatures()).geometry().asPolyline() end_coords = [] if len(ini_coords) > 1: dx = end_point.x() - start_point.x() dy = end_point.y() - start_point.y() end_c = QgsPointXY(ini_coords[0].x() + dx, ini_coords[0].y() + dy) end_coords.append(end_c) for i in range(1, len(ini_coords)): dist = self.distance.measureLine(ini_coords[i-1], ini_coords[i]) angle = self.distance.bearing(ini_coords[i-1], ini_coords[i]) end_c = endpoint(end_coords[i-1], dist, degrees(angle)) end_coords.append(end_c) feature = next(self.layer.dataProvider().getFeatures()) self.layer.startEditing() self.layer.changeGeometry(feature.id(), QgsGeometry.fromPolylineXY(end_coords)) self.layer.commitChanges() if self.band is not None: self.band.hide() self.band = None # get new waypoints and put them into mission structure feats = self.layer.getFeatures() for f in feats: # will be only one if self.layer.geometryType() == QgsWkbTypes.LineGeometry: list_wp = f.geometry().asPolyline() for wp in range(0, len(list_wp)): point = list_wp[wp] self.mission_track.change_position(wp, point) elif self.layer.geometryType() == QgsWkbTypes.PointGeometry: wp = f.geometry().asPoint() self.mission_track.change_position(0, wp) # rotation center and geometry have changed, set rot_center to none to recalculate when needed self.rot_center = None self.last_rot_angle = 0.0 self.ini_geom = next(self.layer.dataProvider().getFeatures()).geometry() def deactivate(self): """ Deactive the tool. """ self.hide_rotation_center() self.hide_rubber_band() def create_rubber_band(self): """ Creates a new rubber band. """ band = QgsRubberBand(self.canvas()) band.setColor(QColor("green")) band.setWidth(2) band.setLineStyle(Qt.DashLine) return band def show_rotation_center(self): """ Shows rotation center of the mission with a point rubber band """ if len(self.mission_track.find_waypoints_in_mission()) > 1: feature = next(self.layer.dataProvider().getFeatures()) list_wp = feature.geometry().asPolyline() if self.rot_center is None or self.rot_center_rb is None: self.rot_center = self.find_geometric_center(list_wp) self.rot_center_rb = QgsRubberBand(self.canvas()) self.rot_center_rb.setColor(QColor("black")) self.rot_center_rb.setWidth(3) self.rot_center_rb.setToGeometry(QgsGeometry.fromPointXY(self.rot_center), None) self.rot_center_rb.update() else: self.rot_center_rb.show() def hide_rotation_center(self): """ Hides the rotation center of the mission and deletes the point rubber band """ if self.rot_center_rb: self.rot_center_rb.hide() # self.rot_center_rb = None def find_geometric_center(self, list_wp): """ Finds geometric center from a list of waypoints :param list_wp: list of waypoints :return: geometric center of the list of waypoints """ center = QgsPointXY() max_x = None min_x = None max_y = None min_y = None # Geometric center for i in range(0, len(list_wp)): point = list_wp[i] if max_x is None or point.x() > max_x: max_x = point.x() if min_x is None or point.x() < min_x: min_x = point.x() if max_y is None or point.y() > max_y: max_y = point.y() if min_y is None or point.y() < min_y: min_y = point.y() center.setX((max_x + min_x)/2) center.setY((max_y + min_y)/2) return center def show_rubber_band(self): """ Creates and shows a rubber band with the geometry of the mission """ if len(self.mission_track.find_waypoints_in_mission()) > 1: self.band = self.create_rubber_band() self.band.setToGeometry(self.ini_geom, self.layer) def hide_rubber_band(self): """ Hides and deletes the rubber band of the geometry of the mission """ if self.band: self.band.hide() self.band = None def rotate_and_project_band(self, rot_angle=0.0): """ Rebuilds the initial geometry of the mission rotated with the angle defined by rot_angle and it gets stored in the geometry of self.band :param rot_angle: Angle used to rotate the geometry """ ini_coords = self.ini_geom.asPolyline() end_coords = [] if len(ini_coords) > 1: dist = self.distance.measureLine(self.rot_center, ini_coords[0]) angle = self.distance.bearing(self.rot_center, ini_coords[0]) + rot_angle end_first_wp = endpoint(self.rot_center, dist, degrees(angle)) end_coords.append(end_first_wp) for i in range(1, len(ini_coords)): dist = self.distance.measureLine(ini_coords[i-1], ini_coords[i]) angle = self.distance.bearing(ini_coords[i-1], ini_coords[i]) + rot_angle end_c = endpoint(end_coords[i-1], dist, degrees(angle)) end_coords.append(end_c) end_band_geom = QgsGeometry().fromPolylineXY(end_coords) self.band.setToGeometry(end_band_geom, self.layer) def rotate_and_project_mission(self): """ Copy the changes from the rotated and projected rubber band to the geometry of the mission """ list_wp = self.band.asGeometry().asPolyline() if len(list_wp) > 1: for i in range(0, len(list_wp)): point = list_wp[i] self.mission_track.change_position(i, point) feature = next(self.layer.dataProvider().getFeatures()) self.layer.startEditing() self.layer.changeGeometry(feature.id(), self.band.asGeometry()) self.layer.commitChanges()
def by_seconds(self, seconds): """move by variable distance""" def iterations(distance, h): FIe1 = 0 LAMe1 = 0 FI = 100 LAM = 100 # iterations while fabs(FI - FIe1) > 0.0000000001 and fabs( LAM - LAMe1) > 0.0000000001: FI = FIe1 LAM = LAMe1 for i in range(0, int(ceil(distance / h))): kfi = [] klam = [] kazi = [] kfi.append( cos(azi[i]) / (a * (1 - (e2)) / (pow( (sqrt(1 - (e2) * pow(sin(fi[i]), 2))), 3)))) klam.append( sin(azi[i]) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i]), 2)))) * cos(fi[i]))) kazi.append( sin(azi[i]) * tan(fi[i]) / (a / (sqrt(1 - (e2) * pow(sin(fi[i]), 2))))) for j in range(1, 3): kfi.append( cos(azi[i] + kazi[j - 1] * h / 2) / (a * (1 - (e2)) / (pow( sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2)), 3)))) klam.append( sin(azi[i] + kazi[j - 1] * h / 2) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2)))) * cos(fi[i] + kfi[j - 1] * h / 2))) kazi.append( sin(azi[i] + kazi[j - 1] * h / 2) * tan(fi[i] + kfi[j - 1] * h / 2) / (a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2))))) kfi.append( cos(azi[i] + kazi[2] * h) / (a * (1 - (e2)) / (pow( sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2)), 3)))) klam.append( sin(azi[i] + kazi[2] * h) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2)))) * cos(fi[i] + kfi[2] * h))) kazi.append( sin(azi[i] + kazi[2] * h) * tan(fi[i] + kfi[2] * h) / (a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2))))) fi.append(fi[i] + (h / 6.0) * (kfi[0] + 2 * kfi[1] + 2 * kfi[2] + kfi[3])) lam.append(lam[i] + (h / 6.0) * (klam[0] + 2 * klam[1] + 2 * klam[2] + klam[3])) azi.append(azi[i] + (h / 6.0) * (kazi[0] + 2 * kazi[1] + 2 * kazi[2] + kazi[3])) FIe1 = fi[i + 1] LAMe1 = lam[i + 1] h = h / 2 fi[1:] = [] lam[1:] = [] azi[1:] = [] return FIe1, LAMe1 self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') beforeSec = header.split('Gtm_sec') numberOfSecColumn = beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if seconds > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveTime = 1 * seconds outline = 1 * line1 inline = line2.split(',') while moveTime > 0: # for case of more than 1 second if line2: line2 = line2.split(',') p1 = QgsPoint(float(line1[len(numberOfLonColumn) - 1]), float(line1[len(numberOfLatColumn) - 1])) p2 = QgsPoint(float(line2[len(numberOfLonColumn) - 1]), float(line2[len(numberOfLatColumn) - 1])) if p1 != p2: aziA = d.bearing(p1, p2) l = d.computeDistanceBearing(p1, p2)[0] if moveTime > ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): moveTime = moveTime - ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) elif moveTime != 0 and moveTime != ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): #first geodetic problem distance = l / ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) * moveTime h = distance / 2.0 fi = [ float(line1[len(numberOfLatColumn) - 1]) * pi / 180 ] lam = [ float(line1[len(numberOfLonColumn) - 1]) * pi / 180 ] azi = [aziA] FIe1, LAMe1 = iterations(distance, h) moveTime = 0 else: FIe1 = float(line2[len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line2[len(numberOfLonColumn) - 1]) * pi / 180 moveTime = 0 break else: if moveTime > ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): moveTime = moveTime - ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) else: FIe1 = float(line2[len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line2[len(numberOfLonColumn) - 1]) * pi / 180 moveTime = 0 break else: break line1 = 1 * line2 line2 = self.inputfile.readline() line1 = 1 * inline if moveTime == 0: outline[len(numberOfLatColumn) - 1] = str( FIe1 * 180 / pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn) - 1] = str(LAMe1 * 180 / pi) outline = ','.join(outline) self.outputfile.write(outline) else: break elif seconds < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') allSecs = (float(line[1][len(numberOfSecColumn) - 1]) - float(line[0][len(numberOfSecColumn) - 1])) i = 1 moveTime = 1 * seconds while fabs(moveTime) > allSecs: line.append(self.inputfile.readline().split(',')) i = i + 1 if line[len(line) - 1] == ['']: break allSecs = allSecs + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) while line[len(line) - 1] != ['']: allSecs = 0 for i in reversed(range(1, len(line))): allSecs = allSecs + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) if fabs(moveTime) <= allSecs: for x in range(i - 1): del line[0] break for i in reversed(range(len(line))): p1 = QgsPoint( float(line[i - 1][len(numberOfLonColumn) - 1]), float(line[i - 1][len(numberOfLatColumn) - 1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn) - 1]), float(line[i][len(numberOfLatColumn) - 1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.computeDistanceBearing(p1, p2)[0] if moveTime < -(float( line[i][len(numberOfSecColumn) - 1]) - float( line[i - 1][len(numberOfSecColumn) - 1])): moveTime = moveTime + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) elif moveTime != 0 and moveTime != -( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1]) ): #first geodetic problem distance = l / ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) * fabs(moveTime) h = distance / 2.0 fi = [ float(line[i][len(numberOfLatColumn) - 1]) * pi / 180 ] lam = [ float(line[i][len(numberOfLonColumn) - 1]) * pi / 180 ] azi = [aziA] FIe1, LAMe1 = iterations(distance, h) break else: FIe1 = float(line[i - 1][len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line[i - 1][len(numberOfLonColumn) - 1]) * pi / 180 break else: if moveTime < -(float( line[i][len(numberOfSecColumn) - 1]) - float( line[i - 1][len(numberOfSecColumn) - 1])): moveTime = moveTime + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) else: FIe1 = float(line[i - 1][len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line[i - 1][len(numberOfLonColumn) - 1]) * pi / 180 break outline = 1 * line[len(line) - 1] outline[len(numberOfLatColumn) - 1] = str( FIe1 * 180 / pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn) - 1] = str(LAMe1 * 180 / pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line) - 1] = line[len(line) - 1].split(',') moveTime = 1 * seconds else: while line1: self.outputfile.write(line1) line1 = self.inputfile.readline() self._close()
class EditTool(QgsMapTool): wp_clicked = pyqtSignal(int) def __init__(self, mission_track, canvas, msglog): QgsMapTool.__init__(self, canvas) self.setCursor(Qt.CrossCursor) self.mission_track = mission_track self.msglog = msglog self.dragging = False self.feature = None self.vertex = None self.startcoord = None self.layer = self.mission_track.get_mission_layer() logger.info(self.mission_track.get_mission_name()) self.rubber_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry) self.rubber_band.setWidth(2) self.rubber_band.setColor(QColor("green")) self.point_cursor_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry) self.point_cursor_band.setWidth(1) self.point_cursor_band.setLineStyle(Qt.DashLine) self.point_cursor_band.setColor(QColor(255, 0, 0, 100)) self.mid_point_band = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.mid_point_band.setColor(QColor(255, 0, 0, 100)) self.mid_point_band.setIconSize(18) self.rubber_band_points = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.rubber_band_points.setColor(QColor("green")) self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubber_band_points.setIconSize(10) self.mission_track.mission_changed.connect(self.update_rubber_bands) self.vertex_marker = QgsVertexMarker(self.canvas()) self.start_end_marker = StartEndMarker(canvas, self.mission_track.find_waypoints_in_mission(), QColor("green")) self.layer.startEditing() self.wp = [] self.mCtrl = False # handler for mission feature self.update_rubber_bands(0) crs = canvas.mapSettings().destinationCrs() self.distance_calc = QgsDistanceArea() self.distance_calc.setSourceCrs(crs, QgsProject.instance().transformContext()) self.distance_calc.setEllipsoid(crs.ellipsoidAcronym()) def update_rubber_bands(self, current_wp): self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.wp = self.mission_track.find_waypoints_in_mission() self.start_end_marker.update_markers(self.wp) if len(self.wp) > 0: for v in self.wp: pc = self.toLayerCoordinates(self.layer, QgsPointXY(v)) self.rubber_band.addPoint(pc) self.rubber_band_points.addPoint(pc) logger.debug("MISSION UPDATE: now we have {} waypoints".format(len(self.wp))) self.vertex_marker.setCenter(QgsPointXY(self.wp[current_wp].x(), self.wp[current_wp].y())) self.vertex_marker.setColor(QColor(25, 255, 0)) self.vertex_marker.setIconSize(7) self.vertex_marker.setIconType(QgsVertexMarker.ICON_X) # ICON_BOX, ICON_CROSS, ICON_X self.vertex_marker.setPenWidth(2) self.vertex_marker.show() self.set_geometry() else: self.vertex_marker.hide() def set_control_state(self, state): self.mCtrl = state def keyPressEvent(self, event): if event.key() == Qt.Key_Control and not self.dragging: self.mCtrl = True pos = self.canvas().mouseLastXY() if not self.find_on_feature(pos, self.calc_tolerance()): self.show_dist_and_bearing_to_point() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False pos = self.canvas().mouseLastXY() if not self.find_on_feature(pos, self.calc_tolerance()) and not self.dragging: self.show_dist_and_bearing_to_point() return def canvasDoubleClickEvent(self, event): self.canvasPressEvent(event) def canvasPressEvent(self, event): if self.dragging: self.canvasReleaseEvent(event) map_pt, layer_pt = self.transform_coordinates(event.pos()) tolerance = self.calc_tolerance() if not self.find_on_feature(event.pos(), tolerance): if event.button() == Qt.LeftButton: # we have clicked outside the track logger.debug("We have clicked outside the track") self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) if not self.mCtrl: # add step to mission at the end self.mission_track.add_step(len(self.wp), layer_pt) self.show_waypoint_distances(len(self.wp)-1) else: self.mission_track.add_step(0, layer_pt) self.show_waypoint_distances(0) else: logger.debug("We have clicked on the track") vertex = self.find_vertex_at(event.pos(), tolerance) if event.button() == Qt.LeftButton: if vertex is None: logger.debug("We have clicked between vertexs") # we have clicked in between vertex, add intermediate point initial_vertex = self.find_segment_at(event.pos()) # self.mission_track.add_step(initial_vertex + 1, layerPt) intersection = intersect_point_to_line(self.toLayerCoordinates(self.layer, event.pos()), QgsPointXY(self.wp[initial_vertex]), QgsPointXY(self.wp[initial_vertex + 1])) logger.debug("intersection point: {} {}".format(str(intersection.x()), str(intersection.y()))) logger.debug("{} {} {} {}".format(self.wp[initial_vertex].x(), self.wp[initial_vertex].y(), self.wp[initial_vertex + 1].x(), self.wp[initial_vertex + 1].y())) # layerPtIntersection = self.toLayerCoordinates(self.layer,intersection) self.mission_track.add_step(initial_vertex + 1, intersection) self.mid_point_band.reset(QgsWkbTypes.PointGeometry) self.show_waypoint_distances(initial_vertex+1) else: logger.debug("We have clicked on vertex {}".format(vertex)) # we have clicked on a vertex # Left click -> move vertex. self.dragging = True self.vertex = vertex self.startcoord = event.pos() # self.moveVertexTo(layerPt) elif event.button() == Qt.RightButton: if vertex is not None and not self.dragging: # Right click -> delete vertex. self.delete_vertex(vertex) if self.find_on_feature(event.pos(), tolerance): # If cursor still over track vertex = self.find_vertex_at(event.pos(), tolerance) if vertex is None: # Cursor is between vertexes self.show_mid_point(event.pos()) else: # Cursor is over a vertex self.show_waypoint_distances(vertex) else: self.show_dist_and_bearing_to_point() def transform_coordinates(self, canvas_pt): return (self.toMapCoordinates(canvas_pt), self.toLayerCoordinates(self.layer, canvas_pt)) def canvasMoveEvent(self, event): if self.dragging: self.move_vertex_to(self.toLayerCoordinates(self.layer, event.pos())) self.mission_track.hide_start_end_markers() self.vertex_marker.hide() self.start_end_marker.hide_markers() self.show_waypoint_distances(self.vertex) else: tolerance = self.calc_tolerance() if self.find_on_feature(event.pos(), tolerance): # if mouse is over the track self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) self.mid_point_band.reset(QgsWkbTypes.PointGeometry) vertex = self.find_vertex_at(event.pos(), tolerance) if vertex is None: # Cursor is between vertexes self.show_mid_point(event.pos()) else: # Cursor is over a vertex self.show_waypoint_distances(vertex) else: self.mid_point_band.reset(QgsWkbTypes.PointGeometry) self.show_dist_and_bearing_to_point() def show_dist_and_bearing_to_point(self): """ Finds distance and bearing from the last point (first if pressing ctrl) to the specified point and shows them in the message log. Also draws a line between the points. """ bearing = 0.0 self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) point = self.canvas().mouseLastXY() if len(self.wp) > 0: cursor_point = self.toMapCoordinates(point) if self.mCtrl: anchor_point = QgsPointXY(self.wp[0]) else: anchor_point = QgsPointXY(self.wp[len(self.wp) - 1]) self.point_cursor_band.addPoint(cursor_point) self.point_cursor_band.addPoint(anchor_point) distance = self.distance_calc.measureLine([anchor_point, cursor_point]) if distance != 0.0: bearing = self.distance_calc.bearing(anchor_point, cursor_point) self.msglog.logMessage("") if self.mCtrl: msg = "Distance to next point: " else: msg = "Distance to previous point: " self.msglog.logMessage(msg + "{:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)), "Distance and bearing", 0) else: self.msglog.logMessage("") def show_mid_point(self, cursor): """ Finds the projection of the cursor over the track and draws a circle in that point. Finds the distances between this projection point and the previous and next points in the mission and shows them in the message log. :param cursor: position to be projected over the track """ prev_vertex = self.find_segment_at(cursor) prev_point = QgsPointXY(self.wp[prev_vertex]) next_point = QgsPointXY(self.wp[prev_vertex + 1]) cursor_point = self.toMapCoordinates(cursor) intersection = intersect_point_to_line(cursor_point, prev_point, next_point) self.mid_point_band.addPoint(intersection) distance1 = self.distance_calc.measureLine([prev_point, intersection]) distance2 = self.distance_calc.measureLine([intersection, next_point]) self.msglog.logMessage("") self.msglog.logMessage("Distance to previous point: {:.3F} m. Distance to next point: {:.3F} m." .format(distance1, distance2), "Distance between points", 0) def show_waypoint_distances(self, vertex): """ Finds the distances to adjacent waypoints of vertex and shows them in the message log :param vertex: index of the waypoint from the mission """ curr_point = self.rubber_band_points.getPoint(QgsWkbTypes.PointGeometry, vertex) if vertex == 0: if len(self.wp) > 1: next_point = QgsPointXY(self.wp[vertex+1]) distance = self.distance_calc.measureLine([curr_point, next_point]) bearing = self.distance_calc.bearing(next_point, curr_point) msg = "Distance to next point: {:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)) else: msg = "" self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {}) ".format(vertex+1), "Vertex distances", 0) elif vertex == len(self.wp) - 1: prev_point = QgsPointXY(self.wp[vertex-1]) distance = self.distance_calc.measureLine([prev_point, curr_point]) bearing = self.distance_calc.bearing(prev_point, curr_point) msg = "Distance to previous point: {:.3F} m. Bearing: {:.3F} º.".format(distance, math.degrees(bearing)) self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0) else: prev_point = QgsPointXY(self.wp[vertex-1]) next_point = QgsPointXY(self.wp[vertex+1]) distance1 = self.distance_calc.measureLine(prev_point, curr_point) distance2 = self.distance_calc.measureLine(curr_point, next_point) msg = "Distance to previous point: {:.3F} m. Distance to next point: {:.3F} m."\ .format(distance1, distance2) self.msglog.logMessage("") self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0) def hide_point_cursor_band(self): """ Hides the rubber band drawn from last (or first) point to cursor """ self.point_cursor_band.reset(QgsWkbTypes.LineGeometry) def canvasReleaseEvent(self, event): if self.dragging and event.button() == Qt.LeftButton: self.dragging = False self.vertex_marker.show() mapPt, layerPt = self.transform_coordinates(event.pos()) # Check distance with initial point dist = math.sqrt( (self.startcoord.x() - event.pos().x()) ** 2 + (self.startcoord.y() - event.pos().y()) ** 2) tolerance = self.calc_tolerance() if dist > tolerance: self.move_vertex_to(layerPt) self.mission_track.change_position(self.vertex, layerPt) self.wp_clicked.emit(self.vertex) self.feature = None self.vertex = None self.layer.updateExtents() else: # If release point is the same, has been just a click self.move_vertex_to(self.toLayerCoordinates(self.layer, QgsPointXY(self.wp[self.vertex]))) self.wp_clicked.emit(self.vertex) self.feature = None self.vertex = None def calc_tolerance(self): """ Compute the tolerance on canvas :return: tolerance """ # 2% of tolerance width_tolerance = 0.02 * self.canvas().width() height_tolerance = 0.02 * self.canvas().height() if width_tolerance < height_tolerance: tolerance = width_tolerance else: tolerance = height_tolerance return tolerance def move_vertex_to(self, layerPt): """ Move current vertex to layerPt position. :param layerPt: layer point :type: QgsPointXY """ if len(self.wp) > 1: self.rubber_band.movePoint(self.vertex, layerPt) self.rubber_band_points.movePoint(self.vertex, layerPt) elif len(self.wp) == 1: # A rubber band with PointGeometry and only 1 point acts as if it had 2 points, we need to reset it in # order to move the point. self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.rubber_band_points.addPoint(layerPt) def delete_vertex(self, vertex): """ Delete step 'vertex'. :param vertex: step """ self.mission_track.remove_step(vertex) self.dragging = False self.vertex = None def find_on_feature(self, pos, tolerance): """ if clicked point has some segment at a smaller distance than tolerance means that we've clicked on the track :param pos: The point that we've clicked :param tolerance: The tolerance of pos :return: bool """ if len(self.wp) > 1: dist_to_segment = [] for v in range(0, len(self.wp) - 1): # convert layer coordinates to canvas coordinates a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1])) dist_to_segment.append( self.dist_to_segment(a1.x(), a1.y(), b1.x(), b1.y(), pos.x(), pos.y())) logger.debug("dist to segment: {}".format(dist_to_segment)) if dist_to_segment[v] < tolerance: return True return False else: # last waypoint vertex = self.find_vertex_at(pos, tolerance) if vertex is None: return False else: return True def find_segment_at(self, pos): """ get the segment that is closer to the clicked point and return its initial vertex :param pos: the point that we've clicked :return: initial vertex of the segment """ dist_to_segment = [] for v in range(0, len(self.wp) - 1): a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1])) dist_to_segment.append(self.dist_to_segment(a1.x(), a1.y(), b1.x(), b1.y(), pos.x(), pos.y())) vertex = dist_to_segment.index(min(dist_to_segment)) return vertex def find_vertex_at(self, pos, tolerance): """ get the vertex that is closer to the clicked point :param pos: The point that we've clicked :param tolerance: The tolerance of pos :return: vertex or None """ if len(self.wp) > 0: dist_to_vertex = [] logger.debug("tolerance {}".format(tolerance)) for v in range(0, len(self.wp)): a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) dist_to_vertex.append(math.sqrt((pos.x() - a1.x()) ** 2 + (pos.y() - a1.y()) ** 2)) logger.debug("dist to vertex: {}".format(dist_to_vertex)) vertex = dist_to_vertex.index(min(dist_to_vertex)) if min(dist_to_vertex) > tolerance: return None else: logger.debug("ON VERTEX") return vertex else: return None def dist_to_segment(self, ax, ay, bx, by, cx, cy): """ Computes the minimum distance between a point (cx, cy) and a line segment with endpoints (ax, ay) and (bx, by). :param ax: endpoint 1, x-coordinate :param ay: endpoint 1, y-coordinate :param bx: endpoint 2, x-coordinate :param by: endpoint 2, y-coordinate :param cx: point, x-coordinate :param cy: point, x-coordinate :return: minimum distance between point and line segment """ # calculate tolerance tolerance = self.calc_tolerance() # get distance between points c-a and c-b dist_to_a = math.sqrt((cx - ax) ** 2 + (cy - ay) ** 2) dist_to_b = math.sqrt((cx - bx) ** 2 + (cy - by) ** 2) # if distance to point a or distance to point b is smaller than tolerance, return -1 if (dist_to_a < tolerance) or (dist_to_b < tolerance): return -1 # if one coordinate are between a coordinates or b coordinates if is_between(ax, ay, bx, by, cx, cy): y = (by - ay) x = (bx - ax) # line defined by two points formula num = abs((y * cx) - (x * cy) + (bx * ay) - (by * ax)) den = math.sqrt(y ** 2 + x ** 2) dl = num / den return dl else: return tolerance + 1 def set_geometry(self): """ Save rubber band to geometry of the layer """ if self.layer.featureCount() == 0: # no feature yet created f = QgsFeature() if len(self.wp) == 1: f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: f.setGeometry(QgsGeometry.fromPolyline(self.wp)) # self.layer.dataProvider().addFeatures([f]) self.layer.addFeatures([f]) else: # mission feature present, edit geometry feats = self.layer.getFeatures() for f in feats: if len(self.wp) == 1: self.layer.changeGeometry(f.id(), QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: self.layer.changeGeometry(f.id(), QgsGeometry.fromPolyline(self.wp)) self.layer.commitChanges() self.layer.startEditing() def close_band(self): self.start_end_marker.close_markers() self.vertex_marker.hide() self.canvas().scene().removeItem(self.vertex_marker) self.vertex_marker = None self.mission_track.mission_changed.disconnect() self.layer.commitChanges() self.rubber_band.hide() self.mid_point_band.hide() self.rubber_band_points.hide() self.point_cursor_band.hide() self.canvas().scene().removeItem(self.rubber_band) self.canvas().scene().removeItem(self.mid_point_band) self.canvas().scene().removeItem(self.rubber_band_points) self.canvas().scene().removeItem(self.point_cursor_band) self.rubber_band = None self.mid_point_band = None self.rubber_band_points = None self.point_cursor_band = None self.msglog.logMessage("")
class SpiralLawnMower(object): def __init__(self): self.template_type = 'spiral_lawnmower' self.wp = list() self.mission = None self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') def get_mission_type(self): return self.template_type def get_mission(self): return self.mission def compute_tracks(self, area_points, track_spacing, num_across_tracks): """ Compute lawn-mower tracks in spiral pattern :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. :param track_spacing: desired space in meters between consecutive along tracks :param num_across_tracks: number of desired across tracks. They will be equally spaced through the area. :return: list of ordered waypoints of the lawn-mower trajectory in spiral pattern """ dist_along_track = self.distance.measureLine(area_points[0], area_points[1]) dist_across_track = self.distance.measureLine(area_points[1], area_points[2]) bearing_along_track = self.distance.bearing(area_points[0], area_points[1]) bearing_across_track = self.distance.bearing(area_points[1], area_points[2]) turn_track_dist = length_one_across_track = track_spacing num_along_tracks = math.ceil(dist_across_track / length_one_across_track) + 1 logger.debug("distAlongTrack: {}".format(dist_along_track)) logger.debug("distAcrossTrack: {}".format(dist_across_track)) logger.debug("bearingAlongTrack {}:".format(bearing_along_track)) logger.debug("bearingAcrossTrack {}:".format(bearing_across_track)) logger.debug("numAlongTrack: {}".format(num_along_tracks)) logger.debug("numAcrossTrack: {}".format(num_across_tracks)) logger.debug("lenghtOneAcrossTrack {}".format(length_one_across_track)) # Initialize with 2 first points current_wp = area_points[0] next_wp = area_points[1] reverse_direction_along = False # For changing direction of alternate along tracks wp_list = [current_wp] # Loop to generate all waypoints of along tracks for i in range(0, int(num_along_tracks / 2)): # The along track next_wp = self.distance.computeSpheroidProject(current_wp, dist_along_track, bearing_along_track) wp_list.append(next_wp) current_wp = next_wp # The across track (dist decremented) curr_dist_across_track = length_one_across_track * (num_along_tracks / 2 - 1) next_wp = self.distance.computeSpheroidProject(current_wp, curr_dist_across_track, bearing_across_track) wp_list.append(next_wp) current_wp = next_wp # The along track reverse direction next_wp = self.distance.computeSpheroidProject(current_wp, dist_along_track, bearing_along_track + math.pi) wp_list.append(next_wp) current_wp = next_wp # The across track reverse direction (dist decremented) curr_dist_across_track = curr_dist_across_track - length_one_across_track next_wp = self.distance.computeSpheroidProject(current_wp, curr_dist_across_track, bearing_across_track + math.pi) wp_list.append(next_wp) current_wp = next_wp if i == int(num_along_tracks / 2 - 1): next_wp = area_points[0] wp_list.append(next_wp) current_wp = next_wp if num_across_tracks > 0: dist_along_track_for_across = dist_along_track / (num_across_tracks + 1) # Distance across track after computing all the along tracks # (might not match with the across track distance defined on the area mission) real_dist_across_track = self.distance.measureLine(wp_list[0], wp_list[2]) next_wp = self.distance.computeSpheroidProject(current_wp, turn_track_dist, bearing_across_track + math.pi) reverse_direction_across = False # For changing direction of alternate across tracks for i in range(num_across_tracks * 2 + 1): wp_list.append(next_wp) current_wp = next_wp if i % 2 == 0: # Compute waypoint along track next_wp = self.distance.computeSpheroidProject(current_wp, dist_along_track_for_across, bearing_along_track + int(reverse_direction_along) * math.pi) else: # Compute waypoint across track next_wp = self.distance.computeSpheroidProject(current_wp, length_one_across_track * ( num_along_tracks - 1) + turn_track_dist, bearing_across_track + int(reverse_direction_across) * math.pi) reverse_direction_across = not reverse_direction_across return wp_list 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)
class MeasureMapTool(QgsMapToolEmitPoint): ''' MapTool for measuring distance and azimuth Display result as tooltip on the canvas ''' def __init__(self, canvas): ''' Constructor ''' self.canvas = canvas super(MeasureMapTool, self).__init__(self.canvas) self.canvas.destinationCrsChanged.connect(self.onCrsChange) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.onCrsChange() self.rubberBand = QgsRubberBand(self.canvas) self.rubberBand.setZValue(1e6) self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(1) self.reset() def reset(self): self.startPoint = self.endPoint = None self.rubberBand.reset() def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) def canvasReleaseEvent(self, e): self.startPoint = None self.reset() def canvasMoveEvent(self, e): if not self.startPoint: return self.endPoint = self.toMapCoordinates(e.pos()) self.rubberBand.setToGeometry( QgsGeometry.fromPolyline( [QgsPoint(self.startPoint), QgsPoint(self.endPoint)]), None) if self.startPoint != self.endPoint: dist = self.distArea.measureLine(self.startPoint, self.endPoint) bearing = self.distArea.bearing(self.startPoint, self.endPoint) * 180 / pi if bearing < 0: bearing += 360.0 text = u'{:.1f} m; {:.1f}\u00b0'.format(dist, bearing) QToolTip.showText(self.canvas.mapToGlobal(e.pos()), text, self.canvas) def activate(self): self.reset() super(MeasureMapTool, self).activate() def deactivate(self): self.reset() super(MeasureMapTool, self).deactivate() @pyqtSlot() def onCrsChange(self): ''' SLot called when the mapcanvas CRS is changed ''' crsDst = self.canvas.mapSettings().destinationCrs() self.distArea.setSourceCrs(crsDst, QgsProject.instance().transformContext())
class Rectangle: def __init__(self): self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') def get_rect_from_center(self, pc, p2, angle=0.0): """ Creates a rectangle from a center point, a corner point and an angle :param pc: center point of the geometry :param p2: a corner of the geometry :param angle: angle of the geometry, 0 by default. In radians :return: 4 points geometry """ if angle == 0: x_offset = abs(p2.x() - pc.x()) y_offset = abs(p2.y() - pc.y()) pt1 = QgsPointXY(pc.x() - x_offset, pc.y() - y_offset) pt2 = QgsPointXY(pc.x() - x_offset, pc.y() + y_offset) pt3 = QgsPointXY(pc.x() + x_offset, pc.y() + y_offset) pt4 = QgsPointXY(pc.x() + x_offset, pc.y() - y_offset) geom = QgsGeometry.fromPolygonXY([[pt1, pt2, pt3, pt4]]) else: x_offset = (cos(angle) * (p2.x() - pc.x()) + sin(angle) * (p2.y() - pc.y())) y_offset = -(-sin(angle) * (p2.x() - pc.x()) + cos(angle) * (p2.y() - pc.y())) pt1 = QgsPointXY(pc.x() - x_offset, pc.y() - y_offset) pt2 = QgsPointXY(pc.x() - x_offset, pc.y() + y_offset) pt3 = QgsPointXY(pc.x() + x_offset, pc.y() + y_offset) pt4 = QgsPointXY(pc.x() + x_offset, pc.y() - y_offset) geom = QgsGeometry.fromPolygonXY([[pt1, pt2, pt3, pt4]]) return geom def get_rect_rotated(self, geom, cp, ep=QgsPointXY(0, 0), ip=QgsPointXY(0, 0), delta=0): """ Rotates a geometry by some delta + the angle between 2 points and the center point of the geometry :param geom: geometry to be rotated :param cp: center point of the geometry :param ep: point marking the end of the rotation :param ip: point marking the beginning of the rotation :param delta: extra angle of rotation in radians :return: geometry rotated and total angle of rotation """ angle_1 = self.distance.bearing(cp, ep) angle_2 = self.distance.bearing(cp, ip) angle_rotation = delta + (angle_2 - angle_1) coords = [] ring = [] for i in geom.asPolygon(): for k in i: ini_point = QgsPointXY(k.x() - cp.x(), k.y() - cp.y()) end_point = rotate_point(ini_point, angle_rotation) p3 = QgsPointXY(cp.x() + end_point.x(), cp.y() + end_point.y()) ring.append(p3) coords.append(ring) ring = [] geom = QgsGeometry().fromPolygonXY(coords) return geom, angle_rotation def get_rect_by3_points(self, p1, p2, p3, length=0): angle_exist = self.distance.bearing(p1, p2) side = calc_is_collinear(p1, p2, p3) # check if x_p2 > x_p1 and inverse side if side == 0: return None if length == 0: length = self.distance.measureLine(p2, p3) p3 = self.distance.computeSpheroidProject( p2, length, angle_exist + radians(90) * side) p4 = self.distance.computeSpheroidProject( p1, length, angle_exist + radians(90) * side) geom = QgsGeometry.fromPolygonXY([[p1, p2, p3, p4]]) return geom def get_rect_projection(self, rect_geom, cp, x_length=0, y_length=0): """ Transforms the rectangle geometry to its projection on the real world, making all its angles 90º :param rect_geom: 4 point geometry :param cp: central point of the geometry :param x_length: distance between first and second points of the rect_geom :param y_length: distance between second and third points of the rect_geom :return: geometry projected to map """ if x_length == 0 and y_length == 0: proj_geom = self.get_rect_by3_points(rect_geom.asPolygon()[0][0], rect_geom.asPolygon()[0][1], rect_geom.asPolygon()[0][2]) else: point_two = endpoint( rect_geom.asPolygon()[0][0], x_length, degrees( self.distance.bearing(rect_geom.asPolygon()[0][0], rect_geom.asPolygon()[0][1]))) point_three = endpoint( rect_geom.asPolygon()[0][0], y_length, degrees( self.distance.bearing(rect_geom.asPolygon()[0][1], rect_geom.asPolygon()[0][3]))) proj_geom = self.get_rect_by3_points(rect_geom.asPolygon()[0][0], point_two, point_three, y_length) if proj_geom is not None: p1 = proj_geom.asPolygon()[0][0] p2 = proj_geom.asPolygon()[0][1] p3 = proj_geom.asPolygon()[0][2] p4 = proj_geom.asPolygon()[0][3] px = (p1.x() + p3.x()) / 2.0 py = (p1.y() + p3.y()) / 2.0 p1 = QgsPointXY(p1.x() - px + cp.x(), p1.y() - py + cp.y()) p2 = QgsPointXY(p2.x() - px + cp.x(), p2.y() - py + cp.y()) p3 = QgsPointXY(p3.x() - px + cp.x(), p3.y() - py + cp.y()) p4 = QgsPointXY(p4.x() - px + cp.x(), p4.y() - py + cp.y()) proj_geom = QgsGeometry.fromPolygonXY([[p1, p2, p3, p4]]) return proj_geom else: return rect_geom
class PositionMarker(QgsMapCanvasItem): ''' MapCanvasItem for showing the MobileItem on the MapCanvas Can have different appearences, fixed ones like corss, x or box or a userdefined shape. Can display also a label on the canvas ''' MIN_SIZE = 30 CIRLCE_SIZE = 30 def __init__(self, canvas, params={}): ''' Constructor :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface :param params: A dictionary defining all the properties of the position marker :type params: dictionary ''' self.canvas = canvas self.type = params.get('type', 'BOX').upper() self.size = int(params.get('size', 16)) self.showLabel = bool(params.get('showLabel', True)) s = (self.size - 1) / 2 self.length = float(params.get('length', 98.0)) self.width = float(params.get('width', 17.0)) self.offsetX = float(params.get('offsetX', 0.0)) self.offsetY = float(params.get('offsetY', 0.0)) self.shape = params.get('shape', ((0.0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.50), (-0.5, -0.3))) self.paintShape = QPolygonF([QPointF(-s, -s), QPointF(s, -s), QPointF(s, s), QPointF(-s, s)]) self.color = self.getColor(params.get('color', 'black')) self.fillColor = self.getColor(params.get('fillColor', 'lime')) self.defaultIcon = bool(params.get('defaultIcon', True)) self.defaultIconFilled = bool(params.get('defaultIconFilled', False)) self.paintCircle = False self.penWidth = int(params.get('penWidth', 1)) spw = s + self.penWidth + 1 self.bounding = QRectF(-spw, -spw, spw * 2, spw * 2) if self.type in ('CROSS', 'X'): self.penWidth = 5 self.trackLen = int(params.get('trackLength', 100)) self.trackColor = self.getColor(params.get('trackColor', self.fillColor)) self.track = deque() self.position = None self.heading = 0 self.northAlign = 0.0 super(PositionMarker, self).__init__(canvas) self.setZValue(int(params.get('zValue', 100))) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') if self.showLabel: self.label = MarkerLabel(self.canvas, params) self.label.setZValue(self.zValue() + 0.1) self.updateSize() def properties(self): return {'type': self.type, 'size': self.size, 'length': self.length, 'width': self.width, 'defaultIcon': self.defaultIcon, 'defaultIconFilled': self.defaultIconFilled, 'offsetX': self.offsetX, 'offsetY': self.offsetY, 'shape': self.shape, 'color': self.color.rgba(), 'fillColor': self.fillColor.rgba(), 'penWidth': self.penWidth, 'trackLength': self.trackLen, 'trackColor' : self.trackColor.rgba(), 'zValue': self.zValue(), 'showLabel': self.showLabel} def setMapPosition(self, pos): if self.position != pos: self.updateTrack() self.position = pos self.setPos(self.toCanvasCoordinates(self.position)) if self.showLabel: self.label.setMapPosition(pos) self.update() def newHeading(self, heading): if self.heading != heading: self.heading = heading self.setRotation(self.canvas.rotation() + self.heading - self.northAlign) self.update() def resetPosition(self): self.position = None if self.showLabel: self.label.resetPosition() def updatePosition(self): if self.position: self.prepareGeometryChange() self.updateSize() self.setPos(self.toCanvasCoordinates(self.position)) self.setRotation(self.canvas.rotation() + self.heading - self.northAlign) def updateMapMagnification(self): self.updatePosition() if self.showLabel: self.label.updatePosition() for tp in self.track: tp[0].updatePosition() def updateSize(self): if self.type != 'SHAPE': return s = self.canvas.mapSettings() self.distArea.setSourceCrs(s.destinationCrs(), QgsProject.instance().transformContext()) try: if self.position: p1 = self.position p = self.toMapCoordinates(self.position) p2 = self.toMapCoordinates(QPoint(p.x(), p.y() + 100.0)) else: p = self.canvas.viewport().rect().center() p1 = self.toMapCoordinates(p) p2 = self.toMapCoordinates(QPoint(p.x(), p.y() + 100)) lngth = self.distArea.measureLine(p1, p2) f = 100.0 / lngth self.northAlign = fmod(self.distArea.bearing(p2, p1) * 180.0 / pi + self.canvas.rotation(), 360.0) except Exception: f = s.outputDpi() / 0.0254 / s.scale() paintLength = max(self.length * f, self.MIN_SIZE) paintWidth = paintLength * self.width / self.length offsY = self.offsetX / self.length * paintLength offsX = self.offsetY / self.width * paintWidth self.paintShape.clear() if (self.length * f) < self.MIN_SIZE and self.defaultIcon: self.paintCircle = True self.bounding = QRectF(-self.CIRLCE_SIZE * 0.5, -self.CIRLCE_SIZE - 2, self.CIRLCE_SIZE, self.CIRLCE_SIZE * 1.5) else: self.paintCircle = False for v in self.shape: self.paintShape << QPointF(v[0] * paintWidth - offsX, v[1] * paintLength + offsY) self.bounding = self.paintShape.boundingRect() self.size = max(paintLength, paintWidth) def newTrackPoint(self, pos): tp = QgsVertexMarker(self.canvas) tp.setCenter(pos) tp.setIconType(QgsVertexMarker.ICON_CROSS) tp.setColor(self.trackColor) tp.setZValue(self.zValue() - 0.1) tp.setIconSize(3) tp.setPenWidth(3) return tp def updateTrack(self): if self.position and self.trackLen: if len(self.track) >= self.trackLen: tpr = self.track.popleft() self.canvas.scene().removeItem(tpr[0]) del(tpr) tp = self.newTrackPoint(self.position) self.track.append((tp, self.position)) def setVisible(self, visible): for tp in self.track: tp[0].setVisible(visible) QgsMapCanvasItem.setVisible(self, visible) if self.showLabel: self.label.setVisible(visible) def deleteTrack(self): for tp in self.track: self.canvas.scene().removeItem(tp[0]) self.track.clear() def setTrack(self, track): self.track.clear() for tp in track: tpn = self.newTrackPoint(tp) self.track.append((tpn, tp)) def paint(self, painter, xxx, xxx2): if not self.position: return s = (self.size - 1) / 2 pen = QPen(self.color) pen.setWidth(self.penWidth) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing, True) if self.type == 'CROSS': painter.drawLine(QLineF(-s, 0, s, 0)) painter.drawLine(QLineF(0, -s, 0, s)) elif self.type == 'X': painter.drawLine(QLineF(-s, -s, s, s)) painter.drawLine(QLineF(-s, s, s, -s)) elif self.type == 'BOX': brush = QBrush(self.fillColor) painter.setBrush(brush) painter.drawConvexPolygon(self.paintShape) elif self.type == 'SHAPE': if self.paintCircle: pen.setWidth(self.penWidth * 2) if self.defaultIconFilled: brush = QBrush(self.fillColor) painter.setBrush(brush) painter.setPen(pen) painter.drawEllipse(QPointF(0, 0), self.CIRLCE_SIZE * 0.4, self.CIRLCE_SIZE * 0.4) painter.drawLine(QLineF(0, -self.CIRLCE_SIZE * 0.4, 0, -self.CIRLCE_SIZE)) else: brush = QBrush(self.fillColor) painter.setBrush(brush) painter.drawConvexPolygon(self.paintShape) def boundingRect(self): return self.bounding def getColor(self, value): try: return QColor.fromRgba(int(value)) except ValueError: return QColor(value) def removeFromCanvas(self): self.deleteTrack() if self.showLabel: self.canvas.scene().removeItem(self.label) self.canvas.scene().removeItem(self)
class RectFromCenterFixedTool(QgsMapTool): msgbar = pyqtSignal(str) rbFinished = pyqtSignal(object) rb_reset_signal = pyqtSignal() def __init__(self, canvas, x_length=0.0, y_length=0.0): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.nbPoints = 0 self.rb = None self.mCtrl = None self.xc, self.yc, self.p2 = None, None, None self.distance = QgsDistanceArea() self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) self.distance.setEllipsoid('WGS84') self.x_length = x_length self.y_length = y_length self.diagonal = sqrt(self.x_length / 2 * self.x_length / 2 + self.y_length / 2 * self.y_length / 2) # our own fancy cursor self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #FF0000", "+ c #17a51a", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. . .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. . .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) self.curr_geom = None self.last_currpoint = None self.curr_angle = 0.0 self.total_angle = 0.0 self.rectangle = Rectangle() self.angle_ini_rot = 0.0 self.ini_geom = None def keyPressEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = True self.point_ini_rot = self.toMapCoordinates( self.canvas.mouseLastXY()) self.angle_ini_rot = self.curr_angle def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False if event.key() == Qt.Key_Escape: self.nbPoints = 0 self.xc, self.yc, self.p2 = None, None, None if self.rb: self.rb.reset(True) self.rb = None self.canvas.refresh() self.rb_reset_signal.emit() return def changegeomSRID(self, geom): layer = self.canvas.currentLayer() layerCRSSrsid = layer.crs().srsid() projectCRSSrsid = QgsMapSettings().destinationCrs().srsid() if layerCRSSrsid != projectCRSSrsid: g = QgsGeometry.fromPoint(geom) g.transform(QgsCoordinateTransform(projectCRSSrsid, layerCRSSrsid)) retPoint = g.asPoint() else: retPoint = geom return retPoint def canvasPressEvent(self, event): layer = self.canvas.currentLayer() if self.nbPoints == 0: color = QColor(255, 0, 0, 128) if self.rb: self.rb.reset() self.rb = None self.rb = QgsRubberBand(self.canvas, True) self.rb.setColor(color) self.rb.setWidth(1) self.canvas.refresh() self.rb_reset_signal.emit() point = self.toLayerCoordinates(layer, event.pos()) pointMap = self.toMapCoordinates(layer, point) if self.nbPoints == 0: self.xc = pointMap.x() self.yc = pointMap.y() if self.x_length != 0: self.diagonal = sqrt(self.x_length / 2 * self.x_length / 2 + self.y_length / 2 * self.y_length / 2) self.p2 = self.distance.computeSpheroidProject( QgsPointXY(self.xc, self.yc), self.diagonal, atan2(self.y_length / 2, self.x_length / 2)) else: self.x_bearing = pointMap.x() self.y_bearing = pointMap.y() self.bearing = self.distance.bearing(QgsPointXY(self.xc, self.yc), pointMap) self.nbPoints += 1 if self.nbPoints == 2: self.nbPoints = 0 self.xc, self.yc, self.p2 = None, None, None self.last_currpoint = None self.rbFinished.emit(self.curr_geom) self.curr_geom = None self.curr_angle = 0.0 self.total_angle = 0.0 if self.rb: return def canvasMoveEvent(self, event): if not self.rb or not self.xc or not self.yc: return currpoint = self.toMapCoordinates(event.pos()) self.msgbar.emit( "Hold Ctrl to adjust track orientation. Click when finished.") if not self.mCtrl: if self.last_currpoint is None: self.last_currpoint = self.p2 self.curr_geom = self.rectangle.get_rect_from_center( QgsPointXY(self.xc, self.yc), self.last_currpoint, ) self.ini_geom = self.curr_geom self.curr_geom = self.rectangle.get_rect_projection( self.curr_geom, QgsPointXY(self.xc, self.yc), self.x_length, self.y_length) elif self.ini_geom is not None: if self.last_currpoint is None: self.last_currpoint = currpoint self.curr_geom, self.curr_angle = self.rectangle.get_rect_rotated( self.ini_geom, QgsPointXY(self.xc, self.yc), currpoint, self.point_ini_rot, self.angle_ini_rot) self.last_currpoint = currpoint self.curr_geom = self.rectangle.get_rect_projection( self.curr_geom, QgsPointXY(self.xc, self.yc), self.x_length, self.y_length) if self.curr_geom is not None: self.rb.setToGeometry(self.curr_geom, None) def show_settings_warning(self): pass def activate(self): self.canvas.setCursor(self.cursor) def deactivate(self): self.nbPoints = 0 self.xc, self.yc, self.x_p2, self.y_p2 = None, None, None, None if self.rb: self.rb.reset(True) self.rb = None self.canvas.refresh() def is_zoom_tool(self): return False def is_transient(self): return False def is_edit_tool(self): return True
def by_seconds(self, seconds): """ shift by variable distance :param seconds: number of seconds used to calculate velocity """ self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') beforeSec = header.split('Gtm_sec') numberOfSecColumn = beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid(self.ellipsoid) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if seconds > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: if self.abort is True: break self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveTime = 1*seconds outline = 1*line1 inline = line2.split(',') while moveTime > 0: # for case of more than 1 second if line2: line2 = line2.split(',') p1 = QgsPointXY(float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p1, p2) l = d.measureLine(p1, p2) if moveTime > (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime = moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) elif moveTime != 0 and moveTime != (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): # first geodetic problem distance = l/(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1]))*moveTime h = distance/2.0 fi = [float( line1[len(numberOfLatColumn)-1])*pi/180] lam = [float( line1[len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( distance, a, e2, h, azi, fi, lam) moveTime = 0 else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 moveTime = 0 break else: if moveTime > (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime = moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 moveTime = 0 break else: break line1 = 1*line2 line2 = self.inputfile.readline() line1 = 1*inline if moveTime == 0: # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) else: break self.progress.emit(float(linePos)/float(self.length)*100) elif seconds < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') allSecs = (float(line[1][len(numberOfSecColumn)-1])-float(line[0][len(numberOfSecColumn)-1])) i = 1 moveTime = 1*seconds while fabs(moveTime) > allSecs: line.append(self.inputfile.readline().split(',')) i = i+1 if line[len(line)-1] == ['']: break allSecs = allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) while line[len(line)-1] != ['']: if self.abort is True: break allSecs = 0 for i in reversed(list(range(1, len(line)))): allSecs = allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) if fabs(moveTime) <= allSecs: for x in range(i-1): del line[0] break for i in reversed(list(range(len(line)))): p1 = QgsPointXY(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPointXY(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.measureLine(p1, p2) if moveTime < -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime = moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) elif moveTime != 0 and moveTime != -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): # first geodetic problem distance = l/(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1]))*fabs(moveTime) h = distance/2.0 fi = [float( line[i][len(numberOfLatColumn)-1])*pi/180] lam = [float( line[i][len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( distance, a, e2, h, azi, fi, lam) break else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveTime < -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime = moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline = 1*line[len(line)-1] # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1] = line[len(line)-1].split(',') moveTime = 1*seconds self.progress.emit( float(self.outputfile.tell()) / float(self.length) * 100) else: while line1: if self.abort is True: break self.outputfile.write(line1) line1 = self.inputfile.readline() self.progress.emit( float(self.outputfile.tell()) / float(self.length) * 100) self._close()
class MeasureAngleTool(QgsMapTool): finished = pyqtSignal() def __init__(self, canvas, msglog): super().__init__(canvas) self.canvas = canvas self.msglog = msglog self.start_point = self.middle_point = self.end_point = None self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubber_band.setColor(QColor(255, 0, 0, 100)) self.rubber_band.setWidth(3) 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(255, 0, 0, 150)) self.rubber_band_curve = QgsRubberBand(self.canvas) self.rubber_band_curve.setWidth(2) self.rubber_band_curve.setColor(QColor(255, 153, 0, 100)) crs = self.canvas.mapSettings().destinationCrs() self.distance_calc = QgsDistanceArea() self.distance_calc.setSourceCrs( crs, QgsProject.instance().transformContext()) self.distance_calc.setEllipsoid(crs.ellipsoidAcronym()) self.reset() def reset(self): self.msglog.logMessage("") self.start_point = self.middle_point = self.end_point = None self.rubber_band.reset(QgsWkbTypes.LineGeometry) self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.rubber_band_curve.reset() def canvasPressEvent(self, event): pass def canvasReleaseEvent(self, event): transform = self.canvas.getCoordinateTransform() point = transform.toMapCoordinates(event.pos().x(), event.pos().y()) if self.start_point and self.middle_point: angle_start_to_middle = self.distance_calc.bearing( self.middle_point, self.start_point) angle_end_to_middle = self.distance_calc.bearing( self.middle_point, point) angle = degrees(angle_end_to_middle - angle_start_to_middle) if angle < -180: angle = 360 + angle elif angle > 180: angle = angle - 360 anglemsg = QMessageBox(self.parent()) anglemsg.finished.connect(self.deactivate) anglemsg.setWindowTitle("Measure angle tool") anglemsg.setText("Angle: {:.3F} º".format(abs(angle))) anglemsg.exec() self.finish() elif self.start_point: self.middle_point = point self.rubber_band.addPoint(self.middle_point) self.rubber_band_points.addPoint(self.middle_point) else: self.start_point = point self.rubber_band.addPoint(self.start_point) self.rubber_band_points.addPoint(self.start_point) def canvasMoveEvent(self, e): if self.start_point and not self.end_point: transform = self.canvas.getCoordinateTransform() point = transform.toMapCoordinates(e.pos().x(), e.pos().y()) self.rubber_band.movePoint(point) if self.start_point and self.middle_point and not self.end_point: angle_start_to_middle = self.distance_calc.bearing( self.middle_point, self.start_point) angle_end_to_middle = self.distance_calc.bearing( self.middle_point, point) angle = degrees(angle_end_to_middle - angle_start_to_middle) if angle < -180: angle = 360 + angle elif angle > 180: angle = angle - 360 self.msglog.logMessage("") self.msglog.logMessage( "Current angle: {:.3F} º".format(abs(angle)), "Measure angle:", 0) self.rubber_band_curve.reset() # get the distance from center to point dist_mid_to_p = sqrt((point.x() - self.middle_point.x()) * (point.x() - self.middle_point.x()) + (point.y() - self.middle_point.y()) * (point.y() - self.middle_point.y())) dist_mid_to_start = sqrt( (self.start_point.x() - self.middle_point.x()) * (self.start_point.x() - self.middle_point.x()) + (self.start_point.y() - self.middle_point.y()) * (self.start_point.y() - self.middle_point.y())) # get angle angle_start = atan2(self.start_point.y() - self.middle_point.y(), self.start_point.x() - self.middle_point.x()) angle_p = atan2(point.y() - self.middle_point.y(), point.x() - self.middle_point.x()) # smaller distance if dist_mid_to_p < dist_mid_to_start: dist = dist_mid_to_p else: dist = dist_mid_to_start y_p = dist * sin(angle_p) x_p = dist * cos(angle_p) y_start = dist * sin(angle_start) x_start = dist * cos(angle_start) circular_ring = QgsCircularString() circular_ring = circular_ring.fromTwoPointsAndCenter( QgsPoint(self.middle_point.x() + x_start / 2, self.middle_point.y() + y_start / 2), QgsPoint(self.middle_point.x() + x_p / 2, self.middle_point.y() + y_p / 2), QgsPoint(self.middle_point.x(), self.middle_point.y()), True) circular_geometry = QgsGeometry(circular_ring) self.rubber_band_curve.addGeometry( circular_geometry, QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem.EpsgCrsId)) def keyPressEvent(self, event): """ When escape key is pressed, line is restarted """ if event.key() == Qt.Key_Escape: self.reset() def finish(self): self.reset() self.finished.emit()