Preface
With the widespread development of mobile Internet today, APP development has become the first choice for many companies to enter the mobile Internet. The author has developed many APPs and found that many apps have such a function, that is, to obtain nearby people. How to obtain nearby people? In fact, it is very simple. It is to always record the user's coordinates (latitude and longitude) information into the database, and then search for all users in the database and the current coordinate position within a certain range based on the current user's coordinates.
In fact, for the distance between two subjects whose geographical location does not change, it is best to directly static the result. That is, write it directly in the configuration.
For example, find a subway station near your home.
In this case, generally speaking, the subject of "home" will not "run around" easily. It doesn't make sense to calculate the distance once every query. It is best to persist the distance and query it directly.
Another case:
Get the subway station near the location of the APP user
In this case, the user's geographical location changes. So the actual distance must be calculated in real time every time.
Implementation ideas
Treat the earth as a standard sphere and use the spherical distance formula to calculate the arc length of the large circle between two points on the spherical surface.
Spherical distance
public static double getDistance2(double long1, double lat1, double long2, double lat2) { lat1 = rad(lat1); lat2 = rad(lat2); double a = lat1 - lat2; double b = rad(long1 - long2); double sa2 = Math.sin(a / 2.0); double sb2 = Math.sin(b / 2.0); return 2 * EARTH_MEAN_RADIUS_KM * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));}Just know the latitude and longitude between two points.
Of course, this calculation has to be placed in the database and then sorted back according to distance. Just bring the above formula into SQL.
Examples of nearby subway stations
Example table for building a subway station
CREATE TABLE station( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NULL COMMENT 'MRT station name', lng DOUBLE NULL COMMENT 'Longitude', lat DOUBLE NULL COMMENT 'Dimension');
SQL example
SET @targetLat = 31.175702;SET @targetLng = 121.519095;SELECT s.id , s.name , s.lng , s.lat , ROUND( 6378.138 * 2 * ASIN( SQRT( POW( SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ), 2 ) + COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 ) * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 ) ) ) * 1000 ) AS distanceFROM station sORDER BY distance ASC , s.idLIMIT 20;
Among them, targetLat and targetLng are the geographical locations of the users.
This can indeed achieve the goal. However, this is to calculate the distance between all data and the user first and then sort it.
When the number of subway stations is too large, this operation will be less elegant. Not only is it not elegant enough, but it is also very efficient.
optimization
In fact, a lot of data can be filtered out before calculating the distance.
There is no need to calculate the distance between the US subway station when calculating the distance between Shanghai subway stations.
This can be filtered out some unwanted data first in most applications.
For example, when the data distinguishes cities, you can change SQL to the following:
SET @targetLat = 31.175702;SET @targetLng = 121.519095;SET @cityId=605;SELECT s.id , s.name , s.lng , s.lat , ROUND( 6378.138 * 2 * ASIN( SQRT( POW( SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ) , 2 ) + COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 ) * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 ) ) ) * 1000 ) AS distanceFROM station swhere city_id=@cityId # First filter part of the data to be calculated ORDER BY distance ASC , s.idLIMIT 20;
The above improvement is to remove most of the data to be calculated before calculating. When looking for a Changsha subway station, there is no need to search in Shanghai first.
Of course, this situation is a bit special because you can know the city where the user is located in advance.
Another improvement is:
With the user's location as the center, draw a circle with a radius R, and then reversely eject the latitude and longitude range of the outer quadrilateral of the circle. Before calculating the distance, filter out data outside the longitude and longitude of the outer quadrilateral.
Specify an ideal radius R and filter out data that cannot meet the criteria first.
Reverse push-out external quadrilateral range
/** * Get the latitude and longitude of the four vertices of the point at the specified latitude and longitude{@code radius} KM's external quadrilateral (strictly speaking, it should be an external cube)* * @param lng longitude* @param lat latitude* @param radius, unit: KM * @return <lng1,lng2,lat1,lat2> */public static Tuple4<Double> calcBoxByDistFromPt(double lng, double lat, double radius) { SpatialContext context = SpatialContext.GEO; Rectangle rectangle = context.getDistCalc()// .calcBoxByDistFromPt(// context.makePoint(lng, lat), // radius * com.spatial4j.core.distance.DistanceUtils.KM_TO_DEG, context, null// ); return new Tuple4<>(rectangle.getMinX(), rectangle.getMaxX(), rectangle.getMinY(), rectangle.getMaxY());}The maven coordinates used here are as follows:
<dependency> <groupId>com.spatial4j</groupId> <artifactId>spatial4j</artifactId> <version>0.5</version></dependency>
At this time, SQL can be changed to this:
SET @targetLat = 31.175702;SET @targetLng = 121.519095;SELECT s.id , s.name , s.lng , s.lat , ROUND( 6378.138 * 2 * ASIN( SQRT( POW( SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ), 2 ) + COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 ) * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 ) ) ) * 1000 ) AS distanceFROM station sWHERE ( s.lng BETWEEN ${lng1} AND ${lng2} ) AND ( s.lat BETWEEN ${lat1} AND ${lat2} )ORDER BY distance ASC , s.idLIMIT 20;The above lng1, lng2, lat1, lat2 is the range of the external quadrilateral.
Cited information: http://blog.csdn.net/a364572/article/details/50483568
Sample source code
service: https://github.com/hylexus/bl...
Initialize data: https://github.com/hylexus/bl...
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.