1. 引言

Mars3D是基于Cesium的Web端的三维GIS库,对Cesium做了进一步封装和扩展

Mars3D官网:Mars3D三维可视化平台 | 火星科技

Mars3D开发手册:开发教程 - Mars3D三维可视化平台 | 火星科技

GitHub地址:Mars3D三维可视化平台 | 火星科技

API文档:API文档 - Mars3D三维可视化平台 | 火星科技

2. 示例

以下是一些基于原生JavaScript的使用案例

2.1 创建三维场景

2.1.1 快速创建地球

即new一个Map,可选的设置参数有:

  • 场景scene
  • 控件control
  • 特效effect
  • ......

具体可参考:API文档 - Mars3D三维可视化平台 | 火星科技

这里仅设置部分底图参数:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link
      href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js"
      type="text/javascript"
    ></script>
    <!--引入mars3d库lib-->
    <link
      href="https://unpkg.com/mars3d/dist/mars3d.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d/dist/mars3d.js"
      type="text/javascript"
    ></script>

    <style>
      html,
      body,
      .mars3d-container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script type="text/javascript">
      let mapOptions = {
        basemaps: [{ name: "高德", type: "gaode", layer: "img_d", show: true }],
      };
      let map = new mars3d.Map("mars3dContainer", mapOptions);
    </script>
  </body>
</html>

image-20230202190434020

2.1.2 根据配置创建

通过配置文件创建地图,配置项与上述的快速创建的配置项相同

config.json文件(和上面的配置一样):

[
    {
        "name": "高德",
        "type": "gaode",
        "layer": "img_d",
        "show": true
    }
]

加载代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link
      href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js"
      type="text/javascript"
    ></script>
    <!--引入mars3d库lib-->
    <link
      href="https://unpkg.com/mars3d/dist/mars3d.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d/dist/mars3d.js"
      type="text/javascript"
    ></script>

    <style>
      html,
      body,
      .mars3d-container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script type="text/javascript">
      fetch("./config/config.json")
        .then((res) => res.json())
        .then((config) => {
          let mapOptions = config.mars3d
          let map = new mars3d.Map("mars3dContainer", mapOptions)
        });
    </script>
  </body>
</html>

2.1.3 根据Cesium创建

先使用Cesium创建一个地球(Viewer),再构造为Mars3d的Map对象:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link
      href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js"
      type="text/javascript"
    ></script>
    <!--引入mars3d库lib-->
    <link
      href="https://unpkg.com/mars3d/dist/mars3d.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d/dist/mars3d.js"
      type="text/javascript"
    ></script>

    <style>
      html,
      body,
      .mars3d-container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script type="text/javascript">
      const viewer = new Cesium.Viewer("mars3dContainer");
      let mapOptions = {
        scene: {
          center: {
            lat: 30.054604,
            lng: 108.885436,
            alt: 17036414,
            heading: 0,
            pitch: -90,
          },
          fxaa: true,
        },
      };
      const map = new mars3d.Map(viewer, mapOptions);
    </script>
  </body>
</html>

image-20230202194917964

2.2 UI控件样板

