Compare commits

..

22 Commits

Author SHA1 Message Date
faae591f4c 修改代码样式 2025-10-27 11:06:03 +08:00
da4b440b0e 1 2025-10-27 10:35:37 +08:00
d8bf6fd1b5 修改样式 2025-10-27 10:33:48 +08:00
ffe45a240d 合并代码 2025-10-27 09:54:17 +08:00
0ed458cb08 Merge branch 'pathPlan' of https://git.rangutech.com/yiqiuyang/kxfx into yqy 2025-10-27 09:50:49 +08:00
a562e2cea8 add 样式 2025-10-27 09:46:51 +08:00
af252cd65e fix 2025-10-24 09:02:28 +08:00
2f6de52604 修改字体 2025-10-24 09:01:00 +08:00
278176a0fb Merge branch 'pathPlan' of https://git.rangutech.com/yiqiuyang/kxfx into yqy 2025-10-23 10:24:10 +08:00
444bded88f add 字体 2025-10-23 10:23:50 +08:00
9444e6db5d Merge branch 'pathPlan' of https://git.rangutech.com/yiqiuyang/kxfx into yqy 2025-10-23 09:47:02 +08:00
2b639ea0f3 1 2025-10-23 09:43:28 +08:00
964ce7cede fix bug修复 2025-10-16 16:02:23 +08:00
ce70fd98ec add json编辑功能 2025-10-15 09:27:20 +08:00
7d22506f18 add json 编辑 2025-10-14 17:23:54 +08:00
0aecd99d65 改成ES5打包 2025-10-14 11:35:33 +08:00
04f23de755 去掉this.$alert 2025-10-13 13:34:22 +08:00
7dca973b3b 新增全部导出功能 2025-10-13 11:33:48 +08:00
31f8c849b8 新增导出功能 2025-10-10 18:32:13 +08:00
328700ec89 fix 2025-10-10 18:31:44 +08:00
2ad6bc1b47 add 导出 2025-10-10 15:32:47 +08:00
41f9034f54 ## 机动路线规划 2025-10-10 11:38:34 +08:00
17 changed files with 4896 additions and 1813 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ pnpm-debug.log*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
*.zip

View File

@ -4,5 +4,6 @@
"semi": false, "semi": false,
"singleQuote": true, "singleQuote": true,
"trailingComma": "es5", "trailingComma": "es5",
"bracketSpacing": false "bracketSpacing": false,
"printWidth": 120
} }

View File

@ -1,29 +1,3 @@
# kxfx # kxfx
## Project setup ## 机动路线规划
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

421
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,11 @@
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@babel/preset-env": "^7.28.3",
"axios": "0.21.0", "axios": "0.21.0",
"core-js": "^3.8.3",
"echarts": "^5.4.3", "echarts": "^5.4.3",
"element-ui": "2.9.2", "element-ui": "2.9.2",
"file-saver": "^2.0.5",
"gsap": "^3.13.0", "gsap": "^3.13.0",
"ini-parser": "^0.0.2", "ini-parser": "^0.0.2",
"js-cookie": "2.2.1", "js-cookie": "2.2.1",
@ -24,13 +25,15 @@
"vxe-table": "~3.18.9" "vxe-table": "~3.18.9"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.28.4",
"@babel/eslint-parser": "^7.12.16", "@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0", "@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"babel-loader": "^10.0.0",
"core-js": "^3.46.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",

View File

@ -1,5 +1,5 @@
[http] [http]
port=8081 port=8083
address=127.0.0.1 address=127.0.0.1
[title] [title]

View File

