Browse Source

feat: Flt모듈 - 공역체크, 허용고도 조회 기능 추가

pull/9/head
lkd9125(이경도) 7 months ago
parent
commit
c2aecdf93f
  1. 8
      build.gradle
  2. 2
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java
  3. 22
      web/api-flight/build.gradle
  4. 284
      web/api-flight/src/main/java/kr/co/palnet/kac/api/util/AirspaceUtils.java
  5. 344
      web/api-flight/src/main/java/kr/co/palnet/kac/api/util/AreaUtils.java
  6. 22
      web/api-flight/src/main/java/kr/co/palnet/kac/api/util/model/FlightPlanAreaCoordModel.java
  7. 26
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java
  8. 11
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAllowableElevationRS.java
  9. 21
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaByAirspaceModel.java
  10. 19
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaByElevModel.java
  11. 14
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaCoordModel.java
  12. 15
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancDuplicatedAirspaceRs.java
  13. 91
      web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java

8
build.gradle

@ -32,7 +32,13 @@ allprojects {
plugins.apply("idea")
repositories {
mavenCentral()
mavenCentral {
content {
excludeModule("javax.media", "jai_core")
}
}
maven { url "https://repo.osgeo.org/repository/release" }
}
configurations {

2
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java

@ -34,7 +34,7 @@ public class ComConfirmBas {
// 상태
@Column(name = "STATUS", length = 20, nullable = false)
private String status; // `GENERATED`, `RECEIVED`, CHECKED, FAILED, EXPIRED
private String status; // GENERATED, RECEIVED, CHECKED, FAILED, EXPIRED
// 대상구분
@Column(name = "TARGET_TYPE", length = 100)

22
web/api-flight/build.gradle

@ -1,14 +1,32 @@
dependencies {
implementation "$boot:spring-boot-starter-web"
implementation "$boot:spring-boot-starter-data-jpa"
implementation 'javax.media:jai_core:1.1.3'
// thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// pdf create
implementation 'com.itextpdf:html2pdf:5.0.3'
// other
implementation 'org.apache.httpcomponents.client5:httpclient5:5.3'
implementation 'org.apache.commons:commons-io:1.3.2'
implementation 'com.itextpdf:html2pdf:5.0.3'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
// geometry
implementation 'com.esri.geometry:esri-geometry-api:2.2.4'
implementation 'org.locationtech.proj4j:proj4j:1.3.0'
implementation 'org.locationtech.proj4j:proj4j-epsg:1.3.0'
implementation 'org.locationtech.jts:jts-core:1.19.0'
implementation 'org.geotools:gt-geojson:29.2'
implementation 'org.geotools:gt-coverage:29.2'
implementation 'org.geotools:gt-geotiff:29.2'
implementation 'org.geotools:gt-epsg-hsql:29.2'
// QR Code
implementation 'com.google.zxing:core:3.5.2'
implementation 'com.google.zxing:javase:3.5.2'

284
web/api-flight/src/main/java/kr/co/palnet/kac/api/util/AirspaceUtils.java

@ -0,0 +1,284 @@
package kr.co.palnet.kac.api.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class AirspaceUtils {
private final String CLASS_PATH = "air/elev2d";
private final GeometryFactory geometryFactory = new GeometryFactory();
private List<FeatureInfo> airspaces;
private AirspaceUtils() {
// 초기화
log.info("===== AirspaceUtils init =====");
this.loadResourceAirspace();
}
public static AirspaceUtils getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final AirspaceUtils INSTANCE = new AirspaceUtils();
}
// 공영 중복 검사 - 고도x
public boolean isDuplicatedAirspace(FeatureInfo target) {
Geometry targetGeometry = target.getGeometry();
return this.airspaces.stream().anyMatch(featureInfo -> {
Geometry featureGeometry = featureInfo.getGeometry();
return featureGeometry.intersects(targetGeometry);
});
}
// 공역 중복 검사
public boolean isDuplicatedAirspaceElev(FeatureInfo target) {
if (this.airspaces == null || this.airspaces.isEmpty()) return true;
Integer targetHighElev = target.getHighElev();
if (targetHighElev == null) targetHighElev = 0;
Geometry targetGeometry = target.getGeometry();
for (FeatureInfo airspace : this.airspaces) {
Integer airspaceHighElev = airspace.getHighElev();
Geometry airspaceGeometry = airspace.getGeometry();
// 임시로 0~최대고도 기준으로 검증
if (airspaceHighElev <= targetHighElev) {
if (airspaceGeometry.intersects(targetGeometry)) {
return true;
}
}
}
return false;
}
/*
LAANC 공역 검사
- 비행구역이 공역(금지구역) 접근할 경우만 검사 - 통과 true, 실패 false
- 겹치지 않을 경우는 실패로 처리 - false
*/
public boolean isValidLaancAirspace(FeatureInfo target) {
if (this.airspaces == null || this.airspaces.isEmpty()) return true;
final int targetHighElev = target.getHighElev() != null ? target.getHighElev() : 0;
Geometry targetGeometry = target.getGeometry();
boolean isDuplicated = this.airspaces.stream().anyMatch(featureInfo -> {
Geometry featureGeometry = featureInfo.getGeometry();
return featureGeometry.intersects(targetGeometry);
});
// 공역(금지구역)과 겹치지 않을 경우는 실패로 처리
if (!isDuplicated) return false;
// 겹칠 경우 공역과 비교
for (FeatureInfo featureInfo : this.airspaces) {
Geometry airspaceGeometry = featureInfo.getGeometry();
int airspaceHighElev = featureInfo.getHighElev() != null ? featureInfo.getHighElev() : 0;
// 0~최대고도 기준으로 검증
if (airspaceHighElev == 0 || airspaceHighElev < targetHighElev) {
if (airspaceGeometry.intersects(targetGeometry)) {
return false;
}
}
}
return true;
}
// get allowable elevation
public Integer getAllowElevation(Geometry target) {
Integer allowElevation = null;
if (this.airspaces == null || this.airspaces.isEmpty()) return null;
// target과 겹치는 airspace 조회
List<FeatureInfo> duplicationAirspace = this.airspaces.stream().filter(featureInfo -> {
Geometry featureGeometry = featureInfo.getGeometry();
return featureGeometry.intersects(target);
}).collect(Collectors.toList());
// 중복된 airspace가 없을 경우 기본 허용고도 반환 150m(관제권x)
if (duplicationAirspace.isEmpty()) return 150;
allowElevation = duplicationAirspace.stream().map(FeatureInfo::getHighElev).min(Integer::compareTo).orElse(150);
return allowElevation;
}
// convert coordiate to geometry
public Geometry createGeometryByCoordinate(List<Coordinate> target) {
return this.createGeometryByCoordinate(target, "Polygon");
}
// convert coordiate to geometry
public Geometry createGeometryByCoordinate(List<Coordinate> target, String type) {
Geometry geometry = null;
if ("Polygon".equals(type)) {
if (target == null || target.isEmpty()) return null;
log.info(">>> {}", target.get(0) != target.get(target.size() - 1));
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 ("LineString".equals(type)) {
geometry = this.geometryFactory.createLineString(target.toArray(new Coordinate[0]));
} else if ("Point".equals(type)) {
geometry = this.geometryFactory.createPoint(target.get(0));
}
return geometry;
}
// get geometry
private List<Geometry> getAirspaceGeometry() {
return this.airspaces.stream().map(FeatureInfo::getGeometry).collect(Collectors.toList());
}
// 파일에서 공역 데이터 가져와서 geometry로 변환 - 초기화.
private void loadResourceAirspace() {
List<FeatureInfo> featureInfos = new ArrayList<>();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = null;
try {
resources = resolver.getResources("classpath:" + CLASS_PATH + "/*-elev.json");
} catch (IOException e) {
log.warn("airspaces load error : {}", e.getMessage());
}
if (resources == null) {
log.info("airspace resources is null");
return;
}
for (Resource resource : resources) {
try (InputStream is = resource.getInputStream()) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
List<FeatureInfo> fis = this.convertGeoJsonToGeometry(jsonObject);
featureInfos.addAll(fis);
} catch (Exception e) {
log.warn("airspace resource read error : {}", e.getMessage());
}
}
log.info(">>> featureInfos size : {}", featureInfos.size());
this.airspaces = featureInfos;
}
private List<FeatureInfo> convertGeoJsonToGeometry(JSONObject jsonObject) {
List<FeatureInfo> featureInfos = new ArrayList<>();
String type = (String) jsonObject.get("type");
if ("FeatureCollection".equals(type)) {
List<JSONObject> features = (List<JSONObject>) jsonObject.get("features");
// log.debug(">>> features size : {}", features.size());
for (JSONObject feature : features) {
JSONObject geometryObject = (JSONObject) feature.get("geometry");
String geometryType = String.valueOf(geometryObject.get("type"));
List<JSONObject> coordinatesObject = (List<JSONObject>) geometryObject.get("coordinates");
if ("Polygon".equals(geometryType)) {
List<JSONArray> innerObject = (List<JSONArray>) coordinatesObject.get(0);
JSONArray firstCoords = innerObject.get(0);
JSONArray lastCoords = innerObject.get(innerObject.size() - 1);
BigDecimal ff = new BigDecimal(String.valueOf(firstCoords.get(0)));
BigDecimal fl = new BigDecimal(String.valueOf(firstCoords.get(1)));
BigDecimal lf = new BigDecimal(String.valueOf(lastCoords.get(0)));
BigDecimal ll = new BigDecimal(String.valueOf(lastCoords.get(1)));
if (!ff.equals(lf) || !fl.equals(ll)) {
JSONObject propertiesObject = (JSONObject) feature.get("properties");
// String nameObject = String.valueOf(propertiesObject.get("name"));
// String descriptionObject = String.valueOf(propertiesObject.get("description"));
// log.info("coords first and last coords not eqauls : name/descriion = {}/{}", nameObject, descriptionObject);
innerObject.add(firstCoords);
}
}
try {
FeatureJSON featureJSON = new FeatureJSON();
SimpleFeature simpleFeature = null;
simpleFeature = featureJSON.readFeature(feature.toJSONString());
Boolean use = Boolean.valueOf(String.valueOf(simpleFeature.getAttribute("use")));
if (use) {
String name = String.valueOf(simpleFeature.getAttribute("name"));
String description = String.valueOf(simpleFeature.getAttribute("description"));
Integer lowElev = Integer.parseInt(String.valueOf(simpleFeature.getAttribute("lowElev")));
Integer highElev = Integer.parseInt(String.valueOf(simpleFeature.getAttribute("highElev")));
Geometry geometry = (Geometry) simpleFeature.getDefaultGeometry();
// log.debug(">>> name, description, use, lowElev, highElev : {}, {}, {}, {}, {}", name, description, use, lowElev, highElev);
FeatureInfo info = new FeatureInfo(name, description, lowElev, highElev, geometry);
featureInfos.add(info);
}
} catch (IOException e) {
log.error("geometry json read error : {}", e.getMessage());
}
}
} else if ("Feature".equals(type)) {
FeatureJSON featureJSON = new FeatureJSON();
try {
SimpleFeature simpleFeature = featureJSON.readFeature(jsonObject.toJSONString());
Boolean use = Boolean.valueOf(String.valueOf(simpleFeature.getAttribute("use")));
if (use) {
String name = String.valueOf(simpleFeature.getAttribute("name"));
String description = String.valueOf(simpleFeature.getAttribute("description"));
Integer lowElev = Integer.parseInt(String.valueOf(simpleFeature.getAttribute("lowElev")));
Integer highElev = Integer.parseInt(String.valueOf(simpleFeature.getAttribute("highElev")));
Geometry geometry = (Geometry) simpleFeature.getDefaultGeometry();
FeatureInfo info = new FeatureInfo(name, description, lowElev, highElev, geometry);
featureInfos.add(info);
}
} catch (IOException e) {
log.error("geometry json read error : {}", e.getMessage());
}
} else {
GeometryJSON geoJson = new GeometryJSON();
try {
Geometry geometry = geoJson.read(jsonObject.toJSONString());
FeatureInfo info = new FeatureInfo(null, null, null, null, geometry);
} catch (IOException e) {
log.error("geometry json read error : {}", e.getMessage());
}
}
return featureInfos;
}
public int getSize() {
if(this.airspaces == null) return 0;
return this.airspaces.size();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureInfo {
private String name;
private String description;
private Integer lowElev;
private Integer highElev;
private Geometry geometry;
}
}

344
web/api-flight/src/main/java/kr/co/palnet/kac/api/util/AreaUtils.java

@ -0,0 +1,344 @@
package kr.co.palnet.kac.api.util;
import kr.co.palnet.kac.api.util.model.FlightPlanAreaCoordModel;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.operation.buffer.BufferOp;
import org.locationtech.jts.operation.buffer.BufferParameters;
import org.locationtech.jts.util.GeometricShapeFactory;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.ProjCoordinate;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@Slf4j
public class AreaUtils {
private List<Polygon> polygons = new ArrayList<>();
private List<Point> points = new ArrayList<>();
private GeometryFactory geometryFactory = new GeometryFactory();
public AreaUtils() throws Exception {
this.init();
}
/**
* TODO 좌표계 변환
*
* @param coordList
* @return
*/
@Cacheable(value = "coordTransform")
public List<Coordinate> transform(List<Coordinate> coordList, String from, String to) {
CRSFactory factory = new CRSFactory();
CoordinateReferenceSystem srcCRS = factory.createFromName(from);
CoordinateReferenceSystem tgtCRS = factory.createFromName(to);
BasicCoordinateTransform transform = new BasicCoordinateTransform(srcCRS, tgtCRS);
List<Coordinate> result = new ArrayList<>();
for(Coordinate coord : coordList) {
ProjCoordinate projCoordinate = new ProjCoordinate(coord.getX(), coord.getY());
ProjCoordinate projTrasform = transform.transform(projCoordinate, new ProjCoordinate());
Coordinate target = new Coordinate(projTrasform.x, projTrasform.y);
result.add(target);
}
return result;
}
/**
* TODO 비행 구역 생성시 장애물 영역 포함 체크
*
* @param targetCoordList - 비행구역 좌표 리스트
* @return boolean - true(비정상), false(정상)
*/
public boolean overlaps(List<Coordinate> targetCoordList) {
boolean result = false;
targetCoordList.add(targetCoordList.get(0));
Polygon targetPolygon = geometryFactory.createPolygon(targetCoordList.toArray(new Coordinate[] {}));
/* 공역 데이터 */
if(polygons.size() > 0) {
for(Polygon polygon : polygons) {
Geometry overlabsGeometry = geometryFactory.createGeometry(polygon);
Geometry targetGeometry = geometryFactory.createGeometry(targetPolygon);
boolean over = targetPolygon.overlaps(polygon);
if(over) {
result = true;
break;
}
}
}
return result;
}
/**
* TODO 구역 포함 여부
*
* @param targetCoordList - 생성 구역
* @param effectiveCoordList - 유효한 비행 구역
* @return boolean - true(비정상), false(정상)
*/
public boolean overlaps(List<Coordinate> targetCoordList, List<Coordinate> effectiveCoordList) {
targetCoordList.add(targetCoordList.get(0));
Polygon targetPolygon = geometryFactory.createPolygon(targetCoordList.toArray(new Coordinate[] {}));
effectiveCoordList.add(effectiveCoordList.get(0));
Polygon effectivePolygon = geometryFactory.createPolygon(effectiveCoordList.toArray(new Coordinate[] {}));
return targetPolygon.overlaps(effectivePolygon);
}
/**
* TODO 드론 관제시 정상 비행 체크 (공역)
*
* @param targetCoordinate - 드론 좌표 정보
* @return boolean - true(비정상), false(정상)
*/
public boolean contains(Coordinate targetCoordinate) {
boolean result = true;
Point target = geometryFactory.createPoint(targetCoordinate);
for(Polygon polygon : polygons) {
boolean contains = polygon.contains(target);
if(contains) {
result = true;
break;
}
}
return result;
}
/**
* TODO 드론 관제시 정상 비행 체크 (비행 구역)
*
* @param areaCoordList - 비행 구역 좌표 리스트
* @param targetCoordinate - 드론 좌표 정보
* @return boolean - true(비정상), false(정상)
*/
public boolean contains(List<Coordinate> areaCoordList, Coordinate targetCoordinate) {
boolean result = true;
areaCoordList.add(areaCoordList.get(0));
if(targetCoordinate != null) {
Polygon plan = geometryFactory.createPolygon(areaCoordList.toArray(new Coordinate[]{})); // 비행 구역
Point target = geometryFactory.createPoint(targetCoordinate);
result = plan.contains(target);
// target.contains(plan);
}
return result;
}
/**
* TODO 비행 구역 - Buffer 영역 생성
*
* @param coordList - 비행 구역 기초 좌표 리스트
* @param bufferZone - 반경
*
*/
public List<Coordinate> buffer(List<Coordinate> coordList, double bufferZone) {
List<Coordinate> bufferList = new ArrayList<>();
LineString line = geometryFactory.createLineString(coordList.toArray(new Coordinate[] {}));
Geometry geometry = geometryFactory.createGeometry(line);
// buffer
int nSegments = 10;
int cap = BufferParameters.CAP_SQUARE;
int join = BufferParameters.JOIN_ROUND;
BufferParameters bufferParam = new BufferParameters(nSegments, cap, join, join);
BufferOp ops = new BufferOp(geometry, bufferParam);
// Geometry bufTrans = ops.getResultGeometry((bufferZone/177763.63662580872)*2);
Geometry bufTrans = ops.getResultGeometry(bufferZone);
Coordinate[] coords = bufTrans.getCoordinates();
bufferList.addAll(Arrays.asList(coords));
return bufferList;
}
/**
* TODO 타원 생성
*
* @param CircleCoord
* @param BufferZone
* @return
*/
public List<Coordinate> createCircle(Coordinate CircleCoord, double BufferZone) {
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
double lng = CircleCoord.x;
double lat = CircleCoord.y;
double diameterInMeters = BufferZone;
shapeFactory.setCentre(new Coordinate(lng , lat));
shapeFactory.setHeight((diameterInMeters * 2) / 111320d);
shapeFactory.setWidth((diameterInMeters * 2) / (40075000 * Math.cos(Math.toRadians(lat)) / 360));
shapeFactory.setNumPoints(64);
final Polygon circle = shapeFactory.createCircle();
circle.setSRID(4326);
Geometry geometry = geometryFactory.createGeometry(circle);
Coordinate[] coords = geometry.getCoordinates();
List<Coordinate> coordList = new ArrayList<>();
coordList.addAll(Arrays.asList(coords));
return coordList;
}
/**
* TODO service model -> jts model mapping
*
* @param coordList
* @return
*/
public List<Coordinate> convertCoordinates(List<FlightPlanAreaCoordModel> coordList) {
List<Coordinate> coordinates = new ArrayList<>();
for(FlightPlanAreaCoordModel coord : coordList) {
Coordinate coordinate = new Coordinate(coord.getLon(), coord.getLat());
coordinates.add(coordinate);
}
return coordinates;
}
/**
* TODO jts model -> service model mapiing
*
* @param bufferList
* @return
*/
public List<FlightPlanAreaCoordModel> convertModel(List<Coordinate> bufferList) {
List<FlightPlanAreaCoordModel> bufferCoordList = new ArrayList<>();
for(Coordinate buffer : bufferList) {
FlightPlanAreaCoordModel bufferCoord = new FlightPlanAreaCoordModel();
bufferCoord.setLat(buffer.getY());
bufferCoord.setLon(buffer.getX());
bufferCoordList.add(bufferCoord);
}
return bufferCoordList;
}
// TODO 공역 데이터 생성
public void init() throws Exception {
// 1. file read
ClassPathResource resource = new ClassPathResource("air/airgeo.json");
InputStream jsonInputStream = resource.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(jsonInputStream, "UTF-8");
BufferedReader reader = new BufferedReader(inputStreamReader);
// 2. json parsing
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
List<JSONObject> features = (List<JSONObject>) jsonObject.get("features");
for(int i=0; i<features.size(); i++) {
JSONObject geometry = (JSONObject) features.get(i).get("geometry");
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates");
String type = (String) geometry.get("type");
if("Polygon".equals(type)) {
for(JSONArray coordList : coordinates) {
List<Coordinate> polygonPaths = new ArrayList<>();
for(Object coord : coordList) {
Object y = ((JSONArray) coord).get(0);
Object x = ((JSONArray) coord).get(1);
Double lon = y instanceof Double ? (Double) y : Double.valueOf((Long) y);
Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x);
Coordinate areaCoord = new Coordinate(lon, lat);
polygonPaths.add(areaCoord);
}
Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[] {}));
polygons.add(polygon);
}
}
if("LineString".equals(type)) {
List<Coordinate> lineStringPaths = new ArrayList<>();
for(JSONArray coordList : coordinates) {
Object y = coordList.get(0);
Object x = coordList.get(1);
Double lon = y instanceof Double ? (Double) y : Double.valueOf((Long) y);
Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x);
Coordinate areaCoord = new Coordinate(lon, lat);
lineStringPaths.add(areaCoord);
}
Polygon polygon = geometryFactory.createPolygon(lineStringPaths.toArray(new Coordinate[] {}));
polygons.add(polygon);
}
if("Point".equals(type)) {
Object y = coordinates.get(0);
Object x = coordinates.get(1);
Double lon = y instanceof Double ? (Double) y : Double.valueOf((Long) y);
Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x);
Coordinate areaCoord = new Coordinate(lon, lat);
Point point = geometryFactory.createPoint(areaCoord);
points.add(point);
}
}
}
public Geometry coordinateToGeometry(List<Coordinate> target) {
if (target == null || target.isEmpty()) return null;
log.info(">>> {}", target.get(0) != target.get(target.size() - 1));
if (target.get(0) != target.get(target.size() - 1)) {
target.add(target.get(0));
}
return geometryFactory.createPolygon(target.toArray(new Coordinate[]{}));
}
}

