Composable elevations interface
Child of #575
Establish a web-appropriate interface for composing elevations similar to WWJava's CompoundElevationModel. Use WorldWindAndroid's ElevationModel and ElevationCoverage interfaces as a baseline for this capability.
Here are points to consider from @AkeluX's brief review of WorldWindAndroid's new elevation interfaces:
Here are some initial thoughts. You might have all this figured out already. In any case, I'm looking forward to learning more about this new interface.
getTimestamp actually returns the max timestamp, i.e. allows to get the timestamp of the newest data in the model. It might be useful to get the timestamp of the oldest data in the model as well. I would therefore have getMaxTimestamp and getMinTimestamp.
The definition of hasCoverage(Sector) should be clarified between "has data for at least one point" and "has data for all the point of the sector". It seems that the former is what is implement, e.g. in TiledElevationCoverage. Would two methods be useful?
Something I don't understand, but also haven't had time to look deeper at, is what is the resolution of the result array and whether this has to be coordinated somehow between the various coverages.
The priority between the coverages seems to be the order of the ArrayList. The last item can override whatever it wants in the result array. I think this is fair enough, but we might want to offer the possibly to insert coverages at any place in the ArrayList, not only at the end with addCoverage and addAllCoverages. This would be the equivalent of insert in ArrayList.
@markpet49 I've had a chance to review the WorldWindAndroid elevation interfaces. Here are a few bullet points relating to what do in WebWorldWind:
• ElevationCoverage's displayName and enabled properties, like their Layer counterparts, provide essential functionality for applications. • ElevationCoverage's user property interface are non-essential, as are the corresponding convenience methods on ElevationModel. These are part of a broader app convenience interface on layers and elevations, which we don't have in WebWorldWind yet. • The timestamp methods are intended as a stopgap measure to control terrain regeneration. It's not a key part of the interface concept, though we need it as we have no alternatives at the moment. • The hasCoverage methods turned out to be non-essential, and I removed them in an iteration after receiving @AkeluX's review. • ElevationModel may make more sense as a self ordering set, rather than an ordered list. Applications often aren't able to discern the order in which elevations ought to appear. ElevationModel's methods ought to reflect whatever choice we make here. • The getHeight methods may be more clear if they provide control over the desired resolution and indicate the resolution of the result array.
@markpet49 It appears that some of my feedback regarding elevation ordering was lost. My apologies for that. Here's the feedback I intended to document:
Java's initial compound elevation system was an ordered list, like Android's is today. This was simple, but left it up to the app to order coverages, and they often didn't realize they needed to manage this. I've found that most developers don't think about coverages as composable, so the topic of composition and ordering confuses them.
Our next iteration for Java added self-ordering based on the coverage resolution. This worked well, but its implementation had a subtle bug which frustrated users, and gave app developers no recourse: coverage resolution was considered global for the purposes of ordering. This simplification broke down with our default coverage, which is multi-resolution: 900m oceans, 30m continents, 10m USA. For example, an app could add 100m bathymetric data, but the sorting step treated the lower-resolution default coverage as 10m, resulting in a sort order that never displays the custom app coverage.
The new compassable elevations interface is looking good. I was reminded of a number of nuances about elevations after reviewing this first iteration. My apologies that much this wasn't clear sooner. We can consider this during second iteration if that's helpful.
- Ordering cannot be global (see my previous comment on Mar 19).
- Querying an elevation at location can be done in reverse order to eliminate redundant lookups.
- Querying an elevation grid requires a step to handle locations with NODATA values and locations outside the coverage area. In Android, this is implemented by letting the coverages write directly to the result array.
- Testing elevations against 0 is not a reliable indicator of existence of value. Identifying a standard NODATA value is required, or a separate test (though the latter is much less efficient). Options are NaN, null, undefined.
@pdavidc Thanks for the feedback. Comments:
- Did you have any thoughts about how to accomplish prioritizing of coverages based on location? Would a priority based on sector be sufficient or do we need something finer grained?
- I will change this after we identify the approach for point 1.
- I will look into the Android implementation and attempt to replicate it.
- Yeah, I wondered about that, but attempted to follow the current Web implementation. I will look at implementing NODATA support. Based on my past experience with NODATA values, this might require some support in underlying classes like geotiff.
My feeling is that we might as well address these items before the merge....
- Priority based on sector ought to be sufficient. You and I may want to work through the cases involved.
- Sounds good.
- I looked into this briefly. I think we should consider taking it up after the merge, as it requires significant changes to TiledElevationCoverage.
- I think what works best is to define a standard value we adopt throughout WorldWind. Components reading elevation images can be responsible for converting to that standard when needed. We went through several very problematic versions of this in WWJava. In the end, we realized that nodata values ought to be easy to handle, both in our components and by the app, and there ought to be a single representation throughout.
- New topic ZeroElevationModel is obsolete now, correct? I think it's equivalent to an empty ElevationCoverage.
- New topic WorldWindow could accept an ElevationCoverage, simplifying app transition to 0.10.0 and simplifying the constructor. I think of ElevationModel like LayerList, in that it organizes app components, and an app is unlikely to replace it.
ElevationModel Resolution and Ordering
@markpet49 I've thought about this more. I've come to a few realizations and new conclusions. I'll outline what I think we should do, and followed by my motivations. I'm curious to hear your thoughts, given that you've been considering this domain as well.
- Require ElevationCoverage to be single resolution, and drop the notion of a multi-resolution EarthElevationCoverage.
- Recast EarthElevationCoverage as EarthElevationModel, which will be a shorthand constructor for an ElevationModel containing three independent WMS-based coverages: GEBCO, Aster, USGS NED.
- Recast EarthRestElevationCoverage as EarthRestElevationModel.
- Recast WcsEarthElevationCoverage as WcsEarthElevationModel and deprecated it. It isn't useful, and WMS vs. WCS coverages will become an implementation detail of our default coverages.
- Order coverages exactly as in the initial implementation, but replace ElevationCoverage's
getBestResolutionwith a property indicating the sole resolution. - In
elevationsForGrid, optimize for multiple coverages and return an array containing the coverages that contributed to the result. We'll need to discuss what optimizing for multiple coverages might look like separately.
Our current method of a serving elevations in a single, multi-resolution elevation coverage is inherently problematic, and complicates WorldWind's elevation interfaces. It's important that we support retrieval of elevations from WorldWind's existing WMS-based elevation services, but we have the flexibility to change how we retrieve those elevations. Said another way, we currently make WMS requests for the layers "GEBCO,aster_v2,USGS-NED", but we can also request those same layers independently. It means more HTTP traffic, but greatly simplifies WorldWind's elevation interfaces, and provides a correct and reliable solution for composing application elevations.
With regard to correctness, consider an application coverage with a resolution between Aster and USGS NED. The mechanism I mentioned on Mar 19: ordering coverages based on sector, still fails when the sector contains Aster, USGS NED, and the app coverage: the app coverage should be ordered between Aster and USGS NED, but there's no way to achieve that. So the app coverage would appear correctly ordered, but only when the terrain tile in question intersected only the Aster sector. The concept of a single, multi-resolution coverage amounts to a nested ElevationModel. Since we don't plan to implement a hierarchical elevation model, I think a clear choice is to separate the model's coverages.
Optimizing ElevationModel for Multiple Coverages
@markpet49 I am convinced we can adjust ElevationModel's implementation to efficiently handle multiple coverages. Here's how:
- Modify
elevationsForGridto identify the coverage with resolution closest to the specified target, then attempt to satisfy the request with the target coverage. - If the target coverage cannot satisfy the entire request, iterate over lower-resolution coverages (if available) to fill in the blanks.
This approach makes two assumptions:
- Coverages are ordered with respect to resolution. Given the potential benefit, it's unclear to me whether application control over coverages ordering is desirable.
- Coverages satisfy the result where they can, and indicate whether the result is complete or partial.
- ElevationModel performs the composition of multiple coverage responses.
Provided we implement the changes in my previous comment on Mar 20, multiple coverages will be the common case for WorldWind. Adjusting ElevationModel's implementation as I've outlined should maintain adequate performance, and has the side effect of increasing compatibility with non-WorldWind elevation services.
Nearly every elevation service we encounter is not designed with a client like WorldWind in mind. These services lack any sort of caching capability, and perform very until poorly when client requests resolutions are vastly different from the underlying data model. Said another way, these services tend to fail or respond slowly to WorldWind's top level tile requests (geographically-large and low-resolution request), and lack the caching that would eventually stabilize the service. The change to request only what's nearest to the desired resolution means WorldWind is more likely to make requests that the service can respond to in a timely manner.
@pdavidc Thanks Dave. There's a lot to ponder here, I will spend some time absorbing it and come back with questions.
@markpet49 That sounds great. Thanks for taking the time to get this right.