在主页面设置UI控件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link
      href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js"
      type="text/javascript"
    ></script>
    <!--引入mars3d库lib-->
    <link
      href="https://unpkg.com/mars3d/dist/mars3d.css"
      rel="stylesheet"
      type="text/css"
    />
    <script
      src="https://unpkg.com/mars3d/dist/mars3d.js"
      type="text/javascript"
    ></script>

    <style>
      html,
      body,
      .mars3d-container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
      .infoview {
        position: absolute;
        top: 10px;
        right: 10px;
        padding: 10px 15px;
        border-radius: 4px;
        border: 1px solid rgba(128, 128, 128, 0.5);
        color: #ffffff;
        background: rgba(0, 0, 0, 0.4);
        box-shadow: 0 3px 14px rgb(128 128 128 / 50%);
        z-index: 19870101;
      }
    </style>
  </head>

  <body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <div class="infoview" style="overflow: auto; max-height: 850px">
      <table class="mars-table">
        <tbody>
          <tr>
            <td>简单文本:</td>
            <td>
              <input
                id="txtUrl"
                type="text"
                value=""
                required
                class="form-control"
                placeholder="请输入"
              />
            </td>
          </tr>

          <tr>
            <td>下拉框:</td>
            <td>
              <select id="txtCrs" class="selectpicker form-control">
                <option value="" selected="selected">默认</option>
                <option value="EPSG:3857">火星</option>
                <option value="EPSG:4326">地球</option>
                <option value="EPSG:4490">太阳</option>
              </select>
            </td>
          </tr>

          <tr>
            <td class="nametd">日期:</td>
            <td>
              <input
                type="text"
                class="form-control"
                id="txtStartTime"
                placeholder="YYYY-MM-DD"
              />
            </td>
          </tr>

          <tr>
            <td>滑动条:</td>
            <td class="slider">
              <input
                id="slider_brightness"
                type="text"
                data-slider-min="-0.5"
                data-slider-max="1.5"
                data-slider-step="0.01"
                data-slider-value="-0.5"
              />
            </td>
          </tr>

          <tr>
            <td>刻度滑动条:</td>
            <td class="slider">
              <input id="slider_showLevel" type="text" />
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    
    <script type="text/javascript">
      let mapOptions = {
        basemaps: [{ name: "高德", type: "gaode", layer: "img_d", show: true }],
      };
      const map = new mars3d.Map("mars3dContainer", mapOptions);
    </script>
  </body>
</html>

image-20230202204233014

2.3 设置地图参数

2.3.1 设置场景参数

在地图创建时可以直接设置一些参数,比如场景、底图等,在地图创建好以后,也可以直接设置这些参数,使用类似于map.setSceneOptions(options)等API

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{ name: "高德", type: "gaode", layer: "img_d", show: true }],
        };
        const map = new mars3d.Map("mars3dContainer", mapOptions);
        map.setSceneOptions({
            center: { lat: 26.8764, lng: 91.148781, alt: 223798, heading: 0, pitch: -45 }
        })
    </script>
</body>

</html>

image-20230203103433558

2.3.2 设置三维地形

三维地形可以在Map创建时设置terrain参数来加,也可以在地图创建后加载

在创建地球后更新terrainProvider(用 mars3d.layer.createTerrainProvider工厂方法创建)[目前1个球只支持1个地形服务]

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{ name: "高德", type: "gaode", layer: "img_d", show: true }],
        };
        const map = new mars3d.Map("mars3dContainer", mapOptions);
        map.setSceneOptions({
            center: { lat: 26.8764, lng: 91.148781, alt: 223798, heading: 0, pitch: -45 }
        })
        map.terrainProvider = mars3d.LayerUtil.createTerrainProvider({
          url: "http://data.mars3d.cn/terrain"
        })
    </script>
</body>

</html>

image-20230203104723141

2.3.3 设置底图

底图(basemap)可以在加载时设置,也可以在底图创建好后加载

加载底图时建议开启底图切换控件(baseLayerPicker),从而实现底图切换

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德", 
                icon: "./icon/offline.png",
                type: "gaode", 
                layer: "img_d", 
                show: true
            }, {
                name: "XYZ地图",
                icon: "./icon/mapboxSatellite.png",
                type: "xyz",
                url: "//data.mars3d.cn/tile/googleImg/{z}/{x}/{y}.jpg",
                maximumLevel: 12
            }],
            control: {
                baseLayerPicker: true, // basemaps底图切换按钮
                homeButton: true, // 视角复位按钮
                sceneModePicker: true, // 二三维切换按钮
                navigationHelpButton: true, // 帮助按钮
                fullscreenButton: true, // 全屏按钮
                contextmenu: { hasDefault: true } // 右键菜单
            }
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.setSceneOptions({
            center: { lat: 26.8764, lng: 91.148781, alt: 223798, heading: 0, pitch: -45 }
        })
        map.terrainProvider = mars3d.LayerUtil.createTerrainProvider({
            url: "http://data.mars3d.cn/terrain"
        })
    </script>
</body>

</html>

image-20230203111212885

2.3.4 添加图层

