@ -8,10 +8,12 @@
< img @click ="drawAvoidArea" src = "@/assets/image/updown.png" / >
< div @click ="clear" class = "sure" > 清除 < / div >
< div @click ="calculateShortestPath" class = "sure" > 确定 < / div >
< div @click ="hadBuffer" class = "sure" > 路线隐蔽规划 < / div >
< div @click ="pointBuffer" class = "sure" > 点隐蔽规划 < / div >
<!-- < div class = "control-panel" >
< button @click ="drawStartPoint" > 绘制起点 < / button >
< button @click ="drawEndPoint" > 绘制终点 < / button >
< button @click ="drawViaPoint" > 绘制途径 点 < / button >
< button @click ="drawViaPoint" > 绘制途经 点 < / button >
< button @click ="drawAvoidPoint" > 绘制避让点 < / button >
< button @click ="drawAvoidArea" > 绘制避让区域 < / button >
< button @click ="calculateShortestPath" > 计算最短路径 < / button >
@ -24,7 +26,7 @@
< div class = "title" > 参数 < / div >
< el-form
@submit.native.prevent ="calculateShortestPath"
label -width = " 10 0px "
label -width = " 12 0px "
label -position = " left "
size = "mini"
:model = "form"
@ -45,7 +47,7 @@
clearable
> < / el-input >
< / el-form-item >
< el-form-item label = "途径 点" >
< el-form-item label = "途经 点" >
< div v-for = "(item, index) in form.viaPoints" :key="index" >
< el -input
v-model = "item.points"
@ -78,10 +80,6 @@
> < / el-input >
< / div >
< / el-form-item >
<!-- < el-form-item >
< el-button type = "primary" @click ="calculateShortestPath" > 计算最短路径 < / el -button >
< el-button @click ="clear" > 清除所有 < / el -button >
< / el-form-item > -- >
< / el-form >
< input
type = "file"
@ -92,10 +90,31 @@
< div class = "importJson" @click ="triggerFileUpload" > 导入json文件 < / div >
< / div >
< div class = "control-panel" >
< div class = "title" > 机动属性 < / div >
< div class = "title" > 隐蔽添加 < / div >
< el-form
label -width = " 120px "
label -position = " left "
size = "mini"
>
< el-form-item label = "缓冲半径( m) " >
< el-input v-model = "hideform.radius" > < / el -input >
< / el-form-item >
< el-form-item label = "面积冗余(%) " >
< el-input v-model = "hideform.redundancy" placeholder="" > < / el -input >
< / el-form-item >
< / el-form >
< / div >
< div class = "control-panel" >
< div class = "title" >
< span > 机动属性 < / span >
< div class = "joinCheck" >
< el-checkbox v-model = "join" > < / el -checkbox >
< span > 参与路线规划 < / span >
< / div >
< / div >
< el-form
@submit.native.prevent ="calculateShortestPath"
label -width = " 10 0px "
label -width = " 12 0px "
label -position = " left "
size = "mini"
>
@ -116,12 +135,11 @@
< / div >
< / div >
< div id = "map" > < / div >
<!-- < div id = "mapbox" > < / div > -- >
< div class = "main-container" style = "width: 452px" >
< div class = "control-panel" style = "width: 452px" >
< div style = "font-size: 14px; margin-bottom: 10px" >
详细路线 : < br / >
起点 ( { { form . startPoint } } ) , 途径 点 ( { {
起点 ( { { form . startPoint } } ) , 途经 点 ( { {
form . viaPoints . length > 0 && form . viaPoints [ 0 ] . points
? form . viaPoints . map ( ( item ) => item . points ) . join ( ';' )
: ''
@ -138,7 +156,7 @@
inputform . minTurnRadius || 0
} } , 最大车辆载重 { { inputform . load || 0 } } 吨
< / div >
< vxe-table ref = "xTable" :data = "infoList" >
< 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 = "80px" > < / vxe-column >
< vxe-column field = "宽度" title = "路宽" > < / vxe-column >
@ -147,24 +165,79 @@
< vxe-column field = "水深" title = "水深" > < / vxe-column >
< vxe-column field = "净空高" title = "净空高" width = "65px" > < / vxe-column >
< / vxe-table >
< vxe-table :data = "factoriesWithVehicles" style = "margin-top: 10px;" >
< vxe-column field = "options.style.properties.FID_1" title = "厂房id" > < / vxe-column >
< vxe-column field = "area" title = "面积(㎡)" >
< template v-slot = "{ row }" >
{{ row.area.toFixed ( 2 ) }}
< / template >
< / vxe -column >
< vxe-column field = "vehicles" title = "车辆" >
< template v-slot = "{ row }" >
{{ ( row.vehicles.map ( item = > item . name ) ) . join ( ',' ) } }
< / template >
< / vxe-column >
< / vxe-table >
< / div >
< / div >
< el-dialog :visible.sync = "dialogVisible" title = "机动属性 " width = "6 00px" >
< el-dialog :visible.sync = "dialogVisible" title = "车辆选择 " width = "8 00px" >
< div style = "margin-bottom: 10px;" >
< el-button type = "primary" size = "mini" @click ="handleAdd" > 新增 < / el -button >
< / div >
< vxe-table
height = "300px"
ref = "vxeTable"
:data = "tableData"
: row -config = " { isCurrent : true , isHover : true } "
: row -config = " { isCurrent : true , isHover : true , keyField : ' id ' } "
: checkbox -config = " { checkField : ' checked ' , highlight : true } "
@ checkbox -change = " handleSelectionChange "
@ checkbox -all = " handleSelectionChange "
@close ="closeSelection"
align = "center"
>
< vxe-column type = "checkbox" width = "50" > < / vxe-column >
< vxe-column field = "width " title = "宽度" > < / vxe-column >
< vxe-column field = "load" title = "载重(吨)" > < / vxe-column >
< vxe-column field = "minTurnRadius" title = "最小转弯半径" > < /vxe-column >
< vxe-column field = "name " title = "名称" width = "100" >
< template v-slot = "{ row }" >
< el -input v-if = "row.editing" v-model="row.name" size="mini" > < /el -input >
< span v-else > {{ row.name }} < / span >
< / template >
< / vxe -column >
< vxe-column field = "long" title = "长度" width = "100" >
< template v-slot = "{ row }" >
< el -input v-if = "row.editing" v-model="row.long" size="mini" > < / el -input >
< span v-else > {{ row.long }} < / span >
< / template >
< / vxe -column >
< vxe-column field = "width" title = "宽度" width = "100" >
< template v-slot = "{ row }" >
< el -input v-if = "row.editing" v-model="row.width" size="mini" > < / el -input >
< span v-else > {{ row.width }} < / span >
< / template >
< / vxe -column >
< vxe-column field = "load" title = "载重(吨)" width = "100" >
< template v-slot = "{ row }" >
< el -input v-if = "row.editing" v-model="row.load" size="mini" > < / el -input >
< span v-else > {{ row.load }} < / span >
< / template >
< / vxe -column >
< vxe-column field = "minTurnRadius" title = "最小转弯半径" >
< template v-slot = "{ row }" >
< el -input v-if = "row.editing" v-model="row.minTurnRadius" size="mini" > < / el -input >
< span v-else > {{ row.minTurnRadius }} < / span >
< / template >
< / vxe -column >
< vxe-column title = "操作" width = "100" >
< template v-slot = "{ row }" >
< 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 type = "text" size = "mini" @click ="handleDelete(row)" > 删除 < / el -button >
< / template >
< / vxe-column >
< / vxe-table >
< div slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisible = false "> 取消 < / el -button >
< el-button type = "primary" @click ="confirmSelection" > 确定 < / el -button >
< el-button size = "mini" @click ="closeSelection "> 取消 < / el -button >
< el-button type = "primary" size = "mini" @click ="confirmSelection" > 确定 < / el -button >
< el-button type = "primary" size = "mini" @click ="suerCofirm" > 保存 < / el -button >
< / div >
< / el-dialog >
< / div >
@ -172,7 +245,10 @@
< / template >
< script >
import router from '@/router '
import Cookies from 'js-cookie '
import axios from 'axios'
import iniParser from 'ini-parser'
import configIni from '/config.ini' ;
export default {
data ( ) {
@ -198,14 +274,26 @@ export default {
pointQD : null ,
pointZD : null ,
shortestPathLayer : null ,
shortestPathList : [ ] ,
infoList : [ ] ,
roadNetworkLayer : null ,
roadNetworkGeoJSON : null ,
mapOptions : null ,
viaPoints : [ ] , // 途径 点
viaPoints : [ ] , // 途经 点
avoidPoints : [ ] , // 避让点
avoidAreas : [ ] , // 避让区域
roadNetworkGeoJSONBuild : null ,
hideform : {
radius : 3000 ,
redundancy : 10 ,
} ,
join : false ,
bufferLayerList : [ ] , // 缓冲区信息
factoryGeoJSON : [ ] , // 拿到的所有的厂房数据
accordFactoryInfo : [ ] , // 在缓冲区 符合条件的厂房
factoriesWithVehicles : [ ] , // 塞入车的厂房集合
accordFactoryLayer : null , // 隐蔽规划
accordPoint : null , // 隐蔽规划点
}
} ,
async mounted ( ) {
@ -220,10 +308,6 @@ export default {
} ,
methods : {
destroyMap ( ) {
// if (this.viewer) {
// this.viewer.destroy();
// this.viewer = null;
// }
this . clear ( )
} ,
async getMapOption ( ) {
@ -237,6 +321,7 @@ export default {
. catch ( ( error ) => { } )
} ,
async initMap ( ) {
const parsedData = iniParser . parse ( configIni ) ;
this . viewer = new window . mars3d . Map (
'map' ,
{
@ -247,11 +332,23 @@ export default {
center : {
lat : 27.729862392917948 ,
lng : 114.27980291774088 ,
alt : 3808 ,
alt : 45000 ,
heading : 5 ,
pitch : - 35 ,
} ,
} ,
// basemaps: [
// {
// id: "image-tdss",
// name: "影像图",
// type: "xyz",
// // url: `http:/www.tdss.website:280/tiles/img_c/{z}/{x}/{y}`,
// url: `http://${parsedData.http.address}:${parsedData.http.port}/web/imgs/{z}/{x}/{y}`,
// // crs: "EPSG:4490",
// crs: "EPSG:3857",
// show: true
// }
// ],
} || { }
)
this . graphicLayer = new window . mars3d . layer . GraphicLayer ( )
@ -259,7 +356,10 @@ export default {
this . shortestPathLayer = new window . mars3d . layer . GraphicLayer ( )
this . viewer . addLayer ( this . shortestPathLayer )
this . loadShapefile ( )
this . accordFactoryLayer = new window . mars3d . layer . GraphicLayer ( )
this . viewer . addLayer ( this . accordFactoryLayer )
this . loadShapefile ( ) // 拿到路网数据
// 添加地图点击事件监听,用于结束绘制
this . viewer . on ( mars3d . EventType . dblClick , ( event ) => {
// 如果正在绘制,点击地图可以结束绘制(除了绘制点)
@ -267,6 +367,7 @@ export default {
} )
} ,
clear ( ) {
this . graphicLayer . stopDraw ( )
// 清除起点
if ( this . pointQD ) {
this . pointQD . remove ( )
@ -281,7 +382,7 @@ export default {
this . form . endPoint = ''
}
if ( this . viaPoints . length > 0 ) {
// 清除途径 点
// 清除途经 点
this . viaPoints . forEach ( ( point ) => {
point . remove ( )
} )
@ -310,6 +411,14 @@ export default {
// 清除最短路径图层
this . shortestPathLayer . clear ( )
this . infoList = [ ]
this . shortestPathList = [ ]
}
if ( this . accordFactoryLayer ) {
// 清除路线隐蔽规划
this . accordFactoryLayer . clear ( )
this . accordFactoryInfo = [ ]
this . bufferLayerList = [ ]
this . factoriesWithVehicles = [ ]
}
} ,
async loadShapefile ( ) {
@ -330,45 +439,422 @@ export default {
// 2. 处理 GeoJSON 数据
this . roadNetworkGeoJSON = shpBuffer
/// 3. 将 GeoJSON 数据添加到 graphicLayer
this . roadNetworkGeoJSON . features . forEach ( ( feature ) => {
const positions = feature . geometry . coordinates [ 0 ]
const graphic = new window . mars3d . graphic . PolylineEntity ( {
positions : positions ,
// ====网路图=====
const graphicLine = new window . mars3d . graphic . PolylineEntity ( {
positions : feature . geometry . coordinates [ 0 ] ,
style : {
color : '#FF0000' ,
width : 2 ,
outline : false ,
} ,
} )
this . graphicLayer . addGraphic ( graphic )
this . graphicLayer . addGraphic ( graphicLine ) ;
} )
this . roadNetworkGeoJSONBuild = this . buildGraph ( this . roadNetworkGeoJSON )
this . loadFactoryGeoJson ( ) // 拿到厂房数据
} catch ( error ) {
console . error ( '加载 Shapefile 数据失败:' , error )
}
} ,
// 弹框
async openDialog ( ) {
await fetch ( './data/minTurnRadius.json' )
// 获取厂房的数据
async loadFactoryGeoJson ( ) {
try {
const shpBuffer = await fetch ( './config/factory.geojson' )
. then ( ( response ) => {
return response . json ( )
} )
. then ( ( data ) => {
this . tableData = data
return data
} )
. catch ( ( error ) => { } )
this . factoryGeoJSON = shpBuffer
} catch ( error ) {
console . error ( '加载厂房数据失败:' , error )
}
} ,
// 去绘制点 进行隐蔽规划
pointBuffer ( ) {
if ( this . shortestPathList . length > 0 || this . accordFactoryInfo > 0 ) {
this . $message . warning ( '请先清空路线以及路线隐蔽规划' )
return
}
if ( this . accordPoint ) {
this . accordPoint . remove ( )
this . accordPoint = null
}
if ( this . accordFactoryLayer ) {
// 清除点的隐蔽规划
this . accordFactoryLayer . clear ( )
this . accordFactoryInfo = [ ]
this . factoriesWithVehicles = [ ]
}
this . accordFactoryLayer . startDraw ( {
type : 'point' ,
style : {
pixelSize : 10 ,
color : '#55ff33' ,
} ,
success : ( graphic ) => {
this . accordPoint = graphic
try {
// 创建缓冲区的宽度
const bufferWidth = this . hideform . radius ; // 避让区的宽度(单位:米)
// 获取绘制的点的坐标
const pointCoordinates = [
graphic . toGeoJSON ( ) . geometry . coordinates [ 0 ] ,
graphic . toGeoJSON ( ) . geometry . coordinates [ 1 ] ,
]
// 创建点的 GeoJSON 特征
const pointFeature = {
type : 'Feature' ,
geometry : {
type : 'Point' ,
coordinates : pointCoordinates ,
} ,
properties : { } ,
} ;
// 使用 Turf.js 计算缓冲区
let buffered = turf . buffer ( pointFeature , bufferWidth / 1000 , { units : 'kilometers' } ) ;
// 将缓冲区存储到数组中
this . bufferLayerList . push ( buffered ) ;
const polygon = new window . mars3d . graphic . PolygonEntity ( {
positions : buffered . geometry . coordinates [ 0 ] ,
style : {
color : '#d4e5db' ,
opacity : 0.5 ,
outline : true ,
outlineWidth : 1 ,
outlineColor : '#ffffff' ,
} ,
time : new Date ( ) . getTime ( )
} )
this . accordFactoryLayer . addGraphic ( polygon ) ;
// 检查缓冲区内的厂房
this . checkFactoryInBuffer ( 'point' , pointCoordinates ) ;
} catch ( error ) {
console . error ( "缓冲区生成或检查异常:" , error ) ;
}
} ,
} )
} ,
// 获取当前路线的缓冲区
hadBuffer ( ) {
if ( this . shortestPathList . length == 0 ) {
this . $message . warning ( '请先进行路线规划' )
return
}
if ( JSON . parse ( Cookies . get ( 'minTurnRadius' ) ) . length == 0 ) {
this . $message . warning ( '请先选择车辆' )
return
}
try {
// =======检查几何对象的类型 缓冲区========
for ( const feature of this . shortestPathList [ 0 ] ) {
// this.shortestPathList[0].forEach((feature) => {
// 创建缓冲区的宽度
const bufferWidth = this . hideform . radius ; // 避让区的宽度(单位:米)
if ( feature . geometry . type === 'LineString' ) {
const positions = feature . geometry . coordinates [ 0 ] ;
// 确保每条线至少有 2 个点
if ( positions . length < 2 ) {
console . warn ( '无效的线,跳过:' , feature ) ;
return ;
}
try {
// 使用 Turf.js 计算缓冲区
var buffered = turf . buffer ( feature , bufferWidth / 1000 , { units : 'kilometers' } ) ;
// 将缓冲区存储到数组中
this . bufferLayerList . push ( buffered ) ;
} catch ( error ) {
console . error ( "缓冲分析异常:" , error ) ;
}
} else if ( feature . geometry . type === 'MultiLineString' ) {
// 遍历每个线段
feature . geometry . coordinates . forEach ( ( lineCoordinates ) => {
// 检查每个线段是否有效
if ( lineCoordinates . length < 2 ) {
console . warn ( '多线段中的无效的线段,跳过:' , lineCoordinates ) ;
return ;
}
// 创建单个线段的 GeoJSON 特征
const lineFeature = {
type : 'Feature' ,
geometry : {
type : 'LineString' ,
coordinates : lineCoordinates ,
} ,
properties : feature . properties
} ;
try {
// 使用 Turf.js 计算缓冲区
var buffered = turf . buffer ( lineFeature , bufferWidth / 1000 , { units : 'kilometers' } ) ;
// 将缓冲区存储到数组中
this . bufferLayerList . push ( buffered ) ;
} catch ( error ) {
console . error ( "缓冲分析异常:" , error ) ;
}
} ) ;
} else {
console . warn ( '不支持的几何类型:' , feature . geometry . type ) ;
}
}
// 去筛选在缓存区的厂房
this . checkFactoryInBuffer ( 'line' ) ;
} catch ( error ) {
console . error ( "处理路径列表时发生错误:" , error ) ;
}
} ,
checkFactoryInBuffer ( type , pointInfo ) {
if ( ! this . factoryGeoJSON || ! this . bufferLayerList . length ) {
this . $message . warning ( '厂房数据或缓冲区数据未加载' )
return
}
if ( JSON . parse ( Cookies . get ( 'minTurnRadius' ) ) . length == 0 ) {
this . $message . warning ( '请先选择车辆' )
return
}
// 将缓冲区数据转换为 Turf.js 的 FeatureCollection
// 遍历每个厂房
const factoryGeoJSON = JSON . parse ( JSON . stringify ( this . factoryGeoJSON ) )
const factoryPromises = factoryGeoJSON . features . map ( ( factory ) => {
return new Promise ( ( resolve , reject ) => {
// 检查几何对象的类型
if ( factory . geometry . type === 'MultiPolygon' ) {
// 创建多边形集合( MultiPolygon)
const factoryMultiPoly = turf . multiPolygon ( factory . geometry . coordinates ) ;
// 计算整个多边形集合的面积
const area = turf . area ( factoryMultiPoly ) ;
// 计算工厂多边形集合的边界框
const [ minX , minY , maxX , maxY ] = turf . bbox ( factoryMultiPoly ) ;
// 筛选与工厂边界框相交的缓冲区
const candidates = this . bufferLayerList . filter ( ( buffer ) => {
const [ bminX , bminY , bmaxX , bmaxY ] = turf . bbox ( buffer ) ;
return ! ( bmaxX < minX || bminX > maxX || bmaxY < minY || bminY > maxY ) ;
} ) ;
// 精确相交检测
let isInside = false ;
for ( const buffer of candidates ) {
if ( turf . booleanIntersects ( factoryMultiPoly , buffer ) ) {
// 如果工厂在缓冲区内,绘制所有多边形
isInside = true ;
this . drawFactory ( factory . geometry . coordinates , factory , area , pointInfo ) ;
break ;
}
}
// 如果工厂不在任何缓冲区内
resolve ( ) ;
} else {
reject ( new Error ( '不支持的几何类型' ) ) ;
}
} )
} ) ;
// 确保所有工厂处理完成后进行排序
Promise . allSettled ( factoryPromises )
. then ( async ( results ) => {
// 只有路线隐蔽规划需要塞入车辆 点的不需要
// 所有工厂处理完成,进行排序 按照距离近到远
this . accordFactoryInfo . sort ( ( a , b ) => a . distance - b . distance ) ;
// 拿到当前的车队车辆信息 并且算出面积 按照从大到小排序
const areaList = JSON . parse ( Cookies . get ( 'minTurnRadius' ) )
areaList . map ( ( item ) => {
item . area = Number ( item . long ) * Number ( item . width )
} )
areaList . sort ( ( a , b ) => b . area - a . area ) ;
// 初始化每个工厂的剩余面积
this . accordFactoryInfo . forEach ( factory => {
factory . remainingArea = factory . area ; // 记录每个工厂的剩余可用面积
factory . vehicles = [ ] ; // 确保每个工厂都有一个 vehicles 属性
} ) ;
// 遍历每个车辆,尝试塞入工厂
areaList . forEach ( ( vehicle ) => {
let isPlaced = false ;
// 遍历每个工厂,尝试塞入车辆
for ( let i = 0 ; i < this . accordFactoryInfo . length ; i ++ ) {
const factory = this . accordFactoryInfo [ i ] ;
// 检查工厂是否还有剩余面积
if ( factory . remainingArea >= vehicle . area ) {
// 塞入车辆
factory . vehicles . push ( {
... vehicle ,
remainingArea : factory . remainingArea - vehicle . area // 记录车辆塞入后的工厂剩余面积
} ) ;
// 更新工厂的剩余面积
factory . remainingArea -= vehicle . area ;
// 标记车辆已放置
isPlaced = true ;
break ;
}
}
// 如果车辆没有被放置,可以在这里处理(例如记录日志或显示警告)
if ( ! isPlaced ) {
console . warn ( ` 车辆 ${ vehicle . id } 无法放置在任何工厂中 ` ) ;
}
} ) ;
// 更新 this.accordFactoryInfo
this . accordFactoryInfo = this . accordFactoryInfo . map ( factory => {
// 确保每个工厂都有 vehicles 属性
if ( ! factory . vehicles ) {
factory . vehicles = [ ] ;
}
// 确保 remainingArea 是一个数字且大于 0
factory . area = factory . area > 0 ? factory . area : 0 ;
return factory ;
} ) ;
// 过滤出有车辆的工厂
const factoriesWithVehicles = this . accordFactoryInfo . filter ( factory => factory . vehicles . length > 0 ) ;
this . factoriesWithVehicles = factoriesWithVehicles
await this . showAreaInfoDialog ( factoriesWithVehicles ) ;
} )
. catch ( ( error ) => {
console . error ( '数据有问题' , error )
} ) ;
} ,
drawFactory ( factoryMultiPoly , factory , area , pointInfo ) {
// 获取当前多边形集合的中心点
const center = turf . center ( turf . multiPolygon ( factory . geometry . coordinates ) ) ;
// 将中心点转换为 Mars3D 的 LngLatPoint 对象
const popupPosition = new mars3d . LngLatPoint ( center . geometry . coordinates [ 0 ] , center . geometry . coordinates [ 1 ] ) ;
// 遍历每个多边形集合
factory . geometry . coordinates [ 0 ] . forEach ( ( coordGroup ) => {
// 创建一个多边形图形
const graphic = new window . mars3d . graphic . PolygonEntity ( {
positions : coordGroup . map ( ( coord ) => Cesium . Cartesian3 . fromDegrees ( coord [ 0 ] , coord [ 1 ] , 0 ) ) ,
style : {
color : 'red' ,
opacity : 0.4 ,
outline : true ,
outlineWidth : 1 ,
outlineColor : '#ffffff' ,
properties : { ... factory . properties } ,
} ,
time : new Date ( ) . getTime ( )
} )
this . accordFactoryLayer . addGraphic ( graphic ) ;
// 计算多边形中心与参考点的距离
const point = pointInfo && pointInfo . length > 0 ? pointInfo : this . form . endPoint . split ( ',' ) . map ( Number )
const distance = turf . distance ( center . geometry . coordinates , point , { units : 'kilometers' } ) * 1000 ; // 米
// 将多边形图形添加到地图层
this . accordFactoryInfo . push ( {
... graphic ,
distance : distance ,
popupPosition : popupPosition ,
area : this . hideform . redundancy && this . hideform . redundancy != 0 && area > 0
? area * ( 100 - this . hideform . redundancy ) * 0.01
: area > 0
? area
: 0 , // 如果 area 不是有效值,设置为 0 或其他默认值
} )
} )
} ,
// 显示面积信息弹框的方法
async showAreaInfoDialog ( info ) {
const graphics = this . accordFactoryLayer . getGraphics ( ) ;
const promises = [ ] ;
info . forEach ( ( item ) => {
graphics . forEach ( ( ele ) => {
if ( 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 ( {
id : 'label' ,
position : item . popupPosition ,
style : {
text : String ( textInfo ) , // 必须字符串
font _family : '楷体' ,
font _size : 24 ,
color : '#ffffff' ,
outline : true ,
outlineColor : '#000000' ,
background : true ,
backgroundColor : '#2f705f' ,
}
} )
// 使用 Promise 确保标签添加完成后继续执行
const promise = new Promise ( ( resolve , reject ) => {
this . accordFactoryLayer . addGraphic ( labelGraphic , ( ) => {
resolve ( ) ;
} ) ;
} ) ;
promises . push ( promise ) ;
}
} )
} )
this . $message . success ( "路线隐蔽规划成功" )
const popupPositionList = info . map ( item => item . popupPosition )
let minLng = Infinity ;
let maxLng = - Infinity ;
let minLat = Infinity ;
let maxLat = - Infinity ;
popupPositionList . forEach ( point => {
if ( point . lng < minLng ) minLng = point . lng ;
if ( point . lng > maxLng ) maxLng = point . lng ;
if ( point . lat < minLat ) minLat = point . lat ;
if ( point . lat > maxLat ) maxLat = point . lat ;
} ) ;
// 创建一个矩形区域,包含所有点
const rectangle = Cesium . Rectangle . fromDegrees ( minLng , minLat , maxLng , maxLat ) ;
this . viewer . scene . camera . flyTo ( {
destination : Cesium . Cartesian3 . fromDegrees (
( minLng + maxLng ) / 2 , // 中心经度
( minLat + maxLat ) / 2 , // 中心纬度
1000 // 增加高度,确保视野范围足够大
) ,
orientation : {
heading : Cesium . Math . toRadians ( 0 ) , // 方位角
pitch : Cesium . Math . toRadians ( - 90 ) , // 俯仰角
roll : 0.0 // 翻滚角
} ,
duration : 2 // 飞行动画持续时间,单位为秒
} ) ;
} ,
// 弹框
async openDialog ( ) {
this . multipleSelection = [ ]
await fetch ( './data/minTurnRadius.json' )
. then ( ( response ) => {
return response . json ( )
} )
. then ( async ( data ) => {
this . dialogVisible = true ;
this . tableData = data
await this . $nextTick ( ( ) => {
this . multipleSelection = JSON . parse ( Cookies . get ( 'minTurnRadius' ) )
this . multipleSelection . forEach ( ( item ) => {
this . $refs . vxeTable . setCheckboxRowKey ( item . id , true )
} )
} )
} )
. catch ( ( error ) => { } )
} ,
handleSelectionChange ( { records } ) {
this . multipleSelection = records
} ,
closeSelection ( ) {
this . dialogVisible = false
} ,
confirmSelection ( ) {
if ( this . multipleSelection . length === 0 ) {
this . $message . warning ( '请至少选择一行数据' )
return
}
Cookies . set ( 'minTurnRadius' , this . multipleSelection )
const maxValues = this . multipleSelection . reduce (
( acc , item ) => {
acc . width = Math . max ( acc . width , item . width )
@ -381,7 +867,47 @@ export default {
this . inputform . width = maxValues . width
this . inputform . load = maxValues . load
this . inputform . minTurnRadius = maxValues . minTurnRadius
this . dialogVisible = false
this . closeSelection ( )
} ,
/** 增删改查 */
handleAdd ( ) {
const newRow = {
id : this . tableData . length + 1 ,
name : '' ,
long : null ,
width : null ,
load : null ,
minTurnRadius : null ,
editing : true ,
} ;
this . tableData . push ( newRow ) ;
} ,
handleDelete ( row ) {
const index = this . tableData . findIndex ( item => item . id === row . id ) ;
if ( index !== - 1 ) {
this . tableData . splice ( index , 1 ) ;
}
} ,
handleEdit ( row ) {
this . $set ( row , 'editing' , true ) ;
} ,
handleSave ( row ) {
this . $set ( row , 'editing' , false ) ;
} ,
// 保存列表数据
suerCofirm ( ) {
const parsedData = iniParser . parse ( configIni ) ;
axios . post ( ` http:// ${ parsedData . http . address } : ${ parsedData . http . port } /api/equpment ` , JSON . stringify ( this . tableData ) , {
headers : {
'Authorization' : 'Bearer your_token_here' ,
'Content-Type' : 'application/json'
}
} )
. then ( response => {
this . $message . success ( '保存成功' )
} )
. catch ( error => {
} ) ;
} ,
// 导入json文件
triggerFileUpload ( ) {
@ -422,7 +948,7 @@ export default {
this . addPointToMap ( 'endPoint' , this . form . endPoint )
}
// 加载途径 点
// 加载途经 点
if ( uploadedJson . viaPoints ) {
this . form . viaPoints = uploadedJson . viaPoints
uploadedJson . viaPoints . forEach ( ( viaPoint ) => {
@ -470,7 +996,7 @@ export default {
: type === 'endPoint'
? '终点'
: type === 'viaPoints'
? '途径 点'
? '途经 点'
: '避让点' ,
font _size : 20 ,
color : '#ffffff' ,
@ -517,7 +1043,6 @@ export default {
} ,
// 输入框失去焦点 反向编辑点
pointsChange ( type , row ) {
console . log ( '111' , type )
if ( type === 'startPoint' ) {
if (
( ! this . form . startPoint ||
@ -530,7 +1055,11 @@ export default {
this . pointQD = null
return
}
if ( this . pointQD == null || this . pointQD == undefined || this . pointQD == '' ) {
this . addPointToMap ( 'startPoint' , this . form . startPoint )
} else {
this . updatePointPosition ( this . pointQD , this . form . startPoint )
}
} else if ( type === 'endPoint' ) {
if (
( ! this . form . endPoint ||
@ -543,7 +1072,11 @@ export default {
this . pointZD = null
return
}
if ( this . pointZD == null || this . pointZD == undefined || this . pointZD == '' ) {
this . addPointToMap ( 'endPoint' , this . form . endPoint )
} else {
this . updatePointPosition ( this . pointZD , this . form . endPoint )
}
} else if ( type === 'viaPoints' ) {
if ( ! row . points ) {
const graphic = this . viaPoints . find (
@ -725,7 +1258,7 @@ export default {
} ,
} )
} ,
// 途径 点
// 途经 点
drawViaPoint ( ) {
const time = Date . now ( )
this . graphicLayer . startDraw ( {
@ -734,7 +1267,7 @@ export default {
pixelSize : 10 ,
color : 'blue' ,
label : {
text : '途径 点' ,
text : '途经 点' ,
font _size : 20 ,
color : '#ffffff' ,
outline : true ,
@ -884,7 +1417,7 @@ export default {
}
return nearestNode
} ,
// 3. 路径规划主函数(经纬度坐标输入) - 支持途径 点 + 避让点/区域
// 3. 路径规划主函数(经纬度坐标输入) - 支持途经 点 + 避让点/区域
async planRoute (
startCoord ,
endCoord ,
@ -893,14 +1426,16 @@ export default {
) {
const { graph , nodeCoords } = this . roadNetworkGeoJSONBuild
// 按顺序组合点:起点 -> 途径 点 -> 终点
const points =
viaPoints && viaPoints . length > 0
? [ startCoord , viaPoints [ 0 ] . geometry . coordinates , endCoord ]
: [ startCoord , endCoord ]
// 按顺序组合点:起点 -> 途经 点 -> 终点
const points = [ startCoord ] ;
if ( viaPoints && viaPoints . length > 0 ) {
viaPoints . forEach ( ( viaPoint ) => {
points . push ( viaPoint . geometry . coordinates ) ;
} ) ;
}
points . push ( endCoord ) ;
const fullPath = [ ]
const infoList = [ ]
for ( let i = 0 ; i < points . length - 1 ; i ++ ) {
const segmentStart = points [ i ]
const segmentEnd = points [ i + 1 ]
@ -960,16 +1495,28 @@ export default {
for ( let j = 0 ; j < pathNodes . length - 1 ; j ++ ) {
const currentNode = pathNodes [ j ]
const nextNode = pathNodes [ j + 1 ]
cons t segment = this . roadNetworkGeoJSON . features . find (
le t segment = { }
// 是否参与路线规划 是 加入机动属性的判断 否就正常走
if ( ! this . join ) {
segment = this . roadNetworkGeoJSON . features . find (
( f ) =>
( f . properties . FNODE _ == currentNode &&
f . properties . TNODE _ == nextNode ) ||
( f . properties . FNODE _ == nextNode &&
f . properties . TNODE _ == currentNode )
)
} else {
segment = this . roadNetworkGeoJSON . features . find (
( f ) =>
( ( f . properties . FNODE _ == currentNode &&
f . properties . TNODE _ == nextNode ) ||
( f . properties . FNODE _ == nextNode &&
f . properties . TNODE _ == currentNode ) ) &&
f . properties . TNODE _ == currentNode ) ) &&
f . properties . 载重吨 >= this . inputform . load &&
f . properties . 宽度 >= this . inputform . width &&
f . properties . 曲率半 <= this . inputform . minTurnRadius
)
}
if ( segment ) {
fullPath . push ( ... segment . geometry . coordinates [ 0 ] )
infoList . push ( segment )
@ -985,13 +1532,14 @@ export default {
return
}
this . shortestPathLayer . clear ( )
this . shortestPathList = [ ]
this . infoList = [ ]
const startPoint = turf . point (
this . pointQD . toGeoJSON ( ) . geometry . coordinates
) . geometry . coordinates // 起点
const endPoint = turf . point ( this . pointZD . toGeoJSON ( ) . geometry . coordinates )
. geometry . coordinates // 终点
// 途径 点
// 途经 点
const viaPointsGeoJSON =
this . viaPoints . map ( ( point ) => point . toGeoJSON ( ) ) || [ ]
const viaPointsTurf = viaPointsGeoJSON . map ( ( p ) =>
@ -1003,7 +1551,7 @@ export default {
const avoidPointsPolygons = avoidPointsGeoJSON . map ( ( point ) => {
return turf . circle (
turf . point ( point . geometry . coordinates ) ,
10 , // 半径10米( 根据需求调整)
1000 , // 半径10米( 根据需求调整)
{ steps : 32 , units : 'meters' } // 显式指定单位
)
} )
@ -1036,8 +1584,13 @@ export default {
} ,
} )
this . shortestPathLayer . addGraphic ( polyline )
this . shortestPathList . push ( path . infoList )
this . infoList = path . infoList . map ( ( item ) => item . properties )
} ,
/** 隐蔽规划 */
concealed ( ) {
} ,
} ,
}
< / script >
@ -1067,7 +1620,8 @@ export default {
gap : 10 px ;
background : # 176363 ;
border - radius : 4 px ;
width : 5 4px ;
min - width: 1 4px ;
padding : 0 10 px ;
height : 24 px ;
color : # ffffff ;
font - weight : 400 ;
@ -1107,7 +1661,17 @@ export default {
/* text-align: center; */
margin - bottom : 10 px ;
color : # 1 c1c1c ;
display : flex ;
justify - content : space - between ;
}
. control - panel . title . joinCheck {
font - size : 14 px ;
color : # 555 ;
}
. el - checkbox {
margin - right : 5 px ! important ;
}
. importJson {
display : flex ;
flex - direction : row ;
@ -1148,4 +1712,15 @@ export default {
width : calc ( 100 vw - 792 px ) ;
height : 100 % ;
}
. popDiloag {
width : 100 px ;
font - size : 16 px ;
background : # d4e5db ;
color : # 1 c1c1c ;
}
. popDiloag . popDiloag - title {
font - weight : 500 ;
}
. popDiloag . popDiloag - p {
}
< / style >