4485 lines
193 KiB
JavaScript
4485 lines
193 KiB
JavaScript
// 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 = `<div class="list-title">
|
||
<p>${keys[i].split('__')[0]}</p>
|
||
<h4>${keys[i].split('__')[1]}</h4>
|
||
</div>`;
|
||
|
||
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 = `<label class="checkbox-label layer" style="opacity: 1;">
|
||
<div class="checkbox-label-left">
|
||
<img class="icon visibility-icon" src="./svg/icon-visibility.svg" alt="icon-visibility" />
|
||
<input type="checkbox" name="list-set" id="plate"
|
||
data-icon-visible="./svg/icon-visibility.svg"
|
||
data-icon-invisible="./svg/icon-invisibility.svg" checked/>
|
||
<span class="checkbox-custom-inbox"></span>
|
||
${tilesetKeys[j]}
|
||
</div>
|
||
</label>
|
||
<div style="display:flex; flex-direction:row;">
|
||
<input type="color" class="model-color-picker" value="#ffffff">
|
||
<div class="z-scaleBar-gauge" style="padding:0 2px;">
|
||
<input type="range" min="0" max="1" step="0.01" value="0" class="slider">
|
||
</div>
|
||
</div>`;
|
||
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 = `<label class="checkbox-label layer" style="opacity: 1;">
|
||
<div class="checkbox-label-left">
|
||
<img class="icon visibility-icon" src="./svg/icon-visibility.svg" alt="icon-visibility" />
|
||
<input type="checkbox" name="list-set" id="plate"
|
||
data-icon-visible="./svg/icon-visibility.svg"
|
||
data-icon-invisible="./svg/icon-invisibility.svg" checked/>
|
||
<span class="checkbox-custom-inbox"></span>
|
||
${shpKey[j]}
|
||
</div>
|
||
</label>
|
||
<div style="display:flex; flex-direction:row;">
|
||
</div>`;
|
||
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 = `<label class="checkbox-label layer" style="opacity: 1;">
|
||
<div class="checkbox-label-left">
|
||
<img class="icon visibility-icon" src="./svg/icon-visibility.svg" alt="icon-visibility" />
|
||
<input type="checkbox" name="list-set" id="plate"
|
||
data-icon-visible="./svg/icon-visibility.svg"
|
||
data-icon-invisible="./svg/icon-invisibility.svg" checked/>
|
||
<span class="checkbox-custom-inbox"></span>
|
||
${tilesetKeys[j]}
|
||
</div>
|
||
</label>
|
||
<div style="display:flex; flex-direction:row;">
|
||
<input type="color" class="model-color-picker" value="#ffffff">
|
||
<div class="z-scaleBar-gauge" style="padding:0 2px;">
|
||
<input type="range" min="0" max="1" step="0.01" value="0" class="slider">
|
||
</div>
|
||
</div>`;
|
||
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 = `<label class="checkbox-label layer" style="opacity: 1;">
|
||
<div class="checkbox-label-left">
|
||
<img class="icon visibility-icon" src="./svg/icon-visibility.svg" alt="icon-visibility" />
|
||
<input type="checkbox" name="list-set" id="plate"
|
||
data-icon-visible="./svg/icon-visibility.svg"
|
||
data-icon-invisible="./svg/icon-invisibility.svg" checked/>
|
||
<span class="checkbox-custom-inbox"></span>
|
||
${shpKey[j]}
|
||
</div>
|
||
</label>
|
||
<div style="display:flex; flex-direction:row;">
|
||
</div>`;
|
||
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 = `
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
||
<foreignObject width="100%" height="100%">
|
||
${new XMLSerializer().serializeToString(element)}
|
||
</foreignObject>
|
||
</svg>
|
||
`;
|
||
// 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 += `<div id="road-${road.RoadId}" style="color:${color[idx%5]};">${road.RoadName}</div>`;
|
||
list.innerHTML += `<li id="road-${road.RoadId}" style="color:${color[idx%5]};">
|
||
<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${road.RoadName}</h4>
|
||
</li>`;
|
||
|
||
//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<pathArray.length;i++){
|
||
svg.appendChild(pathArray[i]);
|
||
}
|
||
}
|
||
|
||
// 선형 클리핑 슬라이더 init
|
||
function setRangeBar(roadName){
|
||
document.getElementById('compare-road').innerText = roadName;
|
||
|
||
let data = Object.keys(hmCesium.compareRoadData[roadName]);
|
||
let intData = data.map(Number);
|
||
|
||
let min = intData.reduce((currentMin, value) => 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 = `<div class="slope-circle" style="background-color: #00ffff"></div>측정 경사 1 : ${m_slope.toFixed(2)} </br>
|
||
// <div class="slope-circle" style="background-color: #ff0000"></div>최단 경사 평균 ${(hmCesium.slopeResult.length>0)?('1 : '+calcAvg(hmCesium.slopeResult).toFixed(2)):' - 최단 경사 측정 실패'}`;
|
||
let text = `
|
||
<div class="point-title">
|
||
<div class="point-wrap">
|
||
<p>측정경사</p>
|
||
<h3>1 : ${m_slope.toFixed(2)}</h3>
|
||
</div>
|
||
<div class="point-wrap">
|
||
<p>최단 경사 평균</p>
|
||
<h3 class="type-em-red">${(hmCesium.slopeResult.length>0)?('1 : '+calcAvg(hmCesium.slopeResult).toFixed(2)):' - 최단 경사 측정 실패'}</h3>
|
||
</div>
|
||
</div>
|
||
`;
|
||
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<array.length;i++){
|
||
halfDist += Cesium.Cartesian3.distance(array[i-1], array[i])/2;
|
||
}
|
||
|
||
let idx = 1;
|
||
while(halfDist > 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 = `<div class="point-title">
|
||
<h3>${addComma(entity.attribute.aerial[entity.attribute.aerial.length-1])}m</h3>
|
||
</div>`
|
||
|
||
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 = `<div class="point-title">
|
||
<h3>${addComma(entity.attribute.horizontal[entity.attribute.horizontal.length-1])}m</h3>
|
||
</div>`
|
||
|
||
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 = `<div class="point-title">
|
||
<h3>${addComma(entity.attribute.vertical[entity.attribute.vertical.length-1])}m</h3>
|
||
</div>`
|
||
|
||
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])}도 <br>
|
||
// 경도 : ${addComma(entity.attribute.coordinate[0])}도 <br>
|
||
// 높이 : ${addComma(entity.attribute.coordinate[2])}m
|
||
// `;
|
||
|
||
text = `
|
||
<div class="point-title">
|
||
<div class="point-wrap-fit">
|
||
<p>위도</p>
|
||
<h3>${addComma(entity.attribute.coordinate[1])}°</h3>
|
||
</div>
|
||
<div class="point-wrap-fit">
|
||
<p>경도</p>
|
||
<h3>${addComma(entity.attribute.coordinate[0])}°</h3>
|
||
</div>
|
||
<div class="point-wrap-fit">
|
||
<p>높이</p>
|
||
<h3>${addComma(entity.attribute.coordinate[2])}m</h3>
|
||
</div>
|
||
</div>
|
||
`
|
||
}else{
|
||
// text = `
|
||
// X : ${addComma(entity.attribute.coordinate[0])}m <br>
|
||
// Y : ${addComma(entity.attribute.coordinate[1])}m <br>
|
||
// 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 = `
|
||
<div class="point-title">
|
||
<h6>${epsg} 기준</h6>
|
||
<div class="point-wrap-fit">
|
||
<p>X</p>
|
||
<h3>${addComma(entity.attribute.coordinate[0])}m</h3>
|
||
</div>
|
||
<div class="point-wrap-fit">
|
||
<p>Y</p>
|
||
<h3>${addComma(entity.attribute.coordinate[1])}m</h3>
|
||
</div>
|
||
<div class="point-wrap-fit">
|
||
<p>Z</p>
|
||
<h3>${addComma(entity.attribute.coordinate[2])}m</h3>
|
||
</div>
|
||
</div>
|
||
`
|
||
}
|
||
}
|
||
|
||
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 = `
|
||
<div class="point-title">
|
||
<div class="point-wrap">
|
||
<p>직선거리 합계</p>
|
||
<h3>${addComma(totalAerial)}m</h3>
|
||
</div>
|
||
</div>
|
||
`
|
||
}
|
||
|
||
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 = `
|
||
<div class="point-title">
|
||
<div class="point-wrap">
|
||
<p>수평거리 합계</p>
|
||
<h3>${addComma(totalHorizontal)}m</h3>
|
||
</div>
|
||
</div>
|
||
`
|
||
}
|
||
|
||
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 = `
|
||
<div class="point-title">
|
||
<div class="point-wrap">
|
||
<p>수직거리 합계</p>
|
||
<h3>${addComma(totalVertical)}m</h3>
|
||
</div>
|
||
</div>
|
||
`
|
||
}
|
||
|
||
// 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 <br>
|
||
// 둘레 : ${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(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||
return result;
|
||
}
|
||
|
||
// 측정 라벨 div, 포인트 추가
|
||
function addMeasureLabelDiv(cartesian3, text, pixelPosition, layer){
|
||
let canvas = hmCesium.viewer.canvas.getBoundingClientRect();
|
||
let div = document.createElement('div');
|
||
div.cartesian3 = cartesian3;
|
||
div.innerHTML = text;
|
||
div.style.position = 'absolute';
|
||
div.style.left = canvas.left + pixelPosition.x + 'px';
|
||
div.style.top = canvas.top + pixelPosition.y + 'px';
|
||
div.classList.add('measureLabel');
|
||
document.body.appendChild(div);
|
||
hmCesium.hmUtil.measureLabelDivArr.push(div);
|
||
|
||
let label = layer.entities.add({
|
||
name: "",
|
||
position : cartesian3,
|
||
point: {
|
||
pixelSize: 4,
|
||
color: Cesium.Color.RED,
|
||
outlineColor: Cesium.Color.WHITE,
|
||
outlineWidth: 2,
|
||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||
clampToGround: false,
|
||
},
|
||
div: div
|
||
});
|
||
hmCesium.viewer.scene.requestRender();
|
||
|
||
hmCesium.hmUtil.measureLabelEntityArr.push(label);
|
||
}
|
||
|
||
//dataSource 가져오기
|
||
function getDataSource(pName, bMake) {
|
||
if(!hmCesium.viewer) return;
|
||
|
||
let layer = hmCesium.viewer.dataSources.getByName(pName);
|
||
if(layer.length > 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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.labels[i].text}</h4>`;
|
||
|
||
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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.labels[i].text}</h4>`;
|
||
|
||
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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.labels[i].text}</h4>`;
|
||
|
||
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<hmCesium.labels.length;i++){
|
||
if(hmCesium.labels[i].id == id) return i;
|
||
}
|
||
}
|
||
|
||
//라벨 가져오기 호출
|
||
document.getElementById('label-get-btn').addEventListener('click',()=>{
|
||
//전체 보이고 현재 모델만 안보이게
|
||
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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.labels[i].text}</h4>`;
|
||
|
||
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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.issues[i].text}</h4>`;
|
||
|
||
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 = `<p>${file}</p>
|
||
// <div class="button-div">
|
||
// <img src="/img/icons/issue-file-download.svg">
|
||
// <img src="/img/icons/issue-file-delete.svg">
|
||
// </div>`;
|
||
// 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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.issues[i].text}</h4>`;
|
||
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 = `<img class="icon" src="./svg/icon-label-dot-white.svg" alt="icon-label-dot-white">
|
||
<h4>${hmCesium.issues[i].text}</h4>`;
|
||
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<hmCesium.issues.length;i++){
|
||
if(hmCesium.issues[i].id == id) return i;
|
||
}
|
||
}
|
||
|
||
//이슈 전체삭제
|
||
document.getElementById('issue-delete-btn').addEventListener('click',async ()=>{
|
||
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 = '<img src="./img/progress.gif">';
|
||
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 : `<div class="point" style="text-align: center; pointer-events: all; height: fit-content; background-color: white; border-radius: 4px;">
|
||
<div class="point-title" style=" display: flex; gap: 8px; border: 1px solid #111; padding: 8px 16px 8px 8px; border-radius: 4px; width: max-content; position: relative; box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.2);">
|
||
<h3 style="font-size: 12px; font-weight: 600; line-height: 20px; margin:0;">
|
||
${keys[i]}</h3>
|
||
<div style="position: absolute; bottom: -15px; left: 50%; transform: translateX(-50%); width: 20px; height: 14px; background: black; clip-path: polygon(50% 100%, 0 0, 100% 0); z-index: 0;"></div>
|
||
<div style="position: absolute; bottom: -14px; left: 50%; transform: translateX(-50%); width: 18px; height: 14px; background: white; clip-path: polygon(50% 100%, 0 0, 100% 0); z-index: 1;"></div>
|
||
</div>
|
||
</div>`,
|
||
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 = `
|
||
<svg xmlns="http://www.w3.org/2000/svg"
|
||
width="${width}" height="${height}"
|
||
viewBox="0 0 ${width-12} ${height}"
|
||
style="background: transparent;">
|
||
<foreignObject x="8" y="8" width="${width-16}" height="${height-16}">
|
||
<div xmlns="http://www.w3.org/1999/xhtml"
|
||
style="font-family: Arial, sans-serif;
|
||
width: 100%;
|
||
height: 100%;
|
||
box-sizing: border-box;">
|
||
${container.innerHTML}
|
||
</div>
|
||
</foreignObject>
|
||
</svg>
|
||
`;
|
||
|
||
// 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;
|
||
} |