图层(layer)可以在创建时配置,也可以在底图创建后添加(addLayer)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true, // basemaps底图切换按钮
                homeButton: true, // 视角复位按钮
                sceneModePicker: true, // 二三维切换按钮
                navigationHelpButton: true, // 帮助按钮
                fullscreenButton: true, // 全屏按钮
                contextmenu: { hasDefault: true } // 右键菜单
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.setSceneOptions({
            center: { lat: 31.72076, lng: 120.233888, alt: 223798, heading: 0, pitch: -45 }
        })
        map.terrainProvider = mars3d.LayerUtil.createTerrainProvider({
            url: "http://data.mars3d.cn/terrain"
        })
        const layerImg = mars3d.LayerUtil.create({
          type: "image",
          url: "//data.mars3d.cn//file/img/radar/201906211112.PNG",
          rectangle: { xmin: 73.16895, xmax: 134.86816, ymin: 12.2023, ymax: 54.11485 },
          alpha: 0.7
        })
        map.addLayer(layerImg)
    </script>
</body>

</html>

image-20230203112656599

2.3.5 地图控件

地图控件可以在地图创建时配置,也可以在地图创建后添加

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true, // basemaps底图切换按钮
                homeButton: true, // 视角复位按钮
                sceneModePicker: true, // 二三维切换按钮
                navigationHelpButton: true, // 帮助按钮
                fullscreenButton: true, // 全屏按钮
                contextmenu: { hasDefault: true } // 右键菜单
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.setSceneOptions({
            center: { lat: 31.72076, lng: 120.233888, alt: 223798, heading: 0, pitch: -45 }
        })
        const locationBar = new mars3d.control.LocationBar()
        map.addControl(locationBar)
    </script>
</body>

</html>

image-20230203113414325

2.4 地图事件

使用map.on(event, callback)函数监听地图事件,地图事件主要有单击、双击等,具体事件可以参考:API文档 - Mars3D三维可视化平台 | 火星科技

使用map.on(event, callback)函数监听地图事件,使用map.off(event, callback)函数解除监听

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true,
                homeButton: true,
                sceneModePicker: true, 
                navigationHelpButton: true,
                fullscreenButton: true, 
                contextmenu: { hasDefault: true } 
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.on("click", function (e){
            console.log(e)
        })
    </script>
</body>

</html>

image-20230203120255730

2.5 地形分析

使用Mars3D提供的地形分析函数实现地形分析

2.5.1 地形开挖

  • new mars3d.thing.TerrainClip(options)

地形开挖, 基于地球材质,可以多个区域开挖,具体参考:API文档 - Mars3D三维可视化平台 | 火星科技

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true,
                homeButton: true,
                sceneModePicker: true,
                navigationHelpButton: true,
                fullscreenButton: true,
                contextmenu: { hasDefault: true }
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.on("click", function (e) {
            console.log(e)
        })
        map.setSceneOptions({
            center: { lat: 30.899171, lng: 116.334222, alt: 23798, heading: 0, pitch: -45 }
        })
        map.terrainProvider = mars3d.LayerUtil.createTerrainProvider({
          url: "http://data.mars3d.cn/terrain"
        })

        const terrainClip = new mars3d.thing.TerrainClip({
            positions: [
            [116.334222, 30.899171, 645.46],
            [116.370874, 30.899171, 645.46],
            [116.370874, 30.944509, 645.46],
            [116.334222, 30.944509, 645.46]
          ],
            diffHeight: 50, // 井的深度
            image: "http://mars3d.cn/img/textures/poly-stone.jpg",
            imageBottom: "http://mars3d.cn/img/textures/poly-soil.jpg",
            splitNum: 80 // 井边界插值数
        })
        map.addThing(terrainClip)
    </script>
</body>

</html>

image-20230203140337853

2.5.2 等高线生成

  • new mars3d.thing.ContourLine(options)

等高线生成,具体参数可以参考:API文档 - Mars3D三维可视化平台 | 火星科技

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true,
                homeButton: true,
                sceneModePicker: true,
                navigationHelpButton: true,
                fullscreenButton: true,
                contextmenu: { hasDefault: true }
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.on("click", function (e) {
            console.log(e)
        })
        map.setSceneOptions({
            center: { lat: 30.899171, lng: 116.334222, alt: 23798, heading: 0, pitch: -45 }
        })
        map.terrainProvider = mars3d.LayerUtil.createTerrainProvider({
            url: "http://data.mars3d.cn/terrain"
        })

        const contourLine = new mars3d.thing.ContourLine({
            positions: [
                [116.334222, 30.899171, 645.46],
                [116.370874, 30.899171, 645.46],
                [116.370874, 30.944509, 645.46],
                [116.334222, 30.944509, 645.46]
            ]
        })
        map.addThing(contourLine)
    </script>
