def bboxlist2string(bbox, decimals=6): """Convert bounding box list to comma separated string Args: * bbox: List of coordinates of the form [W, S, E, N] Returns: * bbox_string: Format 'W,S,E,N' - each will have 6 decimal points """ msg = 'Got string %s, but expected bounding box as a list' % str(bbox) verify(not isinstance(bbox, basestring), msg) try: bbox = list(bbox) except: msg = 'Could not coerce bbox %s into a list' % str(bbox) raise BoundingBoxError(msg) msg = ('Bounding box must have 4 coordinates [W, S, E, N]. ' 'I got %s' % str(bbox)) try: verify(len(bbox) == 4, msg) except VerificationError: raise BoundingBoxError(msg) for x in bbox: try: float(x) except ValueError, e: msg = ('Bounding box %s contained non-numeric entry %s, ' 'original error was "%s".' % (bbox, x, e)) raise BoundingBoxError(msg)
def bboxstring2list(bbox_string): """Convert bounding box string to list Args: * bbox_string: String of bounding box coordinates of the form 'W,S,E,N' Returns: * bbox: List of floating point numbers with format [W, S, E, N] """ msg = ('Bounding box must be a string with coordinates following the ' 'format 105.592,-7.809,110.159,-5.647\n' 'Instead I got %s of type %s.' % (str(bbox_string), type(bbox_string))) verify(isinstance(bbox_string, basestring), msg) fields = bbox_string.split(',') msg = ('Bounding box string must have 4 coordinates in the form ' '"W,S,E,N". I got bbox == "%s"' % bbox_string) try: verify(len(fields) == 4, msg) except VerificationError: raise BoundingBoxError(msg) for x in fields: try: float(x) except ValueError, e: msg = ('Bounding box %s contained non-numeric entry %s, ' 'original error was "%s".' % (bbox_string, x, e)) raise BoundingBoxError(msg)
def bbox_intersection(*args): """Compute intersection between two or more bounding boxes Args: * args: two or more bounding boxes. Each is assumed to be a list or a tuple with four coordinates (W, S, E, N) Returns: * result: The minimal common bounding box """ msg = 'Function bbox_intersection must take at least 2 arguments.' verify(len(args) > 1, msg) result = [-180, -90, 180, 90] for a in args: if a is None: continue msg = ('Bounding box expected to be a list of the ' 'form [W, S, E, N]. ' 'Instead i got "%s"' % str(a)) try: box = list(a) except: raise Exception(msg) if not len(box) == 4: raise BoundingBoxError(msg) msg = ('Western boundary must be less than or equal to eastern. ' 'I got %s' % box) if not box[0] <= box[2]: raise BoundingBoxError(msg) msg = ('Southern boundary must be less than or equal to northern. ' 'I got %s' % box) if not box[1] <= box[3]: raise BoundingBoxError(msg) # Compute intersection # West and South for i in [0, 1]: result[i] = max(result[i], box[i]) # East and North for i in [2, 3]: result[i] = min(result[i], box[i]) # Check validity and return if result[0] <= result[2] and result[1] <= result[3]: return result else: return None
def get_optimal_extent(hazard_geo_extent, exposure_geo_extent, viewport_geo_extent=None): """A helper function to determine what the optimal extent is. Optimal extent should be considered as the intersection between the three inputs. The inasafe library will perform various checks to ensure that the extent is tenable, includes data from both etc. This is a thin wrapper around safe.storage.utilities.bbox_intersection Typically the result of this function will be used to clip input layers to a common extent before processing. :param hazard_geo_extent: An array representing the hazard layer extents in the form [xmin, ymin, xmax, ymax]. It is assumed that the coordinates are in EPSG:4326 although currently no checks are made to enforce this. :type hazard_geo_extent: list :param exposure_geo_extent: An array representing the exposure layer extents in the form [xmin, ymin, xmax, ymax]. It is assumed that the coordinates are in EPSG:4326 although currently no checks are made to enforce this. :type exposure_geo_extent: list :param viewport_geo_extent: (optional) An array representing the viewport extents in the form [xmin, ymin, xmax, ymax]. It is assumed that the coordinates are in EPSG:4326 although currently no checks are made to enforce this. ..note:: We do minimal checking as the inasafe library takes care of it for us. :returns: An array containing an extent in the form [xmin, ymin, xmax, ymax] e.g.:: [100.03, -1.14, 100.81, -0.73] :rtype: list :raises: Any exceptions raised by the InaSAFE library will be propagated. """ message = tr( 'theHazardGeoExtent or theExposureGeoExtent cannot be None.Found: ' '/ntheHazardGeoExtent: %s /ntheExposureGeoExtent: %s' % (hazard_geo_extent, exposure_geo_extent)) if (hazard_geo_extent is None) or (exposure_geo_extent is None): raise BoundingBoxError(message) # .. note:: The bbox_intersection function below assumes that # all inputs are in EPSG:4326 optimal_extent = bbox_intersection(hazard_geo_extent, exposure_geo_extent, viewport_geo_extent) if optimal_extent is None: # Bounding boxes did not overlap message = tr( 'Bounding boxes of hazard data, exposure data and viewport ' 'did not overlap, so no computation was done. Please make ' 'sure you pan to where the data is and that hazard and ' 'exposure data overlaps.') raise InsufficientOverlapError(message) return optimal_extent