Google maps - how to get building's polygon coordinates from address? - google-maps

How to implement the following:
User defines an address
User defines a color
Service searches for a corresponding building on the google map
Service fills the found building on the map with the color
I know how to:
1.find lat/long of the address
2.draw the polygon
So, to do the task I need to get polygon coordinates of building from address. How to?

(1) Acquire image tile
(2) Segment buildings based on pixel color (here, 0xF2EEE6).
(3) Image cleanup (e.g. erosion then dilation) + algorithm to acquire pixel coordinates of polygon corners.
(4) Mercator projection to acquire lat/long of pixel

You can convert the address to geographic coordinates by the use of the Google Geocoding API.
https://maps.googleapis.com/maps/api/geocode/json?address=SOME_ADDRESS&key=YOUR_API_KEY
Then, you can use Python and a styled static map to obtain the polygon of the building (in pixel coordinates) at some location:
import numpy as np
from requests.utils import quote
from skimage.measure import find_contours, points_in_poly, approximate_polygon
from skimage import io
from skimage import color
from threading import Thread
center_latitude = None ##put latitude here
center_longitude = None ##put longitude here
mapZoom = str(20)
midX = 300
midY = 300
# Styled google maps url showing only the buildings
safeURL_Style = quote('feature:landscape.man_made|element:geometry.stroke|visibility:on|color:0xffffff|weight:1')
urlBuildings = "http://maps.googleapis.com/maps/api/staticmap?center=" + str_Center + "&zoom=" + mapZoom + "&format=png32&sensor=false&size=" + str_Size + "&maptype=roadmap&style=visibility:off&style=" + safeURL_Style
mainBuilding = None
imgBuildings = io.imread(urlBuildings)
gray_imgBuildings = color.rgb2gray(imgBuildings)
# will create inverted binary image
binary_imageBuildings = np.where(gray_imgBuildings > np.mean(gray_imgBuildings), 0.0, 1.0)
contoursBuildings = find_contours(binary_imageBuildings, 0.1)
for n, contourBuilding in enumerate(contoursBuildings):
if (contourBuilding[0, 1] == contourBuilding[-1, 1]) and (contourBuilding[0, 0] == contourBuilding[-1, 0]):
# check if it is inside any other polygon, so this will remove any additional elements
isInside = False
skipPoly = False
for othersPolygon in contoursBuildings:
isInside = points_in_poly(contourBuilding, othersPolygon)
if all(isInside):
skipPoly = True
break
if skipPoly == False:
center_inside = points_in_poly(np.array([[midX, midY]]), contourBuilding)
if center_inside:
# approximate will generalize the polygon
mainBuilding = approximate_polygon(contourBuilding, tolerance=2)
print(mainBuilding)
Now, you can convert the pixel coordinates to latitude and longitude by the use of little JavaScript, and the Google Maps API:
function point2LatLng(point, map) {
var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
var scale = Math.pow(2, map.getZoom());
var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
return map.getProjection().fromPointToLatLng(worldPoint);
}
var convertedPointsMain = [];
for (var i = 0; i < pxlMainPolygons[p].length; i++) {
var conv_point = {
x: Math.round(pxlMainPolygons[p][i][1]),
y: Math.round(pxlMainPolygons[p][i][0])
};
convertedPointsMain[i] = point2LatLng(conv_point, map);
}
console.log(convertedPointsMain);

