I would like to find the nearest location for a given address (user input) from an array of locations (lat, lng).
(Or, even better, sort the lcoations by distance)
I want to achieve this without displaying a map.
I'm also not sure which Google API would be best suited for this (Geocoding API, Maps v3 etc.).
What would be the best approach for this?
If someone could point me in the right direction it would be greatly appreciated.
Locations:
[
{
// Amsterdam
"lat": 52.3702157,
"lng": 4.8951679
},
{
// Berlin
"lat": 52.5200066,
"lng": 13.404954
},
{
// Brussels
"lat": 50.85,
"lng": 4.35
},
{
// Paris
"lat": 48.856614,
"lng": 2.3522219
},
{
// Madrid
"lat": 40.4167754,
"lng": -3.7037902
}
]
User input: Antwerp
{
"lat": 51.2194475,
"lng": 4.4024643
}
Should return: Brussels
{
"lat": 50.85,
"lng": 4.35
}
Or, sorted by distance:
[
{
// Brussels
"lat": 50.85,
"lng": 4.35
},
{
// Amsterdam
"lat": 52.3702157,
"lng": 4.8951679
},
{
// Paris
"lat": 48.856614,
"lng": 2.3522219
},
{
// Berlin
"lat": 52.5200066,
"lng": 13.404954
},
{
// Madrid
"lat": 40.4167754,
"lng": -3.7037902
}
]
Android provides a nice feature for you, that can calculate the distance (DistanceTo()) (ref: http://developer.android.com/reference/android/location/Location.html) Heres an example of, how to use DistanceTo with google map api:
private double CalculateDistance(LatLng endPoint)
{
//Convert LatLng to Location
Location location = new Location("tmploc");
location.Latitude = endPoint.Latitude;
location.Longitude = endPoint.Longitude;
location.Time = currentLocation.Time; //Set time as current position's time. (could also be datetime.now)
return currentLocation.DistanceTo(location);
}
You can then use this to find the lowest value:
public int Lowest(params int[] inputs)
{
return inputs.Min();
}
(ref: https://stackoverflow.com/a/4390808/3861983)
If you do a method where you use the first method, add it to a array and then get the lowest number from the second method. You will have achieved your goal.
Related
I am working with a fleet management system. I have a scenario that driver have to go multiple places to pickup and deliver the pickup product in multiple delivery location.
Here i have a scenario like that,
Order 1 - Pickup (P1 time range 10:00AM to 11:00 AM) 10 Product. it has 3 delivery point in different location in any time can be delivered with in shift (D1,D2,D3) all of the picked product will delivered in delivered location .
Order 2 - Pickup (P2 time range 11:00AM to 12:00 PM) 10 Product. it has 3 delivery point in different location in any time can be delivered with in shift (D4,D5,D6) all of the picked product will delivered in delivered location .
Order 3 - Pickup (P3 time range 10:30AM to 11:30 PM) 10 Product. it has 3 delivery point in different location in any time can be delivered with in shift (D7,D8,D9) all of the picked product will delivered in delivered location .
in above scenario we have a restriction that if pickup is not complete then we can't make the delivery of this order like if P1 is not complete then we can't complete D1,D2 or D3.
so our optimized list should be set priority wise. We are getting optimized stop but some time we are getting delivery stop is coming before pickup stop. so we want to prevent this things.
is there any instruction to do this using Here Tour Planning API.
VRP with Multi-Jobs
A multi-job as opposed to a simple job is a job that consists of multiple pickups and deliveries. The specific of such jobs is that they only can be considered as executed when all the tasks inside the job are done, otherwise, none of them will be executed. Also, the sum of demands for pickups and deliveries must be equal. A very common scenario for a multi-job problem could be executing multiple pickups at different locations followed by delivery to a single location.
We can imagine the multi-job VRP in real life as for example a daily routine of a school bus that has to pick up several children at different addresses and deliver them to school. As we can guess, taking the kids back to their homes from the school by the same school bus is a multi-job VRP as well.
Another example of multi-job VRP use in real life is the work of garbage collection companies when a vehicle has to execute several pickups and one delivery within the job (collect garbage from several locations in the city and deliver it to the dump location).
So let’s consider we have a multi-job with several pickups and one delivery in it. Let’s say we need to deliver 3 children to the local school from their specific address via the school bus. Regarding the vehicle, we need it to start and end the shift at one depo, that is at the same location. We specify the routine vehicle constraints like cost, distance, shift time, location, capacity and amount. Note that In the case of a school bus, for example, you may assume your capacity units as people/children.
{
"fleet": {
"types": [
{
"id": "b0130d2f754d",
"profile": "car_1",
"costs": {
"fixed": 5.0,
"distance": 0.007,
"time": 0.002
},
"shifts": [
{
"start": {
"time": "2021-08-27T08:03:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
},
"end": {
"time": "2021-08-27T16:03:00Z",
"location": {
"lat": 52.48693181589403,
"lng": 13.308748991045801
}
}
}
],
"capacity": [
20
],
"amount": 1
}
],
"profiles": [
{
"type": "car",
"name": "car_1"
}
]
},
Regarding the jobs, in this very case, you can set them depending on your needs. One way is to add all of your pickups as separate jobs and then add a delivery job. The other way is to use a multi-job. In this way, you may add a multi-job with all the pickups and one delivery at the end. Let's build a problem where we would have one multi-job with 3 pickups and 1 delivery to deliver all those pickups in one location.
Problem
{
"fleet": {
"types": [
{
"id": "b0130d2f754d",
"profile": "car_1",
"costs": {
"fixed": 5.0,
"distance": 0.007,
"time": 0.002
},
"shifts": [
{
"start": {
"time": "2021-08-27T08:03:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
},
"end": {
"time": "2021-08-27T16:03:00Z",
"location": {
"lat": 52.530971,
"lng": 13.384915
}
}
}
],
"capacity": [
30
],
"amount": 1
}
],
"profiles": [
{
"type": "car",
"name": "car_1"
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"pickups": [
{
"places": [
{
"location": {
"lat": 52.47706593757918,
"lng": 13.390815701172201
},
"duration": 660,
"tag": "Address_1"
}
],
"demand": [
1
]
},
{
"places": [
{
"location": {
"lat": 52.473571009931106,
"lng": 13.389035169086807
},
"duration": 1140,
"tag": "Address_2"
}
],
"demand": [
1
]
},
{
"places": [
{
"location": {
"lat": 52.53090538774364,
"lng": 13.384692097156309
},
"duration": 840,
"tag": "Address_3"
}
],
"demand": [
1
]
}
],
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.58919138279804,
"lng": 13.462161100698735
},
"duration": 1020,
"tag": "Address_4"
}
],
"demand": [
3
]
}
]
}
}
]
}
}
Solution
The solution for this problem will look as follows:
{
"statistic": {
"cost": 273.77500000000003,
"distance": 36041,
"duration": 8244,
"times": {
"driving": 4584,
"serving": 3660,
"waiting": 0,
"break": 0
}
},
"tours": [
{
"vehicleId": "b0130d2f754d_1",
"typeId": "b0130d2f754d",
"stops": [
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2021-08-27T08:03:00Z",
"departure": "2021-08-27T08:03:00Z"
},
"load": [
0
],
"activities": [
{
"jobId": "departure",
"type": "departure"
}
]
},
{
"location": {
"lat": 52.53090538774364,
"lng": 13.384692097156307
},
"time": {
"arrival": "2021-08-27T08:03:02Z",
"departure": "2021-08-27T08:17:02Z"
},
"load": [
1
],
"activities": [
{
"jobId": "job_1",
"type": "pickup",
"jobTag": "Address_3"
}
]
},
{
"location": {
"lat": 52.473571009931106,
"lng": 13.389035169086808
},
"time": {
"arrival": "2021-08-27T08:34:57Z",
"departure": "2021-08-27T08:53:57Z"
},
"load": [
2
],
"activities": [
{
"jobId": "job_1",
"type": "pickup",
"jobTag": "Address_2"
}
]
},
{
"location": {
"lat": 52.47706593757918,
"lng": 13.3908157011722
},
"time": {
"arrival": "2021-08-27T08:54:51Z",
"departure": "2021-08-27T09:05:51Z"
},
"load": [
3
],
"activities": [
{
"jobId": "job_1",
"type": "pickup",
"jobTag": "Address_1"
}
]
},
{
"location": {
"lat": 52.58919138279804,
"lng": 13.462161100698737
},
"time": {
"arrival": "2021-08-27T09:40:21Z",
"departure": "2021-08-27T09:57:21Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_1",
"type": "delivery",
"jobTag": "Address_4"
}
]
},
{
"location": {
"lat": 52.530971,
"lng": 13.384915
},
"time": {
"arrival": "2021-08-27T10:20:24Z",
"departure": "2021-08-27T10:20:24Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival"
}
]
}
],
"statistic": {
"cost": 273.77500000000003,
"distance": 36041,
"duration": 8244,
"times": {
"driving": 4584,
"serving": 3660,
"waiting": 0,
"break": 0
}
}
}
]
}
From this solution we can see that the vehicle starts its way from a depot, after that it executes 3 pickup and 1 delivery multi-job, and arrives back to the depot.
See also the documentation here
HERE REST API fleet.ls
Consider the following REST API call. Note the Long Lats are in Adelaide Australia which has a TZ of +9:30.
https://fleet.ls.hereapi.com/2/calculateroute.json?waypoint0=-34.8751,138.5276&waypoint1=-34.9042,138.5708;sort&waypoint2=stopOver,600!-34.893,138.5546;sort&departure=2021-01-08T17:15:00&mode=fastest;car;traffic:enabled&legAttributes=-li,-mn,le,bt,tt,-tm,sh&routeAttributes=sm,wp&apikey=xxxxxx
The Departure time is set to:
departure=2021-01-08T17:15:00
However the summary returns the following:
"summary": {
"travelTime": 1010,
"distance": 5102,
"baseTime": 882,
"trafficTime": 1010,
"flags": [],
"departure": "2021-01-08T**17:15:00+10**",
"arrival": "2021-01-08T17:31:49+10"
}
The absolute time is incorrect as the location has a timezone of +9.5 (or +10.5 DST). This, is then passed through to other algorithms used and, well, messes everything up by a half an hour.
It appears you are using version 7 of the Calculate Route API, as shown here. It shows timestamps with only whole-hour offsets, such as 2013-07-04T17:00:00+02.
The docs here for version 8+ of the API show a very different format for its output, including timestamps with full hours and minutes in the offset, such as 2019-12-09T16:05:05+01:00. The full example in docs is:
{
"routes": [
{
"id": "bfaed7d0-19c7-4e72-81b7-24eeb148b62b",
"sections": [
{
"arrival": {
"place": {
"location": {
"lat": 52.53232637420297,
"lng": 13.378873988986015
},
"type": "place"
},
"time": "2019-12-09T16:05:05+01:00"
},
"departure": {
"place": {
"location": {
"lat": 52.53098367713392,
"lng": 13.384566977620125
},
"type": "place"
},
"time": "2019-12-09T16:03:02+01:00"
},
"id": "85357f8f-00ad-447e-a510-d8c02e0b264f",
"summary": {
"duration": 123,
"length": 538
},
"transport": {
"mode": "car"
},
"type": "vehicle"
}
]
}
]
}
I suggest you use the latest v8 of the API (8.14.0 at time of writing this). It should give the correct offsets for Adelaide.
I am trying to understand how exactly bounding box is working, but from my tests at the moment it seems that result is returned regardless of the bounding box limits.
I tried various approaches,but it appears that either the flow is working this way or I am missing something. In short, I have tried to put in example request:
https://developer.here.com/api-explorer/rest/geocoder/latitude-longitude-by-mapview-parameter
mapview in Boston suburban area and search text which is my home address in Bulgaria - few thousand miles away from the bounding box borders. However, I still get a result-my address Geocoded correctly. Since it is out of the bounding box I was expecting either 0 results or some exception. Or there is some parameter in the Response I can use for defining outboxing-for this case that might be the Distnace because I am too far but in addresses close to borders I am not sure if that will be fine.
My URL request:
https://geocoder.api.here.com/6.2/geocode.json?searchtext=g.k.%20Krasna%20polyana%201%2022%D0%91%2C%201373%20g.k.%20Krasna%20polyana%201%2C%20Sofia&mapview=42.3902%2C-71.1293%3B42.3312%2C-71.0228&gen=9&app_id=devportal-demo-20180625&app_code=9v2BkviRwi9Ot26kp2IysQ
The result I got:
'{
"Response": {
"MetaInfo": {
"Timestamp": "2019-08-16T16:31:38.596+0000"
},
"View": [
{
"_type": "SearchResultsViewType",
"ViewId": 0,
"Result": [
{
"Relevance": 0.88,
"Distance": 7276566.3,
"MatchLevel": "houseNumber",
"MatchQuality": {
"City": 1,
"District": 0.88,
"Street": [
0.85
],
"HouseNumber": 1,
"PostalCode": 0.56
},
"MatchType": "interpolated",
"Location": {
"LocationId": "NT_i2D3cJK.runCacYakfrAxD_yIjQ",
"LocationType": "address",
"DisplayPosition": {
"Latitude": 42.69695,
"Longitude": 23.28172
},
"NavigationPosition": [
{
"Latitude": 42.69709,
"Longitude": 23.28169
}
],
"MapView": {
"TopLeft": {
"Latitude": 42.6980742,
"Longitude": 23.2801904
},
"BottomRight": {
"Latitude": 42.6958258,
"Longitude": 23.2832496
}
},
"Address": {
"Label": "жк Красна поляна 1 22Б, 1330 София, България",
"Country": "BGR",
"County": "София-град",
"City": "София",
"District": "Красна поляна",
"Street": "жк Красна поляна 1",
"HouseNumber": "22Б",
"PostalCode": "1330",
"AdditionalData": [
{
"value": "България",
"key": "CountryName"
},
{
"value": "София-град",
"key": "CountyName"
}
]
}
}
}
]
}
]
}
}'
I am expecting some standard way to catch the results out of the bounding box. Actually, it seems that either there is no clear value to count on or I am missing something about the way it works. Thanks in advance!
I think you are looking for this one:
bbox - A type of Spatial Filter. A spatial filter limits the search for any other attributes in the request.
For your example: https://geocoder.api.here.com/6.2/geocode.json?searchtext=g.k.%20Krasna%20polyana%201%2022%D0%91%2C%201373%20g.k.%20Krasna%20polyana%201%2C%20Sofia&bbox=42.3902%2C-71.1293%3B42.3312%2C-71.0228&&app_id=yyy&app_code=xxx
When I make a call to the cloud vision web entities detection I will get different results then when I use the exact same image on the demo side (https://cloud.google.com/vision/).
Api results:
"webEntities": [
{
"entityId": "/m/069b9z",
"score": 28.432,
"description": "Muiden Castle"
},
{
"entityId": "/m/0k3p",
"score": 9.7216,
"description": "Amsterdam"
},
{
"entityId": "/m/0gvtk97",
"score": 4.6464,
"description": "Pampus"
},
{
"entityId": "/m/03w10h",
"score": 4.5328,
"description": "Stelling van Amsterdam"
},
{
"entityId": "/m/04rjz",
"score": 0.7232,
"description": "Middle Ages"
}
],
Demo result:
"webDetection": {
"webEntities": [
{
"entityId": "/m/069b9z",
"score": 28.2912,
"description": "Muiden Castle"
},
{
"entityId": "/m/06jsf",
"score": 23.7056,
"description": "Rijksmuseum"
},
{
"entityId": "/m/03w10h",
"score": 4.2744,
"description": "Stelling van Amsterdam"
},
{
"entityId": "/m/0gvtk97",
"score": 4.2264,
"description": "Pampus"
},
{
"entityId": "/g/11clg9rz1_",
"score": 1.3836,
"description": "Marina Muiderzand"
},
{
"entityId": "/m/0w0r9",
"score": 1.1220801,
"description": "Muiden"
},
{
"entityId": "/m/0grl_",
"score": 0.7032,
"description": "Château"
},
{
"entityId": "/m/0d5gx",
"score": 0.5525,
"description": "Castle"
},
{
"entityId": "/m/01k12m",
"score": 0.5256,
"description": "Dutch Golden Age"
},
{
"entityId": "/t/23p50h_kgbnhm",
"score": 0.5227
},
{
"entityId": "/m/026gg32",
"score": 0.3787,
"description": "Water castle"
},
{
"entityId": "/g/122lvp4h",
"score": 0.3709,
"description": "Dag van het Kasteel"
},
{
"entityId": "/m/0pgl9",
"score": 0.3558,
"description": "Tourist attraction"
},
{
"entityId": "/m/0k3p",
"score": 0.103136,
"description": "Amsterdam"
},
{
"entityId": "/m/059j2",
"score": 2.0908006e-11,
"description": "Netherlands"
}
],
This is how I add the image
using (Image image = Image.FromFile(filePath))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
request.Requests[0].Image.Content = Convert.ToBase64String(imageBytes);
}
}
This happens with almost all images.
As far as I know of the only option you have, when calling the web entity detection api is the amount of results you want. But the amount has no effect on the kind of results.
The api's Label detection and landmark detection give the same answers as the demo.
Has anybody seen this behavior too?
Are there other options I missed?
Edit:
Request body:
{
"requests":[
{
"features":[
{
"type": "LABEL_DETECTION",
"maxResults":5
},
{
"type":"LANDMARK_DETECTION",
"maxResults":1
},
{
"type":"WEB_DETECTION",
"maxResults":5
}
],
"image":
{
"content":"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"
}
}
] }
Edit 2:
Endpoint: https://vision.googleapis.com/v1/images:annotate
I do not use a SDK.
Edit 3:
the image I used: https://www.muiderslot.nl/wp-content/uploads/2015/05/DSC5093-Muiderslot-poster.jpg
Strange thing is that I just tested the image again and now the demo also gives as second description "Amsterdam" but the 5th description is still different.
But this image still gives bigger differences: https://imgur.com/a/r76Ah
I have a big data in GeoJSON with Point type like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
2.8125,
47.040182144806664
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
14.765625,
48.69096039092549
]
}
}
]
}
As far as I know, in order to create polygon on a map, my GeoJSON should have Polygon as a Type instead of Points. How can I do it? Does anybody have idea? Should I convert them into polygon? How? I really need your help guys... (I am using Mapbox-Gl-Js by the way)
Thanks!
was having same issue searched for ages then found this lib Terraformer, (http://terraformer.io/core/#terraformercircle), one of the methods allows you to specify a long and lat point, and convert that into a circle around that point.
See my implementation below or you can also go through the docs
http://terraformer.io/core/#terraformercircle
//get the Terraformer lib
var Terraformer = require("terraformer");
const getPolygonFromPoints = async => {
//get the geoJSON
const getPointBasedGeoJSON = await require({localresource}); //or use a fetch if it is an external resource.
//loop over all the featues using ES6 map, to generate a new array of polygon based coordinates
const polygonBasedGeoJSON = getPointBasedGeoJSON.features.map(d => ({
type: "Feature",
...new Terraformer.Circle(
[d.geometry.coordinates[0], d.geometry.coordinates[1]],
500, //The radius of the circle in meters.
5 //How many steps will be used to create the polygon that represents the circle. i.e number of poins in the polyon array
),
/*
Terraformer.Circle will retrun an object similar to this, which we need to spread into our parent object, hence the ES6 spread
"geometry": {
"type": "Point",
"coordinates": [array of polygon coordinates based on the point you referenced]
},
*/
point: [d.geometry.coordinates[0], d.geometry.coordinates[1]], //so that you can still reference a point
properties: {
//specify any properties
}
}));
if (polygonBasedGeoJSON.length > 0){
return polygonBasedGeoJSON
}
return []
}
//Points to Polygon collection ready for use
console.log(getPolygonFromPoints())
It's simple: I had a data regarding terrorism in csv with latitude, longitude. When i converted it to geojson I had a structure like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
2.8125,
47.040182144806664
]
}
}
The question was: how I can create a map like this using this data: terrorism_map
I know that my geojson is useless in this case, but i need a way of creating map using this data. Sorry to confuse...