• 与地图经纬度计算有关的一些积累


    网上有关这些的东西很多,但是试过之后有的计算偏差大一点,有的小一点。下面这几个相关计算我自己试过之后相对来说计算的误差小一点。

    1、已知两点经纬度计算方位角

     /**
         * 以真北为0度起点,由东向南向西顺时针旋转360度,主要是用于控制象限。
         * 根据2点经纬度,计算方位角
         * 给定2点,获得经纬度
         * 起点经纬度,都是以度为单位
         * 终点经纬度,都是以度为单位
         */
        public static double computeAzimuth(LatLng la1, LatLng la2) {
            double lat1 = la1.getLatitude(), lon1 = la1.getLongitude(), lat2 = la2.getLatitude(),
                    lon2 = la2.getLongitude();
            double result = 0.0;
    
            int ilat1 = (int) (0.50 + lat1 * 360000.0);
            int ilat2 = (int) (0.50 + lat2 * 360000.0);
            int ilon1 = (int) (0.50 + lon1 * 360000.0);
            int ilon2 = (int) (0.50 + lon2 * 360000.0);
    
            lat1 = Math.toRadians(lat1);
            lon1 = Math.toRadians(lon1);
            lat2 = Math.toRadians(lat2);
            lon2 = Math.toRadians(lon2);
    
            if ((ilat1 == ilat2) && (ilon1 == ilon2)) {
                return result;
            } else if (ilon1 == ilon2) {
                if (ilat1 > ilat2)
                    result = 180.0;
            } else {
                double c = Math
                        .acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2)
                                * Math.cos(lat1) * Math.cos((lon2 - lon1)));
                double A = Math.asin(Math.cos(lat2) * Math.sin((lon2 - lon1))
                        / Math.sin(c));
                result = Math.toDegrees(A);
                if ((ilat2 > ilat1) && (ilon2 > ilon1)) {
                } else if ((ilat2 < ilat1) && (ilon2 < ilon1)) {
                    result = 180.0 - result;
                } else if ((ilat2 < ilat1) && (ilon2 > ilon1)) {
                    result = 180.0 - result;
                } else if ((ilat2 > ilat1) && (ilon2 < ilon1)) {
                    result += 360.0;
                }
            }
            return result;
        }

    2、已知一点经纬度、方位角和距离,求另一点经纬度

    /*
         * 大地坐标系资料WGS-84 长半径a=6378137 短半径b=6356752.3142 扁率f=1/298.2572236
         */
        /**
         * 长半径a=6378137
         */
        private static double a = 6378137;
        /**
         * 短半径b=6356752.3142
         */
        private static double b = 6356752.3142;
        /**
         * 扁率f=1/298.2572236
         */
        private static double f = 1 / 298.2572236;
    
        /**
         * 计算另一点经纬度
         *
         * @param, lon
         * 经度
         * @param, lat
         * 维度
         * @param, lonlat
         * 已知点经纬度
         * @param, brng
         * 方位角 度
         * @param, dist
         * 距离(米)
         * 已知一点经纬度,方位角,距离,求另一点经纬度
         */
        public static LatLng getLatlngByFixedPointAziDistance(double brng, double dist, LatLng fixedPoint) {
            double lon = fixedPoint.getLongitude();
            double lat = fixedPoint.getLatitude();
    
            double alpha1 = rad(brng);
            double sinAlpha1 = Math.sin(alpha1);
            double cosAlpha1 = Math.cos(alpha1);
    
            double tanU1 = (1 - f) * Math.tan(rad(lat));
            double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
            double sinU1 = tanU1 * cosU1;
            double sigma1 = Math.atan2(tanU1, cosAlpha1);
            double sinAlpha = cosU1 * sinAlpha1;
            double cosSqAlpha = 1 - sinAlpha * sinAlpha;
            double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
            double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
            double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
    
            double cos2SigmaM = 0;
            double sinSigma = 0;
            double cosSigma = 0;
            double sigma = dist / (b * A), sigmaP = 2 * Math.PI;
            while (Math.abs(sigma - sigmaP) > 1e-12) {
                cos2SigmaM = Math.cos(2 * sigma1 + sigma);
                sinSigma = Math.sin(sigma);
                cosSigma = Math.cos(sigma);
                double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)
                        - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
                sigmaP = sigma;
                sigma = dist / (b * A) + deltaSigma;
            }
    
            double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
            double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
                    (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
            double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
            double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
            double L = lambda - (1 - C) * f * sinAlpha
                    * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
    
            double revAz = Math.atan2(sinAlpha, -tmp); // final bearing
    
            //System.out.println(revAz);
            //Log.e("方位角",String.valueOf(revAz));
            //Log.e("经纬度",String.valueOf(deg(lat2))+"经度"+String.valueOf(lon+deg(L)));
            //System.out.println(+","+);
    
            return new LatLng(deg(lat2), lon + deg(L));
        }

    3、已知两个坐标和其对应的方位角,求另一点坐标

     public static LatLng getLatlngByTwoFixedPointAziIntersect(double aziOne, double aziTwo, LatLng fixedPointOne, LatLng fixedPointTwo) {
            double azi;
            LatLng latLng;
            if (fixedPointOne.getLongitude() > fixedPointTwo.getLongitude()) {
                azi = aziOne;
                latLng = fixedPointOne;
                aziOne = aziTwo;
                fixedPointOne = fixedPointTwo;
                aziTwo = azi;
                fixedPointTwo = latLng;
            }
            Double aziAB = computeAzimuth(fixedPointOne, fixedPointTwo);
            Double aziBA = 180 + aziAB;
    
            if (0 <= aziOne && aziOne < 180) {
                if (aziOne <= aziAB) {
                    if (aziOne <= aziTwo && aziTwo < aziBA) {
                        Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                        return new LatLng();
                    }
                }
                if (aziOne > aziAB) {
                    if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo <= 360)) {
                        Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                        return new LatLng();
                    }
                }
            }
    
            if (180 <= aziOne && aziOne < 270) {
                if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo < 360)) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
            if (270 <= aziOne && aziOne < 360) {
                if ((0 <= aziTwo && aziTwo < aziBA) || (aziOne < aziTwo && aziTwo < 360)) {
                    Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                    return new LatLng();
                }
            }
            double k1 = Math.tan(rad(90 - aziOne));
            double k2 = Math.tan(rad(90 - aziTwo));
            double y1 = fixedPointOne.getLatitude();
            double x1 = fixedPointOne.getLongitude();
            double y2 = fixedPointTwo.getLatitude();
            double x2 = fixedPointTwo.getLongitude();
            double lon = (y2 - y1 + k1 * x1 - k2 * x2) / (k1 - k2);
            double lat = (k1 * y2 - k2 * y1 + k1 * k2 * x1 - k1 * k2 * x2) / (k1 - k2);
    /*        if (0 <= aziOne && aziOne < 180) {
                if (aziOne < aziAB) {
                    if (lat < y1) {
                        Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                        return new LatLng();
                    }
                }
                if (aziOne > aziAB) {
                    if (lat > y2) {
                        Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                        return new LatLng();
                    }
                }
            }*/
            if (lat > 90 || lat < -90) {
                Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
                return new LatLng();
            }
            return new LatLng(lat, lon);
        }

    度与弧度的转换关系

     /**
         * 度换成弧度
         *
         * @param d 度
         * @return 弧度
         */
        private static double rad(double d) {
            return d * Math.PI / 180.0;
        }
    
        /**
         * 弧度换成度
         *
         * @param x 弧度
         * @return*/
        private static double deg(double x) {
            return x * 180 / Math.PI;
        }

     4、拓扑关系的相关运算

    public class Topology {
        
        /**
         * 判断点是否在面内
         *
         * @param polygon 组成多边形的坐标串 多变形节点不能少于3
         * @param point   测试的点
         * @return 是否在多边形内
         * @throws IllegalArgumentException
         */
        public static boolean isPointInPolygon(List<LatLng> polygon, LatLng point) throws IllegalArgumentException {
            if (polygon.size() < 3) {
                throw new IllegalArgumentException("polygon 节点少于3");
            }
            LatLngBounds.Builder builder = new LatLngBounds.Builder();
            builder.includes(polygon);
            LatLngBounds bounds = builder.build();
            if (!bounds.contains(point)) return false;
            
            LatLng far = new LatLng(point.getLatitude(), -180.0); //向正西方向做一条射线
            LineSegment ray = new LineSegment(point, far);
            int intersectionCount = 0;
            int count = polygon.size();
            for (int i = 0; i < count; i++) {
                LatLng latLng1 = polygon.get(i);
                LatLng latLng2 = polygon.get((i + 1) % count);
                LineSegment lineSeg = new LineSegment(latLng1, latLng2);
                if (isPointOnLineSegment(point, lineSeg)) return true;
                if (isSameDouble(latLng2.getLatitude(), latLng1.getLatitude())) continue;
                
                if (isSameDouble(latLng1.getLatitude(), point.getLatitude()) && (latLng1.getLatitude() > latLng2.getLatitude())) {
                    intersectionCount++;
                } else if (isSameDouble(latLng2.getLatitude(), point.getLatitude()) && (latLng2.getLatitude() > latLng1.getLatitude())) {
                    intersectionCount++;
                } else {
                    if (isLineSegmentIntersect(lineSeg, ray)) {
                        intersectionCount++;
                    }
                }
                
            }
            return (intersectionCount & 1) == 1;
        }
        
        public static class LineSegment {
            public LatLng start;
            public LatLng end;
            private LatLngBounds bounds;
            
            public LineSegment(LatLng start, LatLng end) {
                this.start = start;
                this.end = end;
            }
            
            
            public LatLngBounds getBounds() {
                if (bounds == null) {
                    LatLngBounds.Builder builder = new LatLngBounds.Builder();
                    builder.include(start).include(end);
                    bounds = builder.build();
                }
                return bounds;
            }
        }
        
        /**
         * 线段是否相交
         *
         * @param l1
         * @param l2
         * @return
         */
        public static boolean isLineSegmentIntersect(LineSegment l1, LineSegment l2) {
            if (isLineSegmentExclusive(l1, l2)) return false; //矩形不相交
            double slat1 = l1.start.getLatitude();
            double slon1 = l1.start.getLongitude();
            double elat1 = l1.end.getLatitude();
            double elon1 = l1.end.getLongitude();
            double slat2 = l2.start.getLatitude();
            double slon2 = l2.start.getLongitude();
            double elat2 = l2.end.getLatitude();
            double elon2 = l2.end.getLongitude();
            //跨立试验
            double p1xq = crossProduct(slon1 - slon2, slat1 - slat2, elon2 - slon2, elat2 - slat2);
            double p2xq = crossProduct(elon1 - slon2, elat1 - slat2, elon2 - slon2, elat2 - slat2);
            
            double q1xp = crossProduct(slon2 - slon1, slat2 - slat1, elon1 - slon1, elat1 - slat1);
            double q2xp = crossProduct(elon2 - slon1, elat2 - slat1, elon1 - slon1, elat1 - slat1);
            
            return (p1xq * p2xq <= 0) && (q1xp * q2xp <= 0);
        }
        
        /**
         * 线段 包围矩形是否 不相交
         *
         * @param l1
         * @param l2
         * @return
         */
        public static boolean isLineSegmentExclusive(LineSegment l1, LineSegment l2) {
            double W1 = Math.min(l1.start.getLongitude(), l1.end.getLongitude());
            double E1 = Math.max(l1.start.getLongitude(), l1.end.getLongitude());
            double N1 = Math.max(l1.start.getLatitude(), l1.end.getLatitude());
            double S1 = Math.min(l1.start.getLatitude(), l1.end.getLatitude());
            double W2 = Math.min(l2.start.getLongitude(), l2.end.getLongitude());
            double E2 = Math.max(l2.start.getLongitude(), l2.end.getLongitude());
            double N2 = Math.max(l2.start.getLatitude(), l2.end.getLatitude());
            double S2 = Math.min(l2.start.getLatitude(), l2.end.getLatitude());
            
            if (N1 < S2) return true;
            if (S1 > N2) return true;
            if (E1 < W2) return true;
            if (W1 > E2) return true;
            return false;
        }
        
        /**
         * 点是否在线段上
         *
         * @param point
         * @param line
         * @return
         */
        public static boolean isPointOnLineSegment(LatLng point, LineSegment line) {
            LatLngBounds.Builder builder = new LatLngBounds.Builder();
            LatLngBounds bounds = builder.include(line.start).include(line.end).build();
            if (!bounds.contains(point)) {
                return false;
            }
            LatLng start = line.start;
            LatLng end = line.end;
            double cp = crossProduct(end.getLongitude() - start.getLongitude(), end.getLatitude() - start.getLongitude(),
                    point.getLongitude() - start.getLongitude(), point.getLatitude() - start.getLatitude());
            return Math.abs(cp) < 0.000000001;
        }
        
        
        /**
         * 点到线段的距离
         *
         * @param point
         * @param lineSegment
         * @return
         */
        public static double point2LineSegment(LatLng point, LineSegment lineSegment) {
            double dis1 = point2Point(point, lineSegment.start);
            double dis2 = point2Point(point, lineSegment.end);
            double dis3 = point2Line(point, lineSegment);
            return Math.min(dis1, Math.min(dis2, dis3));
        }
        
        
        /**
         * 点到直线的距离
         *
         * @param point
         * @param line
         * @return
         */
        public static double point2Line(LatLng point, LineSegment line) {
            //先求过点 point 与 line垂直的直线与line 的交点
            double x1 = line.start.getLongitude();
            double x2 = line.end.getLongitude();
            double y1 = line.start.getLatitude();
            double y2 = line.end.getLatitude();
            double xp = point.getLongitude();
            double yp = point.getLatitude();
            double x, y;
            if (y1 == y2) {
                y = y1;
                x = xp;
                return point.distanceTo(new LatLng(y, x));
            } else if (x1 == x2) {
                x = x1;
                y = yp;
                return point.distanceTo(new LatLng(y, x));
            } else {
                double k = (x2 - x1) / (y1 - y2);
                double b = yp - (k * xp);
                double k1 = (y2 - y1) / (x2 - x1);
                double b1 = y1 - (k1 * x1);
                x = (b1 - b) / (k - k1);
                y = k * x + b;
                return point.distanceTo(new LatLng(y, x));
            }
            
        }
        
        
        /**
         * 线段到面的距离
         *
         * @param lineSegment
         * @param polygon
         * @return
         */
        public static double line2Polygon(LineSegment lineSegment, List<LatLng> polygon) {
            //先判断线是否与面相交
            double minDistance = Double.MAX_VALUE;
            int count = polygon.size();
            for (int i = 0; i < count; i++) {
                LatLng latLng1 = polygon.get(i);
                double dis = point2Line(latLng1, lineSegment);
                minDistance = Math.min(dis, minDistance);
                LatLng latLng2 = polygon.get((i + 1) % count);
                LineSegment lineSeg = new LineSegment(latLng1, latLng2);
                //如果相交,返回0
                if (isLineSegmentIntersect(lineSeg, lineSegment)) {
                    return 0;
                }
            }
            return minDistance;
        }
        
        /**
         * 取模运算
         *
         * @param lineSegment
         * @return
         */
        private static double mod(LineSegment lineSegment) {
            double x = lineSegment.end.getLongitude() - lineSegment.start.getLongitude();
            double y = lineSegment.end.getLatitude() - lineSegment.start.getLatitude();
            return Math.sqrt(x * x + y * y);
        }
        
        /**
         * 点到点的距离
         *
         * @param latLng1
         * @param latLng2
         * @return
         */
        public static double point2Point(LatLng latLng1, LatLng latLng2) {
            return latLng1.distanceTo(latLng2);
        }
        
        
        /**
         * 点和线段是否接近
         *
         * @param buffer    容差
         * @param point     被判断的点
         * @param lienStart 线段起点
         * @param lineEnd   线段终点
         * @return
         */
        public static boolean isNearBy(LatLng point, LatLng lienStart, LatLng lineEnd, double buffer) {
            //先使用经纬度筛选一遍
            LineSegment lineSegment = new LineSegment(lienStart, lineEnd);
            double dis = buffer / 111000; //换算为度
            LatLngBounds bounds = lineSegment.getBounds();
            if (bounds.getLatNorth() + dis < point.getLatitude()) return false;
            if (bounds.getLatSouth() - dis > point.getLatitude()) return false;
            if (bounds.getLonEast() + dis < point.getLongitude()) return false;
            if (bounds.getLonWest() - dis > point.getLongitude()) return false;
            
            double distance = Topology.point2LineSegment(point, lineSegment);
            return distance <= buffer;
        }
        
        /**
         * 求两条直线的交点
         * 没有考虑重合的情况,重合的情况,这里返回不相交
         *
         * @param start1
         * @param end1
         * @param start2
         * @param end2
         * @return
         */
        public static LatLng lineInterSection(LatLng start1, LatLng end1, LatLng start2, LatLng end2) {
            //先判断是否相交
            double deltaX1 = end1.getLongitude() - start1.getLongitude();
            double deltaX2 = end2.getLongitude() - start2.getLongitude();
            double deltaY1 = end1.getLatitude() - start1.getLatitude();
            double deltaY2 = end2.getLatitude() - start2.getLatitude();
            if (deltaX1 == 0.0 && deltaX2 == 0.0) return null;
            
            double k1 = deltaY1 / deltaX1;
            double k2 = deltaY2 / deltaX2;
            
            double b1 = start1.getLatitude() - k1 * start1.getLongitude();
            double b2 = start2.getLatitude() - k2 * start2.getLongitude();
            
            double x = (b2 - b1) / (k1 - k2);
            double y = k1 * x + b1;
            
            return new LatLng(y, x);
            
        }
        
        /**
         * 计算总路程
         *
         * @param latLngList
         * @return 总里程(公里)
         */
        public static double computeDistance(final List<LatLng> latLngList) {
            if (latLngList.size() < 1) return 0.0;
            double distance = 0.0;
            int count = latLngList.size();
            for (int i = 1; i < count; i++) {
                distance += latLngList.get(i - 1).distanceTo(latLngList.get(i));
            }
            
            return distance / 1000;
        }
        
        /**
         * 叉积
         * 矢量积
         *
         * @param x1
         * @param y1
         * @param x2
         * @param y2
         * @return
         */
        public static double crossProduct(double x1, double y1, double x2, double y2) {
            return x1 * y2 - x2 * y1;
        }
        
        /**
         *  盘点点在线的左边还是右边
         * @param x1
         * @param y1
         * @param x2
         * @param y2
         * @param x3
         * @param y3
         * @return 左边 >0 右边 < 0
         */
        public static int leftRight(double x1,double y1,double x2,double y2,double x3,double y3){
            double f = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
            if(f > 0) return 1;
            if(f < 0) return -1;
            return 0;
        }
        
        /**
         * 点积 ,数量积
         *
         * @param x1
         * @param y1
         * @param x2
         * @param y2
         * @return
         */
        public static double dopProduct(double x1, double y1, double x2, double y2) {
            return x1 * x2 + y1 * y2;
        }
        
        public static boolean isSameDouble(double var1, double var2) {
            return Math.abs(var2 - var1) < 0.000000000001;
        }
    }
  • 相关阅读:
    iPhone开发教程之retain/copy/assign/setter/getter
    关于block使用的5点注意事项
    Block的引用循环问题 (ARC & non-ARC)
    浅谈iOS中MVVM的架构设计与团队协作
    JS学习笔记(不断更新)
    神经网络介绍
    JAVA WEB WITH IDEA
    百度地图标注多个点
    脑筋急转弯——Google 面试
    决策树分类器
  • 原文地址:https://www.cnblogs.com/yangms/p/9946399.html
Copyright © 2020-2023  润新知