</body>

</html>

image-20230203163305592

2.5.3 坡度坡向

  • new mars3d.thing.Slope(options)

坡度坡向分析,具体参数参考:API文档 - Mars3D三维可视化平台 | 火星科技

const slope = new mars3d.thing.Slope({
    positions: [
        [116.334222, 30.899171, 645.46],
        [116.370874, 30.899171, 645.46],
        [116.370874, 30.944509, 645.46],
        [116.334222, 30.944509, 645.46]
    ]
})
map.addThing(slope)

image-20230203164237406

2.5.4 淹没分析

  • new mars3d.thing.FloodByMaterial(options)

淹没分析 , 基于地球材质,可以多个区域,具体可以参考:API文档 - Mars3D三维可视化平台 | 火星科技

const floodByMaterial = new mars3d.thing.FloodByMaterial({
    positions: [
        new Cesium.Cartesian3(-2410198.2775535597, 4925725.562201189, 3248372.021893719),
        new Cesium.Cartesian3(-2426218.5805536904, 4917854.35435215, 3248372.021893719),
        new Cesium.Cartesian3(-2421804.8608153155, 4908907.909457106, 3265042.349716699),
        new Cesium.Cartesian3(-2405813.7015733495, 4916764.7981900815, 3265042.349716699)
    ],
    speed: 500,
    minHeight: 0,
    maxHeight: 2000,
    color: "rgba(0, 123, 230, 0.5)"
})

floodByMaterial.on(mars3d.EventType.end, function (event) {
    console.log('分析完成', event)
})
map.addThing(floodByMaterial)
floodByMaterial.restart()

image-20230203190036691

2.6 矢量图层

2.6.1 graphic 数据图层

GraphicLayer是Mars3D中的矢量图层,创建矢量数据的主要步骤如下:

  • 创建矢量图层并添加到Map中
  • 创建矢量数据对象
  • 将矢量数据对象添加到矢量图层中

一个简单的添加点数据代码如下:

const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
const graphicPoint = new mars3d.graphic.PointEntity({
    position: [116.244399, 30.920459, 573.6],
    style: {
        color: "#ff0000",
        pixelSize: 10,
        outlineColor: "#ffffff",
        outlineWidth: 2,
        label: {
            text: "我是点",
            font_size: 18,
            color: "#ffffff",
            pixelOffsetY: -10,
            distanceDisplayCondition: true,
            distanceDisplayCondition_far: 500000,
            distanceDisplayCondition_near: 0
        }
    }
})
graphicLayer.addGraphic(graphicPoint)

image-20230204140208312

2.6.2 DIV矢量对象

DIV矢量对象是Mars3D中一种多用于展示与标注点对象

const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)

const graphicDiv = new mars3d.graphic.DivGraphic({
    position: [116.244399, 30.920459, 573.6],
    style: {
        html: `<div style='border:1px solid #f00'>
                        <p style='color: #0ff'>我是DIV矢量对象</p>
                    </div>`
    }
})
graphicLayer.addGraphic(graphicDiv)

image-20230204143122221

2.6.3 glTF模型

glTF是一种针对GL的三维数据格式,成为了 Web 上的3D 对象标准(Web导出的通用标准)

const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)

const gltf = new mars3d.graphic.ModelEntity({
    position: [121.507762, 31.233975, 200],
    style: {
        url: "//data.mars3d.cn/gltf/mars/shanghai/scene.gltf",
        scale: 520,
        heading: 215
    }
})
graphicLayer.addGraphic(gltf)

image-20230204150546593

2.6.4 3D Tiles模型