@ -1,16 +1,16 @@
{ {
"startPoint": "114.26344,27.800982", "startPoint": "114.312888,27.796612",
"endPoint": "114.284668,27.794961", "endPoint": "114.336525,27.767989",
"viaPoints": [ "viaPoints": [
{ {
"time": "1694352000000", "time": "1694352000000",
"points": "114.272329,27.797299" "points": "114.334239,27.779261"
} }
], ],
"avoidPoints": [ "avoidPoints": [
{ {
"time": "1694352003000", "time": "1694352003000",
"points": "114.27882,27.792857" "points": ""
} }
], ],
"avoidAreas": [ "avoidAreas": [

View File

@ -17,7 +17,7 @@ export default {
return { return {
routerMap: { routerMap: {
1: '/', 1: '/',
2: '/residentAnalysis', // 2: '/residentAnalysis ',
}, },
} }
}, },

Binary file not shown.

View File

@ -1,11 +1,58 @@
@font-face {
font-family: 'Dengxian';
src: url('@/assets/scss/Dengxian.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
/* 全局强制继承 */
html, body, #app, .cesium-widget, .mars3d-container,
.mars3d-popup, .mars3d-tooltip, .mars3d-contextmenu,
.mars3d-measure-result, .cesium-credit-text,
.el-button, .el-input, .el-select, .el-table, .el-form, .el-dialog,
.el-message, .el-notification, .el-tooltip,
.el-menu, .el-breadcrumb, .el-pagination,
.el-radio, .el-checkbox, .el-tag, .el-badge,
.el-alert, .el-steps, .el-tabs, .el-calendar,
.el-date-picker, .el-cascader, .el-transfer,
.el-slider, .el-upload,
.el-empty, .el-result,
.el-loading-text,.el-table,
.el-table__body-wrapper span,
.el-table__footer-wrapper span,
.el-table__header-wrapper span,
.el-table__fixed span,
.el-table__fixed-right span,.vxe-table *,
.vxe-table--render-default .vxe-cell span,
.vxe-table--render-default .vxe-cell--title,
.vxe-table--render-default .vxe-cell--label,
.vxe-toolbar *,
.vxe-pager *,
.vxe-modal--wrapper *,
.vxe-tooltip--wrapper * {
font-family: 'DengXian', sans-serif !important;
}
/* 覆盖 mars3d 所有内部 UI */
.mars3d-draw-tooltip,
.mars3d-measure-tooltip,
.mars3d-contextmenu *,
.mars3d-popup *,
.mars3d-measure-result *,
.mars3d-control-btn {
font-family: 'DengXian', sans-serif !important;
}
.Dengxian {
font-family: 'Dengxian' !important;
}
body, body,
html { html {
margin: 0; margin: 0;
padding: 0; padding: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, font-family: 'Dengxian' !important;
Microsoft YaHei, Arial, sans-serif;
user-select: none; user-select: none;
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: none; -ms-overflow-style: none;
@ -33,3 +80,20 @@ html {
.flex-warp { .flex-warp {
flex-wrap: wrap; flex-wrap: wrap;
} }
.el-form-item {
display: flex!important;
justify-content: space-between;
margin-bottom: 12px!important;
}
.el-form-item__label {
letter-spacing: -1px;
min-width: 130px!important;
padding: 0!important;
white-space: nowrap; /* 强制不换行 */
flex-shrink: 0;
font-size: 16px!important;
}
.el-input__inner {
height: 24px;
line-height: 24px;
}

View File

@ -7,12 +7,12 @@ Vue.use(VueRouter)
const routes = [ const routes = [
{ {
path: '/', path: '/home',
name: 'home', name: 'home',
component: HomeView, component: HomeView,
}, },
{ {
path: '/residentAnalysis', path: '/',
name: 'residentAnalysis', name: 'residentAnalysis',
component: residentAnalysis, component: residentAnalysis,
}, },

View File

@ -22,8 +22,8 @@ export default {
data() { data() {
return { return {
tabList: [ tabList: [
{id: 1, label: '机动路线规划'}, // {id: 1, label: '机动路线规划'},
// {id: 2, label: '临时部署驻地分析'}, {id: 1, label: '临时部署驻地分析'},
], ],
activeIndex: 1, activeIndex: 1,
} }
@ -64,7 +64,7 @@ $label_height: 50px;
line-height: $label_height; line-height: $label_height;
padding: 0 30px; padding: 0 30px;
margin-right: 20px; margin-right: 20px;
font-family: 'HarmonyOS Sans'; // font-family: 'HarmonyOS Sans';
font-weight: 400; font-weight: 400;
font-size: 20px; font-size: 20px;
cursor: pointer; cursor: pointer;

View File

@ -81,21 +81,12 @@
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
<input <input type="file" ref="fileInput" @change="handleFileUpload" style="display: none" />
type="file"
ref="fileInput"
@change="handleFileUpload"
style="display: none"
/>
<div class="importJson" @click="triggerFileUpload">导入json文件</div> <div class="importJson" @click="triggerFileUpload">导入json文件</div>
</div> </div>
<div class="control-panel"> <div class="control-panel">
<div class="title">隐蔽添加</div> <div class="title">隐蔽添加</div>
<el-form <el-form label-width="120px" label-position="left" size="mini">
label-width="120px"
label-position="left"
size="mini"
>
<el-form-item label="缓冲半径m"> <el-form-item label="缓冲半径m">
<el-input v-model="hideform.radius"></el-input> <el-input v-model="hideform.radius"></el-input>
</el-form-item> </el-form-item>
@ -112,12 +103,7 @@
<span>参与路线规划</span> <span>参与路线规划</span>
</div> </div>
</div> </div>
<el-form <el-form @submit.native.prevent="calculateShortestPath" label-width="120px" label-position="left" size="mini">
@submit.native.prevent="calculateShortestPath"
label-width="120px"
label-position="left"
size="mini"
>
<el-form-item label="宽度"> <el-form-item label="宽度">
<el-input v-model="inputform.width"></el-input> <el-input v-model="inputform.width"></el-input>
</el-form-item> </el-form-item>
@ -125,10 +111,7 @@
<el-input v-model="inputform.load" placeholder=""></el-input> <el-input v-model="inputform.load" placeholder=""></el-input>
</el-form-item> </el-form-item>
<el-form-item label="最小转弯半径"> <el-form-item label="最小转弯半径">
<el-input <el-input v-model="inputform.minTurnRadius" placeholder=""></el-input>
v-model="inputform.minTurnRadius"
placeholder=""
></el-input>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="importJson" @click="openDialog">数据选择</div> <div class="importJson" @click="openDialog">数据选择</div>
@ -156,7 +139,7 @@
inputform.minTurnRadius || 0 inputform.minTurnRadius || 0
}}最大车辆载重{{ inputform.load || 0 }} }}最大车辆载重{{ inputform.load || 0 }}
</div> </div>
<vxe-table ref="xTable" :data="infoList" style="max-height: 50vh;overflow: hidden;overflow-y: auto;"> <vxe-table ref="xTable" :data="infoList" style="max-height: 50vh; overflow: hidden; overflow-y: auto">
<vxe-column field="编码" title="编码" width="65px"></vxe-column> <vxe-column field="编码" title="编码" width="65px"></vxe-column>
<vxe-column field="名称" title="名称" width="80px"></vxe-column> <vxe-column field="名称" title="名称" width="80px"></vxe-column>
<vxe-column field="宽度" title="路宽"></vxe-column> <vxe-column field="宽度" title="路宽"></vxe-column>
@ -165,23 +148,23 @@
<vxe-column field="水深" title="水深"></vxe-column> <vxe-column field="水深" title="水深"></vxe-column>
<vxe-column field="净空高" title="净空高" width="65px"></vxe-column> <vxe-column field="净空高" title="净空高" width="65px"></vxe-column>
</vxe-table> </vxe-table>
<vxe-table :data="factoriesWithVehicles" style="margin-top: 10px;"> <vxe-table :data="factoriesWithVehicles" style="margin-top: 10px">
<vxe-column field="options.style.properties.FID_1" title="厂房id"></vxe-column> <vxe-column field="options.style.properties.FID_1" title="厂房id"></vxe-column>
<vxe-column field="area" title="面积(㎡)"> <vxe-column field="area" title="面积(㎡)">
<template v-slot="{ row }"> <template v-slot="{row}">
{{ row.area.toFixed(2)}} {{ row.area.toFixed(2) }}
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="vehicles" title="车辆"> <vxe-column field="vehicles" title="车辆">
<template v-slot="{ row }"> <template v-slot="{row}">
{{ (row.vehicles.map(item => item.name)).join(',')}} {{ row.vehicles.map((item) => item.name).join(',') }}
</template> </template>
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </div>
<el-dialog :visible.sync="dialogVisible" title="车辆选择" width="800px"> <el-dialog :visible.sync="dialogVisible" title="车辆选择" width="800px">
<div style="margin-bottom: 10px;"> <div style="margin-bottom: 10px">
<el-button type="primary" size="mini" @click="handleAdd">新增</el-button> <el-button type="primary" size="mini" @click="handleAdd">新增</el-button>
</div> </div>
<vxe-table <vxe-table
@ -197,37 +180,37 @@
> >
<vxe-column type="checkbox" width="50"></vxe-column> <vxe-column type="checkbox" width="50"></vxe-column>
<vxe-column field="name" title="名称" width="100"> <vxe-column field="name" title="名称" width="100">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-input v-if="row.editing" v-model="row.name" size="mini"></el-input> <el-input v-if="row.editing" v-model="row.name" size="mini"></el-input>
<span v-else>{{ row.name }}</span> <span v-else>{{ row.name }}</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="long" title="长度" width="100"> <vxe-column field="long" title="长度" width="100">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-input v-if="row.editing" v-model="row.long" size="mini"></el-input> <el-input v-if="row.editing" v-model="row.long" size="mini"></el-input>
<span v-else>{{ row.long }}</span> <span v-else>{{ row.long }}</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="width" title="宽度" width="100"> <vxe-column field="width" title="宽度" width="100">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-input v-if="row.editing" v-model="row.width" size="mini"></el-input> <el-input v-if="row.editing" v-model="row.width" size="mini"></el-input>
<span v-else>{{ row.width }}</span> <span v-else>{{ row.width }}</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="load" title="载重(吨)" width="100"> <vxe-column field="load" title="载重(吨)" width="100">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-input v-if="row.editing" v-model="row.load" size="mini"></el-input> <el-input v-if="row.editing" v-model="row.load" size="mini"></el-input>
<span v-else>{{ row.load }}</span> <span v-else>{{ row.load }}</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="minTurnRadius" title="最小转弯半径"> <vxe-column field="minTurnRadius" title="最小转弯半径">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-input v-if="row.editing" v-model="row.minTurnRadius" size="mini"></el-input> <el-input v-if="row.editing" v-model="row.minTurnRadius" size="mini"></el-input>
<span v-else>{{ row.minTurnRadius }}</span> <span v-else>{{ row.minTurnRadius }}</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column title="操作" width="100"> <vxe-column title="操作" width="100">
<template v-slot="{ row }"> <template v-slot="{row}">
<el-button v-if="!row.editing" type="text" size="mini" @click="handleEdit(row)">编辑</el-button> <el-button v-if="!row.editing" type="text" size="mini" @click="handleEdit(row)">编辑</el-button>
<el-button v-else type="text" size="mini" @click="handleSave(row)">保存</el-button> <el-button v-else type="text" size="mini" @click="handleSave(row)">保存</el-button>
<el-button type="text" size="mini" @click="handleDelete(row)">删除</el-button> <el-button type="text" size="mini" @click="handleDelete(row)">删除</el-button>
@ -248,7 +231,7 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import axios from 'axios' import axios from 'axios'
import iniParser from 'ini-parser' import iniParser from 'ini-parser'
import configIni from '/config.ini'; import configIni from '/public/config.ini'
export default { export default {
data() { data() {
@ -321,7 +304,7 @@ export default {
.catch((error) => {}) .catch((error) => {})
}, },
async initMap() { async initMap() {
const parsedData = iniParser.parse(configIni); const parsedData = iniParser.parse(configIni)
this.viewer = new window.mars3d.Map( this.viewer = new window.mars3d.Map(
'map', 'map',
{ {
@ -356,7 +339,7 @@ export default {
this.shortestPathLayer = new window.mars3d.layer.GraphicLayer() this.shortestPathLayer = new window.mars3d.layer.GraphicLayer()
this.viewer.addLayer(this.shortestPathLayer) this.viewer.addLayer(this.shortestPathLayer)
this.accordFactoryLayer = new window.mars3d.layer.GraphicLayer() this.accordFactoryLayer = new window.mars3d.layer.GraphicLayer()
this.viewer.addLayer(this.accordFactoryLayer) this.viewer.addLayer(this.accordFactoryLayer)
this.loadShapefile() // 拿到路网数据 this.loadShapefile() // 拿到路网数据
@ -450,7 +433,7 @@ export default {
outline: false, outline: false,
}, },
}) })
this.graphicLayer.addGraphic(graphicLine); this.graphicLayer.addGraphic(graphicLine)
}) })
this.roadNetworkGeoJSONBuild = this.buildGraph(this.roadNetworkGeoJSON) this.roadNetworkGeoJSONBuild = this.buildGraph(this.roadNetworkGeoJSON)
this.loadFactoryGeoJson() // 拿到厂房数据 this.loadFactoryGeoJson() // 拿到厂房数据
@ -500,7 +483,7 @@ export default {
this.accordPoint = graphic this.accordPoint = graphic
try { try {
// 创建缓冲区的宽度 // 创建缓冲区的宽度
const bufferWidth = this.hideform.radius; // 避让区的宽度(单位:米) const bufferWidth = this.hideform.radius // 避让区的宽度(单位:米)
// 获取绘制的点的坐标 // 获取绘制的点的坐标
const pointCoordinates = [ const pointCoordinates = [
graphic.toGeoJSON().geometry.coordinates[0], graphic.toGeoJSON().geometry.coordinates[0],
@ -514,12 +497,12 @@ export default {
coordinates: pointCoordinates, coordinates: pointCoordinates,
}, },
properties: {}, properties: {},
}; }
// 使用 Turf.js 计算缓冲区 // 使用 Turf.js 计算缓冲区
let buffered = turf.buffer(pointFeature, bufferWidth / 1000, { units: 'kilometers' }); let buffered = turf.buffer(pointFeature, bufferWidth / 1000, {units: 'kilometers'})
// 将缓冲区存储到数组中 // 将缓冲区存储到数组中
this.bufferLayerList.push(buffered); this.bufferLayerList.push(buffered)
const polygon = new window.mars3d.graphic.PolygonEntity({ const polygon = new window.mars3d.graphic.PolygonEntity({
positions: buffered.geometry.coordinates[0], positions: buffered.geometry.coordinates[0],
style: { style: {
@ -529,19 +512,19 @@ export default {
outlineWidth: 1, outlineWidth: 1,
outlineColor: '#ffffff', outlineColor: '#ffffff',
}, },
time: new Date().getTime() time: new Date().getTime(),
}) })
this.accordFactoryLayer.addGraphic(polygon); this.accordFactoryLayer.addGraphic(polygon)
// 检查缓冲区内的厂房 // 检查缓冲区内的厂房
this.checkFactoryInBuffer('point', pointCoordinates); this.checkFactoryInBuffer('point', pointCoordinates)
} catch (error) { } catch (error) {
console.error("缓冲区生成或检查异常:", error); console.error('缓冲区生成或检查异常:', error)
} }
}, },
}) })
}, },
// 获取当前路线的缓冲区 // 获取当前路线的缓冲区
hadBuffer () { hadBuffer() {
if (this.shortestPathList.length == 0) { if (this.shortestPathList.length == 0) {
this.$message.warning('请先进行路线规划') this.$message.warning('请先进行路线规划')
return return
@ -551,34 +534,34 @@ export default {
return return
} }
try { try {
// =======检查几何对象的类型 缓冲区======== // =======检查几何对象的类型 缓冲区========
for (const feature of this.shortestPathList[0]) { for (const feature of this.shortestPathList[0]) {
// this.shortestPathList[0].forEach((feature) => { // this.shortestPathList[0].forEach((feature) => {
// 创建缓冲区的宽度 // 创建缓冲区的宽度
const bufferWidth = this.hideform.radius; // 避让区的宽度(单位:米) const bufferWidth = this.hideform.radius // 避让区的宽度(单位:米)
if (feature.geometry.type === 'LineString') { if (feature.geometry.type === 'LineString') {
const positions = feature.geometry.coordinates[0]; const positions = feature.geometry.coordinates[0]
// 确保每条线至少有 2 个点 // 确保每条线至少有 2 个点
if (positions.length < 2) { if (positions.length < 2) {
console.warn('无效的线,跳过:', feature); console.warn('无效的线,跳过:', feature)
return; return
} }
try { try {
// 使用 Turf.js 计算缓冲区 // 使用 Turf.js 计算缓冲区
var buffered = turf.buffer(feature, bufferWidth / 1000, { units: 'kilometers' }); var buffered = turf.buffer(feature, bufferWidth / 1000, {units: 'kilometers'})
// 将缓冲区存储到数组中 // 将缓冲区存储到数组中
this.bufferLayerList.push(buffered); this.bufferLayerList.push(buffered)
} catch (error) { } catch (error) {
console.error("缓冲分析异常:", error); console.error('缓冲分析异常:', error)
} }
} else if (feature.geometry.type === 'MultiLineString') { } else if (feature.geometry.type === 'MultiLineString') {
// 遍历每个线段 // 遍历每个线段
feature.geometry.coordinates.forEach((lineCoordinates) => { feature.geometry.coordinates.forEach((lineCoordinates) => {
// 检查每个线段是否有效 // 检查每个线段是否有效
if (lineCoordinates.length < 2) { if (lineCoordinates.length < 2) {
console.warn('多线段中的无效的线段,跳过:', lineCoordinates); console.warn('多线段中的无效的线段,跳过:', lineCoordinates)
return; return
} }
// 创建单个线段的 GeoJSON 特征 // 创建单个线段的 GeoJSON 特征
@ -588,27 +571,27 @@ export default {
type: 'LineString', type: 'LineString',
coordinates: lineCoordinates, coordinates: lineCoordinates,
}, },
properties: feature.properties properties: feature.properties,
}; }
try { try {
// 使用 Turf.js 计算缓冲区 // 使用 Turf.js 计算缓冲区
var buffered = turf.buffer(lineFeature, bufferWidth / 1000, { units: 'kilometers' }); var buffered = turf.buffer(lineFeature, bufferWidth / 1000, {units: 'kilometers'})
// 将缓冲区存储到数组中 // 将缓冲区存储到数组中
this.bufferLayerList.push(buffered); this.bufferLayerList.push(buffered)
} catch (error) { } catch (error) {
console.error("缓冲分析异常:", error); console.error('缓冲分析异常:', error)
} }
}); })
} else { } else {
console.warn('不支持的几何类型:', feature.geometry.type); console.warn('不支持的几何类型:', feature.geometry.type)
} }
} }
// 去筛选在缓存区的厂房 // 去筛选在缓存区的厂房
this.checkFactoryInBuffer('line'); this.checkFactoryInBuffer('line')
}catch (error) { } catch (error) {
console.error("处理路径列表时发生错误:", error); console.error('处理路径列表时发生错误:', error)
} }
}, },
checkFactoryInBuffer(type, pointInfo) { checkFactoryInBuffer(type, pointInfo) {
@ -629,106 +612,106 @@ export default {
// 检查几何对象的类型 // 检查几何对象的类型
if (factory.geometry.type === 'MultiPolygon') { if (factory.geometry.type === 'MultiPolygon') {
// 创建多边形集合MultiPolygon // 创建多边形集合MultiPolygon
const factoryMultiPoly = turf.multiPolygon(factory.geometry.coordinates); const factoryMultiPoly = turf.multiPolygon(factory.geometry.coordinates)
// 计算整个多边形集合的面积 // 计算整个多边形集合的面积
const area = turf.area(factoryMultiPoly); const area = turf.area(factoryMultiPoly)
// 计算工厂多边形集合的边界框 // 计算工厂多边形集合的边界框
const [minX, minY, maxX, maxY] = turf.bbox(factoryMultiPoly); const [minX, minY, maxX, maxY] = turf.bbox(factoryMultiPoly)
// 筛选与工厂边界框相交的缓冲区 // 筛选与工厂边界框相交的缓冲区
const candidates = this.bufferLayerList.filter((buffer) => { const candidates = this.bufferLayerList.filter((buffer) => {
const [bminX, bminY, bmaxX, bmaxY] = turf.bbox(buffer); const [bminX, bminY, bmaxX, bmaxY] = turf.bbox(buffer)
return !(bmaxX < minX || bminX > maxX || bmaxY < minY || bminY > maxY); return !(bmaxX < minX || bminX > maxX || bmaxY < minY || bminY > maxY)
}); })
// 精确相交检测 // 精确相交检测
let isInside = false; let isInside = false
for (const buffer of candidates) { for (const buffer of candidates) {
if (turf.booleanIntersects(factoryMultiPoly, buffer)) { if (turf.booleanIntersects(factoryMultiPoly, buffer)) {
// 如果工厂在缓冲区内,绘制所有多边形 // 如果工厂在缓冲区内,绘制所有多边形
isInside = true; isInside = true
this.drawFactory(factory.geometry.coordinates, factory, area, pointInfo); this.drawFactory(factory.geometry.coordinates, factory, area, pointInfo)
break; break
} }
} }
// 如果工厂不在任何缓冲区内 // 如果工厂不在任何缓冲区内
resolve(); resolve()
} else { } else {
reject(new Error('不支持的几何类型')); reject(new Error('不支持的几何类型'))
} }
}) })
}); })
// 确保所有工厂处理完成后进行排序 // 确保所有工厂处理完成后进行排序
Promise.allSettled(factoryPromises) Promise.allSettled(factoryPromises)
.then(async (results) => { .then(async (results) => {
// 只有路线隐蔽规划需要塞入车辆 点的不需要 // 只有路线隐蔽规划需要塞入车辆 点的不需要
// 所有工厂处理完成,进行排序 按照距离近到远 // 所有工厂处理完成,进行排序 按照距离近到远
this.accordFactoryInfo.sort((a, b) => a.distance - b.distance); this.accordFactoryInfo.sort((a, b) => a.distance - b.distance)
// 拿到当前的车队车辆信息 并且算出面积 按照从大到小排序 // 拿到当前的车队车辆信息 并且算出面积 按照从大到小排序
const areaList = JSON.parse(Cookies.get('minTurnRadius')) const areaList = JSON.parse(Cookies.get('minTurnRadius'))
areaList.map((item) => { areaList.map((item) => {
item.area = Number(item.long) * Number(item.width) item.area = Number(item.long) * Number(item.width)
}) })
areaList.sort((a, b) => b.area - a.area); areaList.sort((a, b) => b.area - a.area)
// 初始化每个工厂的剩余面积 // 初始化每个工厂的剩余面积
this.accordFactoryInfo.forEach(factory => { this.accordFactoryInfo.forEach((factory) => {
factory.remainingArea = factory.area; // 记录每个工厂的剩余可用面积 factory.remainingArea = factory.area // 记录每个工厂的剩余可用面积
factory.vehicles = []; // 确保每个工厂都有一个 vehicles 属性 factory.vehicles = [] // 确保每个工厂都有一个 vehicles 属性
}); })
// 遍历每个车辆,尝试塞入工厂 // 遍历每个车辆,尝试塞入工厂
areaList.forEach((vehicle) => { areaList.forEach((vehicle) => {
let isPlaced = false; let isPlaced = false
// 遍历每个工厂,尝试塞入车辆 // 遍历每个工厂,尝试塞入车辆
for (let i = 0; i < this.accordFactoryInfo.length; i++) { for (let i = 0; i < this.accordFactoryInfo.length; i++) {
const factory = this.accordFactoryInfo[i]; const factory = this.accordFactoryInfo[i]
// 检查工厂是否还有剩余面积 // 检查工厂是否还有剩余面积
if (factory.remainingArea >= vehicle.area) { if (factory.remainingArea >= vehicle.area) {
// 塞入车辆 // 塞入车辆
factory.vehicles.push({ factory.vehicles.push({
...vehicle, ...vehicle,
remainingArea: factory.remainingArea - vehicle.area // 记录车辆塞入后的工厂剩余面积 remainingArea: factory.remainingArea - vehicle.area, // 记录车辆塞入后的工厂剩余面积
}); })
// 更新工厂的剩余面积 // 更新工厂的剩余面积
factory.remainingArea -= vehicle.area; factory.remainingArea -= vehicle.area
// 标记车辆已放置 // 标记车辆已放置
isPlaced = true; isPlaced = true
break; break
} }
} }
// 如果车辆没有被放置,可以在这里处理(例如记录日志或显示警告) // 如果车辆没有被放置,可以在这里处理(例如记录日志或显示警告)
if (!isPlaced) { if (!isPlaced) {
console.warn(`车辆 ${vehicle.id} 无法放置在任何工厂中`); console.warn(`车辆 ${vehicle.id} 无法放置在任何工厂中`)
} }
}); })
// 更新 this.accordFactoryInfo // 更新 this.accordFactoryInfo
this.accordFactoryInfo = this.accordFactoryInfo.map(factory => { this.accordFactoryInfo = this.accordFactoryInfo.map((factory) => {
// 确保每个工厂都有 vehicles 属性 // 确保每个工厂都有 vehicles 属性
if (!factory.vehicles) { if (!factory.vehicles) {
factory.vehicles = []; factory.vehicles = []
} }
// 确保 remainingArea 是一个数字且大于 0 // 确保 remainingArea 是一个数字且大于 0
factory.area = factory.area > 0 ? factory.area : 0; factory.area = factory.area > 0 ? factory.area : 0
return factory; return factory
}); })
// 过滤出有车辆的工厂 // 过滤出有车辆的工厂
const factoriesWithVehicles = this.accordFactoryInfo.filter(factory => factory.vehicles.length > 0); const factoriesWithVehicles = this.accordFactoryInfo.filter((factory) => factory.vehicles.length > 0)
this.factoriesWithVehicles = factoriesWithVehicles this.factoriesWithVehicles = factoriesWithVehicles
await this.showAreaInfoDialog(factoriesWithVehicles); await this.showAreaInfoDialog(factoriesWithVehicles)
}) })
.catch((error) => { .catch((error) => {
console.error('数据有问题', error) console.error('数据有问题', error)
}); })
}, },
drawFactory(factoryMultiPoly, factory, area, pointInfo) { drawFactory(factoryMultiPoly, factory, area, pointInfo) {
// 获取当前多边形集合的中心点 // 获取当前多边形集合的中心点
const center = turf.center(turf.multiPolygon(factory.geometry.coordinates)); const center = turf.center(turf.multiPolygon(factory.geometry.coordinates))
// 将中心点转换为 Mars3D 的 LngLatPoint 对象 // 将中心点转换为 Mars3D 的 LngLatPoint 对象
const popupPosition = new mars3d.LngLatPoint(center.geometry.coordinates[0], center.geometry.coordinates[1]); const popupPosition = new mars3d.LngLatPoint(center.geometry.coordinates[0], center.geometry.coordinates[1])
// 遍历每个多边形集合 // 遍历每个多边形集合
factory.geometry.coordinates[0].forEach((coordGroup) => { factory.geometry.coordinates[0].forEach((coordGroup) => {
// 创建一个多边形图形 // 创建一个多边形图形
@ -740,35 +723,39 @@ export default {
outline: true, outline: true,
outlineWidth: 1, outlineWidth: 1,
outlineColor: '#ffffff', outlineColor: '#ffffff',
properties: { ...factory.properties }, properties: {...factory.properties},
}, },
time: new Date().getTime() time: new Date().getTime(),
}) })
this.accordFactoryLayer.addGraphic(graphic); this.accordFactoryLayer.addGraphic(graphic)
// 计算多边形中心与参考点的距离 // 计算多边形中心与参考点的距离
const point = pointInfo && pointInfo.length > 0 ? pointInfo : this.form.endPoint.split(',').map(Number) const point = pointInfo && pointInfo.length > 0 ? pointInfo : this.form.endPoint.split(',').map(Number)
const distance = turf.distance(center.geometry.coordinates, point, { units: 'kilometers' }) * 1000; // 米 const distance = turf.distance(center.geometry.coordinates, point, {units: 'kilometers'}) * 1000 // 米
// 将多边形图形添加到地图层 // 将多边形图形添加到地图层
this.accordFactoryInfo.push({ this.accordFactoryInfo.push({
...graphic, ...graphic,
distance: distance, distance: distance,
popupPosition: popupPosition, popupPosition: popupPosition,
area: this.hideform.redundancy && this.hideform.redundancy != 0 && area > 0 area:
? area * (100 - this.hideform.redundancy) * 0.01 this.hideform.redundancy && this.hideform.redundancy != 0 && area > 0
: area > 0 ? area * (100 - this.hideform.redundancy) * 0.01
? area : area > 0
: 0, // 如果 area 不是有效值,设置为 0 或其他默认值 ? area
: 0, // 如果 area 不是有效值,设置为 0 或其他默认值
}) })
}) })
}, },
// 显示面积信息弹框的方法 // 显示面积信息弹框的方法
async showAreaInfoDialog(info) { async showAreaInfoDialog(info) {
const graphics = this.accordFactoryLayer.getGraphics(); const graphics = this.accordFactoryLayer.getGraphics()
const promises = []; const promises = []
info.forEach((item) => { info.forEach((item) => {
graphics.forEach((ele) => { graphics.forEach((ele) => {
if (ele.options.time === item.options.time && ele.options.style.properties.FID_1 === item.options.style.properties.FID_1) { if (
const textInfo = `${item.area.toFixed(2)}\n${item.vehicles.map(e => e.name).join(',')}` ele.options.time === item.options.time &&
ele.options.style.properties.FID_1 === item.options.style.properties.FID_1
) {
const textInfo = `${item.area.toFixed(2)}\n${item.vehicles.map((e) => e.name).join(',')}`
const labelGraphic = new window.mars3d.graphic.LabelEntity({ const labelGraphic = new window.mars3d.graphic.LabelEntity({
id: 'label', id: 'label',
position: item.popupPosition, position: item.popupPosition,
@ -781,34 +768,34 @@ export default {
outlineColor: '#000000', outlineColor: '#000000',
background: true, background: true,
backgroundColor: '#2f705f', backgroundColor: '#2f705f',
} },
}) })
// 使用 Promise 确保标签添加完成后继续执行 // 使用 Promise 确保标签添加完成后继续执行
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
this.accordFactoryLayer.addGraphic(labelGraphic, () => { this.accordFactoryLayer.addGraphic(labelGraphic, () => {
resolve(); resolve()
}); })
}); })
promises.push(promise); promises.push(promise)
} }
}) })
}) })
this.$message.success("路线隐蔽规划成功") this.$message.success('路线隐蔽规划成功')
const popupPositionList = info.map(item => item.popupPosition) const popupPositionList = info.map((item) => item.popupPosition)
let minLng = Infinity; let minLng = Infinity
let maxLng = -Infinity; let maxLng = -Infinity
let minLat = Infinity; let minLat = Infinity
let maxLat = -Infinity; let maxLat = -Infinity
popupPositionList.forEach(point => { popupPositionList.forEach((point) => {
if (point.lng < minLng) minLng = point.lng; if (point.lng < minLng) minLng = point.lng
if (point.lng > maxLng) maxLng = point.lng; if (point.lng > maxLng) maxLng = point.lng
if (point.lat < minLat) minLat = point.lat; if (point.lat < minLat) minLat = point.lat
if (point.lat > maxLat) maxLat = point.lat; if (point.lat > maxLat) maxLat = point.lat
}); })
// 创建一个矩形区域,包含所有点 // 创建一个矩形区域,包含所有点
const rectangle = Cesium.Rectangle.fromDegrees(minLng, minLat, maxLng, maxLat); const rectangle = Cesium.Rectangle.fromDegrees(minLng, minLat, maxLng, maxLat)
this.viewer.scene.camera.flyTo({ this.viewer.scene.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees( destination: Cesium.Cartesian3.fromDegrees(
@ -819,29 +806,29 @@ export default {
orientation: { orientation: {
heading: Cesium.Math.toRadians(0), // 方位角 heading: Cesium.Math.toRadians(0), // 方位角
pitch: Cesium.Math.toRadians(-90), // 俯仰角 pitch: Cesium.Math.toRadians(-90), // 俯仰角
roll: 0.0 // 翻滚角 roll: 0.0, // 翻滚角
}, },
duration: 2 // 飞行动画持续时间,单位为秒 duration: 2, // 飞行动画持续时间,单位为秒
}); })
}, },
// 弹框 // 弹框
async openDialog() { async openDialog() {
this.multipleSelection = [] this.multipleSelection = []
await fetch('./data/minTurnRadius.json') await fetch('./data/minTurnRadius.json')
.then((response) => { .then((response) => {
return response.json() return response.json()
}) })
.then(async (data) => { .then(async (data) => {
this.dialogVisible = true; this.dialogVisible = true
this.tableData = data this.tableData = data
await this.$nextTick(() => { await this.$nextTick(() => {
this.multipleSelection = JSON.parse(Cookies.get('minTurnRadius')) this.multipleSelection = JSON.parse(Cookies.get('minTurnRadius'))
this.multipleSelection.forEach((item) => { this.multipleSelection.forEach((item) => {
this.$refs.vxeTable.setCheckboxRowKey(item.id, true) this.$refs.vxeTable.setCheckboxRowKey(item.id, true)
})
}) })
}) })
}) .catch((error) => {})
.catch((error) => {})
}, },
handleSelectionChange({records}) { handleSelectionChange({records}) {
this.multipleSelection = records this.multipleSelection = records
@ -879,35 +866,39 @@ export default {
load: null, load: null,
minTurnRadius: null, minTurnRadius: null,
editing: true, editing: true,
}; }
this.tableData.push(newRow); this.tableData.push(newRow)
}, },
handleDelete(row) { handleDelete(row) {
const index = this.tableData.findIndex(item => item.id === row.id); const index = this.tableData.findIndex((item) => item.id === row.id)
if (index !== -1) { if (index !== -1) {
this.tableData.splice(index, 1); this.tableData.splice(index, 1)
} }
}, },
handleEdit(row) { handleEdit(row) {
this.$set(row, 'editing', true); this.$set(row, 'editing', true)
}, },
handleSave(row) { handleSave(row) {
this.$set(row, 'editing', false); this.$set(row, 'editing', false)
}, },
// 保存列表数据 // 保存列表数据
suerCofirm() { suerCofirm() {
const parsedData = iniParser.parse(configIni); const parsedData = iniParser.parse(configIni)
axios.post(`http://${parsedData.http.address}:${parsedData.http.port}/api/equpment`, JSON.stringify(this.tableData), { axios
headers: { .post(
'Authorization': 'Bearer your_token_here', `http://${parsedData.http.address}:${parsedData.http.port}/api/equpment`,
'Content-Type': 'application/json' JSON.stringify(this.tableData),
} {
}) headers: {
.then(response => { Authorization: 'Bearer your_token_here',
this.$message.success('保存成功') 'Content-Type': 'application/json',
}) },
.catch(error => { }
}); )
.then((response) => {
this.$message.success('保存成功')
})
.catch((error) => {})
}, },
// 导入json文件 // 导入json文件
triggerFileUpload() { triggerFileUpload() {
@ -974,21 +965,12 @@ export default {
} }
}, },
addPointToMap(type, point, time) { addPointToMap(type, point, time) {
const coords = time const coords = time ? point.points.split(',').map(Number) : point.split(',').map(Number)
? point.points.split(',').map(Number)
: point.split(',').map(Number)
const graphic = new window.mars3d.graphic.PointEntity({ const graphic = new window.mars3d.graphic.PointEntity({
position: new window.mars3d.LngLatPoint(coords[0], coords[1]), position: new window.mars3d.LngLatPoint(coords[0], coords[1]),
style: { style: {
pixelSize: 10, pixelSize: 10,
color: color: type === 'startPoint' ? 'red' : type === 'endPoint' ? 'red' : type === 'viaPoints' ? 'blue' : 'orange',
type === 'startPoint'
? 'red'
: type === 'endPoint'
? 'red'
: type === 'viaPoints'
? 'blue'
: 'orange',
label: { label: {
text: text:
type === 'startPoint' type === 'startPoint'
@ -1022,9 +1004,7 @@ export default {
addPolygonToMap(type, area, time) { addPolygonToMap(type, area, time) {
const coords = JSON.parse(area.points) const coords = JSON.parse(area.points)
const graphic = new window.mars3d.graphic.PolygonEntity({ const graphic = new window.mars3d.graphic.PolygonEntity({
positions: coords.map( positions: coords.map((coord) => new window.mars3d.LngLatPoint(coord[0], coord[1])),
(coord) => new window.mars3d.LngLatPoint(coord[0], coord[1])
),
style: { style: {
color: 'red', color: 'red',
opacity: 0.4, opacity: 0.4,
@ -1079,94 +1059,55 @@ export default {
} }
} else if (type === 'viaPoints') { } else if (type === 'viaPoints') {
if (!row.points) { if (!row.points) {
const graphic = this.viaPoints.find( const graphic = this.viaPoints.find((viaPoint) => viaPoint.style.time === row.time)
(viaPoint) => viaPoint.style.time === row.time if (this.form.viaPoints.length === 1 && this.form.viaPoints[0].points === '') {
)
if (
this.form.viaPoints.length === 1 &&
this.form.viaPoints[0].points === ''
) {
// 如果只剩下一个空项,不删除图形,清空输入框值 // 如果只剩下一个空项,不删除图形,清空输入框值
this.form.viaPoints[0].points = '' this.form.viaPoints[0].points = ''
graphic?.remove() graphic?.remove()
this.viaPoints = this.viaPoints.filter( this.viaPoints = this.viaPoints.filter((viaPoint) => viaPoint.style.time !== row.time)
(viaPoint) => viaPoint.style.time !== row.time
)
} else { } else {
this.form.viaPoints = this.form.viaPoints.filter( this.form.viaPoints = this.form.viaPoints.filter((viaPoint) => viaPoint.time !== row.time)
(viaPoint) => viaPoint.time !== row.time
)
} }
graphic?.remove() graphic?.remove()
this.viaPoints = this.viaPoints.filter( this.viaPoints = this.viaPoints.filter((viaPoint) => viaPoint.style.time !== row.time)
(viaPoint) => viaPoint.style.time !== row.time
)
} else { } else {
const graphic = this.viaPoints.find( const graphic = this.viaPoints.find((viaPoint) => viaPoint.style.time === row.time)
(viaPoint) => viaPoint.style.time === row.time
)
this.updatePointPosition(graphic, row.points) this.updatePointPosition(graphic, row.points)
} }
} else if (type === 'avoidPoints') { } else if (type === 'avoidPoints') {
if (!row.points) { if (!row.points) {
const graphic = this.avoidPoints.find( const graphic = this.avoidPoints.find((avoidPoint) => avoidPoint.style.time === row.time)
(avoidPoint) => avoidPoint.style.time === row.time if (this.form.avoidPoints.length === 1 && this.form.avoidPoints[0].points === '') {
)
if (
this.form.avoidPoints.length === 1 &&
this.form.avoidPoints[0].points === ''
) {
// 如果只剩下一个空项,不删除图形,清空输入框值 // 如果只剩下一个空项,不删除图形,清空输入框值
this.form.avoidPoints[0].points = '' this.form.avoidPoints[0].points = ''
} else { } else {
this.form.avoidPoints = this.form.avoidPoints.filter( this.form.avoidPoints = this.form.avoidPoints.filter((avoidPoint) => avoidPoint.time !== row.time)
(avoidPoint) => avoidPoint.time !== row.time
)
} }
graphic?.remove() graphic?.remove()
this.avoidPoints = this.avoidPoints.filter( this.avoidPoints = this.avoidPoints.filter((avoidPoint) => avoidPoint.style.time !== row.time)
(avoidPoint) => avoidPoint.style.time !== row.time
)
} else { } else {
const graphic = this.avoidPoints.find( const graphic = this.avoidPoints.find((avoidPoint) => avoidPoint.style.time === row.time)
(avoidPoint) => avoidPoint.style.time === row.time
)
this.updatePointPosition(graphic, row.points) this.updatePointPosition(graphic, row.points)
} }
} else if (type === 'avoidAreas') { } else if (type === 'avoidAreas') {
if (!row.points) { if (!row.points) {
const graphic = this.avoidAreas.find( const graphic = this.avoidAreas.find((avoidArea) => avoidArea.style.time === row.time)
(avoidArea) => avoidArea.style.time === row.time if (this.form.avoidAreas.length === 1 && this.form.avoidAreas[0].points === '') {
)
if (
this.form.avoidAreas.length === 1 &&
this.form.avoidAreas[0].points === ''
) {
// 如果只剩下一个空项,不删除图形,清空输入框值 // 如果只剩下一个空项,不删除图形,清空输入框值
this.form.avoidAreas[0].points = '' this.form.avoidAreas[0].points = ''
} else { } else {
this.form.avoidAreas = this.form.avoidAreas.filter( this.form.avoidAreas = this.form.avoidAreas.filter((avoidArea) => avoidArea.time !== row.time)
(avoidArea) => avoidArea.time !== row.time
)
} }
graphic?.remove() graphic?.remove()
this.avoidAreas = this.avoidAreas.filter( this.avoidAreas = this.avoidAreas.filter((avoidArea) => avoidArea.style.time !== row.time)
(avoidArea) => avoidArea.style.time !== row.time
)
} else { } else {
const graphic = this.avoidAreas.find( const graphic = this.avoidAreas.find((avoidArea) => avoidArea.style.time === row.time)
(avoidArea) => avoidArea.style.time === row.time
)
this.updatePolygonPosition(graphic, row.points) this.updatePolygonPosition(graphic, row.points)
} }
} }
}, },
handleEmptyArray(type) { handleEmptyArray(type) {
if ( if (type === 'viaPoints' && this.form.viaPoints.length === 1 && this.form.viaPoints[0].points === '') {
type === 'viaPoints' &&
this.form.viaPoints.length === 1 &&
this.form.viaPoints[0].points === ''
) {
this.form.viaPoints = [] this.form.viaPoints = []
} else if ( } else if (
type === 'avoidPoints' && type === 'avoidPoints' &&
@ -1174,11 +1115,7 @@ export default {
this.form.avoidPoints[0].points === '' this.form.avoidPoints[0].points === ''
) { ) {
this.form.avoidPoints = [] this.form.avoidPoints = []
} else if ( } else if (type === 'avoidAreas' && this.form.avoidAreas.length === 1 && this.form.avoidAreas[0].points === '') {
type === 'avoidAreas' &&
this.form.avoidAreas.length === 1 &&
this.form.avoidAreas[0].points === ''
) {
this.form.avoidAreas = [] this.form.avoidAreas = []
} }
}, },
@ -1193,9 +1130,7 @@ export default {
if (!graphic) return if (!graphic) return
try { try {
const coords = JSON.parse(pointsStr) const coords = JSON.parse(pointsStr)
graphic.positions = coords.map( graphic.positions = coords.map((coord) => new window.mars3d.LngLatPoint(coord[0], coord[1]))
(coord) => new window.mars3d.LngLatPoint(coord[0], coord[1])
)
} catch (error) { } catch (error) {
graphic.remove() graphic.remove()
} }
@ -1350,9 +1285,7 @@ export default {
success: (graphic) => { success: (graphic) => {
this.avoidAreas.push(graphic) this.avoidAreas.push(graphic)
const avoidAreasGeoJSON = graphic.toGeoJSON() const avoidAreasGeoJSON = graphic.toGeoJSON()
const points = JSON.stringify( const points = JSON.stringify(avoidAreasGeoJSON.geometry.coordinates[0])
avoidAreasGeoJSON.geometry.coordinates[0]
)
if ( if (
this.form.avoidAreas.length == 1 && this.form.avoidAreas.length == 1 &&
this.form.avoidAreas[0].points == '' && this.form.avoidAreas[0].points == '' &&
@ -1385,11 +1318,8 @@ export default {
} }
// 计算边权重(距离,单位:米) // 计算边权重(距离,单位:米)
const distance = const distance =
turf.distance( turf.distance(turf.point(coords[0][0]), turf.point(coords[coords.length - 1][0]), {units: 'kilometers'}) *
turf.point(coords[0][0]), 1000
turf.point(coords[coords.length - 1][0]),
{units: 'kilometers'}
) * 1000
// 构建邻接表(双向图) // 构建邻接表(双向图)
graph[startNode] = graph[startNode] || {} graph[startNode] = graph[startNode] || {}
@ -1418,22 +1348,17 @@ export default {
return nearestNode return nearestNode
}, },
// 3. 路径规划主函数(经纬度坐标输入) - 支持途经点 + 避让点/区域 // 3. 路径规划主函数(经纬度坐标输入) - 支持途经点 + 避让点/区域
async planRoute( async planRoute(startCoord, endCoord, viaPoints = [], avoidObstacles = null) {
startCoord,
endCoord,
viaPoints = [],
avoidObstacles = null
) {
const {graph, nodeCoords} = this.roadNetworkGeoJSONBuild const {graph, nodeCoords} = this.roadNetworkGeoJSONBuild
// 按顺序组合点:起点 -> 途经点 -> 终点 // 按顺序组合点:起点 -> 途经点 -> 终点
const points = [startCoord]; const points = [startCoord]
if (viaPoints && viaPoints.length > 0) { if (viaPoints && viaPoints.length > 0) {
viaPoints.forEach((viaPoint) => { viaPoints.forEach((viaPoint) => {
points.push(viaPoint.geometry.coordinates); points.push(viaPoint.geometry.coordinates)
}); })
} }
points.push(endCoord); points.push(endCoord)
const fullPath = [] const fullPath = []
const infoList = [] const infoList = []
for (let i = 0; i < points.length - 1; i++) { for (let i = 0; i < points.length - 1; i++) {
@ -1457,8 +1382,7 @@ export default {
for (const [node, coord] of Object.entries(nodeCoords)) { for (const [node, coord] of Object.entries(nodeCoords)) {
const pt = turf.point(coord) const pt = turf.point(coord)
avoidObstacles.features.forEach((ob) => { avoidObstacles.features.forEach((ob) => {
if (turf.booleanPointInPolygon(pt.geometry, ob.geometry)) if (turf.booleanPointInPolygon(pt.geometry, ob.geometry)) obstacleNodes.push(node)
obstacleNodes.push(node)
}) })
} }
obstacleNodes.forEach((node) => delete tempGraph[node]) obstacleNodes.forEach((node) => delete tempGraph[node])
@ -1471,10 +1395,7 @@ export default {
delete tempGraph[node][targetNode] delete tempGraph[node][targetNode]
continue continue
} }
const line = turf.lineString([ const line = turf.lineString([nodeCoords[node], nodeCoords[targetNode]])
nodeCoords[node],
nodeCoords[targetNode],
])
avoidObstacles.features.forEach((area) => { avoidObstacles.features.forEach((area) => {
if (turf.booleanCrosses(line, area)) { if (turf.booleanCrosses(line, area)) {
delete tempGraph[node][targetNode] delete tempGraph[node][targetNode]
@ -1500,21 +1421,17 @@ export default {
if (!this.join) { if (!this.join) {
segment = this.roadNetworkGeoJSON.features.find( segment = this.roadNetworkGeoJSON.features.find(
(f) => (f) =>
(f.properties.FNODE_ == currentNode && (f.properties.FNODE_ == currentNode && f.properties.TNODE_ == nextNode) ||
f.properties.TNODE_ == nextNode) || (f.properties.FNODE_ == nextNode && f.properties.TNODE_ == currentNode)
(f.properties.FNODE_ == nextNode &&
f.properties.TNODE_ == currentNode)
) )
} else { } else {
segment = this.roadNetworkGeoJSON.features.find( segment = this.roadNetworkGeoJSON.features.find(
(f) => (f) =>
((f.properties.FNODE_ == currentNode && ((f.properties.FNODE_ == currentNode && f.properties.TNODE_ == nextNode) ||
f.properties.TNODE_ == nextNode) || (f.properties.FNODE_ == nextNode && f.properties.TNODE_ == currentNode)) &&
(f.properties.FNODE_ == nextNode && f.properties.载重吨 >= this.inputform.load &&
f.properties.TNODE_ == currentNode) ) && f.properties.宽度 >= this.inputform.width &&
f.properties.载重吨 >= this.inputform.load && f.properties.曲率半 <= this.inputform.minTurnRadius
f.properties.宽度 >= this.inputform.width &&
f.properties.曲率半 <= this.inputform.minTurnRadius
) )
} }
if (segment) { if (segment) {
@ -1534,20 +1451,13 @@ export default {
this.shortestPathLayer.clear() this.shortestPathLayer.clear()
this.shortestPathList = [] this.shortestPathList = []
this.infoList = [] this.infoList = []
const startPoint = turf.point( const startPoint = turf.point(this.pointQD.toGeoJSON().geometry.coordinates).geometry.coordinates // 起点
this.pointQD.toGeoJSON().geometry.coordinates const endPoint = turf.point(this.pointZD.toGeoJSON().geometry.coordinates).geometry.coordinates // 终点
).geometry.coordinates // 起点
const endPoint = turf.point(this.pointZD.toGeoJSON().geometry.coordinates)
.geometry.coordinates // 终点
// 途经点 // 途经点
const viaPointsGeoJSON = const viaPointsGeoJSON = this.viaPoints.map((point) => point.toGeoJSON()) || []
this.viaPoints.map((point) => point.toGeoJSON()) || [] const viaPointsTurf = viaPointsGeoJSON.map((p) => turf.point(p.geometry.coordinates))
const viaPointsTurf = viaPointsGeoJSON.map((p) =>
turf.point(p.geometry.coordinates)
)
// 避让点 // 避让点
const avoidPointsGeoJSON = const avoidPointsGeoJSON = this.avoidPoints.map((point) => point.toGeoJSON()) || []
this.avoidPoints.map((point) => point.toGeoJSON()) || []
const avoidPointsPolygons = avoidPointsGeoJSON.map((point) => { const avoidPointsPolygons = avoidPointsGeoJSON.map((point) => {
return turf.circle( return turf.circle(
turf.point(point.geometry.coordinates), turf.point(point.geometry.coordinates),
@ -1556,18 +1466,9 @@ export default {
) )
}) })
// 避让区域 // 避让区域
const avoidAreasGeoJSON = const avoidAreasGeoJSON = this.avoidAreas.map((area) => area.toGeoJSON({closure: true})) || []
this.avoidAreas.map((area) => area.toGeoJSON({closure: true})) || [] const obstaclesGeoJSON = turf.featureCollection([...avoidPointsPolygons, ...avoidAreasGeoJSON])
const obstaclesGeoJSON = turf.featureCollection([ const route = await this.planRoute(startPoint, endPoint, viaPointsTurf, obstaclesGeoJSON)
...avoidPointsPolygons,
...avoidAreasGeoJSON,
])
const route = await this.planRoute(
startPoint,
endPoint,
viaPointsTurf,
obstaclesGeoJSON
)
this.drawPath(route) this.drawPath(route)
}, },
@ -1588,9 +1489,7 @@ export default {
this.infoList = path.infoList.map((item) => item.properties) this.infoList = path.infoList.map((item) => item.properties)
}, },
/** 隐蔽规划 */ /** 隐蔽规划 */
concealed() { concealed() {},
},
}, },
} }
</script> </script>
@ -1664,14 +1563,14 @@ export default {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.control-panel .title .joinCheck { .control-panel .title .joinCheck {
font-size: 14px; font-size: 14px;
color: #555; color: #555;
} }
.el-checkbox { .el-checkbox {
margin-right: 5px!important; margin-right: 5px !important;
} }
.importJson { .importJson {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -1721,6 +1620,4 @@ export default {
.popDiloag .popDiloag-title { .popDiloag .popDiloag-title {
font-weight: 500; font-weight: 500;
} }
.popDiloag .popDiloag-p {
}
</style> </style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +1,52 @@
const {defineConfig} = require('@vue/cli-service') const {defineConfig} = require('@vue/cli-service')
const postcssPxToViewport = require('postcss-px-to-viewport') const postcssPxToViewport = require('postcss-px-to-viewport')
const path = require('path') // 需要引入 path 模块 const path = require('path')
module.exports = defineConfig({ module.exports = defineConfig({
publicPath: './', publicPath: './',
transpileDependencies: false, transpileDependencies: false, // 我们自己管,不让 CLI 插手
lintOnSave: false, lintOnSave: false,
devServer: { devServer: {client: {overlay: false}},
client: {
overlay: false, configureWebpack(config) {
}, // 调试
},
configureWebpack: (config) => {
//调试JS
config.devtool = 'source-map' config.devtool = 'source-map'
config.resolve = { // 别名
alias: { config.resolve.alias['@'] = path.resolve(__dirname, 'src')
'@': path.resolve(__dirname, 'src'),
}, /* 1. 追加 ini 规则 */
} config.module.rules.push({
// 添加 .ini 文件处理规则 test: /\.ini$/,
if (config.module && config.module.rules) { use: 'raw-loader',
config.module.rules.push({ })
test: /\.ini$/,
use: 'raw-loader' /* 2. 追加 ES5 规则(只转 src不转 node_modules */
}) // config.module.rules.push({
} else { // test: /\.js$/,
config.module = { // include: path.resolve(__dirname, 'src'),
rules: [ // use: {
{ // loader: 'babel-loader',
test: /\.ini$/, // options: {
use: 'raw-loader' // presets: [
} // [
] // '@babel/preset-env',
} // {
} // targets: {ie: '11'}, // 强制 ES5
// corejs: 3,
// useBuiltIns: 'entry',
// },
// ],
// ],
// },
// },
// })
}, },
css: { css: {
/* 你的 px-to-viewport 配置不动 */
loaderOptions: { loaderOptions: {
postcss: { postcss: {
postcssOptions: { postcssOptions: {
// 增加这一层 postcssOptions
plugins: [ plugins: [
postcssPxToViewport({ postcssPxToViewport({
unitToConvert: 'px', unitToConvert: 'px',
@ -53,7 +59,7 @@ module.exports = defineConfig({
minPixelValue: 1, minPixelValue: 1,
mediaQuery: false, mediaQuery: false,
replace: true, replace: true,
exclude: /(\/|\\)(node_modules)(\/|\\)/, exclude: /node_modules/,
include: [], include: [],
landscape: false, landscape: false,
}), }),