Query database values based on user's location - javascript

How can I perform a query on the database as per the user's location value? The application was developed with HTML5, CSS, Javascript, PHP has a database with columns as in the below table.
On the html webpage the users geo coordinates are collected and are to be compared with the values in the database to find the nearest place to the user with the places in the database.
Please let me know how to achieve this. Any examples / samples will be appreciated.

There is a question that compares the capabilities of various spatial databases, GIS: PostGIS/PostgreSQL vs. MySql vs. SQL Server?, where Postgis comes out a pretty clear winner over MySQL.
Whether you use MySQL or Postgis, you would be much better off, if you can, storing your latitude and longitude values as a geometry/geography (Point), as the functions that can be used to find things nearby, ST_Distance, ST_Distance_Sphere and the more obscure <-> operator, see Find n Nearest Neighbors for given Point using PostGIS? (for example usage) work directly on geometry/geography columns. Even more importantly, you can add a spatial index, which these functions need to work properly, which will outperform searches on separately indexed latitude and longitude columns by a large margin (this will depend on table size, but will grow as table size grows),
In Postgis, you can convert lat and lon to a geometry with:
alter table mytable add column geom (Geometry, 4326);
update mytable set geom = ST_SetSRID(ST_MakePoint(lon, lat), 4326)
create index ix_spatial_mytable_geom on mytable using gist(geom);
At this point, you will be able to very efficient queries to find points near other points, using any of the examples in the above links.
You can do similar things in MySQL, although, it does not support a spatial reference system, ie, the 4326 above, which means lat/lon, and it lacks a ST_MakePoint function, so you would need to use STGeomFromText and concatenate the lat/lon together to make a POINT. It also does everything in planar coordinates, as Claudio and others have stated, which is not an issue with Postgis.
I apologize for a long and somewhat tangential answer, but having done various migrations between databases on large amounts of data (MySQL, SQL Server and Postgres/GIS) and made lots of mistakes on the way, I hope I can set you off in the right direction (and add a bit of future proofing, if you want to start using some other spatial functionality, which Postigs has in spades).

