Placing buildings on the terrain

2,873 views
Skip to first unread message

Hyper Sonic

unread,
Apr 12, 2015, 12:24:42 PM4/12/15
to cesiu...@googlegroups.com
Just to coalesce a couple of threads

The reference ellipsoid doesn't clip building basements at many camera tilt ranges, so it's best to use terrain that does clip. To manually toggle terrain first press the imagery button on the top right, then scroll down to the terrain section (perhaps terrain should have it's own button?) I've created a SandCastle app that allows one to move a building up and down(do full-screen to access all buttons.) 

-Zoom out and try it with terrain on and with terrain off. With terrain off set ellipsoid+30 then move down, you'll notice that there's no clipping with the reference ellipsoid (well depending on the camera tilt angle.)
-With terrain on tHeight + 30 places the bottom on the terrain and the center is 30 meters above the bottom.

var viewer = new Cesium.Viewer('cesiumContainer');
var CC3 = Cesium.Cartesian3;
var tLon = -90.1922703175/180*Math.PI;
var tLat = 38.6286636758/180*Math.PI;

var mycarto = new Cesium.Cartographic();
mycarto.longitude=tLon;mycarto.latitude=tLat;mycarto.height=0;
console.log(mycarto); //defined
var tHeight=viewer.scene.globe.getHeight(mycarto);
console.log(tHeight); //undefined, but why?

tHeight=110.139218977672; //just manually set for now

var thebox = viewer.entities.add({
    name : 'building',
    position: Cesium.Cartesian3.fromDegrees(-90.1922703175, 38.6286636758, 30),
    box : {
        dimensions : new Cesium.Cartesian3(40, 30, 60),
        material : Cesium.Color.RED,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});
viewer.zoomTo(viewer.entities);
function gohere(height)
{
    var test = new Cesium.Cartographic(tLon,tLat,height);
    var mypos = Cesium.Ellipsoid.WGS84.cartographicToCartesian(test);
    thebox.position = mypos;    
}
function upAndDown(scalar)
{
    var mycarte = thebox._position._value;
    var mynormal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(mycarte);
    var relMove = CC3.multiplyByScalar(mynormal,scalar,new CC3());
    CC3.add(mycarte,relMove,mycarte);
    thebox.position = mycarte;
}
Sandcastle.addToolbarButton('up 5 meters', function() 
{upAndDown(5);});
Sandcastle.addToolbarButton('down 5 meters', function() 
{upAndDown(-5);});

//note that this is center of the building, not the bottom
Sandcastle.addToolbarButton('ellipsoid+30', function() 
{gohere(0+30);});
Sandcastle.addToolbarButton('tHeight+10', function() 
{gohere(tHeight+10);});
Sandcastle.addToolbarButton('tHeight+20', function() 
{gohere(tHeight+20);});
Sandcastle.addToolbarButton('tHeight+30', function() 
{gohere(tHeight+30);});
Sandcastle.addToolbarButton('tHeight+40', function() 
{gohere(tHeight+40);});
Sandcastle.addToolbarButton('tHeight+50', function() 
{gohere(tHeight+50);});

If anyone knows why var tHeight=viewer.scene.globe.getHeight(mycarto); is failing please let me know.

nosig...@gmail.com

unread,
Apr 13, 2015, 8:00:53 AM4/13/15
to cesiu...@googlegroups.com
Thank you very much for the great example!

I can't test it on my own project right now, but as far as I understand the code it should be possible to position the model exactly on the ground (terrain) as soon as the getHeight() function works (get the height at the lat/lon and use it for the positioning (height) of the model).

Jerrold Siegel

unread,
Apr 13, 2015, 4:20:17 PM4/13/15
to cesiu...@googlegroups.com
Thanks, this really looks useful, I am going to try to make it work in our setting.

Hyper Sonic

unread,
Apr 13, 2015, 6:01:42 PM4/13/15
to cesiu...@googlegroups.com
I'm glad you found it useful! I still don't understand why viewer.scene.globe.getHeight isn't working, it works just fine in my plugin, and I used it in SandCastle earlier to obtain the terrain height.

Jerrold Siegel

unread,
Apr 14, 2015, 2:37:25 PM4/14/15
to cesiu...@googlegroups.com
I just have to say thanks again, It looks like you pointed me at a solution to our biggest  problem. 
 
The URL is http://vcities.ite-stl.org/Cesium/Apps/Sandcastle/gallery/Cesiumtest.php  and when you switch to the STK terrain the dreaded basements go away.


 

Jerrold Siegel

unread,
Apr 14, 2015, 4:12:34 PM4/14/15
to cesiu...@googlegroups.com

Hyper Sonic

unread,
Apr 14, 2015, 7:16:32 PM4/14/15
to cesiu...@googlegroups.com
That's pretty neat, scrolling the years from 1865 to 2030 you can see buildings pop in and out of existence. I'm glad it's working well now. If one wanted to see the basements they could always turn off the terrain, except for places like Death Valley and the Dead Sea where it's reversed (terrain is under the ellipsoid.) Actually places like Death Valley still pose a problem, the tile under you disappears when you're 90 meters or less above the terrain since that's when the camera goes under the ellipsoid.

nosig...@gmail.com

unread,
Apr 15, 2015, 9:46:55 AM4/15/15
to cesiu...@googlegroups.com
Related to the getHeigh() function:

According to this entry it should work with sampleTerrain(); so I tried an adapted version of this code (see below for sandcastle) and it returns me perfectly the height of a given position. 
The problem is now that there is a small "lag" until the height is available in the variable and can be used for the model placing. So I was searching for a way to "stop" the code until the height is available in the variable. I was playing around with while (result: browser crash) and setTimeout() (does not stop the code, so the rest continues) as well as setInterval() (gets an error with if/else -> resets the changed variable.

var terrainProvider = new Cesium.CesiumTerrainProvider({
    requestVertexNormals : true
});

var test = 1500;  //the altitude variable that should be changed to the value at pos lat/long

var viewer = new Cesium.Viewer('cesiumContainer', 
                               {terrainProvider: terrainProvider, baseLayerPicker: false});
var ellipsoid = viewer.scene.globe.ellipsoid;  //just necessary to fly there.
var POI= Cesium.Cartographic.fromDegrees(46.5,9.5,0, new Cesium.Cartographic());   //the position in lat/long as well as height 0.
viewer.camera.flyTo({destination: ellipsoid.cartographicToCartesian(POI, new Cesium.Cartesian3())});
var promise = Cesium.sampleTerrain(terrainProvider, 11, [POI]); //takes the terrain, a precision value and the point of interest (lat/long; returns a promise.
Cesium.when(promise, function(POIx) { //updates the test variable with the "real" variable (i.e. the altitude at pos. lat/long.
    test = (POIx[0].height);   
});
setTimeout(function(){console.log(test)},0);     //returns immediately the value --> returns 1500; the defined variable
setTimeout(function(){console.log(test)},1000); //returns the value after 1 second --> returns 747; the "real" value at that position.

Since I'm drawing all my models in a loop I need a way to "halt" the function after I update the altitude (since that needs some time) before I can continue with drawing the  model with the now real altitude. Right now I get the value, but always too late -> the models are already drawn at the defined height 1500.

If anybody knows a way to give the code some time, thanks!

Regards
Martin

Jerrold Siegel

unread,
Apr 15, 2015, 11:17:10 AM4/15/15
to cesiu...@googlegroups.com
I had the same problem and I have been using a version of the code below.


function loadPause(){
    if (pausetime>0) {
        pausetime--;
        somedots=somedots+" .";
        setdesc("Loading Buildings Please Wait\n   (loading time approximate)\n\n"+somedots);
        self.setTimeout("loadPause()", 1000);
    } else {
     ........
.....
    }
}

Matthew Amato

unread,
Apr 15, 2015, 11:21:09 AM4/15/15
to cesiu...@googlegroups.com
The right way to use sampleTerrain is to use the promise returned from calling it.  Network requests are asynchronous by nature and any attempt to try and make the synchronous is flawed. setTimeout will create race conditions and and are also inefficient.  There's an example in the documentation: http://cesiumjs.org/Cesium/Build/Documentation/sampleTerrain.html

Just an FYI that clamping things to the ground is on the near term roadmap for Cesium (I was actually hoping we'd have it by now but there's been some hurdles).  Putting a model or anything else on the ground or relative to the ground will be trivial in the next few months.


--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hyper Sonic

unread,
Apr 15, 2015, 12:31:18 PM4/15/15
to cesiu...@googlegroups.com
Will Cesium clamp to ground automatically adapt to tiles changing LOD levels by chance? Maybe when a tile changes LOD, it tags all entities on it to have their heights re-adjusted.

Matthew Amato

unread,
Apr 15, 2015, 1:20:37 PM4/15/15
to cesiu...@googlegroups.com
Yes.

On Wed, Apr 15, 2015 at 12:31 PM, Hyper Sonic <gman...@gmail.com> wrote:
Will Cesium clamp to ground automatically adapt to tiles changing LOD levels by chance? Maybe when a tile changes LOD, it tags all entities on it to have their heights re-adjusted.

--

nosig...@gmail.com

unread,
Apr 15, 2015, 2:32:02 PM4/15/15
to cesiu...@googlegroups.com
@Matthew: Thanks for the clarification. 

I tried it now in this form (sampleTerrain() ...  .then(function(){*here the whole drawing of the model*}). This gives me the model at the right position and altitude.  But: a) I still have quite a big parallax-effect, i.e. the model is "moving" around and not clamped to the ground; and b) only the last model from the array is drawn, i.e. the loop takes first all variables from the array (and goes through all entry in the array) and then the sampleTerrain works only for the last entry in the array. So as far as I understand there is still a problem with this "lag" during the loop, even if I take the result from the sampleTerrain not "outside" of it as a variable but within the .then-part.

Hyper Sonic

unread,
Apr 15, 2015, 2:49:23 PM4/15/15
to cesiu...@googlegroups.com
You can send many points in just one call to sampleTerrain
So call sampleTerrain just one time, then while waiting for the height data place the buildings at the proper lon/lat and whatever height. Then once you get the height data adjust the heights of each of the buildings to the proper value.

One problem with sampleTerrain is that it returns the height at a certain tile LOD, but the tile LOD varies depending on factors such as camera distance.

The parallax effect should only occur if you have terrain off and the building is either buried or floating over the reference ellipsoid. When Cesium has clampToGround I'd assume you'd be able to define what is considered the 'terrain bottom' of the model, which isn't always the always the bottom of the model as some buildings have basements.

nosig...@gmail.com

unread,
Apr 15, 2015, 3:26:35 PM4/15/15
to cesiu...@googlegroups.com
Ciao

Puh, now it is definitely too complicated for me.
How can I move the model after I get back the heigh data?
Hm, terrain is activated and I still get this effect, since the area there is quite flat I do not think it should have anything to do with a wrong position (but maybe with a wrong z-LOD of course, but I though I can omit this with a high precision during the sampling.).

Hyper Sonic

unread,
Apr 15, 2015, 3:40:05 PM4/15/15
to cesiu...@googlegroups.com
You can do
viewer.scene.globe.ellipsoid.cartesianToCartographic
change the height then
viewer.scene.globe.ellipsoid.cartographicToCartesian
and set the model to the result.

Using the STK terrain? If the terrain is fairly flat then there probably isn't much difference between the various LOD tile heights.

nosig...@gmail.com

unread,
Apr 15, 2015, 4:25:43 PM4/15/15
to cesiu...@googlegroups.com
Yes, the STK terrain server.

Hm, but I don't get how I can first load the height for all my positions and then draw the models on those position (+height). I tried to push the result from the sampleTerrain to my array to retrieve it later, but this does not work (not stored at all). I just do not understand how I can retrieve the result later if it is not explicit stored after the sampleTerrain for all positions is done (for only one position and one model it is straightforward).

The parallax effect is way stronger than when I correct it a bit manually; and it is definitely not drawn on the ellipsoid since the altitude at this position is somewhere around 500 meters (when it is drawn on the ellipsoid it would be way below the surface/terrain).

Hyper Sonic

unread,
Apr 15, 2015, 4:47:03 PM4/15/15
to cesiu...@googlegroups.com
Maybe you can pre-process the relative to ellipsoid heights of all your models using sampleTerrain beforehand instead.

A good way to determine what tile LOD you should shoot is by checking out this URL http://www.agi.com/products/stk/terrain-server/
Check mark show tile coordinates, zoom in, and the tile level is listed after the L.

Using sampleTerrain is pretty easy, I just copied this from the reference docs and put it into a SandCastle app. 2 samples with one query.
var viewer = new Cesium.Viewer('cesiumContainer');
var terrainProvider = new Cesium.CesiumTerrainProvider({
    url
: '//assets.agi.com/stk-terrain/world'
});
var positions = [
   
Cesium.Cartographic.fromDegrees(86.925145, 27.988257),
   
Cesium.Cartographic.fromDegrees(87.0, 28.0)
];
var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);
Cesium.when(promise, function(updatedPositions) {
   console
.log("pos0 "+positions[0].height);
   console
.log("pos1 "+positions[1].height);
});

You can .clone() positions array to your own array.

Hyper Sonic

unread,
Apr 15, 2015, 4:50:37 PM4/15/15
to cesiu...@googlegroups.com

nosig...@gmail.com

unread,
Apr 16, 2015, 7:39:06 AM4/16/15
to cesiu...@googlegroups.com
Hello

Thank you for the great inputs!

Now it works, not exactly as the example here suggests but similar:
- one array with all my models as objects with the coordinates stored
- loop through this array and push the (transformed) coordinates to another array
- sampleTerrain on the second array to get the altitude
- wait for 10 seconds, then loop through the first array again to draw the model, during this loop I read also the height from the second array and put it as a variable in the model drawing process.

Now I'm only facing this parallax problem. @Hyper Sonic: thanks for the link to the Terrain-LOD-tiles. As I zoom in I should get LOD=17. As far as I understand I should set this value to the following code line: var promise = Cesium.sampleTerrain(terrainProvider, 17, positions); However, it accepts only the value "14" for the level (and not 17), with all values over 14 I get "undefined" back. Since I need quite a near-to-ground zoom level the moving around of the objects is too strong in my case.

Another interesting fact is that the camera sets automatically so that it looks down at the given position instead of using the defined pitch:

var center = Cesium.Cartesian3.fromDegrees(lat, long, 500);
        var heading = Cesium.Math.toRadians(90.0);
        var pitch = Cesium.Math.toRadians(-55.0);
        var range = 1000.0;

nosig...@gmail.com

unread,
Apr 16, 2015, 7:52:20 AM4/16/15
to cesiu...@googlegroups.com
And apart from this the models are also still on different heights related to the model height (i.e. higher models are drawn partly below surface and only small models are more or less exactly on the ground).

Quite interesting is also that it seems to me that the models are not properly clipped by the terrain (contrary to the example in the introduction of this thread).

Hyper Sonic

unread,
Apr 16, 2015, 9:16:07 AM4/16/15
to cesiu...@googlegroups.com
Are you waiting exactly 10 seconds, or does that happen to be when the callback executes? Since terrain heights really don't change perhaps just do sampleTerrain once, then incorporate that into the original data.

When positioning a model it actually positions the center of the model, so you'll have to raise it a bit if you want the bottom on the terrain. On my example the center was 30 meters above the 'terrain bottom' so they are raised 30 meters.

14 to 15 might be the highest detail for triangle mesh. If you look at the wireframe going higher than 14/15 seems to have the same triangle mesh detail.

What function are you using to position the camera?

nosig...@gmail.com

unread,
Apr 16, 2015, 12:50:32 PM4/16/15
to cesiu...@googlegroups.com
I'm waiting 10 seconds after the site started to load (to make sure that sampleTerrain is finished for all points). sampleTerrain is not within the loop, so it is executed only once for the whole array. I tried to put the result from the sampleTerrain back to the original data, but I got always a new object at the end of the array and was not able to set it "within" the array, so that was the reason for the second array; and this part works quite well.

A ok, thanks for the clarification with the positions. Hm, that means that my problem remains. Or is there a way to get the max. "height" of the model from the .glTF so that this value can be used to "elevate" the model on the terrain? (something like height_offset = get.ModelHeight()/2).

The clipping with terrain works now: The terrain was loaded automatically (with BaseLayerPicker: false); but for the clipping I had to set BaseLayerPicker to true -> the STK is not loaded (visually), this means the models are flying around -> get the STK direct from the dropdown menu -> and now the models are clipped with the terrain (so the parallax-problem is away and only the height offset problem remains).

Camera:
viewer.scene.globe.maximumScreenSpaceError = 1;

       
var center = Cesium.Cartesian3.fromDegrees(lat, long, 500);
       
var heading = Cesium.Math.toRadians(90.0);
       
var pitch = Cesium.Math.toRadians(-55.0);
       
var range = 1000.0;

        viewer
.camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, range));
       
