<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel='stylesheet'/>
<script src='http://ua.bigemap.com:30081/bmsdk/bigemap-gl.js/v1.1.0/bigemap-gl.js'></script>
<title>可視域</title>
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
html, body, #map {
width: 100%;
height: 100%;
}
#start {
position: absolute;
left: 50px;
top: 50px;
z-index: 9999;
}
#step {
position: absolute;
left:120px;
top: 50px;
z-index: 9999;
}
.info{
position: fixed;
top:0;
color: #8a6d3b;
z-index: 99;
margin: 0;
background-color: #fcf8e3;
border-color: #faebcc;
left: 0;
right: 0;
text-align: center;
}
</style>
<body>
<div id="map"></div>
<div class="info">
先點擊開始,然后再次單擊地圖,即可實現可視域分析功能
</div>
<button id="start">
開始
</button>
<button id="step">
進度
</button>
</body>
</html>
<script type="text/javascript">
bmgl.Config.HTTP_URL = 'http://ua.bigemap.com:30081/bmsdk/';
var viewer = new bmgl.Viewer('map', {
terrainId: 'bigemap.dc-terrain',
requestRenderMode:false,
mapId: 'bigemap.dc-tian-w-satellite'
});
var config = initConfig();
function initConfig() {
let base = {
lng: 86,
lat: 28,
sum: 50,
start: 0,
done: 0,
height: 5,
loaded: 0,
delta: 100,
all_seen: 0,
width: 5000,
click: 0,
draw: false,
calc_width: [],
edge: [],
min: [],
inner: [],
};
return base;
// return JSON.parse(JSON.stringify(base));
}
// viewer.entities.add({
// position:bmgl.Cartesian3.fromDegrees(config.lng,config.lat),
// label:{
// text:'C',
// heightReference:bmgl.HeightReference.CLAMP_TO_GROUND,
// }
// });
viewer.scene.globe.depthTestAgainstTerrain = true;
//獲取最新的位置
viewer.camera.setView({
destination: bmgl.Cartesian3.fromDegrees(103.59526245619938,30.9814012061604,3837.4144546),
orientation: {"heading":6.282150327905171,"roll":6.279635689524259,"pitch":-0.6993902253931052}
});
function startDraw() {
// var pp=bmgl.Transforms.eastNorthUpToFixedFrame(bmgl.Cartesian3.fromDegrees(config.lng,config.lat));
document.getElementById('step').innerHTML='0/'+config.sum;
for (let i = 0; i < config.sum; i++) {
var tmp_edge = [];
var tmp_inner = [];
for (let j = 0; j < config.sum; j++) {
var center = bmgl.Cartesian3.fromDegrees(config.lng, config.lat);
var heading = bmgl.Math.PI * 2 * j / config.sum;
var hpr = new bmgl.HeadingPitchRoll(heading, 0.0, 0);
var transform = bmgl.Transforms.headingPitchRollToFixedFrame(center, hpr);
var p = bmgl.Matrix4.multiplyByPoint(transform, new bmgl.Cartesian3(config.width * Math.cos(bmgl.Math.toRadians(90 * i / config.sum)), 0, config.width * Math.sin(bmgl.Math.toRadians(90 * i / config.sum))), new bmgl.Cartesian3());
// var p2=bmgl.Matrix4.multiplyByPoint(transform,new bmgl.Cartesian3(config.width*Math.cos(bmgl.Math.toRadians(90*i/config.sum)),0,0),new bmgl.Cartesian3());
// viewer.entities.add({
// position:p2,
// label:{
// heightReference:bmgl.HeightReference.CLAMP_TO_GROUND,
// text:'b',
// font:'14px arial',
// }
// });
// tmp_inner.push({p:p2});
tmp_edge.push({p, height: config.width * Math.sin(bmgl.Math.toRadians(90 * i / config.sum))});
}
// config.calc_width.push(config.width * Math.cos(bmgl.Math.toRadians(90 * i / config.sum)));
tmp_edge.push(tmp_edge[0]);
config.edge.push(tmp_edge);
// config.inner.push(tmp_inner);
// viewer.entities.add({
// polyline:{
// width:new bmgl.ConstantProperty(2),
// material:bmgl.Color.BLUE,
// // clampToGround:true,
// positions:tmp_edge.map(v=>v.p)
// }
// });
}
console.log(config);
calcShow();
}
// viewer.flyTo(viewer.entities);
let handler = new bmgl.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(function (e) {
if (!config.draw) return;
if (config.click === 0) {
viewer.entities.removeAll();
}
let ray = viewer.camera.getPickRay(e.position);
if (!ray) return;
let cartesian3 = viewer.scene.globe.pick(ray, viewer.scene);
config.click++;
let p = bmgl.Cartographic.fromCartesian(cartesian3);
switch (config.click) {
case 1:
viewer.entities.add({
position: cartesian3,
label: {
text: 'Start',
verticalOrigin:bmgl.VerticalOrigin.BOTTOM,
heightReference: bmgl.HeightReference.CLAMP_TO_GROUND,
}
});
config.lng = bmgl.Math.toDegrees(p.longitude);
config.lat = bmgl.Math.toDegrees(p.latitude);
config.mouse={lng:config.lng,lat:config.lat};
config.tmp_label=viewer.entities.add({
position:new bmgl.CallbackProperty(function (){
return bmgl.Cartesian3.fromDegrees(config.mouse.lng,config.mouse.lat);
}),
label:{
text:'',
verticalOrigin:bmgl.VerticalOrigin.BOTTOM,
heightReference:bmgl.HeightReference.CLAMP_TO_GROUND,
font:'16px arial',
}
});
config.tmp_line=viewer.entities.add({
polyline:{
positions:new bmgl.CallbackProperty(function (){
return bmgl.Cartesian3.fromDegreesArray([config.lng,config.lat,config.mouse.lng,config.mouse.lat]);
}),
clampToGround:true,
material:bmgl.Color.RED.withAlpha(0.8),
}
});
config.tmp_line2=viewer.entities.add({
polyline:{
positions:new bmgl.CallbackProperty(function (){
let p=[];
let dd=bmgl.Cartesian3.distance(bmgl.Cartesian3.fromDegrees(config.lng,config.lat),bmgl.Cartesian3.fromDegrees(config.mouse.lng,config.mouse.lat)).toFixed(2);
for (let i=0;i<40;i++){
var center = bmgl.Cartesian3.fromDegrees(config.lng, config.lat);
var heading = bmgl.Math.PI * 2 * i / 40;
var hpr = new bmgl.HeadingPitchRoll(heading, 0.0, 0);
var transform = bmgl.Transforms.headingPitchRollToFixedFrame(center, hpr);
var p1 = bmgl.Matrix4.multiplyByPoint(transform, new bmgl.Cartesian3(dd, 0, 0), new bmgl.Cartesian3());
p.push(p1);
}
p.push(p[0]);
return p;
}),
clampToGround:true,
material:bmgl.Color.RED.withAlpha(0.8),
}
});
break;
case 2:
let dd = bmgl.Cartesian3.distance(bmgl.Cartesian3.fromDegrees(config.lng, config.lat), cartesian3);
// console.log(dd);
config.width = dd;
viewer.entities.add({
position: cartesian3,
label: {
text: 'End',
verticalOrigin:bmgl.VerticalOrigin.BOTTOM,
heightReference: bmgl.HeightReference.CLAMP_TO_GROUND,
}
});
break;
}
if (config.click > 1) {
//說明已經點擊了兩次,繪制完成了
viewer.entities.remove(config.tmp_label);
viewer.entities.remove(config.tmp_line);
viewer.entities.remove(config.tmp_line2);
startDraw();
config.draw = false;
config.click = 0;
}
}, bmgl.ScreenSpaceEventType.LEFT_CLICK);
handler.setInputAction(function (e){
if (!config.draw) return;
if (config.click===1){
let ray=viewer.camera.getPickRay(e.endPosition);
if (!ray) return;
let pp=viewer.scene.globe.pick(ray,viewer.scene);
pp=bmgl.Cartographic.fromCartesian(pp);
config.mouse={
lng:bmgl.Math.toDegrees(pp.longitude),
lat:bmgl.Math.toDegrees(pp.latitude)
}
config.tmp_label.label.text=bmgl.Cartesian3.distance(bmgl.Cartesian3.fromDegrees(config.lng,config.lat),bmgl.Cartesian3.fromDegrees(config.mouse.lng,config.mouse.lat)).toFixed(2)+'米';
}
},bmgl.ScreenSpaceEventType.MOUSE_MOVE);
document.getElementById('start').addEventListener('click', function () {
config = initConfig();
config.draw = true;
//config=initConfig();
});
function calcShow() {
if (!config.edge[config.start]) {
console.log('all over');
document.getElementById('step').innerHTML=config.sum+'/'+config.sum;
return;
}
config.edge[config.start].map((v, ii) => {
var end = bmgl.Cartographic.fromCartesian(v.p);
end.lng = bmgl.Math.toDegrees(end.longitude);
end.lat = bmgl.Math.toDegrees(end.latitude);
let p = [];
for (let j = 0; j < config.delta; j++) {
let tp = {
lng: config.lng + (end.lng - config.lng) * j / config.delta,
lat: config.lat + (end.lat - config.lat) * j / config.delta
};
// debugger;
// if (config.start===6){
// viewer.entities.add({
// position:bmgl.Cartesian3.fromDegrees(tp.lng,tp.lat),
// label:{
// text:'k'+j,
// heightReference:bmgl.HeightReference.CLAMP_TO_GROUND,
// }
// });
// }
p.push(bmgl.Cartographic.fromCartesian(bmgl.Cartesian3.fromDegrees(tp.lng, tp.lat)));
}
let hh = v.height;
getTerrain(p, ii, (ter, iii) => {
// debugger;
ter[ter.length - 1]['height'] = hh;
config.loaded++;
let result = showVisible(ter);
config.edge[config.start][iii]['v'] = result[result.length - 1];
// viewer.entities.add({
// position: config.edge[config.start][iii]['p'],
// label: {
// text: result[result.length - 1] ? '1' : '0',
// heightReference: bmgl.HeightReference.CLAMP_TO_GROUND,
// }
// });
// var a = bmgl.Cartographic.fromCartesian(config.edge[config.start][iii]['p']);
// viewer.entities.add({
// position: bmgl.Cartesian3.fromDegrees(bmgl.Math.toDegrees(a.longitude), bmgl.Math.toDegrees(a.latitude), hh),
// label: {
// fillColor: config.edge[config.start][iii]['v'] ? bmgl.Color.BLUE : bmgl.Color.RED,
// text: 'X',
// }
// });
if (config.loaded === config.edge[config.start].length) {
//本次圓內已經計算完了
let ttt = [];
config.edge[config.start].map(v1 => {
ttt.push(v1.v);
});
console.log('index: ' + config.start);
document.getElementById('step').innerHTML=config.start+'/'+config.sum;
let all_seen = Array.from(new Set(ttt));
if (all_seen[0] && all_seen.length === 1) {
config.all_seen = config.start;
document.getElementById('step').innerHTML=config.sum+'/'+config.sum;
for (let j=config.start;j<config.edge.length;j++){
drawLine(config.edge[j].map(v=>{
v.v=true;
return v;
}));
}
//第二次繪畫
for (let i=0;i<config.sum;i++){
let tmp=[];
for (let j=0;j<config.sum;j++){
tmp.push(config.edge[j][i]);
}
tmp.push({v:true,p:bmgl.Cartesian3.fromDegrees(config.lng,config.lat,config.width)});
drawLine(tmp);
// console.log(tmp);
}
return;
}
drawLine(config.edge[config.start]);
config.loaded = 0;
config.start++;
calcShow();
}
});
// viewer.entities.add({
// position:v.p,
// label:{
// text:'c',
// heightReference:bmgl.HeightReference.CLAMP_TO_GROUND,
// }
// })
});
}
function drawLine(data) {
// console.log(data);
let path = [];
let tmp = [data[0]];
let prev = data[0]['v'];
for (let j = 1; j < data.length; j++) {
let v = data[j];
tmp.push(v);
if (prev !== v.v) {
if (tmp.length > 1) {
let m;
if (prev) {
m = bmgl.Color.BLUE;
} else {
m = bmgl.Color.RED;
}
console.log('tmp index length : ' + tmp.length);
viewer.entities.add({
polyline: {
material: m,
positions: tmp.map(v => v.p),
}
});
// path.push({v:start,path:[...JSON.parse(JSON.stringify(tmp))]});
tmp.length = 0;
tmp.push(v);
}
prev = v.v;
}
}
if (tmp.length > 1) {
let m;
if (prev) {
m = bmgl.Color.BLUE;
} else {
m = bmgl.Color.RED;
}
console.log('tmp index' + tmp.length);
viewer.entities.add({
polyline: {
material: m,
positions: tmp.map(v => v.p),
}
});
}
console.log(path);
}
function getTerrain(position, i, callback) {
// bmgl.sampleTerrain(viewer.terrainProvider,8,position).then(data=>{
// try {
// if (data.length > 0) callback(data, i);
// } catch (e) {
// console.log(e);
// }
// });
bmgl.sampleTerrainMostDetailed(viewer.terrainProvider, position).then(data => {
try {
if (data.length > 0) callback(data, i);
} catch (e) {
console.log(e);
}
})
}
function showVisible(terrainData) {
var preVisible = true;
var cartesiansLine = [];
var colors = [true];
for (var j = 1; j < terrainData.length; j++) {
//逐點計算可見性
var visible = true;//該點可見性
if (j > 1) {
var cartographicCenterHV = new bmgl.Cartographic(terrainData[0].longitude, terrainData[0].latitude, terrainData[0].height + config.height);
if (preVisible) {
var curPoint = InterpolateIndexLineHeightCartographic(cartographicCenterHV, terrainData[j], j, j - 1);
if (curPoint.height >= terrainData[j - 1].height) {
preVisible = true;
visible = true;
} else {
preVisible = false;
visible = false;
}
} else {
//插值到當前
var curPointArr = Interpolate2IndexLineHeightCartographic(cartographicCenterHV, terrainData[j], j, j - 1);
for (var k = 0; k < curPointArr.length; k++) {
if (curPointArr[k].height >= terrainData[k].height) {
preVisible = true;
visible = true;
} else {
preVisible = false;
visible = false;
break;
}
}
}
}
// var cartesianTemp = bmgl.Cartesian3.fromRadians(terrainData[j].longitude, terrainData[j].latitude, terrainData[j].height + 0.10);
// cartesiansLine.push(cartesianTemp);
//繪制點
colors.push(visible);
}
return colors;
}
function Interpolate2IndexLineHeightCartographic(start, end, num, curIndex) {
if (start && end) {
} else {
return null;
}
if (start.longitude && start.latitude && end.longitude && end.latitude) {
} else {
return null;
}
var result = [];
result.push(new bmgl.Cartographic(start.longitude, start.latitude, start.height));
var stepLon = (end.longitude - start.longitude) / num;
var stepLat = (end.latitude - start.latitude) / num;
var stepHeight = (end.height - start.height) / num;
for (var i = 0; i < curIndex; i++) {
var lon = start.longitude + (i + 1) * stepLon;
var lat = start.latitude + (i + 1) * stepLat;
var hieght = start.height + (i + 1) * stepHeight;
result.push(new bmgl.Cartographic(lon, lat, hieght));
}
return result;
}
function InterpolateIndexLineHeightCartographic(start, end, num, index) {
if (start && end) {
} else {
return null;
}
if (start.longitude && start.latitude && end.longitude && end.latitude) {
} else {
return null;
}
//var delta = _Delta && (typeof _Delta === 'number') ? _Delta : DeltaRadian;
var stepLon = (end.longitude - start.longitude) / num;
var stepLat = (end.latitude - start.latitude) / num;
var stepHeight = (end.height - start.height) / num;
var lon = start.longitude + index * stepLon;
var lat = start.latitude + index * stepLat;
var hieght = start.height + index * stepHeight;
var result = new bmgl.Cartographic(lon, lat, hieght);
return result;
}
</script>