Browse Source

Merge pull request 'pull request' (#1) from master into LAANC-QR-CODE

Reviewed-on: pav/pav-fe-kac#1
pull/2/head
박상현 9 months ago
parent
commit
84c0303ac4
  1. 3137
      src/assets/images/3dpea.gltf
  2. 8
      src/components/laanc/map/FlightArea.js
  3. 6
      src/components/laanc/map/LaancAreaMap.js
  4. 73
      src/components/laanc/map/LaancComn.js
  5. 2
      src/components/laanc/map/LaancDrawControl.js
  6. 347
      src/components/map/mapbox/MapBoxMap.js
  7. 37
      src/components/map/mapbox/dron/DronMarker.js
  8. 458
      src/components/map/mapbox/dron/DronPlan.js
  9. 9
      src/components/map/mapbox/dron/DronToast.js
  10. 15
      src/components/map/mapbox/feature/FeatureAirZone.js
  11. BIN
      src/components/map/mapbox/models/out.glb
  12. BIN
      src/components/map/mapbox/models/scene.bin
  13. 4631
      src/components/map/mapbox/models/scene.gltf
  14. 73
      src/utility/MapUtils.js

3137
src/assets/images/3dpea.gltf

File diff suppressed because one or more lines are too long

8
src/components/laanc/map/FlightArea.js

@ -21,8 +21,9 @@ import {
layerBuffer,
layerPolygon,
layerPolyline,
layerWayPoint
} from '../../../utility/DrawUtil';
layerWayPoint,
handlerCreateAirSpace
} from '../../../utility/MapUtils';
// actions
import {
AREA_COORDINATE_LIST_SAVE,
@ -42,7 +43,6 @@ import { WeatherContainer } from '../../../containers/basis/flight/plan/WeatherC
import { initFlightBas } from '../../../modules/laanc/models/laancModels';
import LaancAreaMap from './LaancAreaMap';
import LaancDrawModal from './LaancDrawModal';
import { handlerCreateAirSpace } from './LaancComn';
export default function FlightArea({
centeredModal,
@ -105,7 +105,7 @@ export default function FlightArea({
//날씨 위치 데이터
const [wheather, setWheather] = useState([]);
// 미니맵에 표출되는 비행구역 정보
// 미니맵에 표출되는 비행구역 geoJson 정보
const previewGeo = {
type: 'FeatureCollection',
features: []

6
src/components/laanc/map/LaancAreaMap.js

@ -16,13 +16,13 @@ import { mapInitAction } from '../../../modules/control/map/actions/controlMapAc
import {
FormattingCoord,
handlerFitBounds,
handlerGetCircleCoord
} from '../../../utility/DrawUtil';
handlerGetCircleCoord,
handlerCreateAirSpace
} from '../../../utility/MapUtils';
import gimpo from '../../map/geojson/gimpoAirportAirArea.json';
import { FeatureAirZone } from '../../map/mapbox/feature/FeatureAirZone';
import LaancMapSearch from './LaancMapSearch';
import { LaancDrawControl } from './LaancDrawControl';
import { handlerCreateAirSpace } from './LaancComn';
export default function LaancAreaMap({
mapContainer,

73
src/components/laanc/map/LaancComn.js

@ -1,73 +0,0 @@
import { useSelector } from 'react-redux';
import geoJson from '../../map/geojson/airArea.json';
import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json';
// 공역 생성
export const handlerCreateAirSpace = (
map,
mapControl,
useGeoJson = {
...geoJson,
...flatGimpo,
features: [...geoJson.features, ...flatGimpo.features]
}
) => {
if (map.getLayer('maine')) {
map.removeLayer('maine');
map.removeSource('maine');
}
let arrGeoJson = [];
useGeoJson.features.map(item => {
if (item.properties.type === '0001' && mapControl.area0001) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FF3648' }
});
} else if (item.properties.type === '0002' && mapControl.area0002) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FFA1AA' }
});
} else if (item.properties.type === '0003' && mapControl.area0003) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FFA800' }
});
} else if (item.properties.type === '0004' && mapControl.area0004) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#A16B00' }
});
} else if (item.properties.type === '0005' && mapControl.area0005) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#AB40FF' }
});
} else if (item.properties.type === '0006' && mapControl.area0006) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#009cad' }
});
}
});
useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon');
// 공역 생성 start
map.addSource('maine', {
type: 'geojson',
data: {
...useGeoJson
}
});
map.addLayer({
id: 'maine',
type: 'fill',
source: 'maine',
layout: {},
paint: {
'fill-color': ['get', 'color'],
// 'fill-extrusion-height': 3000,
'fill-opacity': 0.5
}
});
};

2
src/components/laanc/map/LaancDrawControl.js