var scene = viewer.scene;
       
var canvas = viewer.canvas;
        canvas
.setAttribute('tabindex', '0'); // needed to put focus on the canvas
        canvas
.onclick = function() {
            canvas
.focus();
       
};

Without the terrain I can move arount the point that is defined with lat, long; as son as I load the terrain this remains but the "pitch" is not loaded (the reason for this is that I need in the end a camera that has all parameters fixed and can only be rotated at a certain distance and pitch around a given point).

Hyper Sonic

unread,
Apr 16, 2015, 4:33:59 PM4/16/15
to cesiu...@googlegroups.com
When sampleTerrain calls the callback you know it's finished, it could be less than 10 seconds. You could place the height data into a textarea, copy/paste that into a js file array and get quick access on all later loads.

I'm not sure how to get model dimensions from .glTF files, maybe someone else here knows of a way. 

Do you set terrainProvider at startup, or set it manually with the buttons?

On the code you provided you have lat before lon it seems, though Cesium expects lon before lat.

Perhaps with the initial lookAt settings it pushes the camera into a mountain and gets shoved up?

nosig...@gmail.com

unread,
Apr 17, 2015, 3:36:36 AM4/17/15
to cesiu...@googlegroups.com
When sampleTerrain calls the callback you know it's finished, it could be less than 10 seconds. You could place the height data into a textarea, copy/paste that into a js file array and get quick access on all later loads.

