gis坐标计算

package cn.service.hspd.utils;

import com.alibaba.fastjson2.JSON;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GisUtil {

    // 两点距离 x,lon 经度  y,lat 纬度

    private static final double EARTH_RADIUS = 6371000;


    /**
     * 计算两点jul
     *
     * @param p1
     * @param p2
     * @return
     */
    public static double jl(Point2D p1, Point2D p2) {
        double lat1Rad = Math.toRadians(p1.getY());
        double lon1Rad = Math.toRadians(p1.getX());
        double lat2Rad = Math.toRadians(p2.getY());
        double lon2Rad = Math.toRadians(p2.getX());
        double deltaLat = lat2Rad - lat1Rad;
        double deltaLon = lon2Rad - lon1Rad;
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
                + Math.cos(lat1Rad) * Math.cos(lat2Rad)
                * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return EARTH_RADIUS * c;
    }

    /**
     * 判断两条线是否相交返回相交点
     *
     * @param p1
     * @param p2
     * @param p3
     * @param p4
     * @return
     */
    public static Point2D.Double xj(Point2D p1, Point2D p2, Point2D p3, Point2D p4) {
        double x1 = p1.getX(), y1 = p1.getY();
        double x2 = p2.getX(), y2 = p2.getY();
        double x3 = p3.getX(), y3 = p3.getY();
        double x4 = p4.getX(), y4 = p4.getY();
        double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
        if (d == 0) return null;
        double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
        if (x1 < Math.min(x1, x2) || xi > Math.max(x1, x2) || xi < Math.min(x3, x4) || xi > Math.max(x3, x4))
            return null;
        if (yi < Math.min(y1, y2) || yi > Math.max(y1, y2) || yi < Math.min(y3, y4) || yi > Math.max(y3, y4))
            return null;
        return new Point2D.Double(xi, yi);
    }


    /**
     * 中心点
     *
     * @param list
     * @return
     */
    public static Point2D.Double zxd(List<Point2D.Double> list) {
        if (list.size() <= 1) return null;
        Point2D top = list.get(0);
        Point2D bot = list.get(1);
        if (list.size() == 2) {
            return new Point2D.Double((top.getX() + bot.getX()) / 2.0, (top.getY() + bot.getY()) / 2.0);
        }
        double maxJl = -1;
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (Math.abs(i - j) == 1 || (i == 0 && j == list.size() - 1)) continue;
                double jl = jl(list.get(i), list.get(j));
                if (jl > maxJl) {
                    maxJl = jl;
                    top = list.get(i);
                    bot = list.get(j);
                }
            }
        }
        return new Point2D.Double((top.getX() + bot.getX()) / 2.0, (top.getY() + bot.getY()) / 2.0);
    }


    /**
     * 最大直径
     *
     * @param list
     * @return
     */
    public static double zdzj(List<Point2D.Double> list) {
        if (list.size() <= 1) return 0;
        Point2D top = list.get(0);
        Point2D bot = list.get(1);
        if (list.size() == 2) {
            return jl(top, bot);
        }
        double maxJl = -1;
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (Math.abs(i - j) == 1 || (i == 0 && j == list.size() - 1)) continue;
                double jl = jl(list.get(i), list.get(j));
                if (jl > maxJl) {
                    maxJl = jl;
                    top = list.get(i);
                    bot = list.get(j);
                }
            }
        }
        return jl(top, bot);
    }


    /**
     * 最x小直径
     *
     * @param list
     * @return
     */
    public static double zxzj(List<Point2D.Double> list) {
        if (list.size() <= 1) return 0;
        Point2D top = list.get(0);
        Point2D bot = list.get(1);
        if (list.size() == 2) {
            return jl(top, bot);
        }
        double min = jl(list.get(0), list.get(3));
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (Math.abs(i - j) == 1 || (i == 0 && j == list.size() - 1)) continue;
                double jl = jl(list.get(i), list.get(j));
                if (jl <= min) {
                    min = jl;
                    top = list.get(i);
                    bot = list.get(j);
                }
            }
        }
        return jl(top, bot);
    }

    public static double zc(List<Point2D.Double> list) {
        double zc = 0;
        for (int i = 1; i < list.size(); i++) {
            zc += jl(list.get(i - 1), list.get(i));
        }
        return zc;
    }

    /**
     * 计算体积 圆柱 锥形
     *
     * @param bj
     * @param height
     * @param lx     1 圆柱 2 圆锥
     * @return
     */
    public static double tj(double bj, double height, int lx) {
        if (lx == 1) {
            return Math.PI * Math.pow(bj, 2) * height;
        }
        return (1.0 / 3) * Math.PI * Math.pow(bj, 2) * height;
    }

    public static double format(Double d, int i) {
        if (d == null) return 0.0;
        String format = String.format("%." + i + "f", d);
        return Double.parseDouble(format);
    }


    /**
     * 像素转经纬坐标
     *
     * @param zs     图片左上位置
     * @param yx     图片右下位置
     * @param width  图片宽
     * @param height 图片高
     * @param zb     像素信息
     * @return
     */
    public static Point2D.Double xsTojw(Point2D zs, Point2D yx, double width, double height, Point2D zb) {
        double lat = zs.getY() - (zb.getY() * (zs.getY() - yx.getY()) / height);
        double lon = zs.getX() - (zb.getX() * (yx.getX() - zs.getX()) / width);
        return new Point2D.Double(lon, lat);
    }

    // 长半轴
    private static final double WGS84_A = 6378137.0;
    // 短半轴
    private static final double WGS84_B = 6356752.314245;
    // 扁率
    private static final double WGS84_F = 1.0 / 298.257223563;
    // 第一偏心率平方
    private static final double WGS84_E2 = 6.69437999014e-3;
    // 收敛经度
    private static final double WGS84_EPSILON = 1.0e-12;

    /**
     * 三维直角坐标转经纬度
     *
     * @param x
     * @param y
     * @param z
     * @return
     */
    public static Point2D.Double swTojw(double x, double y, double z) {
        double longitude = Math.atan2(y, x);
        double p = Math.sqrt(x * x + y * y);
        double latitude = Math.atan2(z, p * (1 - WGS84_E2));
        double height = 0.0;
        int maxIterations = 10;
        for (int i = 0; i < maxIterations; i++) {
            double sinLat = Math.sin(latitude);
            double n = WGS84_A / Math.sqrt(1 - WGS84_E2 * sinLat * sinLat);

            double newHeight = p / Math.cos(latitude) - n;
            double newLatitude = Math.atan2(z, p * (1 - WGS84_E2 * n / (n + newHeight)));
            if (Math.abs(newLatitude - latitude) < WGS84_EPSILON && Math.abs(newHeight - height) < WGS84_EPSILON) {
                break;
            }
            latitude = newLatitude;
            height = newHeight;
        }
        double lon = Math.toDegrees(longitude);
        double lat = Math.toDegrees(latitude);
        return new Point2D.Double(lon, lat);
    }

    /**
     * 经纬高转为三维直角坐标
     *
     * @param lon    经度
     * @param lat    纬度
     * @param height 高度
     * @return
     */
    public static List<Double> jwTosw(double lon, double lat, double height) {
        double lonRad = Math.toRadians(lon);
        double latRad = Math.toRadians(lat);

        double sinLat = Math.sin(latRad);
        double coslat = Math.cos(latRad);
        double sinLon = Math.sin(lonRad);
        double cosLon = Math.cos(lonRad);
        double n = WGS84_A / Math.sqrt(1 - WGS84_E2 * sinLat * sinLat);
        double x = (n + height) * coslat * cosLon;
        double y = (n + height) * coslat * sinLon;
        double z = (n * (1 - WGS84_E2) + height) * sinLat;
        return Arrays.asList(x, y, z);
    }

    /**
     * 坐标经纬转像素
     *
     * @param zs     图片左上位置
     * @param yx     图片右下位置
     * @param width  图片宽
     * @param height 图片高
     * @param zb     坐标经纬度
     * @return
     */
    public static Point2D.Double jwToxs(Point2D zs, Point2D yx, double width, double height, Point2D zb) {
        int x = (int) (zb.getX() - zs.getX() * width / (yx.getX() - zs.getX()));
        int y = (int) ((zs.getY() - zb.getY()) * height / (zs.getY() - yx.getY()));
        return new Point2D.Double(x, y);
    }

    /**
     * 判断当前位置是否在多边形区域内
     *
     * @param orderLocation     当前点
     * @param partitionLocation 区域顶点
     * @return
     */
    public static boolean isInPolygon(Map orderLocation, String partitionLocation) {

        double p_x = Double.parseDouble((String) orderLocation.get("X"));
        double p_y = Double.parseDouble((String) orderLocation.get("Y"));
        Point2D.Double point = new Point2D.Double(p_x, p_y);

        List<Point2D.Double> pointList = new ArrayList<Point2D.Double>();
        List objects = JSON.parseArray(partitionLocation);
        for (Object str : objects) {
            List<Double> doubles = JSON.parseArray(JSON.toJSONString(str), Double.class);
            double polygonPoint_x = doubles.get(0);
            double polygonPoint_y = doubles.get(1);
            Point2D.Double polygonPoint = new Point2D.Double(polygonPoint_x, polygonPoint_y);
            pointList.add(polygonPoint);
        }
        return IsPtInPoly(point, pointList);
    }

    /**
     * 返回一个点是否在一个多边形区域内, 如果点位于多边形的顶点或边上,不算做点在多边形内,返回false
     *
     * @param point
     * @param polygon
     * @return
     */
    public static boolean checkWithJdkGeneralPath(Point2D.Double point, List<Point2D.Double> polygon) {
        java.awt.geom.GeneralPath p = new java.awt.geom.GeneralPath();
        Point2D.Double first = polygon.get(0);
        p.moveTo(first.x, first.y);
        polygon.remove(0);
        for (Point2D.Double d : polygon) {
            p.lineTo(d.x, d.y);
        }
        p.lineTo(first.x, first.y);
        p.closePath();
        return p.contains(point);
    }

    /**
     * 判断点是否在多边形内,如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
     *
     * @param point 检测点
     * @param pts   多边形的顶点
     * @return 点在多边形内返回true, 否则返回false
     */
    public static boolean IsPtInPoly(Point2D.Double point, List<Point2D.Double> pts) {

        int N = pts.size();
        boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
        int intersectCount = 0;//cross points count of x
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        Point2D.Double p1, p2;//neighbour bound vertices
        Point2D.Double p = point; //当前点

        p1 = pts.get(0);//left vertex
        for (int i = 1; i <= N; ++i) {//check all rays
            if (p.equals(p1)) {
                return boundOrVertex;//p is an vertex
            }

            p2 = pts.get(i % N);//right vertex
            if (p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)) {//ray is outside of our interests
                p1 = p2;
                continue;//next ray left point
            }

            if (p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)) {//ray is crossing over by the algorithm (common part of)
                if (p.y <= Math.max(p1.y, p2.y)) {//x is before of ray
                    if (p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)) {//overlies on a horizontal ray
                        return boundOrVertex;
                    }

                    if (p1.y == p2.y) {//ray is vertical
                        if (p1.y == p.y) {//overlies on a vertical ray
                            return boundOrVertex;
                        } else {//before ray
                            ++intersectCount;
                        }
                    } else {//cross point on the left side
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y
                        if (Math.abs(p.y - xinters) < precision) {//overlies on a ray
                            return boundOrVertex;
                        }

                        if (p.y < xinters) {//before ray
                            ++intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex
                if (p.x == p2.x && p.y <= p2.y) {//p crossing over p2
                    Point2D.Double p3 = pts.get((i + 1) % N); //next vertex
                    if (p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)) {//p.x lies between p1.x & p3.x
                        ++intersectCount;
                    } else {
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;//next ray left point
        }

        if (intersectCount % 2 == 0) {//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }
    }
}
package cn.service.hspd.utils;



import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;

public class GeoPixelConverter {
    private final AffineTransform transform;
    private final double pixelError;

    public GeoPixelConverter(
            double topLeftLon, double topLeftLat,
            double bottomRightLon, double bottomRightLat,
            int widthPixels, int heightPixels) {

        // 计算仿射变换参数(保留10位小数)
        double scaleX = (bottomRightLon - topLeftLon) / widthPixels;
        double scaleY = (bottomRightLat - topLeftLat) / heightPixels;

        this.transform = new AffineTransform(
                scaleX, 0, 0, scaleY, topLeftLon, topLeftLat);

        // 理论最大误差计算(基于双精度浮点运算)
        this.pixelError = Math.max(
                Math.abs(scaleX) * 1e-10,
                Math.abs(scaleY) * 1e-10);
    }

    public Point2D.Double pixelToGeo(int x, int y) {
        Point2D.Double src = new Point2D.Double(x, y);
        Point2D.Double dst = new Point2D.Double();
        transform.transform(src, dst);

        // 结果四舍五入到小数点后8位
        dst.x = Math.round(dst.x * 1e8) / 1e8;
        dst.y = Math.round(dst.y * 1e8) / 1e8;
        return dst;
    }

    public Point2D geoToPixel(double longitude, double latitude) {
        try {
            Point2D.Double src = new Point2D.Double(longitude, latitude);
            Point2D.Double dst = new Point2D.Double();
            transform.inverseTransform(src, dst);

            // 像素坐标取整
            dst.x = Math.round(dst.x);
            dst.y = Math.round(dst.y);
            return dst;
        } catch (Exception e) {
            throw new IllegalArgumentException("坐标超出转换范围");
        }
    }

    public double getMaxError() {
        return pixelError;
    }

    // 边缘像素补偿算法示例
    public static Point2D.Double adjustEdgePixel(int x, int y, int width, int height) {
        // 对边缘像素进行0.5像素偏移补偿
        double adjX = (x == 0) ? 0.5 : (x == width-1) ? width-1.5 : x;
        double adjY = (y == 0) ? 0.5 : (y == height-1) ? height-1.5 : y;
        return new Point2D.Double(adjX, adjY);
    }

    public static void main(String[] args) {
        // 示例:故宫影像图转换(误差<0.00001度)
        GeoPixelConverter converter = new GeoPixelConverter(
                116.391111, 39.916667, // 左上角经纬度
                116.403889, 39.908333, // 右下角经纬度
                4096, 4096);           // 图像宽高

        Point2D.Double geo = converter.pixelToGeo(4096, 0);
        System.out.printf("中心点坐标: %.8f, %.8f%n", geo.x, geo.y);
        System.out.printf("理论最大误差: %.10f 度", converter.getMaxError());
    }
}

 

    /**
     * 计算初始方位角
     */
    public static double fwj(double lat1, double lon1, double lat2, double lon2) {
        double dLon = Math.toRadians(lon2 - lon1);

        double y = Math.sin(dLon) * Math.cos(Math.toRadians(lat2));
        double x = Math.cos(Math.toRadians(lat1)) * Math.sin(Math.toRadians(lat2)) -
                Math.sin(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.cos(dLon);

        return Math.toDegrees(Math.atan2(y, x));
    }

    /**
     * 从a点到b路过所有经纬度
     *
     * @param start  开始
     * @param end    结束
     * @param number 步长
     * @return
     */
    public static List<Point2D> calculateGreatCircle(Point2D.Double start, Point2D.Double end, int number) {
        GeometryFactory geometryFactory = new GeometryFactory();
        Coordinate[] coordinates = new Coordinate[number];
        for (int i = 0; i < number; i++) {
            double f = (double) i / (number - 1);
            double lat = start.x + f * (end.x - start.x);
            double lng = start.y + f * (end.y - start.y);
            coordinates[i] = new Coordinate(lat, lng);
        }
        return Arrays.stream(geometryFactory.createLineString(coordinates).getCoordinates())
                .map(item -> new Point2D.Double(item.x, item.y))
                .collect(Collectors.toList());
    }


/**
     * 获取本机IPv4 地址
     *
     * @return
     */
    public static String getIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "127.0.0.1";
    }
/**
* http 调用  
*
*/

    public static String post(String url,String json){
        return HttpRequest.post(url)
                .setMaxRedirectCount(1)
                .body(json)
                .timeout(-1)
                .execute()
                .body();
    }

向上取整
Math.ceil(a / b * 100);

 

posted @ 2025-10-05 17:14  chen1777  阅读(18)  评论(0)    收藏  举报