How to convert a drawn multipolygon to a list of polygon in google earth engine? - google-earth-engine

I want to know if this is possible to convert a multipolygon to a list of seperated polygons. because I drew several polygons as multipolygon in code editor and now i separate for training-testing procedure. any advice is appreciated.

there might be several options on the table. but if you want to handle that on the server side you can do it in this way:
// a function which converts a multipolygon to a list of polygons
var multipoly2polylist = function(multipoly){
var size = multipoly.coordinates().size()
var polylist = ee.List.sequence(0, size.add(-1), 1)
var polylist = polylist.map(function(listelem){
return ee.Geometry.Polygon(multipoly.coordinates().get(listelem))
})
return polylist
}
(if we suppose that you drew multipolygon named farm), then you can use this function for farm multipolygon object.
var farm_polylist = multipoly2polylist(farm)
I think it should work.

Related

harp.gl: properly scaling georeferenced 3D geometries (in metres) added through three.js

I have a 3D model in a coordinate system that is defined in metres. The coordinates have been transformed to have the centre of the bounding box of the model as the origin. A vertex with the coordinates (1, 0, 0) would thus lie 1 metre from the origin.
When trying to add the geometries to the map, with the actual latitude/longitude of the origin as geoPosition, they don't get placed at the exact location and appear smaller than they are. How could I solve this?
Thanks.
You can center the map at whatever point you would like in the world with this method:
map.setCameraGeolocationAndZoom(
//Singapore coordinates and zoom level 16:
new harp.GeoCoordinates(1.278676, 103.850216), 16
);
You can specify the projection type in the MapView's constructor.
To implement a globe projection:
const map = new harp.MapView({
canvas,
theme: "https://unpkg.com/#here/harp-map-theme#latest/resources/berlin_tilezen_base_globe.json",
projection: harp.sphereProjection,
//For tile cache optimization:
maxVisibleDataSourceTiles: 40,
tileCacheSize: 100
});
//And set it to a view where you can see the whole world:
map.setCameraGeolocationAndZoom(new harp.GeoCoordinates(1.278676, 103.850216), 4);
Please refer documentation for more reference:
https://developer.here.com/tutorials/harpgl/#modify-the-map

Unable to extract List elements as integers using `getInfo`

I'm using reduceRegion to sum the number of water pixels determined by an NDWI. I want to do this on a collection of images to see change in water area over a period time.
The values are returned from the reduceRegion in the console and appear to be integers, but I am unable to extract them as such. This seems to be a common problem, but the solution is typically using getInfo function to bring these values over to client side. Unfortunately getInfo returns a null in this case.
The code below is for a collection of images OR a single image. The single image(image1) returns an image with an extra property(waterArea), and the mapped algorithm blows up(because the function is returning nulls).
I've also tried using getInfo on waterAg to potentially bring that list over to client side, however that returns the same List of objects that I don't want.
var image1 = ee.Image(leastcloud.first()).select(['B11','B8','B3'])
var stackarea = function(image){
var watermask = ee.Image(0)
var MNDWI = image.normalizedDifference(['B3','B11'])
watermask = watermask.where(MNDWI.gt(.31),1);
//sum of water pixels in an area
var sum = ee.Number(watermask.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: geometry,
scale: 20,
maxPixels: 1e9
}));
var clientSide = sum.getInfo()
var setArea = image.set('waterArea', clientSide)
return setArea
};
var single = stackarea(image1)
print(single)
var watermapped = filterSpot.map(stackarea)
var waterAg = watermapped.aggregate_array('waterArea')
print(waterAg)
I'm really not sure how to extract these values as numbers...
I'm hoping to get a list of numbers so that I can concatenate that array to other arrays(date of image, cloud pixel %, etc.)
reduceRegion returns a dictionary object, not a number-like object. Therefore, in your stackarea function, clientSide variable is a dictionary (i.e. an object), not a number.
The number that you're after is stored in the dictionary returned by the reduceRegion function. You can get your hand on that number by using a get function on this dictionary object:
var sum = watermask.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: geometry,
scale: 20,
maxPixels: 1e9
}).get('nd');
In this way, sum will be a server-side number that store the value you're after (There's no need to use ee.Number here as it does not help much).
In case you wonder about why using get('nd') but not get('somethingelse'), well it's the name of the band in your watermask image, and this name is the default band name given to the result of the normalizedDifference function.
And in my opinion, you don't even need to use the getInfo function which takes much more time to execute. Just delete the line var clientSide = sum.getInfo() and modify the next line into var setArea = image.set('waterArea', sum).
Hope this help.

