Skip to content
This repository has been archived by the owner on Dec 1, 2022. It is now read-only.

Tiling #29

Closed
letmaik opened this issue Oct 16, 2015 · 9 comments
Closed

Tiling #29

letmaik opened this issue Oct 16, 2015 · 9 comments

Comments

@letmaik
Copy link
Member

letmaik commented Oct 16, 2015

The goal of this issue is not to create a tiling specification for CoverageJSON but to make sure that it is possible to do so by exploring several scenarios.

TorqueMaps / TorqueTiles

As a first example, we look at CartoDB's TorqueTiles and see how this maps to CoverageJSON concepts.
TorqueTiles is based conceptually on TileMaps of TMS:

  • A TileMap/TorqueMap describes the domains of all tile layers and how to fetch tiles from each layer via a URL template.
  • A tile layer is also called a tile set.
  • Each layer corresponds to a pixel resolution / zoom level.
  • The TorqueTiles themselves are a sparse listing of those domain coordinates with their range values where the range value is not no-data. CoverageJSON does not have a sparse range encoding (it always includes no-data elements), though this is only a detail of the nature of data within the two formats (Torque is event/point based, CoverageJSON is often more dense with whole grids of data).

Conceptually, a tile layer of a TorqueMap corresponds to a CoverageJSON X-Y-T grid with a specific spatial resolution. Each tile is then a spatial subset of that grid, and is again a CoverageJSON X-Y-T grid.

For efficiency reasons, a physical CoverageJSON tile would not correspond to a full subsetted CoverageJSON coverage document, but rather a tile would only be the range of that grid coverage. This makes sense, since the domains of the layers would have been established in the TileMap document, equal to TorqueMaps.

It seems that conceptually this kind of spatial X-Y tiling with an additional T dimension is not problematic and would be compatible to how CoverageJSON is defined.

Vector-like tiling

Tiling could also be specific in terms of individual coverages which are located in a certain X-Y spatial tile. This is similar to vector-based tiling (see GeoJSON-VT, or Google Maps) where features are cut off at tile boundaries.

This is definitely more tricky to realize than TorqueTiles. It means that you need to have algorithms to cut off any coverage types that are defined in CoverageJSON, for a generic implementation. Supposing that a tile is simply a Coverage collection, the challenge is also whether and how to logically match up the individual parts of one coverage, like a trajectory, and what happens when you click on parts of a coverage. You still want to get a full plot for a trajectory etc.

One way to do it would be to simply use standard index-based subsetting on the coverage domains. While this is simple for grids, it may be a bit trickier for domains with a composite axis like trajectories. It could happen that point 1 and 3 of a trajectory are in a given tile, but point 2 are in the neighbor tile. Would the subsetted trajectory then contain points 1 and 3? Merging this together again may be tricky.

TBD

@jonblower
Copy link
Member

Mapbox Vector Tiles seem to be gaining traction as a standard format for vector tiles: https://www.mapbox.com/developers/vector-tiles/.

@letmaik letmaik added this to the future milestone Jan 20, 2016
@letmaik
Copy link
Member Author

letmaik commented May 18, 2016

With #49 it becomes easy to define a tileset matrix, meaning a collection of "zoom" levels:

