OpenLayers - Mosaic of custom images on one layer - javascript

Is it possible to have a layer made up of a mosaic of custom images?
I've been only able to get a single custom image on a given layer via OpenLayers.Layer.Image. Essentially, if I could find a way to specify custom images for the tiles of a given layer, then my problem would be solved.
I have tried various combinations of OpenLayers.Tile, OpenLayers.Tile.Image, OpenLayers.Layer and OpenLayers.Layer.Grid but haven't been able to things working.
The basic flow I follow is:
var map = new OpenLayers.Map('map');
var layer = new <OpenLayers.Layer | OpenLayers.Layer.Grid> (<parameters>);
var tile1 = new <OpenLayers.Tile | OpenLayers.Tile.Image> (<parameters>);
map.addLayer(layer);
map.zoomToMaxExtent();
Specific examples of how I initialize each constructor are provided below.
Regarding OpenLayers.Layer.Grid, I'm actually not sure what to specify for the url and params constructor parameters.
Any advice on whether this works and/or if I'm on the right track would be greatly appreciated.
OpenLayers.Layer
var layer = new OpenLayers.Layer(
'layer_name',
{
isBaseLayer: true
}
);
OpenLayers.Layer.Grid
var layer = new OpenLayers.Layer.Grid(
'layer_name',
?url?,
?params?
);
OpenLayers.Tile
var layer = new OpenLayers.Tile(
layer_name,
new OpenLayers.Pixel(0,0),
new OpenLayers.Bounds(-1,-1,1,1),
'square1.jpg',
new OpenLayers.Size(300,300)
);
OpenLayers.Tile.Image
var layer = new OpenLayers.Tile.Image(
layer_name,
new OpenLayers.Pixel(0,0),
new OpenLayers.Bounds(-1,-1,1,1),
new OpenLayers.Size(300,300),
{
url: 'square1.jpg'
}
);

Have you tried Zoomify layer? Here's the example. It allows you to load in the map all images from a given directory, named in the form {z}-{x}-{y}.jpg, where {z} is the zoom level.

If you need to break up an image into smaller tiles, I suggest using this free MapTiler software, which will create the tiles for as many zoom levels as you need.
You can create a map layer of image tiles using a TMS Layer:
var layer = new OpenLayers.Layer.TMS("TMS Layer","",
{url: '', serviceVersion: '.', layername: '.', alpha: true,
type: 'png', getURL: getTileURL
}
);
map.addLayer(layer);
The getTileURL function is used by the TMS layer to find the tiled images to display. This function assumes that the images are stored in a hierarchical structure like the one created by MapTiler.
Ex: img/tiles/7/4/1.png is the image that is 5th from the left and 2nd from the bottom of zoom level 7.
function getTileURL(bounds)
{
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
var y = Math.round((bounds.bottom - this.maxExtent.bottom) / (res * this.tileSize.h));
var z = this.map.getZoom();
var path = "img/tiles/" + z + "/" + x + "/" + y + "." + this.type;
var url = this.url;
if (url instanceof Array)
{
url = this.selectUrl(path, url);
}
return url + path;
}

Related

How can I pass a geometry to the Map function in GEE?