It is definitely less than 10 seconds, thats just to be sure; thanks for the other idea, I did not think about this, hope I'll find time to implement it tomorrow.
 
I'm not sure how to get model dimensions from .glTF files, maybe someone else here knows of a way. 

So far I'm using the workaround that I had before with a variable I have by hand (approximates the height of the model) that is added to the height from the terrain, works not that bad and with the clipping it gives me a better result than without the terrain.

Do you set terrainProvider at startup, or set it manually with the buttons?

I thought at startup, it shows me also visually the terrain, but the clipping does not happen. It clips whit the models only when I deactivate the terrain and activate it again after the models are loaded manually with the buttons from the navigation panel. It could be that first the terrain is loaded, then the models are loaded and due to this no clipping happen. Maybe it has to be the other way around: First model, then terrain -> clip. So I'll try to load the terrain for the models, then load the models and after that load again the terrain for the visualization (and clipping) (or your idea with the models without height, then add the terrain and later the height, that should work as well but not with my implementation I have right now).
 
On the code you provided you have lat before lon it seems, though Cesium expects lon before lat.


ups, that is just a typo for the example here, in my working example it is long, lat
 
Perhaps with the initial lookAt settings it pushes the camera into a mountain and gets shoved up?

A, that could be! it is quite a mountainous area where I'm working. Will test that on the weekend, thanks. (However, I think with an distance of 1 km it should not touch the mountain, but maybe it has something to do with the field of view (and hence it is a bit "further" away than 1 km). I was also playing around with the height of the center (now set to 500), maybe I have to move this a bit higher (clearer over the terrain).

