UNPKG

@orca-fe/x-map

Version:
165 lines (164 loc) 7.65 kB
import { AdditiveBlending, CatmullRomCurve3, Color, DoubleSide, ExtrudeGeometry, FrontSide, Mesh, MeshBasicMaterial, MeshStandardMaterial, Shape, TubeGeometry, Vector3, } from 'three'; import { difference, polygon, union } from '@turf/turf'; import { lonLat2Mercator } from '../../utils/coord'; import ThreeObject from './ThreeObject'; // Polygon | MultiPolygon -> MultiPolygon const geoJson2multiPolygon = (geoJson) => { const multiPolygon = { type: 'MultiPolygon', coordinates: [], }; if (geoJson.type === 'Polygon') { multiPolygon.coordinates = [geoJson.coordinates]; } else { multiPolygon.coordinates = geoJson.coordinates; } return multiPolygon; }; // 合成多个holes,并返回在范围内部分 const formatPolygonJson = (polygonJson) => { var _a; const { coordinates } = polygonJson; const shapePoint = [...coordinates]; const holes = shapePoint.splice(1).map(i => polygon([i])); if (holes.length === 0) { return polygonJson; } let [unionHoles] = holes; if (holes.length > 1) { unionHoles = holes.reduce((prev, next) => { const res = union(prev, next); if (res) return res; return prev; }); } return (_a = difference(polygon(shapePoint), unionHoles)) === null || _a === void 0 ? void 0 : _a.geometry; }; export default class ExtrudePolygonObject extends ThreeObject { constructor(options = {}) { super(options); this.object3D = new Mesh(); const { polygonGeoJson, fill = { color: 0x33ccff, opacity: 0.1 }, polygonMaterialParameters, polygonSideMaterialParameters, } = options; this.polygonGeoJson = polygonGeoJson; const color = new Color(fill.color); this.polygonFaceMaterial = new MeshStandardMaterial(Object.assign({ side: FrontSide, depthWrite: true, // depthTest: true, transparent: true, opacity: fill.opacity, color, roughness: 0.6, metalness: 0.5 }, polygonMaterialParameters)); this.polygonSideMaterial = new MeshBasicMaterial(Object.assign({ // blending: AdditiveBlending, side: FrontSide, depthWrite: true, depthTest: true, transparent: true, opacity: fill.opacity, color }, polygonSideMaterialParameters)); this.object3D.position.set(0, 0, this.z); } // 创建一个常规(不带孔)的shape createNormalPolygonShape(polygonJson) { var _a; const shape = new Shape(); const positions = []; const pointPositions = []; if (!((_a = this.layer) === null || _a === void 0 ? void 0 : _a.map)) return { shape }; const { threeCenter } = this.layer.map; const { coordinates } = polygonJson; const [shapePoint = []] = coordinates; for (let i = 0; i < shapePoint.length; i++) { const [x, y] = lonLat2Mercator(shapePoint[i]).map((value, index) => value - threeCenter[index]); if (i === 0) { shape.moveTo(x, y); } shape.lineTo(x, y); positions.push(x, y, 0); pointPositions.push([x, y, 0]); } return { shape, positions: pointPositions }; } createObject() { var _a, _b, _c; if (!((_a = this.layer) === null || _a === void 0 ? void 0 : _a.map)) return; if (!this.polygonGeoJson) return; // 统一格式化为MultiPolygon const multiPolygon = geoJson2multiPolygon(this.polygonGeoJson); const shapeList = []; const extrudeLineList = []; multiPolygon.coordinates.forEach((polygonCoordinates) => { // 合成holes const polygonJson = formatPolygonJson({ type: 'Polygon', coordinates: polygonCoordinates }); if (polygonJson) { // 再次格式化为MultiPolygon const normalizeMultiPolygon = geoJson2multiPolygon(polygonJson); normalizeMultiPolygon.coordinates.forEach((normalizeMultiPolygonCoordinates) => { const mainShapePoint = [...normalizeMultiPolygonCoordinates]; const holes = mainShapePoint.splice(1); // 主体 const { shape, positions } = this.createNormalPolygonShape({ type: 'Polygon', coordinates: mainShapePoint, }); if (this.options.border && positions) { const curve = new CatmullRomCurve3(positions.map(p => new Vector3(...p))); const extrudeLine = new Mesh(new TubeGeometry(curve, positions.length, 200, 8), new MeshBasicMaterial(Object.assign({ blending: AdditiveBlending, side: FrontSide, color: 0xddeeff, transparent: true }, this.options.border))); extrudeLineList.push(extrudeLine); } // 孔 holes.forEach((hole) => { const { shape: holeShape } = this.createNormalPolygonShape({ type: 'Polygon', coordinates: [hole], }); shape.holes.push(holeShape); }); shapeList.push(shape); }); } }); const polygonGeometry = new ExtrudeGeometry(shapeList, this.options.extrudeOptions); polygonGeometry.translate(0, 0, -((_c = (_b = this.options.extrudeOptions) === null || _b === void 0 ? void 0 : _b.depth) !== null && _c !== void 0 ? _c : 0)); this.object3D.clear(); this.object3D.add(new Mesh(polygonGeometry, [this.polygonFaceMaterial, this.polygonSideMaterial])); this.object3D.renderOrder = Math.round(this.z); extrudeLineList.forEach((line) => { line.translateZ(10); this.object3D.add(line); }); // 添加墙体 if (this.options.wall) { const { texture, height, opacity } = this.options.wall; const wallGeometry = new ExtrudeGeometry(shapeList, Object.assign(Object.assign({}, this.options.extrudeOptions), { depth: height })); const faceMaterial = new MeshBasicMaterial({ side: FrontSide, depthTest: false, depthWrite: true, transparent: true, color: 0xffffff, opacity: 0.1, }); const sideMaterial = new MeshBasicMaterial({ side: DoubleSide, depthTest: true, depthWrite: false, blending: AdditiveBlending, transparent: true, opacity, map: texture, }); const wall = new Mesh(wallGeometry, [faceMaterial, sideMaterial]); this.object3D.add(wall); } } setPolygon(polygon) { this.polygonGeoJson = polygon; this.createObject(); } updatePosition() { } updateFill(fill, sideFill = fill) { var _a; this.polygonFaceMaterial.color = new Color(fill.color); this.polygonFaceMaterial.opacity = fill.opacity; this.polygonSideMaterial.color = new Color(sideFill.color); this.polygonSideMaterial.opacity = sideFill.opacity; (_a = this.layer) === null || _a === void 0 ? void 0 : _a.updatePosition(); } }