使用cesium地图动态绘制线和面

直接贴代码吧,cesium版本1.99,turf版本7.0.0

<template>
  <div id="appp" style="width: 100%;height: 100%;position: relative;">
    <div id="cesiumContainer"></div>
    <div class="btnContainer">
      <button @click="draw('Polyline')">标点测距</button>
      <button @click="draw('Polygon')">标点测面</button>
      <button @click="clearAllDrawn()">清空数据</button>
      <div class="tip">
        <p>点击按钮后,在场景内单击左键标点,单击右键结束测量。</p>
        <p>点击“标点测距”按钮后在场景内单击鼠标左键加点,在两点间显示距离,单击右键结束测量。</p>
        <p>点击“标点测面”按钮后在场景内单击鼠标左键加点,单击右键在勾出的范围中显示面积。</p>
        <p>点击“清空数据”按钮删除所有数据。</p>
      </div>
    </div>
  </div>
</template>

<script setup name="cesiumMap">
import { onMounted, ref, onBeforeUnmount, reactive } from 'vue';
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';
import * as turf from '@turf/turf';

const tiandituTk = '天地图的Key'

//天地图影像
let TDT_YX = new Cesium.WebMapTileServiceImageryProvider({
  url: `http://{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=${tiandituTk}`,
  layer: 'img',
  style: 'default',
  format: 'tiles',
  tileMatrixSetID: 'w',
  subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
  credit: new Cesium.Credit('天地图影像'),
  maximumLevel: 18
});

//天地图矢量
let TDT_SL = new Cesium.WebMapTileServiceImageryProvider({
  url: `http://{s}.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=${tiandituTk}`,
  layer: 'vec',
  style: 'default',
  format: 'tiles',
  tileMatrixSetID: 'w',
  subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
  credit: new Cesium.Credit('天地图矢量'),
  maximumLevel: 18
});

// 正射影像
let wmtsImageryProvider = new Cesium.WebMapTileServiceImageryProvider({
  url: 'http://222.71.165.235:8088/geoserver/gwc/service/wmts',
  layer: 'land-survey:gtxz_wgs84_new', // Replace with your workspace and layer name
  style: '', // Or replace with your style name if any
  format: 'image/png', // Or replace with your image format
  tileMatrixSetID: 'EPSG:4326', // Replace with your TileMatrixSet ID
  tileMatrixLabels: ['EPSG:4326:0', 'EPSG:4326:1', 'EPSG:4326:2', 'EPSG:4326:3', 'EPSG:4326:4', 'EPSG:4326:5', 'EPSG:4326:6', 'EPSG:4326:7', 'EPSG:4326:8', 'EPSG:4326:9', 'EPSG:4326:10', 'EPSG:4326:11', 'EPSG:4326:12', 'EPSG:4326:13', 'EPSG:4326:14', 'EPSG:4326:15', 'EPSG:4326:16', 'EPSG:4326:17', 'EPSG:4326:18', 'EPSG:4326:19', 'EPSG:4326:20', 'EPSG:4326:21'], // 根据实际的 TileMatrix 级别列表
  maximumLevel: 21,
  tilingScheme: new Cesium.GeographicTilingScheme(), // 根据坐标系选择适当的 TilingScheme
});

// 加载影像注记
let TDT_ZJ = new Cesium.WebMapTileServiceImageryProvider({
  url: `http://t0.tianditu.gov.cn/cia_w/wmts?tk=${tiandituTk}`,
  layer: 'cia',
  style: 'default',
  tileMatrixSetID: 'w',
  format: 'tiles',
  credit: new Cesium.Credit('天地注记'),
  maximumLevel: 18
});


const viewer = ref(null);
// const handler = ref(null);
const pointNum = ref(0)
const floatingPoint = ref(undefined)
const activeShape = ref(undefined)