Hyper Sonic

unread,
Apr 17, 2015, 6:00:48 PM4/17/15
to cesiu...@googlegroups.com
When outputting to a textarea you can format it anyway you want, then just copy/paste/done!

That's odd that you have to activate terrain after the models for proper clipping. On my example if I start with terrain on
 var viewer = new Cesium.Viewer('cesiumContainer', {
 terrainProvider : new Cesium.CesiumTerrainProvider({
 baseLayerPicker : false
 });
You can see the model buried under the terrain, but if you start with it off then turn it on manually you can't see it buried. That might be a bug.

Is both what you're looking at and the camera over the terrain?




nosig...@gmail.com

unread,
Apr 19, 2015, 5:48:43 PM4/19/15
to cesiu...@googlegroups.com
Ciao

I checked it, my "center/target" and my camera are both clearly over the terrain.

I found now a small workaround (not a pretty one, but hey, it works...):

For the clipping error (no clipping with terrainProvider-data; but clipping with baseLayerPicker-data):
- I have created a custom BaseLayerPicker (according to the ref).
- In the viewer constructor the baseLayerPicker is set to false, no terrainProvider is selected (and, since I have my own data and do not want the basic bing maps, imageryProvider is set to false).
- after that I load the terrain with this code (takes the defined data [terrainProvider] from the manual (and hidden) baseLayerPicker: var baseLayerPicker = new Cesium.BaseLayerPicker('baseLayerPickerContainer', {globe:viewer.scene.globe, terrainProviderViewModels:imageryViewModels});
- after that you can load more layers if you need some (I tested it with an overlay of OSM data, works perfectly).
Thats it, even my models are loaded after the Terrain/OSM data; it clips perfectly with the terrain.

For the zoom-error (the camera was looking down at nadir and not with the specified pitch):
- I tested several distances (range) with a given pitch and heading and found a threshold somewhere at 2000 meter to target. Until 2000 meters it worked fine, after that the camera was automatically shifted.
- Since I needed a distance quite near to the target, I initially set a range of 2000; then I load all data (terrain, models, tiles etc.) After that, I call the camera.zoomIn to the needed distance. Funnily, this works perfect -> I have the camera at the desired position with my 3D models clipped with the terrain.

However, I have still two issues:
- The height-offset from center of model to terrain is still not fixed.
- It seems to me that my own tileServer takes the tiles defined for the ellipsoid-LOD and not for the terrain LOD, this means that they are a bit blurry on the higher terrain altitude. If there is a way to offset this as well, let me know.

Regards
Martin

Hyper Sonic

unread,
Apr 19, 2015, 10:17:31 PM4/19/15
to cesiu...@googlegroups.com
Getting models to clip with the terrain seems to be rather complicated! It would be nice if you can select if a model is to be clipped by the terrain or not by simply setting a variable.

There are some U.S. flat land areas that are >2000 meters above the reference ellipsoid, such as near the NM and CO state border (flat lands in Tibet are typically >5000 meters above the reference ellipsoid.) But if the place you're looking at is 500 meters above reference ellipsoid as in your example that shouldn't be a problem.
In Cesium 1.7: "Added camera-terrain collision detection/response when the camera reference frame is set." I think you can turn this off, but I don't know which var to set.

Alternatively (instead of lookAt then zoomIn combo) you could do a setView then do your own ranging:
//first do setView on the target, then move back with the following:
var CC3=Cesium.Cartesian3;
var temp=new CC3()
CC3
.negate(camera.direction,temp);
CC3
.mutliplyByScalar(temp,range,temp);
CC3
.add(temp,camera.position,temp);
camera
.position=temp.clone();
If you also want to set the camera's transform, do a lookAtTransform(transform,camera.position); Where transform is the ENU transform of the target. This should retain camera position.

I wonder if there is a way to get size data of a model with all dimensions scaled at 1?


Regarding Tile LOD


My guess is that tile LOD is determined the same way whether it be the tile triangle mesh or the tile imagery.
Factors in determining what LOD level to display:
-the lower the distance to the tile's bounding sphere the higher the LOD
-the lower the FOV the higher the LOD

These 2 factors basically estimate how much Solid Angle the tile takes up http://en.wikipedia.org/wiki/Solid_angle Solid angle is basically 'angular area'.
Then it converts 'angular area' to 'screen pixel area'
Then calls for the LOD that is appropriate to that 'pixel area'.
Such as a 100x100 pixel image goes well with 100x100 pixel area. (but a 1000x1000 pixel image would be a waste with a 100x100 pixel area.)

Because it is a bounding sphere the pitch angle doesn't factor in, as a sphere takes up the same solid angle no matter what angle it is viewed from. If tiles had bounding boxes instead of spheres, then pitch angle could be factored in as well. Tile height (lowest valley to highest peak) is usually quite a bit less its width or length. So looking obliquely at a tile would result in a lower solid angle than looking straight down at it.

I wonder if Earth imagery providers store oblique mipmaps (like in the image here)
Or just straight down mipmaps (like the image here)

(there's also viewer.scene.globe.maximumScreenSpaceError which lets the user adjust LOD)
Much of this is supposition though. Kevin Ring wrote an article about this but I misplaced the link.

Hyper Sonic

unread,
Apr 20, 2015, 1:42:36 AM4/20/15
to cesiu...@googlegroups.com
Scratch that idea of oblique mipmaps, it would only work on flat tiles and most tiles are hilly with surface normals in all sorts of directions. I found the slide show I was looking for earlier https://cesiumjs.org/massiveworlds/index.html#WorldScaleTerrainRendering World-Scale Terrain Rendering.

nosig...@gmail.com

unread,
Apr 20, 2015, 9:12:38 AM4/20/15
to cesiu...@googlegroups.com
Thanks for the explanation and the slides, very interesting.

I was now able to extract the height of the models in meters (see below) and tried then to set an offset of half the height to the height from sampleTerrain. the result is, that (at least) all models are on a similar reference level (i.e. height). However, I guess due to the maximal possible precision of 14 in the sampleTerrain function when I'm in reality somewhere on level 16, this results in partly buried models. So I still have to compromise between flying/burying of the models.

To get the height of the models I used some collada (.dae) files (by the way: It was just working with files that had the following pipeline: CityEngine export to .fbx (on mac os) -> convert with AnyCad Exchange3D to .dae (on windows [attention: when you install this program you get also some chinese anti-virus software to your system; so no guarantee for any problems! Also, the exporter has Z as up axis and not Y, this gives you a 90° rotated model that can easily be corrected when you set the up-axis right]. With the direct exporter from CityEngine to .dae or the autodesk fbx converter I got only a non working .dae [for the glTF convert- as well as for the "dimension" task]).

Then I use three.js with ColladaLoader.js to load the .dae file and looped through my array (since it needs also some time I used this "delay" function here). It was also only possible to do 16 models at the same time due to some webGL limitations. During the loop I a) loaded the model; b) got the height (z-Value) of my model with THREE.Box3(); and finally c) logged the respective value to a text file (with debugout.js). This values are then copied to my array where I draw the models in Cesium.

Hyper Sonic

unread,
Apr 20, 2015, 1:51:00 PM4/20/15
to cesiu...@googlegroups.com
Although I had trouble getting viewer.scene.globe.getHeight to work in SandCastle, it works just fine in a regular Cesium app. You can use this to test if there's any difference between 14-15 LOD and 16-20 LOD by moving the camera very close to the ground at the spot. Change viewer.scene.screenSpaceCameraController.minimumZoomDistance to 2 (default is 20 meters) to get the tile LOD as high as you can. 


Hyper Sonic

unread,
Apr 25, 2015, 12:54:08 AM4/25/15
to cesiu...@googlegroups.com

I noticed everything is set at 113.5 meters. Model origin to 'terrain bottom' (top of the basement) can vary from model to model and each part of a city block can vary in terrain height. I'm guessing that since the bottom of the basements seem to align that the model origin is at the bottom of those models.

Jerrold Siegel

unread,
Apr 25, 2015, 11:06:44 AM4/25/15
to cesiu...@googlegroups.com
Hyper Sonic, again thank you for the code to capture a position. I got it to do exactly what I needed. Capture a position, mouse around, and then return to the original position. Here is a link http://vcities.ite-stl.org/Cesium/Apps/Sandcastle/gallery/position.html.

The link also is a good example of the issues we are facing.  First, it takes a while to load the page.  When it is loaded go to 1919. When I mouse around the graphics are pokey. Finally, we have a large catalog of buildings that we need to move and we only know how to set the position relative to the ground, building by building. We do know the basement height but haven't figured out how calculate a per building height based on basement height and terrain height.

Hyper Sonic

unread,
Apr 25, 2015, 2:55:07 PM4/25/15
to cesiu...@googlegroups.com
It's OK that it takes a few seconds to load, but a progress indicator might be nice, such as x% loaded on a div off to the side. You might have to carefully place each building. I made a SandCastle that allows one to move an entity in any cardinal direction either 1 meter or 10 meters which might help, it prints the new location in the console. I'd like to do the same for orientation, but I don't know how to get that. To get position I have to use a private property: thebox._position._value . I'm not sure yet about orientation,  thebox._orientation._value doesn't work. Sure would be nice to have access to entity modelMatrix .

var viewer = new Cesium.Viewer('cesiumContainer');
var CC3 = Cesium.Cartesian3;
var magnitude = 1;

var thebox = viewer.entities.add({
    name : 'building',
    position: Cesium.Cartesian3.fromDegrees(-90.1922703175, 38.6286636758, 30),
    box : {
        dimensions : new Cesium.Cartesian3(40, 30, 60),
        material : Cesium.Color.RED,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});
viewer.zoomTo(viewer.entities);
function getVector(name)
{
    var GD_full_transform = Cesium.Transforms.eastNorthUpToFixedFrame(thebox._position._value, viewer.scene.globe.ellipsoid, new Cesium.Matrix4());
    var GD_rot_transform = Cesium.Matrix4.getRotation(GD_full_transform,new Cesium.Matrix3());
    if(name=="east"){return Cesium.Matrix3.getColumn(GD_rot_transform,0,new CC3());}
    if(name=="north"){return Cesium.Matrix3.getColumn(GD_rot_transform,1,new CC3());}
    if(name=="up"){return Cesium.Matrix3.getColumn(GD_rot_transform,2,new CC3());} 
}
function move(scalar,unitVector)
{
    var mycarte = thebox._position._value;
    var relMove = CC3.multiplyByScalar(unitVector,scalar,new CC3());
    CC3.add(mycarte,relMove,mycarte);
    thebox.position = mycarte;   
    var mycarto = new Cesium.Cartographic();
    mycarto = viewer.scene.globe.ellipsoid.cartesianToCartographic(thebox._position._value);
    console.log("lon "+mycarto.longitude/Math.PI*180);
    console.log("lat "+mycarto.latitude/Math.PI*180);
    console.log("alt "+mycarto.height);
}
Sandcastle.addToolbarButton('magnitude 1', function() 
{magnitude=1;});
Sandcastle.addToolbarButton('magnitude 10', function() 
{magnitude=10;});

Sandcastle.addToolbarButton('east', function() 
{move(magnitude,getVector("east"));});
Sandcastle.addToolbarButton('west', function() 
{move(-magnitude,getVector("east"));});
Sandcastle.addToolbarButton('north', function() 
{move(magnitude,getVector("north"));});
Sandcastle.addToolbarButton('south', function() 
{move(-magnitude,getVector("north"));});
Sandcastle.addToolbarButton('up', function() 
{move(magnitude,getVector("up"));});
Sandcastle.addToolbarButton('down', function() 
{move(-magnitude,getVector("up"));});

Jerrold Siegel

unread,
Apr 26, 2015, 10:55:31 AM4/26/15
to cesiu...@googlegroups.com
Thanks,
I know I keep saying the same thing but you example is going to be very useful. One thing, a bit off the subject, that has been giving me fits is how you get the cube "name" to appear in a billboard when you  click on it. This would be a very useful feature for us, click on a building and have information appear.

Jerrold Siegel

unread,
Apr 26, 2015, 11:32:54 AM4/26/15
to cesiu...@googlegroups.com
Duhhhh, I think I just figured  out how to get the popups. Sorry
 
 

Hyper Sonic

unread,
Apr 26, 2015, 12:20:33 PM4/26/15
to cesiu...@googlegroups.com
I also was wondering how to make entities selectable. All of these entities are selectable by default http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Geometry%20and%20Appearances.html&label=Showcases as I don't see something like selectable:true . Yet you have model entities, perhaps selectability is off by default for those?

"Unless we specifically disable it, clicking on an entity in the Viewer will show the SelectionIndicatorwidget at the Entity’s location as well as bring up the InfoBox widget to provide more information. "

In my example program you can change
thebox._position._value
to
viewer.selectedEntity._position._value

Then you can select and move any entity from a group of entities.

So how did you make them selectable? Did adding infobox property also make them selectable?

Jerrold Siegel

unread,
Apr 26, 2015, 1:20:18 PM4/26/15
to cesiu...@googlegroups.com
Previously, I had
var viewer = new Cesium.Viewer('cesiumContainer', {
            infoBox : false,
            selectionIndicator : false,
            terrainProviderViewModels: terrainModels,
            selectedTerrainProviderViewModel: terrainModels[1]  // Select STK High-res terrain
});

All I did was remove the two "false" lines.
var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProviderViewModels: terrainModels,
    selectedTerrainProviderViewModel: terrainModels[1]  // Select STK High-res terrain
});
Here is the new URL   http://vcities.ite-stl.org/Cesium/Apps/Sandcastle/gallery/Block512.html
The buildings on the right have some play information. Eventually there will be some building history. I also began to move buildings to ground level.

Jerrold Siegel

unread,
Apr 26, 2015, 1:28:28 PM4/26/15
to cesiu...@googlegroups.com
 
Again, too quick on the trigger. Go to year 1919 to see the buildings I am referring to. 

Hyper Sonic

unread,
Apr 26, 2015, 2:17:38 PM4/26/15
to cesiu...@googlegroups.com
Ah, I forgot to look at the viewer options.

The buildings look much better now. The origin on some of the buildings seems to be away from the center as the green crosshairs that appear are off to the side. I wonder if there's a way to correct this without having to adjust the model.

Some buildings can look odd due to terrain tilt. Here's some extreme examples in SF:

Jerrold Siegel

unread,
Apr 27, 2015, 9:03:40 AM4/27/15
to cesiu...@googlegroups.com


Wow, you remind me, There are streets in St. Louis that are a bit challenging, near the Mississippi for example, but not even close.

Do you happen to know where to look for this popup infoBox 's code, or how to, to resize and format it on the fly? For some buildings there is going to be a lot of text.

Hyper Sonic

unread,
Apr 27, 2015, 12:46:32 PM4/27/15
to cesiu...@googlegroups.com
infoBox is created in the viewer constructor and infoBox resides in a div called infoBoxContainer

https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Widgets/InfoBox/InfoBox.js#L135 (line # for Cesium 1.8)
"// Measure and set the new custom height, based on text wrapped above."

Regarding the width, I haven't see any apps that adjust it's width. That seems to be a fixed % relative to the overall size of the Cesium div.
width: 40%;
max-width: 480px;

You can inject this into any SandCastle that uses infoBox to find some info about it after clicking on something that causes it to appear
Sandcastle.addToolbarButton('info', function() 
{console.log(viewer.infoBox._element);});

Perhaps selecting an entity has a callback function you can use to make your own custom div? I haven't looked through the entity selection code yet.

Matthew Amato

unread,
Apr 27, 2015, 1:26:45 PM4/27/15
to cesiu...@googlegroups.com
The InfoBox adjusts the width to fit it's content.  You can provide it HTML content that provides it's own width and styling.  For example, notice the custom styling in balloons for the KML Sandcastle demo: http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=KML.html&label=Showcases

You can also override the default styling in your app by overriding the CSS properties in InfoBox.css.  There's no need to modify the file itself, just override the values in your own app's CSS.  For example, if you wanted to override the width/max-width settings you can just add the below with whatever values you want.

.cesium-infoBox {
    width: 40%;
    max-width: 480px;
}


--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hyper Sonic

unread,
Apr 27, 2015, 1:58:24 PM4/27/15
to cesiu...@googlegroups.com
You could also do
viewer.infoBox._element.style.width="80%";
viewer.infoBox._element.style.maxWidth="800px";
viewer.infoBox._element.style.overflow="scroll"; //or "hidden"
since there's only one infobox, though you'd be using a private property with the underscored name.

Jerrold Siegel

unread,
Apr 27, 2015, 2:59:30 PM4/27/15
to cesiu...@googlegroups.com
Being able to use HTML content would be wonderful. 

This link shows, basically, where I am.  .
.

Here is the relevant code:

var building28 = viewer.entities.add({
                           id: "building28",
                           name:"Firehouse 512  Built 1888-Demolished 1932",
                           availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
                                                      start : Cesium.JulianDate.fromIso8601("1888-01-01"),
                                                      stop : Cesium.JulianDate.fromIso8601("1932-01-01")
                                                })]),
                                  position: Cesium.Cartesian3.fromDegrees(-90.20276954596574
,38.63089539292937,118.2),
                                  model:{
                                  uri:'../../SampleData/models512/90359.gltf'
                                  }
                                  } 
                                 ); 

