|
@@ -1,27 +1,870 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div class="example">
|
|
|
|
|
- skszk example
|
|
|
|
|
|
|
+ <!-- 时空算子库 -->
|
|
|
|
|
+ <div class="example">
|
|
|
|
|
+ <div class="toolbar">
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="tool-item"
|
|
|
|
|
+ @click="activateDraw('point')"
|
|
|
|
|
+ :class="{ active: currentTool === 'point' }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 绘制点
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="tool-item"
|
|
|
|
|
+ @click="activateDraw('polyline')"
|
|
|
|
|
+ :class="{ active: currentTool === 'polyline' }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 绘制线
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="tool-item"
|
|
|
|
|
+ @click="activateDraw('polygon')"
|
|
|
|
|
+ :class="{ active: currentTool === 'polygon' }"
|
|
|
|
|
+ >
|
|
|
|
|
+ 绘制面
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="tool-item" @click="startHoleDrawing" :class="{ active: isDrawingHole }">
|
|
|
|
|
+ 绘制镂空
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="tool-item" @click="clearAll">清除所有</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div id="skysceneryContainer"></div>
|
|
|
|
|
+ </div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
|
|
+import skszk from "../../api/skszk";
|
|
|
|
|
+// 需要开发出一个时空算子库的示例页面:需要能绘制点线面的工具,且能包装绘制的几何对象传入到后台接口中
|
|
|
export default {
|
|
export default {
|
|
|
- name: "",
|
|
|
|
|
- data() {
|
|
|
|
|
- return {
|
|
|
|
|
|
|
+ name: "SkszkExample",
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ globalvar: systemConfig.example,
|
|
|
|
|
+ currentTool: null,
|
|
|
|
|
+ drawingMode: null,
|
|
|
|
|
+ handler: null,
|
|
|
|
|
+ drawnEntities: [],
|
|
|
|
|
+ geometries: [], // 存储绘制的几何对象
|
|
|
|
|
+ // 绘制状态相关
|
|
|
|
|
+ currentEntity: null, // 当前正在绘制的实体
|
|
|
|
|
+ currentPositions: [], // 当前正在绘制的位置数组
|
|
|
|
|
+ isDrawingHole: false, // 是否正在绘制镂空
|
|
|
|
|
+ currentPolygonEntity: null, // 当前要添加镂空的多边形实体
|
|
|
|
|
+ currentPolygonGeometry: null, // 当前要添加镂空的多边形几何对象
|
|
|
|
|
+ tempEntity: null, // 临时预览实体
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ window.SkySceneryConfig = {};
|
|
|
|
|
+ this.loadScripts();
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ loadScripts() {
|
|
|
|
|
+ let that = this;
|
|
|
|
|
+ SkySceneryConfig = {
|
|
|
|
|
+ authUrl: systemConfig.oauthServiceUrlOrigin,
|
|
|
|
|
+ token: localStorage.getItem("token"),
|
|
|
|
|
+ };
|
|
|
|
|
+ this.addScripts(this.globalvar.scriptObj.main).then(function () {
|
|
|
|
|
+ let arr = that.globalvar.scriptObj.plugins.map(function (src) {
|
|
|
|
|
+ return that.addScripts(src);
|
|
|
|
|
+ });
|
|
|
|
|
+ Promise.all(arr).then(function () {
|
|
|
|
|
+ that.creatMap();
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ addScripts(src) {
|
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
|
+ // 创建一个新的script标签
|
|
|
|
|
+ var script = document.createElement("script");
|
|
|
|
|
+ // 设置script标签的src属性为要引入的JavaScript文件的URL
|
|
|
|
|
+ script.src = src;
|
|
|
|
|
+ // 将script标签添加到页面的head部分或者其他合适的位置
|
|
|
|
|
+ document.head.appendChild(script);
|
|
|
|
|
+ if (script.readyState) {
|
|
|
|
|
+ // IE
|
|
|
|
|
+ script.onreadystatechange = function () {
|
|
|
|
|
+ if (script.readyState === "loaded" || script.readyState === "complete") {
|
|
|
|
|
+ script.onreadystatechange = null;
|
|
|
|
|
+ resolve();
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 其他浏览器
|
|
|
|
|
+ script.onload = function () {
|
|
|
|
|
+ resolve();
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ creatMap() {
|
|
|
|
|
+ window.viewer = new SkyScenery.Viewer("skysceneryContainer", {
|
|
|
|
|
+ animation: false, //是否创建动画小器件,左下角仪表
|
|
|
|
|
+ baseLayerPicker: false, //是否显示图层选择器
|
|
|
|
|
+ imageryProvider: new SkyScenery.SingleTileImageryProvider({
|
|
|
|
|
+ url: (function createColorCanvas(color) {
|
|
|
|
|
+ var width = 1,
|
|
|
|
|
+ height = 1;
|
|
|
|
|
+ var canvas = document.createElement("canvas");
|
|
|
|
|
+ canvas.width = width;
|
|
|
|
|
+ canvas.height = height;
|
|
|
|
|
+ var ctx = canvas.getContext("2d");
|
|
|
|
|
+ ctx.fillStyle = color;
|
|
|
|
|
+ ctx.fillRect(0, 0, width, height);
|
|
|
|
|
+ return canvas.toDataURL();
|
|
|
|
|
+ })("#ffffff00"),
|
|
|
|
|
+ rectangle: SkyScenery.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
|
|
|
|
|
+ }),
|
|
|
|
|
+ fullscreenButton: false, //是否显示全屏按钮
|
|
|
|
|
+ geocoder: false, //是否显示geocoder小器件,右上角查询按钮
|
|
|
|
|
+ homeButton: false, //是否显示Home按钮
|
|
|
|
|
+ infoBox: false, //是否显示信息框
|
|
|
|
|
+ sceneModePicker: false, //是否显示3D/2D选择器
|
|
|
|
|
+ selectionIndicator: false, //是否显示选取指示器组件
|
|
|
|
|
+ timeline: false, //是否显示时间轴
|
|
|
|
|
+ navigationHelpButton: false, //是否显示右上角的帮助按钮
|
|
|
|
|
+ scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
|
|
|
|
|
+ shouldAnimate: false, //是否自动播放
|
|
|
|
|
+ // 性能优化配置
|
|
|
|
|
+ requestRenderMode: true,
|
|
|
|
|
+ maximumRenderTimeChange: Infinity,
|
|
|
|
|
+ preserveDrawingBuffer: false,
|
|
|
|
|
+ useBrowserRecommendedResolution: true,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 添加地图服务
|
|
|
|
|
+ viewer.imageryLayers.addImageryProvider(
|
|
|
|
|
+ new SkyScenery.ArcGisMapServerImageryProvider({
|
|
|
|
|
+ url:
|
|
|
|
|
+ "https://szlszxdt.qpservice.org.cn/internal_map/?servertype=shmap_blue_web&proxyToken=" +
|
|
|
|
|
+ SkySceneryConfig.token,
|
|
|
|
|
+ enablePickFeatures: false, // 禁用要素拾取功能以提高性能
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 定位
|
|
|
|
|
+ viewer.camera.setView({
|
|
|
|
|
+ destination: SkyScenery.Cartesian3.fromDegrees(121.1, 31, 30000.0), // 设置位置
|
|
|
|
|
+ orientation: {
|
|
|
|
|
+ heading: SkyScenery.Math.toRadians(0.0), // 方向
|
|
|
|
|
+ pitch: SkyScenery.Math.toRadians(-90.0), // 倾斜角度
|
|
|
|
|
+ roll: 0,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化绘制处理器
|
|
|
|
|
+ this.initDrawHandler();
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化绘制处理器
|
|
|
|
|
+ initDrawHandler() {
|
|
|
|
|
+ // 创建绘制处理器
|
|
|
|
|
+ this.handler = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 激活绘制工具
|
|
|
|
|
+ activateDraw(type) {
|
|
|
|
|
+ // 取消镂空绘制模式
|
|
|
|
|
+ this.isDrawingHole = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果已经是当前激活的工具,则取消激活
|
|
|
|
|
+ if (this.currentTool === type) {
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 先取消之前的绘制模式
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+
|
|
|
|
|
+ // 设置当前工具
|
|
|
|
|
+ this.currentTool = type;
|
|
|
|
|
+ this.drawingMode = type;
|
|
|
|
|
+
|
|
|
|
|
+ // 重置当前绘制状态
|
|
|
|
|
+ this.resetDrawingState();
|
|
|
|
|
+
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case "point":
|
|
|
|
|
+ this.drawPoint();
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "polyline":
|
|
|
|
|
+ this.drawPolyline();
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "polygon":
|
|
|
|
|
+ this.drawPolygon();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 重置绘制状态
|
|
|
|
|
+ resetDrawingState() {
|
|
|
|
|
+ this.currentPositions = [];
|
|
|
|
|
+ this.currentEntity = null;
|
|
|
|
|
+ // 移除临时预览实体
|
|
|
|
|
+ if (this.tempEntity) {
|
|
|
|
|
+ viewer.entities.remove(this.tempEntity);
|
|
|
|
|
+ this.tempEntity = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 取消绘制模式
|
|
|
|
|
+ deactivateDraw() {
|
|
|
|
|
+ if (this.handler) {
|
|
|
|
|
+ // 移除所有事件监听器
|
|
|
|
|
+ this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+ this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
|
|
+ this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.RIGHT_CLICK);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重置状态
|
|
|
|
|
+ this.resetDrawingState();
|
|
|
|
|
+ this.currentTool = null;
|
|
|
|
|
+ this.drawingMode = null;
|
|
|
|
|
+ this.isDrawingHole = false;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制点
|
|
|
|
|
+ drawPoint() {
|
|
|
|
|
+ const that = this;
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.position);
|
|
|
|
|
+ const position = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (position) {
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(position);
|
|
|
|
|
+ const longitude = SkyScenery.Math.toDegrees(cartographic.longitude);
|
|
|
|
|
+ const latitude = SkyScenery.Math.toDegrees(cartographic.latitude);
|
|
|
|
|
+
|
|
|
|
|
+ // 创建点实体(实时渲染)
|
|
|
|
|
+ const entity = viewer.entities.add({
|
|
|
|
|
+ position: position,
|
|
|
|
|
+ point: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ color: SkyScenery.Color.RED,
|
|
|
|
|
+ pixelSize: 10,
|
|
|
|
|
+ outlineColor: SkyScenery.Color.WHITE,
|
|
|
|
|
+ outlineWidth: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ that.drawnEntities.push(entity);
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为geometry格式并保存
|
|
|
|
|
+ const geometry = {
|
|
|
|
|
+ type: "Point",
|
|
|
|
|
+ coordinates: [longitude, latitude],
|
|
|
|
|
+ };
|
|
|
|
|
+ that.geometries.push(geometry);
|
|
|
|
|
+
|
|
|
|
|
+ console.log("绘制了点:", geometry);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否绘制了两个元素
|
|
|
|
|
+ that.checkAndSendGeometries();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制线
|
|
|
|
|
+ drawPolyline() {
|
|
|
|
|
+ const that = this;
|
|
|
|
|
+
|
|
|
|
|
+ // 鼠标移动时更新临时线(实时渲染预览)
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ if (that.currentPositions.length > 0) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.endPosition);
|
|
|
|
|
+ const endPosition = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (endPosition) {
|
|
|
|
|
+ const tempPositions = [...that.currentPositions, endPosition];
|
|
|
|
|
+
|
|
|
|
|
+ // 更新临时预览实体
|
|
|
|
|
+ if (!that.tempEntity) {
|
|
|
|
|
+ that.tempEntity = viewer.entities.add({
|
|
|
|
|
+ polyline: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ positions: tempPositions,
|
|
|
|
|
+ material: SkyScenery.Color.BLUE.withAlpha(0.5),
|
|
|
|
|
+ width: 3,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ that.tempEntity.polyline.positions = tempPositions;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
|
|
+
|
|
|
|
|
+ // 左键点击添加点
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.position);
|
|
|
|
|
+ const position = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (position) {
|
|
|
|
|
+ that.currentPositions.push(position.clone());
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是第一个点,不需要更新实体
|
|
|
|
|
+ if (that.currentPositions.length > 1) {
|
|
|
|
|
+ // 如果已有实体,更新它
|
|
|
|
|
+ if (that.currentEntity) {
|
|
|
|
|
+ viewer.entities.remove(that.currentEntity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 创建当前实体(实时渲染)
|
|
|
|
|
+ that.currentEntity = viewer.entities.add({
|
|
|
|
|
+ polyline: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ positions: [...that.currentPositions],
|
|
|
|
|
+ material: SkyScenery.Color.BLUE,
|
|
|
|
|
+ width: 3,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+
|
|
|
|
|
+ // 右键点击完成绘制
|
|
|
|
|
+ this.handler.setInputAction(function () {
|
|
|
|
|
+ if (that.currentPositions.length > 1) {
|
|
|
|
|
+ // 移除临时预览实体
|
|
|
|
|
+ if (that.tempEntity) {
|
|
|
|
|
+ viewer.entities.remove(that.tempEntity);
|
|
|
|
|
+ that.tempEntity = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 否则创建线
|
|
|
|
|
+ // 确保当前实体存在
|
|
|
|
|
+ if (!that.currentEntity) {
|
|
|
|
|
+ that.currentEntity = viewer.entities.add({
|
|
|
|
|
+ polyline: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ positions: [...that.currentPositions],
|
|
|
|
|
+ material: SkyScenery.Color.BLUE,
|
|
|
|
|
+ width: 3,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ that.drawnEntities.push(that.currentEntity);
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为geometry格式并保存
|
|
|
|
|
+ const coordinates = [];
|
|
|
|
|
+ that.currentPositions.forEach((pos) => {
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(pos);
|
|
|
|
|
+ coordinates.push([
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.longitude),
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.latitude),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const geometry = {
|
|
|
|
|
+ type: "LineString",
|
|
|
|
|
+ coordinates: coordinates,
|
|
|
|
|
+ };
|
|
|
|
|
+ that.geometries.push(geometry);
|
|
|
|
|
+
|
|
|
|
|
+ console.log("绘制了线:", geometry);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否绘制了两个元素
|
|
|
|
|
+ that.checkAndSendGeometries();
|
|
|
|
|
+
|
|
|
|
|
+ // 取消当前绘制模式
|
|
|
|
|
+ that.deactivateDraw();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.RIGHT_CLICK);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制面
|
|
|
|
|
+ drawPolygon() {
|
|
|
|
|
+ const that = this;
|
|
|
|
|
+
|
|
|
|
|
+ // 鼠标移动时更新临时面(实时渲染预览)
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ if (that.currentPositions.length > 0) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.endPosition);
|
|
|
|
|
+ const endPosition = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (endPosition) {
|
|
|
|
|
+ // 为了预览效果,临时闭合多边形
|
|
|
|
|
+ const tempPositions = [
|
|
|
|
|
+ ...that.currentPositions,
|
|
|
|
|
+ endPosition,
|
|
|
|
|
+ that.currentPositions[0],
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // 更新临时预览实体
|
|
|
|
|
+ if (!that.tempEntity) {
|
|
|
|
|
+ that.tempEntity = viewer.entities.add({
|
|
|
|
|
+ polygon: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ hierarchy: new SkyScenery.PolygonHierarchy(tempPositions),
|
|
|
|
|
+ material: new SkyScenery.ColorMaterialProperty(
|
|
|
|
|
+ new SkyScenery.Color(0, 0, 1, 0.2)
|
|
|
|
|
+ ),
|
|
|
|
|
+ outline: true,
|
|
|
|
|
+ outlineColor: SkyScenery.Color.BLUE.withAlpha(0.5),
|
|
|
|
|
+ outlineWidth: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ that.tempEntity.polygon.hierarchy = new SkyScenery.PolygonHierarchy(
|
|
|
|
|
+ tempPositions
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
|
|
+
|
|
|
|
|
+ // 左键点击添加点
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.position);
|
|
|
|
|
+ const position = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (position) {
|
|
|
|
|
+ // 检查是否点击了第一个点附近(自动闭合)
|
|
|
|
|
+ if (
|
|
|
|
|
+ that.currentPositions.length > 2 &&
|
|
|
|
|
+ that.isPositionNearFirst(position, that.currentPositions[0])
|
|
|
|
|
+ ) {
|
|
|
|
|
+ // 完成多边形绘制
|
|
|
|
|
+ that.finalizePolygonDrawing();
|
|
|
|
|
+ that.deactivateDraw();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ that.currentPositions.push(position.clone());
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有足够的点,更新多边形实体(实时渲染)
|
|
|
|
|
+ if (that.currentPositions.length > 2) {
|
|
|
|
|
+ // 闭合多边形
|
|
|
|
|
+ const closedPositions = [...that.currentPositions, that.currentPositions[0]];
|
|
|
|
|
+ // 如果已有实体,更新它
|
|
|
|
|
+ if (that.currentEntity) {
|
|
|
|
|
+ viewer.entities.remove(that.currentEntity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 创建当前实体
|
|
|
|
|
+ that.currentEntity = viewer.entities.add({
|
|
|
|
|
+ polygon: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ hierarchy: new SkyScenery.PolygonHierarchy(closedPositions),
|
|
|
|
|
+ material: new SkyScenery.ColorMaterialProperty(
|
|
|
|
|
+ new SkyScenery.Color(0, 0, 1, 0.3)
|
|
|
|
|
+ ),
|
|
|
|
|
+ outline: true,
|
|
|
|
|
+ outlineColor: SkyScenery.Color.BLUE,
|
|
|
|
|
+ outlineWidth: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+
|
|
|
|
|
+ // 右键点击完成绘制
|
|
|
|
|
+ this.handler.setInputAction(function () {
|
|
|
|
|
+ if (that.currentPositions.length > 2) {
|
|
|
|
|
+ that.finalizePolygonDrawing();
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否绘制了两个元素
|
|
|
|
|
+ that.checkAndSendGeometries();
|
|
|
|
|
+
|
|
|
|
|
+ // 取消当前绘制模式
|
|
|
|
|
+ that.deactivateDraw();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.RIGHT_CLICK);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 完成多边形绘制
|
|
|
|
|
+ finalizePolygonDrawing() {
|
|
|
|
|
+ // 移除临时预览实体
|
|
|
|
|
+ if (this.tempEntity) {
|
|
|
|
|
+ viewer.entities.remove(this.tempEntity);
|
|
|
|
|
+ this.tempEntity = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 确保多边形是闭合的
|
|
|
|
|
+ let closedPositions = [...this.currentPositions];
|
|
|
|
|
+ // 创建最终的多边形实体
|
|
|
|
|
+ if (this.currentEntity) {
|
|
|
|
|
+ viewer.entities.remove(this.currentEntity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.currentEntity = viewer.entities.add({
|
|
|
|
|
+ polygon: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ hierarchy: new SkyScenery.PolygonHierarchy(closedPositions),
|
|
|
|
|
+ material: new SkyScenery.ColorMaterialProperty(
|
|
|
|
|
+ new SkyScenery.Color(0, 0, 1, 0.3)
|
|
|
|
|
+ ),
|
|
|
|
|
+ outline: true,
|
|
|
|
|
+ outlineColor: SkyScenery.Color.BLUE,
|
|
|
|
|
+ outlineWidth: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ this.drawnEntities.push(this.currentEntity);
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为geometry格式并保存(不包含重复的最后一个点)
|
|
|
|
|
+ const coordinates = [];
|
|
|
|
|
+ const mainRing = [];
|
|
|
|
|
+ for (let i = 0; i < closedPositions.length; i++) {
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(closedPositions[i]);
|
|
|
|
|
+ mainRing.push([
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.longitude),
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.latitude),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(closedPositions[0]);
|
|
|
|
|
+ mainRing.push([
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.longitude),
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.latitude),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ coordinates.push(mainRing);
|
|
|
|
|
+
|
|
|
|
|
+ const geometry = {
|
|
|
|
|
+ type: "Polygon",
|
|
|
|
|
+ coordinates: coordinates, // GeoJSON格式
|
|
|
|
|
+ holes: [], // 用于存储镂空区域
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 保存实体和几何对象的关联
|
|
|
|
|
+ this.currentEntity.geometryRef = geometry;
|
|
|
|
|
+ this.geometries.push(geometry);
|
|
|
|
|
+
|
|
|
|
|
+ console.log("绘制了面:", geometry);
|
|
|
},
|
|
},
|
|
|
- mounted() {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 开始绘制镂空
|
|
|
|
|
+ startHoleDrawing() {
|
|
|
|
|
+ // 如果已经在绘制镂空,则取消
|
|
|
|
|
+ if (this.isDrawingHole) {
|
|
|
|
|
+ this.isDrawingHole = false;
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 取消其他绘制模式
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+
|
|
|
|
|
+ // 设置为镂空绘制模式
|
|
|
|
|
+ this.isDrawingHole = true;
|
|
|
|
|
+
|
|
|
|
|
+ console.log("请点击一个多边形以添加镂空");
|
|
|
|
|
+
|
|
|
|
|
+ // 设置点击事件选择多边形
|
|
|
|
|
+ const that = this;
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ // 拾取实体
|
|
|
|
|
+ const pickedObject = viewer.scene.pick(event.position);
|
|
|
|
|
+ if (pickedObject && pickedObject.id && pickedObject.id.polygon) {
|
|
|
|
|
+ const polygonEntity = pickedObject.id;
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否有对应的几何对象
|
|
|
|
|
+ if (polygonEntity.geometryRef && polygonEntity.geometryRef.type === "Polygon") {
|
|
|
|
|
+ that.currentPolygonEntity = polygonEntity;
|
|
|
|
|
+ that.currentPolygonGeometry = polygonEntity.geometryRef;
|
|
|
|
|
+
|
|
|
|
|
+ console.log("已选择多边形,现在绘制镂空区域");
|
|
|
|
|
+
|
|
|
|
|
+ // 开始绘制镂空区域(使用多边形绘制逻辑,但最后添加为镂空)
|
|
|
|
|
+ that.resetDrawingState();
|
|
|
|
|
+ that.drawHole();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log("选择的不是有效的多边形");
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log("未选中任何多边形");
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
},
|
|
},
|
|
|
- methods: {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制镂空区域
|
|
|
|
|
+ drawHole() {
|
|
|
|
|
+ const that = this;
|
|
|
|
|
+
|
|
|
|
|
+ // 清除之前的事件
|
|
|
|
|
+ this.handler.removeInputAction(SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+
|
|
|
|
|
+ // 鼠标移动时更新临时镂空区域
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ if (that.currentPositions.length > 0) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.endPosition);
|
|
|
|
|
+ const endPosition = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (endPosition) {
|
|
|
|
|
+ // 为了预览效果,临时闭合多边形
|
|
|
|
|
+ const tempPositions = [
|
|
|
|
|
+ ...that.currentPositions,
|
|
|
|
|
+ endPosition,
|
|
|
|
|
+ that.currentPositions[0],
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ // 更新临时预览实体
|
|
|
|
|
+ if (!that.tempEntity) {
|
|
|
|
|
+ that.tempEntity = viewer.entities.add({
|
|
|
|
|
+ polygon: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ hierarchy: new SkyScenery.PolygonHierarchy(tempPositions),
|
|
|
|
|
+ material: new SkyScenery.ColorMaterialProperty(
|
|
|
|
|
+ new SkyScenery.Color(1, 0, 0, 0.3)
|
|
|
|
|
+ ),
|
|
|
|
|
+ outline: true,
|
|
|
|
|
+ outlineColor: SkyScenery.Color.RED,
|
|
|
|
|
+ outlineWidth: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ that.tempEntity.polygon.hierarchy = new SkyScenery.PolygonHierarchy(
|
|
|
|
|
+ tempPositions
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
|
|
+
|
|
|
|
|
+ // 左键点击添加点
|
|
|
|
|
+ this.handler.setInputAction(function (event) {
|
|
|
|
|
+ const ray = viewer.camera.getPickRay(event.position);
|
|
|
|
|
+ const position = viewer.scene.globe.pick(ray, viewer.scene);
|
|
|
|
|
+
|
|
|
|
|
+ if (position) {
|
|
|
|
|
+ // 检查是否点击了第一个点附近(自动闭合)
|
|
|
|
|
+ if (
|
|
|
|
|
+ that.currentPositions.length > 2 &&
|
|
|
|
|
+ that.isPositionNearFirst(position, that.currentPositions[0])
|
|
|
|
|
+ ) {
|
|
|
|
|
+ // 完成镂空绘制
|
|
|
|
|
+ that.finalizeHoleDrawing();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ that.currentPositions.push(position.clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
|
+
|
|
|
|
|
+ // 右键点击完成绘制
|
|
|
|
|
+ this.handler.setInputAction(function () {
|
|
|
|
|
+ if (that.currentPositions.length > 2) {
|
|
|
|
|
+ that.finalizeHoleDrawing();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.RIGHT_CLICK);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 完成镂空绘制
|
|
|
|
|
+ finalizeHoleDrawing() {
|
|
|
|
|
+ // 移除临时预览实体
|
|
|
|
|
+ if (this.tempEntity) {
|
|
|
|
|
+ viewer.entities.remove(this.tempEntity);
|
|
|
|
|
+ this.tempEntity = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 确保镂空区域是闭合的
|
|
|
|
|
+ let closedPositions = [...this.currentPositions];
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为几何坐标
|
|
|
|
|
+ const holeCoordinates = [];
|
|
|
|
|
+ for (let i = 0; i < closedPositions.length; i++) {
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(closedPositions[i]);
|
|
|
|
|
+ holeCoordinates.push([
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.longitude),
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.latitude),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const cartographic = SkyScenery.Cartographic.fromCartesian(closedPositions[0]);
|
|
|
|
|
+ holeCoordinates.push([
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.longitude),
|
|
|
|
|
+ SkyScenery.Math.toDegrees(cartographic.latitude),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ // 添加到几何对象的镂空数组
|
|
|
|
|
+ if (!this.currentPolygonGeometry.holes) {
|
|
|
|
|
+ this.currentPolygonGeometry.holes = [];
|
|
|
|
|
+ }
|
|
|
|
|
+ this.currentPolygonGeometry.holes.push(holeCoordinates);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新多边形的层级结构以包含镂空
|
|
|
|
|
+ const polygonHierarchy = this.buildPolygonHierarchyWithHoles(
|
|
|
|
|
+ this.currentPolygonGeometry.coordinates[0],
|
|
|
|
|
+ this.currentPolygonGeometry.holes
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 更新实体显示
|
|
|
|
|
+ this.currentPolygonEntity.polygon.hierarchy = polygonHierarchy;
|
|
|
|
|
+
|
|
|
|
|
+ console.log("添加了镂空区域:", holeCoordinates);
|
|
|
|
|
+ console.log("更新后的多边形几何:", this.currentPolygonGeometry);
|
|
|
|
|
+
|
|
|
|
|
+ // 重置状态
|
|
|
|
|
+ this.resetDrawingState();
|
|
|
|
|
+ this.isDrawingHole = false;
|
|
|
|
|
+ this.currentPolygonEntity = null;
|
|
|
|
|
+ this.currentPolygonGeometry = null;
|
|
|
|
|
+
|
|
|
|
|
+ // 取消绘制模式
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 构建包含镂空的多边形层级结构
|
|
|
|
|
+ buildPolygonHierarchyWithHoles(outerRing, holes) {
|
|
|
|
|
+ // 将外部环转换为Cartesian3数组
|
|
|
|
|
+ const outerRingPositions = [];
|
|
|
|
|
+ outerRing.forEach((coord) => {
|
|
|
|
|
+ const cartesian = SkyScenery.Cartesian3.fromDegrees(coord[0], coord[1]);
|
|
|
|
|
+ outerRingPositions.push(cartesian);
|
|
|
|
|
+ });
|
|
|
|
|
+ // 闭合外部环
|
|
|
|
|
+ outerRingPositions.push(outerRingPositions[0]);
|
|
|
|
|
+
|
|
|
|
|
+ // 创建层级结构
|
|
|
|
|
+ const hierarchy = new SkyScenery.PolygonHierarchy(outerRingPositions);
|
|
|
|
|
+
|
|
|
|
|
+ // 添加镂空
|
|
|
|
|
+ if (holes && holes.length > 0) {
|
|
|
|
|
+ hierarchy.holes = holes.map((hole) => {
|
|
|
|
|
+ const holePositions = [];
|
|
|
|
|
+ hole.forEach((coord) => {
|
|
|
|
|
+ const cartesian = SkyScenery.Cartesian3.fromDegrees(coord[0], coord[1]);
|
|
|
|
|
+ holePositions.push(cartesian);
|
|
|
|
|
+ });
|
|
|
|
|
+ // 闭合镂空环
|
|
|
|
|
+ holePositions.push(holePositions[0]);
|
|
|
|
|
+ return new SkyScenery.PolygonHierarchy(holePositions);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return hierarchy;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 检查点是否靠近第一个点
|
|
|
|
|
+ isPositionNearFirst(position, firstPosition, tolerance = 10) {
|
|
|
|
|
+ // 单位:米
|
|
|
|
|
+ const distance = SkyScenery.Cartesian3.distance(position, firstPosition);
|
|
|
|
|
+ return distance < tolerance;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否绘制了两个元素,如果是则调用后台接口
|
|
|
|
|
+ checkAndSendGeometries() {
|
|
|
|
|
+ if (this.geometries.length >= 2) {
|
|
|
|
|
+ console.log("已绘制两个或更多几何元素,准备发送到后台");
|
|
|
|
|
+ this.sendGeometriesToBackend();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 发送几何数据到后台接口
|
|
|
|
|
+ sendGeometriesToBackend() {
|
|
|
|
|
+ // 这里使用axios发送请求,需要确保项目中已安装并导入axios
|
|
|
|
|
+ const geometriesToSend = this.geometries.slice(0, 2); // 只取前两个几何元素
|
|
|
|
|
+ let FeatureCollectionFeatures = [];
|
|
|
|
|
+ geometriesToSend.forEach((item) => {
|
|
|
|
|
+ FeatureCollectionFeatures.push({
|
|
|
|
|
+ type: "Feature",
|
|
|
|
|
+ properties: {},
|
|
|
|
|
+ geometry: {
|
|
|
|
|
+ type: item.type,
|
|
|
|
|
+ coordinates: item.coordinates,
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ // 构造请求数据
|
|
|
|
|
+ const requestData = {
|
|
|
|
|
+ type: "FeatureCollection",
|
|
|
|
|
+ features: FeatureCollectionFeatures,
|
|
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ console.log("发送到后台的数据:", requestData);
|
|
|
|
|
+
|
|
|
|
|
+ // 示例:使用axios发送POST请求
|
|
|
|
|
+ // 这里需要替换为实际的后台接口URL
|
|
|
|
|
+ const apiUrl = "/api/geometry/submit"; // 假设的接口地址
|
|
|
|
|
+
|
|
|
|
|
+ // 实际项目中使用以下代码发送请求
|
|
|
|
|
+ skszk
|
|
|
|
|
+ .topology(requestData)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: res.message,
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ });
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((error) => {
|
|
|
|
|
+ console.error("后台接口调用失败:", error);
|
|
|
|
|
+ });
|
|
|
|
|
+ // 由于是示例,这里只打印日志
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `假设已调用后台接口 ${apiUrl},发送了 ${geometriesToSend.length} 个几何元素`
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 清除所有绘制的元素
|
|
|
|
|
+ clearAll() {
|
|
|
|
|
+ // 移除所有实体
|
|
|
|
|
+ this.drawnEntities.forEach((entity) => {
|
|
|
|
|
+ viewer.entities.remove(entity);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 清空数组
|
|
|
|
|
+ this.drawnEntities = [];
|
|
|
|
|
+ this.geometries = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 取消当前绘制模式
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+
|
|
|
|
|
+ console.log("已清除所有绘制的元素");
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ beforeUnmount() {
|
|
|
|
|
+ // 组件卸载前清理资源
|
|
|
|
|
+ this.deactivateDraw();
|
|
|
|
|
+ if (this.handler) {
|
|
|
|
|
+ this.handler.destroy();
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
};
|
|
};
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
|
-.container {
|
|
|
|
|
- width: 1920px;
|
|
|
|
|
- margin: 0 auto;
|
|
|
|
|
|
|
+.example {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.toolbar {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 20px;
|
|
|
|
|
+ left: 20px;
|
|
|
|
|
+ z-index: 1000;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.9);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tool-item {
|
|
|
|
|
+ padding: 10px 20px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ user-select: none;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tool-item:hover {
|
|
|
|
|
+ background: #f0f0f0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.tool-item.active {
|
|
|
|
|
+ background: #409eff;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#skysceneryContainer {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+</style>
|