Cesium how to 'drape' a polygon or line onto terrain surface - javascript

So, I'm using cesium and I want to add a polygon or line to represent a property boundary on a terrain surface.
My polygon works fine on the flat/Ellipsoid surface, unfortunately however the polygon doesn't automagically drape over the surface when the terrain layer is shown.
Fair enough, I don't actually have the z/height values - so I'm using the sampleTerrain.js promise method to interpolate the height values based on the terrain. This part works fine, I get my height values. But then what?
I've tried creating a polygon entity with my height-laden positions, but to no avail - it just ignores the height values. When I read the docs, I can really see any reference to height values being ingested - all the "positions" array are two dimensional?
The only reference to height values being considered is in the PolygonOutlineGeometry, which has a promising looking property called perPositionHeight.
This is essentially what I want - I don't want to set the height of the whole poly, I want every points height value to be used..
Here's one of my unsuccessful attempts:
Entity/Polygon:
var entity = viewer.entities.add({
polygon : {
hierarchy : cartesianPositions, //array of positions with z values
outline : true,
outlineColor : Cesium.Color.RED,
outlineWidth : 9,
material : Cesium.Color.BLUE.withAlpha(0.0),
}
});
Bottom line: I just want a polygon or polyline entity that sits nicely on the surface of the terrain.
EDIT:
Using the Orange Polygon example in the comments of the accepted answer combined with sampleTerrain.js, I've been able to simulate 'draping' a polygon onto terrain, with a list of positions that did not have z values, here's a crude example:
var positions = []; // xy position array
var cesiumTerrainProvider = new Cesium.CesiumTerrainProvider({
url : '//assets.agi.com/stk-terrain/world'
});
viewer.terrainProvider = cesiumTerrainProvider;
// go off and sample the terrain layer to get interpolated z values for each position..
var promise = Cesium.sampleTerrain(cesiumTerrainProvider, 11, positions);
Cesium.when(promise, function(updatedPositions) {
var cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(updatedPositions);
var entity = viewer.entities.add({
polygon : {
hierarchy : cartesianPositions,
outline : true,
outlineColor : Cesium.Color.RED,
outlineWidth : 9,
perPositionHeight: true,
material : Cesium.Color.BLUE.withAlpha(0.0),
}
});
viewer.flyTo(entity);
});

As of version 1.13 cesium now supports GroundPrimitives. They will drape over terrain.
It looks like this: http://cesiumjs.org/images/2015/09-01/groundPrimitives.gif
This the example Cesium gives:
var rectangleInstance = new Cesium.GeometryInstance({
geometry : new Cesium.RectangleGeometry({
rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0)
}),
id : 'rectangle',
attributes : {
color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
}
});
scene.primitives.add(new Cesium.GroundPrimitive({
geometryInstance : rectangleInstance
}));

Cesium does not support vector data on terrain yet. It is being actively worked on and most features should start to appear in Cesium 1.10 which will be out on June 1st. Anything that doesn't make that release should be in 1.11 on July 1st.
For Polygons specifically, you can follow along with the GitHub pull request: https://github.com/AnalyticalGraphicsInc/cesium/pull/2618
For Billboards and Labels, check out: https://github.com/AnalyticalGraphicsInc/cesium/pull/2653
Polylines haven't been started yet but will be as soon as the above two are finished.

Related

How to download sentinel 1 for a particular polygon from Google Earth Engine