When I click on the building28 entity I see the "name" value.

I attached a screen shot firehouse.jpg. 

The data at the link is is just play, .
Here is some real data, though not for this firehouse.


I also attached a screenshot firehouse_data.jpg

What I would like to happen is that when I click on the building, an abbreviated version of this Page would appear in the InfoBox rather than just the text  "Firehouse 512 Built 1888-Demolished 1932"
firehouse_data.jpg
firehouse.jpg

Hyper Sonic

unread,
Apr 27, 2015, 4:47:35 PM4/27/15
to cesiu...@googlegroups.com
On that link that Matt gave http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=KML.html&label=Showcases
The infoBox div has these elements
-title div
-camera button
-exit button
-iframe

The iframe consist of an HTML document.

I'm not sure how you set the href of the iframe however.

Matthew Amato

unread,
Apr 27, 2015, 4:51:04 PM4/27/15
to cesiu...@googlegroups.com
You don't.  You simple set the entity.description property to whatever HTML snippet you want.  You can even have that snippet be an iFrame that embeds another site.  Then when you click on an entity, it will load that snippet.

--

Hyper Sonic

unread,
Apr 27, 2015, 5:04:26 PM4/27/15
to cesiu...@googlegroups.com
I should have read the entity doc first https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/DataSources/Entity.js#L94 I noticed that the green selector is off center on some of the buildings (year 1919 west side.) I'm guessing that's where the model origin is. Is there a way to offset that? 

