根据点的经纬度判断是否在围栏内 JAVA 工具类

该文章介绍了Java工具类RailUtil,用于处理地理围栏判定,包括点是否在围栏内、计算区域面积以及与数据上传配置的交互,涉及Jedis缓存和坐标处理功能。
摘要由CSDN通过智能技术生成
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.data.report.domain.dto.MineInfoCacheDTO;
import com.ruoyi.data.report.domain.dto.PointDTO;
import com.ruoyi.data.report.domain.dto.TbDataUploadConfigDTO;
import com.ruoyi.data.report.domain.vo.MonitorRailInfoVO;
import com.ruoyi.data.report.service.cache.DataUploadConfigCacheService;
import com.ruoyi.data.report.service.cache.MineInfoCacheService;
import com.ruoyi.data.report.service.cache.UploadRailInfoCacheService;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 围栏工具类
 *
 * @since 2023/12/22 10:54
 */
@Component
@Slf4j
public class RailUtil {

    @Autowired
    private UploadRailInfoCacheService uploadRailInfoCacheService;

    @Autowired
    private DataUploadConfigCacheService configCacheService;

    @Autowired
    private MineInfoCacheService mineInfoCacheService;

    public double getArea(MonitorRailInfoVO monitorRailInfoVO){
        if (Objects.isNull(monitorRailInfoVO)
                || CollUtil.isEmpty(monitorRailInfoVO.getWgs84RailPoint())){
            // 围栏为空,点为空或点经纬度为空时直接返回不在围栏内,不做报错处理阻断流程
            return 0.0;
        }
        // 补偿初始点,形成闭环
        List<String> tmpPointList = CollUtil.newArrayList(monitorRailInfoVO.getWgs84RailPoint());
        tmpPointList.add(tmpPointList.get(0));
        Coordinate[] coordinates = tmpPointList.stream().map(tmp->{
            String[] point = tmp.split(",");
            double longitude = Convert.toDouble(point[0]);
            double latitude = Convert.toDouble(point[1]);
            return new Coordinate(longitude, latitude);
        }).toArray(Coordinate[]::new);

        LinearRing linearRing = new GeometryFactory().createLinearRing(coordinates); // 将顶点数组转换为线性环
        return calculateArea3(linearRing);
    }

    /**
     * 判断点是否在围栏内
     * @param pointDTO
     * @return
     */
    public static boolean pointIsInRail(PointDTO pointDTO, MonitorRailInfoVO monitorRailInfoVO){
        if (Objects.isNull(monitorRailInfoVO)
                || Objects.isNull(pointDTO)
                || CollUtil.isEmpty(monitorRailInfoVO.getRailPoint())
                || Objects.isNull(pointDTO.getLatitude())
                || Objects.isNull(pointDTO.getLongitude())){
            // 围栏为空,点为空或点经纬度为空时直接返回不在围栏内,不做报错处理阻断流程
            return false;
        }
        // 补偿初始点,形成闭环
        List<String> wgs84RailPoint = CollUtil.newArrayList(monitorRailInfoVO.getWgs84RailPoint());
        wgs84RailPoint.add(wgs84RailPoint.get(0));
        Coordinate[] coordinates = wgs84RailPoint.stream().map(tmp->{
            String[] point = tmp.split(",");
            double longitude = Convert.toDouble(point[0]);
            double latitude = Convert.toDouble(point[1]);
            return new Coordinate(longitude, latitude);
        }).toArray(Coordinate[]::new);

        LinearRing linearRing = new GeometryFactory().createLinearRing(coordinates); // 将顶点数组转换为线性环
        Polygon polygon = new GeometryFactory().createPolygon(linearRing, null); // 根据线性环创建多边形
        Point point = new GeometryFactory().createPoint(new Coordinate(pointDTO.getLongitude().doubleValue(), pointDTO.getLatitude().doubleValue())); // 定义一个点坐标
        return polygon.contains(point); // 判断点是否在多边形内部
    }