I am trying to use the Map function in Google Earth Engine to clip an ImageCollection to a geometry. I have multiple areas of interest (AOIs) and thus would like to apply a generic clip function multiple times (for each AOI). However, when I create a function with two parameters (the image and the geometry) to map over, I get the error image.clip is not a function. When using the function with just one parameter (the image), it works just fine, but then I need to write two (or possible more) functions to do exactly the same task (i.e. clipping an image to a certain geometry).
I have tried the solutions in this post, but they do not work.
Any ideas on how to solve this issue?
Code:
// Get NTL data
var ntl = ee.ImageCollection("NOAA/VIIRS/DNB/MONTHLY_V1/VCMSLCFG");
// Define start and end year
var startYear = 2015;
var endYear = 2018;
// Filter montly and select 'avg_rad' band
var ntlMonthly = ntl.filter(ee.Filter.calendarRange(startYear, endYear, 'year'))
.filter(ee.Filter.calendarRange(1,12,'month'))
.select(['avg_rad']);
// Create geometries of AOIs
// -- Create a geometry of Venezuela
var geomVenezuela = ee.Geometry.Rectangle([-73.341258, 13.363291, -59.637555, -0.372893]);
// -- Create a geometry of Caracas (Venezuela's capital)
var geomCaracas = ee.Geometry.Rectangle([-67.062383, 10.558489, -66.667078, 10.364908]);
// Functions to crop to Venezuela (nationwide) and Caracas (local) resp.
var clipImageToGeometry = function(image, geom) {
return image.clip(geom);
}
// Apply crop function to the ImageCollection
var ntlMonthly_Venezuela = ntlMonthly.map(clipImageToGeometry.bind(null, geomVenezuela));
var ntlMonthly_Caracas = ntlMonthly.map(clipImageToCaracas.bind(null, geomCaracas));
// Convert ImageCollection to single Image (for exporting to Drive)
var ntlMonthly_Venezuela_image = ntlMonthly_Venezuela.toBands();
var ntlMonthly_Caracas_image = ntlMonthly_Caracas.toBands();
// Check geometry in map
Map.addLayer(geomCaracas, {color: 'red'}, 'planar polygon');
Map.addLayer(ntlMonthly_Caracas_image);
// Store scale (m. per pixel) in variable
var VenezuelaScale = 1000;
var CaracasScale = 100;
// Export the image, specifying scale and region.
Export.image.toDrive({
image: ntlMonthly_Caracas_image,
description: 'ntlMonthly_Caracas_'.concat(startYear, "_to_", endYear),
folder: 'GeoScripting',
scale: CaracasScale,
fileFormat: 'GeoTIFF',
maxPixels: 1e9
});
If I understood your question correctly:
If you want to crop each image in the ImageCollection to a geometry, you could just do
var ntlMonthly_Venezuela = ntlMonthly.map(function(image){return ee.Image(image).clip(geomVenezuela)})
And just repeat for other AOIs.
If you wan to cast it into a function:
var clipImageCollection = function(ic, geom){
return ic.map(function(image){return ee.Image(image).clip(geom)})
}
// Apply crop function to the ImageCollection
var ntlMonthly_Venezuela = clipImageCollection(ntlMonthly, geomVenezuela);
var ntlMonthly_Caracas = clipImageCollection(ntlMonthly, geomCaracas);

Earth Engine getThumbURL blurry image

I'm trying to find a way to specify a lat and long and retrieve a close up image. The code below allows me to enter a lat and long but the image is very blurry. Is there a simple way to get a higher resolution image?
My main issue is specifying the zoom level and I haven't found any examples of people retrieving close up images.
var image = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140318').select(['B4','B3','B2']);
// Create a circle with buffer around a point.
var roi = ee.Geometry.Point([-122.4481, 37.7599]).buffer(3000);
Map.centerObject(image, 15)
var a = image.getThumbURL({
image: image,
region:roi.getInfo()
});
//print URL
print(a);
You can add a dimensions parameter to the .getThumbURL() that will define the number of pixels in the output image. Here is the your example with a 2000x2000 output thumb:
var image = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140318').select(['B4','B3','B2']);
// Create a circle with buffer around a point.
var roi = ee.Geometry.Point([-122.4481, 37.7599]).buffer(3000);
Map.centerObject(image, 15)
var a = image.getThumbURL({
image: image,
dimensions:[2000,2000], // specify output thumb size here
region:roi.getInfo()
});
//print URL
print(a);
If you just want to see an image on the map (as displayed), you can do it using the UI facilities.
like:
var textbox = ui.Textbox({
placeholder: 'Point coordinates: long, lat',
onChange: function(text) {
var splitStr = text.split(",");
var lon = parseFloat(splitStr[0]);
var lat = parseFloat(splitStr[1]);
var p = ee.Geometry.Point(lon, lat);
Map.addLayer(p);
Map.centerObject(p, 12);
}
});
print(textbox);
This code will move the map to the given point coordinates and draw it.

How to connect objects with Bezier-like curves using Paper.js

I have a web app prototype where nodes similar to Blender shader editor are connected to each other. I am using Paper.js framework
I want them to be connected using those smooth Bezier-like curves. So I have 2 shapes and I can connect them by making a straight line, but now I want to have handles at the endpoints that smooth these objects out, kinda like this:
So 2 handles on endpoints, pointing horizontally for half the bounding box of the path.
The problem is I can't figure out how to add and edit those handles using Paper.js
The code I have is this:
function makeRectangle(topLeft, size, cornerSize, colour){
var rectangle = new Rectangle(topLeft, size);
var cornerSize = cornerSize;
var path = new Path.RoundRectangle(rectangle, cornerSize);
path.fillColor = colour;
return path;
}
var xy1 = new Point(50,50); //Position of 1st rectangle.
var size = new Size(100, 80); //Size
var c = new Size(8,8); //Corner radius
var col = "#167ee5"; //Colour
var r1 = makeRectangle(xy1, size, c, col); //Make first rectangle
var xy2 = new Point(467,310); //Position of second rectangle
var size2 = new Size(115, 70); //Size of second rectangle
var r2 = makeRectangle(xy2, size2, c, col); //Make secont rectangle
var r1cent = r1.bounds.center; //Get the center points, they will be used as endpoints for the curve.
var r2cent = r2.bounds.center;
var connector = new Path(r1cent, r2cent); //Ok so I made this path... Now what? How do access and edit the handlers at endpoints like in the image?
connector.strokeColor = 'black'; //Give it some colour so we can see it.
You can paste all this code here without any setup, it's a good way to test the framework.
You can use Segment objects when defining the connector rather than using Points (or you can set the handleIn and handleOut properties after creating the path).
The doc is here: Segment
And here is a sketch showing how to use handleIn and handleOut with your code:
sketch.paperjs.org solution

