Skip to content

Commit

Permalink
extrude polygons to terrain
Browse files Browse the repository at this point in the history
  • Loading branch information
hpinkos committed Feb 15, 2018
1 parent 08cdd6e commit c0fc209
Show file tree
Hide file tree
Showing 14 changed files with 663 additions and 125 deletions.
66 changes: 66 additions & 0 deletions Apps/Sandcastle/gallery/Extruded Polygon on Terrain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Demonstrates how to use the Entity API to create a geometry that extrudes down to terrain">
<meta name="cesium-sandcastle-labels" content="Geometries">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
<script type="text/javascript">
if(typeof require === "function") {
require.config({
baseUrl : '../../../Source',
waitSeconds : 120
});
}
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer');
viewer.scene.globe.depthTestAgainstTerrain = true;
var terrainProvider = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});
viewer.terrainProvider = terrainProvider;
var hierarchy = new Cesium.ConstantProperty(Cesium.Cartesian3.fromDegreesArray([-110.9365046146508,37.45609196222294,
-110.9371577263633,37.46126425372983,
-110.9455523711973,37.45766987108922,
-110.9433924350152,37.45268714057247,
-110.9365046146508,37.45609196222294]));

var redPolygon = viewer.entities.add({
polygon : {
hierarchy : hierarchy,
material : Cesium.Color.RED,
height : 1800.0,
extrudedHeight : new Cesium.MinimumTerrainHeightProperty(hierarchy)
}
});