22
web/api-flight/src/main/java/kr/co/palnet/kac/api/util/model/FlightPlanAreaCoordModel.java

@ -0,0 +1,22 @@
package kr.co.palnet.kac.api.util.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class FlightPlanAreaCoordModel {
private Integer planAreaCoordSno;
private Integer planAreaSno;
@Schema(description = "x 좌표", example = "37.5208864")
private double lat;
@Schema(description = "y 좌표", example = "126.6071164")
private double lon;
@Schema(hidden = true)
private String createUserId;
@Schema(hidden = true)
private LocalDateTime createDt;
@Schema(hidden = true)
private String docState = "R";
}

26
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java

@ -7,6 +7,10 @@ import kr.co.palnet.kac.api.v1.flight.laanc.model.create.CreateLaancPlanRS;
import kr.co.palnet.kac.api.v1.flight.laanc.model.pliotvalid.PilotValidRs;
import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRQ;
import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRS;
import kr.co.palnet.kac.api.v1.flight.laanc.model.valid.LaancAllowableElevationRS;
import kr.co.palnet.kac.api.v1.flight.laanc.model.valid.LaancAreaByAirspaceModel;
import kr.co.palnet.kac.api.v1.flight.laanc.model.valid.LaancAreaByElevModel;
import kr.co.palnet.kac.api.v1.flight.laanc.model.valid.LaancDuplicatedAirspaceRs;
import kr.co.palnet.kac.api.v1.flight.laanc.service.FlightLaancService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -14,6 +18,8 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/v1/flight/laanc")
@ -50,6 +56,26 @@ public class FlightLaancController {
return ResponseEntity.ok().body(result);
}
@PostMapping("/valid/duplicated/airspace")
@Operation(summary = "공역(금지구역) 체크", description = "공역(금지구역)에 현좌표가 포함되어있는지 확인합니다.")
public ResponseEntity<List<LaancDuplicatedAirspaceRs>> getDuplicatedAirspace(@RequestBody List<LaancAreaByAirspaceModel> rq) {
List<LaancDuplicatedAirspaceRs> result = flightLaancService.getDuplicatedAirspace(rq);
return ResponseEntity.ok().body(result);
}
@PostMapping("/valid/elev")
@Operation(summary = "비행구역 허용고도 조회", description = "좌표에 해당하는 허용고도 조회")
public ResponseEntity<LaancAllowableElevationRS> getAllowableElevation(@RequestBody List<LaancAreaByElevModel> rq){
LaancAllowableElevationRS result = flightLaancService.getAllowableElevation(rq);
return ResponseEntity.ok().body(result);
}

