def getutmzoneshift(self, e, n): ''' Given UTM easting and northing values, check if they fall outside the reference point's zone boundary. Return the UTM coordinates in a different zone and the new zone if they do. Zone lettering is only changed when the reference point is in the opposite hemisphere. ''' zone = self.refutm[0] (rlat, rlon, ralt) = self.refgeo if e > 834000 or e < 166000: num_zones = (int(e) - 166000) / (utm.R / 10) # estimate number of zones to shift, E (positive) or W (negative) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) # after >3 zones away from refpt, the above estimate won't work # (the above estimate could be improved) if not 100000 <= (e - xshift) < 1000000: # move one more zone away num_zones = (abs(num_zones) + 1) * (abs(num_zones) / num_zones) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) e = e - xshift zone = (zonen2, zonel2) if n < 0: # refpt in northern hemisphere and we crossed south of equator n += 10000000 zone = (zone[0], 'M') elif n > 10000000: # refpt in southern hemisphere and we crossed north of equator n -= 10000000 zone = (zone[0], 'N') return (e, n, zone)
def getutmzoneshift(self, e, n): ''' Given UTM easting and northing values, check if they fall outside the reference point's zone boundary. Return the UTM coordinates in a different zone and the new zone if they do. Zone lettering is only changed when the reference point is in the opposite hemisphere. ''' zone = self.refutm[0] (rlat, rlon, ralt) = self.refgeo if e > 834000 or e < 166000: num_zones = (int(e) - 166000) / (utm.R/10) # estimate number of zones to shift, E (positive) or W (negative) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) # after >3 zones away from refpt, the above estimate won't work # (the above estimate could be improved) if not 100000 <= (e - xshift) < 1000000: # move one more zone away num_zones = (abs(num_zones)+1) * (abs(num_zones)/num_zones) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) e = e - xshift zone = (zonen2, zonel2) if n < 0: # refpt in northern hemisphere and we crossed south of equator n += 10000000 zone = (zone[0], 'M') elif n > 10000000: # refpt in southern hemisphere and we crossed north of equator n -= 10000000 zone = (zone[0], 'N') return (e, n, zone)
def geteastingshift(self, zonen, zonel): """ If the lat, lon coordinates being converted are located in a different UTM zone than the canvas reference point, the UTM meters may need to be shifted. This picks a reference point in the same longitudinal band (UTM zone number) as the provided zone, to calculate the shift in meters for the x coordinate. :param zonen: zonen :param zonel: zone1 :return: the x shift value """ rzonen = int(self.refutm[0][0]) # same zone number, no x shift required if zonen == rzonen: return None z = (zonen, zonel) # x shift already calculated, cached if z in self.zoneshifts and self.zoneshifts[z][0] is not None: return self.zoneshifts[z][0] rlat, rlon, _ralt = self.refgeo # ea. zone is 6deg band lon2 = rlon + 6 * (zonen - rzonen) # ignore northing e2, _n2, _zonen2, _zonel2 = utm.from_latlon(rlat, lon2) # NOTE: great circle distance used here, not reference ellipsoid! xshift = utm.haversine(rlon, rlat, lon2, rlat) - e2 # cache the return value yshift = None if z in self.zoneshifts: yshift = self.zoneshifts[z][1] self.zoneshifts[z] = (xshift, yshift) return xshift
def getxyz(self, lat, lon, alt): """ Given latitude, longitude, and altitude location data, convert them to (x, y, z) Cartesian coordinates based on the configured reference point and scale. Lat/lon is converted to UTM meter coordinates, UTM zones are accounted for, and the scale turns meters to pixels. :param lat: latitude :param lon: longitude :param alt: altitude :return: converted x, y, z coordinates :rtype: tuple """ # convert lat/lon to UTM coordinates in meters e, n, zonen, zonel = utm.from_latlon(lat, lon) _rlat, _rlon, ralt = self.refgeo xshift = self.geteastingshift(zonen, zonel) if xshift is None: xm = e - self.refutm[1] else: xm = e + xshift yshift = self.getnorthingshift(zonen, zonel) if yshift is None: ym = n - self.refutm[2] else: ym = n + yshift zm = alt - ralt # shift (x,y,z) over to reference point (x,y,z) x = self.m2px(xm) + self.refxyz[0] y = -(self.m2px(ym) + self.refxyz[1]) z = self.m2px(zm) + self.refxyz[2] return x, y, z
def getnorthingshift(self, zonen, zonel): ''' If the lat, lon coordinates being converted are located in a different UTM zone than the canvas reference point, the UTM meters may need to be shifted. This picks a reference point in the same latitude band (UTM zone letter) as the provided zone, to calculate the shift in meters for the y coordinate. ''' rzonel = self.refutm[0][1] if zonel == rzonel: return None # same zone letter, no y shift required z = (zonen, zonel) if z in self.zoneshifts and self.zoneshifts[z][1] is not None: return self.zoneshifts[z][1] # y shift already calculated, cached (rlat, rlon, ralt) = self.refgeo # zonemap is used to calculate degrees difference between zone letters latshift = self.zonemap[zonel] - self.zonemap[rzonel] lat2 = rlat + latshift # ea. latitude band is 8deg high (e2, n2, zonen2, zonel2) = utm.from_latlon(lat2, rlon) # NOTE: great circle distance used here, not reference ellipsoid yshift = -(utm.haversine(rlon, rlat, rlon, lat2) + n2) # cache the return value xshift = None if z in self.zoneshifts: xshift = self.zoneshifts[z][0] self.zoneshifts[z] = (xshift, yshift) return yshift
def geteastingshift(self, zonen, zonel): ''' If the lat, lon coordinates being converted are located in a different UTM zone than the canvas reference point, the UTM meters may need to be shifted. This picks a reference point in the same longitudinal band (UTM zone number) as the provided zone, to calculate the shift in meters for the x coordinate. ''' rzonen = int(self.refutm[0][0]) if zonen == rzonen: return None # same zone number, no x shift required z = (zonen, zonel) if z in self.zoneshifts and self.zoneshifts[z][0] is not None: return self.zoneshifts[z][0] # x shift already calculated, cached (rlat, rlon, ralt) = self.refgeo lon2 = rlon + 6*(zonen - rzonen) # ea. zone is 6deg band (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, lon2) # ignore northing # NOTE: great circle distance used here, not reference ellipsoid! xshift = utm.haversine(rlon, rlat, lon2, rlat) - e2 # cache the return value yshift = None if z in self.zoneshifts: yshift = self.zoneshifts[z][1] self.zoneshifts[z] = (xshift, yshift) return xshift
def getxyz(self, lat, lon, alt): ''' Given latitude, longitude, and altitude location data, convert them to (x, y, z) Cartesian coordinates based on the configured reference point and scale. Lat/lon is converted to UTM meter coordinates, UTM zones are accounted for, and the scale turns meters to pixels. ''' # convert lat/lon to UTM coordinates in meters (e, n, zonen, zonel) = utm.from_latlon(lat, lon) (rlat, rlon, ralt) = self.refgeo xshift = self.geteastingshift(zonen, zonel) if xshift is None: xm = e - self.refutm[1] else: xm = e + xshift yshift = self.getnorthingshift(zonen, zonel) if yshift is None: ym = n - self.refutm[2] else: ym = n + yshift zm = alt - ralt # shift (x,y,z) over to reference point (x,y,z) x = self.m2px(xm) + self.refxyz[0] y = -(self.m2px(ym) + self.refxyz[1]) z = self.m2px(zm) + self.refxyz[2] return (x, y, z)
def getxyz(self, lat, lon, alt): ''' Given latitude, longitude, and altitude location data, convert them to (x, y, z) Cartesian coordinates based on the configured reference point and scale. Lat/lon is converted to UTM meter coordinates, UTM zones are accounted for, and the scale turns meters to pixels. ''' # convert lat/lon to UTM coordinates in meters (e, n, zonen, zonel) = utm.from_latlon(lat, lon) (rlat, rlon, ralt) = self.refgeo xshift = self.geteastingshift(zonen, zonel) if xshift is None: xm = e - self.refutm[1] else: xm = e + xshift yshift = self.getnorthingshift(zonen, zonel) if yshift is None: ym = n - self.refutm[2] else: ym = n + yshift zm = alt - ralt # shift (x,y,z) over to reference point (x,y,z) x = self.m2px(xm) + self.refxyz[0] y = -(self.m2px(ym) + self.refxyz[1]) z = self.m2px(zm) + self.refxyz[2] #return (x, y, z) #Note: For some reason the coordinate conversion seems to be off #for the y axix by an amount that depends on the refgeo. No idea why. return (x, y + 3, z)
def setrefgeo(self, lat, lon, alt): ''' Record the geographical reference point decimal (lat, lon, alt) and convert and store its UTM equivalent for later use. ''' self.refgeo = (lat, lon, alt) # easting, northing, zone (e, n, zonen, zonel) = utm.from_latlon(lat, lon) self.refutm = ( (zonen, zonel), e, n, alt)
def setrefgeo(self, lat, lon, alt): ''' Record the geographical reference point decimal (lat, lon, alt) and convert and store its UTM equivalent for later use. ''' self.refgeo = (lat, lon, alt) # easting, northing, zone (e, n, zonen, zonel) = utm.from_latlon(lat, lon) self.refutm = ((zonen, zonel), e, n, alt)
def setrefgeo(self, lat, lon, alt): """ Record the geographical reference point decimal (lat, lon, alt) and convert and store its UTM equivalent for later use. :param lat: latitude :param lon: longitude :param alt: altitude :return: nothing """ self.refgeo = (lat, lon, alt) # easting, northing, zone e, n, zonen, zonel = utm.from_latlon(lat, lon) self.refutm = ((zonen, zonel), e, n, alt)