Openlayers - arrary of info into popupmarker

I have a connection to a database(db). I am getting the lon, lat and name from the db and stroing them:
while ($row_ChartRS = mysql_fetch_array($sql1))
{
$latitude=$row_ChartRS['latitude'];
$longitude=$row_ChartRS['longitude'];
$bus_name =$row_ChartRS['short_name'];
//echo $latitude.'--'.$longitude.'<br>';
echo $bus_name;
I then create a map to display the data. The markers are working fine for all lat, lon locations. Code:
function init()
{
projLonLat = new OpenLayers.Projection("EPSG:4326"); // WGS 1984
projMercator = new OpenLayers.Projection("EPSG:900913"); // Spherical Mercator
overviewMap = new OpenLayers.Control.OverviewMap();
//adding scale ruler
scale = new OpenLayers.Control.ScaleLine();
scale.geodesic = true; // get the scale projection right, at least on small
map = new OpenLayers.Map('demoMap',
{ controls: [ new OpenLayers.Control.Navigation(), // direct panning via mouse drag
new OpenLayers.Control.Attribution(), // attribution text
new OpenLayers.Control.MousePosition(), // where am i?
new OpenLayers.Control.LayerSwitcher(), // switch between layers
new OpenLayers.Control.PanZoomBar(), // larger navigation control
scale,
overviewMap // overview map
]
}
);
map.addLayer(new OpenLayers.Layer.OSM.Mapnik("Mapnik"));
map.addLayer(new OpenLayers.Layer.OSM.Osmarender("Osmarender"));
//Create an explicit OverviewMap object and maximize its size after adding it to the map so that it shows
//as activated by default.
overviewMap.maximizeControl();
//Adding a marker
markers = new OpenLayers.Layer.Markers("Vehicles");
map.addLayer(markers);
vectorLayer = new OpenLayers.Layer.Vector('Routes');
map.addLayer(vectorLayer);
for (k in Locations)
{
//adding a popup for the marker
var feature = new OpenLayers.Feature(markers, new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator));
//true to close the box
feature.closeBox = true;
feature.popupClass = new OpenLayers.Class(OpenLayers.Popup.AnchoredBubble,
{
//create the size of the box
'autoSize': true,
'maxSize': new OpenLayers.Size(100,100)
});
//add info into box
for (z in names)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
//puts a scroll button on box to scroll down to txt
//feature.data.overflow = "auto";
marker = feature.createMarker();
marker.display(true);
markerClick = function (evt) {
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
marker.events.register("mousedown", feature, markerClick);
markers.addMarker(marker);
map.setCenter(new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator), zoom);
var lonLat1 = new OpenLayers.LonLat(Locations[k].lon,Locations[k].lat).transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
var pos2=new OpenLayers.Geometry.Point(lonLat1.lon,lonLat1.lat);
points1.push(pos2);
//Uncomment to put boxes in when map opens
//feature.popup = feature.createPopup(feature.closeBox);
//map.addPopup(feature.popup);
//feature.popup.show()
}
var lineString = new OpenLayers.Geometry.LineString(points1);
var lineFeature = new OpenLayers.Feature.Vector(lineString,'',style_green);
vectorLayer.addFeatures([lineFeature]);
map.setCenter(lonLat1,zoom);
} //function
However the name in the popup marker is the same for all markers. i.e. the last name pulled from the db. Can anyone please help with this - I have spent 3 full days trying to fix it!
Thanks in advance!
A few comments:
The PHP code you’ve posted is completely irrelevant, since it’s not seen to be used anywhere.
The objects names and Locations aren’t declared anywhere in the code you posted. What do they contain?
In the code quoted below, you’re creating multiple new Feature objects, but you assign them all to the same property (thereby overwriting that property each time). Is that intentional?
//add info into box
for (z in names) {
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
Edit:
This does appear to be where it’s going wrong. You should remove the for...z loop, and replace it with the following code:
//add info into box
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[k]).transform(projLonLat,projMercator));
Since in PHP, you’re using the same index ($v) to fill both arrays, it makes sense to use the same index to read them in javascript...
Aside from that, using the for...in loop on Javascript arrays is not considered good practice, for a number of reasons. It’s better to use the following:
for (k = 0; k < Locations.length; k += 1) {
// your code
}
i had the same problem , and i solve it ...
the problem is overwrite
you don't have to loop inside your function , do the loop for function for example:
function init(z)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
for (z in names)
{
init(z)
}