Matthew Amato

unread,
Apr 27, 2015, 5:13:14 PM4/27/15
to cesiu...@googlegroups.com
Currently the selection indicator is positioned based on the combined bounding sphere of all visualization associated with that entity.  It's not perfect but it provides the best value most of the time.  We may provide a way to override it in the future, but it's not on anyone short term schedule.  You can such off the selectionIndicator widget and plug in your own easily enough that uses whatever metric you want.

On Mon, Apr 27, 2015 at 5:04 PM, Hyper Sonic <gman...@gmail.com> wrote:
I should have read the entity doc first https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/DataSources/Entity.js#L94 I noticed that the green selector is off center on some of the buildings (year 1919 west side.) I'm guessing that's where the model origin is. Is there a way to offset that? 

--

Hyper Sonic

unread,
Apr 27, 2015, 10:47:24 PM4/27/15
to cesiu...@googlegroups.com
I tried typing viewer.selectionIndicator in the console, but then I noticed that Jerrold's examples are SandCastle apps and I don't know where the viewer object is buried in SandCastle apps.

Usually the selection indicator is well positioned, but I think the origin point of some of these models is off to the side of the model, not in the center of the model, and the model is the only visualization of the entity. 

viewer.selectionIndicator.position probably matches the model's position
It would be nice if entities provided a 'origin to model center' offset (which would default to (0,0,0) ), as origin and center are not always one in the same.

