1、人员定位大屏区域匹配
parent
44fb60dd2c
commit
ddf94df855
|
|
@ -0,0 +1,122 @@
|
|||
package com.zcloud.personnel.positioning.command.query;
|
||||
|
||||
import com.alibaba.cola.exception.BizException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 使用实时定位坐标匹配本平台区域。
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
class PositionAreaMatcher {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 预解析区域多边形,避免同一次人员查询中为每个人重复解析 JSON。
|
||||
*/
|
||||
List<AreaPolygon> prepare(List<AreaDO> areas) {
|
||||
if (areas == null || areas.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AreaPolygon> result = new ArrayList<>(areas.size());
|
||||
for (AreaDO area : areas) {
|
||||
result.add(new AreaPolygon(area, parsePolygon(area.getPolygonJson())));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用实时经纬度匹配区域;区域重叠时按区域查询顺序返回第一个命中项。
|
||||
*/
|
||||
AreaDO match(BigDecimal lon, BigDecimal lat, List<AreaPolygon> areas) {
|
||||
if (lon == null || lat == null || areas == null) {
|
||||
return null;
|
||||
}
|
||||
for (AreaPolygon area : areas) {
|
||||
if (isPointInPolygon(lon, lat, area.points)) {
|
||||
return area.area;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将区域多边形的多层 JSON 结构展开为经纬度点集合,兼容 FindS 的嵌套坐标格式。
|
||||
*/
|
||||
private List<BigDecimal[]> parsePolygon(String polygonJson) {
|
||||
List<BigDecimal[]> points = new ArrayList<>();
|
||||
if (!StringUtils.hasText(polygonJson)) {
|
||||
return points;
|
||||
}
|
||||
try {
|
||||
collectPoints(objectMapper.readTree(polygonJson), points);
|
||||
} catch (IOException e) {
|
||||
throw new BizException("区域边界坐标JSON格式错误");
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private void collectPoints(JsonNode node, List<BigDecimal[]> points) {
|
||||
if (node == null || node.isNull() || node.isMissingNode()) {
|
||||
return;
|
||||
}
|
||||
if (node.isObject()) {
|
||||
node.elements().forEachRemaining(child -> collectPoints(child, points));
|
||||
return;
|
||||
}
|
||||
if (!node.isArray()) {
|
||||
return;
|
||||
}
|
||||
if (node.size() >= 2 && node.get(0).isNumber() && node.get(1).isNumber()) {
|
||||
points.add(new BigDecimal[]{node.get(0).decimalValue(), node.get(1).decimalValue()});
|
||||
return;
|
||||
}
|
||||
for (JsonNode child : node) {
|
||||
collectPoints(child, points);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用射线法判断实时定位点是否位于区域多边形内。
|
||||
*/
|
||||
private boolean isPointInPolygon(BigDecimal lon, BigDecimal lat, List<BigDecimal[]> points) {
|
||||
if (points == null || points.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
boolean inside = false;
|
||||
double x = lon.doubleValue();
|
||||
double y = lat.doubleValue();
|
||||
for (int i = 0, j = points.size() - 1; i < points.size(); j = i++) {
|
||||
double xi = points.get(i)[0].doubleValue();
|
||||
double yi = points.get(i)[1].doubleValue();
|
||||
double xj = points.get(j)[0].doubleValue();
|
||||
double yj = points.get(j)[1].doubleValue();
|
||||
if ((yi > y) != (yj > y)
|
||||
&& x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
static class AreaPolygon {
|
||||
private final AreaDO area;
|
||||
private final List<BigDecimal[]> points;
|
||||
|
||||
private AreaPolygon(AreaDO area, List<BigDecimal[]> points) {
|
||||
this.area = area;
|
||||
this.points = points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.zcloud.personnel.positioning.persistence.dataobject;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 人员当前定位区域批量更新参数。
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class PersonnelLocationAreaUpdateDO {
|
||||
private String findsStaffNo;
|
||||
private Long locationAreaId;
|
||||
private String locationAreaName;
|
||||
}
|
||||
Loading…
Reference in New Issue