Example #1
0
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,
    }
Example #2
0
    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()
Example #3
0
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()
Example #5
0
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"))
Example #6
0
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'))
Example #7
0
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()
Example #8
0
    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()
Example #9
0
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)
Example #14
0
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())
Example #15
0
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
Example #16
0
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)
Example #17
0
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
Example #18
0
    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()
Example #19
0
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()