Jerrold Siegel

unread,
Apr 28, 2015, 10:24:59 AM4/28/15
to cesiu...@googlegroups.com
 
You folks are making this far to easy :) 


Go to year 1919. The two building that have description content are the one on the left corner, which just has HTML, and the fourth building from the left, just after the alley, which has an iframe showing a random Page. There is lots and lots of Web Page Design left to be done before you would actually show this Page but everything is there that we need to go to the next level.

Much Thanks,

Hyper Sonic

unread,
Apr 28, 2015, 11:48:42 AM4/28/15
to cesiu...@googlegroups.com
I'm glad we could help. It's nice to witness the progress! I've noticed you're placing everything in SandCastle though. You could probably drop the code into Cesium\Apps\HelloWorld.html to convert to a regular app.

Maybe html content could have an abbreviated version with a show more link like I see many mobile news sites have.

Smith Meats building and it's twin neighbor seem to have the origin on it's side, not a big deal though.

It would be nice to resize the The Old Firehouse infoBox content
Then when closing the infoBox maybe make it go back to normal size somehow.

Jerrold Siegel

unread,
Apr 28, 2015, 1:38:36 PM4/28/15
to cesiu...@googlegroups.com
I will work through your suggestions. I have been punting on portability, in particular, since, in the end, all of the Pages will be created dynamically out of a database (and some text files), using a .php generator. Based on our present experience with the current incarnation, the historical data seems to be in a constant state of flux. So static Pages are always out of data, which means access is needed to the database and file system, etc.So leaving the stuff in Sandcastle is less of an issue.Basically,  portability has been achieved through forms.For example,  http://vcities.umsl.edu/tours/Blocksm.html. on a different project server. Anyway, your point is still important and I will now bite the bullet. Again, thanks.