11
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAllowableElevationRS.java

@ -0,0 +1,11 @@
package kr.co.palnet.kac.api.v1.flight.laanc.model.valid;
import lombok.Data;
import java.util.List;
@Data
public class LaancAllowableElevationRS {
private List<Integer> allowableElevation;
}

21
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaByAirspaceModel.java

@ -0,0 +1,21 @@
package kr.co.palnet.kac.api.v1.flight.laanc.model.valid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class LaancAreaByAirspaceModel {
@Schema(description = "구역종류", example = "CIRCLE")
private String areaType;
@Schema(description = "버퍼존", example = "100")
private Integer bufferZone;
@Schema(description = "고도", example = "110")
private String fltElev;
private List<LaancAreaCoordModel> coordList;
}

19
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaByElevModel.java

@ -0,0 +1,19 @@
package kr.co.palnet.kac.api.v1.flight.laanc.model.valid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class LaancAreaByElevModel {
@Schema(description = "구역종류", example = "CIRCLE")
private String areaType;
@Schema(description = "버퍼존", example = "100")
private Integer bufferZone;
private List<LaancAreaCoordModel> coordList;
}

14
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancAreaCoordModel.java

@ -0,0 +1,14 @@
package kr.co.palnet.kac.api.v1.flight.laanc.model.valid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class LaancAreaCoordModel {
@Schema(description = "위도", example = "127.33")
private double lat;
@Schema(description = "경도", example = "37.99")
private double lon;
}