    /**
     * 判断点是否在全局围栏内,如果在则返回最小的围栏
     * @param pointDTO
     * @return 如果点不在大围栏内则返回空,其他情况返回当前所在最小的围栏
     */
    public String pointInRail(PointDTO pointDTO){
        TbDataUploadConfigDTO config = configCacheService.getDataUploadConfig();
        if (Objects.isNull(config) || StringUtils.isBlank(config.getRailCode())){
            // 当前没有配置围栏范围;若所选电子围栏未标注,则认为无区域,车辆设备人员不在区域内,不上传实时信息;
            return null;
        }
        if (Objects.isNull(pointDTO)
                || Objects.isNull(pointDTO.getLongitude())
                || Objects.isNull(pointDTO.getLatitude())) {
            return null;
        }

        // 全局围栏
        List<MonitorRailInfoVO> railList = uploadRailInfoCacheService.getRailList();
        if (CollUtil.isEmpty(railList)){
            // 当前没有配置任何围栏
            return null;
        }
        // 首先判断是否在全局围栏内
        // 获取煤矿编码
        MineInfoCacheDTO mineBaseInfo = mineInfoCacheService.getMineBaseInfo();
        String areaCode =  StringUtils.leftPad( mineBaseInfo.getMineCode(),12,"0")+0+StringUtils.leftPad( config.getRailCode().substring(0,4), 4,"0");
        Optional<MonitorRailInfoVO> largestRail = railList.stream().filter(tmp->areaCode.equals(tmp.getRailCode())).findFirst();
        if (!largestRail.isPresent()){
            // 全局围栏失效,不上传数据
            return null;
        }
        if (pointIsInRail(pointDTO, largestRail.get())){
            // 在全局围栏内,依序判断
            for (MonitorRailInfoVO monitorRailInfoVO : railList) {
                if (pointIsInRail(pointDTO, monitorRailInfoVO)){
                    // 返回满足在围栏条件的第一条围栏
                    return monitorRailInfoVO.getRailName();
                }
            }
        }
        // 不在全局围栏内,直接返回空
        return null;
    }

    public static double calculateArea(LinearRing polygon) {
        int numPoints = polygon.getNumPoints();
        if (numPoints < 3) {
            throw new IllegalArgumentException("至少需要三个点才能构成多边形");
        }
        double area = 0;

        for (int i = 0; i < numPoints - 1; i++) {
            Point p1 = polygon.getPointN(i);
            Point p2 = polygon.getPointN((i + 1) % numPoints);

            area += (p1.getX() * p2.getY()) - (p1.getY() * p2.getX());
        }
        return Math.abs(area / 2);

    }

    public static double calculateArea2(LinearRing polygon){
        int numPoints = polygon.getNumPoints();
        if (numPoints < 3) {
            throw new IllegalArgumentException("至少需要三个点才能构成多边形");
        }
        int i, j;
        int area = 0;
        for (i = 0; i < numPoints; i++)
        {
            j = (i + 1) % numPoints;
            area += polygon.getPointN(i).getX() * polygon.getPointN(j).getY();
            area -= polygon.getPointN(i).getY() * polygon.getPointN(j).getX();
        }
        return Math.abs(area / 2);
    }

    public static double calculateArea3(LinearRing linearRing){
        Polygon polygon = new GeometryFactory().createPolygon(linearRing, null); // 根据线性环创建多边形
        return polygon.getArea();
    }

    private static void testPointInRail(PointDTO pointDTO){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(100); // 设置最大连接数
        jedisPoolConfig.setMaxIdle(10); // 设置最大空闲连接数

        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.30.26", 6379);
        Jedis jedis = jedisPool.getResource();
        String conf = jedis.get("vehicleSafetydb:dataProcess:dataUpload:config");
        String rails = jedis.get("vehicleSafetydb:dataProcess:dataUpload:railInfo");
        jedisPool.close();
        TbDataUploadConfigDTO configDTO = JSON.parseObject(conf, TbDataUploadConfigDTO.class);
        log.info("数据上传配置的围栏编码"+ Optional.ofNullable(configDTO).orElse(new TbDataUploadConfigDTO()).getRailCode());
        List<MonitorRailInfoVO> railList = JSONArray.parseArray(rails, MonitorRailInfoVO.class);
        log.info(JSON.toJSONString(railList));
        for (MonitorRailInfoVO monitorRailInfoVO : railList) {
            log.info(monitorRailInfoVO.getRailName()+" "+monitorRailInfoVO.getRailCode()+" "+pointIsInRail(pointDTO, monitorRailInfoVO));
        }
    }

