-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Geocoder terrain-aware #6876
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,37 @@ | ||
define([ | ||
'../../Core/IonGeocoderService', | ||
'../../Core/Cartesian3', | ||
'../../Core/CartographicGeocoderService', | ||
'../../Core/defaultValue', | ||
'../../Core/defined', | ||
'../../Core/defineProperties', | ||
'../../Core/DeveloperError', | ||
'../../Core/Event', | ||
'../../Core/GeocodeType', | ||
'../../Core/Math', | ||
'../../Core/Matrix4', | ||
'../../Core/Rectangle', | ||
'../../Core/sampleTerrainMostDetailed', | ||
'../../Scene/SceneMode', | ||
'../../ThirdParty/knockout', | ||
'../../ThirdParty/when', | ||
'../createCommand', | ||
'../getElement' | ||
], function( | ||
IonGeocoderService, | ||
Cartesian3, | ||
CartographicGeocoderService, | ||
defaultValue, | ||
defined, | ||
defineProperties, | ||
DeveloperError, | ||
Event, | ||
GeocodeType, | ||
CesiumMath, | ||
Matrix4, | ||
Rectangle, | ||
sampleTerrainMostDetailed, | ||
SceneMode, | ||
knockout, | ||
when, | ||
createCommand, | ||
|
@@ -331,14 +341,79 @@ define([ | |
} | ||
|
||
function updateCamera(viewModel, destination) { | ||
viewModel._scene.camera.flyTo({ | ||
destination : destination, | ||
complete: function() { | ||
viewModel._complete.raiseEvent(); | ||
}, | ||
duration : viewModel._flightDuration, | ||
endTransform : Matrix4.IDENTITY | ||
}); | ||
var scene = viewModel._scene; | ||
var globe = scene.globe; | ||
var ellipsoid; | ||
if (defined(globe)) { | ||
ellipsoid = globe.ellipsoid; | ||
} else { | ||
ellipsoid = scene.mapProjection.ellipsoid; | ||
} | ||
|
||
var camera = scene.camera; | ||
var terrainProvider = scene.terrainProvider; | ||
var availability = defined(terrainProvider) ? terrainProvider.availability : undefined; | ||
|
||
// Always expand single points so we don't zoom | ||
// directly into the ground, even when not using terrain. | ||
if (destination instanceof Cartesian3) { | ||
var carto = ellipsoid.cartesianToCartographic(destination); | ||
var offset = CesiumMath.toRadians(0.001); | ||
destination = new Rectangle( | ||
carto.longitude - offset, | ||
carto.latitude - offset, | ||
carto.longitude + offset, | ||
carto.latitude + offset); | ||
} | ||
|
||
var newDestination = destination; | ||
if (defined(availability)) { | ||
var cartographics; | ||
|
||
cartographics = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mramato These don't need to be on two separate lines but oh well. And shouldn't you use result parameters throughout this? I know it won't really impact performance but it's still a good habit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use result parameters as a necessary evil for performance in hot areas of the code. Not using them makes the code cleaner and is perfectly OK if performance is not going to be an issue. |
||
Rectangle.center(destination), | ||
Rectangle.southeast(destination), | ||
Rectangle.southwest(destination), | ||
Rectangle.northeast(destination), | ||
Rectangle.northwest(destination) | ||
]; | ||
|
||
newDestination = sampleTerrainMostDetailed(terrainProvider, cartographics) | ||
.then(function(positionsOnTerrain) { | ||
var maxHeight = -Number.MAX_VALUE; | ||
positionsOnTerrain.forEach(function(p) { | ||
maxHeight = Math.max(p.height, maxHeight); | ||
}); | ||
|
||
var tmp = camera.getRectangleCameraCoordinates(destination); | ||
var finalPosition; | ||
if (scene.mode === SceneMode.SCENE3D) { | ||
finalPosition = ellipsoid.cartesianToCartographic(tmp); | ||
} else { | ||
finalPosition = scene.mapProjection.unproject(tmp, tmp); | ||
} | ||
|
||
finalPosition.height += maxHeight * 2; | ||
return ellipsoid.cartographicToCartesian(finalPosition); | ||
}); | ||
} | ||
|
||
var finalDestination = destination; | ||
when(newDestination) | ||
.then(function(result) { | ||
finalDestination = result; | ||
}) | ||
.always(function(){ | ||
// Whether terrain querying succeeded or not, fly to the destination. | ||
camera.flyTo({ | ||
destination: finalDestination, | ||
complete: function() { | ||
viewModel._complete.raiseEvent(); | ||
}, | ||
duration: viewModel._flightDuration, | ||
endTransform: Matrix4.IDENTITY | ||
}); | ||
}); | ||
} | ||
|
||
function chainPromise(promise, geocoderService, query, geocodeType) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced this is the right thing to do. The rectangle covers a larger area closer to the equator than the poles so the camera destination will have a greater height at the equator. From experimenting, the camera height at the equator is around 500m and at the poles it's 350m.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree. I was just moving code over from
PeliasGeocoder
and the thought just didn't occur to me. Instead I'm going to apply a fixed offset of 500m to any single point rather than expanding it into a rectangle at all. I'll still query the terrain at that single point, so it will still adjust properly and this will make for consistent zooming with and without terrain.