// import {HMCesium} from '../../hmCesium.js';
// import {HMCesium} from 'http://172.16.42.101:9000/api/hmCesium/hmCesium.min.js';
// import {HMCesium} from 'http://172.16.42.101:5151/data/lib2_origin/hmCesium.min.js';
// import {HMCesium} from 'https://api.digitalarchive.work/hmCesium/hmCesium.min.js';
let searchParam = new URLSearchParams(window.location.search);
let initPosition;
if(searchParam.get('lon') && searchParam.get('lat')&&searchParam.get('height')){
initPosition = [searchParam.get('lon'), searchParam.get('lat'), searchParam.get('height'),6.28, -1.569];
}
let file = await readGSIM(searchParam.get('path'));
if(file){
initPosition = [file.flyTo[0],file.flyTo[1],file.flyTo[2]+3000];
}
let hmCesium = new HMCesium('mapContainer', // Cesium widget을 포함할 DOM 요소나 ID
{
// terrainUrl : 'http://gsim.hanmaceng.co.kr:5151/terrain_upzip/unzip_total_',
// terrainUrl : 'http://172.16.42.112:9000/terrain/unzip',
terrainUrl : file.terrain ? file.terrain : 'http://gsim.hanmaceng.co.kr:4040/terrain/total_',
imageryUrl : [
['URL',"https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png"],
['WMTS','https://api.vworld.kr/req/wmts/1.0.0/729B62A2-3E48-3E62-B180-7EF5EA3C07F4/Base/{TileMatrix}/{TileRow}/{TileCol}.png'],
['WMTS','https://api.vworld.kr/req/wmts/1.0.0/729B62A2-3E48-3E62-B180-7EF5EA3C07F4/Satellite/{TileMatrix}/{TileRow}/{TileCol}.jpeg'],
['WMTS','https://api.vworld.kr/req/wmts/1.0.0/729B62A2-3E48-3E62-B180-7EF5EA3C07F4/Hybrid/{TileMatrix}/{TileRow}/{TileCol}.png'],
['URL',"https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}&hl=en&scale=2&apistyle=s.e:l.i|p.v:off"],
['URL',"https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}&hl=en&scale=2&apistyle=s.e:l.i|p.v:off"],
['URL',"https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"],
['URL',"https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&hl=en&scale=2&apistyle=s.e:l.i|p.v:off"],
['URL',"https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png"]
],
setView:(initPosition)?initPosition:[126.72219913, 38.0632799256, 12283626, 6.28, -1.569],
// flyTo:(initPosition)?[initPosition[0], initPosition[1],initPosition[2]/10,initPosition[3],initPosition[4]]:[126.72219913, 38.0632799256, 1445272, 6.28, -1.569],
mapMode : '3D',
rotate2D : false,
mapEmphasize :(file.empMap<1000)? {
restrictCamera : true, //bool // true/false를 통해 카메라를 제한된 구역 안에서만 움직일 수 있게 해놓는다
center : [file.flyTo[0],file.flyTo[1],0],//lon, lat, height // 카메라의 중심점 설정
range : 1500,//전체 폴리곤 범위 //default : 1500 // 카메라가 움직일 수 있는 전체 영역을 지정한다.
holeRange : file.empMap,//강조 구역 범위 //단위 : km, default : 30 // empMap에 들어가보면 holeRange에 *1000이 되어있다. Cesium의 거리 unit은 m이기 때문에 km인것이다.
}:undefined,
},
{
//dom_option
slider : document.getElementById('slider'),
mouseInfo: document.querySelector('.footer-left'),
},
{
//function_option
}
);
hmCesium.viewer.scene.light = new Cesium.DirectionalLight({
direction: Cesium.Cartesian3.clone(hmCesium.viewer.scene.camera.directionWC),
intensity: 3.0,
color: Cesium.Color.WHITE
});
hmCesium.imageryLayer = {};
{
//searchparam에 .gsim경로 적어서 보내기...path는 main이 될 gsim파일
const searchParam = new URLSearchParams(window.location.search);
//searchParam 받아온 후에 주소창은 기본주소만 남도록 변경(개발 후에 적용)
// window.history.replaceState(null, null, '/')
//hmCesium에 path들어온 순차적으로 정보 넣기
// hmCesium.main = await readGSIM(searchParam.get('path'));
hmCesium.main = file;
//실제 로드부분
if(hmCesium.main.type == 'tileMap'){
await loadTileMap(hmCesium.main.url,hmCesium.main.name);
if(hmCesium.main.flyTo){
hmCesium.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],hmCesium.main.flyTo[2])
});
}
hmCesium.initCamera = hmCesium.main.flyTo;
document.getElementById('model-list').style.display = 'none';
}else if(hmCesium.main.type == 'geoJson'){
await loadGeoJson(hmCesium.main);
if(hmCesium.main.flyTo){
hmCesium.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],hmCesium.main.flyTo[2])
});
}
hmCesium.initCamera = hmCesium.main.flyTo;
document.getElementById('model-list').style.display = 'none';
//vietnam 특수
if(hmCesium.main.name == 'vietnam'){
await makeVietnamBill();
}
}else if(hmCesium.main.type == 'billboard'){
await loadBillboard(hmCesium.main);
if(hmCesium.main.flyTo){
hmCesium.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],hmCesium.main.flyTo[2])
});
}
hmCesium.initCamera = hmCesium.main.flyTo;
document.getElementById('model-list').style.display = 'none';
}else if(hmCesium.main.type=='3dTile' || !hmCesium.main.type){
await loadTileset(hmCesium.main);
// 다른이동은 이벤트 발생안함.
if(Object.keys(hmCesium.projectManager.tileset.main).length > 0){
hmCesium.viewer.flyTo(hmCesium.projectManager.tileset.main[Object.keys(hmCesium.projectManager.tileset.main)[0]]);
}
document.getElementById('model-list').style.display = 'none';
}else if(hmCesium.main.type == 'total'){
//gsim용
//유저 정보 확인
let userRes= await axios.get(`/auth/status`);
hmCesium.user = userRes.data.user;
//terrain 변경
// if(hmCesium.main.terrain){
// await changeTerrain(hmCesium.main.terrain);
// }
//empMap은 flyTo가 꼭 필요함
// if(hmCesium.main.empMap){
// let option = { mapEmphasize : {
// restrictCamera : true, //bool // true/false를 통해 카메라를 제한된 구역 안에서만 움직일 수 있게 해놓는다
// center : [hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],0],//lon, lat, height // 카메라의 중심점 설정
// range : 1500,//전체 폴리곤 범위 //default : 1500 // 카메라가 움직일 수 있는 전체 영역을 지정한다.
// holeRange : hmCesium.main.empMap,//강조 구역 범위 //단위 : km, default : 30 // empMap에 들어가보면 holeRange에 *1000이 되어있다. Cesium의 거리 unit은 m이기 때문에 km인것이다.
// }}
// await hmCesium.hmUtil.empMap.setEmphasize(option);
// }
//화면 이동
if(hmCesium.main.flyTo){
// hmCesium.viewer.camera.setView({
// destination : Cesium.Cartesian3.fromDegrees(hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],hmCesium.main.flyTo[2]+2000)
// });
hmCesium.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(hmCesium.main.flyTo[0],hmCesium.main.flyTo[1],hmCesium.main.flyTo[2])
});
hmCesium.initCamera = hmCesium.main.flyTo;
}
// document.getElementById('loading').style.display= 'none';
//메뉴 활성화
//title
document.getElementById('project-title').innerHTML = hmCesium.main.title;
document.getElementById('project-title').style.display = 'block';
//라벨생성, 이슈생성 쿼리 확인 후 버튼 보이기
if(hmCesium.main.query){
if(hmCesium.main.query.setLabel){
document.getElementById('func-label-btn').style.display = 'flex';
}
if(hmCesium.main.query.setIssue){
document.getElementById('func-issue-btn').style.display = 'flex';
}
}
//목록 만들기
if(hmCesium.main.model){
let modelList = document.getElementById('model-list');
let modelListRight = document.getElementById('model-list-right');
let ul = modelList.querySelector('ul');
ul.innerHTML = '';
//우측 리스트
let right_ul = modelListRight.querySelector('ul');
//라벨가져오기 셀렉트박스
let selectBox = document.getElementById('label-get-list');
selectBox.innerHTML = '';
let keys = Object.keys(hmCesium.main.model);
for(let i = 0; i < keys.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${keys[i].split('__')[0]}
${keys[i].split('__')[1]}
`;
let right_li = li.cloneNode(true);
ul.appendChild(li);
right_ul.appendChild(right_li);
li.querySelector('.list-title').addEventListener('click',async (e)=>{
if(hmCesium.curModel == keys[i]) return;
await resetLayerMode();
hmCesium.curModel = keys[i];
//레이어 셋팅
await setLayer(hmCesium.main.model[hmCesium.curModel].dLayer);
//이전 리스트 박스 삭제
let oldListBox = ul.querySelector('.list-box');
if(oldListBox)
oldListBox.remove();
let listBox = document.createElement('div');
listBox.classList.add('list-box');
let tilesetKeys = []
let shpKey = [];
if(hmCesium.main.model[keys[i]].tileset){
hmCesium.viewer.scene.groundPrimitives.removeAll();
for(let i = 0 ; i < hmCesium.viewer.dataSources._dataSources.length; i++){
if(hmCesium.viewer.dataSources._dataSources[i].name == 'labels'){
hmCesium.viewer.dataSources.remove(hmCesium.viewer.dataSources._dataSources[i]);
}
}
tilesetKeys = Object.keys(hmCesium.main.model[keys[i]].tileset);
}else if(hmCesium.main.model[keys[i]].shp){
hmCesium.viewer.scene.groundPrimitives.removeAll();
for(let i = 0 ; i < hmCesium.viewer.dataSources._dataSources.length; i++){
if(hmCesium.viewer.dataSources._dataSources[i].name == 'labels'){
hmCesium.viewer.dataSources.remove(hmCesium.viewer.dataSources._dataSources[i]);
}
}
shpKey = Object.keys(hmCesium.main.model[keys[i]].shp);
}else if(hmCesium.main.model[keys[i]].polyline){
await loadGeoJson(hmCesium.main.model[keys[i]]);
await makeVietnamBill(hmCesium.main.model[keys[i]].label);
}
for(let j = 0; j < tilesetKeys.length; j++){
let section = document.createElement('div');
section.classList.add('list-box-section');
section.innerHTML = `
`;
listBox.appendChild(section);
//section Event
//on/off
section.querySelector('#plate').addEventListener('click',(e)=>{
let label = e.target.closest('.checkbox-label');
let visibilityIcon = label.querySelector('.visibility-icon');
let checkbox = e.target.closest('input[type="checkbox"]');
let visibleSrc = checkbox.dataset.iconVisible;
let invisibleSrc = checkbox.dataset.iconInvisible;
if (!checkbox.checked) {
label.style.opacity = '0.2';
if (visibilityIcon) visibilityIcon.src = invisibleSrc;
} else {
label.style.opacity = '1';
if (visibilityIcon) visibilityIcon.src = visibleSrc;
}
let id = tilesetKeys[j];
hmCesium.projectManager.tileset.main[id].show = checkbox.checked;
hmCesium.viewer.scene.render();
});
//color change
section.querySelector('.model-color-picker').addEventListener('input',hmCesium.hmUtil.ThrottleTimer((e)=>{
let id = tilesetKeys[j];
let color = e.target.closest('input[type="color"]').value;
let opacity = e.target.closest('input[type="color"]').parentNode.querySelector('input[type="range"]').value;
hmCesium.projectManager.tileset.main[id].style = new Cesium.Cesium3DTileStyle({
color : `color("${color}",${1-opacity})`
});
hmCesium.projectManager.tileset.main[id].color = color;
hmCesium.projectManager.tileset.main[id].opacity = 1-opacity;
hmCesium.viewer.scene.render();
}),50);
//opacity
section.querySelector('.z-scaleBar-gauge .slider').addEventListener('input', (e)=>{
let id = tilesetKeys[j];
let color = e.target.closest('input[type="range"]').parentNode.parentNode.querySelector('input[type="color"]').value;
let opacity = e.target.closest('input[type="range"]').value;
hmCesium.projectManager.tileset.main[id].style = new Cesium.Cesium3DTileStyle({
color : `color("${color}",${1-opacity})`
});
hmCesium.projectManager.tileset.main[id].color = color;
hmCesium.projectManager.tileset.main[id].opacity = 1-opacity;
hmCesium.viewer.scene.render();
})
}
///shp
for(let j = 0; j < shpKey.length; j++){
let section = document.createElement('div');
section.classList.add('list-box-section');
section.innerHTML = `
`;
listBox.appendChild(section);
//section Event
//on/off
section.querySelector('#plate').addEventListener('click',(e)=>{
let label = e.target.closest('.checkbox-label');
let visibilityIcon = label.querySelector('.visibility-icon');
let checkbox = e.target.closest('input[type="checkbox"]');
let visibleSrc = checkbox.dataset.iconVisible;
let invisibleSrc = checkbox.dataset.iconInvisible;
if (!checkbox.checked) {
label.style.opacity = '0.2';
if (visibilityIcon) visibilityIcon.src = invisibleSrc;
} else {
label.style.opacity = '1';
if (visibilityIcon) visibilityIcon.src = visibleSrc;
}
let id = shpKey[j];
hmCesium.imageryLayer['main'].show = checkbox.checked;
hmCesium.viewer.scene.render();
});
}
//shp end
li.appendChild(listBox);
await deleteTileset('main');
await deleteAllTileMap('main');
// await resetMode();
if(hmCesium.main.model[keys[i]].tileset){
await loadTileset(hmCesium.main.model[keys[i]].tileset);
}else if(hmCesium.main.model[keys[i]].shp){
//shp load
await loadTileMap(hmCesium.main.model[keys[i]].shp[shpKey[0]],'main');
}
li.parentNode.querySelectorAll('li').forEach(ele=>{
ele.classList.remove('select-list');
})
li.classList.add('select-list');
})
right_li.querySelector('.list-title').addEventListener('click',async (e)=>{
if(hmCesium.splitModel == keys[i]) return;
hmCesium.splitModel = keys[i];
//이전 리스트 박스 삭제
let oldListBox = right_ul.querySelector('.list-box');
if(oldListBox)
oldListBox.remove();
let listBox = document.createElement('div');
listBox.classList.add('list-box');
let tilesetKeys = []
let shpKey = [];
if(hmCesium.main.model[keys[i]].tileset){
tilesetKeys = Object.keys(hmCesium.main.model[keys[i]].tileset);
}else{
shpKey = Object.keys(hmCesium.main.model[keys[i]].shp);
}
for(let j = 0; j < tilesetKeys.length; j++){
let section = document.createElement('div');
section.classList.add('list-box-section');
section.innerHTML = `
`;
listBox.appendChild(section);
//section Event
//on/off
section.querySelector('#plate').addEventListener('click',(e)=>{
let label = e.target.closest('.checkbox-label');
let visibilityIcon = label.querySelector('.visibility-icon');
let checkbox = e.target.closest('input[type="checkbox"]');
let visibleSrc = checkbox.dataset.iconVisible;
let invisibleSrc = checkbox.dataset.iconInvisible;
if (!checkbox.checked) {
label.style.opacity = '0.2';
if (visibilityIcon) visibilityIcon.src = invisibleSrc;
} else {
label.style.opacity = '1';
if (visibilityIcon) visibilityIcon.src = visibleSrc;
}
let id = tilesetKeys[j];
hmCesium.projectManager.tileset.split[id].show = checkbox.checked;
hmCesium.viewer.scene.render();
});
//color change
section.querySelector('.model-color-picker').addEventListener('input',hmCesium.hmUtil.ThrottleTimer((e)=>{
let id = tilesetKeys[j];
let color = e.target.closest('input[type="color"]').value;
let opacity = e.target.closest('input[type="color"]').parentNode.querySelector('input[type="range"]').value;
hmCesium.projectManager.tileset.split[id].style = new Cesium.Cesium3DTileStyle({
color : `color("${color}",${1-opacity})`
});
hmCesium.projectManager.tileset.split[id].color = color;
hmCesium.projectManager.tileset.split[id].opacity = 1-opacity;
hmCesium.viewer.scene.render();
}),50);
//opacity
section.querySelector('.z-scaleBar-gauge .slider').addEventListener('input', (e)=>{
let id = tilesetKeys[j];
let color = e.target.closest('input[type="range"]').parentNode.parentNode.querySelector('input[type="color"]').value;
let opacity = e.target.closest('input[type="range"]').value;
hmCesium.projectManager.tileset.split[id].style = new Cesium.Cesium3DTileStyle({
color : `color("${color}",${1-opacity})`
});
hmCesium.projectManager.tileset.split[id].color = color;
hmCesium.projectManager.tileset.split[id].opacity = 1-opacity;
hmCesium.viewer.scene.render();
})
}
///shp
for(let j = 0; j < shpKey.length; j++){
let section = document.createElement('div');
section.classList.add('list-box-section');
section.innerHTML = `
`;
listBox.appendChild(section);
//section Event
//on/off
section.querySelector('#plate').addEventListener('click',(e)=>{
let label = e.target.closest('.checkbox-label');
let visibilityIcon = label.querySelector('.visibility-icon');
let checkbox = e.target.closest('input[type="checkbox"]');
let visibleSrc = checkbox.dataset.iconVisible;
let invisibleSrc = checkbox.dataset.iconInvisible;
if (!checkbox.checked) {
label.style.opacity = '1';
if (visibilityIcon) visibilityIcon.src = invisibleSrc;
} else {
label.style.opacity = '1';
if (visibilityIcon) visibilityIcon.src = visibleSrc;
}
let id = shpKey[j];
hmCesium.imageryLayer['split'].show = checkbox.checked;
hmCesium.viewer.scene.render();
});
}
//shp end
right_li.appendChild(listBox);
await deleteTileset('split');
await deleteAllTileMap('split');
// await resetMode();
if(hmCesium.main.model[keys[i]].tileset){
await loadTileset(hmCesium.main.model[keys[i]].tileset, 'split');
}else if(hmCesium.main.model[keys[i]].shp){
//shp load
await loadTileMap(hmCesium.main.model[keys[i]].shp[shpKey[0]],'split');
}
right_li.parentNode.querySelectorAll('li').forEach(ele=>{
ele.classList.remove('select-list');
})
right_li.classList.add('select-list');
})
let selectLi = document.createElement('li');
selectLi.innerHTML = `${keys[i].split('__')[1]}`;
selectLi.id = `select-${keys[i]}`;
selectBox.appendChild(selectLi);
selectLi.addEventListener('click',()=>{
document.getElementById('label-get-selected').innerHTML = `${keys[i].split('__')[1]}`;
document.getElementById('label-get-selected').selectedModel = keys[i];
document.querySelector('.dropdown').classList.toggle('open');
})
}
modelList.style.display = 'flex';
}
//리스트 접기
document.querySelector('#model-list .window-header').addEventListener('click', (e)=>{
document.querySelector('#model-list .icon').classList.toggle('fold-icon');
if(document.querySelector('#model-list .icon').classList.contains('fold-icon')){
document.getElementById('left-list-title').innerHTML = `${hmCesium.curModel.split('__')[1]}`;
document.querySelector('#model-list .window-body').style.display = 'none';
}else{
document.getElementById('left-list-title').innerHTML = hmCesium.projectManager.flag.split?'좌측화면 모델':`모델기반(3D)`;
document.querySelector('#model-list .window-body').style.display = 'flex';
}
})
document.querySelector('#model-list-right .window-header').addEventListener('click', (e)=>{
document.querySelector('#model-list-right .icon').classList.toggle('fold-icon');
if(document.querySelector('#model-list-right .icon').classList.contains('fold-icon')){
document.getElementById('right-list-title').innerHTML = `${document.querySelector('#model-list-right li .list-box').parentElement.querySelector('h4').innerHTML}`;
document.querySelector('#model-list-right .window-body').style.display = 'none';
}else{
document.getElementById('right-list-title').innerHTML = `우측화면 모델`;
document.querySelector('#model-list-right .window-body').style.display = 'flex';
}
})
//중앙 메뉴 활성화
document.getElementById('func-btns').style.display = 'flex';
//레이어버튼 활성화
document.getElementById('set-layer').style.display = 'flex';
//마지막 모델 리스트 강제 클릭
document.getElementById('model-list').querySelector('ul').lastElementChild.querySelector('.list-title').click();
}
}
async function resetLayerMode(){
let onMode = document.getElementById('func-btns').querySelector('.on');
if(onMode && onMode.id != 'func-split-btn'){
onMode.click();
}
if(document.getElementById('func-label-add').style.display == 'flex'){
document.getElementById('func-label-add').style.display = 'none';
}
if(document.getElementById('func-issue-add').style.display == 'flex'){
document.getElementById('func-issue-add').style.display = 'none';
}
//layer전체 종료
if(document.getElementById('wpb-layer-btn').querySelector('input').checked){
document.getElementById('wpb-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('wpb-layer-btn').querySelector('input').dispatchEvent(event);
}
if(document.getElementById('plane-layer-btn').querySelector('input').checked){
document.getElementById('plane-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('plane-layer-btn').querySelector('input').dispatchEvent(event);
}
if(document.getElementById('siteLine-layer-btn').querySelector('input').checked){
document.getElementById('siteLine-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('siteLine-layer-btn').querySelector('input').dispatchEvent(event);
}
if(document.getElementById('label-layer-btn').querySelector('input').checked){
document.getElementById('label-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
}
if(document.getElementById('issue-layer-btn').querySelector('input').checked){
document.getElementById('issue-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
}
//measure layer 청소
initMeasure('clear');
}
//전체 모드 종료
async function resetMode(){
hmCesium.resetTileMode('split');
hmCesium.resetTileMode('overlap');
// hmCesium.resetTileMode('zScale');
// hmCesium.resetTileMode('wireframe');
}
async function readGSIM(path){
try {
const response = await fetch(path);
// 응답 상태 확인
if (!response.ok) {
throw new Error(`HTTP 오류! 상태: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(`파일을 읽는 중 오류 발생: ${error.message}`);
}
}
async function loadTileMap(imgTileUrl, imgLayerName){
const viewer = hmCesium.viewer;
const imageryLayer = Cesium.ImageryLayer.fromProviderAsync(
Cesium.TileMapServiceImageryProvider.fromUrl(
Cesium.buildModuleUrl(imgTileUrl)
)
);
viewer.imageryLayers.add(imageryLayer);
imageryLayer.name = imgLayerName;
imageryLayer.show = true;
hmCesium.imageryLayer[imgLayerName] = imageryLayer;
if(imgLayerName == 'split'){
hmCesium.imageryLayer[imgLayerName].splitDirection = Cesium.SplitDirection.RIGHT;
}
if(hmCesium.projectManager.flag.split && imgLayerName == 'main'){
hmCesium.imageryLayer[imgLayerName].splitDirection = Cesium.SplitDirection.LEFT;
}
}
async function deleteAllTileMap(name){
let key = Object.keys(hmCesium.imageryLayer);
for(let i = 0; i < key.length; i++){
if(key[i] == name){
hmCesium.viewer.imageryLayers.remove(hmCesium.imageryLayer[key[i]]);
delete hmCesium.imageryLayer[key[i]];
}
}
}
async function loadGeoJson(json){
document.getElementById('progress').style.display = 'flex';
let polyline, polygon, point;
let progressCount = 0;
if(json.point){
await readGeoJSONFile(`${json.point}`)
.then((data) => {
if (data) {
point = data;
}
})
.catch((error) => {
console.error("point read 오류 발생:", error);
});
}
if(json.polyline){
let url = json.polyline;
if(url instanceof Object){
let key = Object.keys(url);
url = url[key[0]];
}
await readGeoJSONFile(`${url}`)
.then((data) => {
if (data) {
polyline = data;
}
})
.catch((error) => {
console.error("polyline read 오류 발생:", error);
});
}
if(json.polygon){
await readGeoJSONFile(`${json.polygon}`)
.then((data) => {
if (data) {
polygon = data;
}
})
.catch((error) => {
console.error("polygon read 오류 발생:", error);
});
}
let collection = new Cesium.PrimitiveCollection();
if(point){
progressCount++;
// let pointDataSource = await Cesium.GeoJsonDataSource.load(point);
// collection.add(pointDataSource);
//point 적용해야함
}
if(polygon){
progressCount++;
let geometryArray = [];
let outlineGeometryArray = [];
Cesium.GeoJsonDataSource.load(polygon).then((geojson)=>{
geojson.entities.values.map(entity => {
let polygonPosition = entity.polygon.hierarchy._value.positions
let polygonGeometry = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(polygonPosition),
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
arcType: Cesium.ArcType.GEODESIC,
height: 0,
extrudedHeight: 0
}),
attributes: {
color: new Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString((json.color)?json.color[entity._name]+'50':getRandomHexColor()+'50')),
}
});
geometryArray.push(polygonGeometry);
//외곽선
let outlineGeometry = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonOutlineGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(polygonPosition),
arcType: Cesium.ArcType.GEODESIC
}),
attributes: {
color: new Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString((json.color)?json.color[entity._name]:getRandomHexColor())),
}
});
outlineGeometryArray.push(outlineGeometry);
})
let polygonPrimitive = new Cesium.Primitive({
geometryInstances: geometryArray,
asynchronous: false,
appearance: new Cesium.PerInstanceColorAppearance({ closed: true, flat:true}),
releaseGeometryInstances: false,
allowPicking: false,
});
collection.add(polygonPrimitive);
// 폴리곤 외곽선 Primitive
let outlinePrimitive = new Cesium.Primitive({
geometryInstances: outlineGeometryArray,
asynchronous: false,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
renderState: {
lineWidth: Math.min(1.0, hmCesium.viewer.scene.maximumAliasedLineWidth)
}
}),
releaseGeometryInstances: false,
allowPicking: false,
});
collection.add(outlinePrimitive);
hmCesium.viewer.scene.groundPrimitives.add(collection);
hmCesium.viewer.scene.requestRender();
progressCount--;
if(progressCount == 0){
document.getElementById('progress').style.display = 'none';
}
})
}
if(polyline){
progressCount++;
let geometryArray = [];
Cesium.GeoJsonDataSource.load(polyline).then((geojson)=>{
geojson.entities.values.map(entity => {
let polylinePosition = entity.polyline.positions._value;
let polylineGeometry = new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({
positions: polylinePosition,
width: 8,
arcType: Cesium.ArcType.GEODESIC
}),
attributes: {
color: new Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString((json.color)?json.color[entity._name]:getRandomHexColor())),
}
});
geometryArray.push(polylineGeometry);
})
let polylinePrimitive = new Cesium.GroundPolylinePrimitive({
geometryInstances: geometryArray,
asynchronous: false,
appearance: new Cesium.PolylineColorAppearance(),
releaseGeometryInstances: false,
allowPicking: false,
});
collection.add(polylinePrimitive);
hmCesium.viewer.scene.groundPrimitives.add(collection);
hmCesium.viewer.scene.requestRender();
progressCount--;
if(progressCount == 0){
document.getElementById('progress').style.display = 'none';
}
})
}
}
async function loadBillboard(json){
const container = document.createElement('div');
container.style.position = 'absolute';
container.style.left = '-9999px';
container.style.top = '-9999px';
container.innerHTML = json.html;
document.body.appendChild(container);
const element = container.firstChild;
//이미지 로딩 (작동X)
const images = container.querySelectorAll('img');
const imagePromises = Array.from(images).map(img => {
return new Promise(resolve => {
if (img.complete) {
resolve();
} else {
img.onload = resolve;
img.onerror = resolve;//에러도 우선은 패스
}
});
});
Promise.all(imagePromises).then(() => {
const elementRect = element.getBoundingClientRect();
const width = elementRect.width+4 || 164; // 최소 너비+4
const height = elementRect.height+4 || 66; // 최소 높이+4
const data = `
${new XMLSerializer().serializeToString(element)}
`;
// SVG를 Base64로 인코딩
const svgBlob = new Blob([data], { type: 'image/svg+xml' });
const reader = new FileReader();
let position = Cesium.Cartesian3.fromDegrees(json.position[0],json.position[1],json.position[2])
reader.onload = function(e) {
// Base64 인코딩된 데이터 URL
const dataUrl = e.target.result;
// 실제 이미지 생성 및 빌보드에 추가
const img = new Image();
img.onload = function() {
// 이미지가 로드되면 빌보드 생성
hmCesium.viewer.entities.add({
position: position,
billboard: {
image: dataUrl,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
width: width,
height: height,
pixelOffset : new Cesium.Cartesian2(0,-50),
}
});
hmCesium.viewer.entities.add({
position: position,
billboard: {
image: './img/icon_progress.svg',
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
}
});
document.body.removeChild(container);
};
img.onerror = function() {
console.error('이미지 변환 실패');
document.body.removeChild(container);
};
img.src = dataUrl;
};
reader.readAsDataURL(svgBlob);
});
}
//test용 랜덤핵사코드
function getRandomHexColor() {
const randomColor = Math.floor(Math.random() * 16777215).toString(16);
return '#' + randomColor.padStart(6, '0');
}
async function readGeoJSONFile(fileUrl) {
try {
const response = await fetch(fileUrl);
if (response.ok) {
const geoJSONData = await response.json();
return geoJSONData;
} else {
throw new Error("파일을 불러오는 데 문제가 발생했습니다.");
}
} catch (error) {
console.error("오류:", error);
return null;
}
}
async function loadTileset(json, isCompare){
//iscompare는 split, overlap
if(!isCompare){
await deleteTileset('main');
}else{
await deleteTileset(isCompare);
}
const promise = Object.keys(json).map(async key =>{
if(json[key] != null){
if(!isCompare){
if(key != 'name')
await hmCesium.setTiles('main', key, json[key]);
}else{
if(key != 'name')
await hmCesium.setTiles(isCompare, key, json[key]);
}
}
});
await Promise.all(promise);
}
async function deleteTileset(tileset){
let keys = Object.keys(hmCesium.projectManager.tileset[tileset]);
if(keys.length > 0 ){
for(let i = 0; i < keys.length; i++){
await hmCesium.deleteTileset(tileset, keys[i]);
}
}
}
// document.getElementById('split').addEventListener('click', ()=>{
// if(document.getElementById('sub-gsim').style.display == 'none'){//on
// //모델 리스트
// document.getElementById('sub-gsim').style.display = 'flex';
// // 슬라이더
// document.getElementById('slider').style.display = 'block';
// //모드
// hmCesium.projectManager.setTileMode('split');
// }else{//off
// //모델 리스트
// document.getElementById('sub-gsim').style.display = 'none';
// // 슬라이더
// document.getElementById('slider').style.display = 'none';
// //모드
// hmCesium.projectManager.split.resetSplit();
// }
// })
async function changeTerrain(url){
await hmCesium.hmUtil.setTerrain(hmCesium.viewer, true, url);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** 지도 기본기능(왼쪽, 오른쪽하단) ***///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//왼쪽 하단
//원위치로 돌아오기
document.getElementById('set-location').addEventListener('click',()=>{
if(hmCesium.initCamera){
hmCesium.viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(hmCesium.initCamera[0],hmCesium.initCamera[1],hmCesium.initCamera[2])
});
}else{
if(hmCesium.projectManager.tileset.terrain){
hmCesium.viewer.flyTo(hmCesium.projectManager.tileset.terrain);
}else if(hmCesium.projectManager.tileset.main){
hmCesium.viewer.flyTo(hmCesium.projectManager.tileset.main);
}
}
});
//정북정렬
document.getElementById('set-north').addEventListener('click',()=>{
hmCesium.camera_setNorth(true);
})
//탑뷰
document.getElementById('set-topView').addEventListener('click',()=>{
hmCesium.camera_setVertical(true);
})
//baseMap선택
document.getElementById('set-baseMap').addEventListener('click',()=>{
if(document.getElementById('baseMap-modal').style.display == 'none'){
document.getElementById('baseMap-modal').style.display = 'block';
document.getElementById('set-baseMap').classList.add('on');
}else{
document.getElementById('baseMap-modal').style.display = 'none';
document.getElementById('set-baseMap').classList.remove('on');
}
})
document.getElementById('baseMap-modal').querySelectorAll('input').forEach(ele => {
ele.addEventListener('change',(e)=>{
let value = e.target.value;
changeBaseMap(value);
})
});
document.getElementById('baseMap-modal').querySelector('.modal-close').addEventListener('click',()=>{
document.getElementById('baseMap-modal').style.display = 'none';
document.getElementById('set-baseMap').classList.remove('on');
})
function changeBaseMap(value){
let index = 0;
switch(value){
case 'vworld-hybrid':
index = 3;
break;
case 'vworld-satellite':
index = 2;
break;
case 'vworld-normal':
index = 1;
break;
case 'google-hybrid':
index = 4;
break;
case 'google-satellite':
index = 5;
break;
case 'google-normal':
index = 7;
break;
case 'carto-normal':
index = 0;
break;
case 'carto-light':
index = 6;
break;
case 'carto-dark':
index = 8;
break;
}
hmCesium.changeBaseMap(index);
if(index == 3){
hmCesium.hmUtil.baseMap[2].show = true;
}
}
// //레이어
// document.getElementById('set-layer').addEventListener('click',()=>{
// if(document.getElementById('layer-modal').style.display =='none'){
// document.getElementById('layer-modal').style.display = 'block';
// }else{
// document.getElementById('layer-modal').style.display = 'none';
// }
// })
// //오른쪽하단
// //종단축척
// document.getElementById('set-zScale').addEventListener('click',()=>{
// if(document.getElementById('zScale-slider').style.display=='none'){
// document.getElementById('zScale-slider').style.display = 'block';
// }else{
// document.getElementById('zScale-slider').style.display = 'none';
// }
// })
hmCesium.logScale = 1;
document.getElementById('zScale-slider').addEventListener('input',(e)=>{
let value = 0;
switch(e.target.value){
case '1':
value = 1;
break;
case '2':
value = 1.1;
break;
case '3':
value = 1.25;
break;
case '4':
value = 1.5;
break;
case '5':
value = 1.85;
break;
case '6':
value = 2;
break;
case '7':
value = 2.5;
break;
case '8':
value = 3;
break;
case '9':
value = 4;
break;
case '10':
value = 5;
break;
}
if(e.target.value == 0) value = 0;
// document.getElementById('zScale').querySelector('.value').innerText = 'x'+Number(value).toFixed(1);
hmCesium.viewer.scene.verticalExaggeration = value;
//카메라 높이 맞추기
const cartesian = hmCesium.viewer.scene.pickPosition({x:hmCesium.viewer.container.clientWidth/2,y:hmCesium.viewer.container.clientHeight/2});
if(cartesian){
let heightFactor = new Cesium.Cartographic.fromCartesian(cartesian).height/hmCesium.logScale;
let height = hmCesium.viewer.camera.positionCartographic.height + (heightFactor*((value<1)?0:(value-hmCesium.logScale)));
hmCesium.viewer.camera.setView({
destination: Cesium.Cartesian3.fromRadians(hmCesium.viewer.camera.positionCartographic.longitude, hmCesium.viewer.camera.positionCartographic.latitude, height),
orientation: {
heading : hmCesium.viewer.camera.heading,
pitch : hmCesium.viewer.camera.pitch,
roll : hmCesium.viewer.camera.roll
}
});
}
hmCesium.logScale = ((value < 1)? 1:value);
// roadData
// if(hmCesium.hmUtil.roadDataLayer){
// let bills = hmCesium.hmUtil.roadDataLayer._billboards;
// bills.forEach(item =>{
// item.position = new Cesium.Cartesian3.fromDegrees(item.conv[0],item.conv[1],item.settingHeight*parseFloat(hmCesium.viewer.scene.verticalExaggeration));
// });
// }
// if(hmCesium.hmUtil.roadLineLayer){
// let entities = hmCesium.hmUtil.roadLineLayer._entityCollection._entities._array;
// entities.forEach(item =>{
// let positions = item.origin;
// let new_positions = [];
// for(let i = 0; i < positions.length; i++){
// let carto = Cesium.Cartographic.fromCartesian(positions[i]);
// new_positions.push(new Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, carto.height * parseFloat(hmCesium.viewer.scene.verticalExaggeration)));
// }
// item.polyline.positions.setValue(new_positions);
// });
// }
})
document.getElementById('set-layer').addEventListener('click',(e)=>{
if(document.getElementById('layer-modal').style.display == 'none'){
document.getElementById('layer-modal').style.display = 'block';
document.getElementById('set-layer').classList.add('on');
}else{
document.getElementById('layer-modal').style.display = 'none';
document.getElementById('set-layer').classList.remove('on');
}
});
document.getElementById('layer-modal').querySelector('.modal-close').addEventListener('click',()=>{
document.getElementById('layer-modal').style.display = 'none';
document.getElementById('set-layer').classList.remove('on');
});
//레이어 모달 기능 추가
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** 지도 기본기능(왼쪽, 오른쪽하단) END ***//////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** GSIM 기능 (중앙) ***///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//전체 취소
function resetAllMode(){
let onMode = document.getElementById('func-btns').querySelector('.on');
if(onMode){
onMode.click();
}
if(document.getElementById('func-label-add').style.display == 'flex'){
document.getElementById('func-label-add').style.display = 'none';
}
if(document.getElementById('func-issue-add').style.display == 'flex'){
document.getElementById('func-issue-add').style.display = 'none';
}
}
////////// 이슈, 라벨, 측정 등 지도 클릭 이벤트 발생 시 마우스 커서 div 변경 관련
// 마우스 커서 div 추가
function changeCursor(e) {
document.getElementById('changeCursor').style.display = 'block';
document.getElementById('changeCursor').style.left = (e.clientX - 20) + 'px';
document.getElementById('changeCursor').style.top = (e.clientY - 20) + 'px';
}
// 마우스 커서 div 원상복구
function resetCursor() {
document.getElementById('changeCursor').style.display = 'none';
document.body.removeEventListener('mousemove', changeCursor);
}
// 마우스 커서 div 및 스크린 이벤트 원상복구
function initCursorAndScreenEvent() {
resetCursor();
hmCesium.viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
//분할비교
document.getElementById('func-split-btn').addEventListener('click',()=>{
if(!document.getElementById('func-split-btn').classList.contains('on')){
resetAllMode();
document.getElementById('slider').style.display = 'block';
document.getElementById('model-list-right').style.display = 'block';
document.getElementById('left-list-title').innerText = '좌측화면 모델';
hmCesium.projectManager.setTileMode('split');
if(hmCesium.imageryLayer.main){
hmCesium.imageryLayer.main.splitDirection = Cesium.SplitDirection.LEFT;
}
//마지막 모델 리스트 강제 클릭
document.getElementById('model-list-right').querySelector('ul').lastElementChild.querySelector('.list-title').click();
}else{
document.getElementById('slider').style.display = 'none';
document.getElementById('model-list-right').style.display = 'none';
document.getElementById('left-list-title').innerText = '모델기반(3D)';
hmCesium.projectManager.split.resetSplit();
if(hmCesium.imageryLayer.main){
hmCesium.imageryLayer.main.splitDirection = Cesium.SplitDirection.NONE;
}
if(hmCesium.imageryLayer.split){
deleteAllTileMap('split');
}
hmCesium.splitModel = undefined;
}
document.getElementById('func-split-btn').classList.toggle('on');
})
//선형클리핑
document.getElementById('func-clipping-btn').addEventListener('click',async ()=>{
if(!document.getElementById('func-clipping-btn').classList.contains('on')){
resetAllMode();
if(document.getElementById('wpb-layer-btn').classList.contains('disabled')){
return alert('모델의 선형 중심선이 존재하지 않습니다.');
}
document.getElementById('func-clipping').style.display = 'flex';
//선형중심선 강제 on
if(!document.getElementById('wpb-layer-btn').querySelector('input').checked){
document.getElementById('wpb-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('wpb-layer-btn').querySelector('input').dispatchEvent(event);
}
//initClipping
await compareCrossSection();
}else{
document.getElementById('func-clipping').style.display = 'none';
endCompareCrossSection();
}
document.getElementById('func-clipping-btn').classList.toggle('on');
})
//선형클리핑 init
async function compareCrossSection(){
hmCesium.compareRoadData = {}; //roadData 초기화
await loadRoadDataForCompare();
setRangeBar(document.querySelector('#key-map-list').firstChild.querySelector('h4').innerText);
}
hmCesium.viewer.scene.preRender.addEventListener(()=>{
let rotate = -Cesium.Math.toDegrees(hmCesium.viewer.camera.heading);
//svg 돌리기
document.getElementById('key-map').style.transform = `rotate(${rotate}deg) scale(1,-1)`;
lightPreRender();
});
function lightPreRender(){
const camDir = hmCesium.viewer.scene.camera.directionWC;
// 너무 수평일 때 생기는 음영을 줄이기 위한 살짝 아래쪽 바이어스(선택)
const bias = new Cesium.Cartesian3(0.0, 0.0, -0.15);
const dir = Cesium.Cartesian3.add(camDir, bias, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(dir, dir);
hmCesium.viewer.scene.light.direction = dir;
}
//선형 클리핑 end
function endCompareCrossSection(){
document.getElementById('clipping-key-map').style.display = 'none';
hmCesium.compareRoadData = undefined;
hmCesium.viewer.scene.screenSpaceCameraController.enableCollisionDetection = true;
hmCesium.reverseClipping = false;
hmCesium.cameraFollowClipping = false;
hmCesium.autoPlay = false;
document.getElementById('clipping-camera-follow').classList.remove('on');
document.getElementById('clipping-camera-play').classList.remove('on');
document.getElementById('clipping-inverse').classList.remove('on');
Object.keys(hmCesium.projectManager.tileset.main).forEach(item=>{
if(hmCesium.projectManager.tileset.main[item] != undefined && !(hmCesium.projectManager.tileset.main[item] instanceof Array)){
if(hmCesium.projectManager.tileset.main[item].clippingPlanes){
hmCesium.projectManager.tileset.main[item].clippingPlanes.removeAll();
}
}
});
}
//RoadData 읽어오기
async function loadRoadDataForCompare(){
let jsonPath = hmCesium.main.model[hmCesium.curModel].dLayer['wpb'];
let projection = `EPSG:${hmCesium.main.model[hmCesium.curModel].projection}`;
let jsonObj;
async function readJSONFile(fileUrl) {
try {
const response = await fetch(fileUrl);
if (response.ok) {
const geoJSONData = await response.json();
return geoJSONData;
} else {
throw new Error("파일을 불러오는 데 문제가 발생했습니다.");
}
} catch (error) {
console.error("오류:", error);
return null;
}
}
await readJSONFile(jsonPath).then((data) => {
if (data) {
jsonObj = data;
}
}).catch((error)=> console.error('오류발생 : ',error));
let length = jsonObj.length;
for (let j = 0; j < length; j++) {
let pointArr = [];
const stPoints = jsonObj[j].StationPoints;
const stPointsLength = stPoints.length;
for (let i = 0; i < stPointsLength; i++) {
// const conv = proj4('EPSG:5186').inverse([stPoints[i].Point.X, stPoints[i].Point.Y]);//4326 변환
//==> transform 뽑아두기
proj4.defs([
['EPSG:5185', '+proj=tmerc +lat_0=38 +lon_0=125 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5186', '+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5187', '+proj=tmerc +lat_0=38 +lon_0=129 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5188', '+proj=tmerc +lat_0=38 +lon_0=131 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:3124', '+proj=tmerc +lat_0=0 +lon_0=123 +k=0.99995 +x_0=500000 +y_0=0 +ellps=clrk66 +towgs84=-127.62,-67.24,-47.04,3.068,-4.903,-1.578,-1.06 +units=m +no_defs +type=crs'],
['EPSG:32242', '+proj=utm +zone=42 +ellps=WGS72 +towgs84=0,0,4.5,0,0,0.554,0.219 +units=m +no_defs +type=crs'],
['EPSG:32642', '+proj=utm +zone=42 +datum=WGS84 +units=m +no_defs +type=crs'],
['EPSG:4326', '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'],
['EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs'],
]);
const height = stPoints[i].Point.Z + 0.5; //0.5m 띄워서 표현
const station = stPoints[i].Station;
if (station) {
if(station % 1 == 0){
let sPoint, ePoint;
if(projection == 'EPSG:4978'){
let carto = Cesium.Cartographic.fromCartesian(new Cesium.Cartesian3(stPoints[i].Point.X, stPoints[i].Point.Y, stPoints[i].Point.Z));
let cartoHeight = carto.height + 0.5;
let conv = proj4('EPSG:4326', 'EPSG:5186', [Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude)]);
if(i>0){
let prev = Cesium.Cartographic.fromCartesian(new Cesium.Cartesian3(stPoints[i-1].Point.X, stPoints[i-1].Point.Y, stPoints[i-1].Point.Z));
let prevHeight = prev.height + 0.5;
let prevConv = proj4('EPSG:4326', 'EPSG:5186', [Cesium.Math.toDegrees(prev.longitude), Cesium.Math.toDegrees(prev.latitude)]);
sPoint = new Cesium.Cartesian3(prevConv[0], prevConv[1],prevHeight);
ePoint = new Cesium.Cartesian3(conv[0], conv[1],cartoHeight);
}else{
let next = Cesium.Cartographic.fromCartesian(new Cesium.Cartesian3(stPoints[i+1].Point.X, stPoints[i+1].Point.Y, stPoints[i+1].Point.Z));
let nextHeight = next.height + 0.5;
let nextConv = proj4('EPSG:4326', 'EPSG:5186', [Cesium.Math.toDegrees(next.longitude), Cesium.Math.toDegrees(next.latitude)]);
sPoint = new Cesium.Cartesian3(conv[0], conv[1],cartoHeight);
ePoint = new Cesium.Cartesian3(nextConv[0], nextConv[1],nextHeight);
}
}else{
if(i>0){
sPoint = new Cesium.Cartesian3(stPoints[i-1].Point.X, stPoints[i-1].Point.Y,stPoints[i-1].Point.Z);
ePoint = new Cesium.Cartesian3(stPoints[i].Point.X, stPoints[i].Point.Y,height);
}else{
sPoint = new Cesium.Cartesian3(stPoints[i].Point.X, stPoints[i].Point.Y,stPoints[i].Point.Z);
ePoint = new Cesium.Cartesian3(stPoints[i+1].Point.X, stPoints[i+1].Point.Y,height);//높이는 그려주는 포인트에 맞추기
}
}
let perpendicularPosition = getPerpendicularPoint(sPoint, ePoint, (projection !== 'EPSG:4978')?projection:'EPSG:5186');
if(!hmCesium.compareRoadData[jsonObj[j].RoadName]){
hmCesium.compareRoadData[jsonObj[j].RoadName] = {};
}
hmCesium.compareRoadData[jsonObj[j].RoadName][station] = perpendicularPosition;
}
}
}
}
// data 읽어올때마다 minimap도 초기화해야함
// 4978로 지정된 것들은 다 5186으로 변경해서 표시
makeRoadKeyMap(jsonObj, projection);
}
//선형지점 수직 point 계산
function getPerpendicularPoint(pointA, pointB, projection = 'EPSG:5186'){
let direction = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
let len = 10;
direction = Cesium.Cartesian3.normalize(direction, direction);
let perpendicularDirection = new Cesium.Cartesian3(direction.y, -direction.x, 0.0);
let perpenPosition = [];
let a = Cesium.Cartesian3.add(pointB, Cesium.Cartesian3.multiplyByScalar(perpendicularDirection, len/2, new Cesium.Cartesian3()),new Cesium.Cartesian3());
a.z = pointB.z;
let b = Cesium.Cartesian3.add(pointB, Cesium.Cartesian3.multiplyByScalar(perpendicularDirection, -len/2, new Cesium.Cartesian3()),new Cesium.Cartesian3());
b.z = pointB.z;
let convertA = proj4(projection).inverse([a.x, a.y]);//4326 변환
let convertB = proj4(projection).inverse([b.x, b.y]);//4326 변환
perpenPosition.push(new Cesium.Cartesian3.fromDegrees(convertA[0], convertA[1], a.z));
perpenPosition.push(new Cesium.Cartesian3.fromDegrees(convertB[0], convertB[1], b.z));
return perpenPosition;
}
//roadkeyMap 만들기
function makeRoadKeyMap(json, projection){
let svg = document.getElementById('key-map');
let list = document.getElementById('key-map-list');
list.innerHTML = ``;
//전체 point
let totalPositionX = [];
let totalPositionY = [];
let pathArray = [];
let color = ['#FFFFFF', '#FF3A2D','#FFAD33','#5CD25F','#1EC6FF'];
let idx = -1;
json.forEach(road=>{
idx++;
let pathData = "M ";
for(let i = 0; i < road.StationPoints.length; i++){
if(projection !== 'EPSG:4978'){
totalPositionX.push(road.StationPoints[i].Point.X);
totalPositionY.push(road.StationPoints[i].Point.Y);
let x = road.StationPoints[i].Point.X;
let y = road.StationPoints[i].Point.Y;
pathData += `${x},${y} `;
}else{
let carto = Cesium.Cartographic.fromCartesian(new Cesium.Cartesian3(road.StationPoints[i].Point.X,road.StationPoints[i].Point.Y,road.StationPoints[i].Point.Z));
let conv = proj4('EPSG:4326', 'EPSG:5186', [Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude)])
// totalPositionX.push(carto.longitude);
// totalPositionY.push(carto.latitude);
// let x = carto.longitude;
// let y = carto.latitude;
totalPositionX.push(conv[0]);
totalPositionY.push(conv[1]);
let x = conv[0];
let y = conv[1];
pathData += `${x},${y} `;
}
}
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", pathData);
path.setAttribute("stroke", color[idx%5]);
path.setAttribute("fill", "none");
path.setAttribute("stroke-width", '10');
path.id = `road-${road.RoadId}`;
path.name = road.RoadName;
path.style.cursor = 'pointer';
// path.setAttribute("transform", `scale(1, 0.998)`);
// path.setAttribute("transform", `translate(0, -1000)`);
pathArray.push(path);
//list
// list.innerHTML += `${road.RoadName}
`;
list.innerHTML += `
${road.RoadName}
`;
//path이벤트
path.addEventListener('mouseover', ()=>{
path.setAttribute('stroke-width', '90');
list.querySelector(`#road-${road.RoadId} h4`).style.fontWeight = '900';
})
path.addEventListener('mouseout', ()=>{
path.setAttribute("stroke-width", '10');
list.querySelector(`#road-${road.RoadId} h4`).style.fontWeight = '300';
})
path.addEventListener('click',()=>{
//해당 선 선택
setRangeBar(path.name);
document.getElementById('clipping-key-map').style.display = 'none';
})
let selectedPath;
// list이벤트
list.querySelectorAll('li').forEach(item=>{
item.addEventListener('mouseover',()=>{
for(let i = 0; i < pathArray.length; i++){
if(pathArray[i].id == item.id){
pathArray[i].setAttribute('stroke-width', '90');
}
}
item.querySelector('h4').style.fontWeight = '900';
})
item.addEventListener('mouseout',()=>{
for(let i = 0; i < pathArray.length; i++){
if(pathArray[i].id == item.id){
pathArray[i].setAttribute('stroke-width', '10');
}
}
item.querySelector('h4').style.fontWeight = '300';
})
item.addEventListener('click',()=>{
//해당 선 선택
for(let i = 0; i < pathArray.length; i++){
if(pathArray[i].id == item.id){
setRangeBar(pathArray[i].name);
document.getElementById('clipping-key-map').style.display = 'none';
}
}
})
});
});
//전체 station의 최대, 최소
let minX = totalPositionX.reduce((min, current) => Math.min(min, current), Infinity) - 50;
let maxX = totalPositionX.reduce((max, current) => Math.max(max, current), -Infinity) + 50;
let minY = totalPositionY.reduce((min, current) => Math.min(min, current), Infinity) - 50;
let maxY = totalPositionY.reduce((max, current) => Math.max(max, current), -Infinity) + 50;
svg.setAttribute('viewBox', `${minX} ${minY} ${maxX-minX} ${maxY-minY}`);
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.setAttribute('transform', `scale(1, -1)`);
for(let i = 0; i Math.min(currentMin, value), Infinity);
let max = intData.reduce((currentMax, value) => Math.max(currentMax, value), -Infinity);
document.querySelector('#compare-toolbar input').max = max;
document.querySelector('#compare-toolbar input').min = min;
document.querySelector('#compare-toolbar input').value = min;
document.querySelector('#compare-toolbar input').style.background = `linear-gradient(to right, #fff ${0}%, #aaa ${0}%)`;
setClipping(roadName,min);
}
// 스테이션 선택 이벤트(클리핑)
function setClipping(roadName, stationNum){
Object.keys(hmCesium.projectManager.tileset.main).forEach(item=>{
if(hmCesium.projectManager.tileset.main[item] != undefined && !(hmCesium.projectManager.tileset.main[item] instanceof Array)){
createClippingPlane(hmCesium.projectManager.tileset.main[item], roadName, stationNum);
}
})
document.querySelector('#station-number').innerText = stationNum;
if(hmCesium.cameraFollowClipping){
cameraFollowClipping(roadName, stationNum);
}
}
//카메라 따라가기
function cameraFollowClipping(roadName, stationNum){
if(hmCesium.compareRoadData[roadName][stationNum] == undefined) return;
let pointA = hmCesium.compareRoadData[roadName][stationNum][0];
let pointB = hmCesium.compareRoadData[roadName][stationNum][1];
let normal = getPlanNormal(pointA, pointB);
Cesium.Cartesian3.normalize(normal, normal);
let centerPosition = getCenterPosition([pointA, pointB]);
let moveDist = (hmCesium.reverseClipping)?75:-75;
let moveVec = Cesium.Cartesian3.multiplyByScalar(normal, moveDist, new Cesium.Cartesian3());
let cameraPosition = Cesium.Cartesian3.add(centerPosition, moveVec, new Cesium.Cartesian3());
let cameraCarto = Cesium.Cartographic.fromCartesian(cameraPosition);
let up_cameraP = Cesium.Cartesian3.fromRadians(cameraCarto.longitude, cameraCarto.latitude, cameraCarto.height + 7);
let dir = Cesium.Cartesian3.subtract(centerPosition, up_cameraP,new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(dir,dir);
let up = calcUpVec(pointA, pointB, up_cameraP);
hmCesium.viewer.camera.setView({
destination : up_cameraP,
orientation : {
direction : dir,
up: up
}
})
}
//카메라 upVec 계산
function calcUpVec(A, B, cam){
const bCam = Cesium.Cartesian3.subtract(B, cam, new Cesium.Cartesian3());
const aCam = Cesium.Cartesian3.subtract(A, cam, new Cesium.Cartesian3());
let normal = Cesium.Cartesian3.cross(aCam, bCam, new Cesium.Cartesian3());
if(hmCesium.reverseClipping){
Cesium.Cartesian3.multiplyByScalar(normal, -1, normal);
}
Cesium.Cartesian3.normalize(normal, normal);
return normal;
}
//clipping plane 생성 후 적용(tileset, roadName, stationNum)
function createClippingPlane(tileset, roadName, stationNum){
if(!hmCesium.compareRoadData || hmCesium.compareRoadData[roadName][stationNum] == undefined) return;
let isRight = false;
// 클리핑은 main만 진행
// if(
// tileset == hmCesium.projectManager.tileset.split ||
// tileset == hmCesium.projectManager.tileset.custom ||
// tileset == hmCesium.projectManager.tileset.custom5 ||
// tileset == hmCesium.projectManager.tileset.custom6 ||
// tileset == hmCesium.projectManager.tileset.custom7
// )
// isRight = true;
if(!tileset.clippingPlanes){
tileset.clippingPlanes = new Cesium.ClippingPlaneCollection({
planes:[],
unionClippingRegions:false,
edgeWidth:8.0,//모서리 굵기
edgeColor:(isRight)?Cesium.Color.RED:Cesium.Color.BLUE,//모서리 색상
enabled:true,
// modelMatrix : Cesium.Matrix4.inverse(tileset._clippingPlanesOriginMatrix, new Cesium.Matrix4()),
// modelMatrix : transform,
});
}
let pointA = hmCesium.compareRoadData[roadName][stationNum][0];
let pointB = hmCesium.compareRoadData[roadName][stationNum][1];
//typeA
// let inverse = Cesium.Matrix4.inverse(tileset._clippingPlanesOriginMatrix, new Cesium.Matrix4());
// let convertA = Cesium.Matrix4.multiplyByPoint(inverse, pointA, new Cesium.Cartesian3());
// let convertB = Cesium.Matrix4.multiplyByPoint(inverse, pointB, new Cesium.Cartesian3());
// let normal2 = getPlanNormal(convertA, convertB);
// Cesium.Cartesian3.normalize(normal2, normal2);
// let distance2 = getPlanDistance(normal2, getCenterPosition([convertA, convertB]));
// let plane2 = new Cesium.ClippingPlane(normal2, distance2);
// console.log(plane2);
//typeB
let normal = getPlanNormal(pointA, pointB);
Cesium.Cartesian3.normalize(normal, normal);
if(hmCesium.reverseClipping){
Cesium.Cartesian3.multiplyByScalar(normal, -1, normal);
}
let distance = getPlanDistance(normal, getCenterPosition([pointA, pointB]));
let plane = new Cesium.ClippingPlane(normal, distance);
//collection에 modelMatrix를 적용하면 흔들리는 현상때문에 미리 transform을 곱한 상태로 collection에 밀어넣기
plane = Cesium.Plane.transform(plane, Cesium.Matrix4.inverse(tileset._clippingPlanesOriginMatrix, new Cesium.Matrix4()))
//testType
// Cesium.Matrix4.multiplyByPoint(inverse, normal, normal);
// let distPoint = getCenterPosition([pointA, pointB]);
// let convertPoint = Cesium.Matrix4.multiplyByPoint(inverse, distPoint, new Cesium.Cartesian3());
// let dist = getPlanDistance(normal, convertPoint);
// let plane3 = new Cesium.ClippingPlane(normal, dist);
// console.log(plane3);
//typeC
// let formal = new Cesium.Cartesian3(pointA.x,pointA.y,pointA.z-1);
// let convertA = Cesium.Cartesian3.subtract(pointA, formal, new Cesium.Cartesian3());
// let convertB = Cesium.Cartesian3.subtract(pointB, formal, new Cesium.Cartesian3());
// let normal = getPlanNormal(convertA, convertB);
// Cesium.Cartesian3.normalize(normal, normal);
// let distance = getPlanDistance(normal, getCenterPosition([convertA, convertB]));
// let plane = new Cesium.ClippingPlane(normal, distance);
// let transform = Cesium.Matrix4.fromTranslation(formal, new Cesium.Matrix4());
// let collection = new Cesium.ClippingPlaneCollection({
// planes:[plane],
// unionClippingRegions:false,
// edgeWidth:1.0,//모서리 굵기
// edgeColor:Cesium.Color.RED,//모서리 색상
// enabled:true,
// modelMatrix : Cesium.Matrix4.inverse(tileset._clippingPlanesOriginMatrix, new Cesium.Matrix4()),
// // modelMatrix : transform,
// });
// tileset._clippingPlanesOriginMatrix = Cesium.Matrix4.IDENTITY;
// tileset.clippingPlanes = collection;
//새롭게 적용하면 _target오류가 발생하기 때문에 clippingPlane만 만들어서 collection에 넣어주는 형태로 변경
tileset.clippingPlanes.removeAll();
tileset.clippingPlanes.add(plane);
// tileset.clippingPlanes.modelMatrix = Cesium.Matrix4.inverse(tileset._clippingPlanesOriginMatrix, new Cesium.Matrix4())
}
//clipping plan distance 계산
function getPlanDistance(normal, center){
let globalCenteredPlane = new Cesium.Plane(normal, 0);
let distance = Cesium.Plane.getPointDistance(globalCenteredPlane, center);
// return -(distance-5);
return -distance;
}
//clipping plan normal 계산(진행방향 기준 왼쪽 오른쪽 정해줘야함. default 왼쪽 clipping_CCW) => 면이 표출되는 normal(clipping될 normal)
function getPlanNormal(pointA, pointB, direction='right'){
let pointACarto = Cesium.Cartographic.fromCartesian(pointA);
let pointBCarto = Cesium.Cartographic.fromCartesian(pointB);
//두 점의 높이를 높여 총 4개의 점으로 normal계산(left일때 진행방향은 pointA->pointA_h->pointB_h->pointB)
let pointA_h = Cesium.Cartesian3.fromRadians(pointACarto.longitude, pointACarto.latitude, pointACarto.height + 10);
let pointB_h = Cesium.Cartesian3.fromRadians(pointBCarto.longitude, pointBCarto.latitude, pointBCarto.height + 10);
let array=[];
if(direction == 'left'){
array.push(pointA);
array.push(pointA_h);
array.push(pointB_h);
array.push(pointB);
}else{ //right normal
array.push(pointB);
array.push(pointB_h);
array.push(pointA_h);
array.push(pointA);
}
let dirA = Cesium.Cartesian3.subtract(array[1], array[0], new Cesium.Cartesian3());
let dirB = Cesium.Cartesian3.subtract(array[2], array[0], new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(dirA, dirA);
Cesium.Cartesian3.normalize(dirB, dirB);
let normal = Cesium.Cartesian3.cross(dirA,dirB,new Cesium.Cartesian3());
return normal;
}
//array의 중심점 반환
function getCenterPosition(array){
let len = array.length;
let sum = new Cesium.Cartesian3();
for(let i =0; i< len; i++){
Cesium.Cartesian3.add(sum, array[i], sum);
}
Cesium.Cartesian3.divideByScalar(sum, len, sum);
return sum;
}
//카메라 따라가기 on/off
document.getElementById('clipping-camera-follow').addEventListener('click',()=>{
document.getElementById('clipping-camera-follow').classList.toggle('on');
hmCesium.cameraFollowClipping = document.getElementById('clipping-camera-follow').classList.contains('on');
hmCesium.viewer.scene.screenSpaceCameraController.enableCollisionDetection = !hmCesium.cameraFollowClipping;
setClipping(document.getElementById('compare-road').innerText,document.querySelector('#compare-toolbar input').value);
})
//카메라 반전
document.getElementById('clipping-inverse').addEventListener('click',()=>{
document.getElementById('clipping-inverse').classList.toggle('on');
hmCesium.reverseClipping = document.getElementById('clipping-inverse').classList.contains('on');
setClipping(document.getElementById('compare-road').innerText,document.querySelector('#compare-toolbar input').value);
})
//플레이
document.getElementById('clipping-camera-play').addEventListener('click',()=>{
document.getElementById('clipping-camera-play').classList.toggle('on');
hmCesium.autoPlay = document.getElementById('clipping-camera-play').classList.contains('on');
if(document.getElementById('clipping-camera-play').classList.contains('on')){//on
if(!document.getElementById('clipping-camera-follow').classList.contains('on')){
document.getElementById('clipping-camera-follow').click();
}
setTimeout(autoPlay, 15);
}else{//off
if(document.getElementById('clipping-camera-follow').classList.contains('on')){
document.getElementById('clipping-camera-follow').click();
}
}
})
//카메라 오토play
function autoPlay(){
if(hmCesium.autoPlay){
let input = document.querySelector('#compare-toolbar input');
if(parseInt(input.max) > parseInt(input.value)){
input.value++;
setClipping(document.getElementById('compare-road').innerText,input.value);
setTimeout(autoPlay,15);
}else{
document.getElementById('auto-play').click();
}
}
}
//선형슬라이더
document.querySelector('#compare-toolbar input').addEventListener('input',(e)=>{
setClipping(document.getElementById('compare-road').innerText,e.target.value);
})
//목록보이기
document.getElementById('compare-road').addEventListener('click',()=>{
if(document.getElementById('clipping-key-map').style.display == 'flex'){
document.getElementById('clipping-key-map').style.display = 'none';
}else{
document.getElementById('clipping-key-map').style.display = 'flex';
}
});
document.getElementById('compare-road2').addEventListener('click',()=>{
if(document.getElementById('clipping-key-map').style.display == 'flex'){
document.getElementById('clipping-key-map').style.display = 'none';
}else{
document.getElementById('clipping-key-map').style.display = 'flex';
}
});
//목록 닫기버튼
document.querySelector('#clipping-key-map .window-img-container img.icon').addEventListener('click',()=>{
document.getElementById('clipping-key-map').style.display = 'none';
})
//투명도
document.getElementById('func-opacity-btn').addEventListener('click',(e)=>{
if(document.getElementById('func-opacity').style.display == 'none'){
resetAllMode();
document.getElementById('func-opacity').style.display = 'flex';
document.querySelectorAll('.list-box-section input[type="range"]').forEach(ele=>{
ele.value = 0;
});
document.querySelectorAll('.list-box-section input[type="color"]').forEach(ele=>{
ele.value = '#ffffff';
});
}else{
document.getElementById('func-opacity').querySelector('input').value = 0;
document.getElementById('func-opacity').querySelector('p').innerHTML = '0%';
document.getElementById('func-opacity').style.display = 'none';
}
let keys = Object.keys(hmCesium.projectManager.tileset.main);
for(let i = 0; i < keys.length; i++){
hmCesium.changeOpacity(hmCesium.projectManager.tileset.main[keys[i]], 0);
}
document.getElementById('func-opacity-btn').classList.toggle('on');
});
//투명도 조절
document.getElementById('func-opacity').querySelector('input').addEventListener('input', (e)=>{
let value = e.target.value;
e.target.parentNode.parentNode.querySelector('p').innerHTML = value + '%';
if(value == 1) value = 0.01;
let keys = Object.keys(hmCesium.projectManager.tileset.main);
for(let i = 0; i < keys.length; i++){
hmCesium.changeOpacity(hmCesium.projectManager.tileset.main[keys[i]], value);
// hmCesium.projectManager.tileset.main[keys[i]].style = new Cesium.Cesium3DTileStyle({
// color : `color("${hmCesium.projectManager.tileset.main[keys[i]].color?hmCesium.projectManager.tileset.main[keys[i]].color:'white'}",${1-value})`
// });
}
});
//측정
document.getElementById('func-measurement-btn').addEventListener('click',()=>{
if(document.getElementById('func-measurement').style.display == 'none'){
resetAllMode();
document.getElementById('func-measurement').style.display = 'flex';
}else{
document.getElementById('func-measurement').style.display = 'none';
}
document.getElementById('func-measurement-btn').classList.toggle('on');
});
//각 버튼 연결
document.getElementById('func-measurement').querySelectorAll('.xs-icon-btn').forEach(ele=>{
ele.addEventListener('click', (e)=>{
let type = e.target.closest('.xs-icon-btn').id;
let id = '';
switch(type){
case 'slope-btn':
id = 'slope';
break;
case 'location-btn':
id = 'location';
break;
case 'distance-btn':
id = 'straightDistance';
break;
case 'horizontal-btn':
id = 'horizontalDistance';
break;
case 'vertical-btn':
id = 'verticalDistance';
break;
case 'measure-delete-btn':
id = 'clear';
break;
/* profile, area 없음 */
}
initMeasure(id);
})
})
// measureLabel div에 preRender 적용해서 지도에 위치 고정
hmCesium.viewer.scene.preRender.addEventListener(()=>{
if(hmCesium.hmUtil.measureLabelDivArr && hmCesium.hmUtil.measureLabelDivArr.length > 0){
for(let i =0; i < hmCesium.hmUtil.measureLabelDivArr.length; i++){
let cesiumCanvas = hmCesium.viewer.canvas.getBoundingClientRect();
let div = hmCesium.hmUtil.measureLabelDivArr[i];
let origin_position = div.cartesian3;
let screen_position = Cesium.SceneTransforms.worldToWindowCoordinates(hmCesium.viewer.scene, origin_position);
if (screen_position) {
let divRect = hmCesium.hmUtil.measureLabelDivArr[i].getBoundingClientRect();
div.style.left = (cesiumCanvas.left + screen_position.x - divRect.width / 2) + 'px';
div.style.top = (cesiumCanvas.top + screen_position.y - (divRect.height + 10)) + 'px';
}
}
}
});
// 측정 모드 진입
function initMeasure(id) {
// hmCesium.hmUtil에 measureLayer 생성
if(!hmCesium.hmUtil.measureLayer){
hmCesium.hmUtil.measureLayer = getDataSource('measureLayer');
hmCesium.hmUtil.measureLabelDivArr = [];
hmCesium.hmUtil.measureLabelEntityArr = [];
hmCesium.hmUtil.measureGeometryEntityArr = [];
}
// 기존 측정 이벤트 해제 및 진행중이던 측정 객체 삭제
measureEnd();
if (id == 'clear' || id == 'close') {
measureClear();
} else {
// 마우스 커서 div 추가
document.body.addEventListener('mousemove', changeCursor);
if (id == 'location') measureLoaction();
else if (id == 'straightDistance') measureStraightDistance();
else if (id == 'horizontalDistance') measureHorizontalDistance();
else if (id == 'verticalDistance') measureVerticalDistance();
else if (id == 'area') measureArea();
// else if (id == 'profile') measureProfile();
else if (id == 'slope') measureSlope();
}
}
//경사도 측정
function measureSlope(){
hmCesium.slopeContinue = true;
hmCesium.slopeResult = [];
hmCesium.viewer.screenSpaceEventHandler.setInputAction(slopePickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
let option = {
name : 'slope',//이름
color : '#00ffff',//색상
aerial : { // 표출할 거리 = 표출 속성(text)
text:`@value m`, //값 @value로 표시
textShow : false,
lineShow : true,
},
resultShow : false, //최종결과 show
callback : {
onDrawing : function(entity) {
entity.stopEditing();
hmCesium.endDraw();
hmCesium.originSlope = entity.polyline.positions._value;
entity.entityCollection.remove(entity);
let fPosition_carto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[0]);
let sPosition_carto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[1]);
let option = {
name : 'test',
color : '#00ffff',
position : [
[Cesium.Math.toDegrees(fPosition_carto.longitude),Cesium.Math.toDegrees(fPosition_carto.latitude), fPosition_carto.height],
[Cesium.Math.toDegrees(sPosition_carto.longitude),Cesium.Math.toDegrees(sPosition_carto.latitude), sPosition_carto.height],
]
}
setTimeout(()=>{
hmCesium.setPolyline(option);
let m_slope = Cesium.Cartesian3.distance(entity.polyline.positions._value[0], Cesium.Cartesian3.fromRadians(sPosition_carto.longitude, sPosition_carto.latitude, fPosition_carto.height)) / Math.abs(fPosition_carto.height - sPosition_carto.height);
// let labelPosition = Cesium.Cartesian3.midpoint(entity.polyline.positions._value[0],entity.polyline.positions._value[1], new Cesium.Cartesian3());
let labelPosition = entity.polyline.positions._value[1];
// let text = `
측정 경사 1 : ${m_slope.toFixed(2)}
//
최단 경사 평균 ${(hmCesium.slopeResult.length>0)?('1 : '+calcAvg(hmCesium.slopeResult).toFixed(2)):' - 최단 경사 측정 실패'}`;
let text = `
측정경사
1 : ${m_slope.toFixed(2)}
최단 경사 평균
${(hmCesium.slopeResult.length>0)?('1 : '+calcAvg(hmCesium.slopeResult).toFixed(2)):' - 최단 경사 측정 실패'}
`;
addMeasureLabelDiv(labelPosition, text, Cesium.SceneTransforms.worldToWindowCoordinates(hmCesium.viewer.scene, labelPosition), hmCesium.hmUtil.measureLayer);
stopEditing(undefined, entity);
},500);
},
}
}
hmCesium.getDistance(option);
};
function calcAvg(arr) {
const sum = arr.reduce((acc, val) => acc + val, 0);
return sum / arr.length;
}
function slopePickEvent(e){
let rectLength = 3;
let pointNum = rectLength * 5;
const cartesian = hmCesium.viewer.scene.pickPosition(e.position);
const cartesian_right = hmCesium.viewer.scene.pickPosition(new Cesium.Cartesian2(e.position.x + 20, e.position.y));
const cartesian_left = hmCesium.viewer.scene.pickPosition(new Cesium.Cartesian2(e.position.x - 20, e.position.y));
if(Cesium.defined(cartesian)){
let optionPoint = {
name:'test',
color:'#00ffff',
position : {
latitude:Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cartesian).latitude),
longitude:Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cartesian).longitude),
height:Cesium.Cartographic.fromCartesian(cartesian).height,
}
}
hmCesium.setPoint(optionPoint);
if(hmCesium.slopeContinue){//첫번째 클릭
hmCesium.pickPosition = [];
let points = makeRectPoint2(cartesian, cartesian_left, cartesian_right, rectLength);
let startLine = splitLine(points.startS, points.startE, pointNum);
let endLine = splitLine(points.endS, points.endE, pointNum);
for(let i = 0; i < pointNum; i++){
if(getIntersectionPoint(startLine[i], endLine[i], rectLength) == undefined)
continue;
hmCesium.pickPosition.push(getIntersectionPoint(startLine[i], endLine[i], rectLength));
}
hmCesium.slopeContinue = false;
}else{//두번째 클릭
hmCesium.viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
///////첫번째 라인
hmCesium.pickPosition.forEach(position =>{
let viewCarto = Cesium.Cartographic.fromCartesian(position);
let option = {
name:'test',
color:'#00ffff',
position : {
latitude:Cesium.Math.toDegrees(viewCarto.latitude),
longitude:Cesium.Math.toDegrees(viewCarto.longitude),
height:viewCarto.height,
}
}
hmCesium.setPoint(option);
})
let startPositionArray = [];
hmCesium.pickPosition.forEach(car3 =>{
startPositionArray.push([car3.x, car3.y, car3.z]);
});
let startConvertedPositionsArray = convertCoord(startPositionArray, '4978', '5186');
// let startInterpolrations = calculatePolynomial(startConvertedPositionsArray, 2);
let startInterpolrations = calculatePolynomialWithRotation(startConvertedPositionsArray, 2);
let start_inter_cartoArray = convertCoord(startInterpolrations, '5186', '4326');
let startSplit = [];
start_inter_cartoArray.forEach(item =>{
startSplit.push(Cesium.Cartesian3.fromDegrees(item[0], item[1], item[2]));
})
let startSplineOption = {
name :'test',
color : '#00ff00',
position:start_inter_cartoArray,
};
hmCesium.setPolyline(startSplineOption);
hmCesium.pickPosition = [];
///////두번째 라인
let points = makeRectPoint2(cartesian, cartesian_left, cartesian_right, rectLength);
let startLine = splitLine(points.startS, points.startE, pointNum);
let endLine = splitLine(points.endS, points.endE, pointNum);
for(let i = 0; i < pointNum; i++){
if(getIntersectionPoint(startLine[i], endLine[i], rectLength) == undefined)
continue;
hmCesium.pickPosition.push(getIntersectionPoint(startLine[i], endLine[i], rectLength));
let viewCarto = Cesium.Cartographic.fromCartesian(hmCesium.pickPosition[hmCesium.pickPosition.length-1]);
let option = {
name:'test',
color:'#00ffff',
position : {
latitude:Cesium.Math.toDegrees(viewCarto.latitude),
longitude:Cesium.Math.toDegrees(viewCarto.longitude),
height:viewCarto.height,
}
}
hmCesium.setPoint(option);
}
///////실제 경사비교
// let startCenter = getLineCenter(startSplit);
let startPoint = getSplitPoint(startSplit, 5);//시작점 5개로
/////////////////////n차 interpolration
let positionArray = [];
hmCesium.pickPosition.forEach(car3 =>{
positionArray.push([car3.x, car3.y, car3.z]);
});
let convertedPositionsArray = convertCoord(positionArray, '4978', '5186');
// let interpolrations = calculatePolynomial(convertedPositionsArray, 2);
let interpolrations = calculatePolynomialWithRotation(convertedPositionsArray, 2);
let inter_cartoArray = convertCoord(interpolrations, '5186', '4326');
let endSplit = [];
inter_cartoArray.forEach(item =>{
endSplit.push(Cesium.Cartesian3.fromDegrees(item[0], item[1], item[2]));
})
let splineOption = {
name :'test',
color : '#00ff00',
position:inter_cartoArray,
};
hmCesium.setPolyline(splineOption);
////////////////////////////////////////
startPoint.forEach(car3=>{
let shortestIdx = 0;
let dist=999;
endSplit.forEach((item, idx)=>{
let curDist = Cesium.Cartesian3.distance(item, car3);
if(curDist < dist){
dist = curDist;
shortestIdx = idx;
}
});
endSplit.forEach((item, idx)=>{
let option = {
name :'test',
color : (idx == shortestIdx)?((shortestIdx == 0|| shortestIdx == endSplit.length-1)? '#000000':'#ff0000'):'#888888',
position:[
[Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(car3).longitude),Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(car3).latitude),Cesium.Cartographic.fromCartesian(car3).height],
[Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(item).longitude),Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(item).latitude),Cesium.Cartographic.fromCartesian(item).height],
],
};
if((idx == shortestIdx)){
hmCesium.setPolyline(option);
}
})
let zeroStart =Cesium.Cartesian3.fromRadians(Cesium.Cartographic.fromCartesian(car3).longitude, Cesium.Cartographic.fromCartesian(car3).latitude);
let zeroEnd = Cesium.Cartesian3.fromRadians(Cesium.Cartographic.fromCartesian(endSplit[shortestIdx]).longitude, Cesium.Cartographic.fromCartesian(endSplit[shortestIdx]).latitude);
let slope = Cesium.Cartesian3.distance(zeroStart,zeroEnd)/Math.abs(Cesium.Cartographic.fromCartesian(car3).height - Cesium.Cartographic.fromCartesian(endSplit[shortestIdx]).height);
//슬로프 계산값
if(!(shortestIdx == 0|| shortestIdx == endSplit.length-1)){
hmCesium.slopeResult.push(slope);
makeSlopeResult(car3, endSplit[shortestIdx], slope,endSplit[shortestIdx-1]);
}
});
}
}
}
// 결과 삼각형 그리기(start, end, result,refPosition)
function makeSlopeResult(start, end, result, refPosition){
let midOnLine = getLineCenter([start, end]);
//외접원 반지름
let radius = Math.sqrt(1 + result * result)/2;
//중점에서 상단 dir
let topDir = calculateNormalVector(start, end, refPosition);
//외접원 중심
let circleCenter = Cesium.Cartesian3.add(midOnLine, Cesium.Cartesian3.multiplyByScalar(topDir, radius*0.10, new Cesium.Cartesian3()),new Cesium.Cartesian3());
let upDir = Cesium.Cartesian3.subtract(end,start,new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(upDir, upDir);
let downDir = Cesium.Cartesian3.multiplyByScalar(upDir, -1, new Cesium.Cartesian3());
let upVertex = Cesium.Cartesian3.add(circleCenter, Cesium.Cartesian3.multiplyByScalar(upDir, radius, new Cesium.Cartesian3()),new Cesium.Cartesian3());
let downVertex = Cesium.Cartesian3.add(circleCenter, Cesium.Cartesian3.multiplyByScalar(downDir, radius, new Cesium.Cartesian3()),new Cesium.Cartesian3());
let upCarto = Cesium.Cartographic.fromCartesian(upVertex);
let downCarto = Cesium.Cartographic.fromCartesian(downVertex);
if(upCarto.height < downCarto.height){
let tempVertex = upVertex;
upVertex = downVertex;
downVertex = tempVertex;
let tempCarto = upCarto;
upCarto = downCarto;
downCarto = tempCarto;
}
let rightAngleVertex = Cesium.Cartesian3.fromRadians(downCarto.longitude, downCarto.latitude, upCarto.height);
let rightAngleCarto = Cesium.Cartographic.fromCartesian(rightAngleVertex);
hmCesium.viewer.entities.add({
polygon: {
hierarchy : [upVertex, downVertex, rightAngleVertex],
material : Cesium.Color.fromCssColorString('rgba(0,0,0,0.25)'),
perPositionHeight : true,
show : true,
}
})
let lineOption = {
color : 'rgba(0,0,0,0.35)',
position : [
[Cesium.Math.toDegrees(upCarto.longitude), Cesium.Math.toDegrees(upCarto.latitude), upCarto.height],
[Cesium.Math.toDegrees(downCarto.longitude), Cesium.Math.toDegrees(downCarto.latitude), downCarto.height],
[Cesium.Math.toDegrees(rightAngleCarto.longitude), Cesium.Math.toDegrees(rightAngleCarto.latitude), rightAngleCarto.height],
[Cesium.Math.toDegrees(upCarto.longitude), Cesium.Math.toDegrees(upCarto.latitude), upCarto.height],
],
}
hmCesium.setPolyline(lineOption);
//결과 text넣기
//height
let heightMid = getLineCenter([downVertex, rightAngleVertex]);
let heightTextDir = Cesium.Cartesian3.subtract(rightAngleVertex, upVertex, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(heightTextDir, heightTextDir);
let heightTextPosition = Cesium.Cartesian3.add(heightMid, Cesium.Cartesian3.multiplyByScalar(heightTextDir,0.07,new Cesium.Cartesian3()),new Cesium.Cartesian3());
let heightTextPositionCarto = Cesium.Cartographic.fromCartesian(heightTextPosition);
let heightTextOption = {
text : '1',
style : 0,
color : '#ffffff',
position : {
latitude : Cesium.Math.toDegrees(heightTextPositionCarto.latitude),
longitude : Cesium.Math.toDegrees(heightTextPositionCarto.longitude),
height : heightTextPositionCarto.height,
},
offset : [0,0],
}
hmCesium.setText(heightTextOption);
//distance
let distMid = getLineCenter([upVertex, rightAngleVertex]);
let distTextDir = Cesium.Cartesian3.subtract(rightAngleVertex, downVertex, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(distTextDir, distTextDir);
let distTextPosition = Cesium.Cartesian3.add(distMid, Cesium.Cartesian3.multiplyByScalar(distTextDir,0.04,new Cesium.Cartesian3()),new Cesium.Cartesian3());
let distTextPositionCarto = Cesium.Cartographic.fromCartesian(distTextPosition);
let distTextOption = {
text : result.toFixed(2),
style : 0,
color : '#ffffff',
position : {
latitude : Cesium.Math.toDegrees(distTextPositionCarto.latitude),
longitude : Cesium.Math.toDegrees(distTextPositionCarto.longitude),
height : distTextPositionCarto.height,
},
offset : [0,0],
}
hmCesium.setText(distTextOption);
}
//normalVec 구하기
function calculateNormalVector(p1, p2, p3) {
// 두 벡터를 계산
let vector1 = Cesium.Cartesian3.subtract(p2, p1, new Cesium.Cartesian3());
let vector2 = Cesium.Cartesian3.subtract(p3, p1, new Cesium.Cartesian3());
// 법선 벡터 계산
let normal = Cesium.Cartesian3.cross(vector1, vector2, new Cesium.Cartesian3());
// 노말 벡터의 단위 벡터로 정규화
Cesium.Cartesian3.normalize(normal, normal);
//혹시나 아래쪽 향할때는 반대 벡터...
let angle = Cesium.Math.toDegrees(Cesium.Cartesian3.angleBetween(p1,normal))
if(angle > 90){
normal = Cesium.Cartesian3.multiplyByScalar(normal, -1, new Cesium.Cartesian3());
}
return normal;
}
function getLineCenter(array){
let halfDist = 0;
for(let i =1;i Cesium.Cartesian3.distance(array[idx-1], array[idx])){
halfDist -= Cesium.Cartesian3.distance(array[idx-1], array[idx]);
idx++;
}
let dir = Cesium.Cartesian3.subtract(array[idx], array[idx-1], new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(dir,dir);
let center = new Cesium.Cartesian3();
Cesium.Cartesian3.add(array[idx-1], Cesium.Cartesian3.multiplyByScalar(dir, halfDist, new Cesium.Cartesian3()), center);
return center;
}
function getSplitPoint(array, len) {
let totalDist = 0;
// 총 거리 계산
for (let i = 0; i < array.length - 1; i++) {
totalDist += Cesium.Cartesian3.distance(array[i], array[i + 1]);
}
// 각 포인트 간의 거리
let term = totalDist / (len - 1);
let splitPoints = [array[0]]; // 첫 번째 포인트 추가
let currentDist = 0;
for (let i = 0; i < array.length - 1; i++) {
let start = array[i];
let end = array[i + 1];
let segmentDist = Cesium.Cartesian3.distance(start, end);
while (currentDist + segmentDist >= term) {
let ratio = (term - currentDist) / segmentDist;
let newPoint = Cesium.Cartesian3.lerp(start, end, ratio, new Cesium.Cartesian3());
splitPoints.push(newPoint);
currentDist = 0; // 거리 초기화
if (splitPoints.length === len) {
return splitPoints;
}
}
currentDist += segmentDist;
}
// 필요한 포인트 수를 충족하지 않은 경우, 마지막 포인트 추가
if (splitPoints.length < len) {
splitPoints.push(array[array.length - 1]);
}
return splitPoints;
}
function splitLine(start, end, pointNum) {
let result = [];
const distance = Cesium.Cartesian3.distance(start, end);
const step = distance / (pointNum-1);
const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(direction, direction);
let currentPoint = Cesium.Cartesian3.clone(start);
result.push(currentPoint);
for (let i = 1; i < pointNum-1; i++) {
const nextPoint = Cesium.Cartesian3.add(currentPoint, Cesium.Cartesian3.multiplyByScalar(direction, step * i, new Cesium.Cartesian3()), new Cesium.Cartesian3());
result.push(nextPoint);
}
result.push(end);
return result;
}
function getIntersectionPoint(start, end, rectLength){
let dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
let ray = new Cesium.Ray(start, dir);
let intersectionPoint = hmCesium.viewer.scene.pickFromRay(ray);
if(intersectionPoint && Cesium.Cartesian3.distance(start, intersectionPoint.position) < rectLength){
return intersectionPoint.position;
}
}
//array는 모두 이차배열로 만들어서 넣기
function convertCoord(array, from, to){
let result = [];
proj4.defs([
['EPSG:5185', '+proj=tmerc +lat_0=38 +lon_0=125 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5186', '+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5187', '+proj=tmerc +lat_0=38 +lon_0=129 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:5188', '+proj=tmerc +lat_0=38 +lon_0=131 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs'],
['EPSG:3124', '+proj=tmerc +lat_0=0 +lon_0=123 +k=0.99995 +x_0=500000 +y_0=0 +ellps=clrk66 +towgs84=-127.62,-67.24,-47.04,3.068,-4.903,-1.578,-1.06 +units=m +no_defs +type=crs'],
['EPSG:32242', '+proj=utm +zone=42 +ellps=WGS72 +towgs84=0,0,4.5,0,0,0.554,0.219 +units=m +no_defs +type=crs'],
['EPSG:32642', '+proj=utm +zone=42 +datum=WGS84 +units=m +no_defs +type=crs'],
['EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs'],
['EPSG:4326', '+proj=longlat +datum=WGS84 +no_defs'],
])
array.forEach(coordi=>{
result.push(proj4(`EPSG:${from}`,`EPSG:${to}`,coordi));
});
return result;
}
function makeRectPoint2(center, left, right, length){
let leftDir = Cesium.Cartesian3.subtract(left, center, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(leftDir,leftDir);
let rightDir = Cesium.Cartesian3.subtract(right, center, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(rightDir, rightDir);
let left_car3 = Cesium.Cartesian3.add(center, Cesium.Cartesian3.multiplyByScalar(leftDir, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let right_car3 = Cesium.Cartesian3.add(center, Cesium.Cartesian3.multiplyByScalar(rightDir, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let left_up = new Cesium.Cartesian3();
Cesium.Cartesian3.normalize(left_car3, left_up);
let right_up = new Cesium.Cartesian3();
Cesium.Cartesian3.normalize(right_car3, right_up);
let front = Cesium.Cartesian3.cross(leftDir, left_up, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(front, front);
let back = Cesium.Cartesian3.cross(rightDir, right_up, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(back, back);
let center_carto = Cesium.Cartographic.fromCartesian(center);
let SS_car3 = Cesium.Cartesian3.add(left_car3, Cesium.Cartesian3.multiplyByScalar(back, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let ES_car3 = Cesium.Cartesian3.add(left_car3, Cesium.Cartesian3.multiplyByScalar(front, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let SE_car3 = Cesium.Cartesian3.add(right_car3, Cesium.Cartesian3.multiplyByScalar(back, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let EE_car3 = Cesium.Cartesian3.add(right_car3, Cesium.Cartesian3.multiplyByScalar(front, length/2, new Cesium.Cartesian3()), new Cesium.Cartesian3());
let SS_carto = Cesium.Cartographic.fromCartesian(SS_car3);
let ES_carto = Cesium.Cartographic.fromCartesian(ES_car3);
let SE_carto = Cesium.Cartographic.fromCartesian(SE_car3);
let EE_carto = Cesium.Cartographic.fromCartesian(EE_car3);
let result = {
startS:Cesium.Cartesian3.fromRadians(SS_carto.longitude, SS_carto.latitude, center_carto.height),
startE:Cesium.Cartesian3.fromRadians(SE_carto.longitude, SE_carto.latitude, center_carto.height),
endS:Cesium.Cartesian3.fromRadians(ES_carto.longitude, ES_carto.latitude, center_carto.height),
endE:Cesium.Cartesian3.fromRadians(EE_carto.longitude, EE_carto.latitude, center_carto.height),
}
return result;
}
//무조건 2차...
function calculatePolynomial(points, degree = 2) {
const X = [];
const Y = [];
points.forEach(point => {
X.push(point[0]);
Y.push(point[1]);
});
const coefficients = excelQuadraticRegression(X, Y);
const splinePoints = [];
const numPoints = 100; // 원하는 점의 개수
const xMin = Math.min(...X);
const xMax = Math.max(...X);
const step = (xMax - xMin) / (numPoints - 1); // 각 점 사이의 간격을 계산
for (let i = 0; i < numPoints; i++) {
const x = xMin + i * step; // 현재 x 값을 계산
const y = coefficients.reduce((acc, coeff, index) =>
acc + coeff * Math.pow(x, index), 0
);
splinePoints.push([x,y,points[0][2]]);
}
return splinePoints;
}
function rotatePoint(point, angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return [
point[0] * cos - point[1] * sin,
point[0] * sin + point[1] * cos,
point[2] // Z축 값은 그대로 유지
];
}
function calculateDirection(points) {
const dx = points[points.length - 1][0] - points[0][0];
const dy = points[points.length - 1][1] - points[0][1];
return Math.atan2(dy, dx);
}
//calculatePolynomial => 첫점에서 마지막점으로 향하는 dir을 x축기준으로 변경
function calculatePolynomialWithRotation(points, degree = 2) {
const direction = calculateDirection(points);
const rotatedPoints = points.map(point => rotatePoint(point, -direction));
const X = rotatedPoints.map(point => point[0]);
const Y = rotatedPoints.map(point => point[1]);
const coefficients = excelQuadraticRegression(X, Y);
const splinePoints = [];
const numPoints = 100;
const xMin = Math.min(...X);
const xMax = Math.max(...X);
const step = (xMax - xMin) / (numPoints - 1);
for (let i = 0; i < numPoints; i++) {
const x = xMin + i * step;
const y = coefficients.reduce((acc, coeff, index) =>
acc + coeff * Math.pow(x, index), 0
);
const originalPoint = rotatePoint([x, y, points[0][2]], direction);
splinePoints.push(originalPoint);
}
return splinePoints;
}
function normalizeData(data) {
const mean = data.reduce((a, b) => a + b, 0) / data.length;
const std = Math.sqrt(data.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / data.length);
return {
normalizedData: data.map(x => (x - mean) / std),
mean,
std
};
}
function denormalizeCoefficients(coeffs, xStats) {
// y = a(x-μ)²/σ² + b(x-μ)/σ + c
// y = a'x² + b'x + c'
const a = coeffs.a / Math.pow(xStats.std, 2);
const b = (-2 * coeffs.a * xStats.mean) / Math.pow(xStats.std, 2) + coeffs.b / xStats.std;
const c = (coeffs.a * Math.pow(xStats.mean, 2)) / Math.pow(xStats.std, 2) -
(coeffs.b * xStats.mean) / xStats.std +
coeffs.c;
return { a, b, c };
}
function improvedMultipleLinearRegression(y, x_array) {
const n = y.length;
const k = x_array.length;
function matrixMultiply(a, b) {
const result = Array(a.length).fill().map(() => Array(b[0].length).fill(0));
return result.map((row, i) => {
return row.map((_, j) => {
return a[i].reduce((sum, elm, k) => sum + (elm * b[k][j]), 0)
})
})
}
function matrixTranspose(matrix) {
return matrix[0].map((_, i) => matrix.map(row => row[i]));
}
function luDecomposition(matrix) {
const n = matrix.length;
const lower = Array(n).fill().map(() => Array(n).fill(0));
const upper = Array(n).fill().map((_, i) => [...matrix[i]]);
for (let i = 0; i < n; i++) {
lower[i][i] = 1;
for (let j = i + 1; j < n; j++) {
const factor = upper[j][i] / upper[i][i];
lower[j][i] = factor;
for (let k = i; k < n; k++) {
upper[j][k] -= factor * upper[i][k];
}
}
}
return { lower, upper };
}
function solveLU(lower, upper, b) {
const n = lower.length;
const y = Array(n).fill(0);
const x = Array(n).fill(0);
// Forward substitution Ly = b
for (let i = 0; i < n; i++) {
y[i] = b[i];
for (let j = 0; j < i; j++) {
y[i] -= lower[i][j] * y[j];
}
}
// Back substitution Ux = y
for (let i = n - 1; i >= 0; i--) {
x[i] = y[i];
for (let j = i + 1; j < n; j++) {
x[i] -= upper[i][j] * x[j];
}
x[i] /= upper[i][i];
}
return x;
}
// 행렬 생성
const X = Array(n).fill().map(() => Array(k + 1).fill(1));
for (let i = 0; i < n; i++) {
for (let j = 0; j < k; j++) {
X[i][j + 1] = x_array[j][i];
}
}
const Xt = matrixTranspose(X);
const XtX = matrixMultiply(Xt, X);
const Xty = matrixMultiply(Xt, y.map(val => [val]));
// LU 분해를 사용한 값 구하기
const { lower, upper } = luDecomposition(XtX);
const coefficients = solveLU(lower, upper, Xty.map(row => row[0]));
// R² 계산
const y_mean = y.reduce((a, b) => a + b, 0) / n;
const y_pred = matrixMultiply(X, coefficients.map(c => [c])).map(row => row[0]);
const ss_tot = y.reduce((a, b) => a + Math.pow(b - y_mean, 2), 0);
const ss_res = y.reduce((a, b, i) => a + Math.pow(b - y_pred[i], 2), 0);
const r_squared = 1 - (ss_res / ss_tot);
return {
coefficients,
rSquared: r_squared
};
}
function excelQuadraticRegression(x, y) {
if (!Array.isArray(x) || !Array.isArray(y)) {
throw new Error('x와 y는 배열이어야 합니다');
}
if (x.length !== y.length) {
throw new Error('x와 y의 길이가 같아야 합니다');
}
if (x.length < 3) {
throw new Error('최소 3개의 데이터 포인트가 필요합니다');
}
// 데이터 정규화
const xStats = normalizeData(x);
const normalized_x = xStats.normalizedData;
// 정규화된 x²값 계산
const x_squared = normalized_x.map(val => val * val);
// 다중 선형 회귀 수행
const result = improvedMultipleLinearRegression(y, [normalized_x, x_squared]);
const [c, b, a] = result.coefficients; // 상수항, x계수, x²계수 순서
// 계수 역정규화
const denormalized = denormalizeCoefficients({a, b, c}, xStats);
return [denormalized.c, denormalized.b, denormalized.a];
}
// 위치 측정
function measureLoaction(){
console.log('위치');
let option = {
name : 'altitude',//이름
color : 'rgba(0, 0, 0, 0.0)',//포인트 색상
epsg : hmCesium.domManager.epsg,//표출 좌표계
altitude : {//=> 나중에 표출할 text 옵션
name : 'altitude',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#000000',//글자 색상
text : 'Altitude : @coordinate3', //coordinate1 = 변경된 1번째 좌표, coordinate2 = 변경된 2번째 좌표, coordinate3 = 변경된 3번째 좌표 변수 사용할것 앞에는 @표시
textShow : false,
},
callback : {
stopEditing : function(entity) {
stopEditing('location', entity);
}
}
}
hmCesium.getAltitude(option);
}
// 직선거리 측정
function measureStraightDistance() {
console.log('직선거리');
let option = {
name : 'distance',//이름
color : '#00ffff',//포인트 색상
aerial : { // 표출할 거리 = 표출 속성(text)
name : 'aerial distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#00ffff',//글자 색상
// lineColor:'#ff00ff',//aerial line color은 기본 color를 따라감.
text:`@value m`, //값 @value로 표시
textShow : false,
lineShow : true,
},
resultShow : false, //최종결과 show
callback : {
startEditing : function(entity) {
startEditing('straightDistance', entity);
},
onDrawing : function(entity) {
onDrawing('straightDistance', entity);
},
stopEditing : function(entity) {
stopEditing('straightDistance', entity);
}
}
}
hmCesium.getDistance(option);
}
// 수평거리 측정
function measureHorizontalDistance() {
console.log('수평거리');
let option = {
name : 'distance',//이름
type:'horizontal',
color : '#00ffff',//포인트 색상
aerial : { // 표출할 거리 = 표출 속성(text)
name : 'aerial distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#00ffff',//글자 색상
// lineColor:'#ff00ff',//aerial line color은 기본 color를 따라감.
text:`@value m`, //값 @value로 표시
textShow : false,
lineShow : false,
},
horizontal : { // 표출할 거리 = 표출 속성(text, line)
name : 'horizontal distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#00ff00',//글자 색상
lineColor:'#00ff00',//라인컬러
text:`@value m`,
textShow : false,
lineShow : true,
},
vertical : { // 표출할 거리 = 표출 속성(text, line)
name : 'vertical distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#000000',//글자 색상
lineColor:'#000000',//라인컬러
text:`@value m`,
textShow : false,
lineShow : true,
},
resultShow : false, //최종결과 show
callback : {
startEditing : function(entity) {
startEditing('horizontalDistance', entity);
},
onDrawing : function(entity) {
onDrawing('horizontalDistance', entity);
},
stopEditing : function(entity) {
stopEditing('horizontalDistance', entity);
}
}
}
hmCesium.getDistance(option);
}
// 수직거리 측정
function measureVerticalDistance() {
console.log('수직거리');
let option = {
name : 'distance',//이름
type:'vertical',
color : '#00ffff',//포인트 색상
aerial : { // 표출할 거리 = 표출 속성(text)
name : 'aerial distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#00ffff',//글자 색상
// lineColor:'#ff00ff',//aerial line color은 기본 color를 따라감.
text:`@value m`, //값 @value로 표시
textShow : false,
lineShow : false,
},
horizontal : { // 표출할 거리 = 표출 속성(text, line)
name : 'horizontal distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#00ff00',//글자 색상
lineColor:'#000000',//라인컬러
text:`@value m`,
textShow : false,
lineShow : true,
},
vertical : { // 표출할 거리 = 표출 속성(text, line)
name : 'vertical distance',
style : 2, //fill : 0, outline:1, fillandoutline:2
backgroundColor : '#ffffff',//배경색 미입력시 배경없음
color : '#0000ff',//글자 색상
lineColor:'#0000ff',//라인컬러
text:`@value m`,
textShow : false,
lineShow : true,
},
resultShow : false, //최종결과 show
callback : {
startEditing : function(entity) {
startEditing('verticalDistance', entity);
},
onDrawing : function(entity) {
onDrawing('verticalDistance', entity);
},
stopEditing : function(entity) {
stopEditing('verticalDistance', entity);
}
}
}
hmCesium.getDistance(option);
}
// 면적 측정
function measureArea() {
console.log('면적');
let option = {
name : 'area',
color : 'rgba(255, 255, 0, 0.5)', // 폴리곤 색상
area : {
name : 'area text',
text : `Area : @area ㎡\nPerimeter : @perimeter m`,
textShow : false,
style : 2,
backgroundColor : `#ffffff`,
color : `#000000`,
},
callback : {
startEditing : function(entity) {
startEditing('area', entity);
},
stopEditing : function(entity) {
stopEditing('area', entity);
}
}
}
hmCesium.getArea(option);
}
function startEditing(mode, entity) {
hmCesium.hmUtil.measureGeometryEntityArr.push(hmCesium.hmUtil.draw.drawList[hmCesium.hmUtil.draw.drawList.length-1]);
}
function onDrawing(mode, entity) {
let cartesian3, pixelPosition, text;
if (mode == 'straightDistance') {
cartesian3 = Cesium.Cartesian3.midpoint(
entity.polyline.positions._value[entity.polyline.positions._value.length-3],
entity.polyline.positions._value[entity.polyline.positions._value.length-2],
new Cesium.Cartesian3()
);
// text = `${addComma(entity.attribute.aerial[entity.attribute.aerial.length-1])}m`;
text = `
${addComma(entity.attribute.aerial[entity.attribute.aerial.length-1])}m
`
hmCesium.hmUtil.measureGeometryEntityArr.push(hmCesium.hmUtil.draw.drawList[hmCesium.hmUtil.draw.drawList.length-1]);
}
if (mode == 'horizontalDistance') {
let firstCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-3]);
let secondCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-2]);
let midPoint = entity.attribute.midPointArr[entity.attribute.midPointArr.length-1];
if(firstCarto.height > secondCarto.height){
cartesian3 = Cesium.Cartesian3.midpoint(entity.polyline.positions._value[entity.polyline.positions._value.length-3], midPoint, new Cesium.Cartesian3());
}else{
cartesian3 = Cesium.Cartesian3.midpoint(midPoint, entity.polyline.positions._value[entity.polyline.positions._value.length-2], new Cesium.Cartesian3());
}
// text = `${addComma(entity.attribute.horizontal[entity.attribute.horizontal.length-1])}m`;
text = `
${addComma(entity.attribute.horizontal[entity.attribute.horizontal.length-1])}m
`
for (let i = 5; i >= 1; i--) {
hmCesium.hmUtil.measureGeometryEntityArr.push(hmCesium.hmUtil.draw.drawList[hmCesium.hmUtil.draw.drawList.length-i]);
}
}
if (mode == 'verticalDistance') {
let firstCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-3]);
let secondCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-2]);
let midPoint = entity.attribute.midPointArr[entity.attribute.midPointArr.length-1];
if(firstCarto.height > secondCarto.height){
cartesian3 = Cesium.Cartesian3.midpoint(entity.polyline.positions._value[entity.polyline.positions._value.length-2], midPoint, new Cesium.Cartesian3());
}else{
cartesian3 = Cesium.Cartesian3.midpoint(midPoint, entity.polyline.positions._value[entity.polyline.positions._value.length-3], new Cesium.Cartesian3());
}
// text = `${addComma(entity.attribute.vertical[entity.attribute.vertical.length-1])}m`;
text = `
${addComma(entity.attribute.vertical[entity.attribute.vertical.length-1])}m
`
for (let i = 5; i >= 1; i--) {
hmCesium.hmUtil.measureGeometryEntityArr.push(hmCesium.hmUtil.draw.drawList[hmCesium.hmUtil.draw.drawList.length-i]);
}
}
pixelPosition = Cesium.SceneTransforms.worldToWindowCoordinates(hmCesium.viewer.scene, cartesian3);
if (cartesian3) addMeasureLabelDiv(cartesian3, text, pixelPosition, hmCesium.hmUtil.measureLayer);
}
function stopEditing(mode, entity) {
let cartesian3, pixelPosition, text;
if (mode == 'location') {
cartesian3 = entity.attribute.position;
if(hmCesium.domManager.epsg == '4326'){
// text = `
// 위도 : ${addComma(entity.attribute.coordinate[1])}도
// 경도 : ${addComma(entity.attribute.coordinate[0])}도
// 높이 : ${addComma(entity.attribute.coordinate[2])}m
// `;
text = `
위도
${addComma(entity.attribute.coordinate[1])}°
경도
${addComma(entity.attribute.coordinate[0])}°
높이
${addComma(entity.attribute.coordinate[2])}m
`
}else{
// text = `
// X : ${addComma(entity.attribute.coordinate[0])}m
// Y : ${addComma(entity.attribute.coordinate[1])}m
// Z : ${addComma(entity.attribute.coordinate[2])}m
// `;
let epsg = '중부';
switch(hmCesium.domManager.epsg){
case '5185': epsg = '서부'; break;
case '5186': epsg = '중부'; break;
case '5187': epsg = '동부'; break;
case '5188': epsg = '동해'; break;
}
text = `
${epsg} 기준
X
${addComma(entity.attribute.coordinate[0])}m
Y
${addComma(entity.attribute.coordinate[1])}m
Z
${addComma(entity.attribute.coordinate[2])}m
`
}
}
if (mode == 'straightDistance') {
cartesian3 = entity.polyline.positions._value[entity.polyline.positions._value.length-1];
let totalAerial = 0;
for(let i = 0; i < entity.attribute.aerial.length; i++){
totalAerial += Number(entity.attribute.aerial[i].toFixed(4));
}
// text = `직선거리 합계 : ${addComma(totalAerial)}m`;
text = `
직선거리 합계
${addComma(totalAerial)}m
`
}
if (mode == 'horizontalDistance') {
let lastCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-1]);
let lastMidPoint = Cesium.Cartographic.fromCartesian(entity.attribute.midPointArr[entity.attribute.midPointArr.length-1]);
let lon = Cesium.Math.toDegrees(lastCarto.longitude);
let lat = Cesium.Math.toDegrees(lastCarto.latitude);
let height = lastMidPoint.height;
cartesian3 = new Cesium.Cartesian3.fromDegrees(lon, lat, height);
let totalHorizontal = 0;
for(let i = 0; i < entity.attribute.horizontal.length; i++){
totalHorizontal += Number(entity.attribute.horizontal[i].toFixed(4));
}
// text = `수평거리 합계 : ${addComma(totalHorizontal)}m`;
text = `
수평거리 합계
${addComma(totalHorizontal)}m
`
}
if (mode == 'verticalDistance') {
let lastCarto = Cesium.Cartographic.fromCartesian(entity.polyline.positions._value[entity.polyline.positions._value.length-1]);
let lastMidPoint = Cesium.Cartographic.fromCartesian(entity.attribute.midPointArr[entity.attribute.midPointArr.length-1]);
let lon = Cesium.Math.toDegrees(lastCarto.longitude);
let lat = Cesium.Math.toDegrees(lastCarto.latitude);
let height = lastMidPoint.height;
cartesian3 = new Cesium.Cartesian3.fromDegrees(lon, lat, height);
let totalVertical = 0;
for(let i = 0; i < entity.attribute.vertical.length; i++){
totalVertical += Number(entity.attribute.vertical[i].toFixed(4));
}
// text = `수직거리 합계 : ${addComma(totalVertical)}m`;
text = `
수직거리 합계
${addComma(totalVertical)}m
`
}
// if (mode == 'area') {
// let positions = entity.polygon._hierarchy._value.positions.copyWithin();
// let labelPosition = hmCesium.hmUtil.measurement._getPolygonCenter(positions);
// let labelPositionCarto = Cesium.Cartographic.fromCartesian(labelPosition);
// let lon = Cesium.Math.toDegrees(labelPositionCarto.longitude);
// let lat = Cesium.Math.toDegrees(labelPositionCarto.latitude);
// let height = labelPositionCarto.height;
// cartesian3 = new Cesium.Cartesian3.fromDegrees(lon, lat, height);
// text = `
// 면적 : ${addComma(entity.attribute.areaInMeter)}m
// 둘레 : ${addComma(entity.attribute.perimeter)}m
// `;
// }
pixelPosition = Cesium.SceneTransforms.worldToWindowCoordinates(hmCesium.viewer.scene, cartesian3);
if (cartesian3) addMeasureLabelDiv(cartesian3, text, pixelPosition, hmCesium.hmUtil.measureLayer);
hmCesium.hmUtil.measureLabelEntityArr = [];
hmCesium.hmUtil.measureGeometryEntityArr = [];
initCursorAndScreenEvent();
}
function measureEnd() {
// 마우스모드 초기화
hmCesium.endDraw();
if (hmCesium.hmUtil.measureLabelEntityArr.length != 0) {
hmCesium.hmUtil.measureLabelEntityArr.map(measureLabelEntity => {
// measureLayer에서 measureLabelEntityArr의 요소와 동일한 엔티티 삭제
hmCesium.hmUtil.measureLayer.entities._entities._array.map(entity => {
if (entity.id == measureLabelEntity.id) {
hmCesium.hmUtil.measureLayer.entities.removeById(entity.id);
}
})
// measureLabelArr에서 measureLabelEntityArr의 요소와 동일한 div 삭제
hmCesium.hmUtil.measureLabelDivArr.map(measureLabelDiv => {
if (measureLabelDiv == measureLabelEntity.div) {
hmCesium.hmUtil.measureLabelDivArr = hmCesium.hmUtil.measureLabelDivArr.filter((element) => element != measureLabelEntity.div);
}
})
// 등록되어 있는 measureLabel div중에서 measureLabelEntityArr의 요소와 동일한 div 삭제
let divs = document.querySelectorAll('.measureLabel');
divs.forEach(div=>{
if (div == measureLabelEntity.div) {
div.parentNode.removeChild(div);
}
});
})
}
if (hmCesium.hmUtil.measureGeometryEntityArr.length != 0) {
hmCesium.hmUtil.measureGeometryEntityArr.map(measureGeometryEntity => {
// hmCesium.hmUtil.draw.drawList에서 measureGeometryEntityArr의 요소와 동일한 엔티티 삭제
hmCesium.hmUtil.draw.drawList.map(draw => {
if (draw.id == measureGeometryEntity.id) {
hmCesium.viewer.entities.remove(draw);
hmCesium.hmUtil.draw.drawList = hmCesium.hmUtil.draw.drawList.filter((element) => element.id != draw.id);
}
})
})
}
hmCesium.viewer.scene.requestRender();
hmCesium.hmUtil.measureLabelEntityArr = [];
hmCesium.hmUtil.measureGeometryEntityArr = [];
}
// 측정 Clear 및 측정닫기
function measureClear() {
hmCesium.clearDraw();
// 마우스모드 초기화
hmCesium.endDraw();
// hmCesium.hmUtil.measureLayer에 포함된 엔티티 및 measureLayer에 모두 삭제
if (hmCesium.hmUtil.measureLayer) {
hmCesium.hmUtil.measureLayer.entities.removeAll();
delete hmCesium.hmUtil.measureLayer;
}
hmCesium.viewer.entities.removeAll();
hmCesium.viewer.scene.requestRender();
// 측정 라벨 div 전부 삭제
let divs = document.querySelectorAll('.measureLabel');
divs.forEach(div=>{
div.parentNode.removeChild(div);
});
hmCesium.hmUtil.measureLabelDivArr = [];
initCursorAndScreenEvent();
}
// 숫자 천 단위 콤마 추가, 소수점 넷 째 자리까지 표시
function addComma(val) {
let result = val.toFixed(4).toString().replace(/\B(? 0) return layer[0];
else{
if(!bMake) bMake = true;
if(bMake == true) {
layer = new Cesium.CustomDataSource(pName);
hmCesium.viewer.dataSources.add(layer);
return layer;
}
}
}
//라벨 생성
document.getElementById('func-label-btn').addEventListener('click',async (e)=>{
if(document.getElementById('func-label').style.display == 'none'){
resetAllMode();
document.getElementById('func-label').style.display = 'flex';
document.getElementById('func-label-bar').style.display = 'flex';
if(!document.getElementById('label-layer-btn').querySelector('input').checked){
document.getElementById('label-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
}
let ul = document.querySelector('#func-label ul');
ul.innerHTML = ``;
if(!hmCesium.labels){
hmCesium.labels = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['label']);
}
for(let i = 0; i < hmCesium.labels.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.labels[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.labels[i].longitude, hmCesium.labels[i].latitude, hmCesium.labels[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//라벨 클릭 이벤트
hmCesium.viewer.screenSpaceEventHandler.setInputAction(labelClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}else{
document.getElementById('func-label').style.display = 'none';
document.getElementById('func-label-bar').style.display = 'none';
initCursorAndScreenEvent();
}
document.getElementById('func-label-btn').classList.toggle('on');
})
//라벨 클릭 이벤트
function labelClickEvent(e){
const pickedObject = hmCesium.viewer.scene.pick(e.position,1,1);
if(pickedObject.primitive && pickedObject.primitive.info && pickedObject.primitive.info.id.includes('label')){
openLabelProperty(pickedObject.primitive.info);
}
}
//라벨 생성창 호출
document.getElementById('label-add-btn').addEventListener('click',()=>{
document.body.addEventListener('mousemove', changeCursor);
hmCesium.viewer.screenSpaceEventHandler.setInputAction((e)=>{
const cartesian = hmCesium.viewer.scene.pickPosition(e.position);
if(Cesium.defined(cartesian)){
//위치 전달, 생성창 열기
openLabelProperty(undefined, cartesian);
initCursorAndScreenEvent();
//라벨 클릭 이벤트 다시 달아주기
hmCesium.viewer.screenSpaceEventHandler.setInputAction(labelClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
})
//라벨 속성창
async function openLabelProperty(label,position){
//속성창 오픈
document.getElementById('func-label-add').style.display = 'flex';
let text = document.getElementById('modal-label-text');//input
let size = document.getElementById('modal-label-size');//radio
let color = document.getElementById('modal-label-color');//radio
let alpha = document.getElementById('modal-label-alpha');//range
color.querySelector('#last-swatch').value = '#000000';
color.querySelector('#last-swatch').nextElementSibling.style.backgroundColor = '#000000';
if(label){//라벨 info가 있는경우 속성불러와서 표출
text.value = label.text;
size.querySelector(`input[value="${label.size}"]`).checked = true;
if(color.querySelector(`input[value="${label.bgColor}"]`)){
color.querySelector(`input[value="${label.bgColor}"]`).checked = true;
}else{
color.querySelector('#last-swatch').value = `${label.bgColor}`;
color.querySelector('#last-swatch').nextElementSibling.style.backgroundColor = `${label.bgColor}`;
color.querySelector('#last-swatch').checked = true;
}
alpha.value = (1-label.alpha);
alpha.style.background = `linear-gradient(to right, #fff ${(1-label.alpha)*100}%, #aaa ${(1-label.alpha)*100}%)`;
text.labelId = label.id;
text.latitude = label.latitude;
text.longitude = label.longitude;
text.labelHeight = label.height;
}else{//없는 경우 초기화
text.value = '';
size.querySelector('input[value="25"]').checked = true;
color.querySelector(`input[value="#000000"]`).checked = true;
alpha.value = 0;
alpha.style.background = `linear-gradient(to right, #fff ${0}%, #aaa ${0}%)`;
let carto = Cesium.Cartographic.fromCartesian(position);
text.latitude = Cesium.Math.toDegrees(carto.latitude);
text.longitude = Cesium.Math.toDegrees(carto.longitude);
text.labelHeight = carto.height;
text.labelId = undefined;
}
}
//라벨 속성창 닫기
document.getElementById('func-label-add').querySelector('img').addEventListener('click',()=>{
document.getElementById('func-label-add').style.display = 'none';
})
//라벨 속성창 삭제
document.getElementById('modal-label-delete').addEventListener('click',async ()=>{
let text = document.getElementById('modal-label-text');
let id = text.labelId;
let idx = findLabelIdx(id);
let label = hmCesium.labels[idx];
//삭제컨펌
if(!confirm(`라벨 "${(label)?label.text:document.getElementById('modal-label-text').value}" 정말 삭제합니까?`)) return;
if(idx != undefined){
hmCesium.labels.splice(idx,1);
}
await setLabel();
//라벨리스트 최신화
hmCesium.labels = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['label']);
let ul = document.querySelector('#func-label ul');
ul.innerHTML = ``;
for(let i = 0; i < hmCesium.labels.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.labels[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.labels[i].longitude, hmCesium.labels[i].latitude, hmCesium.labels[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//지도창 라벨 다시 그리기
if(document.getElementById('label-layer-btn').querySelector('input').checked){
document.getElementById('label-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
}
document.getElementById('label-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
document.getElementById('func-label-add').style.display = 'none';
})
//라벨 속성창 적용
document.getElementById('modal-label-submit').addEventListener('click',async ()=>{
let text = document.getElementById('modal-label-text');
let id = text.labelId;
if(document.getElementById('modal-label-text').value == ''){
alert('텍스트를 꼭 입력해주세요.');
return;
}
let label = {
id:id,
text:document.getElementById('modal-label-text').value,
size:document.getElementById('modal-label-size').querySelector('input:checked').value,
bgColor:document.getElementById('modal-label-color').querySelector('input:checked').value,
alpha:1-document.getElementById('modal-label-alpha').value,
latitude:text.latitude,
longitude:text.longitude,
height:text.labelHeight,
projectId : hmCesium.main.projectCode,
modelId: hmCesium.curModel,
type:"label",
createDate:getToday()
}
if(id){
let idx = findLabelIdx(id);
hmCesium.labels[idx] = label;
}else{//신규
if(hmCesium.labels.length > 0)
label.id = `label`+(parseInt(hmCesium.labels[hmCesium.labels.length-1].id.split('label')[1])+1);
else
label.id = `label0`;
hmCesium.labels.push(label);
}
await setLabel();
//라벨리스트 최신화
hmCesium.labels = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['label']);
let ul = document.querySelector('#func-label ul');
ul.innerHTML = ``;
for(let i = 0; i < hmCesium.labels.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.labels[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.labels[i].longitude, hmCesium.labels[i].latitude, hmCesium.labels[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//지도창 라벨 다시 그리기
if(document.getElementById('label-layer-btn').querySelector('input').checked){
document.getElementById('label-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
}
document.getElementById('label-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
document.getElementById('func-label-add').style.display = 'none';
})
//라벨 리스트에서 아이디로 라벨 idx찾기
function findLabelIdx(id){
if(hmCesium.labels.length < 1) return -1;
for(let i =0;i{
//전체 보이고 현재 모델만 안보이게
document.getElementById('label-get-list').querySelectorAll('li').forEach(ele=>{
ele.style.display = 'block';
})
document.getElementById(`select-${hmCesium.curModel}`).style.display = 'none';
document.getElementById('label-get-selected').innerHTML = `라벨을 가져올 모델을 선택하세요.`;
document.getElementById('label-get-selected').selectedModel = undefined;
document.getElementById('label-get').style.display='flex';
})
//라벨 가져오기 닫기
document.querySelector('#label-get img.icon').addEventListener('click',()=>{
document.getElementById('label-get').style.display='none';
})
//라벨 가져오기 적용
document.getElementById('label-get-submit').addEventListener('click',async()=>{
let id = document.getElementById('label-get-selected').selectedModel;
console.log(id);
let labels = await readJSONFile(hmCesium.main.model[id].dLayer['label']);
for(let i = 0; i < labels.length; i++){
if(hmCesium.labels.length > 0){
labels[i].id = `label${(parseInt(hmCesium.labels[hmCesium.labels.length-1].id.split('label')[1])+i+1)}`;
}else{
labels[i].id = `label${i}`;
}
}
hmCesium.labels = [...hmCesium.labels,...labels];
await setLabel();
//라벨리스트 최신화
hmCesium.labels = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['label']);
let ul = document.querySelector('#func-label ul');
ul.innerHTML = ``;
for(let i = 0; i < hmCesium.labels.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.labels[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.labels[i].longitude, hmCesium.labels[i].latitude, hmCesium.labels[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//지도창 라벨 다시 그리기
if(document.getElementById('label-layer-btn').querySelector('input').checked){
document.getElementById('label-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
}
document.getElementById('label-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('label-layer-btn').querySelector('input').dispatchEvent(event);
document.getElementById('label-get').style.display='none';
})
//라벨 전체삭제
document.getElementById('label-delete-btn').addEventListener('click',async ()=>{
if(confirm(`${hmCesium.curModel.split('__')[1]}에 등록된 전체 라벨을 삭제합니까?`)){
// hmCesium.deleteBillAll();
let bills = hmCesium.getBillsByType('label');
bills.forEach(bill=>{
hmCesium.deleteBill(bill);
});
document.querySelector('#func-label ul').replaceChildren();
hmCesium.labels = [];
await setLabel();
}
})
//라벨 저장
async function setLabel(){
let jsonData = hmCesium.labels;
let res = await axios.post(hmCesium.main.query.setLabel.replace(':curModel', hmCesium.curModel), jsonData);
if(res.status != 200){
alert('라벨 저장 중 Error 발생');
}
}
//이슈 생성
document.getElementById('func-issue-btn').addEventListener('click',async (e)=>{
if(document.getElementById('func-issue').style.display == 'none'){
resetAllMode();
document.getElementById('func-issue').style.display = 'flex';
document.getElementById('func-issue-bar').style.display = 'flex';
if(!document.getElementById('issue-layer-btn').querySelector('input').checked){
document.getElementById('issue-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
}
let ul = document.querySelector('#func-issue ul');
ul.innerHTML = ``;
if(!hmCesium.issues){
hmCesium.issues = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['issue']);
}
for(let i = 0; i < hmCesium.issues.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.issues[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.issues[i].longitude, hmCesium.issues[i].latitude, hmCesium.issues[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//이슈 클릭 이벤트
// hmCesium.viewer.screenSpaceEventHandler.setInputAction(issueClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}else{
document.getElementById('func-issue-add').style.display = 'none';
document.getElementById('func-issue').style.display = 'none';
document.getElementById('func-issue-bar').style.display = 'none';
initCursorAndScreenEvent();
}
document.getElementById('func-issue-btn').classList.toggle('on');
})
//이슈 클릭 이벤트
function issueClickEvent(e){
if(document.querySelector('#issue-layer-btn input').checked){
const pickedObject = hmCesium.viewer.scene.pick(e.position,1,1);
if(pickedObject.primitive && pickedObject.primitive.info && pickedObject.primitive.info.id.includes('issue')){
if(document.getElementById('func-issue-bar').style.display !== 'none'){
openIssueProperty(pickedObject.primitive.info, undefined,true);
}else{
openIssueProperty(pickedObject.primitive.info);
}
}
}
}
//이슈 선택용 핸들러
let newHandler = new Cesium.ScreenSpaceEventHandler(hmCesium.viewer.scene.canvas);
newHandler.setInputAction(issueClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//이슈 생성창 호출
document.getElementById('issue-add-btn').addEventListener('click',()=>{
document.body.addEventListener('mousemove', changeCursor);
hmCesium.viewer.screenSpaceEventHandler.setInputAction((e)=>{
const cartesian = hmCesium.viewer.scene.pickPosition(e.position);
if(Cesium.defined(cartesian)){
//위치 전달, 생성창 열기
openIssueProperty(undefined, cartesian, true);
initCursorAndScreenEvent();
//이슈 클릭이벤트 다시 달아주기
hmCesium.viewer.screenSpaceEventHandler.setInputAction(issueClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
})
function openIssueProperty(issue, position, edit){
if(edit){
document.getElementById('modal-issue-text').disabled = false;
document.getElementById('modal-issue-content').disabled = false;
document.querySelector('#func-issue-add .window-btn-wrap').style.display = '';
}else{
document.getElementById('modal-issue-text').disabled = true;
document.getElementById('modal-issue-content').disabled = true;
document.querySelector('#func-issue-add .window-btn-wrap').style.display = 'none';
}
let text = document.getElementById('modal-issue-text'); // 이후 추가부분
let details = document.getElementById('modal-issue-content');
let writer = document.getElementById('modal-issue-writer');
let date = document.getElementById('modal-issue-date');
// let files = document.getElementById('modal-issue-fileList'); //이후 추가부분
// files.style.display = 'none';
// files.innerHTML = ``;
//속성창 오픈 - 우선 파일첨부 보류
document.getElementById('func-issue-add').style.display = 'flex';
if(issue){//issue 가 있으면 속성표출
text.value = issue.text;
details.value = issue.details;
writer.innerHTML = issue.writer;
date.innerHTML = issue.createDate;
// if(issue.filePath && issue.filePath.length > 0){
// files.style.display = 'block';
// issue.filePath.forEach(file=>{
// let item= document.createElement('div');
// item.classList.add('file-item');
// item.innerHTML = `${file}
// `;
// files.appendChild(item);
// //다운로드, 삭제 이벤트 추가
// })
// }
writer.issueId = issue.id;
writer.latitude = issue.latitude;
writer.longitude = issue.longitude;
writer.issueHeight = issue.height;
}else{// 없으면 초기화
text.value = '';
details.value = ``;
writer.innerHTML = `${hmCesium.user.user_nm} ${hmCesium.user.position}`; // 추후 로그인 사용자
date.innerHTML = getToday();
// files.style.display = 'none';
let carto = Cesium.Cartographic.fromCartesian(position);
writer.latitude = Cesium.Math.toDegrees(carto.latitude);
writer.longitude = Cesium.Math.toDegrees(carto.longitude);
writer.issueHeight = carto.height;
writer.issueId = undefined;
}
}
//이슈 속성창 닫기
document.getElementById('func-issue-add').querySelector('img').addEventListener('click',()=>{
document.getElementById('func-issue-add').style.display = 'none';
})
//이슈 속성창 삭제
document.getElementById('modal-issue-cancel').addEventListener('click',async ()=>{
let writer = document.getElementById('modal-issue-writer');
let id = writer.issueId;
let idx = findIssueIdx(id);
let issue = hmCesium.issues[idx];
//삭제컨펌
if(!confirm(`이슈 "${(issue)?issue.text:document.getElementById('modal-issue-text').value}" 정말 삭제합니까?`)) return;
if(idx != undefined){
hmCesium.issues.splice(idx,1);
}
await setIssue();
//이슈 리스트 다시 만들기
hmCesium.issues = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['issue']);
let ul = document.querySelector('#func-issue ul');
ul.innerHTML = ``;
for(let i = 0; i < hmCesium.issues.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.issues[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.issues[i].longitude, hmCesium.issues[i].latitude, hmCesium.issues[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//화면에 이슈 다시 그리기
if(document.getElementById('issue-layer-btn').querySelector('input').checked){
document.getElementById('issue-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
}
document.getElementById('issue-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
document.getElementById('func-issue-add').style.display = 'none';
})
//이슈 속성창 추가
document.getElementById('modal-issue-submit').addEventListener('click',async ()=>{
let writer = document.getElementById('modal-issue-writer');
let id = writer.issueId;
if(document.getElementById('modal-issue-content').value == '' || document.getElementById('modal-issue-text').value == ''){
alert('제목과 상세내용을 꼭 입력해주세요.');
return;
}
let issue = {
id:id,
text:document.getElementById('modal-issue-text').value, //이후 추가부분
latitude:writer.latitude,
longitude:writer.longitude,
height:writer.issueHeight,
projectId : hmCesium.main.projectCode,
modelId: hmCesium.curModel,
type:`issue-type1`,
icon : `./img/icons/issue-type1.svg`,
iconScale:1,
createDate:document.getElementById('modal-issue-date').innerText,
details:document.getElementById('modal-issue-content').value,
writer:document.getElementById('modal-issue-writer').innerHTML,
files : [],
}
if(id){
let idx = findIssueIdx(id);
hmCesium.issues[idx] = issue;
}else{//신규
if(hmCesium.issues.length > 0)
issue.id = `issue`+(parseInt(hmCesium.issues[hmCesium.issues.length-1].id.split('issue')[1])+1);
else
issue.id = `issue0`;
hmCesium.issues.push(issue);
}
await setIssue();
//이슈 리스트 다시 만들기
hmCesium.issues = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['issue']);
let ul = document.querySelector('#func-issue ul');
ul.innerHTML = ``;
for(let i = 0; i < hmCesium.issues.length; i++){
let li = document.createElement('li');
li.innerHTML = `
${hmCesium.issues[i].text} `;
ul.appendChild(li);
li.addEventListener('click',()=>{
let option = {
location : [hmCesium.issues[i].longitude, hmCesium.issues[i].latitude, hmCesium.issues[i].height * 10, 0, -1.57],
duration : 1.5,
}
hmCesium.camera_flyTo(option);
})
}
//화면에 이슈 다시 그리기
if(document.getElementById('issue-layer-btn').querySelector('input').checked){
document.getElementById('issue-layer-btn').querySelector('input').checked = false;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
}
document.getElementById('issue-layer-btn').querySelector('input').checked = true;
let event = new Event('change', { bubbles: true, cancelable: true });
await document.getElementById('issue-layer-btn').querySelector('input').dispatchEvent(event);
document.getElementById('func-issue-add').style.display = 'none';
})
//이슈 리스트에서 아이디로 이슈 idx찾기
function findIssueIdx(id){
if(hmCesium.issues.length < 1) return -1;
for(let i =0;i{
if(confirm(`${hmCesium.curModel.split('__')[1]}에 등록된 전체 이슈를 삭제합니까?`)){
// hmCesium.deleteBillAll();
let bills = hmCesium.getBillsByType('issue-type1');
bills.forEach(bill=>{
hmCesium.deleteBill(bill);
});
document.querySelector('#func-issue ul').replaceChildren();
hmCesium.issues = [];
await setIssue();
}
})
//이슈 저장
async function setIssue(){
let jsonData = hmCesium.issues;
let res = await axios.post(hmCesium.main.query.setIssue.replace(':curModel', hmCesium.curModel), jsonData);
if(res.status != 200){
alert('이슈 저장 중 Error 발생');
}
}
//이슈 파일추가
//이슈 파일삭제
//큐피드 ( 보류 )
//날짜 생성용
function getToday(){
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0'); // 월은 0부터 시작하므로 +1
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** GSIM 기능 (중앙) END ***//////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** Layer (우측 하단) ***///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//각 모델 선택 시 레이어 확인하여 레이어창 없애기
async function setLayer(dlayer){
//wpb - 선형중심선
//label - 라벨
//issue - 이슈
//plane - 계획평면
//siteLine - 용지라인
//이전 레이어 모두 off, 모두 disabled 처리후 있는것들만 풀기
let layer_btns = document.getElementById('layer-modal').querySelectorAll('.checkbox-label.layer');
for(let i = 0; i < layer_btns.length; i++){
layer_btns[i].checked = false;
if(!layer_btns[i].classList.contains('disabled'))
layer_btns[i].classList.add('disabled');
}
let keys = Object.keys(dlayer);
for(let i = 0; i < keys.length; i++){
document.getElementById(`${keys[i]}-layer-btn`).classList.remove('disabled');
// 전체 DLayer off로 시작
// if(keys[i] == 'label'||keys[i] == 'issue'){ //전체 dLayer 처음부터 보이기
// document.getElementById(`${keys[i]}-layer-btn`).querySelector('input').checked = true;
// const changeEvent = new Event('change',{
// bubbles : false,
// cancelable : false,
// composed : false
// });
// document.getElementById(`${keys[i]}-layer-btn`).querySelector('input').dispatchEvent(changeEvent);
// }
}
}
//체크박스 change 이벤트
document.querySelectorAll('#layer-modal input').forEach(ele=>{
ele.addEventListener('change', (e)=>{
if(e.target.closest('.checkbox-label.layer').classList.contains('disabled')){
return;
}
let type = e.target.closest('label').id.split('-layer-btn')[0];
let bOn = ele.checked;
switch(type){
case 'wpb' :
toggleWpb(bOn);
break;
case 'plane' :
togglePlane(bOn);
break;
case 'siteLine' :
toggleSiteLine(bOn);
break;
case 'label' :
toggleLabel(bOn);
break;
case 'issue' :
toggleIssue(bOn);
break;
}
})
})
//선형중심선
async function toggleWpb(bOn){
if(bOn){
hmCesium.loadRoadData(hmCesium.main.model[hmCesium.curModel].dLayer['wpb'], `EPSG:${hmCesium.main.model[hmCesium.curModel].projection}`);
}else{
hmCesium.removeRoadData();
}
}
//계획평면
let basePlanPolylineCollection = undefined;
async function togglePlane(bOn){
if(bOn){
togglePlanFunctionProgress(true);
let params = {
table : hmCesium.main.model[hmCesium.curModel].dLayer['plane']
}
let res = await axios.get(`${hmCesium.main.query['getPlaneData']}`,{params:params});
if (res.data.message == 'Get Plan Data Complete') {
if (res.data.queryResult.length != 0) setPlanPrimitives(res.data.queryResult, 'base');
}
}else{
if (basePlanPolylineCollection) hmCesium.viewer.scene.groundPrimitives.remove(basePlanPolylineCollection);
basePlanPolylineCollection = undefined;
hmCesium.viewer.scene.render();
}
}
//용지라인
let siteLinePlanPolylineCollection = undefined;
async function toggleSiteLine(bOn){
if(bOn){
togglePlanFunctionProgress(true);
let params = {
table : hmCesium.main.model[hmCesium.curModel].dLayer['siteLine']
}
let res = await axios.get(`${hmCesium.main.query['getPlaneData']}`,{params:params});
if (res.data.message == 'Get Plan Data Complete') {
if (res.data.queryResult.length != 0) setPlanPrimitives(res.data.queryResult, 'siteLine');
}
}else{
if (siteLinePlanPolylineCollection) hmCesium.viewer.scene.groundPrimitives.remove(siteLinePlanPolylineCollection);
siteLinePlanPolylineCollection = undefined;
hmCesium.viewer.scene.render();
}
}
//라벨
async function toggleLabel(bOn){
if(bOn){
hmCesium.labels = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['label']);
hmCesium.addBills(hmCesium.labels);
hmCesium.viewer.scene.render();
}else{
let bills = hmCesium.getBillsByType('label');
bills.forEach(bill=>{
hmCesium.deleteBill(bill);
});
hmCesium.labels = undefined;
hmCesium.viewer.scene.render();
}
}
//이슈
async function toggleIssue(bOn){
if(bOn){
hmCesium.issues = await readJSONFile(hmCesium.main.model[hmCesium.curModel].dLayer['issue']);
hmCesium.addBills(hmCesium.issues);
hmCesium.viewer.scene.render();
// hmCesium.viewer.screenSpaceEventHandler.setInputAction(issueClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}else{
let bills = hmCesium.getBillsByType('issue-type1');
bills.forEach(bill=>{
hmCesium.deleteBill(bill);
});
hmCesium.issues = undefined;
hmCesium.viewer.scene.render();
}
}
//json 파일 읽어오기
async function readJSONFile(fileUrl) {
try {
const response = await fetch(fileUrl);
if (response.ok) {
const geoJSONData = await response.json();
return geoJSONData;
} else {
throw new Error("파일을 불러오는 데 문제가 발생했습니다.");
}
} catch (error) {
console.error("오류:", error);
return null;
}
}
//대기창
let planFunctionProgressDiv = undefined;
function togglePlanFunctionProgress(bool) {
if (bool) {
planFunctionProgressDiv = document.createElement('div');
// planFunctionProgressDiv.cartesian3 = lastPickPos;
planFunctionProgressDiv.innerHTML = ' ';
planFunctionProgressDiv.style.position = 'absolute';
planFunctionProgressDiv.style.display = 'flex';
planFunctionProgressDiv.style.width = '50px';
planFunctionProgressDiv.style.height = '50px';
planFunctionProgressDiv.style.left = '50%';
planFunctionProgressDiv.style.top = '50%';
planFunctionProgressDiv.style.transform = 'translate(-50%, -50%)';
planFunctionProgressDiv.style.background = 'rgba(255,255,255,0.5)';
planFunctionProgressDiv.style.borderRadius = '30px';
planFunctionProgressDiv.classList.add('plan-finction-progress');
document.body.appendChild(planFunctionProgressDiv);
} else {
if (!planFunctionProgressDiv) return;
document.body.removeChild(planFunctionProgressDiv);
planFunctionProgressDiv = undefined;
}
}
//plane 그리기함수
async function setPlanPrimitives(data, type, isRight) {
// collection 생성
let collection = new Cesium.PrimitiveCollection();
collection.id = `${type}PlanPolylineCollection`;
let geometryArray = [];
data.map(d => {
// 선 색깔 설정
let color = '#FF0000';
if (d.path) {
if (d.path.includes('Bline')) color = '#6699CC';
if (d.path.includes('Bplan')) color = '#0000FF';
if (d.path.includes('filling')) {
color = '#AABABA';
if (d.path.includes('j_filling')) color = '#CC9900';
if (d.path.includes('s_filling')) color = '#CD66CD';
}
if (d.path.includes('structure')) {
color = '#E8835E';
if (d.path.includes('structureT') || d.path.includes('structure_T')) color = '#00FF00';
}
if (d.path.includes('sichu')) color = '#000000';
if (d.path.includes('ascon')) color = '#848484';
}
if(d.text == 'Modified'){
if (d.path.toLowerCase().includes('blue')) color = '#0000ff';
if (d.path.toLowerCase().includes('brown')) color = '#e0a870';
if (d.path.toLowerCase().includes('cyan')) color = '#00ffff';
if (d.path.toLowerCase().includes('gray')) color = '#808080';
if (d.path.toLowerCase().includes('green')) color = '#00ff00';
if (d.path.toLowerCase().includes('red')) color = '#ff0000';
if (d.path.toLowerCase().includes('white')) color = '#ffffff';
if (d.path.toLowerCase().includes('yellow')) color = '#ffff00';
if (d.path.toLowerCase().includes('magenta')) color = '#ff00ff';
}
if(d.layer.includes('용지')) color = '#0BFA77';
Cesium.GeoJsonDataSource.load(d.geom).then((geojson) => {
geojson.entities.values.map(entity => {
let polylinePosition = entity.polyline.positions._value;
// 상세 도면 primitive 생성
let polylineGeometry = new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({
positions: polylinePosition,
width: 2,
arcType: Cesium.ArcType.GEODESIC
}),
attributes: {
color: new Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(color)),
}
});
geometryArray.push(polylineGeometry);
})
})
})
let polylinePrimitive = new Cesium.GroundPolylinePrimitive({
geometryInstances: geometryArray,
asynchronous: false,
appearance: new Cesium.PolylineColorAppearance(),
releaseGeometryInstances: false,
allowPicking: false,
});
// collection에 primitive 추가
collection.add(polylinePrimitive);
// type에 맞는 전역변수에 collection 저장
if (type == 'base') {
basePlanPolylineCollection = collection;
}else if(type == 'siteLine'){
siteLinePlanPolylineCollection = collection;
} else {
// detailPlanPolylineCollection = collection;
}
// hmCesium.viewer.scene.groundPrimitives에 collection 추가 후 requestRender
hmCesium.viewer.scene.groundPrimitives.add(collection);
hmCesium.viewer.scene.requestRender();
// progress 삭제
// if(type == 'base' || type=='siteLine') setTimeout(togglePlanFunctionProgress(false),2000);
setTimeout(togglePlanFunctionProgress(false),2000);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** Layer (우측 하단) END ***//////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** footer (mouseInfo) ***///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 토목좌표 설정
document.getElementById('gcs2').addEventListener('change', () => {
if(document.querySelector('input[name="pcs"]')) document.querySelector('input[name="pcs"]').checked = true;
document.querySelectorAll('input[name="pcs"]').forEach((radio) => {
radio.disabled = false;
let label = radio.closest('label');
label.style.opacity = '100%';
label.style.cursor = 'pointer';
});
hmCesium.change_coordiUnit(document.querySelector('input[name="pcs"]:checked').id);
});
// 좌표 변환 설정
document.querySelectorAll('input[name="pcs"]').forEach((radio) => {
radio.addEventListener('change', () => {
hmCesium.change_coordiUnit(radio.id);
});
});
// 위경도 설정
document.getElementById('gcs1').addEventListener('change', (e) => {
if (e.target.checked) {
hmCesium.change_coordiUnit('4326');
}
document.querySelectorAll('input[name="pcs"]').forEach((radio) => {
radio.disabled = true;
radio.checked = false;
let label = radio.closest('label');
label.style.opacity = '25%';
label.style.cursor = 'not-allowed';
});
});
// 모달열기
document.querySelector('.coordinate p').addEventListener('click', () => {
if(document.getElementById('select-coordi').style.display == 'none'){
document.getElementById('select-coordi').style.display = 'block';
}else{
document.getElementById('select-coordi').style.display = 'none';
}
});
// 모달닫기
document.getElementById('select-coordi-close').addEventListener('click', () => {
document.getElementById('select-coordi').style.display = 'none';
});
let keys = Object.keys(hmCesium.main.model);
let lastKey = keys[keys.length-1];
//모델 설정 후 좌표 바꾸기
if(hmCesium.main.model[lastKey].projection != '4326'){
document.getElementById('gcs2').click();
if(document.getElementById(hmCesium.main.model[lastKey].projection)){
document.getElementById(hmCesium.main.model[lastKey].projection).click();
}else{
document.getElementById('gcs1').click();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** footer (mouseInfo) END ***//////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////vietnam용 bill
async function makeVietnamBill(pLabels){
let labels = (!pLabels)?hmCesium.main.label:pLabels;
let layer = changeLayer('labels', true);
let keys = Object.keys(labels);
for(let i = 0; i < keys.length; i++){
let bill = {
html : ``,
position : [labels[keys[i]][0], labels[keys[i]][1]],
name : keys[i],
path : ` `,
}
await loadBillboardForVietnam(bill, layer);
}
}
async function loadBillboardForVietnam(json, layer) {
const container = document.createElement('div');
container.style.position = 'absolute';
container.style.left = '-9999px';
container.style.top = '-9999px';
container.style.visibility = 'hidden';
container.innerHTML = json.html;
document.body.appendChild(container);
await new Promise(resolve => setTimeout(resolve, 100));
const elementRect = container.getBoundingClientRect();
const width = Math.ceil(elementRect.width) + 12+6;
const height = Math.ceil(elementRect.height) + 20 + 16;
// SVG 데이터를 Base64로 인코딩하여 사용
const svgData = `
${container.innerHTML}
`;
// Base64 인코딩으로 변경
const encodedSvg = btoa(unescape(encodeURIComponent(svgData)));
const dataUrl = `data:image/svg+xml;base64,${encodedSvg}`;
const position = Cesium.Cartesian3.fromDegrees(json.position[0], json.position[1], 0);
// 이미지 로드 확인을 위한 테스트
const testImg = new Image();
testImg.onload = function() {
console.log('SVG 이미지 로드 성공:', width, 'x', height);
const label = layer.entities.add({
position: position,
name: json.name,
billboard: {
image: dataUrl,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
width: width,
height: height,
pixelOffset: new Cesium.Cartesian2(-4, -45),
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 250_000),
show: true // 명시적으로 표시 설정
}
});
const bill = layer.entities.add({
position: position,
name: json.name,
billboard: {
image: `./img/location.svg`,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
show: true
}
});
bill.__label = label;
document.body.removeChild(container);
};
testImg.onerror = function() {
console.error('SVG 이미지 로드 실패');
console.log('SVG 데이터:', svgData);
document.body.removeChild(container);
};
testImg.src = dataUrl;
}
function changeLayer(name, bMake = false){
let viewer = hmCesium.viewer;
let layer = viewer.dataSources.getByName(name);
if(layer.length == 0){
if(bMake){
layer = new Cesium.CustomDataSource(name);
viewer.dataSources.add(layer);
}else{
return undefined;
}
}else{
layer = layer[0];
}
return layer;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////*** modelFollowingArrow ***///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//화살표 만들기
hmCesium.viewer.scene.preRender.addEventListener(()=>{
let tileset = getBiggestTileset(hmCesium);
if(tileset){
if(!checkTilesetInScreen(tileset,hmCesium)){
if(!hmCesium.tilesetArrow){
loadArrowGlb(hmCesium);
// createArrowPrimitive();
}
//카메라 10m앞에 1.7m 아래위치
let arrowPos = hmCesium.viewer.camera.position.clone();
Cesium.Cartesian3.add(arrowPos, Cesium.Cartesian3.multiplyByScalar(hmCesium.viewer.camera.direction, 10, new Cesium.Cartesian3()), arrowPos);
Cesium.Cartesian3.add(arrowPos, Cesium.Cartesian3.multiplyByScalar(hmCesium.viewer.camera.up, -1.7, new Cesium.Cartesian3()), arrowPos);
let target = tileset.boundingSphere.center.clone();
let dir = Cesium.Cartesian3.subtract(target, arrowPos, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(dir,dir);
if(hmCesium.tilesetArrow){
hmCesium.tilesetArrow.modelMatrix = getTransform(arrowPos, dir, 0.6);
}
}else{
if(hmCesium.tilesetArrow){
hmCesium.tilesetArrow.modelMatrix = Cesium.Matrix4.IDENTITY;
}
}
}
});
//타일셋위치 화살표
async function loadArrowGlb(cesium){
cesium.tilesetArrow = await Cesium.Model.fromGltfAsync({
url: `/libs/gsimViewer/img/arrow_unlit_unweld.glb`,
modelMatrix: Cesium.Matrix4.IDENTITY,
})
cesium.viewer.scene.primitives.add(cesium.tilesetArrow);
cesium.tilesetArrow.color = Cesium.Color.RED.withAlpha(0.5);
}
function getBiggestTileset(cesium){
let keys = Object.keys(cesium.projectManager.tileset.main);
let biggest = undefined;
for(let i =0 ; i < keys.length; i++){
if(cesium.projectManager.tileset.main[keys[i]] && cesium.projectManager.tileset.main[keys[i]].show &&!(cesium.projectManager.tileset.main[keys[i]] instanceof Array)){
if(!biggest) biggest = cesium.projectManager.tileset.main[keys[i]];
if(biggest.boundingSphere.radius <= cesium.projectManager.tileset.main[keys[i]].boundingSphere.radius){
biggest = cesium.projectManager.tileset.main[keys[i]];
}
}
}
return biggest;
}
function checkTilesetInScreen(tileset, cesium){
let boundingSphere = tileset.root.boundingSphere;
let cullingVolume = cesium.viewer.camera.frustum.computeCullingVolume(
cesium.viewer.camera.position,
cesium.viewer.camera.direction,
cesium.viewer.camera.up
);
let flagRadius = boundingSphere.radius;
let visibility = cullingVolume.computeVisibility(boundingSphere);
if(visibility >= 0){
let camPosi = cesium.viewer.camera.position.clone();
let distance = Cesium.Cartesian3.distance(camPosi, tileset.boundingSphere.center);
if(distance>= flagRadius * 10){
visibility = -1;
}
}
return visibility != Cesium.Intersect.OUTSIDE;
}
function getTransform(origin, dir, scale){
let up = Cesium.Cartesian3.normalize(origin, new Cesium.Cartesian3());
let right = Cesium.Cartesian3.cross(dir, up, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(right, right);
let newUp = Cesium.Cartesian3.cross(right, dir, new Cesium.Cartesian3());
Cesium.Cartesian3.normalize(newUp, newUp);
// 회전 행렬 생성
let rotation = new Cesium.Matrix3();
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, newUp, rotation);
Cesium.Matrix3.setColumn(rotation, 2, dir, rotation);
// X축 기준으로 90도 회전 행렬 생성 (화살표를 y축기준으로 만들었음)
const angle = Math.PI / 2; // 90도
const xRotation = Cesium.Matrix3.fromRotationX(angle);
// 기존 회전 행렬에 X축 회전 행렬 곱하기
let finalRotation = Cesium.Matrix3.multiply(rotation, xRotation, new Cesium.Matrix3());
//모델은 z도 돌려줘야함
const zRotation = Cesium.Matrix3.fromRotationZ(-angle);
Cesium.Matrix3.multiply(finalRotation, zRotation, finalRotation);
let matrix = Cesium.Matrix4.multiplyByMatrix3(
Cesium.Matrix4.fromTranslation(origin),
finalRotation,
new Cesium.Matrix4()
);
let scaling = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(scale, scale, scale));
Cesium.Matrix4.multiply(matrix, scaling, matrix);
return matrix;
}