3D Tiles 是在glTF的基础上,加入了分层LOD的概念(可以把3D Tiles简单地理解为带有 LOD 的 glTF ),专门为流式传输和渲染海量 3D 地理空间数据而设计的,例如倾斜摄影、3D 建筑、BIM/CAD、实例化要素集和点云

tiles3dLayer = new mars3d.layer.TilesetLayer({
    name: "县城社区",
    url: "//data.mars3d.cn/3dtiles/qx-shequ/tileset.json",
    position: { alt: 11.5 },
    maximumScreenSpaceError: 1,
    maximumMemoryUsage: 1024,
    dynamicScreenSpaceError: true,
    cullWithChildrenBounds: false,
    skipLevelOfDetail: true,
    preferLeaves: true,
    center: { lat: 28.439577, lng: 119.476925, alt: 229, heading: 57, pitch: -29 },

    flyTo: true
})
map.addLayer(tiles3dLayer)

image-20230204152518611

2.6.5 GeoJSON

GeoJSON是常用的矢量数据格式

const geoJsonLayer = new mars3d.layer.GeoJsonLayer({
    url: "//data.mars3d.cn/file/geojson/wuhan-line2.json",
    symbol: {
        type: "polylineC",
        styleOptions: {
            width: 10, // 线宽
            materialType: "PolylineGlow",
            materialOptions: {
                color: "#FF4500",
                opacity: 0.9,
                glowPower: 0.1 // 发光强度
            }
        }
    },
    show: true
})
map.addLayer(geoJsonLayer)

image-20230204154201679

2.6.6 WFS服务

WFS是OGC定义的矢量数据服务

const wfsLayer = new mars3d.layer.WfsLayer({
    name: "建筑物面WFS",
    url: "//server.mars3d.cn/geoserver/mars/wfs",
    layer: "mars:hfjzw",
    parameters: {
        // 支持所有wfs的参数
        maxFeatures: 210
    },
    minimumLevel: 1,
    symbol: {
        type: "polygonP",
        styleOptions: {
            color: "#00469c",
            outline: false,
            opacity: 1
        }
    },
    buildings: {
        cloumn: "floor"
    },
    debuggerTileInfo: false,
    popup: "名称:{NAME}<br />层数:{floor}",
    show: true
})
map.addLayer(wfsLayer)

image-20230204155540070

2.6.7 WFS查询

WFS允许对矢量要素的增删改查

const queryMapserver = new mars3d.query.QueryGeoServer({
    url: "//server.mars3d.cn/geoserver/mars/wfs",
    layer: "mars:hfjy"
})
map.graphicLayer.startDraw({
    type: "rectangle",
    style: {
        color: "#00FF00",
        opacity: 0.3,
        outline: true,
        outlineColor: "#ffffff",
        clampToGround: true
    },
    success: function (graphic) {
        drawGraphic = graphic
        console.log("矩形:", drawGraphic.toGeoJSON({ outline: true }))
        queryMapserver.query({
            graphic: drawGraphic,
            success: (result) => {
                console.log(result)
            },
            error: (e) => {
                console.log(e)
            }
        })
    }
})

image-20230204163442488

2.7 矢量数据

2.7.1 Entity基础对象

Entity实体是Mars3D中的矢量对象,主要有以下Entity:

创建Entity对象的主要步骤如上述所说:

  • 创建矢量图层并添加到Map中
  • 创建矢量数据对象
  • 将矢量数据对象添加到矢量图层中

以下是示例创建并展示一个PolylineEntity和PolygonEntity:

// 创建矢量数据图层
const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
map.setSceneOptions({
    center: { lat: 31.52076, lng: 117.233888, alt: 23798, heading: 0, pitch: -45 }
})

const polylineEntity = new mars3d.graphic.PolylineEntity({
    positions: [
        [117.220337, 31.832987, 42.8],
        [117.220242, 31.835234, 45.6],
        [117.216263, 31.835251, 39.3],
        [117.217219, 31.819929, 35.8],
        [117.223096, 31.818342, 29.8],
        [117.249686, 31.818964, 40.1],
        [117.263171, 31.816664, 35.2],
        [117.278695, 31.816107, 35.5],
        [117.279826, 31.804185, 34.5],
        [117.286308, 31.804112, 29.2],
        [117.28621, 31.801059, 24.6]
    ],
    style: {
        width: 5,
        color: "#3388ff",
        label: { text: "鼠标移入会高亮", pixelOffsetY: -30 },
        // 高亮时的样式(默认为鼠标移入,也可以指定type:'click'单击高亮),构造后也可以openHighlight、closeHighlight方法来手动调用
        highlight: {
            color: "#ff0000"
        }
    },
})
graphicLayer.addGraphic(polylineEntity)

