import * as mars3d from "mars3d"
export let map // mars3d.Map三维地图对象
let polygonLayer
let graphicLayer
export const mapOptions = {
scene: {
center: { lat: 31.855058, lng: 117.312337, alt: 79936, heading: 0, pitch: -90 }
}
}
/**
* 初始化地图业务,生命周期钩子函数(必须)
* 框架在地图初始化完成后自动调用该函数
* @param {mars3d.Map} mapInstance 地图对象
* @returns {void} 无
*/
export function onMounted(mapInstance) {
map = mapInstance // 记录map
// 加载面数据
loadPolygon()
graphicLayer = new mars3d.layer.GraphicLayer()
map.addLayer(graphicLayer)
}
/**
* 释放当前地图业务的生命周期函数
* @returns {void} 无
*/
export function onUnmounted() {
map = null
}
export function clearGraphicLayer() {
graphicLayer.clear()
}
// 绘制线
export function drawLine() {
clearGraphicLayer()
graphicLayer.startDraw({
type: "polyline",
maxPointNum: 2,
style: {
color: "#55ff33",
width: 3
},
success: (graphic) => {
const clipLine = graphic.toGeoJSON()
clipAllPolygon(clipLine)
graphic.remove()
}
})
}
// 加载面数据
function loadPolygon() {
polygonLayer = new mars3d.layer.GraphicLayer()
map.addLayer(polygonLayer)
const postionArr = [
{
postions: [
[117.21983, 31.780687],
[117.179661, 31.745352],
[117.201462, 31.727826],
[117.258453, 31.727534],
[117.27459, 31.757619],
[117.270985, 31.775139],
[117.26738, 31.774701],
[117.259827, 31.783752],
[117.21983, 31.780687]
]
},
{
postions: [
[117.490393, 31.88435],
[117.596823, 31.895413],
[117.626349, 31.784167],
[117.449369, 31.775197],
[117.490393, 31.88435]
]
},
{
postions: [
[117.250042, 31.954209],
[117.273903, 31.970234],
[117.306862, 31.957994],
[117.303772, 31.912971],
[117.293816, 31.901294],
[117.269611, 31.900128],
[117.250042, 31.954209]
]
},
{
postions: [
[117.168674, 31.964546],
[117.202492, 31.926669],
[117.132111, 31.923592],
[117.125759, 31.95099],
[117.168674, 31.964546]
]
}
]
for (let i = 0; i < postionArr.length; i++) {
const polygonGraphic = new mars3d.graphic.PolygonEntity({
positions: [postionArr[i].postions],
style: {
color: "#00ffff",
opacity: 0.2,
clampToGround: true
}
})
polygonLayer.addGraphic(polygonGraphic)
}
}
// 循环所有面,判断相交的去切割面
function clipAllPolygon(clipLine) {
polygonLayer.eachGraphic(function (graphic) {
try {
const clippedPolygon = geoUtil.polygonClipByLine(graphic.toGeoJSON(), clipLine)
graphicLayer.loadGeoJSON(clippedPolygon, {
style: {
randomColor: true,
opacity: 0.5,
outline: true,
outlineWidth: 2,
outlineColor: "#ffffff",
clampToGround: true
}
})
} catch (error) {
// globalMsg('
' + error.state + ":" + error.message + "
");S
}
})
}
/**
* geoJson数据处理模块(需要引入turf.js)
* 输入输出数据均为标准geoJson格式
*/
const geoUtil = {
// 合并多边形
unionPolygon: function (polygons) {
let polygon = polygons[0]
for (let i = 0; i < polygons.length; i++) {
polygon = turf.union(polygon, polygons[i])
}
return polygon
},
/**
* 线分割面
* 面类型只能是polygon 但可以是环
* 注:线与多边形必须有两个交点
*/
polygonClipByLine: function (polygon, clipLine) {
if (polygon.geometry.type === "Polygon") {
const polyLine = turf.polygonToLine(polygon)
if (polyLine.geometry.type === "LineString") {
// 切割普通多边形
return this._singlePolygonClip(polyLine, clipLine)
} else if (polyLine.geometry.type === "MultiLineString") {
// 切割环
return this._multiPolygonClip(polyLine, clipLine)
}
} else if (polygon.geometry.type === "MultiPolygon") {
// 若输入的多边形类型为Multipolygon则拆分成多个Polygon
const polygons = this.multiPolygon2polygons(polygon)
let clipPolygon = null
let clipPolygonIndex = -1
// 获取MultiPolygon中与切割线相交的多边形(有且只能有一个多边形相交2个交点)
polygons.forEach(function (polygon, index) {
const polyLine = turf.polygonToLine(polygon)
if (turf.lineIntersect(polyLine, clipLine).features.length === 2) {
if (!clipPolygon) {
clipPolygon = polygon
clipPolygonIndex = index
} else {
throw new Error({ state: "裁剪失败", message: "MultiPolygon只能有一个多边形与切割线存在交点" })
}
}
})
if (clipPolygonIndex !== -1) {
polygons.splice(clipPolygonIndex, 1)
return turf.featureCollection(polygons.concat(this.polygonClipByLine(clipPolygon, clipLine).features))
} else {
throw new Error({ state: "裁剪失败", message: "MultiPolygon与切割线无交点" })
}
} else {
throw new Error({ state: "裁剪失败", message: "输入的多边形类型为错误" })
}
},
_singlePolygonClip: function (polyLine, clipLine) {
// 获得裁切点
const intersects = turf.lineIntersect(polyLine, clipLine)
if (intersects.features.length !== 2) {
throw new Error({ state: "裁剪失败", message: "切割线与多边形交点应该为2个,当前交点个数为" + intersects.features.length })
}
// 检查切割线与多边形的位置关系 (切割线的起点和终点不能落在多边形内部)
const clipLineLength = clipLine.geometry.coordinates.length
const clipLineStartPoint = turf.point(clipLine.geometry.coordinates[0])
const clipLineEndPoint = turf.point(clipLine.geometry.coordinates[clipLineLength - 1])
const polygon = turf.polygon([polyLine.geometry.coordinates])
if (turf.booleanPointInPolygon(clipLineStartPoint, polygon) || turf.booleanPointInPolygon(clipLineEndPoint, polygon)) {
throw new Error({ state: "裁剪失败", message: "切割线起点或终点不能在 裁剪多边形内部" })
}
// 通过裁切点 分割多边形(只能获得多边形的一部分)
const slicedPolyLine = turf.lineSlice(intersects.features[0], intersects.features[1], polyLine)
// 裁剪线分割 保留多边形内部部分
const slicedClipLine = turf.lineSlice(intersects.features[0], intersects.features[1], clipLine)
// 重新拼接多边形 存在 对接的问题 所以先进行判断 如何对接裁剪的多边形和裁剪线
const resultPolyline1 = this.connectLine(slicedPolyLine, slicedClipLine)
// 闭合线 来构造多边形
resultPolyline1.geometry.coordinates.push(resultPolyline1.geometry.coordinates[0])
const resultPolygon1 = turf.lineToPolygon(resultPolyline1)
// 构造切割的另一面多边形
const firstPointOnLine = this.isOnLine(turf.point(polyLine.geometry.coordinates[0]), slicedPolyLine)
const pointList = []
if (firstPointOnLine) {
for (let i = 0; i < polyLine.geometry.coordinates.length; i++) {
const coordinate = polyLine.geometry.coordinates[i]
if (!this.isOnLine(turf.point(coordinate), slicedPolyLine)) {
pointList.push(coordinate)
}
}
} else {
let skipNum = 0 // 记录前面被跳过的点的个数
let isStartPush = false
for (let i = 0; i < polyLine.geometry.coordinates.length; i++) {
const coordinate = polyLine.geometry.coordinates[i]
if (!this.isOnLine(turf.point(coordinate), slicedPolyLine)) {
if (isStartPush) {
pointList.push(coordinate)
} else {
skipNum++
}
} else {
isStartPush = true
}
}
// 将前面跳过的点补充到 点数组中
for (let i = 0; i < skipNum; i++) {
pointList.push(polyLine.geometry.coordinates[i])
}
}
const slicedPolyLine_2 = turf.lineString(pointList)
const resultPolyline2 = this.connectLine(slicedPolyLine_2, slicedClipLine)
// 闭合线 来构造多边形
resultPolyline2.geometry.coordinates.push(resultPolyline2.geometry.coordinates[0])
const resultPolygon2 = turf.lineToPolygon(resultPolyline2)
// 返回面要素集
return turf.featureCollection([resultPolygon1, resultPolygon2])
},
_multiPolygonClip: function (polyLine, clipLine) {
// 将环 多边形分割成 内部逆时针多边形+外部多边形
let outPolyline
const insidePolylineList = []
for (let i = 0; i < polyLine.geometry.coordinates.length; i++) {
const splitPolyline = turf.lineString(polyLine.geometry.coordinates[i])
if (turf.booleanClockwise(splitPolyline)) {
if (outPolyline) {
throw new Error({ state: "裁剪失败", message: "出现了两个外部多边形无法处理" })
} else {
outPolyline = splitPolyline
}
} else {
const intersects = turf.lineIntersect(splitPolyline, clipLine)
if (intersects.features.length > 0) {
throw new Error({ state: "裁剪失败", message: "切割线不能与内环有交点" })
}
insidePolylineList.push(splitPolyline)
}
}
const resultCollection = this._singlePolygonClip(outPolyline, clipLine)
for (let i = 0; i < resultCollection.features.length; i++) {
for (let j = 0; j < insidePolylineList.length; j++) {
const startPoint = turf.point(insidePolylineList[j].geometry.coordinates[0])
if (turf.booleanPointInPolygon(startPoint, resultCollection.features[i])) {
resultCollection.features[i] = turf.mask(resultCollection.features[i], turf.lineToPolygon(insidePolylineList[j]))
}
}
}
return resultCollection
},
/**
* 连接两条线
* 方法会将两条线段最近的一段直接连接
*/
connectLine: function (line1, line2) {
const line2_length = line2.geometry.coordinates.length
const line1_startPoint = line1.geometry.coordinates[0]
const line2_startPoint = line2.geometry.coordinates[0]
const line2_endPoint = line2.geometry.coordinates[line2_length - 1]
const pointList = []
// 获取line1 所有点坐标
for (let i = 0; i < line1.geometry.coordinates.length; i++) {
const coordinate = line1.geometry.coordinates[i]
pointList.push(coordinate)
}
// 判断两条线的 起点是否接近,如果接近 逆转line2线 进行连接
if (turf.distance(line1_startPoint, line2_startPoint) < turf.distance(line1_startPoint, line2_endPoint)) {
line2.geometry.coordinates = line2.geometry.coordinates.reverse()
}
for (let i = 0; i < line2.geometry.coordinates.length; i++) {
const coordinate = line2.geometry.coordinates[i]
pointList.push(coordinate)
}
return turf.lineString(pointList)
},
/**
* 判断点是否在线里面
* 注:线组成的坐标对比
*/
isOnLine: function (point, line) {
for (let i = 0; i < line.geometry.coordinates.length; i++) {
const coordinate = line.geometry.coordinates[i]
if (point.geometry.coordinates[0] === coordinate[0] && point.geometry.coordinates[1] === coordinate[1]) {
return true
}
}
return false
},
/**
* 获得两条线交点
*/
getIntersectPoints: function (line1, line2) {
return turf.lineIntersect(line1, line2)
},
// multiPolygon转polygons,不涉及属性
multiPolygon2polygons: function (multiPolygon) {
if (multiPolygon.geometry.type !== "MultiPolygon") {
return
}
const polygons = []
multiPolygon.geometry.coordinates.forEach((item) => {
const polygon = {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: []
}
}
polygon.geometry.coordinates = item
polygons.push(polygon)
})
return polygons
},
/**
* polygons转multiPolygon,不涉及属性,只输出属性为{}
* 考虑polygons中就存在多面的情况
*/
polygons2MultiPolygon: function (geoJson) {
const newGeoJson = {
type: "FeatureCollection",
features: [{ geometry: { coordinates: [], type: "MultiPolygon" }, type: "Feature", properties: {} }]
}
geoJson.features.forEach((item) => {
if (item.geometry.type === "Polygon") {
newGeoJson.features[0].geometry.coordinates.push(item.geometry.coordinates)
} else {
item.geometry.coordinates.forEach((item) => {
newGeoJson.features[0].geometry.coordinates.push(item)
})
}
})
return newGeoJson
}
}