获取距离某坐标附近一定范围内的点的两种方式

获取距离某坐标附近一定范围内的点的两种方式

场景:数据库中有一些点坐标,需要查找出距离当前位置2千米范围内的坐标

方式1:根据两个经纬度计算距离,Oracle/MySql计算地表两点之间的距离:

Oracle:

  • 创建获取弧度的函数:
CREATE OR REPLACE FUNCTION RAD(d number) RETURN NUMBER
is
PI number :=3.141592625;
begin
return  d* PI/180.0;
end ;
  • 创建根据两个坐标计算距离的函数
CREATE OR REPLACE FUNCTION GetDistance(LngBegin number,
                                        LatBegin number,
                                        LngEnd number,
                                        LatEnd number) RETURN NUMBER is
  earth_padius number := 6378.137;
  radLat1      number := rad(LngBegin);
  radLat2      number := rad(LngEnd);
  a            number := radLat1 - radLat2;
  b            number := rad(LatBegin) - rad(LatEnd);
  s            number := 0;
begin
  s := 2 *
       Asin(Sqrt(power(sin(a / 2), 2) +
                 cos(radLat1) * cos(radLat2) * power(sin(b / 2), 2)));
  s := s * earth_padius;
  s := Round(s * 10000)/10;
  return s;
end;
  • 查询距离
SELECT
   GetDistance(#{lon},#{lat},SHOP_LON,SHOP_LAT) AS Mdistance 
FROM Shop

MySql:
查询距离sql:

SELECT
	ROUND( 6378.138 * 2 * ASIN( SQRT( POW( SIN(( #{lat} * PI() / 180 - SHOP_LAT * PI() / 180) / 2 ),
         2 ) + COS(#{lat} * PI() / 180) * COS(SHOP_LAT * PI() / 180) * POW( SIN( ( #{lon} * PI() / 180 - SHOP_LON * PI() / 180 ) / 2 ),
         2 ) ) ) * 1000 ) AS Mdistance
FROM Shop

当然,也可将计算方法封装为函数


拿到距离后根据条件取值,因为是sql查询,若数据量大时,效率是一个问题

方式2:根据经纬度和距离计算出矩形范围,取范围内的值:

  • 提供工具类如下:
public class GeoUtil
{
    /**
     * 地球半径:6378.137KM
     */
    private static double EARTH_RADIUS = 6378.137;
    
    /**
     * 根据经纬度和距离返回一个矩形范围
     * @param lng 经度
     * @param lat 纬度
     * @param distance 距离(单位为米)
     * @return [lng1,lat1, lng2,lat2] 矩形的左下角(lng1,lat1)和右上角(lng2,lat2)
     */
    public static double[] getRectangle(double lng, double lat, long distance)
    {
        float delta = 111000;
        if (lng != 0 && lat != 0)
        {
            double lng1 = lng - distance / Math.abs(Math.cos(Math.toRadians(lat)) * delta);
            double lng2 = lng + distance / Math.abs(Math.cos(Math.toRadians(lat)) * delta);
            double lat1 = lat - (distance / delta);
            double lat2 = lat + (distance / delta);
            return new double[] {lng1, lat1, lng2, lat2};
        }
        else
        {
            double lng1 = lng - distance / delta;
            double lng2 = lng + distance / delta;
            double lat1 = lat - (distance / delta);
            double lat2 = lat + (distance / delta);
            return new double[] {lng1, lat1, lng2, lat2};
        }
    }
    
    /**
     * 得到两点间的距离 米
     * @param lat1
     * @param lng1
     * @param lat2
     * @param lng2
     * @return
     */
    public static double getDistanceOfMeter(double lat1, double lng1, double lat2, double lng2)
    {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10;
        return s;
    }
    
    private static double rad(double d)
    {
        return d * Math.PI / 180.0;
    }
}

这种方式得到的是一个范围,查询时无需计算根据大小即可取出范围内的点,但是就没有具体的距离值了。在数据量大时效率较高。同时比较符合app的某些业务场景,例如每次展示手机屏幕范围内的点(手机是方的)

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一种高效的算法是扫描线算法。具体步骤如下: 1. 找出三角形的最小包围矩形,确定扫描线的范围。 2. 从最小包围矩形的上边界开始,向下沿着扫描线扫描。 3. 对于每条扫描线,计算出与三角形的交,并将这些交按照x坐标排序。 4. 根据相邻两个交之间的距离和扫描线间距,计算出每个像素的y坐标,并将其加入到像素集合中。 下面是C++代码实现: ```c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Point { int x; int y; }; void drawLine(Point p1, Point p2, vector<Point>& points) { int x1 = p1.x; int y1 = p1.y; int x2 = p2.x; int y2 = p2.y; int dx = abs(x2 - x1); int dy = abs(y2 - y1); int sx = x1 < x2 ? 1 : -1; int sy = y1 < y2 ? 1 : -1; int err = dx - dy; while (true) { points.push_back({x1, y1}); if (x1 == x2 && y1 == y2) break; int e2 = 2 * err; if (e2 > -dy) { err -= dy; x1 += sx; } if (e2 < dx) { err += dx; y1 += sy; } } } void drawTriangle(Point p1, Point p2, Point p3, vector<Point>& points) { drawLine(p1, p2, points); drawLine(p2, p3, points); drawLine(p3, p1, points); } void getBoundingBox(Point p1, Point p2, Point p3, Point& minP, Point& maxP) { minP = {min({p1.x, p2.x, p3.x}), min({p1.y, p2.y, p3.y})}; maxP = {max({p1.x, p2.x, p3.x}), max({p1.y, p2.y, p3.y})}; } void scanTriangle(Point p1, Point p2, Point p3, vector<Point>& points) { Point minP, maxP; getBoundingBox(p1, p2, p3, minP, maxP); for (int y = minP.y; y <= maxP.y; y++) { vector<double> intersections; if (y >= p1.y && y < p2.y) { intersections.push_back(p1.x + (double)(p2.x - p1.x) * (double)(y - p1.y) / (double)(p2.y - p1.y)); } if (y >= p1.y && y < p3.y) { intersections.push_back(p1.x + (double)(p3.x - p1.x) * (double)(y - p1.y) / (double)(p3.y - p1.y)); } if (y >= p2.y && y < p3.y) { intersections.push_back(p2.x + (double)(p3.x - p2.x) * (double)(y - p2.y) / (double)(p3.y - p2.y)); } sort(intersections.begin(), intersections.end()); for (int i = 0; i < (int)intersections.size() - 1; i++) { int x1 = (int)intersections[i]; int x2 = (int)intersections[i + 1]; for (int x = x1; x <= x2; x++) { points.push_back({x, y}); } } } } int main() { Point p1 = {0, 0}; Point p2 = {5, 10}; Point p3 = {10, 5}; vector<Point> points; scanTriangle(p1, p2, p3, points); for (auto p : points) { cout << "(" << p.x << ", " << p.y << ")" << endl; } return 0; } ``` 在这个例子中,我们定义了一个getBoundingBox函数来获取三角形的最小包围矩形,定义了一个scanTriangle函数来实现扫描线算法,将计算出来的像素加入到points向量中。在scanTriangle函数中,对于每条扫描线,我们计算出与三角形的交,并将这些交按照x坐标排序,然后根据相邻两个交之间的距离和扫描线间距,计算出每个像素的y坐标,并将其加入到像素集合中。最后,在main函数中,我们使用scanTriangle函数来画出三角形,并输出所有的像素坐标

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值