:py:mod:`gnome.utilities.projections` ===================================== .. py:module:: gnome.utilities.projections .. autoapi-nested-parse:: Module to hold classes and supporting code for projections used in GNOME. Only: * no projection * geo-projection (just scaling to pixels) * a simple "flat earth" projection for Also a bit of code for scaling lat-long to meters, etc. Used by map_canvas code and map code. NOTE: all coordinates are takes as (lon, lat, depth) even though depth is always ignored Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: gnome.utilities.projections.NoProjection gnome.utilities.projections.GeoProjection gnome.utilities.projections.FlatEarthProjection gnome.utilities.projections.RectangularGridProjection gnome.utilities.projections.RegularGridProjection Functions ~~~~~~~~~ .. autoapisummary:: gnome.utilities.projections.to_2d_coords .. py:function:: to_2d_coords(coords) utility function to take whatever the heck someone may pass in for coordinates and make it an Nx2 array :param input: the input coordinates. they should be one of: a (lon, lat) pair a (lon, lat, depth) triple a Nx2 array-like object of (lon,lat) pairs a Nx3 array-like object of (lon, lat, depth) triples The depth is ignored in all cases This is probably overly convenient, but the legacy is there... .. py:class:: NoProjection(name=None, _appearance=None, *args, **kwargs) Bases: :py:obj:`gnome.gnomeobject.GnomeId` This is do-nothing projection class -- returns what it gets. It optionally rounds down to integer (pixel) coordinates used for testing, primarily, and as a definition of the interface .. py:property:: bounding_box .. py:attribute:: _schema .. py:method:: set_scale(bounding_box, image_size=None) Does nothing .. py:method:: to_pixel(coords, asint=False) returns the same (lon, lat) coords, but as an np.array, if they aren't already :param coords: The coords to project :type coords: Nx3 numpy array or compatible sequence (lon, lat, depth) :param asint: Flag to set whether to convert to a integer or not default is to leave it as the same type it came in, so you can have fractional pixels .. py:method:: to_pixel_2D(coords, asint=False) :abstractmethod: same as to_pixel, but expects only (lon, lat) coords as input. :param coords: The coords to project :type coords: Nx2 numpy array or compatible sequence (lon, lat) :param asint: flag to set whether to convert to a integer or not default is to leave it as the same type it came in, so you can have fractional pixels .. py:method:: to_lonlat(coords) returns the same coords, but as a np.array of float64, if they aren't already .. py:class:: GeoProjection(bounding_box=None, image_size=None, *args, **kwargs) Bases: :py:obj:`gnome.gnomeobject.GnomeId` This acts as the base class for other projections This one doesn't really project, but does convert to pixel coords i.e. "geo-coordinates" Create a new projection Projection(bounding_box, image_size) :param bounding_box: The bounding box of the map :type bounding_box: Struct of the form:: ((min_long, min_lat), (max_lon, max_lat)) or a BoundingBox Object :param image_size: The size of the map image :type image_size: Struct of the form (width, height) .. py:property:: bounding_box .. py:attribute:: _schema .. py:method:: __eq__(other) provide an equality check for checking saved state of renderers, etc .. py:method:: __ne__(other) Return self!=value. .. py:method:: set_scale(bounding_box, image_size=None) Set the scaling, etc. of the projection This should be called whenever the bounding box of the map, or the size of the image is changed :param bounding_box: bounding box of the visual portion of the map :type bounding_box: Struct of the form: ((min_long, min_lat), (max_long, max_lat)) :param image_size=None: The size of the image that will be drawn to. if not given, the previous size will be used. .. py:method:: to_pixel(coords, asint=False) Converts input coordinates to pixel coords :param coords: An array of coordinates :type coords: Sequence of NX3 :: ((long1, lat1, z1), (long2, lat2, z2), (long3, lat3, z3), ) (z is ignored, and there is no z in the returned array) :returns: The pixel (x, y) coords as a similar Nx2 array of integer (using the y = 0 at the top, and y increasing down) NOTE: The values between the minimum of a pixel value to less than the max of a pixel range are in that pixel, so a point exactly at the minimum of the bounding box will be in the zeroth pixel, but a point exactly at the max of the bounding box will be considered outside the map .. py:method:: to_pixel_2D(coords, asint=False) :abstractmethod: # Fixme: depreciated, as we have to_2d_coords .. py:method:: to_pixel_multipoint(coords, asint=False) does the to_pixel operation, but on a generic shaped array .. py:method:: to_lonlat(coords) converts pixel coords to long-lat coords :param coords: An array of pixel coordinates (usually integer type :type coords: Sequence of NX2:: ((long1, lat1), (long2, lat2), (long3, lat3), ... ) (as produced by to_pixel) :returns: The pixel coords as a similar Nx2 array of floating point x,y coordinates (using the y = 0 at the top, and y increasing down) NOTE: there is not depth in input -- pixels are always 2-d! NOTE: to_lonlat(to_pixel(coords)) != coords, due to rounding. If the input is integers, a 0.5 is added to "shift" the location to mid-pixel. .. py:class:: FlatEarthProjection(bounding_box=None, image_size=None, *args, **kwargs) Bases: :py:obj:`GeoProjection` class to define a "flat earth" projection: longitude is scaled to the cosine of the mid-latitude -- but that's it. not conforming to equal area, distance, bearing, or any other nifty map properties -- but easy to compute, and it looks OK. Create a new projection Projection(bounding_box, image_size) :param bounding_box: The bounding box of the map :type bounding_box: Struct of the form:: ((min_long, min_lat), (max_lon, max_lat)) or a BoundingBox Object :param image_size: The size of the map image :type image_size: Struct of the form (width, height) .. py:method:: meters_to_lonlat(meters, ref_positions) :staticmethod: Converts from delta meters to delta latitude-longitude, using the Flat-Earth projection. dlat = dy * 8.9992801e-06 dlon = dy * 8.9992801e-06 * cos(ref_lat) (based on previous GNOME value: and/or average radius of the earth of 6366706.989 m) :param meters: Distances in meters :type meters: NX3 numpy array of (dx, dy, dz) (dz is passed through untouched) :param ref_positions: Reference positions in degrees :type ref_positions: NX3, numpy array (Only lat is used here) :returns delta_lon_lat: Differential (delta) positional values Nx3 numpy array of (delta-lon, delta-lat, delta-z) .. py:method:: lonlat_to_meters(lon_lat, ref_positions) :staticmethod: Converts from delta longitude-latitude to delta meters, using the Flat-Earth projection. This should be a reversal of meters_to_latlon. This function mainly used for testing dy = dlon / 8.9992801e-06 dx = dlat / ( 8.9992801e-06 * cos(ref_lat) ) (based on previous GNOME value: and/or average radius of the earth of 6366706.989 m) NOTE: the input is in units of longitude and latitude, but they are relative -- no absolute -- so 0 means zero distance, not on the equator :param lon_lat: Distances in meters :type lon_lat: NX3 numpy array of (dlon, dlat, dz) (dz is passed through untouched) :param ref_positions: Reference positions in degrees :type ref_positions: NX3, numpy array of (lon,lat,z) (Only lat is used here) :returns delta_meters: Differential (delta) positional values in meters Nx3 numpy array of (delta-x, delta-y, delta-z) triples .. py:method:: geodesic_sphere(lon, lat, distance, bearing) :staticmethod: Given a start point, initial bearing, and distance, returns the destination point along a (shortest distance) great circle arc -- assuming a spherical earth. Similar to how GNOME does it. :param lon: longitude in decimal degrees. :param lat: latitude in decimal degrees. :param distance: meters. :param bearing: in decimal degrees, measured clockwise from north. :returns longitude, latitude: in degrees. Code from Brian Zelenke NOTE: performance could be improved a lot here if need be (lots of data copies) .. py:method:: set_scale(bounding_box, image_size=None) set the scaling, etc. of the projection This should be called whenever the bounding box of the map, or the size of the image is changed :param bounding_box: bounding box of the visual portion of the map :type bounding_box: Structure of the form: ((min_long, min_lat), (max_long, max_lat)) :param image_size=None: the size of the image that will be drawn to. if not given, the previous size will be used. .. py:class:: RectangularGridProjection(longitude, latitude) Bases: :py:obj:`NoProjection` Projection for lat-lon to pixel and back for a rectangular but not regular grid. i.e. a rectangular grid that can be defined by a single vector each of latitude and longitude This is a totally different type of projection. It requires a linear interpolation for the latitude and longitude. Primarily used for making a raster land-water map from a non-regular rectangular grid. Create a new Rectangular Grid projection :param longitude: the vector of longitudes :param latitude: the vector of latitudes It is assumed that the largest and smallest values define the bounds of the raster. .. py:method:: set_scale(bounding_box, image_size=None) :abstractmethod: Does nothing .. py:method:: to_pixel(coords, asint=False) Returns the pixel coordinates in the grid for the given lat-lon location. :param coords: The coords to project :type coords: Nx3 numpy array or compatible sequence (lon, lat, depth) :param asint: Flag to set whether to convert to a integer or not default is to leave it as the same type it came in, so you can have fractional pixels .. py:method:: to_pixel_2D(coords, asint=False) :abstractmethod: same as to_pixel, but expects only (lon, lat) coords as input. :param coords: The coords to project :type coords: Nx2 numpy array or compatible sequence (lon, lat) :param asint: Flag to set whether to convert to a integer or not default is to leave it as the same type it came in, so you can have fractional pixels .. py:method:: to_lonlat(coords) Converts pixel coords to long-lat coords :param coords: An array of pixel coordinates (as produced by to_pixel) :type coords: Sequence of Nx2 (usually integer type):: ((long1, lat1), (long2, lat2), (long3, lat3), ... ) :returns: the pixel coords as a similar Nx2 array of floating point x,y coordinates (using the y = 0 at the top, and y increasing down) NOTE: there is not depth in input -- pixels are always 2-d! NOTE: to_lonlat(to_pixel(coords)) != coords, due to rounding. If the input is integers, a 0.5 is added to "shift" the location to mid-pixel. .. py:class:: RegularGridProjection(bounding_box=None, image_size=None, *args, **kwargs) Bases: :py:obj:`GeoProjection` projection for lat-lon to pixel and back for a pre-defined regular grid. This differs from the other projections in that it doesn't try to match the bounding box aspect ratio -- it simply uses the one already defined by the grid. You could use a RectangularGridProjection here as well, but this is simpler and should be faster. Create a new projection Projection(bounding_box, image_size) :param bounding_box: The bounding box of the map :type bounding_box: Struct of the form:: ((min_long, min_lat), (max_lon, max_lat)) or a BoundingBox Object :param image_size: The size of the map image :type image_size: Struct of the form (width, height) .. py:method:: set_scale(bounding_box, image_size=None) Set the scaling, etc. of the projection This should be called whenever the bounding box of the map, or the size of the image is changed :param bounding_box: Bounding box of the visual portion of the map :type bounding_box: Structure of the form: ((min_long, min_lat), (max_long, max_lat)) :param image_size=None: The size of the image that will be drawn to. if not given, the previous size will be used.