15
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/valid/LaancDuplicatedAirspaceRs.java

@ -0,0 +1,15 @@
package kr.co.palnet.kac.api.v1.flight.laanc.model.valid;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class LaancDuplicatedAirspaceRs {
private boolean isDuplicated;
private LaancAreaByAirspaceModel rq;
}

91
web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java

@ -1,15 +1,16 @@
package kr.co.palnet.kac.api.v1.flight.laanc.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import kr.co.palnet.kac.api.external.model.TsQRcodeRQ;
import kr.co.palnet.kac.api.external.service.CtrTrnsLctnService;
import kr.co.palnet.kac.api.external.service.TsService;
import kr.co.palnet.kac.api.util.*;
import kr.co.palnet.kac.api.v1.flight.laanc.model.create.CstmrModel;
import kr.co.palnet.kac.api.v1.flight.laanc.model.*;
import kr.co.palnet.kac.api.v1.flight.laanc.model.create.*;
import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRQ;
import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRS;
import kr.co.palnet.kac.api.v1.flight.laanc.model.valid.*;
import kr.co.palnet.kac.data.com.domain.ComConfirmBas;
import kr.co.palnet.kac.data.com.service.ComConfirmDomainService;
import kr.co.palnet.kac.data.other.service.OtherDomainService;
@ -30,9 +31,6 @@ import kr.co.palnet.kac.data.pty.service.PtyCstmrDomainService;
import kr.co.palnet.kac.data.pty.service.PtyGroupDomainService;
import kr.co.palnet.kac.data.pty.service.PtyTermsDomainService;
import kr.co.palnet.kac.api.external.service.ComnSmsService;
import kr.co.palnet.kac.api.util.DateUtils;
import kr.co.palnet.kac.api.util.FileUtils;
import kr.co.palnet.kac.api.util.HttpUtils;
import kr.co.palnet.kac.api.util.model.LaancPdfModel;
import kr.co.palnet.kac.util.EncryptUtil;
import kr.co.palnet.kac.util.ObjectMapperUtils;
@ -45,11 +43,11 @@ import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import com.google.zxing.WriterException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
@Service
@ -79,6 +77,8 @@ public class FlightLaancService {
//
private final FileUtils fileUtils;
private final AreaUtils areaUtils;
@Value("${app.host}")
private String APP_HOST;
@ -419,4 +419,83 @@ public class FlightLaancService {
return rs;
}
public List<LaancDuplicatedAirspaceRs> getDuplicatedAirspace(List<LaancAreaByAirspaceModel> rq) {
// TODO :: 임시로 모듈안에 Util 만들어서 사용, 추후 만들어진 것으로 사용할 것
AirspaceUtils airspaceUtils = AirspaceUtils.getInstance();
List<LaancDuplicatedAirspaceRs> rs = new ArrayList<>();
for (LaancAreaByAirspaceModel area : rq) {
//rq로 들어온 좌표로 버퍼좌표 생성
List<Coordinate> targetCoord = new ArrayList<>();
List<Coordinate> targetCoordBufferList = new ArrayList<>();
for (LaancAreaCoordModel basLaancAreaCoordModel : area.getCoordList()) {
Coordinate coords = new Coordinate(basLaancAreaCoordModel.getLon(), basLaancAreaCoordModel.getLat());
targetCoord.add(coords);
}
if ("LINE".equals(area.getAreaType())) {
List<Coordinate> trans = areaUtils.transform(targetCoord, "EPSG:4326", "EPSG:5181");
List<Coordinate> bufferList = areaUtils.buffer(trans, area.getBufferZone());
targetCoordBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326");
} else if ("POLYGON".equals(area.getAreaType())) {
targetCoordBufferList.addAll(targetCoord);
} else if ("CIRCLE".equals(area.getAreaType())) {
targetCoordBufferList = areaUtils.createCircle(targetCoord.get(0), area.getBufferZone());
}
Geometry targetGeometry = airspaceUtils.createGeometryByCoordinate(targetCoordBufferList);
Integer fltElev = area.getFltElev() != null ? Integer.parseInt(area.getFltElev()) : 0;
AirspaceUtils.FeatureInfo targetFeatureInfo = new AirspaceUtils.FeatureInfo(null, null, 0, fltElev, targetGeometry);
boolean duplicatedAirspace = airspaceUtils.isDuplicatedAirspace(targetFeatureInfo);
LaancDuplicatedAirspaceRs duplicatedAirspaceRs = LaancDuplicatedAirspaceRs.builder()
.isDuplicated(duplicatedAirspace)
.rq(area)
.build();
rs.add(duplicatedAirspaceRs);
}
return rs;
}
public LaancAllowableElevationRS getAllowableElevation(List<LaancAreaByElevModel> rq) {
AirspaceUtils airspaceUtils = AirspaceUtils.getInstance();
List<Integer> allowElevationList = new ArrayList<>();
for (LaancAreaByElevModel area : rq) {
//rq로 들어온 좌표로 버퍼좌표 생성
List<Coordinate> targetCoord = new ArrayList<>();
List<Coordinate> targetCoordBufferList = new ArrayList<>();
for (LaancAreaCoordModel coord : area.getCoordList()) {
Coordinate coords = new Coordinate(coord.getLon(), coord.getLat());
targetCoord.add(coords);
}
if ("LINE".equals(area.getAreaType())) {
List<Coordinate> trans = areaUtils.transform(targetCoord, "EPSG:4326", "EPSG:5181");
List<Coordinate> bufferList = areaUtils.buffer(trans, area.getBufferZone());
targetCoordBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326");
} else if ("POLYGON".equals(area.getAreaType())) {
targetCoordBufferList.addAll(targetCoord);
} else if ("CIRCLE".equals(area.getAreaType())) {
targetCoordBufferList = areaUtils.createCircle(targetCoord.get(0), area.getBufferZone());
}
Geometry targetGeometry = airspaceUtils.createGeometryByCoordinate(targetCoordBufferList);
// Integer fltElev = area.getFltElev() != null ? Integer.parseInt(area.getFltElev()) : 0;
// AirspaceUtils.FeatureInfo featureInfo = new AirspaceUtils.FeatureInfo(null, null, 0, fltElev, rqGeometry);
Integer allowElevation = airspaceUtils.getAllowElevation(targetGeometry);
allowElevationList.add(allowElevation);
}
LaancAllowableElevationRS result = new LaancAllowableElevationRS();
result.setAllowableElevation(allowElevationList);
return result;
}
}

Loading…
Cancel
Save