• Cesium开发三维地图入门


    需求:要求将GLTF三维模型放到地图上展示,并且添加各种图标和线进行标注。

     用CesiumJS地图库实现代码如下:

    引入CesiumJS库

    1、直接clone源码包,在index.html中引入,如下:

    <head>
      <meta charset="utf-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
      <meta name="description" content="Create 3D models using glTF.">
      <title>Chemical plant</title>
      <script type="text/javascript" src="../../Cesium-1.77/Build/Cesium/Cesium.js"></script>
      <link href="../../Cesium-1.77/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    </head>
    
    <body>
      <div id="cesiumContainer"></div>

    2、参考官网说明(https://www.cesium.com/docs/tutorials/cesium-and-webpack/)用npm安装

     贴下package.json和webpack.config.js:

    package.json

    {
      "name": "cesium-webpack-app",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "node_modules/.bin/webpack --config webpack.config.js",
        "start": "node_modules/.bin/webpack serve --config webpack.config.js --open"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "cesium": "^1.78.0",
        "copy-webpack-plugin": "^7.0.0",
        "css-loader": "^5.0.2",
        "html-webpack-plugin": "^5.2.0",
        "style-loader": "^2.0.0",
        "url-loader": "^4.1.1",
        "webpack": "^5.23.0",
        "webpack-cli": "^4.5.0",
        "webpack-dev-server": "^3.11.2"
      }
    }

    webpack.config.js

    const path = require('path');
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
    const cesiumSource = 'node_modules/cesium/Source';
    const cesiumWorkers = '../Build/Cesium/Workers';
    
    
    
    module.exports = {
        context: __dirname,
        entry: {
            app: './src/index.js'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist'),
            sourcePrefix: ''
        },
        amd: {
            toUrlUndefined: true
        },
        module: {
            rules: [{
                test: /.css$/,
                use: ['style-loader', 'css-loader']
            }, {
                test: /.(png|gif|jpg|jpeg|svg|xml|json)$/,
                use: ['url-loader']
            }]
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: 'src/index.html'
            }),
            new CopyWebpackPlugin({
                patterns: [
                    { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' },
                    { from: path.join(cesiumSource, 'Assets'), to: 'Assets' },
                    { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' }
                ]
            }),
            new webpack.DefinePlugin({
                CESIUM_BASE_URL: JSON.stringify('')
            })
        ],
        devServer: {
            contentBase: path.join(__dirname, "dist")
        },
        resolve: {
            alias: {
                cesium: path.resolve(__dirname, cesiumSource)
            },
            fallback: {
                fs: false
            }
        }
    };

    以上2种方式经测试都不需要在官网申请token,直接使用api即可。

    初始化地图:

        const imageryProvider = new Cesium.UrlTemplateImageryProvider({
          url: "http://webst01.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x={x}&y={y}&z={z}",
          tilingScheme: new Cesium.WebMercatorTilingScheme(),
          fileExtension: 'png',
          minimumLevel: 0,
          maximumLevel: 20,
        });
    
        const viewer = new Cesium.Viewer("cesiumContainer", {
          imageryProvider: imageryProvider,
          animation: false,        //是否显示动画控件
          homeButton: false,       //是否显示home键
          geocoder: false,         //是否显示地名查找控件,如果设置为true,则无法查询
          baseLayerPicker: false,  //是否显示图层选择控件
          timeline: false,         //是否显示时间线控件
          fullscreenButton: false,  //是否全屏显示
          scene3DOnly: true,       //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
          infoBox: false,           //是否显示点击要素之后显示的信息
          sceneModePicker: false,  //是否显示投影方式控件  三维/二维
          navigationInstructionsInitiallyVisible: false,
          navigationHelpButton: false,     //是否显示帮助信息控件
          selectionIndicator: false,       //是否显示指示器组件
        });
    
        viewer._cesiumWidget._creditContainer.style.display = "none";
    
        //添加文字标注
        viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
          url: "http://t0.tianditu.com/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=TOKEN",
          layer: "tdtAnnoLayer",
          style: "default",
          format: "image/jpeg",
          tileMatrixSetID: "GoogleMapsCompatible",
          show: false,
        }));
    
        viewer.scene.primitives.add(Cesium.createOsmBuildings());
        viewer.scene.highDynamicRange = false;
        viewer.shadows = false;

        { //修改鼠标控制地图视图的默认行为:左键拖动,右键旋转
          viewer.scene.screenSpaceCameraController.zoomEventTypes = [
            Cesium.CameraEventType.WHEEL,
            Cesium.CameraEventType.MIDDLE_DRAG,
            Cesium.CameraEventType.PINCH,
          ];
          viewer.scene.screenSpaceCameraController.tiltEventTypes = [
            Cesium.CameraEventType.RIGHT_DRAG,
            Cesium.CameraEventType.PINCH,

            {
              eventType: Cesium.CameraEventType.RIGHT_DRAG,
              modifier: Cesium.KeyboardEventModifier.CTRL,
            },

            {
              eventType: Cesium.CameraEventType.MIDDLE_DRAG,
              modifier: Cesium.KeyboardEventModifier.CTRL,
            },
          ];
        }
    
    
        createGltfModel("../../data/gltf/NewFile.gltf", 117.628293, 23.798717, 0.0, {
          modelScale: 1, //模型放大倍数
          lightColor: new Cesium.Cartesian3(20.0, 20.0, 20.0), //模型的材质亮度
          position: {
            //地图初始化位置,坐标是3维笛卡尔坐标
            x: -2707823.1735314624,
            y: 5173260.303294086,
            z: 2558159.506208664,
          },
          orientation: {
            heading: 4.735189003200103,
            pitch: -0.4113143959917751,
            roll: 6.2804863005660785,
          },
        });
    
        function createGltfModel(url, lng, lat, height, {
          modelScale,
          lightColor,
          position,
          orientation
        } = {
            modelScale: 1,
            lightColor: new Cesium.Cartesian3(0, 0, 0),
            position: { x: 0, y: 0, z: 0 },
            orientation: { heading: 0, pitch: 0, roll: 0 }
          }) {
          viewer.entities.removeAll();
          let ellipsoid = viewer.scene.globe.ellipsoid;
          let cart3 = ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(lng, lat, height));
          let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(cart3);
          let model = viewer.scene.primitives.add(Cesium.Model.fromGltf({
            url,
            modelMatrix,
            scale: 1,     //放大倍数
            lightColor,//gltf模型加载后比较暗,这个起到增大模型材质亮度的作用
          }));
    
          let initialPosition = new Cesium.Cartesian3(position.x, position.y, position.z); // 相机的位置
          let homeCameraView = {
            destination: initialPosition, // 相机的位置
            orientation,
          };
    
          viewer.scene.camera.setView(homeCameraView);
    
          
          /**
           * 这个时间是我调试的结果,模型不至于很暗
           * 主要是时间要调到太阳照射到整个模型区域,日期没有多大影响
           */
          let utc = Cesium.JulianDate.fromDate(new Date("2021/02/20 03:40:00"));//UTC
          viewer.clock.currentTime = Cesium.JulianDate.addHours(utc, 8, new Cesium.JulianDate());
        }

     抗锯齿处理:

     //抗锯齿处理
        {
          viewer.scene.fxaa = true
          viewer.scene.postProcessStages.fxaa.enabled = true;
          let supportsImageRenderingPixelated = viewer.cesiumWidget._supportsImageRenderingPixelated;
          if (supportsImageRenderingPixelated) {
            let vtxf_dpr = window.devicePixelRatio;
            while (vtxf_dpr >= 2.0) { vtxf_dpr /= 2.0; }
            viewer.resolutionScale = vtxf_dpr;
          }
        }

    添加图片:

     //添加图片
        {
          const iconMarks = [
            {
              id: 'factory1',
              position: [117.62514171688602, 23.800514411219126, 40],
              image: '../../data/icons/废气-C.png',
            },
            {
              id: 'factory2',
              position: [117.62441672316956, 23.801488899527932, 40],
              image: '../../data/icons/废气-C.png',
            },
            {
              id: 'camera1',
              position: [117.62438331048037, 23.80172986514075, 20],
              image: '../../data/icons/摄像头-C.png',
               13,
              height: 18
            },
            {
              id: 'camera2',
              position: [117.6251283858732, 23.801983468675637, 10],
              image: '../../data/icons/摄像头-C.png',
               13,
              height: 18
            }
          ];
    
          for (const mark of iconMarks) {
            let width = mark.width || 30;
            let height = mark.height || 30;
            viewer.entities.add({
              id: mark.id,
              name: 'mark',
              position: Cesium.Cartesian3.fromDegrees(...mark.position),
              billboard: {
                // 图像地址,URI或Canvas的属性
                image: mark.image,
                // 设置颜色和透明度
                // color: Cesium.Color.WHITE.withAlpha(1),
                // 高度(以像素为单位)
                height,
                // 宽度(以像素为单位)
                width,
                // 逆时针旋转
                rotation: 0,
                // 大小是否以米为单位
                sizeInMeters: false,
                // 相对于坐标的垂直位置
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                // 相对于坐标的水平位置
                horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
                // 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
                pixelOffset: new Cesium.Cartesian2(-width / 2, -height / 2),
                // 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
                scale: 1.0,
                // 是否显示
                show: true
              }
            });
          }
        }

    添加线:

     //添加线
        {
          const markLines = [
            {
              id: 'line1',
              positions: [[117.62514171688602, 23.800514411219126, 0], [117.62514171688602, 23.800514411219126, 40]],
            },
            {
              id: 'line2',
              positions: [[117.62441672316956, 23.801488899527932, 0], [117.62441672316956, 23.801488899527932, 40]],
            },
            {
              id: 'line3',
              positions: [[117.62441672316956, 23.801488899527932, 20],
              [117.62438331048037, 23.80172986514075, 20],
              [117.6251283858732, 23.801983468675637, 10],
              [117.62516689671625, 23.802117335288763, 10]]
            }
          ];
    
          for (const line of markLines) {
            let polyline = new Cesium.PolylineGraphics();
            polyline.material = new Cesium.ColorMaterialProperty(new Cesium.Color(0.18, 0.67, 1, 1));
            polyline.width = new Cesium.ConstantProperty(2);
            polyline.arcType = new Cesium.ConstantProperty(
              Cesium.ArcType.NONE
            );
            let coordArr = line.positions.map(e => Cesium.Cartesian3.fromDegrees(...e));
            console.log('coordArr', coordArr);
            polyline.positions = new Cesium.ConstantProperty(coordArr);
            let entity = new Cesium.Entity({
              id: line.id,
              show: true,
              polyline,
              name: 'line',
            });
            viewer.entities.add(entity);
          }
        }

    添加事件:

    //事件
        {
          let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
          handler.setInputAction(function (evt) {
            let pick = viewer.scene.pick(evt.position);
            // //选中某模型
            if (pick && pick.id) {
              alert(pick.id._id)
            }
            let cartesian = viewer.camera.pickEllipsoid(evt.position, viewer.scene.globe.ellipsoid);
            let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
            let lng = Cesium.Math.toDegrees(cartographic.longitude);//经度值
            let lat = Cesium.Math.toDegrees(cartographic.latitude);//纬度值
            let mapPosition = { x: lng, y: lat, z: cartographic.height };//cartographic.height的值始终为零。
            // console.log('mapPosition: ', mapPosition);
            console.log('lng: ', lng, 'lat: ', lat);//拾取坐标
    
          }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    
          handler.setInputAction(evt => {
            let pick = viewer.scene.pick(evt.endPosition);
            //选中某模型
            if (pick && pick.id && pick.id._name === 'mark') {
              // console.log('pick', pick.id._id);
    // 修改鼠标指针样式
    viewer._container.style.cursor = 'pointer'; } else { viewer._container.style.cursor = ''; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) }

    效果:

  • 相关阅读:
    【leetcode 461】. Hamming Distance
    【leetcode 476】. Number Complement
    大数据概述
    对于编译原理的看法
    PHP基础(二) 文件包含
    PHP基础(一)
    webpack 之(6) commonJS和 ES6 Module区别 (未完成)
    webpack 之(5) webpack.config.js配置 之 img
    webpack 之(4) webpack.config.js配置 之 html
    webpack 之(3) webpack.config.js配置 之 css/less
  • 原文地址:https://www.cnblogs.com/davidxu/p/14430906.html
Copyright © 2020-2023  润新知