viewer.zoomTo(viewer.entities);
//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Apps/Sandcastle/gallery/Picking.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function(movement) {
var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, scene.globe.ellipsoid);
if (cartesian) {
if (Cesium.defined(cartesian)) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Change Log

##### Additions :tada:
* Added support for a promise to a resource for `CesiumTerrainProvider`, `createTileMapServiceImageryProvider` and `Cesium3DTileset` [#6204](https://github.com/AnalyticalGraphicsInc/cesium/pull/6204)
* Added `MinimumTerrainHeightProperty`, which can be used for extruding geometry down to terrain [#6214](https://github.com/AnalyticalGraphicsInc/cesium/pull/6214)
* Added `Cesium.Math.cbrt`. [#6222](https://github.com/AnalyticalGraphicsInc/cesium/pull/6222)
* `Resource` class [#6205](https://github.com/AnalyticalGraphicsInc/cesium/issues/6205)
* Added `put`, `patch`, `delete`, `options` and `head` methods, so it can be used for all XHR requests.
Expand Down
203 changes: 203 additions & 0 deletions Source/Core/ApproximateTerrainHeights.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
define([
'./buildModuleUrl',
'./defaultValue',
'./defined',
'./BoundingSphere',
'./Cartesian2',
'./Cartesian3',
'./Cartographic',
'./Check',
'./DeveloperError',
'./Ellipsoid',
'./GeographicTilingScheme',
'./Rectangle',
'./Resource'
], function(
buildModuleUrl,
defaultValue,
defined,
BoundingSphere,
Cartesian2,
Cartesian3,
Cartographic,
Check,
DeveloperError,
Ellipsoid,
GeographicTilingScheme,
Rectangle,
Resource) {
'use strict';

var scratchDiagonalCartesianNE = new Cartesian3();
var scratchDiagonalCartesianSW = new Cartesian3();
var scratchDiagonalCartographic = new Cartographic();
var scratchCenterCartesian = new Cartesian3();
var scratchSurfaceCartesian = new Cartesian3();

var scratchBoundingSphere = new BoundingSphere();
var tilingScheme = new GeographicTilingScheme();
var scratchCorners = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
var scratchTileXY = new Cartesian2();

/**
* A collection of functions for approximating terrain height
* @private
*/
var ApproximateTerrainHeights = {};

/**
* Initializes the minimum and maximum terrain heights
* @return {Promise}
*/
ApproximateTerrainHeights.initialize = function() {
var initPromise = ApproximateTerrainHeights._initPromise;
if (defined(initPromise)) {
return initPromise;
}

ApproximateTerrainHeights._initPromise = Resource.fetchJson(buildModuleUrl('Assets/approximateTerrainHeights.json')).then(function(json) {
ApproximateTerrainHeights._terrainHeights = json;
});

return ApproximateTerrainHeights._initPromise;
};

/**
* Computes the minimum and maximum terrain heights for a given rectangle
* @param {Rectangle} rectangle THe bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {{minimumTerrainHeight: Number, maximumTerrainHeight: Number}}
*/
ApproximateTerrainHeights.getApproximateTerrainHeights = function(rectangle, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
Check.defined('rectangle', rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError('You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function');
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);

var xyLevel = getTileXYLevel(rectangle);

// Get the terrain min/max for that tile
var minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
var maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
var heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
minTerrainHeight = heights[0];
maxTerrainHeight = heights[1];
}

// Compute min by taking the center of the NE->SW diagonal and finding distance to the surface
ellipsoid.cartographicToCartesian(Rectangle.northeast(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianNE);
ellipsoid.cartographicToCartesian(Rectangle.southwest(rectangle, scratchDiagonalCartographic),
scratchDiagonalCartesianSW);

Cartesian3.subtract(scratchDiagonalCartesianSW, scratchDiagonalCartesianNE, scratchCenterCartesian);
Cartesian3.add(scratchDiagonalCartesianNE,
Cartesian3.multiplyByScalar(scratchCenterCartesian, 0.5, scratchCenterCartesian), scratchCenterCartesian);
var surfacePosition = ellipsoid.scaleToGeodeticSurface(scratchCenterCartesian, scratchSurfaceCartesian);
if (defined(surfacePosition)) {
var distance = Cartesian3.distance(scratchCenterCartesian, surfacePosition);
minTerrainHeight = Math.min(minTerrainHeight, -distance);
} else {
minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight;
}
}

minTerrainHeight = Math.max(ApproximateTerrainHeights._defaultMinTerrainHeight, minTerrainHeight);

return {
minimumTerrainHeight: minTerrainHeight,
maximumTerrainHeight: maxTerrainHeight
};
};

/**
* Computes the bounding sphere based on the tile heights in the rectangle
* @param {Rectangle} rectangle The bounding rectangle
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid
* @return {BoundingSphere} The result bounding sphere
*/
ApproximateTerrainHeights.getInstanceBoundingSphere = function(rectangle, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
Check.defined('rectangle', rectangle);
if (!defined(ApproximateTerrainHeights._terrainHeights)) {
throw new DeveloperError('You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function');
}
//>>includeEnd('debug');
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);

var xyLevel = getTileXYLevel(rectangle);

// Get the terrain max for that tile
var maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight;
if (defined(xyLevel)) {
var key = xyLevel.level + '-' + xyLevel.x + '-' + xyLevel.y;
var heights = ApproximateTerrainHeights._terrainHeights[key];
if (defined(heights)) {
maxTerrainHeight = heights[1];
}
}

var result = BoundingSphere.fromRectangle3D(rectangle, ellipsoid, 0.0);
BoundingSphere.fromRectangle3D(rectangle, ellipsoid, maxTerrainHeight, scratchBoundingSphere);

return BoundingSphere.union(result, scratchBoundingSphere, result);
};

function getTileXYLevel(rectangle) {
Cartographic.fromRadians(rectangle.east, rectangle.north, 0.0, scratchCorners[0]);
Cartographic.fromRadians(rectangle.west, rectangle.north, 0.0, scratchCorners[1]);
Cartographic.fromRadians(rectangle.east, rectangle.south, 0.0, scratchCorners[2]);
Cartographic.fromRadians(rectangle.west, rectangle.south, 0.0, scratchCorners[3]);

// Determine which tile the bounding rectangle is in
var lastLevelX = 0, lastLevelY = 0;
var currentX = 0, currentY = 0;
var maxLevel = ApproximateTerrainHeights._terrainHeightsMaxLevel;
var i;
for(i = 0; i <= maxLevel; ++i) {
var failed = false;
for(var j = 0; j < 4; ++j) {
var corner = scratchCorners[j];
tilingScheme.positionToTileXY(corner, i, scratchTileXY);
if (j === 0) {
currentX = scratchTileXY.x;
currentY = scratchTileXY.y;
} else if(currentX !== scratchTileXY.x || currentY !== scratchTileXY.y) {
failed = true;
break;
}
}

if (failed) {
break;
}

lastLevelX = currentX;
lastLevelY = currentY;
}

if (i === 0) {
return undefined;
}

return {
x : lastLevelX,
y : lastLevelY,
level : (i > maxLevel) ? maxLevel : (i - 1)
};
}

ApproximateTerrainHeights._terrainHeightsMaxLevel = 6;
ApproximateTerrainHeights._defaultMaxTerrainHeight = 9000.0;
ApproximateTerrainHeights._defaultMinTerrainHeight = -100000.0;
ApproximateTerrainHeights._terrainHeights = undefined;
ApproximateTerrainHeights._initPromise = undefined;

return ApproximateTerrainHeights;
});
Loading

0 comments on commit c0fc209

Please sign in to comment.