In order to add markers on terrain in cesium I used the sampleTerrain
function to get the height.
I'm able to add a marker on top of a mountain but the marker is located far from the mouse click. How can I add a marker on Cesium terrain so the marker will be added exactly in the clicked position?
For reference I'll put my code here:
async leftClickInputAction(event:{position: {x:number, y:number}}):Promise<any> {
let positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
let positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
await Cesium.sampleTerrain(this.cesium.viewer.terrainProvider, 9, [positionCartographic]);
let height = positionCartographic.height;
let cart3_with_height = Cesium.Cartesian3.fromRadians(positionCartographic.longitude, positionCartographic.latitude, positionCartographic.height );
let window_coordinates = this.cesium.calcService.toFixes7Obj(Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.cesium.viewer.scene,cart3_with_height));
positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
positionCartographic.height = height;*/
let lngDeg:number = Cesium.Math.toDegrees(positionCartographic.longitude);
let latDeg:number = Cesium.Math.toDegrees(positionCartographic.latitude);
let position: [number, number, number] = [lngDeg, latDeg, positionCartographic.height];
let color:string = this.cesium.positionFormService.getSelectedColor();
let marker_picker = {position};
if(color != "blue") marker_picker['color'] = color;
this.cesium.queryParamsHelperService.addMarker(marker_picker);
In order to add markers on terrain in cesium I used the sampleTerrain
function to get the height.
I'm able to add a marker on top of a mountain but the marker is located far from the mouse click. How can I add a marker on Cesium terrain so the marker will be added exactly in the clicked position?
For reference I'll put my code here:
async leftClickInputAction(event:{position: {x:number, y:number}}):Promise<any> {
let positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
let positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
await Cesium.sampleTerrain(this.cesium.viewer.terrainProvider, 9, [positionCartographic]);
let height = positionCartographic.height;
let cart3_with_height = Cesium.Cartesian3.fromRadians(positionCartographic.longitude, positionCartographic.latitude, positionCartographic.height );
let window_coordinates = this.cesium.calcService.toFixes7Obj(Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.cesium.viewer.scene,cart3_with_height));
positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
positionCartographic.height = height;*/
let lngDeg:number = Cesium.Math.toDegrees(positionCartographic.longitude);
let latDeg:number = Cesium.Math.toDegrees(positionCartographic.latitude);
let position: [number, number, number] = [lngDeg, latDeg, positionCartographic.height];
let color:string = this.cesium.positionFormService.getSelectedColor();
let marker_picker = {position};
if(color != "blue") marker_picker['color'] = color;
this.cesium.queryParamsHelperService.addMarker(marker_picker);
Share
Improve this question
edited Feb 15, 2017 at 15:00
emackey
12.5k2 gold badges41 silver badges61 bronze badges
asked Feb 15, 2017 at 13:04
Harel.LebelHarel.Lebel
2896 silver badges17 bronze badges
2 Answers
Reset to default 4This line is your problem:
let positionCartesian3 = this.cesium.viewer.camera.pickEllipsoid(event.position);
The pickEllipsoid
function picks values off the WGS84 ellipsoid (think "similar to sea level" but don't confuse it with actual MSL). This function will never return a point from the top of a mountain.
Of course, you augmented this function by calling sampleTerrain
, which is good but doesn't fix the problem. The "pick" misses the mountaintop, and ends up picking a spot on the ellipsoid far below and behind the mountain, not near where the user thought they clicked.
There's another function you can use, viewer.scene.pickPosition
, that will return positions by reading them out of WebGL's depth buffer. This means the function is only reliable at close range, when the camera is near enough to see individual mountains for example, not zoomed out to the whole globe. But it does let you pick mountain tops and such.
Here's a Sandcastle demo. It uses code lifted from the Picking Demo and modified to work at Mount Everest.
var terrain = Cesium.createDefaultTerrainProviderViewModels();
var viewer = new Cesium.Viewer('cesiumContainer', {
animation: false,
timeline: false,
geocoder : false,
selectionIndicator : false,
infoBox : false,
terrainProviderViewModels: terrain,
selectedTerrainProviderViewModel: terrain[1]
});
function lookAtMtEverest() {
var target = new Cesium.Cartesian3(300770.50872389384, 5634912.131394585, 2978152.2865545116);
var offset = new Cesium.Cartesian3(6344.974098678562, -793.3419798081741, 2499.9508860763162);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
lookAtMtEverest();
var labelEntity = viewer.entities.add({
label : {
show : false,
showBackground : true,
font : '14px monospace',
horizontalOrigin : Cesium.HorizontalOrigin.LEFT,
verticalOrigin : Cesium.VerticalOrigin.TOP,
pixelOffset : new Cesium.Cartesian2(15, 0)
}
});
var sceneModeWarningPosted = false;
// Mouse over the globe to see the cartographic position
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(movement) {
var foundPosition = false;
var scene = viewer.scene;
var pickedObject = scene.pick(movement.endPosition);
if (scene.pickPositionSupported) {
if (scene.mode === Cesium.SceneMode.SCENE3D) {
var cartesian = viewer.scene.pickPosition(movement.endPosition);
if (Cesium.defined(cartesian)) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(3);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(3);
var heightString = cartographic.height.toFixed(2);
labelEntity.position = cartesian;
labelEntity.label.show = true;
labelEntity.label.text =
'Lon: ' + (' ' + longitudeString).slice(-8) + '\u00B0' +
'\nLat: ' + (' ' + latitudeString).slice(-8) + '\u00B0' +
'\nAlt: ' + (' ' + heightString).slice(-7) + 'm';
var camera = scene.camera;
labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, camera.frustum.near * 1.5 - Cesium.Cartesian3.distance(cartesian, camera.position));
foundPosition = true;
}
} else if (!sceneModeWarningPosted) {
sceneModeWarningPosted = true;
console.log("pickPosition is currently only supported in 3D mode.");
}
}
if (!foundPosition) {
labelEntity.label.show = false;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
I used that :
let ray = this.cesium.viewer.camera.getPickRay(event.position);
let positionCartesian3 = this.cesium.viewer.scene.globe.pick(ray, this.cesium.viewer.scene);
let positionCartographic = Cesium.Cartographic.fromCartesian(positionCartesian3);
let lngDeg: number = Cesium.Math.toDegrees(positionCartographic.longitude);
let latDeg: number = Cesium.Math.toDegrees(positionCartographic.latitude);
position = [lngDeg, latDeg, positionCartographic.height];
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744770005a4592700.html
评论列表(0条)