I am facing an unusual problem where I need to calculate the latlong of a position on a map that has streetview imagery, without knowing the actual position.
I know the end destination of my user, but I need to calculate the latlong of a nearby position (approximately 1km away or less, this should be variable) that has streetview imagery and use that as the start destination.
An example would be that I know I need to go to Times Square, but I want to have a start destination that is about 1km away by road. I then need to verify that there is street view imagery for this co-ordinate before I decide that it's the starting point.
The function below recursively doubles the search distance, (up to a maximum of 10000 meters), until a panorama is found.
Sample code:
// Global vars
var G = google.maps;
var streetViewService = new G.StreetViewService();
function getNearSVP(latlon,maxDist) {
streetViewService.getPanoramaByLocation(latlon, maxDist, function(data, status) {
if (status == google.maps.StreetViewStatus.OK) {
return data.location.latLng;
}
else{
if (maxDist < 10000){
maxDist = maxDist * 2;
return getNearSVP(latlon, maxDist);
}
else {
alert('StreetView is not available within '+maxDist+' meters of this location');
}
}
});
}
Live demo here
Related
I don't have any code to share at this point, but I'm trying to figure out how to solve my issue.. I was hoping some of you might have some advice.
I'm building an app where I get the user's lat/long from geolocation and if they are in an predetermined area with a radius they can post data to the server, but not if they aren't in an area that I specified is allowed.. Here is an image for example:
So in this example, the user could post if they are in the radius of one of the circles but not if they aren't.
I would also have to fetch the data based off of which circle they are in..
What I'm wondering is, how would I specify where these radius' exist and does this scale easily? If I needed to add 10-30 new locations would that be easy to do?
You have the user location from the device and as you have the circles; you have the circle centre with their radius. At time of posting, you check the distance from the user location to the circle centre and enumerate thought the circle locations. if the distance is within the radius, they can post if not, not.
var radius = 100 //example
let canPostLocations = [
CLLocation1,
CLLocation2
]
func isInRange() -> Bool {
for canPost in canPostLocations {
let locationDistance = location.distance(from: canPost)
if (locationDistance < radius) {
return true
}
}
return false
}
use as:
var mayPost = false
var userLocation: CLLocation! = nil
if userLocation != nil {
mayPost = InRange(location: userLocation).isInRange()
}
Ok I am trying to make a dynamic pathing system so the player can move from point A to point B without having predefined paths. Note this game is all text based no graphics. The player can move in 10 directions: up, down, n, e, s, w, sw, se, nw and ne.
The map of the entire world is in a database, each row of the database contains a room or a node, each room/node has directions it's capable of going. The room may not be sequential persay. An Example:
Map Number, Room Number, Direction_N, Direction_S, Direction_E, Direction_W, etc.
1 1 1/3 1/100 1/1381 1/101
The Direction_N indicates it goes to Map 1 Room 3, Direction_S Map 1 Room 100, etc...
Ok, I reworked the code with suggestions (thank you guys by the way!) here is revised code. It seems to find the rooms now, even vast distances! But now the issue is finding the shortest path to the destination, I tried traversing the collection but the path is not coming out right...
In the image link below, I have start point in red square in center and stop point at red square at upper left. This returns visitedStartRooms = 103 and visitedStopRooms = 86, when it's only about 16 rooms.
Quess my missing piece of the puzzle is I am not sure how to sort out the rooms in those collection to gain the true shortest route.
Example of map
Here is the new code
public void findRoute(ROOM_INFO startRoom, ROOM_INFO destinationRoom)
{
Dictionary<ROOM_INFO, bool> visitedStartRooms = new Dictionary<ROOM_INFO, bool>();
Dictionary<ROOM_INFO, bool> visitedStopRooms = new Dictionary<ROOM_INFO, bool>();
List<string> directions = new List<string>();
startQueue.Enqueue(startRoom); // Queue up the initial room
destinationQueue.Enqueue(destinationRoom);
visitedStartRooms.Add(startRoom, true);// say we have been there, done that
visitedStopRooms.Add(destinationRoom, true);
string direction = "";
bool foundRoom = false;
while (startQueue.Count != 0 || destinationQueue.Count != 0)
{
ROOM_INFO currentStartRoom = startQueue.Dequeue(); // remove room from queue to check out.
ROOM_INFO currentDestinationRoom = destinationQueue.Dequeue();
ROOM_INFO startNextRoom = new ROOM_INFO();
ROOM_INFO stopNextRoom = new ROOM_INFO();
if (currentStartRoom.Equals(destinationRoom))
{
break;
}
else
{
// Start from destination and work to Start Point.
foreach (string exit in currentDestinationRoom.exitData)
{
stopNextRoom = extractMapRoom(exit); // get adjacent room
if (stopNextRoom.Equals(startRoom))
{
visitedStopRooms.Add(stopNextRoom, true);
foundRoom = true;
break;
}
if (stopNextRoom.mapNumber != 0 && stopNextRoom.roomNumber != 0)
{
if (!visitedStopRooms.ContainsKey(stopNextRoom))
{
if (visitedStartRooms.ContainsKey(stopNextRoom))
{
foundRoom = true;
}
else
{
destinationQueue.Enqueue(stopNextRoom);
visitedStopRooms.Add(stopNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
// start from the start and work way to destination point
foreach (string exit in currentStartRoom.exitData)
{
startNextRoom = extractMapRoom(exit); // get adjacent room
if (startNextRoom.Equals(destinationRoom))
{
visitedStartRooms.Add(startNextRoom, true);
foundRoom = true;
break;
}
if (startNextRoom.mapNumber != 0 && startNextRoom.roomNumber != 0)
{
if (!visitedStartRooms.ContainsKey(startNextRoom))
{
if (visitedStopRooms.ContainsKey(startNextRoom))
{
foundRoom = true;
break;
}
else
{
startQueue.Enqueue(startNextRoom);
visitedStartRooms.Add(startNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
}
You have a good start. There are a few basic improvements that will help. First, to be able to reconstruct your path, you should create a new data structure to store visited rooms. But for each entry, you want to store the room, plus the previous room in the path back to the starting point. A good data structure for this would be a dictionary where the key is the room identifier, and the value is the previous room identifier. To know if you've visited a room, you look to see if it exists in that data structure, not your openList queue. With this new structure, you can properly check if you've visited a room, and you can reconstruct the path back by repeatedly looking up the previous room in the same structure until you get to the origination.
The second improvement will increase the performance quite a bit. Instead of just doing a breadth-first search from the start point until you bump into the destination, as you currently do, instead create matching data structures like you have for the start room search, but have them be for the destination room. After you've looked one room away from the start, look one room away from the destination. Repeat this...two rooms away from start, then two rooms away from destination.. etc., working your way out, until you discover a room that has been visited by both your search from start and your search from destination. Build the path from this room back to the start, and back to the destination, and that will be your shortest path.
The problem you are trying to solve is the shortest path problem with unweighted edges or where the weights of all edges are equal. The weight of an edge is the time/cost to move from one room to another. If the cost to move from one room to another varies depending on which pair of rooms you're talking about, then the problem is more complicated, and the algorithm you started with and for which I've suggested modifications, will not work as it is. Here are some links about it:
Shortest path (fewest nodes) for unweighted graph
http://en.wikipedia.org/wiki/Shortest_path_problem
You may also be interested in the A* algorithm which uses a different approach. It uses a hueristic approach to concentrate the search in a subset of the solution space more likely to contain the shortest path. http://en.wikipedia.org/wiki/A%2a_search_algorithm
But A* is probably overkill in your case since the weight of all edges is the same between all rooms.
I have an application in Flex 4 with a map, a database of points and a search tool.
When the user types something and does the search it returns name, details and coordinates of the objects in my database.
I have a function that, when i click one of the results of my search, it zooms the selected point of the map.
The question is, i want a function that zooms all the result points at once. For example if i search "tall trees" and it returns 10 points, i want that the map zooms to a position where i can see the 10 points at once.
Below is the code im using to zoom one point at a time, i thought flex would have some kind of function "zoom to group of points", but i cant find anything like this.
private function ResultDG_Click(event:ListEvent):void
{
if (event.rowIndex < 0) return;
var obj:Object = ResultDG.selectedItem;
if (lastIdentifyResultGraphic != null)
{
graphicsLayer.remove(lastIdentifyResultGraphic);
}
if (obj != null)
{
lastIdentifyResultGraphic = obj.graphic as Graphic;
switch (lastIdentifyResultGraphic.geometry.type)
{
case Geometry.MAPPOINT:
lastIdentifyResultGraphic.symbol = objPointSymbol
_map.extent = new Extent((lastIdentifyResultGraphic.geometry as MapPoint).x-0.05,(lastIdentifyResultGraphic.geometry as MapPoint).y-0.05,(lastIdentifyResultGraphic.geometry as MapPoint).x+0.05,(lastIdentifyResultGraphic.geometry as MapPoint).y+0.05,new SpatialReference(29101)).expand(0.001);
break;
case Geometry.POLYLINE:
lastIdentifyResultGraphic.symbol = objPolyLineSymbol;
_map.extent = lastIdentifyResultGraphic.geometry.extent.expand(0.001);
break;
case Geometry.POLYGON:
lastIdentifyResultGraphic.symbol = objPolygonSymbol;
_map.extent = lastIdentifyResultGraphic.geometry.extent.expand(0.001);
break;
}
graphicsLayer.add(lastIdentifyResultGraphic);
}
}
See the GraphicUtil class from com.esri.ags.Utils package. You can use the method "getGraphicsExtent" to generate an extent from an array of Graphics. You then use the extent to set the zoom factor of your map :
var graphics:ArrayCollection = graphicsLayer.graphicProvider as ArrayCollection;
var graphicsArr:Array = graphics.toArray();
// Create an extent from the currently selected graphics
var uExtent:Extent;
uExtent = GraphicUtil.getGraphicsExtent(graphicsArr);
// Zoom to extent created
if (uExtent)
{
map.extent = uExtent;
}
In this case, it would zoom to the full content of your graphics layer. You can always create an array containing only the features you want to zoom to. If you find that the zoom is too close to your data, you can also use map.zoomOut() after setting the extent.
Note: Be careful if you'Ve got TextSymbols in your graphics, it will break the GraphicUtil. In this case you need to filter out the Graphics with TextSymbols
Derp : Did not see the thread was 5 months old... Hope my answer helps other people
Running/walking distance display.
User enters a location and a distance.
I can overlay a circle with a radius of the distance the user entered, with the user's location as the center point.
I can set four cardinal points (N, S, E, W) around the point of origin at the distance the user set and draw the routes to those points, such that point B is 100KM from point A, but the mapped route is, say, 145km along the road.
Is it possible to display a route along the road exactly 100km?
Edited to update progress.
Finally solved this and thought I'd share.
so, the user supplies a location and a distance; we'll say 100Km.
The code finds cardinal points 100Km N, S, E, W of the point of origin, then solves routes to each point. If solving for the route is successful, the result contains an array of points from the point of origin to the destination.
directionsService.route({
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
}, function(result) {
renderDirections(result);
});
//don't use the google api DirectionsRender() to draw the route.
//instead - result holds an array of lat/long points that make up the entire route. Lets say it's latlong[123]
//iterate through that array, getting a distance from point A to latlong[0], A to latlong[1], etc...
//when that distance is >= user supplied distance, STOP, and draw a polyline from point A through the latlong points in the array latlong[78]
function computeTotalDistance(result) {
var total = 0;
var myroute = result.routes[0];
if(myroute)
{
//create a LatLon from the Starting point
var objGeo = new LatLon(Geo.parseDMS(myroute.overview_path[0].Qa), Geo.parseDMS(myroute.overview_path[0].Ra));
//call get distance from the starting point to each other point in the array
//each subsequent point should be a longer distance
var arrPointsToDraw =[];
for(var i = 1; i<=myroute.overview_path.length-1;i++)
{
try
{
var objGeo2 = new LatLon(Geo.parseDMS(myroute.overview_path[i].Qa), Geo.parseDMS(myroute.overview_path[i].Ra));
}
catch(err)
{
alert(err.description);
}
//here, total = kilometers
total = objGeo.distanceTo(objGeo2,3);
//add coordinates to our array of points that we are going to draw
arrPointsToDraw.push(new google.maps.LatLng(objGeo2._lat, objGeo2._lon));
if(parseInt(total) > parseInt(distance.value))
{
arrPointsToDraw.pop();//remove the last element of the array
break;
}
}
//at this point, arrPointsToDraw[] contains the lat/long points that are closest to our distance
//without going over
lines[lines.length] = new google.maps.Polyline({
path: arrPointsToDraw,
strokeColor: '#1589FF',
strokeOpacity: 1.0,
strokeWeight: 3
});
lines[lines.length-1].setMap(map);
}//end if(myRoute)
}
This code makes use of two fantastic collections of functions found here
When streetview is not available for a certain location, I would like to find the nearest possible location with streetview?
The only way I could think of is.
radius = 0;
noOfPoints = 3;
while(radius < 10 miles){
radius = radius + 0.2 miles
points = calculate 4 * noOfPoints at this radius
loop(points)
{
if(streetview visibile for point)
bingo, break;
}
break if bingo;
noOfPOints = noOfPoints+1;
}
But this is ridiculously expensive even if I want to find streetview within a 10-mile radius and I am counting on luck to find streetview at one of these points, i.e, I could just miss an actual point with streetview.
can somebody please direct me towards a better approach??
You can try to use the StreetViewService to help you find a nearest existing street view:
var astorPlace = new google.maps.LatLng(40.729884, -73.990988);
var webService = new google.maps.StreetViewService();
/**Check in a perimeter of 50 meters**/
var checkaround = 50;
/** checkNearestStreetView is a valid callback function **/
webService.getPanoramaByLocation(astorPlace,checkaround ,checkNearestStreetView);
function checkNearestStreetView(panoData){
if(panoData){
if(panoData.location){
if(panoData.location.latLng){
/**Well done you can use a nearest existing street view coordinates**/
}
}
}
/** Else do something... **/
}