Might I humbly suggest you use OpenStreetMaps for this instead ?
It's a lot easier, because then you can use the OverPass API.
However, polygons might not match with google-maps or with state survey.
The latter also holds true if you would use google-maps.
// https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
private static string GetOqlBuildingQuery(int distance, decimal latitude, decimal longitude)
{
System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo()
{
NumberGroupSeparator = "",
NumberDecimalSeparator = ".",
CurrencyGroupSeparator = "",
CurrencyDecimalSeparator = ".",
CurrencySymbol = ""
};
// [out: json];
// way(around:25, 47.360867, 8.534703)["building"];
// out ids geom meta;
string oqlQuery = #"[out:json];
way(around:" + distance.ToString(nfi) + ", "
+ latitude.ToString(nfi) + ", " + longitude.ToString(nfi)
+ #")[""building""];
out ids geom;"; // ohne meta - ist minimal
return oqlQuery;
}
public static System.Collections.Generic.List<Wgs84Point> GetWgs84PolygonPoints(int distance, decimal latitude, decimal longitude)
{
string[] overpass_services = new string[] {
"http://overpass.osm.ch/api/interpreter",
"http://overpass.openstreetmap.fr/api/interpreter",
"http://overpass-api.de/api/interpreter",
"http://overpass.osm.rambler.ru/cgi/interpreter",
// "https://overpass.osm.vi-di.fr/api/interpreter", // offline...
};
// string url = "http://overpass.osm.ch/api/interpreter";
// string url = "http://overpass-api.de/api/interpreter";
string url = overpass_services[s_rnd.Next(0, overpass_services.Length)];
System.Collections.Specialized.NameValueCollection reqparm = new System.Collections.Specialized.NameValueCollection();
reqparm.Add("data", GetOqlBuildingQuery(distance, latitude, longitude));
string resp = PostRequest(url, reqparm);
// System.IO.File.WriteAllText(#"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", resp, System.Text.Encoding.UTF8);
// System.Console.WriteLine(resp);
// string resp = System.IO.File.ReadAllText(#"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", System.Text.Encoding.UTF8);
System.Collections.Generic.List<Wgs84Point> ls = null;
Overpass.Building.BuildingInfo ro = Overpass.Building.BuildingInfo.FromJson(resp);
if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
{
ls = new System.Collections.Generic.List<Wgs84Point>();
for (int i = 0; i < ro.Elements[0].Geometry.Count; ++i)
{
ls.Add(new Wgs84Point(ro.Elements[0].Geometry[i].Latitude, ro.Elements[0].Geometry[i].Longitude, i));
} // Next i
} // End if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
return ls;
} // End Function GetWgs84Points

I've been working on this for hours, the closest I have come is finding a request uri that returns a result with a polygon in it. I believe it specifies the building(boundary) by editids parameter. We just need a way to get the current editids from a building(boundary).
The URI I have is:
https://www.google.com/mapmaker?hl=en&gw=40&output=jsonp&ll=38.934911%2C-92.329359&spn=0.016288%2C0.056477&z=14&mpnum=0&vpid=1354239392511&editids=nAlkfrzSpBMuVg-hSJ&xauth=YOUR_XAUTH_HERE&geowiki_client=mapmaker&hl=en
Part of the result has what is needed:
"polygon":[{"gnew":{"loop":[{"vertex":[{"lat_e7":389364691,"lng_e7":-923341133},{"lat_e7":389362067,"lng_e7":-923342783},{"lat_e7":389361075,"lng_e7":-923343356},{"lat_e7":389360594,"lng_e7":-923342477},

I was intrigued on this problem and wrote a solution to it. See my github project.

The Google Maps API contains a GeocoderResults object that might be what you need. Specifically the data returned in the geometry field.

Related

Can we recall a set of variable inside the Sequence Array?

I'd like to ask about my program bcs it doesn't work correctly. I want to recall a set of variable in two different Sequence Array. Here is my code.
// Array of Arrays
var SequenceGo:Array =
\[
{dt:dt1, P:P1, s0:s01, s:s1},
{dt:dt2, P:P2, s0:s02, s:s2},
{dt:dt3, P:P3, s0:s03, s:s3},
{dt:dt4, P:P4, s0:s04, s:s4},
{dt:dt5, P:P5, s0:s05, s:s5},
{dt:dt6, P:P6, s0:s06, s:s6},
{dt:dt7, P:P7, s0:s07, s:s7},
{dt:dt8, P:P8, s0:s08, s:s8},
{dt:dt9, P:P9, s0:s09, s:s9},
{dt:dt10, P:P10, s0:s010, s:s10},
\];
var SequenceBack:Array =
\[
{dtback:dt10back, P:P10, s0:s010, sback:s10back},
{dtback:dt9back, P:P9, s0:s09, sback:s9back},
{dtback:dt8back, P:P8, s0:s08, sback:s8back},
{dtback:dt7back, P:P7, s0:s07, sback:s7back},
{dtback:dt6back, P:P6, s0:s06, sback:s6back},
{dtback:dt5back, P:P5, s0:s05, sback:s5back},
{dtback:dt4back, P:P4, s0:s04, sback:s4back},
{dtback:dt3back, P:P3, s0:s03, sback:s3back},
{dtback:dt2back, P:P2, s0:s02, sback:s2back},
{dtback:dt1back, P:P1, s0:s01, sback:s1back}
\];
function onNext(index:int = 0):void
{
if (index >= SequenceGo.length)
{
return;
}
var aDataGo:Object = SequenceGo[index];
var aDataBack:Object = SequenceBack[index];
//variables
F = s_teganganst.value;
m = s_masjenst.value/10000;
v = Math.sqrt(F/m);
tp = 5000/v;
f = s_frekuensist.value;
w = 2*Math.PI*f;
aDataGo.dt += t;
aDataGo.s = aDataGo.s0 - A * Math.sin(w * aDataGo.dt);
aDataGo.P.y = aDataGo.s;
if(P10.y < 607){
aDataBack.dtback += t;
aDataBack.sback = - A * Math.sin(w * aDataBack.dtBack);
aDataBack.P.y = aDataGo.s + aDataBack.sback;
}
setTimeout(onNext, tp, index + 1);
}
Actually, code
aDataBack.P.y = aDataGo.s + aDataBack.sback;
is not a fit code for the animation because aDataBack is ordered inversely from aDataGo (we have to stay this inverse order for the proper animation in my program). I want to recall the variables based on its number, so each variable will match with another variable. For example,
P1.y = s1 + s1back;
P2.y = s2 + s2back;
P3.y = s3 + s3back;
P4.y = s4 + s4back;
//and so on
I've tried the code above, but it also doesn't work. Any other expression for calling some couples of variables just like my code above? Thanks!
I want to recall the variables based on its number, so each variable will match with another variable
Ok, there are two options.
Option one, simple and straightforward: compose a method to find the correspondent back object on spot:
function findBack(P:Object):Object
{
for each (var aDataBack:Object in SequenceBack)
{
if (aDataBack.P == P)
{
return aDataBack;
}
}
}
So, that piece of code would be
var aDataGo:Object = SequenceGo[index];
var aDataBack:Object = findBack(aDataGo.P);
The possible problem here is the performance. It is fine on the scale of 10 or 100 objects, but as (I suppose) you devise a particle system, the object count easily scales to thousands, and the amount of loop-searching might become cumbersome.
So I advise to prepare a pre-indexed hash so that you won't need to search each single time.
var SequenceBack:Array =
[
// ...
];
// Dictionary is a storage of key:value data, just like Object,
// but Dictionary allows Object keys.
var HashBack:Dictionary = new Dictionary;
for each (var aDataBack:Object in SequenceBack)
{
HashBack[aDataBack.P] = aDataBack;
}
I encourage you to read more about Dictionary class.
And so that piece of code would be
var aDataGo:Object = SequenceGo[index];
var aDataBack:Object = HashBack[aDataGo.P];

Parse JSON String By Comma Deliminator Flutter

I have some string that I need to separate into Latitude and Longitude to get LatLng but, do not know how to separate by delimiter to pull it off.
The string is: {location: 40.748817,-73.985428}
I need to separate it into Lat and lng to create a marker and do not know how
Try this !
//If String
String location = 'location: 40.748817,-73.985428';
List<String> latAndLong =
location.replaceFirst(' ', '').replaceAll('location:', '').split(',');
LatLng latLng = new LatLng(double.parse(latAndLong[0]),double.parse(latAndLong[1]));
//If Map/JSON
var location2 = {'location': '40.748817,-73.985428'};
String locationExtracted = location2['location'].toString();
List<String> latAndLong2 =
locationExtracted.replaceFirst(' ', '').replaceAll('location:', '').split(',');
LatLng latLng2 = new LatLng(double.parse(latAndLong2[0]),double.parse(latAndLong2[1]));
Depending on what the actual input format is, it can be easier or harder.
If the input is actually a JSON map with the format {"location": "40.748817,-73.985428"}, then just parse it as JSON first, then split the string on the comma:
List<double> parseCoordinates(String source) {
var parts = jsonParse(source)["location"]?.split(",");
if (parts == null || parts.length != 2) {
throw FormatException("Not valid location coordinates", source);
}
return [double.parse(parts[0], double.parts[1])];
}
If the input is actually a string of the form {location: 40.748817,-73.985428}, which is not valid JSON, then it looks like something which is actually most easily solved with a RegExp.
Example:
final _coordRE = RegExp(r"^\{location: (-?\d+(?:.\d+)), (-?\d+(?:.\d+))\}$");
List<double> parseCoordinates2(String source) {
var match = _coordRE.firstMatch(source);
if (match == null) throw FormatException("Not valid coordinates", source);
return [double.parse(match[1]), double.parse(match[2])];
}
and then use it as
var coords = parseCoordinates(source);
var lat = coords[0];
var lng = coords[1];
Alternatively, since you know the format so precisely, you can just extract the substrings yourself instead of using a RegExp:
List<double> parseCoordinates(String source) {
var prefix = "{location: ";
if (source.startsWith(prefix) && source.endsWith("}")) {
var commaIndex = source.indexOf(",", prefix.length);
if (commaIndex >= 0) {
var lat = double.parse(source.substring(prefix.length, commaIndex));
var lng = double.parse(source.substring(commaIndex + 1, source.length - 1));
return [lat, lng];
}
}
throw FormatException("Not valid coordinates", source);
}
If the format can vary more than your example (perhaps it allows -.5 as a coordinate, with no leading 0), you'll have to adapt the regexp. One option is to have the capture groups simply capture [-.\d]+ and rely on the double parser to handle syntax errors.
Have you tried the function jsonDecode? It returns a dynamic.
var coordinate = jsonDecode('[your json string]');
print(coordinate['location']);
Then the rest is just to split it into tokens with split() function.
G'luck.

Autodesk Forge Viewer How to get coordinates of line start/stop

I am trying to do room highlighting in forge viewer.
In revit I have created lines that represent the borders of a room. After conversion to svf I know the dbids of those lines. Now I want to know the start and stop points (vertices) of those lines so that I can create a Three.Shape() of the room borders.
[EDIT] I get the fragId from dbId
function getFragIdFromDbId(viewer, dbid){
var returnValue;
var it = viewer.model.getData().instanceTree;
it.enumNodeFragments(dbid, function(fragId) {
console.log("dbId: " + dbid + " FragId : " + fragId);
returnValue = fragId;
}, false);
return returnValue;
}
Question:
Once I know the fragId is there a way to see its start and stop points(vertices)? Also will those vertices be world space or local space?
This is what I ended up doing. Note make sure the model is finished loading before calling instanceTree. Also in my case the dbid and fragid where one to one, not sure if this will always be the case in the instance tree.
function getFragIdFromDbId(viewer, dbid) {
var returnValue;
var it = viewer.model.getData().instanceTree;
it.enumNodeFragments(dbid, function (fragId) {
console.log("dbId: " + dbid + " FragId : " + fragId);
returnValue = fragId;
}, false);
return returnValue;
}
...
// only need the start vertex
var floatArray = [];
for (var i = 0; i < dbidArray.length; i++) {
var fragId = getFragIdFromDbId(viewer, dbidArray[i]);
var mesh = viewer.impl.getRenderProxy(viewer.model, fragId);
var matrixWorld = mesh.matrixWorld;
var lmvBufferGeometry = mesh.geometry;
var lmvFloatArray = lmvBufferGeometry.vb; //this will have an array of 6 values 0,1,2 are start vertext , 3,4,5 are end vertex
floatArray.push(lmvFloatArray[0]);
floatArray.push(lmvFloatArray[1]);
floatArray.push(lmvFloatArray[2]);
}
//use matrixWorld to convert array to worldSpace

Google Maps: Find all zip codes along route

Given two locations you can calculate a route in Google Maps.
Is it possible to find all zip codes along the route?
Given a zip code, can I expand the area easily with a 10 km radius and find all zip codes in that area?
What methods should I use to get this information? Tutorials are welcome. I don't need a complete working solution, although if one is available that would be really nice.
You need a data source containing the zipcode (ZCTA) polygons. One possible source is this FusionTable.
proof of concept
proof of concept showing ZCTA polygons
Note: since it queries for the zip code at every point along the route, it will take longer to finish the longer the route is.
code that performs the query (using the Google Visualization API):
function queryForZip(latlng) {
//set the query using the current latlng
var queryStr = "SELECT geometry, ZIP, latitude, longitude FROM "+ tableid + " WHERE ST_INTERSECTS(geometry, CIRCLE(LATLNG"+latlng+",1))";
var queryText = encodeURIComponent(queryStr);
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(addZipCode);
}
function addZipCode(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
document.getElementById('status').innerHTML += 'Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage()+"<br>";
return;
}
FTresponse = response;
//for more information on the response object, see the documentation
//http://code.google.com/apis/visualization/documentation/reference.html#QueryResponse
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
for(i = 0; i < numRows; i++) {
var zip = response.getDataTable().getValue(i, 1);
var zipStr = zip.toString()
if (!zipcodes[zipStr]) {
zipcodes[zipStr] = zipStr;
document.getElementById('zipcodes').innerHTML += zipStr+"<br>";
}
}
}

Winphone 8 GPS weirdness

I'm writing a POC for WinPhone 8 (I have a Nokia 928 running the 8.1 release).
One of the features I'm working with is GeoLocator and I'm noticing some odd behavior. My app gets your current location and then tracks your movement and calculates the distance between the two points. The odd behavior is that I'm sitting still and the PositionChanged event is firing! What gives? I've yet to move and my app already says the distance from the origin and my current location is ~9Meters.
Is this normal behavior for GPS? If so, what is the recommended method of dealing with it?
Here is how my GeoLocator is setup:
_Geolocator = new Geolocator();
_Geolocator.DesiredAccuracy = PositionAccuracy.High;
_Geolocator.MovementThreshold = 5;
_Geolocator.ReportInterval = 1000;
I have a button that gets the current location and starts the position changed event (chopping code for brevity):
Geoposition position = await _Geolocator.GetGeopositionAsync();
_trackLocation = true;
_currentLocation = position;
OrigLongitude = _currentLocation.Coordinate.Longitude;
OrigLatitude = _currentLocation.Coordinate.Latitude;
_Geolocator.PositionChanged += _Geolocator_PositionChanged;
Message = "tracking location";
and the PositionChanged event:
_currentLocation = args.Position;
//calculate the distance
double d = _pointTracker.DistanceTo(_currentLocation.Coordinate.Latitude, _currentLocation.Coordinate.Longitude);
double accuracy = _currentLocation.Coordinate.Accuracy;
if (true == show.Contains("tracking X"))
{
show = "tracking Y " + accuracy.ToString();
}
else
{
show = "tracking X " + accuracy.ToString();
}
DispatcherHelper.CheckBeginInvokeOnUI(() => { Distance = d; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Message = show; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Longitude = _currentLocation.Coordinate.Longitude; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Latitude = _currentLocation.Coordinate.Latitude; });
The show junk just lets me see that a message showing that the event is firing. the only thing of interest in it is the GPS accuracy I'm getting back (usually it's about 3 meters, in doors it is 9 meters).
Any direction or help would be greatly appreciated.
TIA