Skip to content

可视域分析

可视域分析在模型上显示了给定观察点与目标点的可见与不可见状况

引入可视域分析插件的 css 和 js

html
<link
  rel="stylesheet"
  type="text/css"
  href="./SDK/Plugins/ViewshedAnalysis/ViewshedAnalysis.css"
/>
javascript
<script src="./SDK/Plugins/ViewshedAnalysis/ViewshedAnalysis.js"></script>

使用可视域分析

判断鼠标是否点击在模型上;

设置this.viewshed3d.viewerPosition为观察点

this.viewshed3d.setPoseByTargetPoint()设置目标点

javascript
enableAnalysis() {
  //1).初始化可视域分析
  let viewshed3daction = true;
  this.viewshed3ding = false; //用于是否正在绘制可视域分析
  this.viewshed3d; //当前可视域对象
  this.aViewshed3d = []; //保存可视域分析的数组
  //初始化可视域对象
  this.viewshed3d = new LSGlobe.Viewshed3D(this.viewer.scene);
  //将可视域分析对象加入到可是与分析数组中
  this.aViewshed3d.push(this.viewshed3d);
  //2).绘制可视域分析
  //初始化鼠标事件
  let ViewAnalysisHandler = new LSGlobe.ScreenSpaceEventHandler(
    this.viewer.scene.canvas
  );
  ViewAnalysisHandler.setInputAction((movement) => {
    //可视域分析点必须在模型上
    //确保点击在模型上,不在的话结束函数
    let posit = this.viewer.scene.pick(movement.position);
    if (!LSGlobe.defined(posit)) {
      return;
    }
    let cartesian = this.viewer.scene.pickGlobe(movement.position);
    let cartographic = LSGlobe.Cartographic.fromCartesian(cartesian);
    let currentClickLon = LSGlobe.Math.toDegrees(cartographic.longitude);
    let currentClickLat = LSGlobe.Math.toDegrees(cartographic.latitude);

    //判断点是否在模型上函数--另一种方法
    /* let CurrentTileSet = this.#whichTileset(currentClickLon, currentClickLat);
    if (CurrentTileSet.length < 1) {
      return;
    } */

    if (cartesian != undefined && !this.viewshed3ding) {
      this.viewshed3d.viewerPosition = cartesian;
      //初始添加一个点
      this.viewshed3ding = true;
    } else {
      this.viewshed3d.setPoseByTargetPoint(cartesian);
      //点击第二个点绘制结束
      this.viewshed3ding = false;
    }
  }, LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

  ViewAnalysisHandler.setInputAction((movement) => {
    if (viewshed3daction && this.viewshed3ding) {
      let cartesian = this.viewer.scene.pickGlobe(movement.endPosition);
      this.viewshed3d.setPoseByTargetPoint(cartesian);
    }
  }, LSGlobe.ScreenSpaceEventType.MOUSE_MOVE);
}

获取可见与不可见面积比

javascript
const ratio = this.viewshed3d.getVisibleHiddenRatio();

删除所有可视域分析

javascript
clearAnalysis() {
  for (var i = 0; i < this.aViewshed3d.length; i++) {
    try {
      this.aViewshed3d[i].destroy();
    } catch (e) {}
  }
  this.aViewshed3d = [];
  this.viewshed3ding = false;
}

完整代码

javascript
class wish3dEarth {
  viewer = null;
  tileset = null;
  constructor() {
    if (!LSGlobe?.viewer) {
      this.#initEarth();
    } else {
      this.viewer = LSGlobe.viewer;
    }
    //加载模型
    this.#loadModel();
  }
  //初始化地球
  #initEarth() {
    let licenseCode = '';
    let wish3DEarthLicenseUrl = '';
    this.viewer = new LSGlobe.Viewer('lsGlobe', {
      guid: licenseCode,
      licenseUrl: wish3DEarthLicenseUrl,
    });
  }
  //加载模型
  #loadModel() {
    //模型开启阴影
    const url = ''
    try {
      this.tileset = await LSGlobe.LSPageLOD.fromUrl(url, {
        shadows: LSGlobe.ShadowMode.ENABLED,
      });
      this.viewer.scene.pageLODLayers.add(this.tileset);
      let oCenter = this.tileset.tileBoundingSphere.center;
      let cartesian3 = new LSGlobe.Cartesian3(
        oCenter.x,
        oCenter.y,
        oCenter.z
      );
      let cartographic =
        this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
      let lat = LSGlobe.Math.toDegrees(cartographic.latitude);
      let lng = LSGlobe.Math.toDegrees(cartographic.longitude);
      let height = cartographic.height;
      setTimeout(() => {
        this.viewer.camera.flyTo({
          destination: LSGlobe.Cartesian3.fromDegrees(
            lng,
            lat,
            height + 1500
          ),
          duration: 1,
        });
      }, 2000);
      } catch (error) {
        console.log(`Error loading LSPageLOD: ${error}`)
    }
  }
}
class viewShedAnalysis extends wish3dEarth {
  constructor() {
    super();
  }
  //启用可视域分析
  enableAnalysis() {
    //1).初始化可视域分析
    let viewshed3daction = true;
    this.viewshed3ding = false; //用于是否正在绘制可视域分析
    this.viewshed3d; //当前可视域对象
    this.aViewshed3d = []; //保存可视域分析的数组
    //初始化可视域对象
    this.viewshed3d = new LSGlobe.Viewshed3D(this.viewer.scene);
    //将可视域分析对象加入到可是与分析数组中
    this.aViewshed3d.push(this.viewshed3d);
    //2).绘制可视域分析
    //初始化鼠标事件
    let ViewAnalysisHandler = new LSGlobe.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    );

