How can one determine which LatLng a certain pixel (not determined by clicking!) in the map canvas div corresponds to? Say, I have x and y "offset" of a pixel within the map canvas div and I want to find out a LatLng this pixel corresponds to (f.ex., to place a marker on it).
You need to implement a Javascript class that extends google.maps.OverlayView (http://code.google.com/apis/maps/documentation/javascript/reference.html#OverlayView).
When the map is panned, the draw() method of your class will be called. Within that method you can call getProjection() to get a MapProjection object, and then use MapProjection.fromContainerPixelToLatLng to convert a pixel (relative to the top left of the map) to a LatLng.
The reason that this is so complex is that it's almost certainly not the right thing to be doing. Why do you need to place something relative to the map in pixel space? Users of maps tend to be interested in "real world" space (e.g. points on the surface of the Earth).
Related
I am implementing the navigation manager in javascript for learning purposes where I would like to navigate the user based on the calculated route. If the start and destination points are located in south, north directions respectively, then the marker for the start position appears in the bottom of the map's viewPort and the target maker would appear on the top by default. In contrast, assume the following situation where the start and destination point's are located in north, south directions respectively. I would like to change the orientation of the view upside down in order to keep the start position in the bottom and destination on the top (Similar to commercial android apps).
I tried two different methods to change the cameraview but I couldn't achieve it due to the following reasons.
Method-1:
The first method is based on startInteraction which is given in the following link where I couldn't find any options to set the HEADING angle
https://developer.here.com/documentation/maps/topics_api/h-map-render-renderengine-interactionmodifiers.html
Code:
var map = new H.Map(...);
var viewPort = map.getViewPort();
viewPort.startInteraction(H.map.render.RenderEngine.InteractionModifiers.HEADING);
Method-2:
I am trying to change the camera view according to the given position, orientation data which will be processed by the renderer. The setCameraData method from the following link works fine with the parameters zoom, position {H.geo.IPoint} and the renderer updates the map correspondingly.
https://developer.here.com/documentation/maps/topics_api/h-map-viewmodel.html#h-map-viewmodel__setcameradata
When I change the orientation of the virtual camera, i observe absolutely no difference in the map though roll, pitch, yaw properties are assigned with some values (I tried both the degrees (type used by HERE maps) and radians).
Code:
var map = new H.Map(...);
var viewModel = map.getViewModel();
var data = {'zoom': 16, 'position': curLoc, 'pitch': 0, 'yaw': 0, 'roll': 45.0}; // type - {H.map.ViewModel.CameraData}
viewModel.setCameraData(data);
Note: I have also tried updating the view with setViewBounds() method but I couldn't set the map's view upside down.
Best Regards,
Jeyaprakash Rajagopal
The JS API itself is just supporting one map view and that means north is on the top.
It appears to me that Leaflet.ImageOverlay does not have a minZoom and a maxZoom option like Leaflet.TileLayer has. But I have a map image that I only want to be visible at two or three zoom leves. Is there a cunning way to circumvent this issue?
I guess, I can use gdal2tiles.py or gdal_retile.py to create a file for a tile layer, but as I'm using UTM projection (Mercator gives a horrible distortion in Norway), I'm not sure what tile numbers makes my map image fit in with the background map.
Use the zoomend event to conditionally hide/show your L.ImageOverlay.
I have a tile-based isometric world and I can calculate which tile is underneath specific (mouse) coordinates by using the following calculations:
function isoTo2D(pt:Point):Point{
var tempPt:Point = new Point(0, 0);
tempPt.x = (2 * pt.y + pt.x) / 2;
tempPt.y = (2 * pt.y - pt.x) / 2;
return(tempPt);
}
function getTileCoordinates(pt:Point, tileHeight:Number):Point{
var tempPt:Point = new Point(0, 0);
tempPt.x = Math.floor(pt.x / tileHeight);
tempPt.y = Math.floor(pt.y / tileHeight);
return(tempPt);
}
(Taken from http://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511, this is a flash implementation but the maths is the same)
However, my problem comes in when I have tiles that have different elevation levels:
In these scenarios, due to the height of some tiles which have a higher elevation, the tiles (or portions of tiles) behind are covered up and shouldn't be able to be selected by the mouse, instead selecting the tile which is in front of it.
How can I calculate the tile by mouse coordinates taking into account the tiles' elevation?
I'm using a javascript and canvas implementation.
There is a technique of capturing object under the mouse on a canvas without needing to recalculate mouse coordinates into your "world" coordinates. This is not perfect, has some drawbacks and restrictions, yet it does it's job in some simple cases.
1) Position another canvas atop of your main canvas and set it's opacity to 0. Make sure your second canvas has the same size and overlaps your main one.
2) Whenever you draw your interactive objects to the main canvas, draw and fill the same objects on the second canvas, but using one unique color per object (from #000000 to #ffffff)
3) Set mouse event handling to the second canvas.
4) Use getPixel on the second canvas at mouse position to get the "id" of the object clicked/hovered over.
Main advantage is WYSIWYG principle, so (if everything is done properly) you can be sure, that objects on the main canvas are in the same place as on the second canvas, so you don't need to worry about canvas resizing or object depth (like in your case) calculations to get the right object.
Main drawback is need to "double-render" the whole scene, yet it can be optimized by not drawing on the second canvas when it's not necessary, like:
in "idling" scene state, when interactive objects are staying on their places and wait for user action.
in "locked" scene state, when some stuff is animated or smth. and user is not allowed to interact with objects.
Main restriction is a maximum number of interactive objects on the scene (up to #ffffff or 16777215 objects).
So... Not reccomended for:
Games with big amount of interactive objects on a scene. (bad performance)
Fast-paced games, where interactive objects are constantly moved/created/destroyed.(bad performance, issues with re-using id's)
Good for:
GUI's handling
Turn-based games / slow-paced puzzle games.
Your hit test function will need to have access to all your tiles in order to determine which one is hit. It will then perform test hits starting with the tallest elevation.
Assuming that you only have discreet (integer) tile heights, the general algorithm would be like this (pseudo code, assuming that tiles is a two-dimensional array of object with an elevation property):
function getTile(mousePt, tiles) {
var maxElevation = getMaxElevation(tiles);
var minElevation = getMinElevation(tiles);
var elevation;
for (elevation = maxElevation; elevation >= minElevation; elevation--) {
var pt = getTileCoordinates(mousePt, elevation);
if (tiles[pt.x][pt.y].elevation === elevation) {
return pt;
}
}
return null; // not tile hit
}
This code would need to be adjusted for arbitrary elevations and could be optimized to skip elevation that don't contain any tiles.
Note that my pseudocode ignores vertical sides of a tile and clicks on them will select the (lower elevation) tile obscured by the vertical side. If vertical tiles need to be accounted for, then a more generic surface hit detection approach will be needed. You could visit every tile (from closest to farthest away) and test whether the mouse coordinates are in the "roof" or in one of the viewer facing "wall" polygons.
If map is not rotatable and exatly same as picture you posted here,
When you are drawing polygons, save each tile's polygon(s) in a polygon array. Then sort the array only once using distance of them(their tile) to you(closest first, farthest last) while keeping them grouped by tile index.
When click event happens, get x,y coordinates of mouse, and do point in polygon test starting from first element array until last element. When hit, stop at that element.
No matter how high a tile is, will not hide any tile that is closer to you(or even same distance to you).
Point in polygon test is already solved:
Point in Polygon Algorithm
How can I determine whether a 2D Point is within a Polygon?
Point in polygon
You can even check every pixel of canvas once with this function and save results into an 2d array of points, vect2[x][y] which gives i,j indexes of tiles from x,y coordinates of mouse, then use this as a very fast index finder.
Pros:
fast and parallelizable using webworkers(if there are millions of tiles)
scalable to multiple isometric maps using arrays of arrays of polygons sorted by distance to you.
Elevation doesnt decrease performance because of only 3 per tile maximum.
Doesn't need any conversion to isometric to 2d. Just the coordinates of corners of polygons on canvas and coordinates of mouse on the same canvas.
Cons:
You need coordinates of each corner if you haven't already.
Clicking a corner will pick closest tile to you while it is on four tiles at the same time.
The answer, oddly, is written up in the Wikipedia page, in the section titled "Mapping Screen to World Coordinates". Rather than try to describe the graphics, just read the section three times.
You will need to determine exactly which isomorphic projection you are using, often by measuring the tile size on the screen with a ruler.
I am wondering if there's a way to access the Bounding Box Gui properties of mask shapes so that I can see how to create perfect circle shape masks in After Effects?
My code is below:
maskpath = app.project.item(1).layer("Orange Solid 2").property("ADBE Mask Parade").property("ADBE Mask Atom").property("ADBE Mask Shape");
Not sure what you mean by "access the Bounding Box Gui properties of mask shapes", but I do think I know what you mean by "how to create perfect circle shape masks in After Effects".
See D. Ebberts' script code posted here: http://aenhancers.com/viewtopic.php?f=11&t=2084
I believe it does (or will lead you to do) what you want.
I found the answer from After-Effects-CS6-Scripting-Guide.pdf page 48
AVLayer sourceRectAtTime() method
Retrieves the rectangle bounds of the layer at the specified time index, corrected for text or shape layer content.
Use, for example, to write text that is properly aligned to the baseline.
app.project.item(index).layer(index).sourceRectAtTime(timeT, extents)
Returns
A JavaScript object with four attributes: [top, left, width, height].
I think you are talking about how to access Left Top Right Bottom values of this window.
This window appears when you click on shape of mask path
(position where pointing hand drown blue color arrow)
please any one can tell me how to access those values via Script
Based on samples, I can see that you can set a default view in OpenLayers by saying something along the lines of:
var bounds = new OpenLayers.Bounds(-125, 25, -65, 50);
var map = new OpenLayers.Map('map', {restrictedExtent: bounds });
However, this also (as the name implies), restricts me to be able to ONLY navigate within these bounds. I can zoom out and see things outside of these bounds, but I can't then zoom back onto them, or scroll to them.
I've tried not having any restrictedExtent (or making it the entire map), but then I can't get it to focus on the area I want. I tried using:
map.setCenter(new OpenLayers.LonLat(0,0), 3);
console.log(map.getCenter());
To set the zoom and the center...but it doesn't seem to do ANYTHING, other than set the variable "center" which I can then read from map.getCenter() (if I don't set it, it's null, if I do set it, I can see it...but the map itself stays fully extended and it's center doesn't seem to change at all...)
The Map layer I am using is:
OpenLayers.Layer.OSM.Mapnik
with displayOutsideMaxExtent set to true... I'm really at a loss here.
My goal is to have a default region of the world zoomed in to and in view (such as the United States), with the option of viewers being able to go outside the default to view things.
I think I've figured it out. For whatever reason, the zoom was never changing, but the center apparently WAS moving (it was just so zoomed out I couldn't tell). Add to the fact that I needed to transform the center to use the google projection, and it seems to work just fine.
What I ended up doing was:
var lonlat = new OpenLayers.LonLat(20,37).transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:900913"));
map.setCenter(lonlat);
map.zoomTo(4);