def scale_bar(ax, lat, lon, length, location=(0.5, 0.05), linewidth=5): """ ax is the axes to draw the scalebar on. location is center of the scalebar in axis coordinates ie. 0.5 is the middle of the plot length is the length of the scalebar in km. linewidth is the thickness of the scalebar. """ import utm import cartopy.crs as ccrs #Projection in metres, need to change this to suit your own figure zone = utm.latlon_to_zone_number(lat,lon) if lat < 0: sh = True else: sh = False utm_c = ccrs.UTM(zone, southern_hemisphere=sh) #Get the extent of the plotted area in coordinates in metres x0, x1, y0, y1 = ax.get_extent(utm_c) #Turn the specified scalebar location into coordinates in metres sbcx, sbcy = x0 + (x1 - x0) * location[0], y0 + (y1 - y0) * location[1] #Generate the x coordinate for the ends of the scalebar for i in range(0,length): if i % 2 == 0: c = 'k' else: c = 'w' bar_xs = [sbcx - length * 500 + i * 1000, sbcx - length * 500 + (i+1) * 1000] #Plot the scalebar ax.plot(bar_xs, [sbcy, sbcy], transform=utm_c, color=c, linewidth=linewidth) #Plot the scalebar label sbcy = sbcy + (y1 - y0) * 0.02 ax.text(sbcx, sbcy, str(length) + ' km', color="black", transform=utm_c, fontweight="bold", horizontalalignment='center', verticalalignment='bottom', fontsize=15)
def read(self, filename, **kwargs): """ :param filename: ROI_PAC binary file :type filename: str :param par_file: Corresponding parameter (:file:`*rsc`) file. (optional) :type par_file: str :returns: Import dictionary :rtype: dict :raises: ImportError """ par_file = kwargs.pop('par_file', self._getParameterFile(filename)) par = self._parseParameterFile(par_file) nlines = int(par['FILE_LENGTH']) nrows = int(par['WIDTH']) wavelength = par['WAVELENGTH'] heading = par['HEADING_DEG'] lat_ref = par['LAT_REF1'] lon_ref = par['LON_REF1'] look_ref1 = par['LOOK_REF1'] look_ref2 = par['LOOK_REF2'] look_ref3 = par['LOOK_REF3'] look_ref4 = par['LOOK_REF4'] utm_zone_letter = utm.latitude_to_zone_letter( par['LAT_REF1']) utm_zone = utm.latlon_to_zone_number(par['LAT_REF1'], par['LON_REF1']) look = num.mean( num.array([look_ref1, look_ref2, look_ref3, look_ref4])) data = num.memmap(filename, dtype='<f4') data = data.reshape(nlines, nrows*2) displ = data[:, nrows:] displ[displ == -0.] = num.nan displ = displ / (4.*num.pi) * wavelength z_scale = par.get('Z_SCALE', 1.) z_offset = par.get('Z_OFFSET', 0.) displ += z_offset displ *= z_scale c = self.container c.displacement = displ c.theta = 90. - look c.phi = -heading - 180 c.meta.title = par.get('TITLE', 'None') c.meta.wavelength = par['WAVELENGTH'] c.bin_file = filename c.par_file = par_file c.frame.llLat = par['Y_FIRST'] + par['Y_STEP'] * nrows c.frame.llLon = par['X_FIRST'] c.frame.dLon = par['X_STEP'] c.frame.dLat = par['Y_STEP'] return self.container
def get_area_from_geometry(geom, src_crs="epsg:4326"): """Semi-accurately calculates the area for an input GeoJSON shape in km^2 by reprojecting it into a local UTM coordinate system. Args: geom (dict): A polygon (or multipolygon) in GeoJSON format src_crs (str, optional): The CRS of `geom`. Defaults to "epsg:4326". Raises: ValueError: This will be thrown if geom isn't formatted correctly, or is not a Polygon or MultiPolygon type Returns: area (float): The area of `geom` in km^2 """ # get one of the coordinates try: if geom["type"] == "Polygon": lon, lat = geom["coordinates"][0][0] elif geom["type"] == "MultiPolygon": lon, lat = geom["coordinates"][0][0][0] else: raise ValueError("Polygons and MultiPolygons only") except: raise ValueError("Input shape is not in the correct format") zone_number = utm.latlon_to_zone_number(lat, lon) hemisphere = "+north" if lat > 0 else "+south" dest_crs = "+proj=utm +zone=%d %s +datum=WGS84 +units=m +no_defs" % (zone_number, hemisphere) projected_geom = fiona.transform.transform_geom(src_crs, dest_crs, geom) area = shapely.geometry.shape(projected_geom).area / 1000000.0 # we calculate the area in square meters then convert to square kilometers return area
def utm_from_latlon(lats, lons): import utm import pyproj n = utm.latlon_to_zone_number(lats[0], lons[0]) l = utm.latitude_to_zone_letter(lats[0]) proj_src = pyproj.Proj('+proj=latlong') proj_dst = pyproj.Proj('+proj=utm +zone={}{}'.format(n, l)) return pyproj.transform(proj_src, proj_dst, lons, lats)
def unique(shape): ## Determine whether the administrative division is within a single UTM shape.to_crs('epsg:4326', inplace=True) shape['min'] = list(zip(shape.bounds['miny'], shape.bounds['minx'])) uniq_min = shape['min'].apply( lambda x: utm.latlon_to_zone_number(*x)).unique() shape.drop(columns=['min'], inplace=True) shape['max'] = list(zip(shape.bounds['maxy'], shape.bounds['maxx'])) uniq_max = shape['max'].apply( lambda x: utm.latlon_to_zone_number(*x)).unique() shape.drop(columns=['max'], inplace=True) uniq = np.unique(np.append(uniq_min, uniq_max)) if uniq.shape[0] > 1: print("ERROR: Cross-UTM input shapefile not yet supported.") sys.exit(0) return (uniq)
def get_area_from_geometry(geom, src_crs="epsg:4326"): if geom["type"] == "Polygon": lon, lat = geom["coordinates"][0][0] elif geom["type"] == "MultiPolygon": lon, lat = geom["coordinates"][0][0][0] else: raise ValueError("Polygons and MultiPolygons only") zone_number = utm.latlon_to_zone_number(lat, lon) hemisphere = "+north" if lat > 0 else "+south" dest_crs = "+proj=utm +zone=%d %s +datum=WGS84 +units=m +no_defs" % (zone_number, hemisphere) projected_geom = fiona.transform.transform_geom(src_crs, dest_crs, geom) area = shapely.geometry.shape(projected_geom).area / 1000000.0 # we calculate the area in square meters then convert to square kilometers return area
def utm_from_latlon(lats, lons): """ Fast function to convert latitudes, longitudes to UTM coordinates. """ import utm import pyproj n = utm.latlon_to_zone_number(lats[0], lons[0]) l = utm.latitude_to_zone_letter(lats[0]) proj_src = pyproj.Proj('+proj=latlong') srs = '+proj=utm +zone={}{}'.format(n, l) if l < 'N': # latitude bands in the southern hemisphere range from 'C' to 'M' srs += ' +south' proj_dst = pyproj.Proj(srs) return pyproj.transform(proj_src, proj_dst, lons, lats)
def get_utm_zone(x, y, epsg_in=4326): # type: (float, float, int) -> (int, str) """ Get UTM zone from a given coordinate. :param x: x-coordinate :param y: y-coordinate :param epsg_in: EPSG code of input coordinates :return: Tuple of UTM zone number as integer and Hemisphere as string """ if epsg_in != 4326: x, y = project_coords_epsg(x, y, epsg_in, 4326) zone_num = utm.latlon_to_zone_number(y, x) zone_letter = utm.latitude_to_zone_letter(y) zone_letter = 'N' if zone_letter > 'M' else 'S' return zone_num, zone_letter
def unique(shape): ## Determine whether the administrative division is within a single UTM shape.to_crs('epsg:4326', inplace=True) ## TODO: make this majority count an option ## and bring back cross-utm error as default behaviour uniq = shape.representative_point().apply( lambda p: utm.latlon_to_zone_number(p.y, p.x)).value_counts( ).idxmax() #if uniq.shape[0] > 1: # print("ERROR: Cross-UTM input shapefile not yet supported.") # sys.exit(0) return (uniq)
def read(self, filename, **kwargs): """ :param filename: ROI_PAC binary file :type filename: str :param par_file: Corresponding parameter (:file:`*rsc`) file. (optional) :type par_file: str :returns: Import dictionary :rtype: dict :raises: ImportError """ par_file = kwargs.pop('par_file', self._getParameterFile(filename)) par, geo_ref = self._parseParameterFile(par_file) nlines = int(par['FILE_LENGTH']) nrows = int(par['WIDTH']) wavelength = par['WAVELENGTH'] heading = par['HEADING_DEG'] if geo_ref == 'latlon': lat_ref = par['Y_FIRST'] lon_ref = par['X_FIRST'] elif geo_ref == 'all': lat_ref = par['LAT_REF3'] lon_ref = par['LON_REF3'] look_ref1 = par['LOOK_REF1'] look_ref2 = par['LOOK_REF2'] look_ref3 = par['LOOK_REF3'] look_ref4 = par['LOOK_REF4'] utm_zone_letter = utm.latitude_to_zone_letter(lat_ref) utm_zone = utm.latlon_to_zone_number(lat_ref, lon_ref) look = num.mean( num.array([look_ref1, look_ref2, look_ref3, look_ref4])) data = num.memmap(filename, dtype='<f4') data = data.reshape(nlines, nrows*2) displ = data[:, nrows:] displ = num.flipud(displ) displ[displ == -0.] = num.nan displ = displ / (4.*num.pi) * wavelength z_scale = par.get('Z_SCALE', 1.) z_offset = par.get('Z_OFFSET', 0.) displ += z_offset displ *= z_scale c = self.container c.displacement = displ c.theta = num.deg2rad(90. - look) c.phi = num.deg2rad(-heading + 180.) c.meta.title = par.get('TITLE', 'None') c.meta.wavelength = par['WAVELENGTH'] c.bin_file = filename c.par_file = par_file if geo_ref == 'all': if par['X_UNIT'] == 'meters': c.frame.spacing = 'meter' c.frame.dE = par['X_STEP'] c.frame.dN = -par['Y_STEP'] geo_ref = 'utm' elif par['X_UNIT'] == 'degree': c.frame.spacing = 'degree' geo_ref = 'latlon' elif geo_ref == 'latlon': self._log.info('Georeferencing is in Lat-Lon [degrees].') c.frame.spacing = 'degree' c.frame.llLat = par['Y_FIRST'] + par['Y_STEP'] * nrows c.frame.llLon = par['X_FIRST'] # c_utm_0 = utm.from_latlon(lat_ref, lon_ref) # c_utm_1 = utm.from_latlon(lat_ref + par['Y_STEP'], # lon_ref + par['X_STEP']) # c.frame.dE = c_utm_1[0] - c_utm_0[0] # c.frame.dN = abs(c_utm_1[1] - c_utm_0[1]) c.frame.dE = par['X_STEP'] c.frame.dN = -par['Y_STEP'] elif geo_ref == 'utm': self._log.info('Georeferencing is in UTM (zone %d%s)', utm_zone, utm_zone_letter) y_ll = par['Y_FIRST'] + par['Y_STEP'] * nrows c.frame.llLat, c.frame.llLon = utm.to_latlon( par['X_FIRST'], y_ll, utm_zone, zone_letter=utm_zone_letter) return self.container
def read(self, filename, **kwargs): """ :param filename: ROI_PAC binary file :type filename: str :param par_file: Corresponding parameter (:file:`*rsc`) file. (optional) :type par_file: str :returns: Import dictionary :rtype: dict :raises: ImportError """ par_file = kwargs.pop("par_file", self._getParameterFile(filename)) par, geo_ref = self._parseParameterFile(par_file) nlines = int(par["FILE_LENGTH"]) ncols = int(par["WIDTH"]) wavelength = par["WAVELENGTH"] heading = par["HEADING_DEG"] if geo_ref == "latlon": lat_ref = par["Y_FIRST"] lon_ref = par["X_FIRST"] elif geo_ref == "all": lat_ref = par["LAT_REF3"] lon_ref = par["LON_REF3"] look_ref1 = par["LOOK_REF1"] look_ref2 = par["LOOK_REF2"] look_ref3 = par["LOOK_REF3"] look_ref4 = par["LOOK_REF4"] utm_zone_letter = utm.latitude_to_zone_letter(lat_ref) utm_zone = utm.latlon_to_zone_number(lat_ref, lon_ref) look = num.mean(num.array([look_ref1, look_ref2, look_ref3, look_ref4])) data = num.memmap(filename, dtype="<f4") data = data.reshape(nlines, ncols * 2) displ = data[:, ncols:] displ = num.flipud(displ) displ[displ == -0.0] = num.nan displ = displ / (4.0 * num.pi) * wavelength z_scale = par.get("Z_SCALE", 1.0) z_offset = par.get("Z_OFFSET", 0.0) displ += z_offset displ *= z_scale container = self.container container.displacement = displ container.theta = num.deg2rad(90.0 - look) container.phi = num.deg2rad(-heading + 180.0) container.meta.title = par.get("TITLE", "None") container.meta.wavelength = par["WAVELENGTH"] container.bin_file = filename container.par_file = par_file if geo_ref == "all": if par["X_UNIT"] == "meters": container.frame.spacing = "meter" container.frame.dE = par["X_STEP"] container.frame.dN = -par["Y_STEP"] geo_ref = "utm" elif par["X_UNIT"] == "degree": container.frame.spacing = "degree" geo_ref = "latlon" elif geo_ref == "latlon": self._log.info("Georeferencing is in Lat-Lon [degrees].") container.frame.spacing = "degree" container.frame.llLat = par["Y_FIRST"] + par["Y_STEP"] * nlines container.frame.llLon = par["X_FIRST"] # c_utm_0 = utm.from_latlon(lat_ref, lon_ref) # c_utm_1 = utm.from_latlon(lat_ref + par['Y_STEP'], # lon_ref + par['X_STEP']) # c.frame.dE = c_utm_1[0] - c_utm_0[0] # c.frame.dN = abs(c_utm_1[1] - c_utm_0[1]) container.frame.dE = par["X_STEP"] container.frame.dN = -par["Y_STEP"] elif geo_ref == "utm": self._log.info("Georeferencing is in UTM (zone %d%s)", utm_zone, utm_zone_letter) y_ll = par["Y_FIRST"] + par["Y_STEP"] * nlines container.frame.llLat, container.frame.llLon = utm.to_latlon( par["X_FIRST"], y_ll, utm_zone, zone_letter=utm_zone_letter) return self.container
# projection example # The answer might be helpful for others so I have posted my solution. I found pyproj works better then utm. In pyproj we can specify utm zone. # import pyproj from pyproj import Proj from pprint import pprint from utm import latlon_to_zone_number longs = [16.01783828, 17.0086323, 16.4784] lats = [48.09774797, 48.55559181, 48.231] zone_number = latlon_to_zone_number(lats[0], longs[1]) pprint(f'zone number: {zone_number}') pprint(f'longitudes: {longs}, latitudes: {lats}') projection_31286_adapted = "+proj=tmerc +lat_0=0 +lon_0=16.33333333333333 +k=1 +x_0=+500000 +y_0=0 +ellps=bessel +towgs84=577.326,90.129,463.919,5.137,1.474,5.297,2.4232 +units=m +no_defs" epsg = 31286 myProj = Proj(projection_31286_adapted) eastings, northings = myProj(longs, lats) pprint(f'eastings: {eastings}, northings: {northings}') eastings_crs = [575782.1956641411, 648215.3421904881] northings_crs = [5327665.617543304, 5380002.786198429] pprint(f'crs transform') pprint(f'eastings crs: {eastings_crs}, northings crs {northings_crs}') ''' 0 POINT (16.01783828 48.09774797) 1 POINT (17.0086323 48.55559181) 2018-12-14 12:11:21,086 - INFO - geometry 0 POINT (575782.1956641411 5327665.617543304) 1 POINT (648215.3421904881 5380002.786198429)
def zonestring_from_lonlat(lon, lat): import utm n = utm.latlon_to_zone_number(lat, lon) l = utm.latitude_to_zone_letter(lat) s = "%d%s" % (n, l) return s
def aoi_info_from_geotiff_gt(ref_filename, gt_filename, padding=0.0, height_guard=[-5, +5]): ''' aoi_from_gt Returns an aoi from an image and a gt padding: relative to the size the gt region (e.g. 0.1 adds a 10% of the extension of the region on the four boundaries) ''' # get the dimensions of the first image width, height, pixel_dim = s2p.common.image_size_gdal(ref_filename) # get the rpc of the first image ref_image_rpc = rpcm.rpc_from_geotiff(ref_filename) # get the localization of the center of the image lon_center, lat_center = ref_image_rpc.localization( width // 2, height // 2, 0) zone_number = utm.latlon_to_zone_number(lat_center, lon_center) zone_letter = utm.latitude_to_zone_letter(lat_center) # Build the AOI of the GT ------------------------------ gt_metadata = readGTIFFmeta(gt_filename) bounding_box = gt_metadata[1] gt_min_easting = bounding_box.left gt_max_easting = bounding_box.right gt_min_northing = bounding_box.bottom gt_max_northing = bounding_box.top # padding gt_easting_extension = gt_max_easting - gt_min_easting gt_northing_extension = gt_max_northing - gt_min_northing gt_min_easting -= padding * gt_easting_extension gt_max_easting += padding * gt_easting_extension gt_min_northing -= padding * gt_northing_extension gt_max_northing += padding * gt_northing_extension # update the extension gt_easting_extension = gt_max_easting - gt_min_easting gt_northing_extension = gt_max_northing - gt_min_northing # convert easting, northing to lon,lat gt_min_lat, gt_min_lon = utm.to_latlon(gt_min_easting, gt_min_northing, zone_number, zone_letter) gt_max_lat, gt_max_lon = utm.to_latlon(gt_max_easting, gt_max_northing, zone_number, zone_letter) zone_hemisphere = 'N' if gt_min_lat > 0 else 'S' aoi = { 'coordinates': [[[gt_min_lon, gt_min_lat], [gt_min_lon, gt_max_lat], [gt_max_lon, gt_max_lat], [gt_max_lon, gt_min_lat], [gt_min_lon, gt_min_lat]]], 'type': 'Polygon' } utm_bbx = [ gt_min_easting, gt_max_easting, gt_min_northing, gt_max_northing ] lonlat_bbx = [gt_min_lon, gt_max_lon, gt_min_lat, gt_max_lat] # get min and max height from the gt image gt = s2p.common.gdal_read_as_array_with_nans(gt_filename) min_height, max_height = robust_image_min_max(gt) # add height guard min_height += height_guard[0] max_height += height_guard[1] return aoi, min_height, max_height, zone_hemisphere, zone_letter, zone_number, utm_bbx, lonlat_bbx
def convert_to_latlon(self, zone: LatLon): zone_number = latlon_to_zone_number(zone.lat, zone.lon) zone_letter = latitude_to_zone_letter(zone.lat) lat, lon = to_latlon(self.east, self.north, zone_number, zone_letter) return LatLon(lat, lon)
def get_grid_latitudes_longitudes_from_aoi(aoi, resolution=1, **kwargs): r""" get_grid_latitudes_longitudes_from_aoi Returns the arrays of latitudes and longitudes for a certain grid resolution on the aoi . Parameters ---------- aoi : dict with 'coordinates' key Area of interest (a rectangle is expected) resolution : double Resolution of the grid. Defaults to 1 (meter) **kwargs Arbitrary optional keyword argument. grid_shape : tuple or list or array of two integers defining the grid shape (rows (latitudes), cols (longitudes)) This parameter overrides resolution Returns ------- latitudes: 1D numpy array Array of latitudes of the grid longitudes: 1D numpy array Array of longitudes of the grid """ min_easting, max_easting, min_northing, max_northing = utils.utm_bounding_box_from_lonlat_aoi( aoi) if 'grid_shape' in kwargs.keys(): m, n = kwargs.get('grid_shape') latitudes = np.arange( start=np.min(np.array(aoi['coordinates'])[0, :, 1]), stop=np.max(np.array(aoi['coordinates'])[0, :, 1]), step=(np.max(np.array(aoi['coordinates'])[0, :, 1]) - np.min(np.array(aoi['coordinates'])[0, :, 1])) / m) longitudes = np.arange( start=np.min(np.array(aoi['coordinates'])[0, :, 0]), stop=np.max(np.array(aoi['coordinates'])[0, :, 0]), step=(np.max(np.array(aoi['coordinates'])[0, :, 0]) - np.min(np.array(aoi['coordinates'])[0, :, 0])) / n) else: Northings = np.arange(min_northing, max_northing, resolution) Eastings = np.arange(min_easting, max_easting, resolution) zone_number = utm.latlon_to_zone_number(aoi['coordinates'][0][0][1], aoi['coordinates'][0][0][0]) zone_letter = utm.latitude_to_zone_letter(aoi['coordinates'][0][0][1]) latitudes = [ utm.to_latlon(Eastings[0], Northings[i], zone_number, zone_letter)[0] for i in range(len(Northings)) ] longitudes = [ utm.to_latlon(Eastings[i], Northings[0], zone_number, zone_letter)[1] for i in range(len(Eastings)) ] latitudes = np.array(latitudes) longitudes = np.array(longitudes) return latitudes, longitudes