|
|
@@ -0,0 +1,1406 @@
|
|
|
+<template>
|
|
|
+ <div id="controlPanelBox">
|
|
|
+ <div>
|
|
|
+ <div class="sceneNameBox">
|
|
|
+ <div class="">
|
|
|
+ 场景名称:
|
|
|
+ <el-cascader
|
|
|
+ placeholder="试试搜索:距离"
|
|
|
+ :options="SceneList"
|
|
|
+ :props="{ expandTrigger: 'hover' }"
|
|
|
+ @change="handleChange"
|
|
|
+ filterable
|
|
|
+ ></el-cascader>
|
|
|
+ <el-tooltip
|
|
|
+ v-if="SceneValue && SceneRule[SceneValue].functionalDefinition"
|
|
|
+ :content="SceneRule[SceneValue].functionalDefinition"
|
|
|
+ placement="bottom"
|
|
|
+ effect="light"
|
|
|
+ >
|
|
|
+ <el-icon
|
|
|
+ style="margin-left: 1rem; width: 1rem; height: 1rem"
|
|
|
+ v-show="SceneValue && SceneRule[SceneValue].functionalDefinition"
|
|
|
+ ><QuestionFilled
|
|
|
+ /></el-icon>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-button type="primary" @click="sendGeometriesToBackend"
|
|
|
+ >发送<i class="el-icon-s-promotion el-icon--right"></i
|
|
|
+ ></el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-divider></el-divider>
|
|
|
+ <div>
|
|
|
+ 参数个数:{{
|
|
|
+ SceneValue && SceneRule[SceneValue] ? SceneRule[SceneValue].numberOf : ""
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 参数类型:{{
|
|
|
+ SceneValue && SceneRule[SceneValue] ? SceneRule[SceneValue].elementTypes : ""
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 接口地址:{{
|
|
|
+ SceneValue && SceneRule[SceneValue] ? SceneRule[SceneValue].apiUrl : ""
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-divider></el-divider>
|
|
|
+ <div>
|
|
|
+ <!-- 元素文本渲染和操作区域 -->
|
|
|
+ <el-tabs tab-position="left" style="height: calc(100vh - 250px)" class="demo-tabs">
|
|
|
+ <el-tab-pane label="入参">
|
|
|
+ <json-viewer
|
|
|
+ :value="jsonData"
|
|
|
+ :editable="true"
|
|
|
+ :preview-mode="false"
|
|
|
+ style="
|
|
|
+ pointer-events: auto;
|
|
|
+ max-height: calc(100vh - 250px) !important;
|
|
|
+ overflow-y: scroll !important;
|
|
|
+ "
|
|
|
+ copyable
|
|
|
+ @input="handleJsonInput"
|
|
|
+ />
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="返回">
|
|
|
+ <json-viewer
|
|
|
+ :value="backData"
|
|
|
+ :editable="true"
|
|
|
+ :preview-mode="false"
|
|
|
+ style="
|
|
|
+ pointer-events: auto;
|
|
|
+ max-height: calc(100vh - 250px) !important;
|
|
|
+ overflow-y: scroll !important;
|
|
|
+ "
|
|
|
+ copyable
|
|
|
+ /></el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+ <!-- 绘制工具栏 -->
|
|
|
+ <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>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import skszk from "../../api/skszk";
|
|
|
+// 控制面板
|
|
|
+export default {
|
|
|
+ name: "ControlPanel",
|
|
|
+ // 2. 接收父组件传递的 props(单向数据流,子组件不能直接修改)
|
|
|
+ props: {
|
|
|
+ btnText: {
|
|
|
+ type: String, // 类型限制
|
|
|
+ default: "默认按钮", // 默认值
|
|
|
+ required: false, // 是否必传
|
|
|
+ },
|
|
|
+ showCount: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // 请求参数
|
|
|
+ jsonData: {},
|
|
|
+ // 返回参数
|
|
|
+ backData: {},
|
|
|
+ // 当前场景值
|
|
|
+ SceneValue: "",
|
|
|
+ // 场景列表
|
|
|
+ SceneList: [
|
|
|
+ {
|
|
|
+ value: "1.5.1",
|
|
|
+ label: "1.5.1拓扑计算",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.1.1",
|
|
|
+ label: "点线面拓扑关系",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2",
|
|
|
+ label: "1.5.2空间量算",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.2.1",
|
|
|
+ label: "两点欧氏距离",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.2",
|
|
|
+ label: "点到线的最短距离",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.3",
|
|
|
+ label: "点到面的最短距离",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.4",
|
|
|
+ label: "面到面的最短距离",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.5",
|
|
|
+ label: "折线距离(累加线段长度)",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.6",
|
|
|
+ label: "平面面积、不规则面面积",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.7",
|
|
|
+ label: "曲面面积,考虑地形起伏",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.8",
|
|
|
+ label: "单点高程查询",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.9",
|
|
|
+ label: "两点高程差",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.2.10",
|
|
|
+ label: "区域高程统计",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.3",
|
|
|
+ label: "1.5.3几何运算",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.3.1",
|
|
|
+ label: "并集运算",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.3.2",
|
|
|
+ label: "交集运算",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.3.3",
|
|
|
+ label: "差集运算",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.3.4",
|
|
|
+ label: "几何参数计算",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.4",
|
|
|
+ label: "1.5.4关系分析",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.4.1",
|
|
|
+ label: "邻接关系分析",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.4.2",
|
|
|
+ label: "包含关系分析",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.4.3",
|
|
|
+ label: "相交关系分析",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.4.4",
|
|
|
+ label: "相离关系分析",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.4.5",
|
|
|
+ label: "近邻关系分析",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.5",
|
|
|
+ label: "1.5.5非空间数据转换",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.5.1",
|
|
|
+ label: "非空间数据转空间数据",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.6",
|
|
|
+ label: "1.5.6坐标转换",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.6.1",
|
|
|
+ label: "单点的坐标转换接口",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.7",
|
|
|
+ label: "1.5.7时空数据格式转换",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ value: "1.5.7.1",
|
|
|
+ label: "文件格式转换",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "1.5.7.2",
|
|
|
+ label: "转换文件下载",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 场景规则
|
|
|
+ SceneRule: {
|
|
|
+ "1.5.1.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "拓扑计算功能聚焦于深度解析大批量数据的点、线、面之间的拓扑关系,能够精准判断点与线、面的位置关系,以及线、面之间的相交、平行、邻接、包含等复杂状态。借助四叉树、R 树等精心设计的数据结构,结合 Douglas - Peucker 等高效算法,确保在处理海量空间数据时,也能快速且准确地输出分析结果。",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/topology/geoJsonToGeoJson",
|
|
|
+ },
|
|
|
+ "1.5.2.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "计算两个点要素之间的最短空间距离,单位支持米、千米。操作逻辑为:用户通过接口输入两点经纬度坐标,或在系统内部地图上点击选择两点,系统基于坐标系参数计算欧氏距离。例如:计算青浦区某学校与社区卫生服务中心的直线距离,用于公共服务覆盖半径评估;计算两个监测点位的直线距离,用于监测设备信号覆盖范围判断。",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "point"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "METER",
|
|
|
+ label: "米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "KILOMETER",
|
|
|
+ label: "千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/pointToPoint",
|
|
|
+ },
|
|
|
+ "1.5.2.2": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition: "计算点和线要素之间的最短空间距离,单位支持米、千米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "METER",
|
|
|
+ label: "米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "KILOMETER",
|
|
|
+ label: "千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/pointToLine",
|
|
|
+ },
|
|
|
+ "1.5.2.3": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition: "计算点和面要素之间的最短空间距离,单位支持米、千米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polygon"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "METER",
|
|
|
+ label: "米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "KILOMETER",
|
|
|
+ label: "千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/pointToPolygon",
|
|
|
+ },
|
|
|
+ "1.5.2.4": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition: "计算两个面要素之间的最短空间距离,单位支持米、千米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon", "polygon"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "METER",
|
|
|
+ label: "米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "KILOMETER",
|
|
|
+ label: "千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/PolygonToPolygon",
|
|
|
+ },
|
|
|
+ "1.5.2.5": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition: "计算多条线段组成的折线总长度,单位支持米、千米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polyline"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "METER",
|
|
|
+ label: "米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "KILOMETER",
|
|
|
+ label: "千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/calculatePolylineDistance",
|
|
|
+ },
|
|
|
+ "1.5.2.6": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "计算面要素在二维平面上的投影面积,单位支持平方米、公顷、平方千米切换",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "SQUARE_METER",
|
|
|
+ label: "平方米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "HECTARE",
|
|
|
+ label: "公顷",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "SQUARE_KILOMETER",
|
|
|
+ label: "平方千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/calculatePlaneAreaInGeometry",
|
|
|
+ },
|
|
|
+ "1.5.2.7": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "结合 DEM 高程数据,计算面要素在三维地形上的实际曲面面积(考虑地形起伏),精度依赖 DEM 数据分辨率。,单位支持平方米、公顷、平方千米切换",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 单位
|
|
|
+ unit: [
|
|
|
+ {
|
|
|
+ value: "SQUARE_METER",
|
|
|
+ label: "平方米",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "HECTARE",
|
|
|
+ label: "公顷",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "SQUARE_KILOMETER",
|
|
|
+ label: "平方千米",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/calculateSurfaceAreaInGeometry",
|
|
|
+ },
|
|
|
+ "1.5.2.8": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "查询单个点要素的海拔高度(基于 CGCS2000 大地高程基准),单位为米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/getPointElevationInGeometry",
|
|
|
+ },
|
|
|
+ "1.5.2.9": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "计算两个点要素之间的高程差值,支持正负值显示(正值表示前者高于后者,负值相反)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "point"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/calculateElevationDiffInGeometry",
|
|
|
+ },
|
|
|
+ "1.5.2.10": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "查询单个面要素的海拔高度(基于 CGCS2000 大地高程基准),单位为米",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatialMeasure/calculateAreaElevationStatsInGeometry",
|
|
|
+ },
|
|
|
+ "1.5.3.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "将两个或多个不重叠 / 部分重叠的面要素,合并为一个连续的新面要素(消除重叠部分,保留所有要素的覆盖范围)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 元素个数
|
|
|
+ minNumberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/geometry/union",
|
|
|
+ },
|
|
|
+ "1.5.3.2": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "提取两个或多个面要素之间的重叠区域,生成新的面要素(仅保留所有要素共同覆盖的范围)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 元素个数
|
|
|
+ minNumberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/geometry/intersection",
|
|
|
+ },
|
|
|
+ "1.5.3.3": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "以一个面要素(称为 “源面”)为基础,减去与另一个面要素(称为 “裁剪面”)的重叠区域,生成新的面要素(保留源面中未被裁剪面覆盖的部分)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon"],
|
|
|
+ // 元素个数
|
|
|
+ minNumberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/geometry/difference",
|
|
|
+ },
|
|
|
+ "1.5.3.4": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "计算面要素的参数(面积、周长、中心坐标、最小外接矩形等)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 1,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/geometry/parameters",
|
|
|
+ },
|
|
|
+ "1.5.4.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "判断两个面要素是否 “边界接触但不重叠”,且距离小于等于自定义阈值(默认 1 米,可通过接口参数调整),核心用于 “相邻区域联动” 场景",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["polygon", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/relationAnalys/adjacent",
|
|
|
+ },
|
|
|
+ "1.5.4.2": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "判断一个要素(含点、线、面)是否完全位于另一个面要素内部,且无任何部分超出,核心用于 “归属界定” 场景",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/relationAnalys/include",
|
|
|
+ },
|
|
|
+ "1.5.4.3": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "判断两个要素(点与线、点与面、线与线、线与面、面与面)是否存在空间重叠(含部分重叠),核心用于 “交叉影响” 场景",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/relationAnalys/intersect",
|
|
|
+ },
|
|
|
+ "1.5.4.4": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "判断两个要素(点、线、面)之间无任何空间接触(含边界接触),且最小距离大于自定义阈值(默认 10 米,可通过接口参数调整),核心用于 “无关联排除” 场景",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/relationAnalys/parting",
|
|
|
+ },
|
|
|
+ "1.5.4.5": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "以一个核心要素(点、线、面)为中心,按自定义半径(如 500 米、1 千米)划定范围,查询范围内所有目标要素(如设施、地块、道路),核心用于 “资源覆盖范围” 场景。",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["point", "polyline", "polygon"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 2,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/relationAnalys/neighbor",
|
|
|
+ },
|
|
|
+ "1.5.5.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "非空间数据转空间数据功能支持常见格式的非空间数据转换,如 CSV、Excel 表格数据等。通过与地理编码服务紧密结合,关联空间参考信息(如地址、行政区域、关联 ID),转换为带坐标的空间要素(点、线、面),将表格中的地址、坐标等信息转换为具有空间位置的矢量数据的功能,并依据用户设定规则赋予属性信息。核心解决 “业务数据与地图引擎关联” 的问题,实现 “数据可视化” 与 “空间分析” 的联动。在智慧城市建设中,整合人口、环境、交通等多源非空间数据,实现数据融合分析,为城市精细化管理提供数据支持;在地理大数据分析中,拓展非空间数据的应用维度,挖掘数据潜在价值。",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["file"],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 0,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/nonStandardToStandard/importFile",
|
|
|
+ },
|
|
|
+ "1.5.6.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "坐标转换是基于青浦区三维数字底板的坐标系统(SH2000投影坐标系),将空间要素的坐标在不同坐标系之间进行转换的功能,包括地理坐标系(如 WGS84、上海 2000 等)和投影坐标系(如高斯 - 克吕格投影、UTM 投影等)",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["lon", "lat"],
|
|
|
+ inPrj: [
|
|
|
+ {
|
|
|
+ value: "WGS84",
|
|
|
+ label: "WGS84",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "SH2000",
|
|
|
+ label: "SH2000",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "UTM",
|
|
|
+ label: "UTM",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ outPrj: [
|
|
|
+ {
|
|
|
+ value: "WGS84",
|
|
|
+ label: "WGS84",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "SH2000",
|
|
|
+ label: "SH2000",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "UTM",
|
|
|
+ label: "UTM",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 0,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/coordinateSystemTransformation/pointTransformation",
|
|
|
+ },
|
|
|
+ "1.5.7.1": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition:
|
|
|
+ "时空数据格式转换是将青浦区三维数字底板中的时空数据(含空间坐标与时间属性的数据,如轨迹数据、时序监测数据),在不同标准数据格式之间进行转换的功能,如 Shapefile、GeoJSON、KML、NetCDF 等。核心支持 “矢量数据格式转换”“栅格数据格式转换”“时空轨迹数据格式转换” 三类转换,确保数据能在不同 GIS 软件、不同应用系统之间兼容流转,不同部门、不同系统之间顺利读取和处理时空数据;在大数据存储和管理时,根据不同应用场景和存储需求,选择合适的数据格式。提高数据存储和访问效率,满足数据共享、分析、展示的多场景需求。",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: ["file", "outFileType", "lonKey", "latKey"],
|
|
|
+ outFileType: [
|
|
|
+ {
|
|
|
+ value: "geoJson",
|
|
|
+ label: "geoJson",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "shp",
|
|
|
+ label: "shp",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "csv",
|
|
|
+ label: "csv",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "xlsx",
|
|
|
+ label: "xlsx",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 0,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatiotemporal_data_format_conversion/fileFormatConversion",
|
|
|
+ },
|
|
|
+ "1.5.7.2": {
|
|
|
+ // 功能描述
|
|
|
+ functionalDefinition: "转换文件下载",
|
|
|
+ // 元素类型
|
|
|
+ elementTypes: [],
|
|
|
+ // 元素个数
|
|
|
+ numberOf: 0,
|
|
|
+ // 后台接口路径
|
|
|
+ apiUrl: "/spatiotemporal_data_format_conversion/downloadFile",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ currentTool: null,
|
|
|
+ drawingMode: null,
|
|
|
+ handler: null,
|
|
|
+ drawnEntities: [],
|
|
|
+ geometries: [], // 存储绘制的几何对象
|
|
|
+ // 绘制状态相关
|
|
|
+ currentEntity: null, // 当前正在绘制的实体
|
|
|
+ currentPositions: [], // 当前正在绘制的位置数组
|
|
|
+ isDrawingHole: false, // 是否正在绘制镂空
|
|
|
+ currentPolygonEntity: null, // 当前要添加镂空的多边形实体
|
|
|
+ currentPolygonGeometry: null, // 当前要添加镂空的多边形几何对象
|
|
|
+ tempEntity: null, // 临时预览实体
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {},
|
|
|
+
|
|
|
+ beforeUnmount() {
|
|
|
+ // 组件卸载前清理资源
|
|
|
+ this.deactivateDraw();
|
|
|
+ if (this.handler) {
|
|
|
+ this.handler.destroy();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleJsonInput(value) {
|
|
|
+ this.jsonData = JSON.parse(value);
|
|
|
+ },
|
|
|
+ handleChange(emit) {
|
|
|
+ this.SceneValue = emit[emit.length - 1];
|
|
|
+ console.log(emit, this.SceneValue);
|
|
|
+ },
|
|
|
+ // 初始化绘制处理器
|
|
|
+ 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);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 开始绘制镂空
|
|
|
+ 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);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 绘制镂空区域
|
|
|
+ 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);
|
|
|
+ this.jsonData = requestData;
|
|
|
+ // 实际项目中使用以下代码发送请求
|
|
|
+ skszk
|
|
|
+ .topology(this.SceneRule[this.SceneValue].apiUrl, requestData)
|
|
|
+ .then((res) => {
|
|
|
+ this.backData = res;
|
|
|
+ this.$message({
|
|
|
+ message: res.message,
|
|
|
+ type: "success",
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("后台接口调用失败:", error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清除所有绘制的元素
|
|
|
+ clearAll() {
|
|
|
+ // 移除所有实体
|
|
|
+ this.drawnEntities.forEach((entity) => {
|
|
|
+ viewer.entities.remove(entity);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 清空数组
|
|
|
+ this.drawnEntities = [];
|
|
|
+ this.geometries = [];
|
|
|
+
|
|
|
+ // 取消当前绘制模式
|
|
|
+ this.deactivateDraw();
|
|
|
+
|
|
|
+ console.log("已清除所有绘制的元素");
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+// 操作栏样式
|
|
|
+#controlPanelBox {
|
|
|
+ width: calc(30vw - 2rem);
|
|
|
+ min-width: 500px;
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 1rem;
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+// 绘制按钮区域
|
|
|
+.toolbar {
|
|
|
+ position: absolute;
|
|
|
+ top: 20px;
|
|
|
+ left: -120px;
|
|
|
+ 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;
|
|
|
+}
|
|
|
+.sceneNameBox {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+</style>
|