지대한
2 months ago
2 changed files with 376 additions and 2 deletions
@ -0,0 +1,374 @@
|
||||
package com.palnet.comn.utils; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fasterxml.jackson.annotation.JsonValue; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.locationtech.jts.geom.Coordinate; |
||||
import org.locationtech.jts.geom.Geometry; |
||||
import org.locationtech.jts.geom.GeometryFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.stream.Collectors; |
||||
|
||||
// TODO areaUtils, airspaceUtils merge
|
||||
// TODO airspaceUtils의 검증 관련 로직은 해당 표시에서 적용.
|
||||
@Slf4j |
||||
public class AirAreaUtils { |
||||
|
||||
private final String RESOURCE_BASE_PATH = "air/airspace/"; |
||||
private final String COMMON_PATH = "common/"; |
||||
private final String CUSTOM_PATH = "custom/"; |
||||
private final String SUFFIX_FILE_NAME = "Area.json"; |
||||
|
||||
private Map<String, List<FeatureInfo>> airAreaMap; |
||||
private GeometryFactory geometryFactory; |
||||
|
||||
private AirAreaUtils() { |
||||
log.info("===== AirAreaUtils init ====="); |
||||
this.init(); |
||||
} |
||||
|
||||
public static AirAreaUtils getInstance() { |
||||
return LazyHolder.INSTANCE; |
||||
} |
||||
|
||||
private static class LazyHolder { |
||||
private static final AirAreaUtils INSTANCE = new AirAreaUtils(); |
||||
} |
||||
|
||||
// TODO 초기화
|
||||
private void init() { |
||||
geometryFactory = new GeometryFactory(); |
||||
// TODO 데이터 로드
|
||||
} |
||||
|
||||
/** |
||||
* air area와 중복 여부(고도 무시) |
||||
* |
||||
* @param targetfeatureInfo |
||||
* @return |
||||
*/ |
||||
public boolean isDuplicatedAirAreaIgnoreElev(FeatureInfo targetfeatureInfo) { |
||||
return isDuplicatedAirAreaIgnoreElev(targetfeatureInfo, AirAreaType.ALL); |
||||
} |
||||
|
||||
/** |
||||
* air area와 중복 여부(고도 무시) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @param airAreaType |
||||
* @return |
||||
*/ |
||||
public boolean isDuplicatedAirAreaIgnoreElev(FeatureInfo targetFeatureInfo, AirAreaType airAreaType) { |
||||
if (targetFeatureInfo == null) return false; |
||||
if (airAreaMap == null || airAreaMap.isEmpty()) { |
||||
log.warn("airAreaMap is empty"); |
||||
return false; |
||||
} |
||||
if (airAreaType == null) airAreaType = AirAreaType.ALL; |
||||
|
||||
Geometry targetGeometry = targetFeatureInfo.getGeometry(); |
||||
if (targetGeometry == null) return false; |
||||
|
||||
List<FeatureInfo> duplicatedAirAreaFeatureInfos = getDuplicatedAirAreaIgnoreElev(targetFeatureInfo, airAreaType); |
||||
|
||||
return !duplicatedAirAreaFeatureInfos.isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* air area와 중복 여부(고도 포함) |
||||
* |
||||
* @param featureInfo |
||||
* @return |
||||
*/ |
||||
public boolean isDuplicatedAirArea(FeatureInfo featureInfo) { |
||||
return isDuplicatedAirArea(featureInfo, AirAreaType.ALL); |
||||
} |
||||
|
||||
/** |
||||
* air area와 중복 여부(고도 포함) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @param airAreaType |
||||
* @return |
||||
*/ |
||||
public boolean isDuplicatedAirArea(FeatureInfo targetFeatureInfo, AirAreaType airAreaType) { |
||||
if (targetFeatureInfo == null) return false; |
||||
if (airAreaMap == null || airAreaMap.isEmpty()) { |
||||
log.warn("airAreaMap is empty"); |
||||
return false; |
||||
} |
||||
if (airAreaType == null) airAreaType = AirAreaType.ALL; |
||||
|
||||
List<FeatureInfo> duplicatedAirAreaFeatureInfos = getDuplicatedAirArea(targetFeatureInfo, airAreaType); |
||||
return !duplicatedAirAreaFeatureInfos.isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* 중복되는 air area FeatureInfo 반환(고도 무시) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @return |
||||
*/ |
||||
public List<FeatureInfo> getDuplicatedAirAreaIgnoreElev(FeatureInfo targetFeatureInfo) { |
||||
return getDuplicatedAirAreaIgnoreElev(targetFeatureInfo, AirAreaType.ALL); |
||||
} |
||||
|
||||
/** |
||||
* 중복되는 air area FeatureInfo 반환(고도 무시) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @param airAreaType |
||||
* @return |
||||
*/ |
||||
public List<FeatureInfo> getDuplicatedAirAreaIgnoreElev(FeatureInfo targetFeatureInfo, AirAreaType airAreaType) { |
||||
Geometry targetGeometry = targetFeatureInfo.getGeometry(); |
||||
if (targetGeometry == null) return new ArrayList<>(); |
||||
|
||||
List<FeatureInfo> airAreaFeatureInfos = null; |
||||
if (AirAreaType.ALL == airAreaType) { |
||||
airAreaFeatureInfos = airAreaMap.values().stream() |
||||
.flatMap(List::stream) |
||||
.collect(Collectors.toList()); |
||||
} else { |
||||
airAreaFeatureInfos = airAreaMap.get(airAreaType.getCode()); |
||||
} |
||||
|
||||
return airAreaFeatureInfos.stream() |
||||
.filter(airAreaFeatureInfo -> { |
||||
Geometry airAreaGeometry = airAreaFeatureInfo.getGeometry(); |
||||
if (airAreaGeometry == null) return false; |
||||
return airAreaGeometry.intersects(targetGeometry); |
||||
}) |
||||
.collect(Collectors.toList()); |
||||
} |
||||
|
||||
/** |
||||
* 중복되는 air area FeatureInfo 반환(고도 포함) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @return |
||||
*/ |
||||
public List<FeatureInfo> getDuplicatedAirArea(FeatureInfo targetFeatureInfo) { |
||||
return getDuplicatedAirArea(targetFeatureInfo, AirAreaType.ALL); |
||||
} |
||||
|
||||
/** |
||||
* 중복되는 air area FeatureInfo 반환(고도 포함) |
||||
* |
||||
* @param targetFeatureInfo |
||||
* @param airAreaType |
||||
* @return |
||||
*/ |
||||
public List<FeatureInfo> getDuplicatedAirArea(FeatureInfo targetFeatureInfo, AirAreaType airAreaType) { |
||||
List<FeatureInfo> duplicatedAirAreaFeatureInfosIgnoreElev = getDuplicatedAirAreaIgnoreElev(targetFeatureInfo, airAreaType); |
||||
final double targetHighElev = targetFeatureInfo.getHighElev() != null ? targetFeatureInfo.getHighElev() : 0D; |
||||
return duplicatedAirAreaFeatureInfosIgnoreElev.stream().filter(airAreaFeatureInfo -> { |
||||
final double airAreaHighElev = airAreaFeatureInfo.getHighElev() != null ? airAreaFeatureInfo.getHighElev() : 0D; |
||||
return targetHighElev <= airAreaHighElev; |
||||
}).collect(Collectors.toList()); |
||||
} |
||||
|
||||
/** |
||||
* FeatureInfo 생성 |
||||
* |
||||
* @param coordinates |
||||
* @return |
||||
*/ |
||||
public FeatureInfo craeteFeatureInfo(List<Coordinate> coordinates) { |
||||
return craeteFeatureInfo(coordinates, GeometryType.POLYGON, null); |
||||
} |
||||
|
||||
/** |
||||
* FeatureInfo 생성 |
||||
* |
||||
* @param coordinates |
||||
* @param geometryType |
||||
* @param highElev |
||||
* @return |
||||
*/ |
||||
public FeatureInfo craeteFeatureInfo(List<Coordinate> coordinates, GeometryType geometryType, Double highElev) { |
||||
return craeteFeatureInfo(coordinates, geometryType, null, null, null, highElev); |
||||
} |
||||
|
||||
/** |
||||
* FeatureInfo 생성 |
||||
* |
||||
* @param coordinates |
||||
* @param geometryType |
||||
* @param name |
||||
* @param description |
||||
* @param type |
||||
* @param highElev |
||||
* @return |
||||
*/ |
||||
public FeatureInfo craeteFeatureInfo(List<Coordinate> coordinates, GeometryType geometryType, String name, String description, String type, Double highElev) { |
||||
return craeteFeatureInfo(coordinates, geometryType, name, description, type, null, highElev, true); |
||||
} |
||||
|
||||
/** |
||||
* FeatureInfo 생성 |
||||
* |
||||
* @param coordinates |
||||
* @param geometryType |
||||
* @param name |
||||
* @param description |
||||
* @param type |
||||
* @param lowElev |
||||
* @param highElev |
||||
* @param isUse |
||||
* @return |
||||
*/ |
||||
public FeatureInfo craeteFeatureInfo(List<Coordinate> coordinates, GeometryType geometryType, String name, String description, String type, Double lowElev, Double highElev, boolean isUse) { |
||||
Geometry geometry = createGeometryByCoordinate(coordinates, geometryType); |
||||
return FeatureInfo.builder() |
||||
.name(name) |
||||
.description(description) |
||||
.type(type) |
||||
.lowElev(lowElev) |
||||
.highElev(highElev) |
||||
.isUse(isUse) |
||||
.geometry(geometry) |
||||
.build(); |
||||
} |
||||
|
||||
/** |
||||
* Geometry 생성 |
||||
* 좌표 목록과 GeometryType을 이용하여 Geometry 생성 |
||||
* |
||||
* @param target |
||||
* @param type |
||||
* @return |
||||
*/ |
||||
public Geometry createGeometryByCoordinate(List<Coordinate> target, GeometryType type) { |
||||
if (target == null || target.isEmpty()) return null; |
||||
|
||||
if (type == null) { |
||||
if (target.size() == 1) { |
||||
type = GeometryType.POINT; |
||||
} else if (target.size() == 2) { |
||||
type = GeometryType.LINESTRING; |
||||
} else { |
||||
type = GeometryType.POLYGON; |
||||
} |
||||
} |
||||
|
||||
Geometry geometry = null; |
||||
if (GeometryType.POLYGON == type) { |
||||
if (target.get(0) != target.get(target.size() - 1)) { |
||||
target.add(target.get(0)); |
||||
} |
||||
geometry = this.geometryFactory.createPolygon(target.toArray(new Coordinate[0])); |
||||
} else if (GeometryType.LINESTRING == type) { |
||||
geometry = this.geometryFactory.createLineString(target.toArray(new Coordinate[0])); |
||||
} else if (GeometryType.POINT == type) { |
||||
geometry = this.geometryFactory.createPoint(target.get(0)); |
||||
} |
||||
return geometry; |
||||
} |
||||
|
||||
|
||||
@Data |
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
@Builder |
||||
public static class FeatureInfo { |
||||
private String name; |
||||
private String description; |
||||
private String type; |
||||
private Double lowElev; |
||||
private Double highElev; |
||||
private boolean isUse; |
||||
private Geometry geometry; |
||||
} |
||||
|
||||
/** |
||||
* AirAreaType - 모두, 김포 |
||||
*/ |
||||
public enum AirAreaType { |
||||
ALL("all"), |
||||
GIMPO("gimpo"); |
||||
|
||||
private final String code; |
||||
|
||||
@JsonValue |
||||
public String getCode() { |
||||
return code; |
||||
} |
||||
|
||||
AirAreaType(String code) { |
||||
this.code = code; |
||||
} |
||||
|
||||
@JsonCreator |
||||
public static AirAreaType fromCode(String code) { |
||||
for (AirAreaType type : AirAreaType.values()) { |
||||
if (type.code.equals(code)) { |
||||
return type; |
||||
} |
||||
} |
||||
log.warn("Unknown AirAreaType code: {}", code); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* GeometryType - Point, LineString, Polygon |
||||
*/ |
||||
public enum GeometryType { |
||||
POINT("Point"), |
||||
LINESTRING("LineString"), |
||||
POLYGON("Polygon"); |
||||
// MULTIPOINT("MultiPoint"),
|
||||
// MULTILINESTRING("MultiLineString"),
|
||||
// MULTIPOLYGON("MultiPolygon"),
|
||||
// GEOMETRYCOLLECTION("GeometryCollection");
|
||||
|
||||
private final String code; |
||||
|
||||
@JsonValue |
||||
public String getCode() { |
||||
return code; |
||||
} |
||||
|
||||
GeometryType(String code) { |
||||
this.code = code; |
||||
} |
||||
|
||||
@JsonCreator |
||||
public static GeometryType fromCode(String code) { |
||||
for (GeometryType type : GeometryType.values()) { |
||||
if (type.code.equals(code)) { |
||||
return type; |
||||
} |
||||
} |
||||
log.warn("Unknown GeometryType code: {}", code); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
// TODO 가장 가까운 거리 반환
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) { |
||||
AirAreaUtils utils = AirAreaUtils.getInstance(); |
||||
log.info("utils: {}", utils); |
||||
AirAreaUtils utils2 = AirAreaUtils.getInstance(); |
||||
log.info("utils2: {}", utils2); |
||||
log.info("utils == utils2: {}", utils == utils2); |
||||
|
||||
List<Integer> list = List.of(1, 2, 3, 4, 5); |
||||
boolean b = list.stream().anyMatch(i -> i == 3); |
||||
log.info("b:: {}", b); |
||||
List<Integer> list2 = new ArrayList<>(); |
||||
boolean b2 = list2.stream().anyMatch(i -> i == 3); |
||||
log.info("b2:: {}", b2); |
||||
} |
||||
} |
Loading…
Reference in new issue