    ViewAnalysisHandler.setInputAction((movement) => {
      //可视域分析点必须在模型上
      //确保点击在模型上,不在的话结束函数
      let posit = this.viewer.scene.pick(movement.position);
      if (!LSGlobe.defined(posit)) {
        return;
      }
      let cartesian = this.viewer.scene.pickGlobe(movement.position);
      let cartographic = LSGlobe.Cartographic.fromCartesian(cartesian);
      let currentClickLon = LSGlobe.Math.toDegrees(cartographic.longitude);
      let currentClickLat = LSGlobe.Math.toDegrees(cartographic.latitude);

      //判断点是否在模型上函数--另一种方法
      /* let CurrentTileSet = this.#whichTileset(currentClickLon, currentClickLat);
        if (CurrentTileSet.length < 1) {
          return;
        } */

      if (cartesian != undefined && !this.viewshed3ding) {
        this.viewshed3d.viewerPosition = cartesian;
        //初始添加一个点
        this.viewshed3ding = true;
      } else {
        this.viewshed3d.setPoseByTargetPoint(cartesian);
        //点击第二个点绘制结束
        this.viewshed3ding = false;
      }
    }, LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

    ViewAnalysisHandler.setInputAction((movement) => {
      if (viewshed3daction && this.viewshed3ding) {
        let cartesian = this.viewer.scene.pickGlobe(movement.endPosition);
        this.viewshed3d.setPoseByTargetPoint(cartesian);
      }
    }, LSGlobe.ScreenSpaceEventType.MOUSE_MOVE);
  }
  //清除所有可视域分析
  clearAnalysis() {
    for (var i = 0; i < this.aViewshed3d.length; i++) {
      try {
        this.aViewshed3d[i].destroy();
      } catch (e) {}
    }
    this.aViewshed3d = [];
    this.viewshed3ding = false;
  }
  //获取可见与不可见面积比
  caculateRatio() {
    const ratio = this.viewshed3d.getVisibleHiddenRatio();
    alert(`可见与不可见面积比:${ratio}`);
  }
  //获取两个经纬度之间的距离函数
  #getDistance(position, x, y) {
    let radLatA = position.y * 0.0174532925199432957692369077;
    let radLatB = y * 0.0174532925199432957692369077;
    let radLonA = position.x * 0.0174532925199432957692369077;
    let radLonB = x * 0.0174532925199432957692369077;
    return (
      Math.acos(
        Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB) +
          Math.sin(radLatA) * Math.sin(radLatB)
      ) * 6378137
    );
  }
  //获取当前压平的模型对象函数
  #whichTileset(x, y) {
    let returnValue = [];
    for (let i = 0; i < this.viewer.scene.pageLODLayers._pageLODs.length; i++) {
      let aTileSet = this.viewer.scene.pageLODLayers._pageLODs[i];
      let oCenter = aTileSet.tileBoundingSphere.center;
      let ellipsoid = this.viewer.scene.globe.ellipsoid;
      let cartesian3 = new LSGlobe.Cartesian3(oCenter.x, oCenter.y, oCenter.z);
      let cartographic = ellipsoid.cartesianToCartographic(cartesian3);
      //ellipsoid表示球对象
      let lat = LSGlobe.Math.toDegrees(cartographic.latitude);
      let lng = LSGlobe.Math.toDegrees(cartographic.longitude);
      let position = {
        x: lng,
        y: lat,
        z: cartographic.height,
      };
      let distance = this.#getDistance(position, x, y);
      if (distance < aTileSet.tileBoundingSphere.radius) {
        returnValue.push(aTileSet);
      }
    }
    return returnValue;
  }
}
let analysis = new viewShedAnalysis();
analysis.enableAnalysis();
//清除分析
//analysis.clearAnalysis()
//计算面积比
//analysis.caculateRatio()

示例代码 code

code示例地址

Released under the MIT License.