判断某个经纬度,是否在一个封闭区域内(通过mysql提供的GEOMETRY类型)

下面通过一个在开发中的真是应用描述一下

需求就像标题所说, 现在需要处理这个封闭区域信息, 这里选用的是mysql提供的GEOMETRY类型

注: 代码存在部分省略

工具类:
经纬度对象
@Data
@NoArgsConstructor
public class GeoPoint {

    private double latitude;
    private double longitude;

    public GeoPoint(double latitude, double longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

public class Geo {
	/**
     * 获取地块首位经纬度
     * 
     * @param plotRange 地块范围
     * @param flag      ture 第一个, false 最后一个
     * @return
     */
    public static GeoPoint getGeoPoint(String plotRange, boolean flag) {
        JSONArray jsonArray = JSON.parseArray(plotRange);
        if (flag) {
            JSONArray geo = jsonArray.getJSONArray(0);
            return new GeoPoint(Double.parseDouble(geo.get(1).toString()), Double.parseDouble(geo.get(0).toString()));
        }
        JSONArray geo = jsonArray.getJSONArray(jsonArray.size() - 1);
        return new GeoPoint(Double.parseDouble(geo.get(1).toString()), Double.parseDouble(geo.get(0).toString()));
    }

    /**
     * 获取最终mysql地理类型的的地块范围
     * 封闭范围
     *
     * @param range
     * @return
     */
    public static String getFinalGeo(String range) {
        GeoPoint geoPoint = getGeoPoint(range, true);
        return "{\"type\":\"MultiPolygon\",\"coordinates\":[[" + range.substring(0, range.length() - 1) + ",[" + geoPoint.getLongitude() + "," + geoPoint.getLatitude() + "]]]]}".trim();
    }

    /**
     * 获取Point格式
     *
     * @param geoPoint 经纬度
     * @return 格式化后的Point
     */
    public static String getPointGeoForMysqlGEOMETRY(GeoPoint geoPoint) {
        return String.format("POINT(%s %s)", geoPoint.getLatitude(), geoPoint.getLongitude());
    }
}
表结构:

判断某个经纬度,是否在一个封闭区域内(通过mysql提供的GEOMETRY类型)_第1张图片

对于判断一个经纬度是否在一个封闭区域内的的示例:

实体类:
/**
 * 公司管理地块范围实体
 *
 * @author : cookie
 * date : 2024-01-26
 */
public class ScreenCompanyRange {

    @Id
    private String id;

    @ApiModelProperty("一个完整封闭区域范围")
    private String range;

    @ApiModelProperty("公司id")
    @Column(name = "company_id")
    private String companyId;

    @ApiModelProperty("范围名称")
    @Column(name = "range_name")
    private String rangeName;

    private String geo;

}
service层方法
@Override
public int save(ScreenCompanyRange screenCompanyRange) {
    // 手动设置id
    screenCompanyRange.setId(Sid.nextShort());
    // 调用工具类中的方法获取mysql GEOMETRY 类型需要的格式
    screenCompanyRange.setGeo(Geo.getFinalGeo(screenCompanyRange.getRange()));
    return screenCompanyRangeMapper.insertMessage(screenCompanyRange);
}
*Mapper.xml

这里使用了 ST_GeomFromGeoJSON 方法 将我们格式化好的数据转换为 mysql中 GEOMETRY 类型

    <insert id="insertMessage">
        insert into screen_company_range(id, `range`, company_id, geo, range_name)
        values (#{id}, #{range}, #{companyId}, ST_GeomFromGeoJSON(#{geo}), #{rangeName})
    </insert>
插入数据格式:

下面数据是一个示例, 经纬度列表就按照 , 顺序即可

我提供的经纬度不一定对, 做了混淆

{
  "companyId": "240565BX5H7TRNMW",
  "range": "[[116.269186,32.159889],[126.261416,32.147559],[116.275658,32.156151],[116.268110,32.149781]]",
  "rangeName": "xxxx"
}
数据展示

插入成功后数据库中的数据如下:

在这里插入图片描述

现在就还差最后一步, 就是判断点是否在一个范围内, 通过下面的示例SQL

SELECT ST_INTERSECTS(ST_GEOMFROMTEXT('POINT(31.149781 106.268110)', 4326), geo) exist FROM screen_company_range 

判断某个经纬度,是否在一个封闭区域内(通过mysql提供的GEOMETRY类型)_第2张图片

存在 返回1 不存在结果是 0

POINT(31.149781 106.268110) 这一块封装的有 方法 getPointGeoForMysqlGEOMETRY

注意这里的经纬度,是反过来的

你可能感兴趣的:(mysql,数据库,java)