In the well-constrained 2D case, is there a canned implementation for a scale indicator, such as a printed map legend would typically provide? (I want to provide measurement context for the user, similar to miles/kilometers per inch – not zoom levels.)
Arguably, this might vary by projection. However, I am not seeking cartographic correctness, just simply an approximate indication of scale as users interact with the zoom controls.
I would like to see something similar in the 2.5D and 3D models, but I understand that the differing constraints make the problem more challenging.
I see that the 2D scale display refers to the terrain between the camera and Earth’s center, which is matches the view if the camera pitch is at or near -90 degrees. This is probably how most 2D scales operate, as most people don’t tilt the view I suppose.
What would be neat is when the camera is tilted have a 2D scale on all 4 corners of the screen and one in the middle. If that’s going overboard, perhaps just the standard ‘below the camera’ scale and one for the center of the screen when tilted.
No, the repo is in the same place, but the code has been merged to master and the phil-ui branch has been deleted. If it’s not obvious how to update the URLs, let me know and I’ll send them through next time I’m on a real computer.
Awesome, instead of adding a function yourself to calculate the shortest distance along the curved surface (such as from http://www.movable-type.co.uk/scripts/latlong.html ) There’s a Cesium function that’ll calculate this for you:
I see that I was wrong, the 2 rays cast are at the bottom center of the screen. I’m surprised they are only 1 pixel apart, but I suppose that is sufficient. Most of the time the bottom center of the screen shows the Earth, but if you zoom way out and pitch way down the rays won’t intersect the Earth. However, this is a rare case from which I doubt many will be using to measure.
To determine pixelDistance divide screen width in meters by viewer.canvas.clientWidth
For CV(‘2.5D’) it’s mostly the same as 3D, except the part where you determine the distance between leftPosition and rightPosition. Since the world is flat and not curved it’s a simple straight line distance computation rather than curved distance computation. So I believe you’d just have to change these 4 lines
var leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition);
var rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition);
On second thought, although that will get you the actual displayed distance, flat maps of Earth are warped. The Equator on a flat map is 40 Mega Meters which is the circumference. However, the Artic circle’s circumference is about 16 Mega Meters yet it is stretched out at 40 Mega Meters. So the horizontal warp depends on the latitude. Vertical is warped in a different manner. So just use the same code as 3D. CV represents the curved Earth although it is displayed in a warped fashion.
Hi Kevin,
I am able to implement navigation controls and compass for 3D but it's not working for 2D and 2.5D. I need your help in implementing it for 2D and 2.5 D. Did you implemented it for 2D and 2.5D also? If not can you guide me on this?
Thanks in advance,
Gowtham.
To make things less confusing you can un-swizzle the ray
function unSwizzle(cart)
{
var temp=cart.z;
cart.z=cart.x; //X to Z
cart.x=cart.y; //Y to X
cart.y=temp; //Z to Y
}
ray.origin=unSwizzle(ray.origin);
ray.direction=unSwizzle(ray.direction);
``
So first get 2 rays one pixel apart on the bottom of the screen using camera.getPickRay , un-swizzle them, then
//get point on ground in Cartesian (unswizzled)
var CC3=Cesium.Cartesian3;
var steps=camera.position.z/(-myRay.direction.z);
var vec=new CC3();desCarte=new CC3();
CC3.multiplyByScalar(myRay.direction,steps,vec);
CC3.add(myRay.position,vec,desCarte);
//Cartesian to Cartographic (for Columbus and 2D unswizzled)
function yToLat(y)
{
var neg=1;if(y<0){neg=-1;}y=Math.abs(y);
var halfheight = Math.PI * 6378137 / 2; //width/2/2;
var ratio = y / halfheight;
return ratio * (Math.PI/2) * neg;
}
desCarto = new Cesium.Cartographic();
desCarto.longitude=desCarte.x / 6378137;
desCarto.latitude=yToLat(desCarte.y);
desCarto.height=desCarte.z;
``
Once you have both of your Cartographic points you can figure the distance (this is from https://github.com/NICTA/nationalmap/blob/master/src/ViewModels/DistanceLegendViewModel.js )
var leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition);
var rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition);
geodesic.setEndPoints(leftCartographic, rightCartographic);
var pixelDistance = geodesic.surfaceDistance;
Thanks for the updated link Kevin! From DistanceLegendViewModel.js the 2 rays are 1 pixel apart
var left = scene.camera.getPickRay(new Cartesian2((width / 2) | 0, height - 1));
var right = scene.camera.getPickRay(new Cartesian2(1 + (width / 2) | 0, height - 1));
Hi Kevin,
As per the implementation of scale legend in DistanceLegendViewModel.js geodesic.surfaceDistance is the actual distance between two points in cesium map. For what purpose you are using distances array and you are taking values like 1,2,3,5.. 10,20,30,50.. like that. Could you please explain me about this?