I have terrain view in Cesium Sandcastle and I have loaded roads data in GeoJSON format, they are lines. I want to clamp them on terrain, like this example (in drop-down menu choose "Sample line positions and draw with depth test disabled") -> http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Ground%20Clamping.html&label=Tutorials
In the example, the line you see is defined within code, but I have data (roads) on my PC which is loaded in app. When loaded, roads are flat (under the terrain) and somehow I have to clamp them on terrain but don't know how.
I have tried using the existing code from the example but haven't succeed.
This is my code for now:
//Add terrain
var viewer = new Cesium.Viewer('cesiumContainer');
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});
viewer.terrainProvider = cesiumTerrainProviderMeshes;
viewer.scene.globe.depthTestAgainstTerrain = true;
//Load data (roads)
var dataSource = Cesium.GeoJsonDataSource.load('../../SampleData/ceste_rab_okvir.geojson');
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);
I know there is Cesium.GeoJsonDataSource.clampToGround, but as I'm not a developer, I don't understand how to write it in my code.
Does anyone knows how to do it? Or maybe there is another way to clamp roads to terrain?
Thanks in advance.
I've figured it out. It should be written like this:
//Add terrain
var viewer = new Cesium.Viewer('cesiumContainer');
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});
viewer.terrainProvider = cesiumTerrainProviderMeshes;
viewer.scene.globe.depthTestAgainstTerrain = true;
//Load data (roads)
Cesium.GeoJsonDataSource.clampToGround = true;
var dataSource = Cesium.GeoJsonDataSource.load('../../SampleData/ceste_rab_okvir.geojson');
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);
Related
Please I need help here. I am trying to generate a time-series NDVI chart using the code below, but I keep getting an error that reads "image.normalizedDifference is not a function"
I need help with this please. I am new to the GEE platform.
var finni = ee.FeatureCollection("users/Time-series-NDVI/Finney_shapefile"),
landsat7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_RT");
//define start and end dates
var startDate = '2001-01-01'
var endDate = '2020-12-31'
// filter images to cover only the dates required
var images = landsat7.filter(ee.Filter.date(startDate, endDate));
//print(images);
//crop images to my study area
var imgextent = images.filter(ee.Filter.bounds(finni));
print(imgextent);
// remove cloud cover
var image = imgextent.filter(ee.Filter.eq('CLOUD_COVER', 0));
print(image);
// Select on Red and NIR bands from the collection
var image = image.select(['B4', 'B3'])
print(image)
// Compute the Normalized Difference Vegetation Index (NDVI).
var addNDVI = function(image){
var ndvi = image.normalizedDifference(['B4', 'B3']).rename('NDVI');
return image.addBands(ndvi);
};
//Add the calculated NDVI band to my "image" already containing Red and NIR band
var withNDVI = image.map(addNDVI);
//Export a chart of only NDVI layer
var chart = ui.Chart.image.series({
imageCollection: withNDVI.select('NDVI'),
region: finni,
reducer: ee.Reducer.mean(),
scale: 30
}).setOptions({title: 'NDVI over time'});
// Display the chart in the console.
print(chart);
Use the addBands function with .clip() instead of the select function.
Use this line return image.addBands(ndvi).clip(finni); instead of this "withNDVI.select('NDVI').clip(finni);"
That should work.
I'm working on a task of showing all polylines(of different colours) on my map using leaflet. I'm getting all my dynamic polylines' latitudes and longitudes with their colours but when I merge it using layers, it just takes the last polyline and shows it.
I think I'm making some mistake in layering it. Can someone recommend the correct way to layer polylines in leaflets?
Here's a sample of the code where this is happening -
let newColour = this.returnMapColor(moment(startDate).day());
var layerGroups = {}
console.log("colour", newColour, startDate );
let range = this.props.history.filter((v) => { return moment(v.time).format("YYYY-MM-DD") == moment(startDate).format("YYYY-MM-DD") });
startDate = moment(startDate).add(1, 'days');
range.map((row)=> {
positions.push([row.latitude,row.longitude,row.sp] )
});
if(this.props.map){
const leafletMap = this.props.map.leafletElement;
this.hotlineLayer = L.layerGroup(L.polyline(positions, {color: newColour})).addTo(leafletMap);
}
++i;
A polyline requires at least two sets of lat, longs. Could you point out where in your code are you forming polylines?
In your code, the range.map the operation will only lead to creating an array of positions. And hence, your code is rendering a single line.
If you intend to create multiple polylines and render them using LayerGroup, I would suggest something in the lines of:
var latlngs1 = [
[45.51, -122.68,0],
[37.77, -122.43,1],
[34.04, -118.2,2]
];
var latlngs2 = [
[34.04, -118.2,2],
[32.08, -110.5,2]
];
const polyline1 = L.polyline(latlngs1, {color: 'red'})
var polyline2 = L.polyline(latlngs2, {color: 'blue'})
var hotlineLayer = L.layerGroup([polyline1, polyline2]).addTo(map);
Example Code: https://jsfiddle.net/idhruvs/n75omjbd/32/
Here is some code that can be pasted into a Cesium Sandcastle.
It adds an entity to the map, then every second, updates the CallbackProperty for the position property. Each time it is updated the entity flashes.
var viewer = new Cesium.Viewer('cesiumContainer');
var position = new Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0);
var constant = false;
var blueBox = viewer.entities.add({
name : 'Blue box',
position: new Cesium.CallbackProperty(getPos, constant),
box : {
dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
material : Cesium.Color.BLUE
}
});
function getPos() {
return position;
}
function setPosCallback() {
constant = !constant;
blueBox.position.setCallback(getPos, constant);
}
setInterval(setPosCallback, 1000);
Is there a way to update this type of property without causing the entity to flash? Maybe using requestAnimationFrame or something?
I need to use the callbackProperties for drawing shapes, but once they are drawn, I want them to use constant properties. I have also tried changing the isConstant property, but its read only.
I realize this question was from a long time ago, but it looks like the problem is this line "constant = !constant;". Simply removing this will fix the flickering.
Edit: I misunderstood the question, I too have the flicker issue when switching between constants and callbacks.
var viewer = new Cesium.Viewer('cesiumContainer');
var position = new Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0);
var constant = true;
var blueBox = viewer.entities.add({
name : 'Blue box',
position: new Cesium.CallbackProperty(getPos, constant),
box : {
dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
material : Cesium.Color.BLUE
}
});
var count = -114.0;
function getPos() {
count+=0.2;
return new Cesium.Cartesian3.fromDegrees(count, 40.0, 300000.0);
}
function setPosCallback() {
constant = !constant;
blueBox.position.setCallback(getPos.bind(blueBox), true);
}
setInterval(setPosCallback, 1000);
hi, the box is moving and it didnt flash in my browser when i bind the callback function to the entity and kept constant = true.
you might want to try again. cheers
I got this Openlayer Question.
Im trying to get a bunch of points from some objects. Which i believe shouldnt be hard.
Im am passing the st_astext to the WKT reader to create a Openlayers.Geometry.Point() Feature to add to the initial layer that will hold all of the lines. But that doesnt seem to work. Can anyone see what im doing wrong?
//Routes for each bridge?
vesselPosition = new OpenLayers.Layer.Vector('Vessels');
var wkt = new OpenLayers.Format.WKT();
$.ajax({
url: "/ajax/getPositions",
dataType: 'json',
success: function(result) {
for (var reportID in result) {
//Store the object at hand.
var data = result[reportID];
//Get all the positions and print them onto the vesselpoisition layer.
var positions = data.positions;
var listOfPoints = new Array();
for (var index in positions) {
var positionData = positions[index];
var point= wkt.read(positionData.st_astext);
listOfPoints.push(point.geometry);
}
var pointmap = new OpenLayers.Geometry.LineString({points:listOfPoints});
vesselPosition.addFeatures(pointmap);
};
}
});
OpenLayers.Geometry.LineString expects array of points for parameter, not object:
http://dev.openlayers.org/docs/files/OpenLayers/Geometry/LineString-js.html#OpenLayers.Geometry.LineString.OpenLayers.Geometry.LineString
Answer: Projection issue:
point.geometry.transform(
new OpenLayers.Projection("EPSG:4326"),
new OpenLayers.Projection("EPSG:900913")
);
So try
var pointmap = new OpenLayers.Geometry.LineString(listOfPoints);
Also pay attention for
vesselPosition.addFeatures(pointmap);
addFeatures() expects feature, not geometry for parameter. Use:
vesselPosition.addFeatures(new OpenLayers.Feature.Vector(pointmap));
For testing purposes, you may draw individual points to map:
var point= wkt.read(positionData.st_astext);
vesselPosition.addFeatures(point);
Also, check vesselPosition.features.length to determine, whether there are any features.
Hi there I am Using appcelerator, and I want to integrate a map with an array of markers I am getting from a HTTPRequest...
I am effing lost, totally lost.
This is how the map looks like:
var mapview = Titanium.Map.createView({
mapType: Titanium.Map.STANDARD_TYPE,
region: {latitude:33.74511, longitude:-84.38993,
latitudeDelta:0.01, longitudeDelta:0.01},
animate:true,
regionFit:true,
userLocation:true,
annotations:[mountainView]
});
And I have the example of 1 marker hardcoded ...
var mountainView = Titanium.Map.createAnnotation({
latitude:37.390749,
longitude:-122.081651,
title:"Appcelerator Headquarters",
subtitle:'Mountain View, CA',
pincolor:Titanium.Map.ANNOTATION_RED,
animate:true,
leftButton: '../images/appcelerator_small.png',
myid:1 // CUSTOM ATTRIBUTE THAT IS PASSED INTO EVENT OBJECTS
});
So yo create the marker and in the annotations section you add it to the map, the thing here is that I am getting the markers from this:
var url = "http://myURLwithMyParameters";
var xhr = Ti.Network.createHTTPClient({
onload: function(e) {
// this function is called when data is returned from the server and available for use
// this.responseText holds the raw text return of the message (used for text/JSON)
var result = this.responseText;
var xml = Ti.XML.parseString(result);
var items = xml.documentElement.getElementsByTagName("marker");
var name = xml.documentElement.getElementsByTagName("name");
var value = xml.documentElement.getElementsByTagName("address");
var data = [];
for (var i=0;i<items.length;i++) {
data.push({
name: items.item[i].getElementsByTagName("name")[0].textContent,
address: items.item[i].getElementsByTagName("address")[0].textContent
})
Does any one know how to integrate this?
I think I must build the map in the same function as the markers, but I've tried several options and haven't found ANY example of this in the web.
Any clue would be very appreciated.
Thank you in advance.
If all you have is an address, you'll need to forward geocode those addresses to get lat/long coordinates. Those coords are required to place annotations on the map. Check the docs at forwardGeocoder(). There's an example in the KitchenSink