From 7abb6439ccfff9de4f73eed0c5763abb2b4c07e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dhji=28=EC=A7=80=EB=8C=80=ED=95=9C=29?= Date: Thu, 12 Sep 2024 18:39:51 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=98=81=EC=97=AD(=EB=B2=94?= =?UTF-8?q?=EC=9C=84)=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A1=9C=20=EB=8B=B4?= =?UTF-8?q?=EB=8B=B9=EB=B6=80=EC=84=9C=20=EB=B0=98=ED=99=98=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http/server/common.http | 4 + .../model/CompotentAuthorityItemRS.java | 37 + .../model/CompotentAuthorityRQ.java | 8 +- .../model/CompotentAuthorityRS.java | 2 +- .../service/ComnCoordinateService.java | 88 +- .../com/palnet/comn/utils/CoordUtils.java | 1116 ++++++++++------- .../service/ComnCoordinateServiceTest.java | 42 + 7 files changed, 790 insertions(+), 507 deletions(-) create mode 100644 http/server/common.http create mode 100644 pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java create mode 100644 pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java diff --git a/http/server/common.http b/http/server/common.http new file mode 100644 index 00000000..46ef843c --- /dev/null +++ b/http/server/common.http @@ -0,0 +1,4 @@ +### 좌표 to 관할지역 +GET {{appHost}}/api/comn/coordinate/comptent-authority + ?lat=37.5666103&lon=126.978 +Authorization: {{accessToken}} diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java new file mode 100644 index 00000000..2e7d68c5 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java @@ -0,0 +1,37 @@ +package com.palnet.biz.api.comn.coordinate.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CompotentAuthorityItemRS { + + // 관할기관코드 + private String cptAuthCode; + + // 관할기관명 + private String cptAuthNm; + + // 관할기관연락처 + private String cptAuthTp; + + // 관할기관FAX + private String cptAuthFax; + + // 비고 + private String rm; + + // 수정일자 + private Instant updateDt; + + // 생성일자 + private Instant createDt; + +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java index b76efeae..dd604af5 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java @@ -1,12 +1,18 @@ package com.palnet.biz.api.comn.coordinate.model; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class CompotentAuthorityRQ { private Double lat; private Double lon; - + } diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java index 672c6193..b7320148 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java @@ -13,6 +13,6 @@ public class CompotentAuthorityRS { private String address; - private List fltCptpAuthBasList; + private List fltCptpAuthBasList; } diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java index adde2210..cb561164 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java @@ -1,20 +1,17 @@ package com.palnet.biz.api.comn.coordinate.service; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil; import com.palnet.biz.api.comn.coordinate.model.*; import com.palnet.biz.jpa.entity.ComAdmDistrictBas; +import com.palnet.biz.jpa.entity.FltCptAuthBas; import com.palnet.biz.jpa.repository.com.ComAdmDistrictBasRepository; import com.palnet.biz.jpa.repository.flt.FltCptAuthAdmDistrictRelRepository; +import com.palnet.biz.jpa.repository.flt.FltCptAuthAdminDistrictBasQueryRepository; import com.palnet.comn.code.ErrorCode; import com.palnet.comn.exception.CustomException; +import com.palnet.comn.utils.CoordUtils; +import com.palnet.comn.utils.DmsUtils; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.json.simple.JSONObject; import org.json.simple.parser.ParseException; @@ -24,12 +21,13 @@ import org.locationtech.jts.geom.GeometryFactory; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import com.palnet.biz.jpa.entity.FltCptAuthBas; -import com.palnet.biz.jpa.repository.flt.FltCptAuthAdminDistrictBasQueryRepository; -import com.palnet.comn.utils.CoordUtils; -import com.palnet.comn.utils.DmsUtils; - -import lombok.RequiredArgsConstructor; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -50,9 +48,9 @@ public class ComnCoordinateService { Coordinate coord = new Coordinate(rq.getLat(), rq.getLon()); CoordUtils utils = CoordUtils.getInstance(); - + String dms = DmsUtils.convertDDtoDMS(coord); - + JSONObject code = new JSONObject(); try { code = utils.getPlace(coord); @@ -63,24 +61,74 @@ public class ComnCoordinateService { String[] scope = {"ctprvn", "sig", "emd", "li"}; final String cd = (String) code.get("CD"); - Set fltCptAuthBas = new HashSet<>(); + Set fltCptAuthBas = new HashSet<>(); for (String s : scope) { String cdParam = CoordUtils.getInstance().addAdmCd(cd, s); List authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam); - fltCptAuthBas.addAll(new HashSet<>(authList)); + List itemList = authList.stream().map(item -> CompotentAuthorityItemRS.builder() + .cptAuthCode(item.getCptAuthCode()) + .cptAuthNm(item.getCptAuthNm()) + .cptAuthTp(item.getCptAuthTp()) + .cptAuthFax(item.getCptAuthFax()) + .rm(item.getRm()) + .updateDt(item.getUpdateDt()) + .createDt(item.getCreateDt()) + .build()).collect(Collectors.toList()); + + fltCptAuthBas.addAll(new HashSet<>(itemList)); } CompotentAuthorityRS result = new CompotentAuthorityRS(); - + result.setFltCptpAuthBasList(new ArrayList<>(fltCptAuthBas)); result.setDMS(dms); result.setAddress(code.get("address").toString()); - + return result; } + public List getCompetentAuthority(List rq) { + + CoordUtils utils = CoordUtils.getInstance(); + + List coords = rq.stream().map(r -> new Coordinate(r.getLat(), r.getLon())).collect(Collectors.toList()); + List codeList = utils.getPlace(coords); + + String[] scope = {"ctprvn", "sig", "emd", "li"}; + + Set list = new HashSet<>(); + + for (JSONObject code : codeList) { + final String cd = (String) code.get("CD"); + + + + for (String s : scope) { + String cdParam = CoordUtils.getInstance().addAdmCd(cd, s); + List authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam); + + List itemList = authList.stream().map(item -> CompotentAuthorityItemRS.builder() + .cptAuthCode(item.getCptAuthCode()) + .cptAuthNm(item.getCptAuthNm()) + .cptAuthTp(item.getCptAuthTp()) + .cptAuthFax(item.getCptAuthFax()) + .rm(item.getRm()) + .updateDt(item.getUpdateDt()) + .createDt(item.getCreateDt()) + .build()).collect(Collectors.toList()); + + list.addAll(new HashSet<>(itemList)); + } + } + + log.debug("list : {}", list); + return new ArrayList<>(list); + } + + + public SearchAddressCoordinateRS getCoordinateByAddress(SearchAddressCoordinateRQ rq) { String address = rq.getAddress(); diff --git a/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java index 444c216b..e2c60c3f 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java @@ -1,289 +1,284 @@ package com.palnet.comn.utils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.regex.Pattern; - import com.palnet.comn.code.ErrorCode; import com.palnet.comn.exception.CustomException; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.geom.*; import org.springframework.core.io.ClassPathResource; -import lombok.extern.slf4j.Slf4j; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; @Slf4j public class CoordUtils { - private final String basePath = "air/coordinateFolder/"; - - private static final CoordUtils INSTANCE = new CoordUtils(); - - private final String baseFileName = "all_location.geojson"; - - private List allLocation; - - private GeometryFactory geometryFactory = new GeometryFactory(); - - private CoordUtils() { - - this.locationInit(); - } - - public static CoordUtils getInstance() { - return INSTANCE; - } - + private final String basePath = "air/coordinateFolder/"; + + private static final CoordUtils INSTANCE = new CoordUtils(); + + private final String baseFileName = "all_location.geojson"; + + private List allLocation; + + private GeometryFactory geometryFactory = new GeometryFactory(); + + private CoordUtils() { + + this.locationInit(); + } + + public static CoordUtils getInstance() { + return INSTANCE; + } + public int getSize() { - if(this.allLocation == null) return 0; + if (this.allLocation == null) return 0; return this.allLocation.size(); } - - public void locationInit() { - - List result = new ArrayList(); - + + public void locationInit() { + + List result = new ArrayList(); + ExecutorService executorService = Executors.newFixedThreadPool(10); Integer[] coords = {11, 26, 27, 28, 29, 30, 31, 36, 41, 43, 44, 45, 46, 47, 48, 50, 51}; - + List> callables = new ArrayList<>(); for (int i = 0; i < coords.length; i++) { - - int path = i; + + int path = i; callables.add(() -> initCoordinates(coords[path])); - + } - + try { - - List> results = new ArrayList<>(); - - for (Callable callable : callables) { - results.add(executorService.submit(callable)); - } + + List> results = new ArrayList<>(); + + for (Callable callable : callables) { + results.add(executorService.submit(callable)); + } executorService.shutdown(); - for (Future rslt : results) { - - result.add(rslt.get()); - - } + for (Future rslt : results) { + + result.add(rslt.get()); + + } } catch (Exception e) { - log.error("", e); + log.error("", e); } - + this.allLocation = result; - } - - public JSONObject initCoordinates(Integer coords) { - - JSONObject jsonObject = new JSONObject(); - - String path = basePath + coords + "/" + baseFileName; - - try(InputStream inputStream = new ClassPathResource(path).getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192)) { - - JSONParser jsonParser = new JSONParser(); - - jsonObject = (JSONObject) jsonParser.parse(reader); - - }catch(Exception e) { - log.error("", e); - } - return jsonObject; - } - - public JSONObject getPlace(Coordinate coord) throws IOException, ParseException { - - int numberOfThreads = 5; + } + + public JSONObject initCoordinates(Integer coords) { + + JSONObject jsonObject = new JSONObject(); + + String path = basePath + coords + "/" + baseFileName; + + try (InputStream inputStream = new ClassPathResource(path).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192)) { + + JSONParser jsonParser = new JSONParser(); + + jsonObject = (JSONObject) jsonParser.parse(reader); + + } catch (Exception e) { + log.error("", e); + } + return jsonObject; + } + + public JSONObject getPlace(Coordinate coord) throws IOException, ParseException { + + int numberOfThreads = 5; ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads); - + String address = ""; - + String depth = ""; - + Double distance = 1000000.0; - + List> callables = new ArrayList<>(); for (int i = 0; i < allLocation.size(); i++) { - - int path = i; + + int path = i; callables.add(() -> getCoordinateGis(coord, allLocation.get(path))); - + } - + try { - - List> results = new ArrayList<>(); - - for (Callable callable : callables) { - results.add(executorService.submit(callable)); - } + + List> results = new ArrayList<>(); + + for (Callable callable : callables) { + results.add(executorService.submit(callable)); + } executorService.shutdown(); - - for (Future rslt : results) { - - JSONObject jsonObject = new JSONObject(); - - try { - - jsonObject = rslt.get(); - - } catch (InterruptedException | ExecutionException e) { - - jsonObject = null; - } - - if(jsonObject != null && jsonObject.get("distance") == null) { - - depth = (String) jsonObject.get("CD"); - - address = jsonObject.get("KOR_NM").toString(); - - break; - - } else if(jsonObject != null && jsonObject.get("distance") != null) { - - Double distances = (Double) jsonObject.get("distance"); - - if(distance > distances) { - - distance = distances; - - depth = (String) jsonObject.get("CD"); - - address = jsonObject.get("KOR_NM").toString(); - - } - } - } - - JSONObject result = this.getCoordinateGis(coord, depth); - - address += result.get("add"); - - result.put("address", address); - - return result; - + + for (Future rslt : results) { + + JSONObject jsonObject = new JSONObject(); + + try { + + jsonObject = rslt.get(); + + } catch (InterruptedException | ExecutionException e) { + + jsonObject = null; + } + + if (jsonObject != null && jsonObject.get("distance") == null) { + + depth = (String) jsonObject.get("CD"); + + address = jsonObject.get("KOR_NM").toString(); + + break; + + } else if (jsonObject != null && jsonObject.get("distance") != null) { + + Double distances = (Double) jsonObject.get("distance"); + + if (distance > distances) { + + distance = distances; + + depth = (String) jsonObject.get("CD"); + + address = jsonObject.get("KOR_NM").toString(); + + } + } + } + + JSONObject result = this.getCoordinateGis(coord, depth); + + address += result.get("add"); + + result.put("address", address); + + return result; + } catch (Exception e) { - log.error("", e); + log.error("", e); } - + return null; // 모든 작업이 실패한 경우 null 반환 } - - public JSONObject getCoordinateGis(Coordinate coordinate, JSONObject polygon) throws IOException, ParseException { - - JSONObject obj = new JSONObject(); - obj = parseGeoJson(polygon, coordinate); + public JSONObject getCoordinateGis(Coordinate coordinate, JSONObject polygon) throws IOException, ParseException { + + JSONObject obj = new JSONObject(); - if(obj == null) return null; + obj = parseGeoJson(polygon, coordinate); - return obj; + if (obj == null) return null; + + return obj; } - - public JSONObject getCoordinateGis(Coordinate coordinate, String depth) throws IOException, ParseException { - - JSONObject obj = new JSONObject(); - - String address = ""; - - String path = basePath + depth.substring(0,2) + "/" + depth + "/"; - - while(true) { - - ClassPathResource classPathResource = new ClassPathResource(path+baseFileName); - - if(!classPathResource.exists()) { - - obj.put("add", address); - - return obj; - } - - obj = parseGeoJson(path+baseFileName, coordinate); - - if(obj == null) return null; - - address += " " + obj.get("KOR_NM"); - - path += obj.get("CD")+"/"; - - } + + public JSONObject getCoordinateGis(Coordinate coordinate, String depth) throws IOException, ParseException { + + JSONObject obj = new JSONObject(); + + String address = ""; + + String path = basePath + depth.substring(0, 2) + "/" + depth + "/"; + + while (true) { + + ClassPathResource classPathResource = new ClassPathResource(path + baseFileName); + + if (!classPathResource.exists()) { + + obj.put("add", address); + + return obj; + } + + obj = parseGeoJson(path + baseFileName, coordinate); + + if (obj == null) return null; + + address += " " + obj.get("KOR_NM"); + + path += obj.get("CD") + "/"; + + } } - - public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException { - + + + public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException { + Point point = geometryFactory.createPoint(coordinate); String type = (String) obj.get("type"); - + List features = (List) obj.get("features"); return this.contains(features, point); - + } - - public JSONObject parseGeoJson(String path, Coordinate coordinate){ - - List features = new ArrayList(); - - Point point = null; - - try(InputStream inputStream = new ClassPathResource(path).getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { - JSONParser jsonParser = new JSONParser(); + public JSONObject parseGeoJson(String path, Coordinate coordinate) { - JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); + List features = new ArrayList(); + Point point = null; - point = geometryFactory.createPoint(coordinate); + try (InputStream inputStream = new ClassPathResource(path).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { - features = (List) jsonObject.get("features"); + JSONParser jsonParser = new JSONParser(); - }catch(Exception e) { - log.error("", e); - } + JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); - - return this.contains(features, point); - - } - public JSONObject contains(List features, Point point) { - - JSONObject result = null; - - Double standard = 10000000.0; - for(int i=0; i) jsonObject.get("features"); + + } catch (Exception e) { + log.error("", e); + } + + + return this.contains(features, point); + + } + + public JSONObject contains(List features, Point point) { + + JSONObject result = null; + + Double standard = 10000000.0; + + for (int i = 0; i < features.size(); i++) { JSONObject geometry = (JSONObject) features.get(i).get("geometry"); @@ -291,298 +286,449 @@ public class CoordUtils { List coordinates = (List) geometry.get("coordinates"); - for(int k = 0; k< coordinates.size(); k++) { + for (int k = 0; k < coordinates.size(); k++) { - List polygonPaths = new ArrayList<>(); + List polygonPaths = new ArrayList<>(); - for(Object coords : coordinates.get(k)) { + for (Object coords : coordinates.get(k)) { - for(int j = 0; j<((JSONArray)coords).size(); j++) { + for (int j = 0; j < ((JSONArray) coords).size(); j++) { - Object coord = ((JSONArray) coords).get(j); + Object coord = ((JSONArray) coords).get(j); - Object x = ((JSONArray) coord).get(0); - Object y = ((JSONArray) coord).get(1); + Object x = ((JSONArray) coord).get(0); + Object y = ((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); + 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); + Coordinate areaCoord = new Coordinate(lon, lat); - polygonPaths.add(areaCoord); + polygonPaths.add(areaCoord); - } + } - polygonPaths.add(polygonPaths.get(0)); + polygonPaths.add(polygonPaths.get(0)); - } + } - Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[] {})); + Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[]{})); - if(polygon.contains(point)) { + if (polygon.contains(point)) { - return properties; + return properties; - }else { + } else { - Double distance = polygon.distance(point); + Double distance = polygon.distance(point); - if(standard > distance) { + if (standard > distance) { - standard = distance; + standard = distance; - result = properties; - } - } + result = properties; + } + } } } - + result.put("distance", standard); - - return result; - } - - /** - * 주소로 지역 바운더리 좌표 가져오기 - * @param searchAdmCd DB에서 조회한 법정동 코드[10자리] - * @param scope 지역 스코프, - * @return 지역좌표 반환 - */ - public List getCoordinateByAddress (String searchAdmCd, String scope){ - - String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope); - String admCd = this.removeAdmCd(searchAdmCd, scope); - - List locationCoordinateModelList = new ArrayList<>(); - - try (InputStream inputStream = new ClassPathResource(coordinateForderPath).getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192);) { - - JSONParser jsonParser = new JSONParser(); - JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); - List features = (List) jsonObject.get("features"); - - Optional resultJsonObject = features.stream() - .filter(feature -> { - JSONObject properties = (JSONObject) feature.get("properties"); - String cd = (String) properties.get("CD"); - - return cd.equals(admCd); - }) - .map(JSONObject::new) - .findFirst(); - - JSONObject result = resultJsonObject.orElseThrow(() -> new CustomException(ErrorCode.DATA_NO)); - JSONObject geometry = (JSONObject)result.get("geometry"); - - JSONArray coordinates = (JSONArray) geometry.get("coordinates"); - - - for(int i = 0; i < coordinates.size(); i ++){ - JSONArray arrayNode = (JSONArray)((JSONArray)coordinates.get(i)).get(0) ; - - List coordinateList = new ArrayList<>(); - - for (Object o : arrayNode) { - JSONArray node = (JSONArray) o; - Coordinate coordimateModel = new Coordinate((Double) node.get(0), (Double) node.get(1)); - coordinateList.add(coordimateModel); - } - - LocationCoordinateModel locationCoordinateModel = new LocationCoordinateModel(); - locationCoordinateModel.setIndex(i); - locationCoordinateModel.setCoordinateList(coordinateList); - - locationCoordinateModelList.add(locationCoordinateModel); - } - } catch (IOException | ParseException e) { - log.error("", e); - } - - return locationCoordinateModelList; - - } - - - - /** - * 주소의 스코프 체크 기능. - * @param address 스코프 체크할 주소 - * @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li - */ - public String getScope(String address) { - Map patternMap = new HashMap<>(); - patternMap.put("ctprvn", new String[]{ - "^[^ ]+시$", - "^[^ ]+도$" - }); - patternMap.put("sig", new String[]{ - "^[^ ]+시 [^ ]+구$", - "^[^ ]+시 [^ ]+군$", - "^[^ ]+도 [^ ]+시$", - "^[^ ]+도 [^ ]+군$", - "^[^ ]+도 [^ ]+시 [^ ]+구$" - }); - patternMap.put("emd", new String[]{ - "^[^ ]+시 [^ ]+구 [^ ]+동$", - "^[^ ]+시 [^ ]+동$", - "^[^ ]+시 [^ ]+읍$", - "^[^ ]+시 [^ ]+면$", - "^[^ ]+도 [^ ]+시 [^ ]+동$", - "^[^ ]+도 [^ ]+시 [^ ]+읍$", - "^[^ ]+도 [^ ]+시 [^ ]+면$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면$", - "^[^ ]+시 [^ ]+군 [^ ]+읍$", - "^[^ ]+시 [^ ]+군 [^ ]+면$" - }); - patternMap.put("li", new String[]{ - "^[^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", - "^[^ ]+시 [^ ]+동 [^ ]+리$", - "^[^ ]+시 [^ ]+읍 [^ ]+리$", - "^[^ ]+시 [^ ]+면 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+동 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+읍 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+면 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면 [^ ]+리$", - "^[^ ]+시 [^ ]+군 [^ ]+읍 [^ ]+리$", - "^[^ ]+시 [^ ]+군 [^ ]+면 [^ ]+리$" - }); - - for (Map.Entry entry : patternMap.entrySet()) { - for (String pattern : entry.getValue()) { - if (Pattern.matches(pattern, address)) { - return entry.getKey(); - } - } - } - - throw new CustomException(ErrorCode.NON_VALID_PARAMETER); - } - - /** - * 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 - * @param cd 조회할 법정동코드 - * @param scope 스코프 - * @return 폴더경로 - */ - private String getCodeForderPath(String cd, String scope){ - - if(cd.length() != 10) return null; - - Stack forderPathStack = new Stack<>(); - - switch (scope) { - case "li": - forderPathStack.push(cd.substring(0, 8)); - case "emd": - forderPathStack.push(cd.substring(0, 5)); - case "sig": - forderPathStack.push(cd.substring(0, 2)); - case "ctprvn": - } - - StringBuilder forderPath = new StringBuilder(); - forderPath.append(this.basePath); - - while(!forderPathStack.isEmpty()){ - forderPath.append(forderPathStack.pop()); - forderPath.append("/"); - } - - forderPath.append(this.baseFileName); - - return forderPath.toString(); - } - - /** - * 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] - * @param cd 10자리가 안되는 법정동코드 - * @param scope 현재 법정동 코드의 스코프 - * @return 10자리에 맞게 0이 추가된 법정동코드 - */ - public String addAdmCd(String cd, String scope){ - switch (scope) { - case "ctprvn": - - if(cd.length() < 2) break; - - cd = cd.substring(0, 2); - break; - case "sig": - - if(cd.length() < 5) break; - - cd = cd.substring(0, 5); - break; - case "emd": - - if(cd.length() < 8) break; - - cd = cd.substring(0, 8); - break; - case "li": - - if(cd.length() < 10) break; - - cd = cd.substring(0, 10); - break; - } - - int length = cd.length(); - int maxLength = 10; - - int difference = maxLength - length; - - StringBuilder sb = new StringBuilder(); - sb.append(cd); - - for(int i = 0; i < difference; i++){ - sb.append("0"); - } - - return sb.toString(); - } - - /** - * 스코프에 맞게 법정동코드 길이를 자르는 기능. - * @param cd 잘라낼 법정동 코드 - * @param scope 스코프 - * @return 잘라진 법정동코드 - */ - public String removeAdmCd(String cd, String scope){ - - if(cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER); - - String result = ""; - - switch (scope) { - case "li": - result = cd.substring(0, 10); - break; - case "emd": - result = cd.substring(0, 8); - break; - case "sig": - result = cd.substring(0, 5); - break; - case "ctprvn": - result = cd.substring(0, 2); - break; - default: - throw new CustomException(ErrorCode.NON_VALID_PARAMETER); - } - return result; - } - - @Data - public static class LocationCoordinateModel { - private Integer index; - private List coordinateList; - - } + + return result; + } + + /** + * 주소로 지역 바운더리 좌표 가져오기 + * + * @param searchAdmCd DB에서 조회한 법정동 코드[10자리] + * @param scope 지역 스코프, + * @return 지역좌표 반환 + */ + public List getCoordinateByAddress(String searchAdmCd, String scope) { + + String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope); + String admCd = this.removeAdmCd(searchAdmCd, scope); + + List locationCoordinateModelList = new ArrayList<>(); + + try (InputStream inputStream = new ClassPathResource(coordinateForderPath).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192);) { + + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); + List features = (List) jsonObject.get("features"); + + Optional resultJsonObject = features.stream() + .filter(feature -> { + JSONObject properties = (JSONObject) feature.get("properties"); + String cd = (String) properties.get("CD"); + + return cd.equals(admCd); + }) + .map(JSONObject::new) + .findFirst(); + + JSONObject result = resultJsonObject.orElseThrow(() -> new CustomException(ErrorCode.DATA_NO)); + JSONObject geometry = (JSONObject) result.get("geometry"); + + JSONArray coordinates = (JSONArray) geometry.get("coordinates"); + + + for (int i = 0; i < coordinates.size(); i++) { + JSONArray arrayNode = (JSONArray) ((JSONArray) coordinates.get(i)).get(0); + + List coordinateList = new ArrayList<>(); + + for (Object o : arrayNode) { + JSONArray node = (JSONArray) o; + Coordinate coordimateModel = new Coordinate((Double) node.get(0), (Double) node.get(1)); + coordinateList.add(coordimateModel); + } + + LocationCoordinateModel locationCoordinateModel = new LocationCoordinateModel(); + locationCoordinateModel.setIndex(i); + locationCoordinateModel.setCoordinateList(coordinateList); + + locationCoordinateModelList.add(locationCoordinateModel); + } + } catch (IOException | ParseException e) { + log.error("", e); + } + + return locationCoordinateModelList; + + } + + + /** + * 주소의 스코프 체크 기능. + * + * @param address 스코프 체크할 주소 + * @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li + */ + public String getScope(String address) { + Map patternMap = new HashMap<>(); + patternMap.put("ctprvn", new String[]{ + "^[^ ]+시$", + "^[^ ]+도$" + }); + patternMap.put("sig", new String[]{ + "^[^ ]+시 [^ ]+구$", + "^[^ ]+시 [^ ]+군$", + "^[^ ]+도 [^ ]+시$", + "^[^ ]+도 [^ ]+군$", + "^[^ ]+도 [^ ]+시 [^ ]+구$" + }); + patternMap.put("emd", new String[]{ + "^[^ ]+시 [^ ]+구 [^ ]+동$", + "^[^ ]+시 [^ ]+동$", + "^[^ ]+시 [^ ]+읍$", + "^[^ ]+시 [^ ]+면$", + "^[^ ]+도 [^ ]+시 [^ ]+동$", + "^[^ ]+도 [^ ]+시 [^ ]+읍$", + "^[^ ]+도 [^ ]+시 [^ ]+면$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면$", + "^[^ ]+시 [^ ]+군 [^ ]+읍$", + "^[^ ]+시 [^ ]+군 [^ ]+면$" + }); + patternMap.put("li", new String[]{ + "^[^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", + "^[^ ]+시 [^ ]+동 [^ ]+리$", + "^[^ ]+시 [^ ]+읍 [^ ]+리$", + "^[^ ]+시 [^ ]+면 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+동 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+읍 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+면 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면 [^ ]+리$", + "^[^ ]+시 [^ ]+군 [^ ]+읍 [^ ]+리$", + "^[^ ]+시 [^ ]+군 [^ ]+면 [^ ]+리$" + }); + + for (Map.Entry entry : patternMap.entrySet()) { + for (String pattern : entry.getValue()) { + if (Pattern.matches(pattern, address)) { + return entry.getKey(); + } + } + } + + throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + } + + /** + * 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 + * + * @param cd 조회할 법정동코드 + * @param scope 스코프 + * @return 폴더경로 + */ + private String getCodeForderPath(String cd, String scope) { + + if (cd.length() != 10) return null; + + Stack forderPathStack = new Stack<>(); + + switch (scope) { + case "li": + forderPathStack.push(cd.substring(0, 8)); + case "emd": + forderPathStack.push(cd.substring(0, 5)); + case "sig": + forderPathStack.push(cd.substring(0, 2)); + case "ctprvn": + } + + StringBuilder forderPath = new StringBuilder(); + forderPath.append(this.basePath); + + while (!forderPathStack.isEmpty()) { + forderPath.append(forderPathStack.pop()); + forderPath.append("/"); + } + + forderPath.append(this.baseFileName); + + return forderPath.toString(); + } + + /** + * 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] + * + * @param cd 10자리가 안되는 법정동코드 + * @param scope 현재 법정동 코드의 스코프 + * @return 10자리에 맞게 0이 추가된 법정동코드 + */ + public String addAdmCd(String cd, String scope) { + switch (scope) { + case "ctprvn": + + if (cd.length() < 2) break; + + cd = cd.substring(0, 2); + break; + case "sig": + + if (cd.length() < 5) break; + + cd = cd.substring(0, 5); + break; + case "emd": + + if (cd.length() < 8) break; + + cd = cd.substring(0, 8); + break; + case "li": + + if (cd.length() < 10) break; + + cd = cd.substring(0, 10); + break; + } + + int length = cd.length(); + int maxLength = 10; + + int difference = maxLength - length; + + StringBuilder sb = new StringBuilder(); + sb.append(cd); + + for (int i = 0; i < difference; i++) { + sb.append("0"); + } + + return sb.toString(); + } + + /** + * 스코프에 맞게 법정동코드 길이를 자르는 기능. + * + * @param cd 잘라낼 법정동 코드 + * @param scope 스코프 + * @return 잘라진 법정동코드 + */ + public String removeAdmCd(String cd, String scope) { + + if (cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + + String result = ""; + + switch (scope) { + case "li": + result = cd.substring(0, 10); + break; + case "emd": + result = cd.substring(0, 8); + break; + case "sig": + result = cd.substring(0, 5); + break; + case "ctprvn": + result = cd.substring(0, 2); + break; + default: + throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + } + return result; + } + + @Data + public static class LocationCoordinateModel { + private Integer index; + private List coordinateList; + + } + + + public List getPlace(List coords) { + Geometry target = geometryFactory.createPolygon(coords.toArray(new Coordinate[]{})); + List result = new ArrayList<>(); + List firstIntersectList = new ArrayList<>(); + + for (JSONObject location : this.allLocation) { + List features = (List) location.get("features"); + + List intersects = this.intersects(features, target); + firstIntersectList.addAll(intersects); + } + + boolean isIntersect = firstIntersectList.stream().anyMatch(properties -> properties.get("distance") == null); + if (isIntersect) { + firstIntersectList = firstIntersectList.stream().filter(properties -> properties.get("distance") == null).collect(Collectors.toList()); + } else { + JSONObject jsonObject = firstIntersectList.stream().min(Comparator.comparingDouble(properties -> (Double) properties.get("distance"))).orElse(null); + if (jsonObject != null) { + firstIntersectList = new ArrayList<>(); + firstIntersectList.add(jsonObject); + } + } + + if (firstIntersectList.isEmpty()) { + return result; + } + + for (JSONObject properties : firstIntersectList) { + List subPropertiesList = getSubPropertiesByFile(properties, target); + if(!subPropertiesList.isEmpty()) { + result.addAll(subPropertiesList); + } + } + + return result; + } + + private List getSubPropertiesByFile(JSONObject properties, Geometry target) { + String depth = properties.get("CD").toString(); + final String address = properties.get("KOR_NM").toString(); + String path = basePath + depth.substring(0, 2) + "/" + depth + "/"; + String filename = path + baseFileName; + + ClassPathResource classPathResource = new ClassPathResource(filename); + List result = new ArrayList<>(); + if (!classPathResource.exists()) { + return result; + } + List features = new ArrayList<>(); + try (InputStream inputStream = new ClassPathResource(filename).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); + features = (List) jsonObject.get("features"); + } catch (Exception e) { + log.error("", e); + } + + result = this.intersects(features, target); + + boolean isIntersect = result.stream().anyMatch(p -> p.get("distance") == null); + if (isIntersect) { + result = result.stream().filter(p -> p.get("distance") == null).collect(Collectors.toList()); + } else { + JSONObject jsonObject = result.stream().min(Comparator.comparingDouble(p -> (Double) p.get("distance"))).orElse(null); + if (jsonObject != null) { + result = new ArrayList<>(); + result.add(jsonObject); + } + } + + result.forEach(subProperties -> subProperties.put("address", address + " " + subProperties.get("KOR_NM"))); + + for (JSONObject subProperties : result) { + List subSubPropertiesList = getSubPropertiesByFile(subProperties, target); + if(!subSubPropertiesList.isEmpty()) { + result.addAll(subSubPropertiesList); + } + } + + return result; + } + + private List intersects(List features, Geometry target) { + List intersectRs = new ArrayList<>(); + JSONObject isNotInstersectRs = null; + double distance = Double.MAX_VALUE; + + for (JSONObject feature : features) { + JSONObject properties = (JSONObject) feature.get("properties"); + JSONObject geometry = (JSONObject) feature.get("geometry"); + List coordinates = (List) geometry.get("coordinates"); + + List polygons = new ArrayList<>(); + for (JSONArray coordinate : coordinates) { + List polygonPaths = new ArrayList<>(); + for (Object coords1 : coordinate) { + for (int j = 0; j < ((JSONArray) coords1).size(); j++) { + Object coord = ((JSONArray) coords1).get(j); + Object x = ((JSONArray) coord).get(0); + Object y = ((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); + } + polygonPaths.add(polygonPaths.get(0)); + } + Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[]{})); + if (!polygon.isEmpty()) { + polygons.add(polygon); + } + } + + MultiPolygon multiPolygon = null; + if (!polygons.isEmpty()) { + multiPolygon = geometryFactory.createMultiPolygon(polygons.toArray(new Polygon[]{})); + } + + if (multiPolygon != null) { + boolean isIntersects = multiPolygon.intersects(target); + if (isIntersects) { + intersectRs.add(properties); + isNotInstersectRs = null; + } else { + if (intersectRs.isEmpty()) { + double targetDistance = multiPolygon.distance(target); + if (targetDistance < distance) { + distance = targetDistance; + properties.put("distance", distance); + isNotInstersectRs = properties; + } + } + } + } else { + log.debug("multiPolygon is null"); + } + } + + if (intersectRs.isEmpty() && isNotInstersectRs != null) { + intersectRs.add(isNotInstersectRs); + } + + return intersectRs; + } } diff --git a/pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java b/pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java new file mode 100644 index 00000000..e2c52222 --- /dev/null +++ b/pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java @@ -0,0 +1,42 @@ +package com.palnet.biz.api.comn.coordinate.service; + +import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityItemRS; +import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRQ; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.ActiveProfiles; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@Slf4j +@ActiveProfiles("local")@Profile("local") +@SpringBootTest +class ComnCoordinateServiceTest { + + @Autowired + private ComnCoordinateService comnCoordinateService; + + @Test + void getCompotentAuthority() { + // given + List rq = List.of( + CompotentAuthorityRQ.builder().lat(37.566).lon(126.978).build(), + CompotentAuthorityRQ.builder().lat(37.567).lon(126.978).build(), + CompotentAuthorityRQ.builder().lat(37.567).lon(126.979).build(), + CompotentAuthorityRQ.builder().lat(37.566).lon(126.979).build(), + CompotentAuthorityRQ.builder().lat(37.566).lon(126.978).build() + ); + + // when + List result = comnCoordinateService.getCompetentAuthority(rq); + + // then + log.debug("result: {}", result); + } +} \ No newline at end of file From dcbf072d5aa8c75f185736a45e63aeb32f68d9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dhji=28=EC=A7=80=EB=8C=80=ED=95=9C=29?= Date: Fri, 13 Sep 2024 11:08:35 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EB=93=9C=EB=A1=A0=EC=9B=90?= =?UTF-8?q?=EC=8A=A4=ED=86=B1=20=EC=A0=95=EB=B3=B4=20=EB=B0=9B=EC=9D=84?= =?UTF-8?q?=EC=8B=9C=20=EB=B6=80=EC=84=9C=EA=B5=AC=EB=B3=84=20(=EB=8B=A8,?= =?UTF-8?q?=20=EA=B4=80=EC=A0=9C=EA=B6=8C=EA=B3=BC=20=EB=8B=B4=EB=8B=B9?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=EC=9D=B4=20=EB=8B=A4=EB=A5=BC=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EC=9E=88=EC=96=B4=20=ED=99=95=EC=9D=B8=20=ED=95=84?= =?UTF-8?q?=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/external/model/DosCptAuthResult.java | 17 +++++ .../external/service/DronOneStopService.java | 57 +++++++++++++++-- .../com/palnet/comn/utils/AirspaceUtils.java | 62 +------------------ 3 files changed, 72 insertions(+), 64 deletions(-) create mode 100644 pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java diff --git a/pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java b/pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java new file mode 100644 index 00000000..adb6515e --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java @@ -0,0 +1,17 @@ +package com.palnet.biz.api.external.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DosCptAuthResult { + private List cptCode; + private List controlCptCode; +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java b/pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java index 6810b921..ba592dfc 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java @@ -1,11 +1,11 @@ package com.palnet.biz.api.external.service; import com.palnet.biz.api.bas.dos.model.LimitZoneType; +import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityItemRS; +import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRQ; +import com.palnet.biz.api.comn.coordinate.service.ComnCoordinateService; import com.palnet.biz.api.comn.share.ShareService; -import com.palnet.biz.api.external.model.ApprovalCd; -import com.palnet.biz.api.external.model.DosApprovalResult; -import com.palnet.biz.api.external.model.DosPlanRq; -import com.palnet.biz.api.external.model.DosPlanRs; +import com.palnet.biz.api.external.model.*; import com.palnet.biz.jpa.entity.*; import com.palnet.biz.jpa.entity.type.ReviewedType; import com.palnet.biz.jpa.repository.dos.*; @@ -26,6 +26,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Slf4j @@ -41,6 +42,8 @@ public class DronOneStopService { private final DosFltPlanPilotRepository dosFltPlanPilotRepository; private final ShareService shareService; private final AreaUtils areaUtils; + private final ComnCoordinateService comnCoordinateService; + private final List PASS_PURPOSES = List.of("수색구조", "인명구조", "시설정검"); public DosPlanRs saveDosPlan(DosPlanRq rq) { @@ -130,6 +133,7 @@ public class DronOneStopService { // 검토결과 - approvalCd가 비대상일 경우 검토불필요 그외 대기 ReviewedType reviewedType = saveApprovalCd == ApprovalCd.UNTARGETED_AREA ? ReviewedType.UNNECESSARY : ReviewedType.WAIT; + DosCptAuthResult cptAuth = this.getCptAuth(centerCoordinate, area.getRadius()); // area save DosFltPlanArea dosFltPlanAreaInsert = DosFltPlanArea.builder() .planSno(saveDosFltPlanBas.getPlanSno()) @@ -144,6 +148,8 @@ public class DronOneStopService { .limitZone(approvalResult.getLimitZone()) .reviewedType(reviewedType) .reqElev(reqElev) + .cptCd(cptAuth.getCptCode()) + .innerCptCd(cptAuth.getControlCptCode()) .updateDt(Instant.now()) .createDt(Instant.now()) .build(); @@ -352,4 +358,47 @@ public class DronOneStopService { return distance; } + public DosCptAuthResult getCptAuth(Coordinate centerCoordinate, Double radius) { + List targetCoordinate = areaUtils.createCircle(centerCoordinate, radius); + List rq = targetCoordinate.stream().map(coordinate -> CompotentAuthorityRQ.builder() + .lat(coordinate.y) + .lon(coordinate.x) + .build()).collect(Collectors.toList()); + List competentAuthority = comnCoordinateService.getCompetentAuthority(rq); + DosCptAuthResult result = new DosCptAuthResult(); + if (competentAuthority != null && !competentAuthority.isEmpty()) { + List cptCode = competentAuthority.stream().map(CompotentAuthorityItemRS::getCptAuthCode).distinct().collect(Collectors.toList()); + result.setCptCode(cptCode); + } + // TODO 관제권 체크 후 결과 반환 + // 관제권 airspaces + Map airspaceParamMap = Map.of( + AirspaceUtils.AirspaceType.C_CONTROL_GIMPO, "F0002", // 김포항공관리사무소(안전운항과) + AirspaceUtils.AirspaceType.C_CONTROL_ULSAN, "C0001" // 울산공항출장소 +// AirspaceUtils.AirspaceType.C_CONTROL_JEJU, "F0008", // 제주지방항공청(안전운항과) + + ); + List controlCptCode = new ArrayList<>(); + AirspaceUtils airspaceUtils = AirspaceUtils.getInstance(); + Geometry targetGeometry = airspaceUtils.createGeometryByCoordinate(targetCoordinate); + for (AirspaceUtils.AirspaceType airspaceType : airspaceParamMap.keySet()) { + List airspaces = airspaceUtils.getAirspaces(airspaceType); + if (airspaces == null || airspaces.isEmpty()) { + continue; + } + String innerCptCode = airspaceParamMap.get(airspaceType); + for (AirspaceUtils.FeatureInfo airspace : airspaces) { + if (airspace.getGeometry().intersects(targetGeometry)) { + controlCptCode.add(innerCptCode); + break; + } + } + } + if (!controlCptCode.isEmpty()) { + result.setControlCptCode(controlCptCode); + } + + return result; + } + } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java index 58294446..5ce73aee 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java @@ -33,10 +33,8 @@ public class AirspaceUtils { private final String CLASS_PATH = "air" + File.separator + "airspace"; private final GeometryFactory geometryFactory = new GeometryFactory(); - // private List airspaces; private Map> airspaceMap; - private AirspaceUtils() { // 초기화 log.info("===== AirspaceUtils init ====="); @@ -77,7 +75,6 @@ public class AirspaceUtils { }); } - // 공역 중복 검사 public boolean isDuplicatedAirspaceElev(FeatureInfo target) { @@ -238,68 +235,13 @@ public class AirspaceUtils { // get geometry public List getAirspaces(AirspaceType airspaceType) { - return this.airspaceMap.get(airspaceType.name()); + return this.airspaceMap.get(airspaceType); } - /* - // 파일에서 공역 데이터 가져와서 geometry로 변환 - 초기화. - private void loadResourceAirspace() { - - Map> featureInfoMap = new HashMap<>(); - 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) { - log.info(">>> resource name : {}", resource.getFilename()); - 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 fis = this.convertGeoJsonToGeometry(jsonObject); - - String airspaceType = AirspaceType.ETC.name(); - if (resource.getFilename().contains("gimpo-airport-2d-elev.json")) { - airspaceType = AirspaceType.GIMPO.name(); - } - - List featureInfos = featureInfoMap.get(airspaceType); - if (featureInfos == null) { - featureInfos = new ArrayList<>(); - } - featureInfos.addAll(fis); - featureInfoMap.put(airspaceType, featureInfos); - - } catch (Exception e) { - log.warn("airspace resource read error : {}", e.getMessage()); - } - } - - for (Map.Entry> entry : featureInfoMap.entrySet()) { - log.info(">>> key : {}, size : {}", entry.getKey(), entry.getValue().size()); - } - - this.airspaceMap = featureInfoMap; - } - */ // 파일에서 공역 데이터 가져와서 geometry로 변환 - 초기화. private void loadResourceAirspace() { -// D_NO_FLY_ZONE, // 비행금지구역 -// D_RESTRICTED_FLIGHT_AREA, // 비행제한구역 -// D_CONTROL_AIRPORT, // 관제권(공항) -// D_CONTROL_MILITARY_CIVILIAN, // 관제권(군사/민간) -// D_LIGHT_AIRCRAFT, // 경량항공기이착륙장 -// D_ULTRA_LIGHT_AIRCRAFT, // 초경량비행장치공역 + Map resourceInfo = Map.of( AirspaceType.D_NO_FLY_ZONE, "default_airspace/_prohibitedArea.json", AirspaceType.D_RESTRICTED_FLIGHT_AREA, "default_airspace/_restrictedArea.json", From 3e9244ab9e517a1b8a20990edb701ee93b4d1b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dhji=28=EC=A7=80=EB=8C=80=ED=95=9C=29?= Date: Fri, 13 Sep 2024 11:13:50 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=EB=93=9C=EB=A1=A0=EC=9B=90?= =?UTF-8?q?=EC=8A=A4=ED=86=B1=20CPT=20=EC=BD=94=EB=93=9C=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../external/service/DronOneStopServiceTest.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java b/pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java index fa677e0c..c2e4af61 100644 --- a/pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java +++ b/pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java @@ -1,6 +1,7 @@ package com.palnet.biz.api.external.service; import com.palnet.biz.api.external.model.DosApprovalResult; +import com.palnet.biz.api.external.model.DosCptAuthResult; import com.palnet.biz.jpa.entity.DosFltPlanArea; import com.palnet.biz.jpa.entity.DosFltPlanResult; import com.palnet.biz.jpa.repository.dos.DosFltPlanAreaRepository; @@ -127,9 +128,15 @@ class DronOneStopServiceTest { } } + // CPT 코드 업데이트 - 전체 @Test - void test() { - DosApprovalResult approvalResult= dronOneStopService.getApprovalResult(500.0, 492.0, new Coordinate(126.83916033495814, 37.56642984745274)); - log.info("{}", approvalResult); + void updateAllCptCode() { + List all = dosFltPlanAreaRepository.findAll(); + all.forEach(area -> { + DosCptAuthResult result = dronOneStopService.getCptAuth(new Coordinate(area.getLon(), area.getLat()), area.getBufferZone()); + result.setCptCode(result.getCptCode()); + result.setControlCptCode(result.getControlCptCode()); + }); + dosFltPlanAreaRepository.saveAll(all); } } \ No newline at end of file