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 } }