Adding Panoramio Photos To An OpenLayers Map

I have a pretty well integrated OpenLayers map that I want to add photos from the Panoramio API to. Unfortunately, it seems both API's are under documented on this subject. I found one great tutorial here http://www.gisandchips.org/2010/05/04/openlayers-y-panoramio/ but as I am new to all of this, could be why I cannot complete this on my own. I feel like even using this tutorial I have a lot of blank spaces in my mind and not to mention, the photos are NOT appearing on my map :-/
Here is my portion of the code that demonstrates my use of that tutorial and what I have attempted so far:
var url = "http://www.panoramio.com/map/get_panoramas.php";
var parameters = {
order: 'popularity',
set: 'full',
from: 0,
to: 20,
minx: 84.05,
miny: 31.36,
maxx: 91.89,
maxy: 32.30,
size: 'thumbnail'
} //end parameters
OpenLayers.loadURL(url, parameters, this, displayPhotos);
function displayPhotos(response) {
var json = new OpenLayers.Format.JSON();
var panoramio = json.read(response.responseText);
var features = new Array(panoramio.photos.length);
for (var i = 0; i < panoramio.photos.length; i++) {
var upload_date = panoramio.photos[i].upload_date;
var owner_name = panoramio.photos[i].owner_name;
var photo_id = panoramio.photos[i].photo_id;
var longitude = panoramio.photos[i].longitude;
var latitude = panoramio.photos[i].latitude;
var pheight = panoramio.photos[i].height;
var pwidth = panoramio.photos[i].width;
var photo_title = panoramio.photos[i].photo_title;
var owner_url = panoramio.photos[i].owner_url;
var owner_id = panoramio.photos[i].owner_id;
var photo_file_url = panoramio.photos[i].photo_file_url;
var photo_url = panoramio.photos[i].photo_url;
var fpoint = new OpenLayers.Geometry.Point(longitude, latitude);
var attributes = {
'upload_date': upload_date,
'owner_name': owner_name,
'photo_id': photo_id,
'longitude': longitude,
'latitude': latitude,
'pheight': pheight,
'pwidth': pwidth,
'pheight': pheight,
'photo_title': photo_title,
'owner_url': owner_url,
'owner_id': owner_id,
'photo_file_url': photo_file_url,
'photo_url': photo_url
} //end attributes
features[i] = new OpenLayers.Feature.Vector(fpoint, attributes);
} //end for
var panoramio_style2 = new OpenLayers.StyleMap(OpenLayers.Util.applyDefaults({
pointRadius: 7,
fillColor: "red",
fillOpacity: 1,
strokeColor: "black",
externalGraphic: "panoramio-marker.png"
}, OpenLayers.Feature.Vector.style["default"]));
var vectorPano = new OpenLayers.Layer.Vector("Panoramio Photos", {
styleMap: panoramio_style2
});
vectorPano.addFeatures(features);
map.addLayer(vectorPano);
} //end displayPhotos
In my mind this code should work perfectly. Giving me a result of some Panoramio thumbnails on my slippy map. Unfortunately it seems that the layer is there, but blank..When I look at the response text in Firebug I can see that the JSON is returned with attributes of photos from Panoramio, in the location I have specified (Tibet). I appreciate your help and time to consider my issues.
Thank you,
elshae
I don't know how proficient you are in OpenLayers, but the project is certainly not underdocumented. There is an extensive api documentation and also numerous examples that should help to get you started.
But now back to your problem: likely, this is a projection issue. Panoramio returns WSG-84 (GPS) Coordinates for all the photos it found, and the openstreetmap baselayer of your map is in Spherical Mercator projection ('EPSG:900913').
So you have to convert the coordinates from WSG-84 to Spherical Mercator using something like
var curPic = panoramio.photos[i];
var panLonLat = new OpenLayers.LonLat(curPic.longitude, curPic.latitude);
panLonLat.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection('EPSG:900913'));
and then use the converted point for your geometry

Categories

Resources