let tempEntities = reactive([]);
/* 空间两点距离计算函数 */
function getLength(start, end) {
  // 将起点与终点位置信息从笛卡尔坐标形式转换为Cartographic形式
  let startCartographic = Cesium.Cartographic.fromCartesian(start)
  let endCartographic = Cesium.Cartographic.fromCartesian(end)
  // 初始化测地线
  let geodesic = new Cesium.EllipsoidGeodesic()
  // 设置测地线起点和终点,EllipsoidGeodesic中setEndPoints常与surfaceDistance搭配使用
  geodesic.setEndPoints(startCartographic, endCartographic)
  // 获取起点和终点之间的表面距离,单位为m,规定四舍五入保留两位小数
  // surfaceDistance返回number 单位为m,带小数
  // console.log((geodesic.surfaceDistance / 1000).toFixed(2))
  return (geodesic.surfaceDistance).toFixed(2)
}
/* 空间两点计算中点函数 */
function getMidpoint(start, end) {
  let startPoint = Cesium.Cartographic.fromCartesian(start)
  let endPoint = Cesium.Cartographic.fromCartesian(end)
  let geodesic = new Cesium.EllipsoidGeodesic()
  geodesic.setEndPoints(startPoint, endPoint)
  let geoPoint = geodesic.interpolateUsingFraction(0.5)
  // console.log(Cesium.Ellipsoid.WGS84.cartographicToCartesian(geoPoint))
  return Cesium.Ellipsoid.WGS84.cartographicToCartesian(geoPoint)
}

function addLabel(midPoint, labelLength) {
  return viewer.value.entities.add({
    name: '中点',
    position: midPoint,
    label: {
      text: labelLength + 'm',
      font: '12px sans-serif',
      fillColor: Cesium.Color.WHITE,
      outlineWidth: 2,
      backgroundColor: Cesium.Color.BLACK,
      showBackground: true,
      style: Cesium.LabelStyle.FILL,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      disableDepthTestDistance: Number.POSITIVE_INFINITY // 确保标签不被遮挡
    }
  })

}

//面积计算
function getArea(positions) {
  console.log(positions)
  // 将 Cartesian3 坐标转换为 WGS84 经纬度坐标
  let wgs84Coordinates = positions.map(cartesian => {
    let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    return [
      Cesium.Math.toDegrees(cartographic.longitude),
      Cesium.Math.toDegrees(cartographic.latitude)
    ];
  });

  // 构建 GeoJSON 对象
  let geoJsonPolygon = {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Polygon",
          coordinates: [wgs84Coordinates.concat([wgs84Coordinates[0]])] // 闭合多边形
        }
      }
    ]
  };
  // 输出结果
  console.log(geoJsonPolygon);
  // 计算面积
  let area = turf.area(geoJsonPolygon.features[0]);
  // 输出面积结果(以平方米为单位)
  console.log(`Area: ${area} square meters`);

  // 计算面的中心点
  const center = turf.center(geoJsonPolygon);

  // 从中心点的经纬度坐标提取
  const [longitude, latitude] = center.geometry.coordinates;

  // 将经纬度坐标转换为 Cartesian3 坐标
  const cartesian3 = Cesium.Cartesian3.fromDegrees(longitude, latitude);

  // 输出结果
  console.log(cartesian3);
  return [area.toFixed(2),cartesian3]
}

function addArea(area, position) {
  return viewer.value.entities.add({
    name: '多边形面积',
    position: position,
    label: {
      text: area + 'm²',
      font: '12px sans-serif',
      fillColor: Cesium.Color.WHITE,
      outlineWidth: 2,
      backgroundColor: Cesium.Color.BLACK,
      showBackground: true,
      style: Cesium.LabelStyle.FILL,
      // pixelOffset: new Cesium.Cartesian2(60,-100,0),
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      disableDepthTestDistance: Number.POSITIVE_INFINITY
    }
  })
}

/* 绘制函数 */
function drawPointLabel(position, pointNum) {
  // 本质上就是添加一个点的实体
  return viewer.value.entities.add({
    name: '点几何对象',
    position: position,
    point: {
      color: Cesium.Color.WHEAT,
      pixelSize: 5,
      outlineWidth: 3,
      disableDepthTestDistance: Number.POSITIVE_INFINITY, //
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 规定贴地
    }
  })
}

function drawPoint(position) {
  // 本质上就是添加一个点的实体
  return viewer.value.entities.add({
    position: position,
    point: {
      color: Cesium.Color.WHEAT,
      pixelSize: 5,
      outlineWidth: 3,
      disableDepthTestDistance: Number.POSITIVE_INFINITY,
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 规定贴地
    }
  })
}

function drawPolyline(positions) {
  if (positions.length < 1) return
  return viewer.value.entities.add({
    name: '线几何对象',
    polyline: {
      positions: positions,
      width: 5.0,
      material: new Cesium.PolylineGlowMaterialProperty({
        // eslint-disable-next-line new-cap
        color: Cesium.Color.WHEAT
      }),
      depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
        // eslint-disable-next-line new-cap
        color: Cesium.Color.WHEAT
      }),
      clampToGround: true
    }
  })
}