I want to download Sentinel-1 SAR data for both VV and VH with IW only within a rectangular polygon? I could download with the ROI, but even though ROI is a rectangle, the output to export is a rectangle.
The red rectangle is my ROI, but it's taking the extreme coordinates and making a square that encloses the ROI and exporting that output as shown.
I only want the data inside the ROI.
I even tried to use ee.Image.clip. But I couldn't able to comeup with a solution which can download the data. It was going to a large file
var start_date = ee.Date('2019-05-01');
finish_date = ee.Date('2019-06-15');
var orbit = 'ASCENDING';
var collectionS1 = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
// .filter(ee.Filter.eq('orbitProperties_pass', orbit))
.filterDate(start_date, finish_date)
//.filterBounds(polygons);
// Get the VV collection.
var collectionVV = collectionS1.select('VV');
// Get the VH collection.
var collectionVH = collectionS1.select('VH');
var VV = ee.Image(collectionVV.first().clip(roi_A); //roi_A is my rectangular roi
var VH = ee.Image(collectionVH.first());
// I would like to take VV and VH and stack them and download
var VVVH = VV.addBands(VH)
Export.image.toDrive({
image: VV,
description: 'A_ERT',
scale: 10,
//region: ROI,
fileFormat: 'GeoTIFF',
//formatOptions: {
// cloudOptimized: true
//}
});
I'm getting the following error message.
Error: Export too large: specified 6875185131 pixels (max: 100000000). Specify higher maxPixels value if you intend to export a large area.
At first, have a look at the guide here:
https://developers.google.com/earth-engine/guides/exporting
There are multiple ways to go about this in Export.image.toDrive:
specify a region - create geometry and specify its name in the export (f.ex. region: geometry)
if exporting large scale images - reduce the scale (f.ex. scale: 20)
in case you really want the full resolution for your region - add "maxPixels:" to your export and increase the value as specified in the guide I linked above (f.ex. maxPixels: 1e10)
To speed up your workflow also filter data in your imageCollection to your geometry by adding .filterBounds(geometry)

Cesium - drawing polygon using camera Lat-Lon-Alt positions

This question is related to these two:
Cesium how to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out
Cesium - using camera to scale a polygon to match Lat-Lon positions while zoom-in/zoom-out
The sample code I am following to get lat-lon-alt positions from the camera is located in the gold standard that appears to be baked into the existing camera controller. With this code I can retrieve lat-lon-alt positions from the distance of the camera to get values that are almost exact to the original lat-lon position selected and a height above the surface of the earth. Perfect!
All examples and documentation show polygon creation using degrees or points from degrees.
Now what? Maybe I'm missing something but the intent I thought was to be able to create the polygon using specific x, y, z coordinates so the polygon would "stick" to the top of my house on zoom-in, zoom-out, and camera movement. Now that I have those values, what is the secret to drawing the polygon with those values?
FYI, these are the value I currently have:
=========================NEW INFORMATION===========================
The code for the redPolygon works:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
-115.0, 32.0,
-102.0, 31.0,
-102.0, 35.0,
-102.0, 35.0]),
material : Cesium.Color.RED
}
});
viewer.flyTo(redPolygon);
The code for the bluePolygon does not work:
var bluePolygon = viewer.entities.add({
name : 'Blue polygon on surface',
polygon : {
//hierarchy: collection.latlonalt,
hierarchy: Cesium.Cartesian3.fromArray(collection.latlonalt),
material : Cesium.Color.BLUE
}
});
viewer.flyTo(bluePolygon);
If I use hierarchy: collection.latlonalt, I receive the following error:
So I changed the code to hierarchy: Cesium.Cartesian3.fromArray(collection.latlonalt), where collection.latlonalt is my Cartesian3 array:
But nothing gets drawn. No errors. This is what I see in the console:
Just for test, I tried adding a z position to the redPolygon and changing .fromDegreesArray to .fromArray like this:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromArray([-115.0, 37.0, 10.0,
-115.0, 32.0, 10.0,
-102.0, 31.0, 10.0,
-102.0, 35.0, 10.0,
-102.0, 35.0, 10.0]),
material : Cesium.Color.RED
}
});
viewer.flyTo(redPolygon);
That didn't work either.
Cesium has helper functions like Cartesian3.fromDegreesArray that are used by the Polygon Demo, but, these helper functions are not needed now that you've got your hands on actual Cartesian3 values.
For example, the polygon demo code looks like this:
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
-115.0, 32.0,
-107.0, 33.0,
-102.0, 31.0,
-102.0, 35.0]),
material : Cesium.Color.RED
}
});
In the above code, fromDegreesArray in this case just takes a list of 5 lot/lan value pairs, and converts them into a JavaScript array of 5 instances of the Cartesian3 class. This array of 5 Cartesian3s is then stored as the value of hierarchy in the polygon definition. If you inspect that definition at runtime, you'll find the original lon/lat values have been discarded, replaced by the actual Cartesian3s, thanks to the helper function.
So in your code, you'll need an array of Cartesian3s that the user has clicked on thus far. This starts as the empty array, and you'll need to gather at least three clicks, converting each click into a Cartesian3 as you've shown works in your question above, and push that value into the array. Once the array has accumulated 3 or more clicks, you can then pass that array as the hierarchy field of the polygon definition.
In this manner, you've avoided calling fromDegreesArray because your click handler is doing the more detailed work of gathering an exact Cartesian position per click. This gathering has to happen at the time of each click, in case the camera is moved between clicks. So, the array "in progress" has to survive between clicks, until all the clicks have been gathered and a polygon can be created.
EDIT: Here's an example of the code structure I'm trying to describe. I don't show the actual click handlers here, since you seem to have Cartesian3 values coming out of your mouse clicks already. Instead, I show three such values being used to create a polygon.
var viewer = new Cesium.Viewer('cesiumContainer');
// Create an empty array of click positions at the start.
var clickPositions = [];
// When the first mouse click is received, convert to Cartesian3, and push it into the array.
var click1 = new Cesium.Cartesian3(-2155350.2, -4622163.4, 3817393.1);
clickPositions.push(click1);
// Later, more mouse clicks are received and pushed into the array.
var click2 = new Cesium.Cartesian3(-2288079.8, -4906803.1, 3360431.4);
clickPositions.push(click2);
var click3 = new Cesium.Cartesian3(-1087466.8, -5116129.4, 3637866.9);
clickPositions.push(click3);
// Finally, draw the polygon.
var redPolygon = viewer.entities.add({
name : 'Red polygon on surface',
polygon : {
hierarchy : clickPositions,
material : Cesium.Color.RED
}
});
Notice nothing happens to clickPositions when it's assigned to hierarchy. The array of Cartesian3 values is already in the form needed by Cesium here.

