下面通过一个在开发中的真是应用描述一下
需求就像标题所说, 现在需要处理这个封闭区域信息, 这里选用的是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());
}
}
对于判断一个经纬度是否在一个封闭区域内的的示例:
/**
* 公司管理地块范围实体
*
* @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;
}
@Override
public int save(ScreenCompanyRange screenCompanyRange) {
// 手动设置id
screenCompanyRange.setId(Sid.nextShort());
// 调用工具类中的方法获取mysql GEOMETRY 类型需要的格式
screenCompanyRange.setGeo(Geo.getFinalGeo(screenCompanyRange.getRange()));
return screenCompanyRangeMapper.insertMessage(screenCompanyRange);
}
这里使用了 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
存在 返回1 不存在结果是 0
POINT(31.149781 106.268110) 这一块封装的有 方法 getPointGeoForMysqlGEOMETRY
注意这里的经纬度,是反过来的