feat(positioning): 添加封闭区域匹配功能
parent
961a87226e
commit
c70864998e
|
|
@ -42,3 +42,4 @@ build/
|
|||
# Local smoke-test logs and extracted dependency metadata
|
||||
/tmp/
|
||||
/logs/
|
||||
/start/src/main/resources/templates/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
package com.zcloud.personnel.positioning.command.query;
|
||||
|
||||
import com.alibaba.cola.exception.BizException;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.ClosedAreaDO;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
class ClosedAreaMatcher {
|
||||
|
||||
List<AreaPolygon> prepare(List<ClosedAreaDO> areas) {
|
||||
if (areas == null || areas.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AreaPolygon> result = new ArrayList<>(areas.size());
|
||||
for (ClosedAreaDO area : areas) {
|
||||
result.add(new AreaPolygon(area, parseLocation(area)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
AreaPolygon match(BigDecimal lon, BigDecimal lat, List<AreaPolygon> areas) {
|
||||
if (lon == null || lat == null || areas == null) {
|
||||
return null;
|
||||
}
|
||||
for (AreaPolygon area : areas) {
|
||||
if (contains(lon, lat, area)) {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean contains(BigDecimal lon, BigDecimal lat, AreaPolygon area) {
|
||||
if (lon == null || lat == null || area == null || area.points.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
boolean inside = false;
|
||||
double x = lon.doubleValue();
|
||||
double y = lat.doubleValue();
|
||||
for (int i = 0, j = area.points.size() - 1; i < area.points.size(); j = i++) {
|
||||
double xi = area.points.get(i)[0].doubleValue();
|
||||
double yi = area.points.get(i)[1].doubleValue();
|
||||
double xj = area.points.get(j)[0].doubleValue();
|
||||
double yj = area.points.get(j)[1].doubleValue();
|
||||
if ((yi > y) != (yj > y)
|
||||
&& x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
private List<BigDecimal[]> parseLocation(ClosedAreaDO area) {
|
||||
List<BigDecimal[]> points = new ArrayList<>();
|
||||
if (area == null || !StringUtils.hasText(area.getLocation())) {
|
||||
throw locationFormatException(area);
|
||||
}
|
||||
for (String coordinate : area.getLocation().split(";")) {
|
||||
if (!StringUtils.hasText(coordinate)) {
|
||||
continue;
|
||||
}
|
||||
String[] values = coordinate.trim().split(",");
|
||||
if (values.length != 2) {
|
||||
throw locationFormatException(area);
|
||||
}
|
||||
try {
|
||||
points.add(new BigDecimal[]{
|
||||
new BigDecimal(values[0].trim()),
|
||||
new BigDecimal(values[1].trim())
|
||||
});
|
||||
} catch (NumberFormatException e) {
|
||||
throw locationFormatException(area);
|
||||
}
|
||||
}
|
||||
if (points.size() < 3) {
|
||||
throw locationFormatException(area);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private BizException locationFormatException(ClosedAreaDO area) {
|
||||
return new BizException("封闭区域经纬度格式错误,区域id=" + (area == null ? null : area.getId()));
|
||||
}
|
||||
|
||||
static class AreaPolygon {
|
||||
private final ClosedAreaDO area;
|
||||
private final List<BigDecimal[]> points;
|
||||
|
||||
private AreaPolygon(ClosedAreaDO area, List<BigDecimal[]> points) {
|
||||
this.area = area;
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
ClosedAreaDO getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
BigDecimal center(int coordinateIndex) {
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
for (BigDecimal[] point : points) {
|
||||
total = total.add(point[coordinateIndex]);
|
||||
}
|
||||
return total.divide(BigDecimal.valueOf(points.size()), 12, RoundingMode.HALF_UP)
|
||||
.stripTrailingZeros();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.zcloud.personnel.positioning.persistence.dataobject;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ClosedAreaDO {
|
||||
private Long id;
|
||||
private String closedAreaName;
|
||||
private String closedAreaType;
|
||||
private Long jurisdictionalCorpId;
|
||||
private String jurisdictionalCorpName;
|
||||
private String location;
|
||||
}
|
||||
Loading…
Reference in New Issue