Check if a point is inside a Polygon with the Google Maps API

I am developing an application using the Google Maps API v3, and I'm struggling to know how to find out if an X coordinate is inside a polygon.
You can use the Geometry Library of the Google Maps JS API. There's a function called containsLocation which tells you if a given LatLng is inside a Polygon. Note that it's a Polygon, not a Polyline. A Polyline is (as it says in the name) a line. So there is no such thing as a point being inside a polyline. You can check if a point is inside a Polygon with the containsLocation function.
google.maps.geometry.poly.containsLocation(somePoint, somePolygon)
In iOS it can be done by using GMSGeometryContainsLocation
Just create a GMSMutablePath, then fill with vertexes of your polygon and test the point.
Example(Swift 4.0):
func isWithin(_ point: CLLocationCoordinate2D) -> Bool {
let p = GMSMutablePath()
p.add(CLLocationCoordinate2D(latitude:30.02356126, longitude: -90.07047824))
p.add(CLLocationCoordinate2D(latitude:30.02501037, longitude: -90.0614231))
p.add(CLLocationCoordinate2D(latitude:30.03321034, longitude: -90.0617981))
p.add(CLLocationCoordinate2D(latitude:30.03192855, longitude: -90.07342815))
return GMSGeometryContainsLocation(point, p, true)
}
Note: If the last param of GMSGeometryContainsLocation is set to true, the GMSMutablePath is composed of great circle segments, otherwise it's of rhumb (loxodromic) segments.

Convert WebMercatorExtent in Extent in Flex