{
  "type" : "CoverageCollection",
  "domainType": "Grid",
  "referencing": [{
    "components": ["x","y"],
    "system": {
      "type": "GeodeticCRS",
      "id": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"        
    }
  }, {
    "components": ["t"],
    "system": {
      "type": "TemporalRS",
      "calendar": "Gregorian"
    }
  }],
  "parameters" : {
    "air_temp": {
      "type" : "Parameter",
      "description" : {
        "en": "The air temperature measured in degrees Celsius."
      },
      "unit" : {
        "label": {
          "en": "Degree Celsius"
        },
        "symbol": {
          "value": "Cel",
          "type": "http://www.opengis.net/def/uom/UCUM/"
        }
      },
      "observedProperty" : {
        "id" : "http://vocab.nerc.ac.uk/standard_name/air_temperature/",
        "label" : {
          "en": "Air temperature",
          "de": "Lufttemperatur"
        }
      }
    }
  },
  "coverages": [{
    "type" : "Coverage",
    "domain" : {
      "type": "Domain",
      "axes": {
        "x": { "start": -179.5, "stop": 179.5, "num": 360 },
        "y": { "start": -89.5, "stop": 89.5, "num": 180 },
        "t": { "values": ["2016-01-01T00:00:00Z", "2016-01-01T06:00:00Z"] }
      }
    },
    "ranges" : {
      "air_temp" : {
        "type": "TiledNdArray",
        "axisNames": ["t","y","x"],
        "shape": [2, 180, 360],
        "tileSets": [{
          "tileShape": [1, 60, 60],
          "urlTemplate": "http://example.com/weather/temperature/0/{t}/{x}/{y}.covjson"
        }]
      }
    }
  }, {
    "type" : "Coverage",
    "domain" : {
      "type": "Domain",
      "axes": {
        "x": { "start": -179.5, "stop": 179.5, "num": 720 },
        "y": { "start": -89.5, "stop": 89.5, "num": 360 },
        "t": { "values": ["2016-01-01T00:00:00Z", "2016-01-01T06:00:00Z"] }
      }
    },
    "ranges" : {
      "air_temp" : {
        "type": "TiledNdArray",
        "axisNames": ["t","y","x"],
        "shape": [2, 360, 720],
        "tileSets": [{
          "tileShape": [1, 60, 60],
          "urlTemplate": "http://example.com/weather/temperature/1/{t}/{x}/{y}.covjson"
        }]
      }
    }
  }, {
    "type" : "Coverage",
    "domain" : {
      "type": "Domain",
      "axes": {
        "x": { "start": -179.5, "stop": 179.5, "num": 1440 },
        "y": { "start": -89.5, "stop": 89.5, "num": 720 },
        "t": { "values": ["2016-01-01T00:00:00Z", "2016-01-01T06:00:00Z"] }
      }
    },
    "ranges" : {
      "air_temp" : {
        "type": "TiledNdArray",
        "axisNames": ["t","y","x"],
        "shape": [2, 720, 1440],
        "tileSets": [{
          "tileShape": [1, 60, 60],
          "urlTemplate": "http://example.com/weather/temperature/2/{t}/{x}/{y}.covjson"
        }]
      }
    }
  }]
}

@letmaik
Copy link
Member Author

letmaik commented May 18, 2016

And I think this would be a good candidate for a "profile", e.g. "HorizontalTileMatrixSet" or whatever, which would say that this is such a tile matrix set and that all coverages must have the same axis names and parameters, that they have TiledNdArray as range type with always the same axis order, and that all "tileShape"s are identical. Also, that the zoom happens on the horizontal spatial axes and the others stay identical. And I included only a single tile set in the example above, but there could be more, and these would have to be consistent between the coverages. So, lots of constraints. Of course, you could be pragmatic and just include at the root "horizontalTileMatrixSet": true...

@jonblower
Copy link
Member

Given that Google Maps etc use a single tileset specification to cover tiling in x, y and zoom, I'm wondering if we can just extend the syntax in #49?

For example a tileset could also contain a "zoomLevel" property, where zoom level 0 means sample every pixel in a particular dimension, zoom level 1 means sample every alternate pixel, etc.

  "shape": [2, 720, 1440],
  "tileSets": [{
    "tileShape": [1, 60, 60],
    "urlTemplate": "http://example.com/weather/temperature/2/{t}/{x}/{y}.covjson",
    "zoom": [0,2,2] // means not zoomed in t, but zoomed to level 2 in x and y
  }]

Of course, if zoom is non-zero for a particular dimension, it means there are fewer tiles in that dimension.

I haven't thought this through properly, so there may be a big problem here!

@letmaik
Copy link
Member Author

letmaik commented May 20, 2016

I'm not sure how that "zoom" thing would translate to a single URL template, since you have zoom per axis and not a single spatial zoom as in google maps.

@jonblower
Copy link
Member

The idea was that you could have multiple tilesets for a range, each at a different zoom level. So a zoom of [0,1,1] means "all tiles in this set sample every point in t, but every alternate point in x and y". Then you could have another tileset with zoom=[0,2,2], etc, but the same tileShape. The default zoom level (if not specified) would be [0,0,0].

But I'd need to write this out in full to be sure that it works.

@letmaik
Copy link
Member Author

letmaik commented Jun 2, 2016

I think having something like "zoom" in a tileset is not a good idea as it would mean that you can define tilesets which don't give you all range data. It kind of violates the contract that the range has to match the domain.

@jonblower
Copy link
Member

Good point that the domain and range won't match in a zoomed tileset. Maybe the CoverageCollection is the way to go. And yes, a profile could be useful here.

@letmaik
Copy link
Member Author

letmaik commented Feb 18, 2022

Closing this since the goal was simply to explore whether zoom-style tiling can be expressed in some way, and coverage collections were identified as one way to do it.

@letmaik letmaik closed this as completed Feb 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants