{"action":"created","issue":{"url":"https://api.github.com/repos/mapbox/rasterio/issues/525","labels_url":"https://api.github.com/repos/mapbox/rasterio/issues/525/labels{/name}","comments_url":"https://api.github.com/repos/mapbox/rasterio/issues/525/comments","events_url":"https://api.github.com/repos/mapbox/rasterio/issues/525/events","html_url":"https://github.com/mapbox/rasterio/issues/525","id":116584307,"number":525,"title":"Standardize or normalize use of bounds and bounding boxes","user":{"login":"brendan-ward","id":3375604,"avatar_url":"https://avatars.githubusercontent.com/u/3375604?v=3","gravatar_id":"","url":"https://api.github.com/users/brendan-ward","html_url":"https://github.com/brendan-ward","followers_url":"https://api.github.com/users/brendan-ward/followers","following_url":"https://api.github.com/users/brendan-ward/following{/other_user}","gists_url":"https://api.github.com/users/brendan-ward/gists{/gist_id}","starred_url":"https://api.github.com/users/brendan-ward/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brendan-ward/subscriptions","organizations_url":"https://api.github.com/users/brendan-ward/orgs","repos_url":"https://api.github.com/users/brendan-ward/repos","events_url":"https://api.github.com/users/brendan-ward/events{/privacy}","received_events_url":"https://api.github.com/users/brendan-ward/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/mapbox/rasterio/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-11-12T16:22:27Z","updated_at":"2015-11-12T16:47:12Z","closed_at":null,"body":"Our use of bounds and bounding boxes is not altogether consistent (see [comments](https://github.com/mapbox/rasterio/pull/522#discussion_r44348646) on a recent PR).\r\n\r\nPart of the problem is that bounds in some contexts, especially those [derived from features](https://github.com/mapbox/rasterio/blob/master/rasterio/_features.pyx#L345-L365) follow the `(xmin, ymin, xmax, ymax)` convention.\r\n\r\nMost other places in rasterio, e.g., the `bounds` property on a raster, follow rasterio's `BoundingBox` representation `(left, bottom, right, top)`.  This relies on the affine transform of the raster.  \r\n\r\nDepending on the direction of the y dimension, these two forms may be equivalent (where y is decreasing from upper left).  In the case of y increasing from upper left (e.g., `Affine.identity()` or numpy indexes), these are not equivalent, and issues ensue when we don't account for this.\r\n\r\nOne approach would be to create a series of normalization functions, that we could use for interchange between functions that expect one form or another.  I've started to do so, but I'm now questioning this approach.\r\n\r\n```\r\ndef normalize_bounds(bbox):\r\n    \"\"\"\r\n    Normalizes an instance of a BoundingBox (left, bottom, right, top) to\r\n    bounds (xmin, ymin, xmax, ymax)\r\n\r\n    Parameters\r\n    ----------\r\n    bbox: BoundingBox or bounds tuple\r\n\r\n    Returns\r\n    -------\r\n    bounds tuple: (xmin, ymin, xmax, ymax)\r\n    \"\"\"\r\n\r\n    return (\r\n        min(bbox[0], bbox[2]),\r\n        min(bbox[1], bbox[3]),\r\n        max(bbox[0], bbox[2]),\r\n        max(bbox[1], bbox[3])\r\n    )\r\n\r\n\r\ndef normalize_boundingbox(bounds, affine):\r\n    \"\"\"\r\n    Normalizes bounds (xmin, ymin, xmax, ymax) to a\r\n    BoundingBox (left, bottom, right, top).\r\n\r\n    Parameters\r\n    ----------\r\n    bounds: bounds or BoundingBox tuple\r\n    affine: affine.Affine object\r\n\r\n    Returns\r\n    -------\r\n    BoundingBox tuple: (left, bottom, right, top).\r\n    \"\"\"\r\n\r\n    if isinstance(bounds, BoundingBox):\r\n        return bounds\r\n\r\n    x = [min(bounds[0], bounds[2]), max(bounds[0], bounds[2])]\r\n    if affine.a < 0:\r\n        x.reverse()\r\n\r\n    y = [min(bounds[1], bounds[3]), max(bounds[1], bounds[3])]\r\n    if affine.e < 0:\r\n        y.reverse()\r\n\r\n    return BoundingBox(x[0], y[0], x[1], y[1])\r\n```\r\n\r\nOne downside to this approach is that the user needs to know when to use these based on the function signature or docstring of the method they are passing bounds or bounding boxes into.\r\n\r\nOverall, this presents mostly in dealing with interactions between features and rasters, so we can deal with more of the conversions internally in those cases.\r\n\r\n@sgillies @perrygeo thoughts?"},"comment":{"url":"https://api.github.com/repos/mapbox/rasterio/issues/comments/156162294","html_url":"https://github.com/mapbox/rasterio/issues/525#issuecomment-156162294","issue_url":"https://api.github.com/repos/mapbox/rasterio/issues/525","id":156162294,"user":{"login":"perrygeo","id":1151287,"avatar_url":"https://avatars.githubusercontent.com/u/1151287?v=3","gravatar_id":"","url":"https://api.github.com/users/perrygeo","html_url":"https://github.com/perrygeo","followers_url":"https://api.github.com/users/perrygeo/followers","following_url":"https://api.github.com/users/perrygeo/following{/other_user}","gists_url":"https://api.github.com/users/perrygeo/gists{/gist_id}","starred_url":"https://api.github.com/users/perrygeo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/perrygeo/subscriptions","organizations_url":"https://api.github.com/users/perrygeo/orgs","repos_url":"https://api.github.com/users/perrygeo/repos","events_url":"https://api.github.com/users/perrygeo/events{/privacy}","received_events_url":"https://api.github.com/users/perrygeo/received_events","type":"User","site_admin":false},"created_at":"2015-11-12T16:47:11Z","updated_at":"2015-11-12T16:47:11Z","body":"@brendan-ward That's an excellent framing of the problem for inverted y-axis rasters! I'll take a deeper look next week but for now, initial thought is that we might be able to handle this is an implementation detail within `base.DatasetReader` methods (window_bounds, ul, bounds, get_window, etc) so that users wouldn't need to deal with them explicitly. "}}