I retrieve dynamically an Array with latidude longitude values that need to be calculated into an Extent so they fit exactly on a map (Adobe Flex). The layers I'm using in the Esri Map component are now:
<esri:ArcGISTiledMapServiceLayer id="arcgisonlineLayer" load="{trace(arcgisonlineLayer.version)}"
url="http://services.arcgisonline.nl/arcgis/rest/services/Basiskaarten/PDOK_BRT/MapServer"/>
<esri:WMSLayer url="{wmsLayerUrl}">
<esri:visibleLayers>
<s:ArrayList>
<fx:String>0</fx:String><!-- background colors -->
<fx:String>1</fx:String><!-- signs -->
<fx:String>2</fx:String><!-- red overview road map can be outcommented-->
<fx:String>3</fx:String><!-- lines -->
</s:ArrayList>
</esri:visibleLayers>
</esri:WMSLayer>
Before I used the standard Esri layers...
<esri:ArcGISTiledMapServiceLayer id="serviceLayer"
url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
visible="{viewModeButtonBar.selectedIndex == 0}"/>
<esri:ArcGISTiledMapServiceLayer
url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
visible="{viewModeButtonBar.selectedIndex == 1}"/>
..and I could use the WebMercatorExtent class to create an extend that would fit but now I need to use these layers and can't use the WebMercatorExtent because the service "http://services.arcgisonline.nl/arcgis/rest/services/Basiskaarten/PDOK_BRT/MapServer" uses
<esri:SpatialReference id="wgs" wkid="28992"/>
Which doesn't go with WebMercatorExtent. Anyone knows how to convert this com.esri.ags.geometry.WebMercatorExtent into an Extent?
It sounds like you need to convert a longitude/latitude Extent to an Extent in spatial reference 28992, right? If so, see the Flex sample on projecting geometries. Especially see the projectNow function. It uses GeometryService.project to project points from one coordinate system to another. You can use the same function to project extents from one coordinate system to another.
Here is how it's done in code. You need to declare as GeometryService that uses some an external webservice. This one is the sampleservice from Esri that might be out of order when you read this answer because there has been an upgrade. Best is to use your own arcgis service, for now I used this one:
http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer
Put in to Declarations
<fx:Declarations>
<esri:GeometryService id="geometryService"
concurrency="last"
fault="geometryService_faultHandler(event)"
projectComplete="projectCompleteHandler(event)"
showBusyCursor="true"
url="http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer"/>
</fx:Declarations>
Then create the WebMercatorExtent, create a SpatialReference you want your Geometry converted to and project it. The web service will provide the answer...
var wmExtent:WebMercatorExtent = new WebMercatorExtent(
_mapItemBounds.getSouthWest().lng(),
_mapItemBounds.getSouthWest().lat(),
_mapItemBounds.getNorthEast().lng(),
_mapItemBounds.getNorthEast().lat());
var outSR:SpatialReference = new SpatialReference(28992);
const projectParameters:ProjectParameters = new ProjectParameters;
projectParameters.geometries = [ wmExtent];
projectParameters.outSpatialReference = outSR;
geometryService.project(projectParameters);
...in the function
protected function projectCompleteHandler(event:GeometryServiceEvent):void
{
try
{
// Note: As of version 2.0, GeometryService returns geometries (instead of graphics)
var extent:Extent = (event.result as Array)[0] as Extent;
map.extent = extent;
}
catch (error:Error)
{
Alert.show(error.toString());
}
}

d3.js mercator projection to NYC map

I am making a map of the boroughs in NYC and I can't seem to get the projection right: the only thing I get is a tiny map.
I tried recreating this example, which only made the console go crazy with errors, I suspect because there was something off about the equation.
When I was trying to get albers to work, I tried out the answer to this question, and still I could not get the map to work.
With 960/500 height and width, I used: var projection = d3.geo.albers().center([40.71, 73.98]).parallels([29.5, 45.5]).scale(10000).translate([(width) / 2, (height)/2]);
Right now, I am using a transverse Mercator, with the code below, and the topojson I created using one of these files.
var width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("nyc-borough.json", function(error, nyb) {
var boroughs = topojson.feature(nyb, nyb.objects["nyc-borough-boundaries-polygon"]).features;
var projection = d3.geo.transverseMercator()
.scale(1600)
.rotate([73 + 58 / 60, -48 - 47 / 60]);
var path = d3.geo.path()
.projection(projection);
var g = svg.append("g");
g.append("g")
.attr("id", "boroughs")
.selectAll(".state")
.data(boroughs)
.enter().append("path")
.attr("class", function(d){ return d.properties.name; })
.attr("d", path);
});
Please, please halp :(
Thanks in advance!
I created a bl.ock with the NYC boroughs here. You were on the right path with WSG84/Mercator as that was what the original data was in, as a quick check in QGIS demonstrated.
QGIS was also good checking the centre of the data, again which came out to be [-73.94, 40.70]. Note that these are the opposite way round to your co-ordinates which were lat and long, but d3 needs long and lat as discussed here in the API. The other thing to look out for is the negatives. North is positive so latitude in the northern hemisphere is positive and negative in the southern hemisphere. For the east and west hemispheres its east that's positive. Of course this only matters for the global projections the USA Albers wouldn't have negatives for the USA. Oh, and no discussion on Projections would be complete without a look at Jason Davies work.
If you want to use a different projection to the projection your data is in I generally think it's better to preprocess your data into that projection and QGIS is a great tool for that but there are many others such as gdal.

Resources