Google map polygon with outside map tinted [duplicate]

This question already has an answer here:
Google Maps API Polygon with "Hole" In Center
(1 answer)
Closed 7 years ago.
First of all, for the issue you're going to read, I used this snippet of code to highlight my polygon :
Highlight polygon and tint rest of map using Google Maps
Here is my code (it's Angular) :
var boundaries = [];
// big area
var overlay = [
new $rootScope.googleApi.LatLng(80.0, -90.0),
new $rootScope.googleApi.LatLng(-60.0, -90.0),
new $rootScope.googleApi.LatLng(-60.0, 90.0),
new $rootScope.googleApi.LatLng(80.0, 90.0)
];
// my polygon
angular.forEach(settings_boundaries, function(val, key) {
boundaries.push(new $rootScope.googleApi.LatLng(val[1], val[0]));
});
// create a polygon with overlay first
var poly = new $rootScope.googleApi.Polygon({
paths: [overlay, boundaries],
strokeColor: "blue",
strokeWeight: "1",
fillColor: "black",
fillOpacity: 0.4,
clickable: false
});
poly.setMap(interactiveMap);
Now, the real problem is,
If I use these coordinates (which I don't remember how I got them in the first place) :
[[1.6101837158203125,49.00274483644452],
[1.6294097900390625,49.01175312475694],
[1.5947341918945312,48.98787759766659],
[1.6101837158203125,49.00274483644452]]
Everything works fine (as you can see here).
But if I use these ones :
[[1.6809940338134766,48.98337149775796],
[1.6791915893554688,48.96849847697763],
[1.7185020446777344,48.995199140974066],
[1.6809940338134766,48.98337149775796]]
This is not working anymore.
As you can see here.
I used this website to generate the coordinates :
http://www.the-di-lab.com/polygon/ (view screenshot)
I searched for a long time what the issue could be, but I have really no idea. It's approximately the same coordinates. The first lat,lon values are the same than the last ones, for both of them.
If you have any idea (I guess there's something special in the coordinates), I would like to know !
Thanks !
Structurally, the coordinates of the triangle are correct. Only a geometrical difference the first triangle (the one functioning) is drawn in a clockwise direction while the latter is drawn counterclockwise. I have already met a situation like this but I do not remember which site. Then try to reverse the direction of drawing of the triangle in this way:
[[1.6809940338134766,48.98337149775796],
[1.7185020446777344,48.995199140974066]
[1.6791915893554688,48.96849847697763]
[1.6809940338134766,48.98337149775796]]

After Effects Extendscript - changing the centerpoint for addlight

Using this example code:
app.project.item(index).layers.addLight(name, centerPoint)
I created the following test code where I add a light to my second scene (composition) in my project to create a shadow:
var s2light1 = scene2.layers.addLight("s2light1", [1143,121]);
This works perfectly. But I now also want to set the 3rd (Z) value for the centerPoint in Extendscript (as is possible in After Effects).
However according to the After Effects CS6 scripting guide it seems you can only set the X and Y values: "The center of the new camera, a floating-point array [x, y]. This is used to set the initial x and y values of the new camera’s Point of Interest property. The z value is set to 0."
Is there another approach or work around to set the Z-value for the center point in Extendscript which I can try?
newLight = app.project.item(1).layers.addLight("foo", [22, 33]);
//now set the point of interest ('center point') value:
newLight.property("Point of Interest").setValue([22, 33, 11]);
and to make a light not auto-orient (one-node):
newLight.autoOrient = AutoOrientType.NO_AUTO_ORIENT;
In which case you would control the Position and Rotation properties -- no point of interest.

Cesium JS How to fade a polyline to transparent

I had a look at Material Fade, but it was not working well and I had to try to find the direction of the polyline. Not sure if Fade even works with polyline with 20 points...
Is there a better way to change the color between each polyline point?
Or a working example of using Material Fade is much appreciated!
The PerInstanceColorAppearance sounds like what I'm looking for... but I have no idea how to implement this for the Polyline in the PolylineCollection...
How does a polyline collection with several polylines that is added to the primitives translate into something like this from the example http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Geometry%20and%20Appearances.html
positions = [];
colors = [];
for (i = 0; i < 40; ++i) {
positions.push(ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-100.0 + i, 9.0)));
colors.push(Cesium.Color.fromRandom({alpha : 1.0}));
}
primitives.add(new Cesium.Primitive({
geometryInstances : new Cesium.GeometryInstance({
geometry : new Cesium.PolylineGeometry({
positions : positions,
width : 10.0,
vertexFormat : Cesium.PolylineColorAppearance.VERTEX_FORMAT,
colors : colors,
colorsPerVertex : true
})
}),
appearance : new Cesium.PolylineColorAppearance()
}));
I've also added a life-duration attribute to each polyline to determine when they need to be removed from the polyline collection. Potentially I have a lot of polylines that need to be added and removed per second and each polyline has different points.

Categories

Resources