const polygonEntity = new mars3d.graphic.PolygonEntity({
    positions: [
        [117.220337, 31.832987, 42.8],
        [117.220242, 31.835234, 45.6],
        [117.216263, 31.835251, 39.3],
        [117.217219, 31.819929, 35.8],
        [117.220337, 31.832987, 42.8]
    ],
    style: {
        width: 5,
        color: "#0ff",
        highlight: {
            color: "#ff0000"
        }
    },
})
graphicLayer.addGraphic(polygonEntity)

image-20230205173231486

2.7.2 Primitive基础对象

Primitive API 的主要目的是为了完成(可视化)任务的最少的抽象需求,Primitive方式更接近渲染引擎底层,拥有更好的绘制性能,但是它的封装不如Entity API,Entity使用起来更方便

Primitive图元也是Mars3D中的矢量对象,主要有以下Primitive:

以下是示例创建并展示一个PolylinePrimitive和PolygonPrimitive(和Entity基本类似):

// 创建矢量数据图层
const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
map.setSceneOptions({
    center: { lat: 31.52076, lng: 117.233888, alt: 23798, heading: 0, pitch: -45 }
})

const polylinePrimitive = new mars3d.graphic.PolylinePrimitive({
    positions: [
        [117.220337, 31.832987, 42.8],
        [117.220242, 31.835234, 45.6],
        [117.216263, 31.835251, 39.3],
        [117.217219, 31.819929, 35.8],
        [117.223096, 31.818342, 29.8],
        [117.249686, 31.818964, 40.1],
        [117.263171, 31.816664, 35.2],
        [117.278695, 31.816107, 35.5],
        [117.279826, 31.804185, 34.5],
        [117.286308, 31.804112, 29.2],
        [117.28621, 31.801059, 24.6]
    ],
    style: {
        width: 5,
        color: "#3388ff",
        label: { text: "鼠标移入会高亮", pixelOffsetY: -30 },
        // 高亮时的样式(默认为鼠标移入,也可以指定type:'click'单击高亮),构造后也可以openHighlight、closeHighlight方法来手动调用
        highlight: {
            color: "#ff0000"
        }
    },
})
graphicLayer.addGraphic(polylinePrimitive)

const polygonPrimitive = new mars3d.graphic.PolygonPrimitive({
    positions: [
        [117.220337, 31.832987, 42.8],
        [117.220242, 31.835234, 45.6],
        [117.216263, 31.835251, 39.3],
        [117.217219, 31.819929, 35.8],
        [117.223096, 31.818342, 29.8]
    ],
    style: {
        width: 5,
        color: "#0ff",
        highlight: {
            color: "#ff0000"
        }
    },
})
graphicLayer.addGraphic(polygonPrimitive)

image-20230205203410426

2.7.3 CombinePrimitive对象

CombinePrimitive对象是合并渲染的Primitive图元 ,更适合大数据渲染,主要的有:

