Skip to content

坡度分析

坡度分析是通过创建色彩渐变,使地形的坡度以色彩渐变的形式展示出来

地形加载

requestVertexNormals 设置为 true 时会计算法线,用于坡度坡向

Javascript
async loadTerrain() {
  let terrainPath = '';
  try{
    //构建地形数据,参数requestVertexNormals为true时会计算法线,用于坡度坡向
    let terrainLayer = await LSGlobe.LSTerrainProvider.fromUrl(terrainPath, {
      requestVertexNormals: true,
    });
    this.viewer.terrainLayers.addTerrainProvider(terrainLayer);
    //单个地形时
    let rect = terrainLayer.rectangle; //地形范围
    this.viewer.scene.globe.materialRectangle = rect; //设置坡度坡向分析的范围

    //有多个地形时,合并多个地形
    /*
    let rect = this.viewer.terrainLayers.get(0).rectangle;
    for (let i = 0; i < this.viewer.terrainLayers.length; i++) {
      this.viewer.terrainLayers.get(i)._requestVertexNormals = true;
      LSGlobe.Rectangle.union(rect, this.viewer.terrainLayers.get(i).rectangle, rect);
    }
    */
      this.#flyToRectBoundingSphere(rect);
  } catch (error) {
      console.log(`Error loading terrain: ${error}`);
  }
}

创建色带

创建一个 canvas 容器,填充渐变色

javascript
getColorRamp() {
  let ramp = document.createElement('canvas');
  ramp.width = 100;
  ramp.height = 1;
  let ctx = ramp.getContext('2d');
  let values;
  let colors;
  values = slopeAnalysis.colorLegends.map(
    (item) => Math.floor((item.value / 90) * 100) / 100
  );
  colors = slopeAnalysis.colorLegends.map((item) => item.color);
  var grd = ctx.createLinearGradient(0, 0, 100, 1);
  values?.forEach((item, i) => {
    grd.addColorStop(values[i], colors[i]);
  });
  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, 100, 1);
  return ramp;
}

启用坡度分析

javascript
enableAnalysis() {
  //创建材质
  let material = LSGlobe.Material.fromType('SlopeRamp');
  // 采用临近采样 ***
  material._minificationFilter = LSGlobe.TextureMinificationFilter.NEAREST;
  material._magnificationFilter = LSGlobe.TextureMinificationFilter.NEAREST;
  //加载色带
  let shadingUniforms = material.uniforms;
  shadingUniforms.image = this.#getColorRamp();
  let globe = this.viewer.scene.globe;
  //启用灯光
  globe.enableLighting = true;
  //应用材质
  globe.material = material;
}

完整代码

Javascript
class wish3dEarth {
  viewer = null;
  constructor() {
    if (!LSGlobe?.viewer) {
      this.#initEarth();
    } else {
      this.viewer = LSGlobe.viewer;
    }
    //加载地形
    this.#loadTerrain();
  }
  //初始化地球
  #initEarth() {
    let licenseCode = '';
    let wish3DEarthLicenseUrl = '';
    this.viewer = new LSGlobe.Viewer('lsGlobe', {
      guid: licenseCode,
      licenseUrl: wish3DEarthLicenseUrl,
    });
  }
  //加载地形
  #loadTerrain() {
    let terrainPath = '';
    try{
      //构建地形数据,参数requestVertexNormals为true时会计算法线,用于坡度坡向
      let terrainLayer = await LSGlobe.LSTerrainProvider.fromUrl(terrainPath, {
        requestVertexNormals: true,
      });
      this.viewer.terrainLayers.addTerrainProvider(terrainLayer);
      //单个地形时
      let rect = terrainLayer.rectangle; //地形范围
      this.viewer.scene.globe.materialRectangle = rect; //设置坡度坡向分析的范围

      //有多个地形时,合并多个地形
      /*
      let rect = this.viewer.terrainLayers.get(0).rectangle;
      for (let i = 0; i < this.viewer.terrainLayers.length; i++) {
        this.viewer.terrainLayers.get(i)._requestVertexNormals = true;
        LSGlobe.Rectangle.union(rect, this.viewer.terrainLayers.get(i).rectangle, rect);
      }
      */
        this.#flyToRectBoundingSphere(rect);
    } catch (error) {
      console.log(`Error loading terrain: ${error}`);
    }
  }
  //飞行至rectangle
  #flyToRectBoundingSphere(rect) {
    let boundingSphere = LSGlobe.BoundingSphere.fromRectangle3D(rect);
    const heading = LSGlobe.Math.toRadians(30.0);
    const pitch = LSGlobe.Math.toRadians(-30.0);
    const range = 1.4e4;
    this.viewer.camera.flyToBoundingSphere(boundingSphere, {
      offset: new LSGlobe.HeadingPitchRange(heading, pitch, range),
      maximumHeight: 2e6,
      pitchAdjustHeight: 2e6,
      duration: 4,
      complete: this.showPanel,
    });
  }
}
class slopeAnalysis extends wish3dEarth {
  //色带分级
  static colorLegends = [
    {
      value: 0,
      color: '#ffffff00',
      show: false,
    },
    {
      value: 3, // todo 由于LSGlobe-2.0.0.612引擎是根据法线计算的值,精度不是很准确存在全球着色的问题,所以我们将3度以下的设置为透明的颜色(引擎的测试代码是设置效果限制范围:viewer.scene.globe.materialRectangle = rect)
      color: '#95f20445',
      show: false,
    },
    {
      value: 15,
      color: '#caf98245',
    },
    {
      value: 30,
      color: '#ffff8045',
    },
    {
      value: 45,
      color: '#ffff0045',
    },
    {
      value: 60,
      color: '#facd9145',
    },
    {
      value: 75,
      color: '#f59a2345',
    },
    {
      value: 90,
      color: '#ec808d45',
    },
  ];
  constructor() {
    super();
  }
  //启用分析
  enableAnalysis() {
    let material = LSGlobe.Material.fromType('SlopeRamp');
    // 采用临近采样 ***
    material._minificationFilter = LSGlobe.TextureMinificationFilter.NEAREST;
    material._magnificationFilter = LSGlobe.TextureMinificationFilter.NEAREST;
    let shadingUniforms = material.uniforms;
    shadingUniforms.image = this.#getColorRamp();
    let globe = this.viewer.scene.globe;
    globe.enableLighting = true;
    globe.material = material;
  }
  //清除分析
  clearAnalysis() {
    this.viewer.scene.globe.enableLighting = false;
    try {
      if (this.viewer.scene.globe.material !== undefined) {
        this.viewer.scene.globe.material = undefined;
      }
    } catch (error) {
      console.error(error);
    }
  }
  //生成色带
  #getColorRamp() {
    let ramp = document.createElement('canvas');
    ramp.width = 100;
    ramp.height = 1;
    let ctx = ramp.getContext('2d');
    let values;
    let colors;
    values = slopeAnalysis.colorLegends.map(
      (item) => Math.floor((item.value / 90) * 100) / 100
    );
    colors = slopeAnalysis.colorLegends.map((item) => item.color);
    var grd = ctx.createLinearGradient(0, 0, 100, 1);
    values?.forEach((item, i) => {
      grd.addColorStop(values[i], colors[i]);
    });
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 100, 1);
    return ramp;
  }
}
let analysis = new slopeAnalysis();
analysis.enableAnalysis();
//删除分析
//analysis.clearAnalysis()

示例代码 code

code示例地址

Released under the MIT License.