For a rough measure I would try something like the following (only Euclidean geometry, it doesn't take into account the Earth curvature or problems like this).
First you could compute the difference between the user's coordinates and the coordinates of places in the database. Like this:
distLat = abs(userLat - placeLat)
distLong = abs(userLong - placeLong)
Then I would compute the distance between the two points using Pythagora's theorem. So:
distance = squareRoot(distLat * distLat + distLong * distLong)
You can compare the distances of all places in the database and take the minimum, which teoreticaly is the place nearest to the user's position.
If you use MySQL I think that a query like this should work:
SELECT * FROM places ORDER BY MIN(SQRT((p.latitude - userLatitude) * (p.latitude - userLatitude) + (p.longitude - userLongitude) * (p.longitude - userLongitude))) LIMIT 1
Beware that this query could be very slow depending on how many places you have, because it needs to read all the rows in the table and compute the distance for each one. Indexes have no effects.
Anyway, for this kind of problems you should better use GIS or databases with good geospatial extensions. MySQL geospatial extension is not very powerful, even in MySQL 5.6. It has a ST_DISTANCE function but still uses Euclidean geometry which is not very accurate for calculation on a spherical surface like the Earth. Anyway, if you use MySQL 5.6, I think that it should be better to use the ST_DISTANCE function, which is for sure much more optimized than doing calculations "manually" in the query.
See also this article for a deep explanation and more examples: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc
EDIT
As requested by the OP, I add more details on how to deal with negative coordinates.
Negative coordinates are generally not a big issue. I will try to explain this with some examples.
Take for example the coordinates of the Brooklyn bridge: 40.704391, -73.994675.
With the above formula, the distance of the Brooklyn bridge from the Statue of Liberty is:
sqrt((40.704391 - 40.689167)^2 + (-73.994675 - -74.044444)^2) = 0.052045399
Now consider the distance between the Statue of Liberty and the Brooklyn Bowl (coordinates 40.7179666, -73.9670125), that is:
sqrt((40.7179666 - 40.689167)^2 + (-73.9670125 - -74.044444)^2) = 0.082613886
As you can see the distance of the Brooklyn Bowl from the Statue of Liberty is bigger than the distance of the Brooklyn Bridge. It is correct since the Brooklyn Bowl is 4 miles away from the Statue of Liberty, while the Brooklyn Bridge is only 1 mile away from it.
In this example both the two points has a negative longitude. But the formula works even if one of the two has positive coordinates. For example, the distance between the Statue of Liberty and the Tour Eiffel (Paris, coordinates 48.858360, 2.294460), is:
sqrt((48.858360 - 40.689167)^2 + (2.294460 - -74.044444)^2) = 76.77476134
Then calculate also the distance between the Statue of Liberty and the Colosseum (Rome, coordinates 41.890238, 12.492242):
sqrt((41.890238 - 40.689167)^2 + (12.492242 - -74.044444)^2) = 86.54502063
As you can see it works, the distance of the Colosseum is bigger since it is about 8000km away from the Statue of Liberty, while the Tour Eiffel is about 800 km closer.
The only issue I see is when you have to calculate the distance between two places that are in the far east and in the far west respectively. The above formula will give you a very high distance, but actually the they could be very close. Take for example Anchorage, a city in Alaska (coordinates 61.252240, -149.896769), and Beringovskij, a city in the very east of Russia (coordinates 63.049797, 179.310011). They have a distance of only about 1500 km but with the above formula you get:
sqrt((61.252240 - 63.049797)^2 + (-149.896769 - 179.310011)^2) = 329.2116875
Definitely a too high value for only 1500 km: I would expect something less than 50.
The problem is that the formula calculates the distance taking the central meridian as a reference point, that is the meridian with a 0 degrees latitude. This is good until the distance is "no more that half the Earth".
I think that a solution could be to calculate two distances.
The first with a reference point of 0 degrees: it is what the above formula does.
The second with a reference point of 180 degrees. It's like calculating the distance on a world map shifted by 180 degrees, like this: http://www.bouwman.com/world/Formilab-180.html.
And then take the minimum of these two distances.
Thus the formula becomes a little more complex:
distance = squareRoot(min((userLat - placeLat)^2, (userLat - placeLat - 360)^2) + (userLong - placeLong)^2)
Note that we subtract 360 because it is the distance between the degree -180 and the degree 180.
With this new formula we get correct results for places that are more then 180 degrees away from each other, and we get also the same result given by the previous formula when comparing places that are less then 180 degrees away from each other. The calculate distance Anchorage - Beringovskij is now: 30.84564166.
Of course, as I have already said, this is not an exact method for calculating distances. You can take a look at this article for more "scientific" techniques: https://en.wikipedia.org/wiki/Geographical_distance :D

Related

How to translate markers into a half circle with minimal line intersection?

I have a map and a lot of markers are displayed on it. Sometimes markers are so close to each-other that they overlap. To remedy this, I have implemented a spiderfier library to remedy this situation.
The idea is to group the markers being close-enough upwards on the screen (downwards mathematically) in such a way that they will not intersect each-other.
Markers are displayed as rectangles.
Implementation:
traverses the markers and markers which intersect each-other are included into a group with the center of ((minX + maxX) / 2, maxY) and the radius is just large-enough to display the markers on the periphery without intersecting each-other
while there are semi-circles which intersect each-other, we merge them into a larger half-circle
we sort the markers by a comparator, placing "smaller" markers to the left on the periphery of the circle compared to their "greater" counterparts
we display the markers on the top-half circle, but we display a line from their modified location to their real location
So far, so good.
Problem: These lines are intersecting each-other too often and we need a comparator function with which the number of marker line intersection is minimalized.
Tries:
P1.x <= P2.x => P1 <= P2
arctan((P1.y - C.y) / (R * (P1.x - C.x))) <= arctan((P2.y - C.y) / (R * (P2.x - C.x))) => P1 <= P2
I had high hopes tied to the second try, but had to acknowledge that it is not a good idea, since the translation line and the line between the real location and the center of the circle are not necessarily collinear, in fact, their angle can become fairly big if there are many markers having their real location very close to each-other, whilst the half-circle's surface except this sub-region is fairly barren. So, this leads to intersections as well and it is much more complex than the first try. I believe Javascript's Math.atan is implemented either with Taylor series or Fourier series, which involves derivatives in the first case and integral in the second case. Or, there might be a third approach, which is highly complex as well. I would think about optimizations and stuff like that if this second approach would have significantly reduced the number of intersections, but since the improvement is barely observable if at all, I returned to the first approach.
I am thinking about the following approach:
calculate the locations of the marker slots on the periphery
try to translate all the markers to their closest possible slot
find the conflicting groups and solve all conflicts by finding the optimum, which is the translation-set with the smallest total translation
Is this idea leading to a state where spider line intersection number is minimalized and if not, how could I minimalize the number of such intersections?
This is a difficult problems, studied for a long time now.
It is sometimes called
automatic label placement.
The work cited below is typical of what is available in the literature.
Van Kreveld, Marc, Tycho Strijk, and Alexander Wolff. "Point set labeling with sliding labels." Proceedings of the fourteenth annual symposium on Computational geometry. ACM, 1998. ACM link.

ol3 - calculate real meters in epgs 3857

I use ol3 as a map service.
I have made a linestring with two points with coordinates : [[0,0],[0,1000]] and calculated the distance using the vincenty formula. This resulted in 1000 meter, what is accurate.
But when i made another linestring for example [[4052627,3971934],[4052627,3972934]] vincenty distance was around 850 meters.
I dont know what i forgot here. Any way to correct that? I want to calculate epgs:3857 meters (units) for a given real distance.
You can use ol.sphere.haversineDistance:
var c1 = [4052627, 3971934];
var c2 = [4052627,3972934];
var wgs84Sphere = new ol.Sphere(6378137);
var length = wgs84Sphere.haversineDistance(
ol.proj.transform(c1, 'EPSG:3857', 'EPSG:4326'),
ol.proj.transform(c2, 'EPSG:3857', 'EPSG:4326'));
// 833.12 m
Distances are tricky. The fact that the map units of a coordinate system are in meters (as epsg:3857) doesn't mean that you can measure distances in meters directly. See https://en.wikipedia.org/wiki/List_of_map_projections, and look how many of those have the "equidistant" property.
I suggest you use turf.js to calculate accurate geodetic distances: http://turfjs.org/static/docs/module-turf_distance.html
After alot of search I've found this PDF document:
Web Mercator:
Non-Conformal, Non-Mercator
There is something called Point Scale Factor - according to the way web Mercator is projected - which has tow values, not one like normal Mercator , North/South Scale Factor and East/West Scale Factor.
in my program I've ignored the East/West Scale Factors because it's to much small.
Once I've calculated the scale factor the real distance is almost equal to scale_factor * epgs_3857_distence

using geolocation on google map to group students home by nearest locations to each other?

I have many points on google map that represents students's homes
I also have many buses .
I have to group students according to their locations by grouping the nearest students to each other with the same bus .
so the bus driver will get them to the school.
any ideas about the algorithm about that?
any ideas??
I'm not quite sure if I completly understood your question (especially as you mention from your comment that "the route of the bus is the lat/lng of students's home"). So I assume then that you don't have predefined bus routes but want to find the best possible routes.
Now to clarify we should split the task into sub-tasks, after my assumptions we can say that:
You need an algorithm to assign student-homes to the closest
bus-stop. The bus-stops might be predefined, or not - you need to
clarify if the bus-stops are defined or not.
Since you have multiple buses, each bus needs to be assigned to a
group of bus-stops (lets call it a bus-zone) that they are
responsible for stopping at.
Then you need to solve the TSP (Traveling salesman problem) for each bus-zone ( group of bus-stops).
Possible solutions
1 - What you want to look into is how to group points (meaning in this case - student-homes) defined by (lat,lon). To do that you need to be able to calculate the distance between two points on earth, the Haversine formula is widely used for this. You can find alot of existing implementations if you search for this - here is a simple JS implementation:
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
There is also a function implemented in the Google Maps API v3, you can find more information at this SO question.
So if you have pre-defined bus-stops it would simply be a matter of calculating the distance of each student-home to each bus-stop and then grouping each student to it's closest bus-stop (meaning the lowest calculated distance)
Depending on the amount of data/calculations needed for your project, you might want to consider moving that to a backend solution instead of doing it in the client.
2 - Again this depends on the requirements for your project, if you have predefined bus-zones (polygons) you then simply determine which bus-stops belongs to each bus-zone. This is simply the problem of solving Point in polygon for a sphere. If you need your own implementation search SO, there is alot of existing solutions available. Othwerise Google maps API v3 has a function containsLocation() which you can use:
google.maps.geometry.poly.containsLocation(google.maps.LatLng(latitude, longitude),polygons);
3 - There is a lot of information on solving the TSP. A good solution for getting the fastest route in google maps is OptiMap. The source-code is also available. You should be able to run it for each bus-zone (group of bus-stops).
I don't know if this helps: Genetic Algorithm Traveling Salesman Problem with Javascript
Love the project..... should be fun
I would properly split the map up and make a bus responsible for each area and than have some fail safe procedures (in case 1 region ends up with 99% of the students, in which the case the regions would dynamically change to make it more even). You could also make it so that if one bus's route ends up being more than 20% other busses, than reduce students for that bus.
From there each bus will have a students from which you can calculate a route. It will however be a lot of work to create an algorithm that calculates the best route for multiple busses.
You may wish to consider services which already do this, such as MapBox. This would make your life a lot easier however It would also incur an ongoing cost.
Hope that helps
You can try a hierarchical cluster to group the students. Then you can use an open tsp algorithm to find a route. Optimap from Gebweb is a free solver. To group the students you can look for clusterfck JavaScript. You can also try a heuristic like the saving algorithm.
The brute force approach
If you know where the busses are and you have all the students locations then you should calculate the distance of all students in relation to all bus stops. For each student sort their distances to each bus stop and assign them to the closest bus stop.
Optimization 1
Rule out bus stops for some students. There are some bus stops that don't need distance calculated and you may know this right off the bat. You can say that if some student belongs to some quadrant. Then you would only need to calculate distance for a subset of busses (only 1/4th instead of all). This might result in interesting situations at the borders, but you could account for that.
Optimization 2
Based on the previous optimization you can do this further, up until the point where you are basically guaranteed to not compute any distances. If a user falls within some node then they will end up going to some bus stop. You essentially overlay a grid onto your map if a student falls within some grid node they will go to that bus stop. The previous problem is basically solved as well. It shouldn't matter if the distance to a bus stop is slightly longer since it is relatively trivial. You can however guarantee maximum distance traveled for any student.
Solution
Each bus has a serviceable area (a hit box). For each student within some quadrant/node determine if they fall within a bus' service area. If not bubble them up to a higher level quadrant/node.
yes i used that with more then 500 markers at a time i can send you some links for your help :
first link
second link
Read it and apply with the help of array.

Converting Southing/Easting GPS coordinates to Latitude/Longitude

I am developing a web application using JQuery Framework and am using Geolocation to determine the locations of our hardware stations to display on Google Maps.
In our database the locations of the sites are stored in Southing/Easting format.
I need a way to convert Southing/Easting coordinates to Latitude/Longitude that Google Maps can understand.
Can anyone please tell me the formula or the best way to approach this problem?
I have done searches on Southing/Easting however nothing came up, more like northing/westing etc and even then, not much info..
The programming part I don't really need much assistance just the actual concepts on how the conversion between these two formats can be performed.
Thanks!
There's not enough information in your question to answer it -- but you may be able to figure out the information on your own. Here's how I would go about it.
Southing and easting (and northing and westing) are simply measuring a distance from a certain "zero-point". It makes it much easier if you know what the zero-point is, and what the units are -- but it's not impossible to convert if you don't.
For example, the city of Atlanta was founded exactly 5 miles west of Decatur, Georgia (I'm assuming due west for this example, although it was actually 5 miles west-by-southwest). And Emory University is 1.5 miles north and 1.5 miles west of Decatur (this is an approximation, but for our purpose, let's assume it's exactly right).
Now let's assume a few things:
We have been told that Atlanta is north-0 and west-8800.
We have been told that Emory University is north-2640 and west-2640.
No one remembers that Decatur is the origin of the grid.
No one remembers what unit is represented by the distances (it's yards, by the way).
If we go to Google Maps and drop a latitude marker (may have to be enabled in Google Maps labs) on the zero-mile post in Atlanta, we find it is at 33.75116, -84.38740.
And if we do the same for Emory University, we find that it is at 33.7909, -84.3248.
Then we can do the following math to find the ratio of longitude to the unknown westing units:
abs( -84.38740 - -84.3248 ) = ( abs ( 8000 - 2640 ) ) * x
0.0626 = 5360 * x
x = 0.0626 / 5360
x = 0.000011679
And from there we can find the longitude of our theoretically-unknown zero-point by multiplying Atlanta's westing value by this factor and then adding it (because Atlanta is west of the prime meridian, and thus has negative longitude numbers) to Atlanta's known longitude:
zero-longitude = -84.38740 + ( 8000 * 0.000011679 )
zero-longitude = -84.293968
Applying the same logic to latitude, we could find a factor based on the unknown northing units:
abs( 33.75116 - 33.7909 ) = ( abs ( 2640 - 0 ) ) * y
0.03974 = 2640 * y
y = 0.03974 / 2640
y = 0.000015053
And we find the zero-latitude point the same way (which is obvious in this example because Atlanta was at north-0 -- but it's good to go through the motions anyway):
zero-latitude = 33.75116 + ( 0 * 0.000015053 )
zero-latitude = 33.75116
So our calculated zero-point is 33.75116, -84.293968. Google Maps confirms that this latitude falls where expected in relation to known points.
So then I could find any other of the northing and westing points by using this derived zero-point and the derived ratios. For example, if we were told something was north-3000 west-500, we'd get it's latitude and longitude as follows:
latitude = 33.75116 + ( 3000 * 0.000015053 )
(adding because we're moving north)
latitude = 33.796319
longitude = -84.293968 - ( 500 * 0.000011679 )
(subtracting because we're moving west)
longitude = -84.2998075
Thus, north-3000 west-500 = 33.796319, -84.2998075
If your zero-point and your units of measure haven't been lost to history, you've got a major head start. If they have, you can use this technique to deduce them -- but you may have to fine-tune it with multiple correlations until you have values that feel reliable.

Group array of lat/lng coordinates together on map

I'm trying to compare an array of lat/lng coordinates for a map to see if any "cluster" or group together. I want to remove the ones that are too close together so if there are 4-5 stacking on top of each other on a map, it wil only show 1 until you zoom in a bit more, and then it will recalculate all of them again.
I've tried comparing the array to itself, but it doesn't seem to give consistant results. Has anyone attempted something like this before?
JSON Example:
[
{
Latitude = "44.033843";
Longitude = "-79.48865499999999";
},
{
Latitude = "44.033843";
Longitude = "-79.48865499999999";
}]
Iterate the nodes and for a zoom level only display those that are beyond a set distance from each other. The haversine formula is simple enough to implement: example in JS here.
http://www.movable-type.co.uk/scripts/latlong.html
For the efficiency aspect, you probably don't want to calculate the entire list against the temporary list on every iteration so as a first level declutter a simple rounding works (every degree being ~60 miles from each other) ... start with rounding to the nearest 5 degrees, then 1, then 10ths, 100ths, etc as you zoom in. Ordering these lists and pulling unique array values first - then calculating distances from the resultant list.
There are certainly many other algorithms to do it - but at some point you have to calculate distances.
EDIT: this assumes you're happy to fudge things a little bit, and instead of worrying about the actual distance between points on the globe, you look at the "Manhattan" distance of their lat/long coordinates. It depends on how precise you need to be, and whether you have points near the Earth's poles. But for most practical purposes this assumption should be fine.
Suppose your desired precision is one decimal place. Then I would just iterate through the array, building up a has where the keys are the rounded coordinates and the values are arrays of lat/long pairs which round to the corresponding key.
hash = Hash.new
latLongArray.each { |point|
key = [point.lat.round(1), point.long.round(1)]
hash[key] = Array(hash[key]) + [point.lat, point.long]
}
This way you have them clustered, and you can in fact just put markers at the coordinates given by the keys themselves.

Categories