    public static void main(String[] args) {
//        MonitorRailInfoVO monitorRailInfoVO = new MonitorRailInfoVO();
        // 漏斗
//        monitorRailInfoVO.setRailPoint(CollUtil.newArrayList("0,0","6,0","0,6","6,6"));
        // 正方
//        monitorRailInfoVO.setRailPoint(CollUtil.newArrayList("0,0","6,0","6,6","0,6"));
        // 漏斗内
//        System.out.println(pointIsInRail(new PointDTO(3.0,1.0,0.0), monitorRailInfoVO));
        // 漏斗外
//        monitorRailInfoVO.setWgs84RailPoint(CollUtil.newArrayList(
//                "112.55829096,37.80848749,0",
//                "112.56965870,37.80851027,0",
//                "112.57004195,37.79914526,0",
//                "112.55822657,37.79971515,0"
//        ));
//        monitorRailInfoVO.setWgs84RailPoint(CollUtil.newArrayList(
//                "112.55202017090623,37.807970416154156,0.0",
//                "112.56340765953608,37.80801002434173,0.0",
//                "112.56379253544473,37.798644260311264,0.0",
//                "112.55195666578163,37.799196815255726,0.0"
//        ));
//        System.out.println(pointIsInRail(new PointDTO(112.5624,37.805181,0.0), monitorRailInfoVO));
//        System.out.println(pointIsInRail(new PointDTO(112.554133,37.80557,0.0), monitorRailInfoVO));
//        System.out.println((new RailUtil()).getArea(monitorRailInfoVO));

        // 漏斗外
//        monitorRailInfoVO.setWgs84RailPoint(CollUtil.newArrayList(
//                "90.31417085,44.54428293,0",
//                "90.31520082,44.50033762,0",
//                "90.37450982,44.49982264,0",
//                "90.37244989,44.54651453,0"
//        ));
//
//        System.out.println(pointIsInRail(new PointDTO(90.32366497846226,44.517821758247244,0.0), monitorRailInfoVO));
        testPointInRail(new PointDTO(112.5624,37.805181,0.0));

    }


}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要根据经纬度判断某个是否在另一个附近几公里内,可以使用 Haversine 公式计算两个之间的距离。 Haversine 公式如下: ``` a = sin²(Δlat/2) + cos(lat1) * cos(lat2) * sin²(Δlong/2) c = 2 * atan2( √a, √(1−a) ) d = R * c ``` 其中,`lat1` 和 `long1` 为第一个的纬度和经度,`lat2` 和 `long2` 为第二个的纬度和经度,`Δlat` 和 `Δlong` 分别为两个纬度和经度的差值,`R` 为地球半径,取值为 6,371km。 根据公式计算出两个之间的距离后,只需要判断这个距离是否小于等于目标附近的距离,如果小于等于,则说明该在目标附近。 Java 代码示例: ```java public static final double EARTH_RADIUS = 6371; // 地球半径,单位 km public static boolean isNearby(double lat1, double long1, double lat2, double long2, double distance) { double dLat = Math.toRadians(lat2 - lat1); double dLong = Math.toRadians(long2 - long1); double a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.pow(Math.sin(dLong / 2), 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double d = EARTH_RADIUS * c; // 计算两个之间的距离,单位 km return d <= distance; } ``` 其中,`lat1` 和 `long1` 是第一个的纬度和经度,`lat2` 和 `long2` 是第二个的纬度和经度,`distance` 是目标附近的距离,单位 km。函数返回值为布尔类型,表示第二个是否在目标附近。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值