function drawPolygon(positions) {
  if (positions.length < 2) return
  return viewer.value.entities.add({
    name: '面几何对象',
    polygon: {
      hierarchy: positions,
      // eslint-disable-next-line new-cap
      material: new Cesium.ColorMaterialProperty(
        Cesium.Color.WHEAT.withAlpha(0.4)
      )
    }
  })
}
/* 清除实体 */
function clearAllDrawn() {
  tempEntities = []
  pointNum.value = 0
  viewer.value.entities.removeAll()
}

/* 根据类型绘制对象 */
function draw(type) {
  switch (type) {
    case 'Polyline':
      drawPolylineHandler();
      break;
    case 'Polygon':
      drawPolygonHandler();
      break;
  }
}

function drawPolylineHandler() {
  let tempPoints = [];
  let activeShapeLine;
  let activeShapeLabel;
  let drawing = false;

  let handler = new Cesium.ScreenSpaceEventHandler(viewer.value.scene.canvas);

  // 左键点击事件处理函数:开始绘制线段
  handler.setInputAction(function (click) {
    let ray = viewer.value.camera.getPickRay(click.position);
    let pickedPosition = viewer.value.scene.globe.pick(ray, viewer.value.scene);
    if (Cesium.defined(pickedPosition)) {
      if (!drawing) {
        tempPoints = [pickedPosition];
        drawing = true;
        pointNum.value += 1;
        let point = drawPointLabel(pickedPosition, JSON.stringify(pointNum.value));
        tempEntities.push(point);
      } else {
        tempPoints.push(pickedPosition);
        let point = drawPointLabel(pickedPosition, JSON.stringify(pointNum.value));
        tempEntities.push(point);
        let lastPoint = tempPoints[0];
        activeShapeLine = drawPolyline([lastPoint, pickedPosition]);
        tempEntities.push(activeShapeLine);
        let pointLength = getLength(lastPoint, pickedPosition);
        let midPosition = getMidpoint(lastPoint, pickedPosition);
        activeShapeLabel = addLabel(midPosition, pointLength);
        tempEntities.push(activeShapeLabel);
        tempPoints = [pickedPosition];
      }
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  // 鼠标移动事件处理函数:更新线段和长度标签
  handler.setInputAction(function (movement) {
    if (drawing && tempPoints.length > 0) {
      let ray = viewer.value.camera.getPickRay(movement.endPosition);
      let pickedPosition = viewer.value.scene.globe.pick(ray, viewer.value.scene);
      if (Cesium.defined(pickedPosition)) {
        if (activeShapeLine) {
          viewer.value.entities.remove(activeShapeLine);
        }
        let lastPoint = tempPoints[0];
        activeShapeLine = drawPolyline([lastPoint, pickedPosition]);
        tempEntities.push(activeShapeLine);
        if (activeShapeLabel) {
          viewer.value.entities.remove(activeShapeLabel);
        }
        let pointLength = getLength(lastPoint, pickedPosition);
        let midPosition = getMidpoint(lastPoint, pickedPosition);
        activeShapeLabel = addLabel(midPosition, pointLength);
        tempEntities.push(activeShapeLabel);
      }
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

  // 右键点击事件处理函数:结束绘制
  handler.setInputAction(function (click) {
    if (drawing) {
      if (tempPoints.length > 1) {
        if (activeShapeLine) {
          viewer.value.entities.remove(activeShapeLine);
        }
        if (activeShapeLabel) {
          viewer.value.entities.remove(activeShapeLabel);
        }
        tempPoints.pop();
        if (tempPoints.length > 1) {
          let lastPoint = tempPoints[tempPoints.length - 2];
          let currentPoint = tempPoints[tempPoints.length - 1];
          activeShapeLine = drawPolyline([lastPoint, currentPoint]);
          tempEntities.push(activeShapeLine);
          let pointLength = getLength(lastPoint, currentPoint);
          let midPosition = getMidpoint(lastPoint, currentPoint);
          activeShapeLabel = addLabel(midPosition, pointLength);
          tempEntities.push(activeShapeLabel);
        }
      } else {
        drawing = false;
        tempPoints = [];
        if (activeShapeLine) {
          viewer.value.entities.remove(activeShapeLine);
        }
        if (activeShapeLabel) {
          viewer.value.entities.remove(activeShapeLabel);
        }
        if (floatingPoint.value) {
          viewer.value.entities.remove(floatingPoint.value);
        }
        handler.destroy();
        handler = null;
        floatingPoint.value = undefined;
        activeShape.value = undefined;
        activeShapeLine = undefined;
        activeShapeLabel = undefined;
      }
    }
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}

function drawPolygonHandler() {
  let activeShapePoints = [];
  let activeShapeLines = []; // 存储所有的线段
  let activeShape; // 存储当前绘制的面
  let floatingPoint = { value: undefined }; // 用于存储浮动点
  let drawing = false; // 标记当前是否正在绘制

  // 创建场景的HTML canvas元素
  let handler = new Cesium.ScreenSpaceEventHandler(viewer.value.scene.canvas);

  // 鼠标移动事件处理函数:实时更新当前线段
  handler.setInputAction(function (movement) {
    if (drawing && activeShapePoints.length > 0) {
      let ray = viewer.value.camera.getPickRay(movement.endPosition);
      let pickedPosition = viewer.value.scene.globe.pick(ray, viewer.value.scene);
      if (Cesium.defined(pickedPosition)) {
        // 移除当前绘制的临时线段
        if (activeShapeLines.length > activeShapePoints.length - 1) {
          let lastLine = activeShapeLines.pop();
          viewer.value.entities.remove(lastLine);
        }

        // 绘制新的临时线段
        let lastPoint = activeShapePoints[activeShapePoints.length - 1];
        let newLine = drawPolyline([lastPoint, pickedPosition]);
        activeShapeLines.push(newLine);
        tempEntities.push(newLine);

        // 更新面
        if (activeShape) {
          viewer.value.entities.remove(activeShape);
        }
        activeShape = drawPolygon(new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(activeShapePoints.concat([pickedPosition])), false));
        tempEntities.push(activeShape);
      }
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

  // 左键点击事件处理函数:添加点并更新线段
  handler.setInputAction(function (click) {
    let ray = viewer.value.camera.getPickRay(click.position);
    let earthPosition = viewer.value.scene.globe.pick(ray, viewer.value.scene);
    if (Cesium.defined(earthPosition)) {
      if (!drawing) {
        // 开始绘制
        drawing = true;
        activeShapePoints.push(earthPosition);
        floatingPoint.value = drawPoint(earthPosition);
        tempEntities.push(floatingPoint.value);

        // 初始化面
        activeShape = drawPolygon(new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(activeShapePoints), false));
        tempEntities.push(activeShape);
      } else {
        // 继续绘制
        activeShapePoints.push(earthPosition);

        // 绘制新的线段
        if (activeShapePoints.length > 1) {
          let lastPoint = activeShapePoints[activeShapePoints.length - 2];
          let newLine = drawPolyline([lastPoint, earthPosition]);
          activeShapeLines.push(newLine);
          tempEntities.push(newLine);
        }

        // 更新面
        if (activeShape) {
          viewer.value.entities.remove(activeShape);
        }
        activeShape = drawPolygon(new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(activeShapePoints), false));
        tempEntities.push(activeShape);
      }
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  // 右键点击事件处理函数:结束绘制
  handler.setInputAction(function (click) {
    if (drawing) {
      // 移除最后一个线段
      if (activeShapeLines.length > 0) {
        let lastLine = activeShapeLines.pop();
        viewer.value.entities.remove(lastLine);
      }

      // 移除最后一个临时面
      if (activeShape) {
        viewer.value.entities.remove(activeShape);
        activeShape = undefined;
      }

      if (activeShapePoints.length > 2) {
        // 闭合最后一条线
        let lastPoint = activeShapePoints[activeShapePoints.length - 1];
        let firstPoint = activeShapePoints[0];
        let closingLine = drawPolyline([lastPoint, firstPoint]);
        activeShapeLines.push(closingLine);
        tempEntities.push(closingLine);

        // 计算面积并添加标注
        let pointArea = getArea(activeShapePoints);
        addArea(pointArea[0], pointArea[1]);
      } else {
        alert('闭合操作需要至少3个点');
      }

      // 绘制最终的面
      activeShape = drawPolygon(new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(activeShapePoints), false));
      tempEntities.push(activeShape);

      // 清理绘制过程中的临时实体
      if (floatingPoint.value) {
        viewer.value.entities.remove(floatingPoint.value);
      }
      floatingPoint.value = undefined;
      activeShape = undefined;

      // 不销毁绘制好的线和面
      handler.destroy();
      handler = null;
      drawing = false;
    }
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}


onMounted(() => {
  Cesium.Ion.defaultAccessToken = 'CesiumToken';

  viewer.value = new Cesium.Viewer('cesiumContainer', {
    infoBox: false,
    imageryProvider: TDT_YX,
    shouldAnimate: true, // 设置影像图列表
    geocoder: false, // 右上角查询按钮
    shadows: false,
    terrainProvider: new Cesium.EllipsoidTerrainProvider(), // 不使用地形
    animation: false, // 动画小窗口
    baseLayerPicker: false, // 图层选择器
    fullscreenButton: false, // 全屏
    vrButton: false, // vr 按钮
    homeButton: false, // home 按钮
    sceneModePicker: false, // 2D,2.5D,3D 切换
    selectionIndicator: false,
    timeline: false, // 时间轴
    navigationHelpButton: false, // 帮助按钮
    creditContainer: document.createElement('div'), // 隐藏logo
    contextOptions: {
      webgl: {
        alpha: true,
        depth: true,
        stencil: true,
        antialias: true,
        premultipliedAlpha: true,
        preserveDrawingBuffer: true, //通过canvas.toDataURL()实现截图需要将该项设置为true
        failIfMajorPerformanceCaveat: true
      },
      allowTextureFilterAnisotropic: true
    }
  })

  viewer.value.camera.lookAt(
    Cesium.Cartesian3.fromDegrees(121.37200, 31.66248, 1000),
    new Cesium.Cartesian3(0, 0.0, 1000.0)
  )
  viewer.value.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)

});

onBeforeUnmount(() => {
  if (viewer) {
    viewer.value.destroy();
  }
});
</script>

<style>
#cesiumContainer {
  overflow: hidden;
  /* 隐藏滚动条 */
}

#appp,
#cesiumContainer {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.btnContainer {
  position: absolute;
  left: 15px;
  top: 80px;
  padding: 10px 15px;
  /*添加圆角边框*/
  border-radius: 5px;
  border: 1px solid rgba(128, 128, 128, 0.5);
  color: #ffffff;
  background: rgba(0, 0, 0, 0.4);
  box-shadow: 0 4px 8px rgb(128 128 128 / 50%);
  max-width: 300px;
}

button {
  background: transparent;
  border: 1px solid #00d0ffb8;
  color: white;
  padding: 7px 9px;
  border-radius: 3px;
  cursor: pointer;
}

.tip p {
  margin: 2px 0px;
  padding: 5px 1px;
}
</style>
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,作为AI语言模型,我不能提供代码。但我可以给你一些思路和建议。要在cesium使用鼠标动态绘制线,你需要以下步骤: 1. 监听鼠标点击事件,获取鼠标在地球上的位置。 2. 将鼠标点击的位置转换成笛卡尔坐标系。 3. 将笛卡尔坐标系转换成经纬度坐标系。 4. 将经纬度坐标系转换成cesium中的Cartesian3坐标系。 5. 将Cartesian3坐标系坐标添加到cesium的Entity对象中,以便可以动态绘制线。 6. 使用cesium的PolylineGraphics对象设置曲线的样式、颜色等属性。 以下是一个示例代码片段,仅供参考: ```javascript var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); var linePositions = []; handler.setInputAction(function (click) { // 获取鼠标点击位置的笛卡尔坐标系 var cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid); if (cartesian) { // 将笛卡尔坐标系转换成经纬度坐标系 var cartographic = Cesium.Cartographic.fromCartesian(cartesian); // 将经纬度坐标系转换成cesium的Cartesian3坐标系 var position = Cesium.Cartesian3.fromDegrees(cartographic.longitude, cartographic.latitude, cartographic.height); linePositions.push(position); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); var entity = viewer.entities.add({ polyline: { positions: linePositions, width: 5, material: Cesium.Color.RED } }); ``` 这段代码监听了鼠标左键点击事件,获取鼠标点击位置的坐标系,并将其添加到linePositions数组中。然后使用这个数组创建了一个PolylineGraphics对象,设置了线条的颜色和宽度,并将其添加到了cesium的Entity对象中,以便可以动态绘制线
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值