From 82b8d0c60dd448ff01ed278c0243fb843f73fff3 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, 16 Nov 2023 13:30:17 +0900 Subject: [PATCH] =?UTF-8?q?=EB=93=9C=EB=A1=A0=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20https://www.notion.so/cozy-han/f776272c332a48aca329?= =?UTF-8?q?d7c052dd24fd=3Fpvs=3D4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/ctr/cntrl/model/CtrCntrlDtlModel.java | 56 +- .../ctr/cntrl/service/CtrCntrlService.java | 1592 ++++++++--------- .../ctr/CtrCntrlQueryRepository.java | 76 +- 3 files changed, 881 insertions(+), 843 deletions(-) diff --git a/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/model/CtrCntrlDtlModel.java b/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/model/CtrCntrlDtlModel.java index 11a4857..2e8e2b3 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/model/CtrCntrlDtlModel.java +++ b/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/model/CtrCntrlDtlModel.java @@ -1,35 +1,35 @@ package com.palnet.biz.api.ctr.cntrl.model; -import java.time.Instant; -import java.util.Date; - import lombok.Data; +import java.time.Instant; + @Data public class CtrCntrlDtlModel { - -private String messageTypeCd; - - private String cntrlId; - private Instant cntrlStDt; - private Instant cntrlEndDt; - private int arcrftSno; - private String prdctNum; - private String arcrftTypeCd; - private String arcrftModelNm; - private String prdctCmpnNm; - private String wghtTypeCd; - private String imageUrl; - private String cameraYn; - private String insrncYn; - private String ownerNm; - private String hpno; - private String telno; - private String corpRegYn; - private String aprvlYn; - private Instant aprvlDt; - - private String stAreaNm; - - + + private String messageTypeCd; + + private String cntrlId; + private Instant cntrlStDt; + private Instant cntrlEndDt; + private int arcrftSno; + private String prdctNum; + private String arcrftTypeCd; + private String arcrftTypeNm; + private String arcrftModelNm; + private String prdctCmpnNm; + private String wghtTypeCd; + private String imageUrl; + private String cameraYn; + private String insrncYn; + private String ownerNm; + private String hpno; + private String telno; + private String corpRegYn; + private String aprvlYn; + private Instant aprvlDt; + + private String stAreaNm; + + } diff --git a/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/CtrCntrlService.java b/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/CtrCntrlService.java index 8c08357..66225e6 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/CtrCntrlService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/CtrCntrlService.java @@ -48,34 +48,33 @@ import java.util.*; @Service public class CtrCntrlService { - @Value("${weather.api.url}") - private String weatherUrl; - - @Value("${weather.api.key}") - private String weatherKey; - - private final JwtTokenUtil jwtTokenUtil; - private final CtrTrnsLctnService ctrTrnsLctnService; - private final FltPlanCtrCntrlRelRepository relRepository; - - private final CtrCntrlQueryRepository query; - private final CtrCntrlBasRepository cntrlBasRepository; - private final CtrCntrlHstryRepository cntrlHstryRepository; - private final CtrCntrlWarnLogRepository warnLogRepository; - private final ComIdntBasRepository idntfRepository; - private final ComArcrftBasRepository arcrftRepository; - private final FltPlanBasRepository planBasRepository; - private final FltPlanArcrftRepository planArcrftRepository; - private final FltPlanAreaRepository planAreaRepository; - private final FltPlanAreaCoordRepository planCoordRepository; - private final AreaUtils areaUtils; - private final ControlGpsDataContext shareContext; - private final FltPlanQueryRepository fltPlanQueryRepository; - - - - public List getListHistory(String objectId) { - List filterList = new ArrayList(); + @Value("${weather.api.url}") + private String weatherUrl; + + @Value("${weather.api.key}") + private String weatherKey; + + private final JwtTokenUtil jwtTokenUtil; + private final CtrTrnsLctnService ctrTrnsLctnService; + private final FltPlanCtrCntrlRelRepository relRepository; + + private final CtrCntrlQueryRepository query; + private final CtrCntrlBasRepository cntrlBasRepository; + private final CtrCntrlHstryRepository cntrlHstryRepository; + private final CtrCntrlWarnLogRepository warnLogRepository; + private final ComIdntBasRepository idntfRepository; + private final ComArcrftBasRepository arcrftRepository; + private final FltPlanBasRepository planBasRepository; + private final FltPlanArcrftRepository planArcrftRepository; + private final FltPlanAreaRepository planAreaRepository; + private final FltPlanAreaCoordRepository planCoordRepository; + private final AreaUtils areaUtils; + private final ControlGpsDataContext shareContext; + private final FltPlanQueryRepository fltPlanQueryRepository; + + + public List getListHistory(String objectId) { + List filterList = new ArrayList(); // if(cic.getHistoryData(objectId).size() > 0) { // resultList = cic.getHistoryData(objectId); @@ -88,789 +87,786 @@ public class CtrCntrlService { // } // } - return filterList; - - } - - /** - * TODO 관제 상세 조회 - * - * @param controlId - * @return - */ - public CtrCntrlDtlModel getDetail(String controlId) { - - CtrCntrlDtlModel result; - - result = query.detailCntrl(controlId); - - List areaList = query.detailArea(controlId); - String stAreaNm = ""; - - if (result.getHpno() == null || result.getHpno().isEmpty()) { - } else { - result.setHpno(EncryptUtils.decrypt(result.getHpno())); - } - - for (CtrCntrlHstryArea data : areaList) { - if (data.getActnType().equals("01")) { - if (!StringUtils.isEmpty(data.getArea1())) { - stAreaNm = stAreaNm + " " + data.getArea1(); - } - - if (!StringUtils.isEmpty(data.getArea2())) { - stAreaNm = stAreaNm + " " + data.getArea2(); - } - - if (!StringUtils.isEmpty(data.getArea3())) { - stAreaNm = stAreaNm + " " + data.getArea3(); - } - - if (!StringUtils.isEmpty(data.getLandNm())) { - stAreaNm = stAreaNm + " " + data.getLandNm(); - } - - if (!StringUtils.isEmpty(data.getLandNum())) { - stAreaNm = stAreaNm + " " + data.getLandNum(); - } - } - } - - - result.setStAreaNm(stAreaNm); - - return result; - } - - /** - * TODO 관제 이력 조회 - * - * @param controlId - * @return - */ - public List getHistory(String controlId) { - return query.getDroneHistory(controlId); - } - - /** - * TODO 그룹의 기체 정보 조회 - * - * @param cstmrSno - * @return - */ - - public List getGroupAuthInfo() { - - List list = query.findByGroupInfo(); - List arcrftList = new ArrayList<>(); - if (list.size() > 0) { - for (CtrCntrlGroupModel lists : list) { - List groupArcrft = query.findByGroupArcrft(lists.getGroupId()); - arcrftList.addAll(groupArcrft); - } - } - return arcrftList; - } - - /** - * TODO 비정상 상황 이력 조회 - * - * @param controlId - * @return - */ - public List getWarnLog(String controlId) { - List logs = warnLogRepository.findAllByCntrlId(controlId); - List warnLog = new ArrayList<>(); - - for (CtrCntrlWarnLog log : logs) { - CtrCntrlWarnLogModel model = new CtrCntrlWarnLogModel(); - - model.setCntrlId(log.getCntrlId()); - model.setCreateDt(log.getCreateDt()); - model.setWarnLogSno(log.getWarnLogSno()); - model.setWarnType(log.getWarnType()); - model.setIdntfNum(log.getIdntfNum()); - - warnLog.add(model); - } - - return warnLog; - } - - - /** - * TODO 비행계획서에 등록 된 기체 별 최신 비정상 로그 및 비정상 로그 전체 개수 - * - * @param id - * @return - */ - @Transactional - public List getArcrftWarnList(String id) { - - List result = new ArrayList<>(); - - if ("".equals(id) || id == null) return null; - - String[] ids = id.indexOf(",") > -1 ? id.split(",") : new String[]{id}; // 식별번호(cntrlId)가 여러개일 경우 콤마 구분자로 나눠 배열에 저장 - - for (String cntrlId : ids) { - CtrCntrlArcrftWarnModel model = new CtrCntrlArcrftWarnModel(); - - String idntfNum = cntrlBasRepository.getIdntfNum(cntrlId); //이미 Socket에서 payload의 trim에 따라 cntrlBas에 식별번호가 PA로 시작하는 데이터가 insert 되어 있음. 이 데이터 중 매개변수로 들어온 id와 일치하는 cntrlBas의 식별번호를 가져옴 - CtrCntrlHstry hisControl = query.getWarnHstryList(cntrlId); // repo method 이름을 왜 이렇게 지었는지는 모르겠으나.. cntrlBas에 insert될 때 같이 insert되는 cntrlHstry 데이터 중 가장 마지막에 찍힌 hstry 로그를 가져옴 - - int planSno = relRepository.getPlanSno(idntfNum).orElse(0); // cntrlBas insert될때 같이 insert된 mapping 테이블에서 식별번호로 planSno 가져옴 - if(query.checkPlanSno(planSno) < 1) continue; - - FltPlanArea planAreaData = query.getPlanData(planSno); // planSno에 맞는 비헹계획서의 비행계획경로정보 가져옴 - - List coordList = planCoordRepository.getCoordinate(planAreaData.getPlanAreaSno()); // 비행계획서에 등록한 경로의 좌표 전부를 가져옴 - - CtrCntrlSocketContainsRq containsRq = new CtrCntrlSocketContainsRq(); - if (idntfNum != null) { - containsRq.setIdntfNum(idntfNum); - model.setIdntfNum(idntfNum); - model.setCntrlId(cntrlId); - } - - if (planAreaData != null) { - containsRq.setLat(hisControl.getLat()); - containsRq.setLon(hisControl.getLon()); - } - - if (hisControl != null) { - containsRq.setAreaType(planAreaData.getAreaType()); - containsRq.setBufferZone(planAreaData.getBufferZone()); - } - - if (coordList != null) { - containsRq.setCoordList(coordList); - } - - CtrCntrlPlanContainsRs ctrCntrlPlanContainsRs = this.checkSocketContains(containsRq); // 위의 정보를 기반으로 만들어진 비행계획서 경로와 rq의 좌표를 비교해서 정상 비행 여부 확인 - model.setControlWarnCd(ctrCntrlPlanContainsRs.isWarning()); - - if (model.isControlWarnCd()) { // 정상 비행이 아니라면 warning log 생성 - CtrCntrlWarnLog log = new CtrCntrlWarnLog(); - log.setCntrlId(cntrlId); - log.setIdntfNum(idntfNum); - log.setOccurDt(hisControl.getSrvrRcvDt()); - log.setLat(hisControl.getLat()); - log.setLon(hisControl.getLon()); - log.setElev(hisControl.getElev()); - log.setCreateDt(Instant.now()); - log.setWarnType("PLAN"); - warnLogRepository.save(log); - } - CtrCntrlWarnLog warnLog = warnLogRepository.findFirstByCntrlIdOrderByOccurDtDesc(cntrlId); // 가장 마지막에 쌓인 warnLog 가져옴 - Integer warnCount = warnLogRepository.countByCntrlId(cntrlId); // warnLog 누적 카운트 가져옴 - - if (warnLog != null) { // front에 표출할 warnLog 정보 set - model.setWarnType(warnLog.getWarnType()); - model.setOccurDt(warnLog.getOccurDt()); - model.setCreateDt(warnLog.getCreateDt()); - model.setCreateUserId(warnLog.getCreateUserId()); - } - model.setWarnCount(warnCount); - - result.add(model); - } - return result; - } - - /** - * TODO 식별 번호에 해당되는 비행구역 조회 - * - * @param idntfNum - * @return - */ - public List getFlightPlan(String idntfNum) { - List rs = new ArrayList<>(); - - Instant fltNowDt = Instant.now(); - - // 기체 식별 정보 조회 - ComIdntfBas idntfBas = idntfRepository.findById(idntfNum).orElse(null); - - if (idntfBas != null) { - ComArcrftBas arcrftBas = arcrftRepository.findById(idntfBas.getArcrftSno()).orElse(null); - - if (arcrftBas != null) { - // 비행 계획 기체 조회 - List arcrftList = planArcrftRepository. - findByIdntfNumAndArcrftSnoOrderByPlanArcrftSnoAsc(idntfNum, arcrftBas.getArcrftSno()); - - if (arcrftList != null && !arcrftList.isEmpty()) { - arcrftList.forEach(arcrft -> { - FltPlanBas plan = planBasRepository. - findByGroupFlightPlan(arcrft.getPlanSno(), "Y", fltNowDt).orElse(null); - ListarcrftMappingList = new ArrayList<>(); - BasFlightPlanArcrftModel arcrftMapping = BasFlightMapper.mapper.entityToModel(arcrftBas); - arcrftMapping.setIdntfNum(idntfNum); - arcrftMappingList.add(arcrftMapping); - if (plan != null) { - BasFlightPlanModel planMapping = BasFlightMapper.mapper.entityToModel(plan); - - // 비행 계획서 구역 조회 - List areaList = planAreaRepository.findByPlanSnoOrderByPlanAreaSnoAsc(plan.getPlanSno()); - - if (areaList != null && !areaList.isEmpty()) { - List areaMappingList = new ArrayList<>(); - - areaList.forEach(area -> { - BasFlightPlanAreaModel areaMapping = BasFlightMapper.mapper.entityToModel(area); - - // 비행 구역 좌표 조회 - List coordList = - planCoordRepository.findByPlanAreaSnoOrderByPlanAreaCoordSnoAsc(area.getPlanAreaSno()); - - if (coordList != null && !coordList.isEmpty()) { - // 좌표 리스트 model mapping - List coordListMapping = - BasFlightMapper.mapper.entityToModelCoordList(coordList); - - // 구역 정보에 좌표 저장 - areaMapping.setCoordList(coordListMapping); - - // Buffer 영역 생성 저장 - if ("LINE".equals(area.getAreaType())) { - List convertCoordinates = areaUtils.convertCoordinates(areaMapping.getCoordList()); - List transCoordList = areaUtils.transform(convertCoordinates, "EPSG:4326", "EPSG:5181"); - - List bufferList = areaUtils.buffer(transCoordList, areaMapping.getBufferZone()); - List transBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326"); // buffer 영역 좌표계 변환 - - List bufferCoordList = areaUtils.convertModel(transBufferList); - - areaMapping.setBufferCoordList(bufferCoordList); - } - } - areaMappingList.add(areaMapping); - }); - - // 비행 계획서에 구역 목록 저장 - planMapping.setAreaList(areaMappingList); - planMapping.setArcrftList(arcrftMappingList); - - } - - rs.add(planMapping); - } - }); - } - } - } - - return rs; - } - - /** - * 식별 번호에 해당되는 비행구역 조회 - * KAC에서는 기초데이터를 먼저 입력하는 것이 아닌 비행계획서만 작성하므로 생략되는 로직이 있음 - * 따라서 별도로 구성함 - * @param idntfNum - * @return - */ - public List getFlightPlanForKac(String idntfNum) { - List rs = fltPlanQueryRepository.getPlanByIdntfNum(idntfNum); - - // Line일 경우 버퍼 생성 - if(rs != null && !rs.isEmpty()){ - rs.forEach(r -> { - List areaList = r.getAreaList(); - if(areaList != null && !areaList.isEmpty()){ - areaList.forEach(a -> { - List coordList = a.getCoordList(); - if(coordList != null && !coordList.isEmpty()){ - // Buffer 영역 생성 저장 - if ("LINE".equals(a.getAreaType())) { - List convertCoordinates = areaUtils.convertCoordinates(coordList); - List transCoordList = areaUtils.transform(convertCoordinates, "EPSG:4326", "EPSG:5181"); - - List bufferList = areaUtils.buffer(transCoordList, a.getBufferZone()); - List transBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326"); // buffer 영역 좌표계 변환 - - List bufferCoordList = areaUtils.convertModel(transBufferList); - - a.setBufferCoordList(bufferCoordList); - } - } - }); - } - }); - } - - - return rs; - } - - /** - * TODO 비행 관제 비정상 상황 판별 - * - * @param rq - * @return - */ - public CtrCntrlPlanContainsRs checkPlanContains(CtrCntrlPlanContainsRq rq) { - CtrCntrlPlanContainsRs rs = new CtrCntrlPlanContainsRs(); - - int countSuccess = 0; - - if (rq.getIdntfNum() != null) { - for (BasFlightPlanModel plan : rq.getPlanList()) { - for (BasFlightPlanAreaModel area : plan.getAreaList()) { - List planArea = areaUtils.convertCoordinates(area.getCoordList()); - - // 드론 위치 - Coordinate targetCoord = new Coordinate(rq.getLon(), rq.getLat()); - - /** - * 1. 비행 구역에 벗어나면 모든 경우의 수는 비정상 상황으로 판단 - * 2. 비정상 상황 TYPE(비행구역, 공역)에 따라 구분 (미적용) - */ - boolean areaContains = true; + return filterList; + + } + + /** + * TODO 관제 상세 조회 + * + * @param controlId + * @return + */ + public CtrCntrlDtlModel getDetail(String controlId) { + + CtrCntrlDtlModel result; + +// result = query.detailCntrl(controlId); + result = query.detailCntrlForKac(controlId); + + List areaList = query.detailArea(controlId); + String stAreaNm = ""; + + if (result.getHpno() != null && !result.getHpno().isEmpty()) { + try { + String decHpno = EncryptUtils.decrypt(result.getHpno()); + if (decHpno != null && !decHpno.isEmpty()) { + result.setHpno(decHpno); + } + } catch (Exception e) { + log.error("ERROR: ", e); + } + } + + for (CtrCntrlHstryArea data : areaList) { + if (data.getActnType().equals("01")) { + if (!StringUtils.isEmpty(data.getArea1())) { + stAreaNm = stAreaNm + " " + data.getArea1(); + } + + if (!StringUtils.isEmpty(data.getArea2())) { + stAreaNm = stAreaNm + " " + data.getArea2(); + } + + if (!StringUtils.isEmpty(data.getArea3())) { + stAreaNm = stAreaNm + " " + data.getArea3(); + } + + if (!StringUtils.isEmpty(data.getLandNm())) { + stAreaNm = stAreaNm + " " + data.getLandNm(); + } + + if (!StringUtils.isEmpty(data.getLandNum())) { + stAreaNm = stAreaNm + " " + data.getLandNum(); + } + } + } + + + result.setStAreaNm(stAreaNm); + + return result; + } + + /** + * TODO 관제 이력 조회 + * + * @param controlId + * @return + */ + public List getHistory(String controlId) { + return query.getDroneHistory(controlId); + } + + /** + * TODO 그룹의 기체 정보 조회 + * + * @param cstmrSno + * @return + */ + + public List getGroupAuthInfo() { + + List list = query.findByGroupInfo(); + List arcrftList = new ArrayList<>(); + if (list.size() > 0) { + for (CtrCntrlGroupModel lists : list) { + List groupArcrft = query.findByGroupArcrft(lists.getGroupId()); + arcrftList.addAll(groupArcrft); + } + } + return arcrftList; + } + + /** + * TODO 비정상 상황 이력 조회 + * + * @param controlId + * @return + */ + public List getWarnLog(String controlId) { + List logs = warnLogRepository.findAllByCntrlId(controlId); + List warnLog = new ArrayList<>(); + + for (CtrCntrlWarnLog log : logs) { + CtrCntrlWarnLogModel model = new CtrCntrlWarnLogModel(); + + model.setCntrlId(log.getCntrlId()); + model.setCreateDt(log.getCreateDt()); + model.setWarnLogSno(log.getWarnLogSno()); + model.setWarnType(log.getWarnType()); + model.setIdntfNum(log.getIdntfNum()); + + warnLog.add(model); + } + + return warnLog; + } + + + /** + * TODO 비행계획서에 등록 된 기체 별 최신 비정상 로그 및 비정상 로그 전체 개수 + * + * @param id + * @return + */ + @Transactional + public List getArcrftWarnList(String id) { + + List result = new ArrayList<>(); + + if ("".equals(id) || id == null) return null; + + String[] ids = id.indexOf(",") > -1 ? id.split(",") : new String[]{id}; // 식별번호(cntrlId)가 여러개일 경우 콤마 구분자로 나눠 배열에 저장 + + for (String cntrlId : ids) { + CtrCntrlArcrftWarnModel model = new CtrCntrlArcrftWarnModel(); + + String idntfNum = cntrlBasRepository.getIdntfNum(cntrlId); //이미 Socket에서 payload의 trim에 따라 cntrlBas에 식별번호가 PA로 시작하는 데이터가 insert 되어 있음. 이 데이터 중 매개변수로 들어온 id와 일치하는 cntrlBas의 식별번호를 가져옴 + CtrCntrlHstry hisControl = query.getWarnHstryList(cntrlId); // repo method 이름을 왜 이렇게 지었는지는 모르겠으나.. cntrlBas에 insert될 때 같이 insert되는 cntrlHstry 데이터 중 가장 마지막에 찍힌 hstry 로그를 가져옴 + + int planSno = relRepository.getPlanSno(idntfNum).orElse(0); // cntrlBas insert될때 같이 insert된 mapping 테이블에서 식별번호로 planSno 가져옴 + if (query.checkPlanSno(planSno) < 1) continue; + + FltPlanArea planAreaData = query.getPlanData(planSno); // planSno에 맞는 비헹계획서의 비행계획경로정보 가져옴 + + List coordList = planCoordRepository.getCoordinate(planAreaData.getPlanAreaSno()); // 비행계획서에 등록한 경로의 좌표 전부를 가져옴 + + CtrCntrlSocketContainsRq containsRq = new CtrCntrlSocketContainsRq(); + if (idntfNum != null) { + containsRq.setIdntfNum(idntfNum); + model.setIdntfNum(idntfNum); + model.setCntrlId(cntrlId); + } + + if (planAreaData != null) { + containsRq.setLat(hisControl.getLat()); + containsRq.setLon(hisControl.getLon()); + } + + if (hisControl != null) { + containsRq.setAreaType(planAreaData.getAreaType()); + containsRq.setBufferZone(planAreaData.getBufferZone()); + } + + if (coordList != null) { + containsRq.setCoordList(coordList); + } + + CtrCntrlPlanContainsRs ctrCntrlPlanContainsRs = this.checkSocketContains(containsRq); // 위의 정보를 기반으로 만들어진 비행계획서 경로와 rq의 좌표를 비교해서 정상 비행 여부 확인 + model.setControlWarnCd(ctrCntrlPlanContainsRs.isWarning()); + + if (model.isControlWarnCd()) { // 정상 비행이 아니라면 warning log 생성 + CtrCntrlWarnLog log = new CtrCntrlWarnLog(); + log.setCntrlId(cntrlId); + log.setIdntfNum(idntfNum); + log.setOccurDt(hisControl.getSrvrRcvDt()); + log.setLat(hisControl.getLat()); + log.setLon(hisControl.getLon()); + log.setElev(hisControl.getElev()); + log.setCreateDt(Instant.now()); + log.setWarnType("PLAN"); + warnLogRepository.save(log); + } + CtrCntrlWarnLog warnLog = warnLogRepository.findFirstByCntrlIdOrderByOccurDtDesc(cntrlId); // 가장 마지막에 쌓인 warnLog 가져옴 + Integer warnCount = warnLogRepository.countByCntrlId(cntrlId); // warnLog 누적 카운트 가져옴 + + if (warnLog != null) { // front에 표출할 warnLog 정보 set + model.setWarnType(warnLog.getWarnType()); + model.setOccurDt(warnLog.getOccurDt()); + model.setCreateDt(warnLog.getCreateDt()); + model.setCreateUserId(warnLog.getCreateUserId()); + } + model.setWarnCount(warnCount); + + result.add(model); + } + return result; + } + + /** + * TODO 식별 번호에 해당되는 비행구역 조회 + * + * @param idntfNum + * @return + */ + public List getFlightPlan(String idntfNum) { + List rs = new ArrayList<>(); + + Instant fltNowDt = Instant.now(); + + // 기체 식별 정보 조회 + ComIdntfBas idntfBas = idntfRepository.findById(idntfNum).orElse(null); + + if (idntfBas != null) { + ComArcrftBas arcrftBas = arcrftRepository.findById(idntfBas.getArcrftSno()).orElse(null); + + if (arcrftBas != null) { + // 비행 계획 기체 조회 + List arcrftList = planArcrftRepository. + findByIdntfNumAndArcrftSnoOrderByPlanArcrftSnoAsc(idntfNum, arcrftBas.getArcrftSno()); + + if (arcrftList != null && !arcrftList.isEmpty()) { + arcrftList.forEach(arcrft -> { + FltPlanBas plan = planBasRepository. + findByGroupFlightPlan(arcrft.getPlanSno(), "Y", fltNowDt).orElse(null); + List arcrftMappingList = new ArrayList<>(); + BasFlightPlanArcrftModel arcrftMapping = BasFlightMapper.mapper.entityToModel(arcrftBas); + arcrftMapping.setIdntfNum(idntfNum); + arcrftMappingList.add(arcrftMapping); + if (plan != null) { + BasFlightPlanModel planMapping = BasFlightMapper.mapper.entityToModel(plan); + + // 비행 계획서 구역 조회 + List areaList = planAreaRepository.findByPlanSnoOrderByPlanAreaSnoAsc(plan.getPlanSno()); + + if (areaList != null && !areaList.isEmpty()) { + List areaMappingList = new ArrayList<>(); + + areaList.forEach(area -> { + BasFlightPlanAreaModel areaMapping = BasFlightMapper.mapper.entityToModel(area); + + // 비행 구역 좌표 조회 + List coordList = + planCoordRepository.findByPlanAreaSnoOrderByPlanAreaCoordSnoAsc(area.getPlanAreaSno()); + + if (coordList != null && !coordList.isEmpty()) { + // 좌표 리스트 model mapping + List coordListMapping = + BasFlightMapper.mapper.entityToModelCoordList(coordList); + + // 구역 정보에 좌표 저장 + areaMapping.setCoordList(coordListMapping); + + // Buffer 영역 생성 저장 + if ("LINE".equals(area.getAreaType())) { + List convertCoordinates = areaUtils.convertCoordinates(areaMapping.getCoordList()); + List transCoordList = areaUtils.transform(convertCoordinates, "EPSG:4326", "EPSG:5181"); + + List bufferList = areaUtils.buffer(transCoordList, areaMapping.getBufferZone()); + List transBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326"); // buffer 영역 좌표계 변환 + + List bufferCoordList = areaUtils.convertModel(transBufferList); + + areaMapping.setBufferCoordList(bufferCoordList); + } + } + areaMappingList.add(areaMapping); + }); + + // 비행 계획서에 구역 목록 저장 + planMapping.setAreaList(areaMappingList); + planMapping.setArcrftList(arcrftMappingList); + + } + + rs.add(planMapping); + } + }); + } + } + } + + return rs; + } + + /** + * 식별 번호에 해당되는 비행구역 조회 + * KAC에서는 기초데이터를 먼저 입력하는 것이 아닌 비행계획서만 작성하므로 생략되는 로직이 있음 + * 따라서 별도로 구성함 + * + * @param idntfNum + * @return + */ + public List getFlightPlanForKac(String idntfNum) { + List rs = fltPlanQueryRepository.getPlanByIdntfNum(idntfNum); + + // Line일 경우 버퍼 생성 + if (rs != null && !rs.isEmpty()) { + rs.forEach(r -> { + List areaList = r.getAreaList(); + if (areaList != null && !areaList.isEmpty()) { + areaList.forEach(a -> { + List coordList = a.getCoordList(); + if (coordList != null && !coordList.isEmpty()) { + // Buffer 영역 생성 저장 + if ("LINE".equals(a.getAreaType())) { + List convertCoordinates = areaUtils.convertCoordinates(coordList); + List transCoordList = areaUtils.transform(convertCoordinates, "EPSG:4326", "EPSG:5181"); + + List bufferList = areaUtils.buffer(transCoordList, a.getBufferZone()); + List transBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326"); // buffer 영역 좌표계 변환 + + List bufferCoordList = areaUtils.convertModel(transBufferList); + + a.setBufferCoordList(bufferCoordList); + } + } + }); + } + }); + } + + + return rs; + } + + /** + * TODO 비행 관제 비정상 상황 판별 + * + * @param rq + * @return + */ + public CtrCntrlPlanContainsRs checkPlanContains(CtrCntrlPlanContainsRq rq) { + CtrCntrlPlanContainsRs rs = new CtrCntrlPlanContainsRs(); + + int countSuccess = 0; + + if (rq.getIdntfNum() != null) { + for (BasFlightPlanModel plan : rq.getPlanList()) { + for (BasFlightPlanAreaModel area : plan.getAreaList()) { + List planArea = areaUtils.convertCoordinates(area.getCoordList()); + + // 드론 위치 + Coordinate targetCoord = new Coordinate(rq.getLon(), rq.getLat()); + + /** + * 1. 비행 구역에 벗어나면 모든 경우의 수는 비정상 상황으로 판단 + * 2. 비정상 상황 TYPE(비행구역, 공역)에 따라 구분 (미적용) + */ + boolean areaContains = true; // boolean airspaceContains = false; - if ("LINE".equals(area.getAreaType())) { - List transPlanArea = areaUtils.transform(planArea, "EPSG:4326", "EPSG:5181"); + if ("LINE".equals(area.getAreaType())) { + List transPlanArea = areaUtils.transform(planArea, "EPSG:4326", "EPSG:5181"); - List planBuffer = areaUtils.buffer(transPlanArea, area.getBufferZone()); - List transPlanBuffer = areaUtils.transform(planBuffer, "EPSG:5181", "EPSG:4326"); + List planBuffer = areaUtils.buffer(transPlanArea, area.getBufferZone()); + List transPlanBuffer = areaUtils.transform(planBuffer, "EPSG:5181", "EPSG:4326"); - areaContains = areaUtils.contains(transPlanBuffer, targetCoord); + areaContains = areaUtils.contains(transPlanBuffer, targetCoord); // log.info("LINE CONTAINS : {}", areaContains); - } - - if ("POLYGON".equals(area.getAreaType())) { - planArea.add(planArea.get(0)); - areaContains = areaUtils.contains(planArea, targetCoord); - } - - if ("CIRCLE".equals(area.getAreaType())) { - List circle = areaUtils.createCircle(planArea.get(0), area.getBufferZone()); - areaContains = areaUtils.contains(circle, targetCoord); - - } - - if (areaContains) countSuccess++; - } - } - } - - // 1개라도 - if (countSuccess > 0) { - rs.setWarning(false); - } else { - rs.setWarning(true); - } - - rs.setIdntfNum(rq.getIdntfNum()); - - return rs; - } - - /** - * TODO 임시)warnList 최적화 - * - * @param rq - * @return - */ - public CtrCntrlPlanContainsRs checkSocketContains(CtrCntrlSocketContainsRq rq) { - CtrCntrlPlanContainsRs rs = new CtrCntrlPlanContainsRs(); - - int countSuccess = 0; - - if (rq.getIdntfNum() != null) { - List planArea = new ArrayList<>(); - for(FltPlanAreaCoord coord : rq.getCoordList()) { - Coordinate coordinate = new Coordinate(coord.getLon(), coord.getLat()); - - planArea.add(coordinate); - } - // 드론 위치 - Coordinate targetCoord = new Coordinate(rq.getLon(), rq.getLat()); - - /** - * 1. 비행 구역에 벗어나면 모든 경우의 수는 비정상 상황으로 판단 - * 2. 비정상 상황 TYPE(비행구역, 공역)에 따라 구분 (미적용) - */ - boolean areaContains = true; - switch(rq.getAreaType()) { - case "LINE" : - List transPlanArea = areaUtils.transform(planArea, "EPSG:4326", "EPSG:5181"); - List planBuffer = areaUtils.buffer(transPlanArea, rq.getBufferZone()); - List transPlanBuffer = areaUtils.transform(planBuffer, "EPSG:5181", "EPSG:4326"); - - areaContains = areaUtils.contains(transPlanBuffer, targetCoord); - break; - - case "POLYGON" : - planArea.add(planArea.get(0)); - areaContains = areaUtils.contains(planArea, targetCoord); - break; - - case "CIRCLE" : - List circle = areaUtils.createCircle(planArea.get(0), rq.getBufferZone()); - areaContains = areaUtils.contains(circle, targetCoord); - break; - } - - if (areaContains) countSuccess++; - } - - // 1개라도 - if (countSuccess > 0) { - rs.setWarning(false); - } else { - rs.setWarning(true); - } - - rs.setIdntfNum(rq.getIdntfNum()); - - return rs; - } - - - /** - * TODO 비행 이력 Control-Id 발급 - * - * @param id - * @return - */ - public Map getId(String id) { - Map result = new HashMap<>(); - - - /* 식별번호의 가장 최근 이력 불러오기 */ - CtrCntrlBas latestControl = cntrlBasRepository.findFirstByIdntfNumOrderByCreateDtDesc(id).orElse(null); - - boolean isControl = false; - - if (latestControl != null) { - CtrCntrlHstry latestHistory = cntrlHstryRepository.findFirstByCntrlIdOrderBySrvrRcvDtDesc(latestControl.getCntrlId()).orElse(null); - - if (latestHistory != null) { - long diffMinute = DateUtils.diffMinute(latestHistory.getSrvrRcvDt(), Instant.now()); + } + + if ("POLYGON".equals(area.getAreaType())) { + planArea.add(planArea.get(0)); + areaContains = areaUtils.contains(planArea, targetCoord); + } + + if ("CIRCLE".equals(area.getAreaType())) { + List circle = areaUtils.createCircle(planArea.get(0), area.getBufferZone()); + areaContains = areaUtils.contains(circle, targetCoord); + + } + + if (areaContains) countSuccess++; + } + } + } + + // 1개라도 + if (countSuccess > 0) { + rs.setWarning(false); + } else { + rs.setWarning(true); + } + + rs.setIdntfNum(rq.getIdntfNum()); + + return rs; + } + + /** + * TODO 임시)warnList 최적화 + * + * @param rq + * @return + */ + public CtrCntrlPlanContainsRs checkSocketContains(CtrCntrlSocketContainsRq rq) { + CtrCntrlPlanContainsRs rs = new CtrCntrlPlanContainsRs(); + + int countSuccess = 0; + + if (rq.getIdntfNum() != null) { + List planArea = new ArrayList<>(); + for (FltPlanAreaCoord coord : rq.getCoordList()) { + Coordinate coordinate = new Coordinate(coord.getLon(), coord.getLat()); + + planArea.add(coordinate); + } + // 드론 위치 + Coordinate targetCoord = new Coordinate(rq.getLon(), rq.getLat()); + + /** + * 1. 비행 구역에 벗어나면 모든 경우의 수는 비정상 상황으로 판단 + * 2. 비정상 상황 TYPE(비행구역, 공역)에 따라 구분 (미적용) + */ + boolean areaContains = true; + switch (rq.getAreaType()) { + case "LINE": + List transPlanArea = areaUtils.transform(planArea, "EPSG:4326", "EPSG:5181"); + List planBuffer = areaUtils.buffer(transPlanArea, rq.getBufferZone()); + List transPlanBuffer = areaUtils.transform(planBuffer, "EPSG:5181", "EPSG:4326"); + + areaContains = areaUtils.contains(transPlanBuffer, targetCoord); + break; + + case "POLYGON": + planArea.add(planArea.get(0)); + areaContains = areaUtils.contains(planArea, targetCoord); + break; + + case "CIRCLE": + List circle = areaUtils.createCircle(planArea.get(0), rq.getBufferZone()); + areaContains = areaUtils.contains(circle, targetCoord); + break; + } + + if (areaContains) countSuccess++; + } + + // 1개라도 + if (countSuccess > 0) { + rs.setWarning(false); + } else { + rs.setWarning(true); + } + + rs.setIdntfNum(rq.getIdntfNum()); + + return rs; + } + + + /** + * TODO 비행 이력 Control-Id 발급 + * + * @param id + * @return + */ + public Map getId(String id) { + Map result = new HashMap<>(); + + + /* 식별번호의 가장 최근 이력 불러오기 */ + CtrCntrlBas latestControl = cntrlBasRepository.findFirstByIdntfNumOrderByCreateDtDesc(id).orElse(null); + + boolean isControl = false; + + if (latestControl != null) { + CtrCntrlHstry latestHistory = cntrlHstryRepository.findFirstByCntrlIdOrderBySrvrRcvDtDesc(latestControl.getCntrlId()).orElse(null); + + if (latestHistory != null) { + long diffMinute = DateUtils.diffMinute(latestHistory.getSrvrRcvDt(), Instant.now()); // log.info("DIFF MINUTE : {}", diffMinute); - if ("01".equals(latestControl.getEndTypeCd()) || diffMinute > 5) { - isControl = false; - } - if (!"01".equals(latestControl.getEndTypeCd()) && diffMinute < 5) { - isControl = true; - } - } else { - isControl = false; - } - - } else { - isControl = false; - } - - if (isControl) { - result.put("controlId", latestControl.getCntrlId()); - result.put("typeCd", "02"); - result.put("areaTrnsYn", "E"); - } else { - String controlID = UUID.randomUUID().toString(); - result.put("controlId", controlID); - result.put("typeCd", "01"); - result.put("areaTrnsYn", "N"); - - // 기체 식별번호의 관제 ID 저장 (single ton) - shareContext.putIdntfKey(id, controlID); - } - - return result; - } - - public Map checkWarring(String id, Double lat, Double lon) { - Map result = new HashMap<>(); - - List planList = this.getFlightPlan(id); - - result.put("controlWarnCd", "N"); - if (planList != null && !planList.isEmpty()) { - CtrCntrlPlanContainsRq containsRq = new CtrCntrlPlanContainsRq(); - containsRq.setIdntfNum(id); - containsRq.setLat(lat); - containsRq.setLon(lon); - containsRq.setPlanList(planList); - - CtrCntrlPlanContainsRs ctrCntrlPlanContainsRs = this.checkPlanContains(containsRq); - result.put("controlWarnCd", ctrCntrlPlanContainsRs.isWarning() ? "Y" : "N"); - } - - return result; - } - - public JSONObject getWeather(CtrCntrlWeatherModel rq) throws IOException, ParseException { - - StringBuilder urlBuilder = new StringBuilder(weatherUrl); - - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); - Calendar c1 = Calendar.getInstance(); - String strToday = sdf.format(c1.getTime()); - // 현재 시간 - LocalTime now = LocalTime.now(); - - // 현재시간 출력 - - // 시, 분, 초 구하기 - int hour = now.getHour(); - int minute = now.getMinute(); - int length = (int)(Math.log10(minute)+1); - int hourlength = (int)(Math.log10(hour)+1); - String strminute = Integer.toString(minute); - String strhour = Integer.toString(hour); - String basetime = null; - - if(length<=1){ - strminute = 0+Integer.toString(minute); - }if(hourlength<=1){ - strhour = 0+Integer.toString(hour); - } - // 시, 분, 초 출력 - if ((Integer.parseInt(strhour) >= 2 && Integer.parseInt(strminute )> 9) && Integer.parseInt(strhour) <= 5) { - basetime = "0200"; - } - else if ((Integer.parseInt(strhour) >= 5 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 8) { - basetime = "0500"; - } - else if (Integer.parseInt(strhour) <= 8 && Integer.parseInt(strminute ) < 10) { - basetime = "0500"; - } - else if ((Integer.parseInt(strhour) >= 8 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 11) { - basetime = "0800"; - } - else if (Integer.parseInt(strhour) <= 11 && Integer.parseInt(strminute ) < 10) { - basetime = "0800"; - } - else if ((Integer.parseInt(strhour) >= 11 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 14) { - basetime = "1100"; - } - else if (Integer.parseInt(strhour) <= 14 && Integer.parseInt(strminute ) < 10) { - basetime = "1100"; - } - else if ((Integer.parseInt(strhour) >= 14 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 17) { - basetime = "1400"; - } - else if (Integer.parseInt(strhour) <= 17 && Integer.parseInt(strminute ) < 10) { - basetime = "1400"; - } - else if ((Integer.parseInt(strhour) >= 17 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 20) { - basetime = "1700"; - } - else if (Integer.parseInt(strhour) <= 20 && Integer.parseInt(strminute ) < 10) { - basetime = "1700"; - } - else if ((Integer.parseInt(strhour) >= 20 && Integer.parseInt(strminute ) > 9) && Integer.parseInt(strhour) < 23) { - basetime = "2000"; - } - else if (Integer.parseInt(strhour) <= 23 && Integer.parseInt(strminute ) < 10) { - basetime = "2000"; - } - else - basetime = "2300"; - - - List coordList = new ArrayList<>(); - Coordinate coord = new Coordinate(); - Coordinate returnCoord = new Coordinate(); - coord.setX(rq.getNx()); - coord.setY(rq.getNy()); - returnCoord = this.wheather(coord); - - double nx = returnCoord.getX(); - double ny = returnCoord.getY(); - String Snx = String.format("%.0f",nx); - String Sny = String.format("%.0f",ny); - - urlBuilder.append("?" + URLEncoder.encode("serviceKey","UTF-8") + weatherKey); - urlBuilder.append("&" + URLEncoder.encode("pageNo","UTF-8") + "=" + URLEncoder.encode("1","UTF-8")); - urlBuilder.append("&" + URLEncoder.encode("numOfRows","UTF-8") + "=" + URLEncoder.encode("14", "UTF-8")); /*한 페이지 결과 수*/ - urlBuilder.append("&" + URLEncoder.encode("dataType","UTF-8") + "=" + URLEncoder.encode("JSON", "UTF-8")); /*요청자료형식(XML/JSON) Default: XML*/ - urlBuilder.append("&" + URLEncoder.encode("base_date","UTF-8") + "=" + URLEncoder.encode(strToday, "UTF-8")); /*'21년 6월 28일 발표*/ - urlBuilder.append("&" + URLEncoder.encode("base_time","UTF-8") + "=" + URLEncoder.encode(basetime, "UTF-8")); /*06시 발표(정시단위) */ - urlBuilder.append("&" + URLEncoder.encode("nx","UTF-8") + "=" + URLEncoder.encode(Snx, "UTF-8")); /*예보지점의 X 좌표값*/ - urlBuilder.append("&" + URLEncoder.encode("ny","UTF-8") + "=" + URLEncoder.encode(Sny, "UTF-8")); /*예보지점의 Y 좌표값*/ - URL url = new URL(urlBuilder.toString()); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Content-type", "application/json"); - log.info("Response code: " + conn.getResponseCode()); - BufferedReader rd; - if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) { - rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); - } else { - rd = new BufferedReader(new InputStreamReader(conn.getErrorStream())); - } - StringBuilder sb = new StringBuilder(); - String line; - while ((line = rd.readLine()) != null) { - sb.append(line); - } - CtrTrnsLctnModel weatherResult = ctrTrnsLctnService.convertLatlonToAddress(rq.getNx(),rq.getNy()); - log.info("weatherResult >>>> : {}", weatherResult); - - String str = sb.toString(); - JSONParser parser = new JSONParser(); - JSONObject jsonObject = (JSONObject) parser.parse(str); - if(weatherResult != null) { - jsonObject.put("area1",weatherResult.getArea1()); - jsonObject.put("area2",weatherResult.getArea2()); - jsonObject.put("area3",weatherResult.getArea3()); - jsonObject.put("landNm",weatherResult.getLandNm()); - jsonObject.put("landNum",weatherResult.getLandNum()); - } - rd.close(); - conn.disconnect(); - log.info(sb.toString()); - - return jsonObject; - } - public Coordinate wheather(Coordinate coord) { - double nx; - double ny; - nx = coord.getX(); - ny = coord.getY(); - double RE = 6371.00877; // 지구 반경(km) - double GRID = 5.0; // 격자 간격(km) - double SLAT1 = 30.0; // 투영 위도1(degree) - double SLAT2 = 60.0; // 투영 위도2(degree) - double OLON = 126.0; // 기준점 경도(degree) - double OLAT = 38.0; // 기준점 위도(degree) - double XO = 43; // 기준점 X좌표(GRID) - double YO = 136; // 기1준점 Y좌표(GRID) - - // - // LCC DFS 좌표변환 ( code : "TO_GRID"(위경도->좌표, lat_X:위도, lng_Y:경도), "TO_GPS"(좌표->위경도, lat_X:x, lng_Y:y) ) - // - - double DEGRAD = Math.PI / 180.0; - double RADDEG = 180.0 / Math.PI; - - double re = RE / GRID; - double slat1 = SLAT1 * DEGRAD; - double slat2 = SLAT2 * DEGRAD; - double olon = OLON * DEGRAD; - double olat = OLAT * DEGRAD; - - double sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5); - sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn); - double sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5); - sf = Math.pow(sf, sn) * Math.cos(slat1) / sn; - double ro = Math.tan(Math.PI * 0.25 + olat * 0.5); - ro = re * sf / Math.pow(ro, sn); - - double theta; - if (true) { - nx = nx; - ny = ny; - double ra = Math.tan(Math.PI * 0.25 + (nx) * DEGRAD * 0.5); - ra = re * sf / Math.pow(ra, sn); - theta = ny * DEGRAD - olon; - if (theta > Math.PI) theta -= 2.0 * Math.PI; - if (theta < -Math.PI) theta += 2.0 * Math.PI; - theta *= sn; - nx = Math.floor(ra * Math.sin(theta) + XO + 0.5); - ny = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5); - } else { - nx = nx; - ny = ny; - double xn = nx - XO; - double yn = ro - ny + YO; - double ra = Math.sqrt(xn * xn + yn * yn); - if (sn < 0.0) { - ra = -ra; - } - - double alat = Math.pow((re * sf / ra), (1.0 / sn)); - alat = 2.0 * Math.atan(alat) - Math.PI * 0.5; - - if (Math.abs(xn) <= 0.0) { - theta = 0.0; - } else { - if (Math.abs(yn) <= 0.0) { - theta = Math.PI * 0.5; - if (xn < 0.0) { - theta = -theta; - } - } else theta = Math.atan2(xn, yn); - } - double alon = theta / sn + olon; - nx = alat * RADDEG; - ny = alon * RADDEG; - } - - Coordinate returnCoord = new Coordinate(); - returnCoord.setX(nx); - returnCoord.setY(ny); - return returnCoord; - } - - /** - * TODO 비행 종료 데이터 상세 조회 - * - * @param controlId - * @return - */ - public CtrCntrlArcrftComplModel getComplete(String controlId) { - - CtrCntrlArcrftComplModel result = new CtrCntrlArcrftComplModel(); - List completeInfo = query.getCompleteInfo(controlId); - - Double mvDistanceAll = 0.0; - Duration duration = null; - - if(completeInfo.size() > 2) { - - - Instant start = completeInfo.get(0).getSrvrRcvDt(); - Instant end = completeInfo.get(completeInfo.size()-1).getSrvrRcvDt(); - - if(start != null && end != null) { - LocalDate startDate = start.atZone(ZoneId.of("Asia/Seoul")).toLocalDate(); - LocalDate endDate = end.atZone(ZoneId.of("Asia/Seoul")).toLocalDate(); - - duration = Duration.between(startDate, endDate); - } - - for (int from = 0, to = 1; from 5) { + isControl = false; + } + if (!"01".equals(latestControl.getEndTypeCd()) && diffMinute < 5) { + isControl = true; + } + } else { + isControl = false; + } + + } else { + isControl = false; + } + + if (isControl) { + result.put("controlId", latestControl.getCntrlId()); + result.put("typeCd", "02"); + result.put("areaTrnsYn", "E"); + } else { + String controlID = UUID.randomUUID().toString(); + result.put("controlId", controlID); + result.put("typeCd", "01"); + result.put("areaTrnsYn", "N"); + + // 기체 식별번호의 관제 ID 저장 (single ton) + shareContext.putIdntfKey(id, controlID); + } + + return result; + } + + public Map checkWarring(String id, Double lat, Double lon) { + Map result = new HashMap<>(); + + List planList = this.getFlightPlan(id); + + result.put("controlWarnCd", "N"); + if (planList != null && !planList.isEmpty()) { + CtrCntrlPlanContainsRq containsRq = new CtrCntrlPlanContainsRq(); + containsRq.setIdntfNum(id); + containsRq.setLat(lat); + containsRq.setLon(lon); + containsRq.setPlanList(planList); + + CtrCntrlPlanContainsRs ctrCntrlPlanContainsRs = this.checkPlanContains(containsRq); + result.put("controlWarnCd", ctrCntrlPlanContainsRs.isWarning() ? "Y" : "N"); + } + + return result; + } + + public JSONObject getWeather(CtrCntrlWeatherModel rq) throws IOException, ParseException { + + StringBuilder urlBuilder = new StringBuilder(weatherUrl); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); + Calendar c1 = Calendar.getInstance(); + String strToday = sdf.format(c1.getTime()); + // 현재 시간 + LocalTime now = LocalTime.now(); + + // 현재시간 출력 + + // 시, 분, 초 구하기 + int hour = now.getHour(); + int minute = now.getMinute(); + int length = (int) (Math.log10(minute) + 1); + int hourlength = (int) (Math.log10(hour) + 1); + String strminute = Integer.toString(minute); + String strhour = Integer.toString(hour); + String basetime = null; + + if (length <= 1) { + strminute = 0 + Integer.toString(minute); + } + if (hourlength <= 1) { + strhour = 0 + Integer.toString(hour); + } + // 시, 분, 초 출력 + if ((Integer.parseInt(strhour) >= 2 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) <= 5) { + basetime = "0200"; + } else if ((Integer.parseInt(strhour) >= 5 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 8) { + basetime = "0500"; + } else if (Integer.parseInt(strhour) <= 8 && Integer.parseInt(strminute) < 10) { + basetime = "0500"; + } else if ((Integer.parseInt(strhour) >= 8 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 11) { + basetime = "0800"; + } else if (Integer.parseInt(strhour) <= 11 && Integer.parseInt(strminute) < 10) { + basetime = "0800"; + } else if ((Integer.parseInt(strhour) >= 11 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 14) { + basetime = "1100"; + } else if (Integer.parseInt(strhour) <= 14 && Integer.parseInt(strminute) < 10) { + basetime = "1100"; + } else if ((Integer.parseInt(strhour) >= 14 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 17) { + basetime = "1400"; + } else if (Integer.parseInt(strhour) <= 17 && Integer.parseInt(strminute) < 10) { + basetime = "1400"; + } else if ((Integer.parseInt(strhour) >= 17 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 20) { + basetime = "1700"; + } else if (Integer.parseInt(strhour) <= 20 && Integer.parseInt(strminute) < 10) { + basetime = "1700"; + } else if ((Integer.parseInt(strhour) >= 20 && Integer.parseInt(strminute) > 9) && Integer.parseInt(strhour) < 23) { + basetime = "2000"; + } else if (Integer.parseInt(strhour) <= 23 && Integer.parseInt(strminute) < 10) { + basetime = "2000"; + } else + basetime = "2300"; + + + List coordList = new ArrayList<>(); + Coordinate coord = new Coordinate(); + Coordinate returnCoord = new Coordinate(); + coord.setX(rq.getNx()); + coord.setY(rq.getNy()); + returnCoord = this.wheather(coord); + + double nx = returnCoord.getX(); + double ny = returnCoord.getY(); + String Snx = String.format("%.0f", nx); + String Sny = String.format("%.0f", ny); + + urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + weatherKey); + urlBuilder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8")); + urlBuilder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("14", "UTF-8")); /*한 페이지 결과 수*/ + urlBuilder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode("JSON", "UTF-8")); /*요청자료형식(XML/JSON) Default: XML*/ + urlBuilder.append("&" + URLEncoder.encode("base_date", "UTF-8") + "=" + URLEncoder.encode(strToday, "UTF-8")); /*'21년 6월 28일 발표*/ + urlBuilder.append("&" + URLEncoder.encode("base_time", "UTF-8") + "=" + URLEncoder.encode(basetime, "UTF-8")); /*06시 발표(정시단위) */ + urlBuilder.append("&" + URLEncoder.encode("nx", "UTF-8") + "=" + URLEncoder.encode(Snx, "UTF-8")); /*예보지점의 X 좌표값*/ + urlBuilder.append("&" + URLEncoder.encode("ny", "UTF-8") + "=" + URLEncoder.encode(Sny, "UTF-8")); /*예보지점의 Y 좌표값*/ + URL url = new URL(urlBuilder.toString()); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Content-type", "application/json"); + log.info("Response code: " + conn.getResponseCode()); + BufferedReader rd; + if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) { + rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + } else { + rd = new BufferedReader(new InputStreamReader(conn.getErrorStream())); + } + StringBuilder sb = new StringBuilder(); + String line; + while ((line = rd.readLine()) != null) { + sb.append(line); + } + CtrTrnsLctnModel weatherResult = ctrTrnsLctnService.convertLatlonToAddress(rq.getNx(), rq.getNy()); + log.info("weatherResult >>>> : {}", weatherResult); + + String str = sb.toString(); + JSONParser parser = new JSONParser(); + JSONObject jsonObject = (JSONObject) parser.parse(str); + if (weatherResult != null) { + jsonObject.put("area1", weatherResult.getArea1()); + jsonObject.put("area2", weatherResult.getArea2()); + jsonObject.put("area3", weatherResult.getArea3()); + jsonObject.put("landNm", weatherResult.getLandNm()); + jsonObject.put("landNum", weatherResult.getLandNum()); + } + rd.close(); + conn.disconnect(); + log.info(sb.toString()); + + return jsonObject; + } + + public Coordinate wheather(Coordinate coord) { + double nx; + double ny; + nx = coord.getX(); + ny = coord.getY(); + double RE = 6371.00877; // 지구 반경(km) + double GRID = 5.0; // 격자 간격(km) + double SLAT1 = 30.0; // 투영 위도1(degree) + double SLAT2 = 60.0; // 투영 위도2(degree) + double OLON = 126.0; // 기준점 경도(degree) + double OLAT = 38.0; // 기준점 위도(degree) + double XO = 43; // 기준점 X좌표(GRID) + double YO = 136; // 기1준점 Y좌표(GRID) + + // + // LCC DFS 좌표변환 ( code : "TO_GRID"(위경도->좌표, lat_X:위도, lng_Y:경도), "TO_GPS"(좌표->위경도, lat_X:x, lng_Y:y) ) + // + + double DEGRAD = Math.PI / 180.0; + double RADDEG = 180.0 / Math.PI; + + double re = RE / GRID; + double slat1 = SLAT1 * DEGRAD; + double slat2 = SLAT2 * DEGRAD; + double olon = OLON * DEGRAD; + double olat = OLAT * DEGRAD; + + double sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5); + sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn); + double sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5); + sf = Math.pow(sf, sn) * Math.cos(slat1) / sn; + double ro = Math.tan(Math.PI * 0.25 + olat * 0.5); + ro = re * sf / Math.pow(ro, sn); + + double theta; + if (true) { + nx = nx; + ny = ny; + double ra = Math.tan(Math.PI * 0.25 + (nx) * DEGRAD * 0.5); + ra = re * sf / Math.pow(ra, sn); + theta = ny * DEGRAD - olon; + if (theta > Math.PI) theta -= 2.0 * Math.PI; + if (theta < -Math.PI) theta += 2.0 * Math.PI; + theta *= sn; + nx = Math.floor(ra * Math.sin(theta) + XO + 0.5); + ny = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5); + } else { + nx = nx; + ny = ny; + double xn = nx - XO; + double yn = ro - ny + YO; + double ra = Math.sqrt(xn * xn + yn * yn); + if (sn < 0.0) { + ra = -ra; + } + + double alat = Math.pow((re * sf / ra), (1.0 / sn)); + alat = 2.0 * Math.atan(alat) - Math.PI * 0.5; + + if (Math.abs(xn) <= 0.0) { + theta = 0.0; + } else { + if (Math.abs(yn) <= 0.0) { + theta = Math.PI * 0.5; + if (xn < 0.0) { + theta = -theta; + } + } else theta = Math.atan2(xn, yn); + } + double alon = theta / sn + olon; + nx = alat * RADDEG; + ny = alon * RADDEG; + } + + Coordinate returnCoord = new Coordinate(); + returnCoord.setX(nx); + returnCoord.setY(ny); + return returnCoord; + } + + /** + * TODO 비행 종료 데이터 상세 조회 + * + * @param controlId + * @return + */ + public CtrCntrlArcrftComplModel getComplete(String controlId) { + + CtrCntrlArcrftComplModel result = new CtrCntrlArcrftComplModel(); + List completeInfo = query.getCompleteInfo(controlId); + + Double mvDistanceAll = 0.0; + Duration duration = null; + + if (completeInfo.size() > 2) { + + + Instant start = completeInfo.get(0).getSrvrRcvDt(); + Instant end = completeInfo.get(completeInfo.size() - 1).getSrvrRcvDt(); + + if (start != null && end != null) { + LocalDate startDate = start.atZone(ZoneId.of("Asia/Seoul")).toLocalDate(); + LocalDate endDate = end.atZone(ZoneId.of("Asia/Seoul")).toLocalDate(); + + duration = Duration.between(startDate, endDate); + } + + for (int from = 0, to = 1; from < completeInfo.size() - 2; from++, to++) { + Coordinate fromCoord = new Coordinate(); + Coordinate toCoord = new Coordinate(); + + fromCoord.setX(completeInfo.get(from).getLat()); + fromCoord.setY(completeInfo.get(from).getLon()); + toCoord.setX(completeInfo.get(to).getLat()); + toCoord.setY(completeInfo.get(to).getLon()); + if (fromCoord.x != toCoord.x || fromCoord.y != toCoord.y) { - + double distance = calculateDistance(fromCoord, toCoord); - + mvDistanceAll += distance; - } - } - } - - double speedAvg = completeInfo.stream() + } + } + } + + double speedAvg = completeInfo.stream() .mapToDouble(CtrCntrlHstry::getSpeed) // Integer를 int로 매핑 .average() .orElse(0.0); - - double elevAvg = completeInfo.stream() + + double elevAvg = completeInfo.stream() .mapToDouble(CtrCntrlHstry::getElev) // Integer를 int로 매핑 .average() .orElse(0.0); - - result.setElevAvg(elevAvg); - result.setSpeedAvg(speedAvg); - result.setMvDistance(mvDistanceAll*1000); - if(duration != null) result.setMvTime(duration.toString()); - - return result; - } - - public static double calculateDistance(Coordinate coord1, Coordinate coord2) { + + result.setElevAvg(elevAvg); + result.setSpeedAvg(speedAvg); + result.setMvDistance(mvDistanceAll * 1000); + if (duration != null) result.setMvTime(duration.toString()); + + return result; + } + + public static double calculateDistance(Coordinate coord1, Coordinate coord2) { double earthRadius = 6371; // 지구의 반지름 (단위: km) // 위도와 경도를 라디안으로 변환 @@ -883,11 +879,11 @@ public class CtrCntrlService { double dlon = lon2 - lon1; double dlat = lat2 - lat1; double a = Math.sin(dlat / 2) * Math.sin(dlat / 2) - + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon / 2) * Math.sin(dlon / 2); + + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon / 2) * Math.sin(dlon / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = earthRadius * c; return distance; } - + } diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java index 7fbabb3..405d771 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java @@ -10,6 +10,7 @@ import java.util.Date; import java.util.List; import com.palnet.biz.api.main.dash.model.MainDashFlightNumStcsModel; +import com.palnet.biz.jpa.entity.*; import com.querydsl.core.Tuple; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -32,23 +33,6 @@ import com.palnet.biz.api.ctr.cntrl.model.CtrCntrlGroupArcrftModel; import com.palnet.biz.api.ctr.cntrl.model.CtrCntrlGroupModel; import com.palnet.biz.api.main.dash.model.MainDashStcsModel; import com.palnet.biz.api.main.statistics.model.FlightStcsValueModel; -import com.palnet.biz.jpa.entity.ComArcrftBas; -import com.palnet.biz.jpa.entity.ComIdntfBas; -import com.palnet.biz.jpa.entity.CtrCntrlHstry; -import com.palnet.biz.jpa.entity.CtrCntrlHstryArea; -import com.palnet.biz.jpa.entity.FltPlanArea; -import com.palnet.biz.jpa.entity.FltPlanBas; -import com.palnet.biz.jpa.entity.QComArcrftBas; -import com.palnet.biz.jpa.entity.QComIdntfBas; -import com.palnet.biz.jpa.entity.QCtrCntrlBas; -import com.palnet.biz.jpa.entity.QCtrCntrlHstry; -import com.palnet.biz.jpa.entity.QCtrCntrlHstryArea; -import com.palnet.biz.jpa.entity.QCtrCntrlWarnLog; -import com.palnet.biz.jpa.entity.QFltPlanArea; -import com.palnet.biz.jpa.entity.QFltPlanBas; -import com.palnet.biz.jpa.entity.QFltPlanCtrCntrlRel; -import com.palnet.biz.jpa.entity.QPtyCstmrGroup; -import com.palnet.biz.jpa.entity.QPtyGroupBas; import com.palnet.comn.model.GPHistoryModel; import com.palnet.comn.utils.DateUtils; import com.palnet.comn.utils.InstantUtils; @@ -1311,6 +1295,64 @@ public List listCntrlHstry(String id){ return result; } + + // TODO 임시 수정 + public CtrCntrlDtlModel detailCntrlForKac(String controlId) { + QCtrCntrlBas ctr = QCtrCntrlBas.ctrCntrlBas; +// QComArcrftBas cBas = QComArcrftBas.comArcrftBas; +// QComIdntfBas own = QComIdntfBas.comIdntfBas; + QFltPlanArcrft fltArcrft = QFltPlanArcrft.fltPlanArcrft; + QFltPlanPilot fltPilot = QFltPlanPilot.fltPlanPilot; + QFltPlanCtrCntrlRel rel = QFltPlanCtrCntrlRel.fltPlanCtrCntrlRel; + QFltPlanBas fBas = QFltPlanBas.fltPlanBas; + + CtrCntrlDtlModel result = query.select(Projections.bean(CtrCntrlDtlModel.class, + ctr.cntrlId, + ctr.cntrlStDt, + ctr.cntrlEndDt, + fltArcrft.arcrftSno, + fltArcrft.prdctNum, + fltArcrft.arcrftTypeCd.stringValue().as("arcrftTypeCd"), + fltArcrft.arcrftModelNm, + fltArcrft.prdctCmpnNm, + fltArcrft.wghtTypeCd, + fltArcrft.imageUrl, + fltArcrft.cameraYn, + fltArcrft.insrncYn, + fltArcrft.ownerNm, + fltPilot.hpno, + fBas.corpRegYn, + fBas.aprvlDt, + fBas.aprvlYn + )) + .from(ctr) + .leftJoin(rel) + .on(ctr.cntrlId.eq(rel.cntrlId)) + .leftJoin(fBas) + .on(rel.planSno.eq(fBas.planSno)) + .leftJoin(fltArcrft) + .on(fBas.planSno.eq(fltArcrft.planSno).and(ctr.idntfNum.eq(fltArcrft.idntfNum))) + .leftJoin(fltPilot) + .on(fBas.planSno.eq(fltPilot.planSno)) + .where(ctr.cntrlId.eq(controlId)) + .orderBy(ctr.createDt.desc()) + .fetchFirst(); + + + if (result == null) return new CtrCntrlDtlModel(); + +// if(!StringUtils.isEmpty(result.getOwnerNm())) { +//// result.setOwnerNm(EncryptUtils.decrypt(result.getOwnerNm())); +//// } +//// if(!StringUtils.isEmpty(result.getHpno())) { +//// result.setHpno(EncryptUtils.decrypt(result.getHpno())); +//// } +//// if(!StringUtils.isEmpty(result.getTelno())) { +//// result.setTelno(EncryptUtils.decrypt(result.getTelno())); +//// } + return result; + + } /** * 상세보기 조회