以下是示例创建并展示一个PolylinePrimitive和PolygonPrimitive:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入cesium基础lib-->
    <link href="https://unpkg.com/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d-cesium/Build/Cesium/Cesium.js" type="text/javascript"></script>
    <!--引入turf基础lib-->
    <script src="http://mars3d.cn/lib/turf/turf.min.js"></script>
    <!--引入mars3d库lib-->
    <link href="https://unpkg.com/mars3d/dist/mars3d.css" rel="stylesheet" type="text/css" />
    <script src="https://unpkg.com/mars3d/dist/mars3d.js" type="text/javascript"></script>

    <style>
        html,
        body,
        .mars3d-container {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="mars3dContainer" class="mars3d-container"></div>
    <script>
        let mapOptions = {
            basemaps: [{
                name: "高德",
                icon: "./icon/offline.png",
                type: "gaode",
                layer: "img_d",
                show: true
            }],
            control: {
                baseLayerPicker: true, // basemaps底图切换按钮
                homeButton: true, // 视角复位按钮
                sceneModePicker: true, // 二三维切换按钮
                navigationHelpButton: true, // 帮助按钮
                fullscreenButton: true, // 全屏按钮
                contextmenu: { hasDefault: true } // 右键菜单
            },
            layers: [{
                name: "天地图注记",
                type: "tdt",
                layer: "img_z",
                show: true
            }]
        }
        const map = new mars3d.Map("mars3dContainer", mapOptions)
        map.setSceneOptions({
            center: { lat: 31.72076, lng: 117.033888, alt: 223798, heading: 0, pitch: -45 }
        })

        // 创建矢量数据图层
        const graphicLayer = new mars3d.layer.GraphicLayer()
        map.addLayer(graphicLayer)
        map.setSceneOptions({
            center: { lat: 31.82076, lng: 117.233888, alt: 23798, heading: 0, pitch: -45 }
        })
        
        // 生成演示数据(测试数据量)
        let bbox = [116.984788, 31.625909, 117.484068, 32.021504]
        let count = 1000
        let result = mars3d.PolyUtil.getGridPoints(bbox, count, 30)
        console.log("生成的测试网格坐标", result)

        let arrData = []
        for (let j = 0; j < result.points.length; ++j) {
            let position = result.points[j]
            let index = j + 1

            let pt1 = mars3d.PointUtil.getPositionByDirectionAndLen(position, 225, result.radius)
            let pt2 = mars3d.PointUtil.getPositionByDirectionAndLen(position, 315, result.radius)

            arrData.push({
                positions: [pt1, position, pt2],
                style: {
                    width: 3.0,
                    color: Cesium.Color.fromRandom({ alpha: 1.0 })
                },
                attr: { index: index }
            })
        }

        // 多个线对象的合并渲染。
        const polylineCombine = new mars3d.graphic.PolylineCombine({
            instances: arrData,
            // 高亮时的样式
            highlight: {
                type: mars3d.EventType.click,
                color: Cesium.Color.YELLOW
            }
        })
        graphicLayer.addGraphic(polylineCombine)
        // 多个面对象的合并渲染
        const polygonCombine = new mars3d.graphic.PolygonCombine({
            instances: arrData,
        })
        graphicLayer.addGraphic(polygonCombine)
    </script>

</body>

</html>

image-20230205235542405

2.7.4 ParticleSystem粒子对象

ParticleSystem粒子对象是一些粒子效果

// 创建矢量数据图层
const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
map.setSceneOptions({
    center: { lat: 31.815135, lng: 117.233888, alt: 898, heading: 0, pitch: -45 }
})

const particleSystem = new mars3d.graphic.ParticleSystem({
    position: Cesium.Cartesian3.fromDegrees(117.224855, 31.815135, 28.05), // 位置
    style: {
        image: "./img/particle/penquan.png",
        particleSize: 8, // 粒子大小(单位:像素)
        emissionRate: 100.0, // 发射速率 (单位:次/秒)
        heading: 290, // 方向角
        pitch: 40, // 俯仰角
        gravity: -3.5, // 重力因子,会修改速度矢量以改变方向或速度(基于物理的效果)
        transZ: 5, // 离地高度(单位:米)
        maxHeight: 5000, // 超出该高度后不显示粒子效果

        startColor: new Cesium.Color(1, 1, 1, 0.6), //  开始颜色
        endColor: new Cesium.Color(0.8, 0.86, 1, 0.4), // 结束颜色
        startScale: 1.0, //  开始比例(单位:相对于imageSize大小的倍数)
        endScale: 4.0, // 结束比例(单位:相对于imageSize大小的倍数)
        minimumParticleLife: 6, // 最小寿命时间(秒)
        maximumParticleLife: 7, // 最大寿命时间(秒)
        minimumSpeed: 9.0, // 最小速度(米/秒)
        maximumSpeed: 9.5 // 最大速度(米/秒)
    },
    attr: { remark: "水柱粒子效果" }
})

graphicLayer.addGraphic(particleSystem)

image-20230206112109953

2.7.5 漫游路线对象

漫游路线对象展示对象按照一定轨迹移动,主要有以下漫游路线对象:

以下是固定路线(FixedRoute)游:

const fixedRoute = new mars3d.graphic.FixedRoute({
    speed: 100,
    positions: [
        [117.298794, 31.882442, 500],
        [117.249731, 31.88091, 600]
    ],
    model: {
        url: "//data.mars3d.cn/gltf/mars/zhanji.glb",
        scale: 0.01,
        minimumPixelSize: 60
    },
    path: {
        color: "#ffff00",
        opacity: 0.5,
        width: 1,
        leadTime: 0
    },
    coneTrack: {
        angle: 5, // 半场角度
        color: "rgba(255,0,0,0.5)"
    }
})
graphicLayer.addGraphic(fixedRoute)

image-20230206134643412

2.7.6 视频融合对象

投射视频物体表面

// 创建矢量数据图层
const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
map.setSceneOptions({
    center: { lat: 31.815135, lng: 117.233888, alt: 2898, heading: 0, pitch: -45 }
})

const video3D = new mars3d.graphic.Video3D({
    position: [117.233888, 31.815135, 0],
    style: {
        url: "//data.mars3d.cn/file/video/menqian.mp4",
        maskImage: "img/textures/video-mask.png", // 羽化视频四周,融合更美观
        angle: 46.3,
        angle2: 15.5,
        heading: 178.5,
        pitch: -49.5,
        showFrustum: true
    }
})
graphicLayer.addGraphic(video3D)

image-20230206201450309

2.8 样式及效果

2.8.1 设置样式

样式主要就是设置style

// 模型
const tiles3dLayer = new mars3d.layer.TilesetLayer({
    name: "合肥市建筑物",
    url: "//data.mars3d.cn/3dtiles/jzw-hefei2/tileset.json",
    maximumScreenSpaceError: 1,
    maximumMemoryUsage: 1024,
    style: {
        color: {
            conditions: [
                ["${height} >= 300", "rgba(45, 0, 75, 0.5)"],
                ["${height} >= 200", "rgb(102, 71, 151)"],
                ["${height} >= 100", "rgb(170, 162, 204)"],
                ["${height} >= 50", "rgb(224, 226, 238)"],
                ["${height} >= 30", "rgb(252, 230, 200)"],
                ["${height} >= 20", "rgb(248, 176, 87)"],
                ["${height} >= 10", "rgb(198, 106, 11)"],
                ["true", "rgb(127, 59, 8)"]
            ]
        }
    },
    highlight: { type: "click", color: "#FFFF00" },
    popup: [
        { field: "objectid", name: "编号" },
        { field: "name", name: "名称" },
        { field: "height", name: "楼高", unit: "米" }
    ]
})
map.addLayer(tiles3dLayer)

image-20230206204723650

2.8.2 自定义Shader

Tileset支持自定义shader

// 创建矢量数据图层
const graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
map.setSceneOptions({
    center: { lat: 31.267519, lng: 121.42728, alt: 2923, heading: 118, pitch: -27 }
})

const tiles3dLayer = new mars3d.layer.TilesetLayer({
    name: "上海市建筑物",
    url: "//data.mars3d.cn/3dtiles/jzw-shanghai/tileset.json",
    maximumScreenSpaceError: 8,
    maximumMemoryUsage: 1024,
    popup: "all"
})

// 当前效果是:根据视角距离,模型呈现不同颜色
tiles3dLayer.customShader = new Cesium.CustomShader({
    lightingModel: Cesium.LightingModel.UNLIT,
    fragmentShaderText: `
          void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
          {
            material.diffuse = vec3(0.0, 0.0, 1.0);
            material.diffuse.g = -fsInput.attributes.positionEC.z / 1.0e4;
          } `
})
map.addLayer(tiles3dLayer)

image-20230206205841560

3. 参考资料

[1]功能示例(Vue版) - Mars3D三维可视化平台 | 火星科技

[2]API文档 - Mars3D三维可视化平台 | 火星科技

[3]开发教程 - Mars3D三维可视化平台 | 火星科技

[4]Viewer - Cesium Documentation (mars3d.cn)