Skip to content
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

Added terrain drawing sandcastle example #6692

Merged
merged 11 commits into from
Jun 21, 2018
Merged
156 changes: 156 additions & 0 deletions Apps/Sandcastle/gallery/Drawing on Terrain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!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="Draw lines and polygons on terrain with mouse clicks.">
<meta name="cesium-sandcastle-labels" content="Showcases">
<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">
require.config({
baseUrl : '../../../Source',
waitSeconds : 60
});
</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">
<table class="infoPanel">
<tbody>
<tr>
<td>Left click to add a vertex.</td>
</tr>
<tr>
<td>Right click to start new shape.</td>
</tr>
</tbody>
</table>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer', {
selectionIndicator : false,
infoBox : false,
terrainProvider : Cesium.createWorldTerrain()
});
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
function createPoint(worldPosition) {
var point = viewer.entities.add({
position : worldPosition,
point : {
color : Cesium.Color.WHITE,
pixelSize : 5,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
}
});
return point;
}
var drawingMode = 'line';
function drawShape(positionData) {
var shape;
if (drawingMode === 'line') {
shape = viewer.entities.add({
polyline : {
positions : positionData,
clampToGround : true,
width : 3
}
});
}
else if (drawingMode === 'polygon') {
shape = viewer.entities.add({
polygon: {
hierarchy: positionData,
outline: true,
material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.7))
}
});
}
return shape;
}
var activeShapePoints = [];
var activeShape;
var floatingPoint;
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(function(event) {
// We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
// we get the correct point when mousing over terrain.
var earthPosition = viewer.scene.pickPosition(event.position);
// `earthPosition` will be undefined if our mouse is not over the globe.
if (Cesium.defined(earthPosition)) {
if (activeShapePoints.length === 0) {
floatingPoint = createPoint(earthPosition);
activeShapePoints.push(earthPosition);
var dynamicPositions = new Cesium.CallbackProperty(function () {
return activeShapePoints;
}, false);
activeShape = drawShape(dynamicPositions);
}
activeShapePoints.push(earthPosition);
createPoint(earthPosition);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

handler.setInputAction(function(event) {
if (Cesium.defined(floatingPoint)) {
var newPosition = viewer.scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
floatingPoint.position.setValue(newPosition);
activeShapePoints.pop();
activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// Redraw the shape so it's not dynamic and remove the dynamic shape.
function terminateShape() {
activeShapePoints.pop();
drawShape(activeShapePoints);
viewer.entities.remove(floatingPoint);
viewer.entities.remove(activeShape);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shapes flash when you terminate the shape. Is it possible to re-use the same entity and create the position property, or do we have to delete the old one and create a new dynamic one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested that out, and it'll still take a few seconds to render when you switch the CallbackProperty with just an array of points.

I talked briefly with @mramato about this. We could do any of the following to remove that flicker:

  • Keep all the shapes with isConstant : false
  • Don't remove the dynamic shape right away, keep it there for a few seconds to hide the gap until the new one renders.

But none of those seem like good practices we want to encourage in an official Sandcastle example.

It might be nice to have a "flush" command that would try to immediately render an entity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a long standing issue in "sometimes changing" geometry data in Cesium. I recommend this PR keeps whatever is cleanest for example code. I would love to see us improve interactive geometry like this, but it's probably going to result in a request-render style method for entities that needs to be thought through.

floatingPoint = undefined;
activeShape = undefined;
activeShapePoints = [];
}
handler.setInputAction(function(event) {
terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

var options = [{
text : 'Draw Lines',
onselect : function() {
terminateShape();
drawingMode = 'line';
}
}, {
text : 'Draw Polygons',
onselect : function() {
terminateShape();
drawingMode = 'polygon';
}
}];

Sandcastle.addToolbarMenu(options);
// Zoom in to an area with mountains
viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(-122.2058, 46.1955, 1000.0), new Cesium.Cartesian3(5000.0, 5000.0, 5000.0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
Binary file added Apps/Sandcastle/gallery/Drawing on Terrain.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.