@ -9,7 +9,7 @@ import {
handlerRemoveAllMarker,
handlerRemoveGroupMarker,
handlerReturnMode
} from '../../../utility/DrawUtil';
} from '../../../utility/MapUtils';
import { drawTypeChangeAction } from '../../../modules/control/map/actions/controlMapActions';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import {

347
src/components/map/mapbox/MapBoxMap.js

@ -1,224 +1,31 @@
import { useEffect, useState, useRef, useLayoutEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
// mapbox
import 'mapbox-gl/dist/mapbox-gl.css';
import { MAPBOX_TOKEN } from '../../../configs/constants';
import mapboxgl from 'mapbox-gl';
import threebox from 'threebox-plugin';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
// import * as THREE from 'three';
import MapboxLanguage from '@mapbox/mapbox-gl-language';
import { MAPBOX_TOKEN } from '../../../configs/constants';
import { useEffect, useState, useRef, useLayoutEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { DronToast } from './dron/DronToast';
import { DronMarker } from './dron/DronMarker';
// import { DronHistory } from './dron/DronHistory';
// import MapBoxMapControl from './MapBoxMapControl';
// import { NaverMapSearch } from './search/NaverMapSearch';
import { DronPlan } from './dron/DronPlan';
import { FeatureAirZone } from './feature/FeatureAirZone';
import threebox from 'threebox-plugin';
import geoJson from '../../map/geojson/airArea.json';
// import gimPo from '../../map/geojson/gimpoAirportAirArea.json';
import gimPo from '../../map/geojson/gimpoAirportAirArea.json';
// 김포 격자 공역
import gimPoGrid from '../../../components/map/geojson/airportAirArea.json';
// 김포 선형 공역
import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json';
// import DronPlan from './dron/DronPlan';
// import NewDronPlan from './dron/NewDronPlan';
// import { NewDronHistory } from './dron/NewDronHistroy';
// import DronToast from './dron/DronToast';
// import SensorZone from './sensor/SensorZone';
import { mapInitAction } from '../../../modules/control/map/actions/controlMapActions';
import DronPlan from './dron/DronPlan';
import DronToast from './dron/DronToast';
import * as THREE from 'three';
// example 3d gltf 파일
import Gltf from '../../../assets/images/3dpea.gltf';
const uamPosition = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
name: 'V1',
background: '#ffffff',
border: '#15298A',
spanColor: '#000000'
},
geometry: {
type: 'Point',
coordinates: [126.540668, 37.4797865]
}
},
{
type: 'Feature',
properties: {
name: 'V2',
background: '#ffffff',
border: '#15298A',
spanColor: '#000000'
},
geometry: {
type: 'Point',
coordinates: [126.6107763, 37.521245]
}
},
{
type: 'Feature',
properties: {
name: 'V3',
background: '#ffffff',
border: '#15298A',
spanColor: '#000000'
},
geometry: {
type: 'Point',
coordinates: [126.6243464, 37.5642352]
}
},
{
type: 'Feature',
properties: {
name: 'V4',
background: '#ffffff',
border: '#15298A',
spanColor: '#000000'
},
geometry: {
type: 'Point',
coordinates: [126.6650669, 37.3658236]
}
},
{
type: 'Feature',
properties: {
name: 'V5',
background: '#ffffff',
border: '#15298A',
spanColor: '#000000'
},
geometry: {
type: 'Point',
coordinates: [126.7074861, 37.4520753]
}
},
{
type: 'Feature',
properties: {
name: 'R1',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.5801572, 37.492581]
}
},
{
type: 'Feature',
properties: {
name: 'R2',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6036588, 37.542031]
}
},
{
type: 'Feature',
properties: {
name: 'R3',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6005224, 37.5764269]
}
},
{
type: 'Feature',
properties: {
name: 'R4',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6600404, 37.5790407]
}
},
{
type: 'Feature',
properties: {
name: 'R5',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.649562, 37.524016]
}
},
{
type: 'Feature',
properties: {
name: 'R6',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.693722, 37.5506488]
}
},
{
type: 'Feature',
properties: {
name: 'R7',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6023981, 37.4712333]
}
},
{
type: 'Feature',
properties: {
name: 'R8',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6202759, 37.4046495]
}
},
{
type: 'Feature',
properties: {
name: 'R9',
background: '#429629',
border: '#ffffff',
spanColor: '#ffffff'
},
geometry: {
type: 'Point',
coordinates: [126.6296542, 37.3450207]
}
}
]
};
import UamGltf from './models/out.glb';
let gridCoords = [];
let altitudeMarker = [];
@ -263,51 +70,32 @@ let linerAltitude = [
let linerAltitudeMarker = [];
export default function MapBoxMap() {
const naver = window.naver;
const dispatch = useDispatch();
// 공역표출 타입
const mapControl = useSelector(state => state.controlMapReducer);
// 지도
const mapContainer = useRef(null);
const [mapObject, setMapObject] = useState(null);
// 지도 로드 여부
const [isMapLoaded, setMapLoaded] = useState(false);
const [arrPolyline, setArrPolyline] = useState([]);
// 노탐 정보 모달
const [centeredModal, setCenteredModal] = useState(false);
const mapContainer = useRef(null);
const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer);
// 비행예상경로 geoJson 정보
const [planGeo, setPlanGeo] = useState({
type: 'FeatureCollection',
features: []
});
// 지도 초기 셋팅
useLayoutEffect(() => {
mapBoxMapInit();
}, []);
// useEffect(() => {
// if (mapObject) {
// uamPosition.features.map(uam => {
// const el = document.createElement('div');
// const elChild = document.createElement('span');
// elChild.innerText = uam.properties.name;
// elChild.style.color = uam.properties.spanColor;
// el.className = 'marker';
// el.style.background = uam.properties.background;
// el.style.borderRadius = '50%';
// el.style.border = `4px solid ${uam.properties.border}`;
// el.style.padding = '5px';
// el.style.width = '40px';
// el.style.height = '40px';
// el.style.textAlign = 'center';
// el.appendChild(elChild);
// new mapboxgl.Marker(el)
// .setLngLat(uam.geometry.coordinates)
// .addTo(mapObject);
// });
// }
// }, [mapObject]);
// 공역 표출 정보에 따른 공역 변경
useEffect(() => {
console.log(mapObject);
if (mapObject) {
handlerCreateAirSpace(mapObject);
}
@ -321,6 +109,7 @@ export default function MapBoxMap() {
mapControl.liner
]);
// 공역 생성
const handlerCreateAirSpace = (
map,
useGeoJson = {
@ -494,6 +283,13 @@ export default function MapBoxMap() {
});
};
let stats;
const animate = () => {
requestAnimationFrame(animate);
stats.update();
};
// 맵박스 지도 초기 셋팅
const mapBoxMapInit = () => {
mapboxgl.accessToken = MAPBOX_TOKEN;
@ -515,9 +311,12 @@ export default function MapBoxMap() {
map,
map.getCanvas().getContext('webgl'),
{
defaultLights: true,
enableSelectingFeatures: true,
enableSelectingObjects: true,
enableTooltips: true,
defaultLights: true
enableDraggingObjects: true,
enableRotatingObjects: true,
enableTooltips: true
}
));
@ -629,6 +428,7 @@ export default function MapBoxMap() {
);
/*************************************************************** 3D UAM Model Layer 추기 코드 start */
// map.addLayer({
// id: 'custom-threebox-model',
// type: 'custom',
@ -636,9 +436,9 @@ export default function MapBoxMap() {
// onAdd: function () {
// // 3d model option
// const options = {
// obj: Gltf, // 3D Model 파일
// obj: UamGltf, // 3D Model 파일
// type: 'gltf', // 3D Model 확장자 타입
// scale: { x: 200, y: 200, z: 200 }, // 3D Model 크기 값
// scale: { x: 50, y: 50, z: 50 }, // 3D Model 크기 값
// units: 'meters', // 높이 단위
// rotation: { x: 90, y: -90, z: 0 } // // 3D Model 방향 각도 초기 값
// };
@ -646,7 +446,7 @@ export default function MapBoxMap() {
// tb.loadObj(options, model => {
// let longitude = 127.81101412107547; // 3D Model 경도 값
// const latitude = 37.510357; // 3D Model 위도 값
// let hei = 100; // 3D Model 높이 값
// let hei = 0; // 3D Model 높이 값
// model.setCoords([longitude, latitude, hei]); // 3D Model 위치 지정
// model.setRotation({ x: 0, y: 0, z: 241 }); // 3D Model 방향 각도 지정
@ -657,7 +457,26 @@ export default function MapBoxMap() {
// longitude += 0.001; // 경도를 약간 증가시킵니다.
// hei += 50; // 높이값 증가
// model.setCoords([longitude, latitude, hei]);
// }, 500);
// }, 1000);
// const mixer = new THREE.AnimationMixer(model);
// // 애니메이션 클립 찾기
// const clips = model.animations;
// if (clips && clips.length) {
// // 모든 애니메이션 클립 재생
// clips.forEach(clip => {
// mixer.clipAction(clip).play();
// });
// }
// function update() {
// mixer.update(0.005); // 프레임 간격을 제공하여 애니메이션을 업데이트합니다.
// // tb.update();
// requestAnimationFrame(update);
// }
// // 애니메이션 시작
// update();
// });
// },
@ -777,13 +596,13 @@ export default function MapBoxMap() {
'fill-outline-color': '#000000'
},
filter: ['in', '$type', 'Polygon']
// filter: ['==', ['get', 'id'], ['polygon', 'circle']]
});
setMapLoaded(true);
});
setMapObject(map);
dispatch(mapInitAction(map));
// map.on('style.load', () => {
// map.addLayer({
// id: 'custom-threebox-model',
@ -817,28 +636,6 @@ export default function MapBoxMap() {
// });
};
const createUamArea = uam => {
const title = uam.title;
const position = new naver.maps.LatLng(uam.lat, uam.lon);
const circle = new naver.maps.Circle({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#8a1c05',
fillOpacity: 0.1,
center: position,
// map: mapObject,
radius: 100,
clickable: true
});
// circle.setMap(mapObject);
};
const handleHistoryInit = line => {
setArrPolyline([...arrPolyline, line]);
};
return (
<>
<div
@ -848,28 +645,10 @@ export default function MapBoxMap() {
></div>
{isMapLoaded && mapObject ? (
<>
<DronToast />
<DronMarker map={mapObject} mapboxgl={mapboxgl} />
<DronPlan map={mapObject} planGeo={planGeo} setPlanGeo={setPlanGeo} />
<DronToast />
{/* <MapBoxMapControl map={mapObject} /> */}
{/* <DronHistory
map={mapObject}
naver={naver}
arrPolyline={arrPolyline}
handleHistoryInit={handleHistoryInit}
/> */}
{/* <NewDronHistory
map={mapObject}
naver={naver}
arrPolyline={arrPolyline}
handleHistoryInit={handleHistoryInit}
/> */}
<FeatureAirZone map={mapObject} mapboxgl={mapboxgl} />
{/* <NaverMapSearch map={mapObject} naver={naver} /> */}
{/* <SensorZone map={mapObject} naver={naver} /> */}
</>
) : null}

37
src/components/map/mapbox/dron/DronMarker.js

@ -1,4 +1,3 @@
import $ from 'jquery';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import '../../../../assets/css/custom.css';
@ -7,7 +6,6 @@ import FlightDetailIcon from '../../../../assets/images/airplan_pp.svg';
import DronIcon from '../../../../assets/images/drone-marker-icon.png';
import DronDetailIcon from '../../../../assets/images/drone-marker-icon-pulple.png';
import DronUamIcon from '../../../../assets/images/uam_icon.png';
import DronUamDetailIcon from '../../../../assets/images/uam_icon_purple.png';
import {
controlGpDtlAction,
controlGpFlightPlanAction,
@ -29,28 +27,27 @@ export const DronMarker = props => {
state => state.controlMapReducer,
shallowEqual
);
// const { controlGroupAuthInfo } = useSelector(
// state => state.controlGroupAuthState
// );
const { controlGpArcrftWarnList } = useSelector(
state => state.controlGpLogState
);
// 유저 정보
const { user } = useSelector(state => state.authState);
// 유저가 가입한 그룹 목록
const { joinList } = useSelector(state => state.groupState);
// 마커, 데이터 블록 배열
const [arrMarkers, setArrMarkers] = useState([]);
const [arrInfos, setArrInfos] = useState([]);
// 비행 기체 개수
const [count, setCount] = useState({
drone: [],
flight: []
});
// useLayoutEffect(() => {
// dispatch(controlGroupAuthAction.request());
// }, [controlGpList]);
// 유저가 속한 그룹 리스트 알아냄
useEffect(() => {
dispatch(
JOIN_LIST.request({
@ -59,6 +56,7 @@ export const DronMarker = props => {
);
}, []);
// 비행 기체 개수 계산
useEffect(() => {
if (count.drone.length > 0 || count.flight.length > 0) {
dispatch(
@ -79,12 +77,14 @@ export const DronMarker = props => {
}
}, [count]);
// 마커 생성 시 데이터 블록 자동 생성
useEffect(() => {
if (arrMarkers.length != 0) {
markerInfo(arrMarkers);
}
}, [arrMarkers]);
// 마커 셋팅
useEffect(() => {
markerInit();
}, [controlGpList]);
@ -158,7 +158,7 @@ export const DronMarker = props => {
// });
// }, [objectId]);
//마커를 그린다.
//마커 생성
const addMarkers = (position, id, controlId, gps) => {
const gpsCnt = {
gps: gps,
@ -286,23 +286,23 @@ export const DronMarker = props => {
}
};
// 마커 클릭 시 드론 상세 정보 표출
const handlerDronClick = marker => {
dispatch(objectClickAction(marker.controlId));
dispatch(controlGpDtlAction.request(marker.controlId));
// dispatch(controlGpFlightPlanAction.request(idntfNum));
};
//마커 삭제 한다.
//마커 삭제
const removeMarkers = marker => {
marker.remove();
};
// 마커 데이터 블록 삭제
// 데이터 블록 삭제
const removeInfos = info => {
info.remove();
};
//마커 위치 이동한다.
//마커 위치 이동
const moveMarkers = (marker, position, gps) => {
marker.setLngLat(position);
const warnList = controlGpArcrftWarnList?.filter(
@ -324,6 +324,7 @@ export const DronMarker = props => {
marker.setRotation(gps.heading);
};
// 데이터 블록 위치 이동
const moveInfos = (info, position, item, idx) => {
if (info) {
info.setLngLat([position.lng, position.lat]);
@ -353,7 +354,7 @@ export const DronMarker = props => {
}
};
//데이터가 없는 마커 모두 삭제 한다.
//데이터가 없는 마커 모두 삭제
const allRemoveMarkers = () => {
let isUnClick = false;
if (arrMarkers && controlGpList) {
@ -398,7 +399,7 @@ export const DronMarker = props => {
return isUnClick;
};
//마커 셋팅 한다.
//마커 셋팅
const markerInit = () => {
if (controlGpList) {
allRemoveMarkers();
@ -422,14 +423,17 @@ export const DronMarker = props => {
}
};
// 마커 목록 업데이트
const removeArrMarkers = arrData => {
setArrMarkers(arrData);
};
// 데이터블록 목록 업데이트
const updateArrInfos = arrData => {
setArrInfos(arrData);
};
// 데이터 블록 생성
const markerInfo = arrMarkers => {
arrMarkers.forEach((marker, idx) => {
// 중복 데이터블록 체크
@ -476,7 +480,6 @@ export const DronMarker = props => {
info._controlId = marker.controlId;
setArrInfos(m => [...m, info]);
// }
});
};

458
src/components/map/mapbox/dron/DronPlan.js

@ -1,431 +1,24 @@
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { handlerGetCircleCoord } from '../../../../utility/DrawUtil';
import { handlerGetCircleCoord } from '../../../../utility/MapUtils';
export const dummyPolyline = [
{
planSno: 242,
groupId: 'C807F9',
cstmrSno: 2,
memberName: '팔네트웍스',
email: 'dhji@palnet.co.kr',
hpno: '01082504456',
clncd: '+82',
schFltStDt: '2023-11-15 10:00:00',
schFltEndDt: '2023-11-15 16:31:18',
fltPurpose: 'EDUCATION_FLIGHT',
aprvlYn: 'Y',
delYn: 'N',
createUserId: 'palnet',
createDt: '2023-11-15 10:00:00',
updateUserId: 'palnet',
updateDt: '2023-11-15 10:00:00',
docState: 'R',
areaList: [
{
planAreaSno: 242,
planSno: 242,
areaType: 'LINE',
fltAreaAddr: '인천광역시 계양구 봉오대로463번길 26',
bufferZone: 100,
fltElev: '100',
createUserId: 'palnet',
createDt: '2023-11-14 15:57:21',
updateUserId: 'palnet',
updateDt: '2023-11-14 15:57:21',
docState: 'R',
coordList: [
{
planAreaCoordSno: 515,
planAreaSno: 242,
lat: 37.530121373976954,
lon: 126.69937537668989,
createUserId: 'palnet',
createDt: '2023-11-14 15:57:21',
docState: 'R'
},
{
planAreaCoordSno: 516,
planAreaSno: 242,
lat: 37.53072487369214,
lon: 126.70586394488811,
createUserId: 'palnet',
createDt: '2023-11-14 15:57:21',
docState: 'R'
},
{
planAreaCoordSno: 517,
planAreaSno: 242,
lat: 37.52748497586097,
lon: 126.70594405066777,
createUserId: 'palnet',
createDt: '2023-11-14 15:57:21',
docState: 'R'
}
],
bufferCoordList: [
{
lat: 37.5316197886034,
lon: 126.70573274477093,
docState: 'R'
},
{
lat: 37.531625304714495,
lon: 126.70590392813509,
docState: 'R'
},
{
lat: 37.53161017252108,
lon: 126.70607419460082,
docState: 'R'
},
{
lat: 37.531574739035676,
lon: 126.70623963959872,
docState: 'R'
},
{
lat: 37.53151981682155,
lon: 126.70639646913716,
docState: 'R'
},
{
lat: 37.53144666535704,
lon: 126.70654108681464,
docState: 'R'
},
{
lat: 37.531356962150426,
lon: 126.70667017629863,
docState: 'R'
},
{
lat: 37.53125276426794,
lon: 126.70678077737894,
docState: 'R'
},
{
lat: 37.53113646115761,
lon: 126.70687035385097,
docState: 'R'
},
{
lat: 37.53101071985107,
lon: 126.7069368516722,
docState: 'R'
},
{
lat: 37.53087842380056,
lon: 126.70697874605814,
docState: 'R'
},
{
lat: 37.530742606753975,
lon: 126.70699507643907,
docState: 'R'
},
{
lat: 37.527502707958675,
lon: 126.70707513332411,
docState: 'R'
},
{
lat: 37.526601887803295,
lon: 126.70709739090397,
docState: 'R'
},
{
lat: 37.526566413313844,
lon: 126.70483525338567,
docState: 'R'
},
{
lat: 37.52971486141971,
lon: 126.70475736339164,
docState: 'R'
},
{
lat: 37.529226466217224,
lon: 126.69950664996875,
docState: 'R'
},
{
lat: 37.52912191557935,
lon: 126.69838296584224,
docState: 'R'
},
{
lat: 37.53091172822204,
lon: 126.69812038962549,
docState: 'R'
},
{
lat: 37.5316197886034,
lon: 126.70573274477093,
docState: 'R'
}
]
}
],
arcrftList: [
{
arcrftSno: 1,
idntfNum: 'PA0001',
prdctNum: 'PAV_001_PPAL20230914',
arcrftTypeCd: '01',
arcrftModelNm: 'PAV_001',
prdctCmpnNm: 'PalNetworks',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
wghtTypeCd: '250G+2KG-',
takeoffWght: 0,
useYn: 'Y',
cameraYn: 'N',
insrncYn: 'Y',
createUserId: 'palnet',
createDt: '2023-09-14 17:32:59',
updateUserId: 'palnet',
updateDt: '2023-09-14 17:32:59',
docState: 'R'
}
],
corpRegYn: 'N',
serviceType: 'PAV-KAC'
}
];
export const dummyPolygon = [
{
planSno: 244,
groupId: 'C807F9',
cstmrSno: 2,
memberName: '팔네트웍스',
email: 'dhji@palnet.co.kr',
hpno: '01082504456',
clncd: '+82',
schFltStDt: '2023-11-15 16:26:13',
schFltEndDt: '2023-11-15 18:21:13',
fltPurpose: 'TRAFFIC_MANAGEMENT',
fltType: 'COMMERCIAL',
fltTypeNm: '상업용',
aprvlYn: 'Y',
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
updateUserId: 'palnet',
updateDt: '2023-11-15 16:22:46',
serviceType: 'PAV-KAC',
corpRegYn: 'N',
pdfUrl: '/api/comn/file/download/387',
areaList: [
{
planAreaSno: 244,
planSno: 244,
areaType: 'POLYGON',
fltAreaAddr: '인천광역시 계양구 26',
bufferZone: 0,
fltElev: '100',
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
updateUserId: 'palnet',
updateDt: '2023-11-15 16:22:46',
docState: 'R',
coordList: [
{
planAreaCoordSno: 522,
planAreaSno: 244,
lat: 37.575642815639966,
lon: 126.7053377657183,
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
docState: 'R'
},
{
planAreaCoordSno: 523,
planAreaSno: 244,
lat: 37.56753805633005,
lon: 126.7033921798162,
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
docState: 'R'
},
{
planAreaCoordSno: 524,
planAreaSno: 244,
lat: 37.56832705395003,
lon: 126.71429651010209,
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
docState: 'R'
},
{
planAreaCoordSno: 525,
planAreaSno: 244,
lat: 37.57553523611571,
lon: 126.71606111127,
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
docState: 'R'
}
]
}
],
arcrftList: [
{
planArcrftSno: 240,
planSno: 244,
arcrftSno: 0,
idntfNum: 'PA0001',
arcrftTypeCd: 'UNMANNED_AIRCRAFT',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
takeoffWght: 0,
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
updateUserId: 'palnet',
updateDt: '2023-11-15 16:22:46',
docState: 'R',
acrftInsuranceYn: 'N',
arcrftWghtCd: 'W250G_LOE'
}
],
pilotList: [
{
planPilotSno: 242,
planSno: 244,
cstmrSno: 2,
groupNm: 'KAC',
memberName: '팔네트웍스',
email: 'dhji@palnet.co.kr',
hpno: '01082504456',
clncd: '+82',
createUserId: 'palnet',
createDt: '2023-11-15 16:22:46',
updateUserId: 'palnet',
updateDt: '2023-11-15 16:22:46',
docState: 'R'
}
],
arcrftWght: '최대이륙중량 250g 이하',
elev: '100'
}
];
export const dummyCircle = [
{
planSno: 239,
groupId: 'C807F9',
cstmrSno: 2,
memberName: '팔네트웍스',
email: 'dhji@palnet.co.kr',
hpno: '01082504456',
clncd: '+82',
schFltStDt: '2023-11-14 12:01:00',
schFltEndDt: '2023-11-14 13:56:00',
fltPurpose: 'TRAFFIC_MANAGEMENT',
fltType: 'COMMERCIAL',
fltTypeNm: '상업용',
aprvlYn: 'Y',
createUserId: 'palnet',
createDt: '2023-11-13 11:59:10',
updateUserId: 'palnet',
updateDt: '2023-11-13 11:59:13',
serviceType: 'PAV-KAC',
corpRegYn: 'N',
pdfUrl: '/api/comn/file/download/382',
areaList: [
{
planAreaSno: 239,
planSno: 239,
areaType: 'CIRCLE',
fltMethod: 'CLOCK_FLIGHT',
fltAreaAddr: '인천광역시 부평구 401',
bufferZone: 100,
fltElev: '12',
createUserId: 'palnet',
createDt: '2023-11-13 11:59:10',
updateUserId: 'palnet',
updateDt: '2023-11-13 11:59:10',
docState: 'R',
coordList: [
{
planAreaCoordSno: 507,
planAreaSno: 239,
lat: 37.52165750816398,
lon: 126.71042734097875,
createUserId: 'palnet',
createDt: '2023-11-13 11:59:10',
docState: 'R'
}
]
}
],
arcrftList: [
{
planArcrftSno: 235,
planSno: 239,
arcrftSno: 0,
idntfNum: 'PA0001',
arcrftTypeCd: 'UNMANNED_AIRCRAFT',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
takeoffWght: 0,
createUserId: 'palnet',
createDt: '2023-11-13 11:59:10',
updateUserId: 'palnet',
updateDt: '2023-11-13 11:59:10',
docState: 'R',
acrftInsuranceYn: 'N',
arcrftWghtCd: 'W250G_LOE'
}
],
pilotList: [
{
planPilotSno: 237,
planSno: 239,
cstmrSno: 2,
groupNm: 'KAC',
memberName: '팔네트웍스',
email: 'dhji@palnet.co.kr',
hpno: '01082504456',
clncd: '+82',
createUserId: 'palnet',
createDt: '2023-11-13 11:59:10',
updateUserId: 'palnet',
updateDt: '2023-11-13 11:59:10',
docState: 'R'
}
],
elev: '12',
arcrftWght: '최대이륙중량 250g 이하'
}
];
export default function DronPlan({ map, planGeo, setPlanGeo }) {
export const DronPlan = ({ map, planGeo, setPlanGeo }) => {
const { controlGpList } = useSelector(state => state.controlGpState);
// 비행예상경로 목록
const { controlGpFltPlanList } = useSelector(
state => state.controlGpFltPlanState
);
const [objArr, setObjArr] = useState([]);
const [areaArr, setAreaArr] = useState([]);
const [bufferArr, setBufferArr] = useState([]);
// 비행중인 기체의 controlId 목록
const [controlIdArr, setControlIdArr] = useState([]);
useEffect(() => {
if (controlGpFltPlanList) {
console.log(controlGpFltPlanList, 'planList');
planInit();
}
}, [controlGpFltPlanList]);
// useEffect(() => {
// planInit();
// }, []);
useEffect(() => {
if (controlGpList) {
const listArr = controlGpList.map(gpList => {
@ -439,6 +32,7 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
}
}, [controlGpList]);
// 비행예상경로 geoJson 업데이트
const updatePlanGeo = feature => {
setPlanGeo(prev => ({
...prev,
@ -446,11 +40,8 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
}));
};
// 비행예상경로 생성 준비 셋팅
const planInit = () => {
// const planList = dummyPolyline;
// const planList = dummyPolygon;
// const planList = dummyCircle;
const planList = controlGpFltPlanList;
planList.forEach(plan => {
const areaList = plan.areaList;
@ -480,6 +71,7 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
map?.getSource('plan').setData(planGeo);
};
// circle 비행예상경로 생성
const createCircle = (paths, bufferZone, idntfNum) => {
const center = [paths[0][0], paths[0][1]];
const circlePaths = handlerGetCircleCoord(center, bufferZone);
@ -494,10 +86,10 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
properties: { id: 'circle', idntfNum: idntfNum }
};
updatePlanGeo(circle);
setObjArr(prev => [...prev, { idntfNum: idntfNum, obj: circle }]);
}
};
// polygon 비행예상경로 생성
const createPolygon = (paths, idntfNum) => {
if (paths && paths[0].length > 2) {
const polygon = {
@ -509,10 +101,10 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
properties: { id: 'polygon', idntfNum: idntfNum }
};
updatePlanGeo(polygon);
setObjArr(prev => [...prev, { idntfNum: idntfNum, obj: polygon }]);
}
};
// wayPoint 비행예상경로 생성
const createWayPoint = (paths, bufferList, idntfNum) => {
if (paths && paths.length > 1) {
const line = {
@ -524,7 +116,6 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
properties: { id: 'line', idntfNum: idntfNum }
};
updatePlanGeo(line);
setObjArr(prev => [...prev, { idntfNum: idntfNum, obj: line }]);
}
if (bufferList && bufferList.length > 1) {
@ -543,32 +134,23 @@ export default function DronPlan({ map, planGeo, setPlanGeo }) {
properties: { id: 'buffer', idntfNum: idntfNum }
};
updatePlanGeo(buffer);
setObjArr(prev => [...prev, { idntfNum: idntfNum, obj: buffer }]);
}
};
// 표출된 비행예상경로 삭제
const clear = diffArr => {
if (objArr) {
const clearObj = objArr
.filter(obj => diffArr.includes(obj.idntfNum))
.map(obj => obj.obj);
clearObj.map(obj => {
const feature = planGeo.features.filter(
geo => geo.properties.idntfNum !== obj.properties.idntfNum
);
setPlanGeo(prev => ({
...prev,
features: feature
}));
});
const saveObj = objArr.filter(obj => !diffArr.includes(obj.idntfNum));
setObjArr(saveObj);
if (planGeo.features.length > 0) {
const existObj = planGeo.features.filter(
obj => !diffArr.includes(obj.properties.idntfNum)
);
setPlanGeo(prev => ({
...prev,
features: existObj
}));
}
map?.getSource('plan').setData(planGeo);
};
return null;
}
};

9
src/components/map/mapbox/dron/DronToast.js

@ -12,16 +12,20 @@ import {
import Avatar from '../../../../@core/components/avatar';
import { Info } from 'react-feather';
export default function DronToast() {
export const DronToast = () => {
const dispatch = useDispatch();
const [playing, toggle] = useAudio(warning);
// 비정상상황 목록
const { controlGpArcrftWarnList } = useSelector(
state => state.controlGpLogState
);
const [toastId, setToastId] = useState();
let warningList = [];
// 비정상 toast표출 및 알림음 재생
useEffect(() => {
if (controlGpArcrftWarnList) {
if (!toastId) {
@ -64,6 +68,7 @@ export default function DronToast() {
}
}, [controlGpArcrftWarnList]);
// 기체 클릭 시
const handlerToastClick = (controlId, idntfNum) => {
dispatch(objectClickAction(controlId));
dispatch(controlGpDtlAction.request(controlId));
@ -93,4 +98,4 @@ export default function DronToast() {
};
return null;
}
};

15
src/components/map/mapbox/feature/FeatureAirZone.js

@ -1,17 +1,10 @@
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useEffect } from 'react';
import * as turf from '@turf/turf';
import geoJson from '../../../../components/map/geojson/airArea.json';
import '../../../../assets/css/custom.css';
// 격자 공역 Source
const airPort = [
// {
// title: '김포공항',
// buffer: 9300,
// center: [126.793722, 37.558522],
// reduce: [54.4, 218.6, 500, 905.4, 1459.8, 2195, 3173.5, 4552.5, 6952.5]
// },
{
title: '인천공항',
buffer: 9300,
@ -33,14 +26,13 @@ const airPort = [
];
export const FeatureAirZone = props => {
const mapControl = useSelector(state => state.controlMapReducer);
let popup;
let infoWindow;
useEffect(() => {
featureAirZoneInit();
}, []);
// 공역 정보 표출 window 생성
const infowindowOpen = data => {
const content =
'<div class="tooltip-box">' +
@ -74,6 +66,7 @@ export const FeatureAirZone = props => {
.addTo(props.map);
};
// 공역 정보 표출 이벤트 로직
const featureAirEvent = markers => {
markers.forEach(marker => {
marker.getElement().addEventListener('mouseover', e => {
@ -323,8 +316,6 @@ export const FeatureAirZone = props => {
'line-opacity': opacity
}
});
// Grid area
};
return null;

BIN
src/components/map/mapbox/models/out.glb

Binary file not shown.

BIN
src/components/map/mapbox/models/scene.bin

Binary file not shown.

4631
src/components/map/mapbox/models/scene.gltf

File diff suppressed because it is too large Load Diff

73
src/utility/DrawUtil.js → src/utility/MapUtils.js

@ -2,6 +2,9 @@ import * as turf from '@turf/turf';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import geoJson from '../components/map/geojson/airArea.json';
import flatGimpo from '../components/map/geojson/flatGimpoAirportAirArea.json';
// geojson Feature 형식으로 반환
export const InitFeature = (type, id) => {
return {
@ -234,3 +237,73 @@ export const layerBuffer = source => {
filter: ['==', ['get', 'id'], 'buffer']
};
};
// 공역 생성
export const handlerCreateAirSpace = (
map,
mapControl,
useGeoJson = {
...geoJson,
...flatGimpo,
features: [...geoJson.features, ...flatGimpo.features]
}
) => {
if (map.getLayer('maine')) {
map.removeLayer('maine');
map.removeSource('maine');
}
let arrGeoJson = [];
useGeoJson.features.map(item => {
if (item.properties.type === '0001' && mapControl.area0001) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FF3648' }
});
} else if (item.properties.type === '0002' && mapControl.area0002) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FFA1AA' }
});
} else if (item.properties.type === '0003' && mapControl.area0003) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#FFA800' }
});
} else if (item.properties.type === '0004' && mapControl.area0004) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#A16B00' }
});
} else if (item.properties.type === '0005' && mapControl.area0005) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#AB40FF' }
});
} else if (item.properties.type === '0006' && mapControl.area0006) {
arrGeoJson.push({
...item,
properties: { ...item.properties, color: '#009cad' }
});
}
});
useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon');
// 공역 생성 start
map.addSource('maine', {
type: 'geojson',
data: {
...useGeoJson
}
});
map.addLayer({
id: 'maine',
type: 'fill',
source: 'maine',
layout: {},
paint: {
'fill-color': ['get', 'color'],
// 'fill-extrusion-height': 3000,
'fill-opacity': 0.5
}
});
};
Loading…
Cancel
Save