Jerrold Siegel

unread,
May 10, 2015, 11:33:16 AM5/10/15
to cesiu...@googlegroups.com
I would really appreciate it if somebody could help me with this? Some of the buildings in our views are not important and it would be useful if we could turn off the infoBox for those entities.

 Plan B would be to work with the selectionIndicator,  turn it off for certain entities. I tried


        viewer.scene.canvas.addEventListener('click', function(e) {
               viewer.selectionIndicator.viewModel.showSelection=false;
                });
which does not work.

Is there a way to do this? Also I have not figured out how to compute the entity.id of the entity being clicked.
Thanks,

nosig...@gmail.com

unread,
May 23, 2015, 3:04:29 PM5/23/15
to cesiu...@googlegroups.com
Hello

I have also a follow up question:

Am Montag, 20. April 2015 04:17:31 UTC+2 schrieb Hyper Sonic:

In Cesium 1.7: "Added camera-terrain collision detection/response when the camera reference frame is set." I think you can turn this off, but I don't know which var to set.


I thought it should be this function. But when I set viewer.scene.enableColissionDetection = false; the camera follows still the terrain. What else do I have to set that the camera can also go "below" the terrain?

Thanks and Regards
Martin

Mike LP

unread,
May 25, 2015, 10:58:37 PM5/25/15
to cesiu...@googlegroups.com, nosig...@gmail.com
The SceneCameraController tries to prevent the camera from going below terrain.  The easiest method is going to overwrite the mouse handlers so you can use the scene.camera object directly.  The Camera methods are allowed to go wherever you tell it to regardless of terrain collision. 
Reply all
Reply to author
Forward
0 new messages