Compare commits

...

5 Commits

  1. 4
      http/server/common.http
  2. 71
      pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java
  3. 17
      pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java
  4. 4
      pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java
  5. 13
      pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java
  6. 37
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java
  7. 6
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java
  8. 2
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java
  9. 80
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java
  10. 17
      pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java
  11. 57
      pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java
  12. 198
      pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java
  13. 62
      pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java
  14. 264
      pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java
  15. 42
      pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java
  16. 13
      pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java

4
http/server/common.http

@ -0,0 +1,4 @@
### 좌표 to 관할지역
GET {{appHost}}/api/comn/coordinate/comptent-authority
?lat=37.5666103&lon=126.978
Authorization: {{accessToken}}

71
pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java

@ -4,32 +4,95 @@ import com.palnet.biz.api.bas.dos.model.AllStatDataRS;
import com.palnet.biz.api.bas.dos.model.CptStatRQ;
import com.palnet.biz.api.bas.dos.model.CptStatRS;
import com.palnet.biz.api.bas.dos.service.StatisticsDosService;
import com.palnet.biz.api.comn.response.ErrorResponse;
import com.palnet.biz.api.comn.response.SuccessResponse;
import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@Slf4j
@RequestMapping("/api/statistics/dos")
@RequiredArgsConstructor
@Tag(name = "드론 원스톱 통계 컨트롤러", description = "드론원스톱 통계 관련 API")
public class StatisticsDosController {
private final StatisticsDosService statisticsDosService;
@GetMapping("/all-data")
@GetMapping("/top-data")
@Operation(summary = "통계 페이지 상단 데이터 조회", description = "가장 많은 비행승인 데이터가 들어온 관할기관 데이터를 조회합니다.")
public ResponseEntity<?> allData(){
log.info("allData");
AllStatDataRS result = statisticsDosService.allData();
AllStatDataRS result = null;
try {
result = statisticsDosService.allData();
} catch(CustomException e){
ErrorCode errorCode = ErrorCode.fromCode(e.getSourceErrorCode());
String paramMessage = (String) e.getParamArray()[0];
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", errorCode.code());
resultMap.put("errorMessage", errorCode.message());
resultMap.put("errorDesc", paramMessage);
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGONE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Server Error", "-1"));
}
return ResponseEntity.ok().body(result);
}
@GetMapping("/table-data")
@Operation(summary = "통계 페이지 테이블 데이터 조회", description = "관할 기관 별 날짜별로 데이터 건수를 조회합니다.")
public ResponseEntity<?> tableData(CptStatRQ rq){
CptStatRS result = statisticsDosService.cptStatData(rq);
CptStatRS result = null;
try {
result = statisticsDosService.cptStatData(rq);
} catch(CustomException e){
ErrorCode errorCode = ErrorCode.fromCode(e.getSourceErrorCode());
String paramMessage = (String) e.getParamArray()[0];
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", errorCode.code());
resultMap.put("errorMessage", errorCode.message());
resultMap.put("errorDesc", paramMessage);
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGONE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Server Error", "-1"));
}
return ResponseEntity.ok().body(result);
}

17
pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java

@ -2,19 +2,22 @@ package com.palnet.biz.api.bas.dos.model;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AllStatDataRS {
private GroupModel fullApproval;
private List<GroupModel> fullApproval;
private GroupModel controlApproval;
private List<GroupModel> controlApproval;
private GroupModel nonControlApproval;
private List<GroupModel> nonControlApproval;
@Data
public static class GroupModel{
private String groupName;
private List<String> groupName;
private Long all;
@ -24,13 +27,11 @@ public class AllStatDataRS {
private Long day;
public GroupModel(){
this.groupName = new ArrayList<>();
}
@Data
public static class CptCountModel{
private String cptName;
private Long count;
}
}

4
pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java

@ -1,5 +1,6 @@
package com.palnet.biz.api.bas.dos.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
@ -7,9 +8,12 @@ import java.time.LocalDate;
@Data
public class CptStatRQ {
@Schema(description = "[ year: 연도별, month: 월별, day: 일일 ] 카테고리 선택 컬럼" , example = "month")
private String category;
@Schema(description = "검색 시작일자" , example = "2024-03-01")
private LocalDate startDt;
@Schema(description = "검색 종료일자" , example = "2024-12-31")
private LocalDate endDt;
}

13
pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java

@ -18,20 +18,18 @@ import java.util.List;
@RequiredArgsConstructor
public class StatisticsDosService {
private final DosFltPlanBasRepository dosFltPlanBasRepository;
private final DosFltPlanAreaRepository dosFltPlanAreaRepository;
private final DosFltPlanAreaQueryRepository dosFltPlanAreaQueryRepository;
public AllStatDataRS allData() {
AllStatDataRS.GroupModel fullApproval = dosFltPlanAreaQueryRepository.allApplyData();
List<AllStatDataRS.GroupModel> fullApproval = dosFltPlanAreaQueryRepository.allApplyTopData();
List<AllStatDataRS.GroupModel> controlApproval = dosFltPlanAreaQueryRepository.controlApplyTopData(true);
List<AllStatDataRS.GroupModel> nonControlApproval = dosFltPlanAreaQueryRepository.controlApplyTopData(false);
AllStatDataRS result = new AllStatDataRS();
result.setFullApproval(fullApproval);
result.setControlApproval(controlApproval);
result.setNonControlApproval(nonControlApproval);
return result;
}
@ -68,5 +66,4 @@ public class StatisticsDosService {
}
}

37
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;
}

6
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java

@ -1,8 +1,14 @@
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;

2
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<FltCptAuthBas> fltCptpAuthBasList;
private List<CompotentAuthorityItemRS> fltCptpAuthBasList;
}

80
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
@ -63,13 +61,23 @@ public class ComnCoordinateService {
String[] scope = {"ctprvn", "sig", "emd", "li"};
final String cd = (String) code.get("CD");
Set<FltCptAuthBas> fltCptAuthBas = new HashSet<>();
Set<CompotentAuthorityItemRS> fltCptAuthBas = new HashSet<>();
for (String s : scope) {
String cdParam = CoordUtils.getInstance().addAdmCd(cd, s);
List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
fltCptAuthBas.addAll(new HashSet<>(authList));
List<CompotentAuthorityItemRS> 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();
@ -81,6 +89,46 @@ public class ComnCoordinateService {
return result;
}
public List<CompotentAuthorityItemRS> getCompetentAuthority(List<CompotentAuthorityRQ> rq) {
CoordUtils utils = CoordUtils.getInstance();
List<Coordinate> coords = rq.stream().map(r -> new Coordinate(r.getLat(), r.getLon())).collect(Collectors.toList());
List<JSONObject> codeList = utils.getPlace(coords);
String[] scope = {"ctprvn", "sig", "emd", "li"};
Set<CompotentAuthorityItemRS> 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<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
List<CompotentAuthorityItemRS> 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();

17
pav-server/src/main/java/com/palnet/biz/api/external/model/DosCptAuthResult.java vendored

@ -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<String> cptCode;
private List<String> controlCptCode;
}

57
pav-server/src/main/java/com/palnet/biz/api/external/service/DronOneStopService.java vendored

@ -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<String> 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<Coordinate> targetCoordinate = areaUtils.createCircle(centerCoordinate, radius);
List<CompotentAuthorityRQ> rq = targetCoordinate.stream().map(coordinate -> CompotentAuthorityRQ.builder()
.lat(coordinate.y)
.lon(coordinate.x)
.build()).collect(Collectors.toList());
List<CompotentAuthorityItemRS> competentAuthority = comnCoordinateService.getCompetentAuthority(rq);
DosCptAuthResult result = new DosCptAuthResult();
if (competentAuthority != null && !competentAuthority.isEmpty()) {
List<String> cptCode = competentAuthority.stream().map(CompotentAuthorityItemRS::getCptAuthCode).distinct().collect(Collectors.toList());
result.setCptCode(cptCode);
}
// TODO 관제권 체크 후 결과 반환
// 관제권 airspaces
Map<AirspaceUtils.AirspaceType, String> airspaceParamMap = Map.of(
AirspaceUtils.AirspaceType.C_CONTROL_GIMPO, "F0002", // 김포항공관리사무소(안전운항과)
AirspaceUtils.AirspaceType.C_CONTROL_ULSAN, "C0001" // 울산공항출장소
// AirspaceUtils.AirspaceType.C_CONTROL_JEJU, "F0008", // 제주지방항공청(안전운항과)
);
List<String> controlCptCode = new ArrayList<>();
AirspaceUtils airspaceUtils = AirspaceUtils.getInstance();
Geometry targetGeometry = airspaceUtils.createGeometryByCoordinate(targetCoordinate);
for (AirspaceUtils.AirspaceType airspaceType : airspaceParamMap.keySet()) {
List<AirspaceUtils.FeatureInfo> 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;
}
}

198
pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java

@ -10,19 +10,15 @@ import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberTemplate;
import com.querydsl.core.types.dsl.StringTemplate;
import com.querydsl.core.types.dsl.*;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Repository
@ -33,58 +29,73 @@ public class DosFltPlanAreaQueryRepository {
private final JPAQueryFactory query;
public AllStatDataRS.GroupModel allApplyData() {
/**
* 데이터 조회
* @return
*/
public List<AllStatDataRS.GroupModel> allApplyTopData() {
QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea;
QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas;
Integer year = LocalDate.now().getYear();
Integer month = LocalDate.now().getMonth().getValue();
NumberTemplate<Long> yearTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} THEN 1 END)", qDosFltPlanBas.applyDt, year);
NumberTemplate<Long> monthTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} AND MONTH({2}) = {3} THEN 1 END)", qDosFltPlanBas.applyDt, year, qDosFltPlanBas.applyDt, month);
NumberTemplate<Long> todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt);
// TODO :: CPT_CD의 데이터가 없음으로 임시 F0002처리
StringTemplate ifTemplate = Expressions.stringTemplate("CASE WHEN {0} IS NULL THEN 'F0002' ELSE {0} END", qDosFltPlanArea.cptCd);
BooleanBuilder builder = new BooleanBuilder();
builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.cptCd));
Map<String, Long> cptCountModels = query
Map<String, AllStatDataRS.GroupModel> groupModel = query
.select(
Projections.bean(
AllStatDataRS.CptCountModel.class,
ifTemplate.as("cptName"),
qDosFltPlanArea.count().as("count")
AllStatDataRS.GroupModel.class,
qDosFltPlanArea.cptCd.as("groupName"),
qDosFltPlanArea.count().as("all"),
yearTemplate.as("year"),
monthTemplate.as("month"),
todayTemplate.as("day")
)
)
.from(qDosFltPlanArea)
.leftJoin(qDosFltPlanBas)
.on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno))
.where(builder)
.groupBy(qDosFltPlanArea.cptCd)
.fetch()
.stream()
.collect(Collectors.toMap(
AllStatDataRS.CptCountModel::getCptName,
AllStatDataRS.CptCountModel::getCount
));
key -> {
for(Map.Entry<String, Long> entry : cptCountModels.entrySet()){
if(key.getGroupName() == null) return "";
String[] cptCdArray = entry.getKey().split(",");
if(cptCdArray.length > 1) continue;
StringBuilder result = new StringBuilder();
for(String cptCd : cptCdArray){
Long newCount = cptCountModels.get(cptCd) + entry.getValue();
cptCountModels.put(cptCd, newCount);
}
}
key.getGroupName().forEach(node -> {
result.append(node);
result.append(",");
});
// 정렬
Long max = -1000L;
String cptCd = "";
result.deleteCharAt(result.length() - 1);
for(Map.Entry<String, Long> entry : cptCountModels.entrySet()){
Long value = entry.getValue();
return result.toString();
},
value -> value
));
if(value > max){
max = value;
cptCd = entry.getKey();
}
return this.topDataParsing(groupModel);
}
/**
* 관제, 비관제 데이터 조회
* @param controlFlag TRUE : 관제권 조회, FALSE : 관제권 조회
* @return
*/
public List<AllStatDataRS.GroupModel> controlApplyTopData(Boolean controlFlag) {
QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea;
QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas;
Integer year = LocalDate.now().getYear();
Integer month = LocalDate.now().getMonth().getValue();
@ -93,13 +104,23 @@ public class DosFltPlanAreaQueryRepository {
NumberTemplate<Long> monthTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} AND MONTH({2}) = {3} THEN 1 END)", qDosFltPlanBas.applyDt, year, qDosFltPlanBas.applyDt, month);
NumberTemplate<Long> todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt);
ListPath<String, StringPath> groupingColumn = null;
BooleanBuilder builder = new BooleanBuilder();
builder.and(qDosFltPlanArea.cptCd.contains(cptCd));
builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.cptCd));
if(controlFlag){
builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.innerCptCd));
groupingColumn = qDosFltPlanArea.innerCptCd;
} else {
builder.and(Expressions.booleanTemplate("{0} IS NULL", qDosFltPlanArea.innerCptCd));
groupingColumn = qDosFltPlanArea.cptCd;
}
AllStatDataRS.GroupModel groupModel = query
Map<String, AllStatDataRS.GroupModel> groupModel = query
.select(
Projections.bean(
AllStatDataRS.GroupModel.class,
groupingColumn.as("groupName"),
qDosFltPlanArea.count().as("all"),
yearTemplate.as("year"),
monthTemplate.as("month"),
@ -109,14 +130,37 @@ public class DosFltPlanAreaQueryRepository {
.from(qDosFltPlanArea)
.leftJoin(qDosFltPlanBas)
.on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno))
.fetchOne();
.where(builder)
.groupBy(groupingColumn)
.fetch()
.stream()
.collect(Collectors.toMap(
key -> {
if(key.getGroupName() == null) return "";
StringBuilder result = new StringBuilder();
groupModel.setGroupName(cptCd);
key.getGroupName().forEach(node -> {
result.append(node);
result.append(",");
});
return groupModel;
result.deleteCharAt(result.length() - 1);
return result.toString();
},
value -> value
));
return this.topDataParsing(groupModel);
}
/**
* 공항별 데이터 통계
* @param rq
* @return
*/
public List<CptStatRS.CptStat> cptStatData(CptStatRQ rq) {
QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea;
@ -131,7 +175,10 @@ public class DosFltPlanAreaQueryRepository {
String format = this.getFormat(rq.getCategory());
StringTemplate formattedDate = Expressions.stringTemplate("DATE_FORMAT({0},{1})", qDosFltPlanBas.applyDt , format);
String cptCd = competnetAgency.name();
BooleanBuilder builder = new BooleanBuilder();
builder.and(Expressions.booleanTemplate("{0} LIKE CONCAT('%', {1}, '%')", qDosFltPlanArea.cptCd, cptCd));
if(!rq.getCategory().equals("year")){
builder.and(qDosFltPlanBas.applyDt.goe(rq.getStartDt()));
@ -171,12 +218,8 @@ public class DosFltPlanAreaQueryRepository {
CptStatRS.CptStat cptStatModel = new CptStatRS.CptStat();
cptStatModel.setCptName(competnetAgency.getDesc());
cptStatModel.setCptCd(competnetAgency.name());
// TODO :: CPT_CD 나오기전 임시 코드
if(competnetAgency.name().equals("F0002")){
cptStatModel.setCountModel(countModel);
cptStatModel.setCoordinateModels(coordinateModels);
}
cptStatList.add(cptStatModel);
}
@ -184,6 +227,72 @@ public class DosFltPlanAreaQueryRepository {
return cptStatList;
}
private List<AllStatDataRS.GroupModel> topDataParsing(Map<String, AllStatDataRS.GroupModel> groupModel){
Map<String, AllStatDataRS.GroupModel> currentMap = new ConcurrentHashMap<>(groupModel);
// CptCd가 한 개가 아닌 값들에 대한 로직
for(Map.Entry<String, AllStatDataRS.GroupModel> entry : currentMap.entrySet()){
String[] cptCdArray = entry.getKey().split(",");
// CptCd가 1개일 경우 continue
if(cptCdArray.length <= 1) continue;
for(String cptCd : cptCdArray){
// 기존 Map에 없는 값일 경우 CptCd를 Key로 새로 만들어 put
if(currentMap.get(cptCd) == null){
AllStatDataRS.GroupModel node = new AllStatDataRS.GroupModel();
node.setGroupName(Collections.singletonList(cptCd));
node.setAll(entry.getValue().getAll());
node.setYear(entry.getValue().getYear());
node.setMonth(entry.getValue().getMonth());
node.setDay(entry.getValue().getDay());
currentMap.put(cptCd, node);
continue;
}
// 기존 값이 있을 경우 객체를 새로운 메모리에 할당하여 put
AllStatDataRS.GroupModel node = new AllStatDataRS.GroupModel();
node.setGroupName(Collections.singletonList(cptCd));
node.setAll(currentMap.get(cptCd).getAll() + entry.getValue().getAll());
node.setYear(currentMap.get(cptCd).getYear() + entry.getValue().getYear());
node.setMonth(currentMap.get(cptCd).getMonth() + entry.getValue().getMonth());
node.setDay(currentMap.get(cptCd).getDay() + entry.getValue().getDay());
currentMap.put(cptCd, node);
}
currentMap.remove(entry.getKey());
}
// Key의 맞는 GroupName Set
currentMap.forEach((key, value) -> {
value.setGroupName(Collections.singletonList(key));
});
// 총 카운트가 가장많은 값 추출
Long max = currentMap.values().stream()
.mapToLong(AllStatDataRS.GroupModel::getAll)
.max()
.orElse(0);
List<AllStatDataRS.GroupModel> result = new ArrayList<>();
// 가장 많은 값만 반환 리스트에 ADD
for(Map.Entry<String, AllStatDataRS.GroupModel> entry : currentMap.entrySet()){
if(entry.getValue().getAll().equals(max)){
result.add(entry.getValue());
}
}
if(result.isEmpty()) result.add(new AllStatDataRS.GroupModel());
return result;
}
private String getFormat(String category){
String format = null;
@ -204,4 +313,5 @@ public class DosFltPlanAreaQueryRepository {
return format;
}
}

62
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<FeatureInfo> airspaces;
private Map<AirspaceType, List<FeatureInfo>> 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<FeatureInfo> getAirspaces(AirspaceType airspaceType) {
return this.airspaceMap.get(airspaceType.name());
}
/*
// 파일에서 공역 데이터 가져와서 geometry로 변환 - 초기화.
private void loadResourceAirspace() {
Map<String, List<FeatureInfo>> 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<FeatureInfo> fis = this.convertGeoJsonToGeometry(jsonObject);
String airspaceType = AirspaceType.ETC.name();
if (resource.getFilename().contains("gimpo-airport-2d-elev.json")) {
airspaceType = AirspaceType.GIMPO.name();
}
List<FeatureInfo> 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<String, List<FeatureInfo>> entry : featureInfoMap.entrySet()) {
log.info(">>> key : {}, size : {}", entry.getKey(), entry.getValue().size());
return this.airspaceMap.get(airspaceType);
}
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<AirspaceType, String> resourceInfo = Map.of(
AirspaceType.D_NO_FLY_ZONE, "default_airspace/_prohibitedArea.json",
AirspaceType.D_RESTRICTED_FLIGHT_AREA, "default_airspace/_restrictedArea.json",

264
pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java

@ -1,32 +1,25 @@
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 {
@ -51,7 +44,7 @@ public class CoordUtils {
}
public int getSize() {
if(this.allLocation == null) return 0;
if (this.allLocation == null) return 0;
return this.allLocation.size();
}
@ -101,14 +94,14 @@ public class CoordUtils {
String path = basePath + coords + "/" + baseFileName;
try(InputStream inputStream = new ClassPathResource(path).getInputStream();
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) {
} catch (Exception e) {
log.error("", e);
}
return jsonObject;
@ -157,7 +150,7 @@ public class CoordUtils {
jsonObject = null;
}
if(jsonObject != null && jsonObject.get("distance") == null) {
if (jsonObject != null && jsonObject.get("distance") == null) {
depth = (String) jsonObject.get("CD");
@ -165,11 +158,11 @@ public class CoordUtils {
break;
} else if(jsonObject != null && jsonObject.get("distance") != null) {
} else if (jsonObject != null && jsonObject.get("distance") != null) {
Double distances = (Double) jsonObject.get("distance");
if(distance > distances) {
if (distance > distances) {
distance = distances;
@ -204,7 +197,7 @@ public class CoordUtils {
obj = parseGeoJson(polygon, coordinate);
if(obj == null) return null;
if (obj == null) return null;
return obj;
@ -216,30 +209,31 @@ public class CoordUtils {
String address = "";
String path = basePath + depth.substring(0,2) + "/" + depth + "/";
String path = basePath + depth.substring(0, 2) + "/" + depth + "/";
while(true) {
while (true) {
ClassPathResource classPathResource = new ClassPathResource(path+baseFileName);
ClassPathResource classPathResource = new ClassPathResource(path + baseFileName);
if(!classPathResource.exists()) {
if (!classPathResource.exists()) {
obj.put("add", address);
return obj;
}
obj = parseGeoJson(path+baseFileName, coordinate);
obj = parseGeoJson(path + baseFileName, coordinate);
if(obj == null) return null;
if (obj == null) return null;
address += " " + obj.get("KOR_NM");
path += obj.get("CD")+"/";
path += obj.get("CD") + "/";
}
}
public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException {
Point point = geometryFactory.createPoint(coordinate);
@ -251,13 +245,13 @@ public class CoordUtils {
}
public JSONObject parseGeoJson(String path, Coordinate coordinate){
public JSONObject parseGeoJson(String path, Coordinate coordinate) {
List<JSONObject> features = new ArrayList<JSONObject>();
Point point = null;
try(InputStream inputStream = new ClassPathResource(path).getInputStream();
try (InputStream inputStream = new ClassPathResource(path).getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) {
JSONParser jsonParser = new JSONParser();
@ -269,7 +263,7 @@ public class CoordUtils {
features = (List<JSONObject>) jsonObject.get("features");
}catch(Exception e) {
} catch (Exception e) {
log.error("", e);
}
@ -277,13 +271,14 @@ public class CoordUtils {
return this.contains(features, point);
}
public JSONObject contains(List<JSONObject> features, Point point) {
JSONObject result = null;
Double standard = 10000000.0;
for(int i=0; i<features.size(); i++) {
for (int i = 0; i < features.size(); i++) {
JSONObject geometry = (JSONObject) features.get(i).get("geometry");
@ -291,13 +286,13 @@ public class CoordUtils {
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates");
for(int k = 0; k< coordinates.size(); k++) {
for (int k = 0; k < coordinates.size(); k++) {
List<Coordinate> 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);
@ -317,17 +312,17 @@ public class CoordUtils {
}
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;
}else {
} else {
Double distance = polygon.distance(point);
if(standard > distance) {
if (standard > distance) {
standard = distance;
@ -344,11 +339,12 @@ public class CoordUtils {
/**
* 주소로 지역 바운더리 좌표 가져오기
*
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리]
* @param scope 지역 스코프,
* @return 지역좌표 반환
*/
public List<LocationCoordinateModel> getCoordinateByAddress (String searchAdmCd, String scope){
public List<LocationCoordinateModel> getCoordinateByAddress(String searchAdmCd, String scope) {
String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope);
String admCd = this.removeAdmCd(searchAdmCd, scope);
@ -373,13 +369,13 @@ public class CoordUtils {
.findFirst();
JSONObject result = resultJsonObject.orElseThrow(() -> new CustomException(ErrorCode.DATA_NO));
JSONObject geometry = (JSONObject)result.get("geometry");
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) ;
for (int i = 0; i < coordinates.size(); i++) {
JSONArray arrayNode = (JSONArray) ((JSONArray) coordinates.get(i)).get(0);
List<Coordinate> coordinateList = new ArrayList<>();
@ -404,9 +400,9 @@ public class CoordUtils {
}
/**
* 주소의 스코프 체크 기능.
*
* @param address 스코프 체크할 주소
* @return /: ctprvn, //: sig, //: emd, : li
*/
@ -465,13 +461,14 @@ public class CoordUtils {
/**
* 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능
*
* @param cd 조회할 법정동코드
* @param scope 스코프
* @return 폴더경로
*/
private String getCodeForderPath(String cd, String scope){
private String getCodeForderPath(String cd, String scope) {
if(cd.length() != 10) return null;
if (cd.length() != 10) return null;
Stack<String> forderPathStack = new Stack<>();
@ -488,7 +485,7 @@ public class CoordUtils {
StringBuilder forderPath = new StringBuilder();
forderPath.append(this.basePath);
while(!forderPathStack.isEmpty()){
while (!forderPathStack.isEmpty()) {
forderPath.append(forderPathStack.pop());
forderPath.append("/");
}
@ -500,33 +497,34 @@ public class CoordUtils {
/**
* 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함]
*
* @param cd 10자리가 안되는 법정동코드
* @param scope 현재 법정동 코드의 스코프
* @return 10자리에 맞게 0이 추가된 법정동코드
*/
public String addAdmCd(String cd, String scope){
public String addAdmCd(String cd, String scope) {
switch (scope) {
case "ctprvn":
if(cd.length() < 2) break;
if (cd.length() < 2) break;
cd = cd.substring(0, 2);
break;
case "sig":
if(cd.length() < 5) break;
if (cd.length() < 5) break;
cd = cd.substring(0, 5);
break;
case "emd":
if(cd.length() < 8) break;
if (cd.length() < 8) break;
cd = cd.substring(0, 8);
break;
case "li":
if(cd.length() < 10) break;
if (cd.length() < 10) break;
cd = cd.substring(0, 10);
break;
@ -540,7 +538,7 @@ public class CoordUtils {
StringBuilder sb = new StringBuilder();
sb.append(cd);
for(int i = 0; i < difference; i++){
for (int i = 0; i < difference; i++) {
sb.append("0");
}
@ -549,13 +547,14 @@ public class CoordUtils {
/**
* 스코프에 맞게 법정동코드 길이를 자르는 기능.
*
* @param cd 잘라낼 법정동 코드
* @param scope 스코프
* @return 잘라진 법정동코드
*/
public String removeAdmCd(String cd, String scope){
public String removeAdmCd(String cd, String scope) {
if(cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER);
if (cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER);
String result = "";
@ -585,4 +584,151 @@ public class CoordUtils {
}
public List<JSONObject> getPlace(List<Coordinate> coords) {
Geometry target = geometryFactory.createPolygon(coords.toArray(new Coordinate[]{}));
List<JSONObject> result = new ArrayList<>();
List<JSONObject> firstIntersectList = new ArrayList<>();
for (JSONObject location : this.allLocation) {
List<JSONObject> features = (List<JSONObject>) location.get("features");
List<JSONObject> 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<JSONObject> subPropertiesList = getSubPropertiesByFile(properties, target);
if(!subPropertiesList.isEmpty()) {
result.addAll(subPropertiesList);
}
}
return result;
}
private List<JSONObject> 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<JSONObject> result = new ArrayList<>();
if (!classPathResource.exists()) {
return result;
}
List<JSONObject> 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>) 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<JSONObject> subSubPropertiesList = getSubPropertiesByFile(subProperties, target);
if(!subSubPropertiesList.isEmpty()) {
result.addAll(subSubPropertiesList);
}
}
return result;
}
private List<JSONObject> intersects(List<JSONObject> features, Geometry target) {
List<JSONObject> 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<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates");
List<Polygon> polygons = new ArrayList<>();
for (JSONArray coordinate : coordinates) {
List<Coordinate> 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;
}
}

42
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<CompotentAuthorityRQ> 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<CompotentAuthorityItemRS> result = comnCoordinateService.getCompetentAuthority(rq);
// then
log.debug("result: {}", result);
}
}

13
pav-server/src/test/java/com/palnet/biz/api/external/service/DronOneStopServiceTest.java vendored

@ -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<DosFltPlanArea> 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);
}
}
Loading…
Cancel
Save