From 36a228062d783e7090a756ef1b809bb0db8335ab Mon Sep 17 00:00:00 2001 From: YiQianYao <42212176+2912401452@users.noreply.github.com> Date: Wed, 3 Aug 2022 19:08:46 +0800 Subject: [PATCH] fix: fix simple line err (#1269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update version 2.9.18 -> 2.9.19 * chore: 修改引用 * style: lint style * fix: 修复 simple line 失效 * style: lint style --- .storybook/preview.ts | 4 +- packages/layers/src/core/triangulation.ts | 40 +- packages/layers/src/utils/extrude_polyline.ts | 192 +++++++++ stories/Map/components/gridTile.tsx | 394 +----------------- 4 files changed, 230 insertions(+), 400 deletions(-) diff --git a/.storybook/preview.ts b/.storybook/preview.ts index febd5ba076..685b2ba41c 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -23,8 +23,8 @@ addParameters({ // automatically import all files ending in *.stories.tsx // const req = require.context('../stories', true, /\.stories\.tsx$/); -const req = require.context('../stories/layerbuild', true, /\.stories\.tsx$/); -// const req = require.context('../stories/Map', true, /\.stories\.tsx$/); +// const req = require.context('../stories/layerbuild', true, /\.stories\.tsx$/); +const req = require.context('../stories/Map', true, /\.stories\.tsx$/); // const req = require.context('../stories/MapPerformance', true, /\.stories\.tsx$/); // const req = require.context('../stories/tile', true, /\.stories\.tsx$/); diff --git a/packages/layers/src/core/triangulation.ts b/packages/layers/src/core/triangulation.ts index 7e48f08995..d9e9b08ddc 100644 --- a/packages/layers/src/core/triangulation.ts +++ b/packages/layers/src/core/triangulation.ts @@ -147,21 +147,45 @@ export function LineTriangulation(feature: IEncodeFeature) { } export function SimpleLineTriangulation(feature: IEncodeFeature) { - const { coordinates } = feature; + const { coordinates, originCoordinates, version } = feature; - const line = new SimpleLine(); - let path = coordinates as number[][][] | number[][]; - if (path[0] && !Array.isArray(path[0][0])) { - path = [coordinates] as number[][][]; - } - path.forEach((item: any) => { - line.simpleExtrude(item as number[][]); + const line = new ExtrudePolyline({ + dash: true, + join: 'bevel', }); + if (version === 'GAODE2.x') { + // 处理高德2.0几何体构建 + let path1 = coordinates as number[][][] | number[][]; // 计算位置 + if (!Array.isArray(path1[0][0])) { + path1 = [coordinates] as number[][][]; + } + let path2 = originCoordinates as number[][][] | number[][]; // 计算法线 + if (!Array.isArray(path2[0][0])) { + path2 = [originCoordinates] as number[][][]; + } + for (let i = 0; i < path1.length; i++) { + // 高德2.0在计算线时,需要使用经纬度计算发现,使用 customCoords.lnglatToCoords 计算的数据来计算顶点的位置 + const item1 = path1[i]; + const item2 = path2[i]; + line.simpleExtrude_gaode2(item1 as number[][], item2 as number[][]); + } + } else { + // 处理非高德2.0的几何体构建 + let path = coordinates as number[][][] | number[][]; + if (path[0] && !Array.isArray(path[0][0])) { + path = [coordinates] as number[][][]; + } + path.forEach((item: any) => { + line.simpleExtrude(item as number[][]); + }); + } + const linebuffer = line.complex; return { vertices: linebuffer.positions, // [ x,y,z, distance, miter, total ] indices: linebuffer.indices, + normals: linebuffer.normals, size: 6, }; } diff --git a/packages/layers/src/utils/extrude_polyline.ts b/packages/layers/src/utils/extrude_polyline.ts index 20c2766568..e8f90822f0 100644 --- a/packages/layers/src/utils/extrude_polyline.ts +++ b/packages/layers/src/utils/extrude_polyline.ts @@ -91,6 +91,92 @@ export default class ExtrudePolyline { }; } + public simpleExtrude(points: number[][]) { + const complex = this.complex; + if (points.length <= 1) { + return complex; + } + this.lastFlip = -1; + this.started = false; + this.normal = null; + this.totalDistance = 0; + + const total = points.length; + let count = complex.startIndex; + for (let i = 1; i < total; i++) { + const last = points[i - 1] as vec3; + const cur = points[i] as vec3; + const next = i < points.length - 1 ? points[i + 1] : null; + const amt = this.simpleSegment(complex, count, last, cur, next as vec3); + count += amt; + } + + if (this.dash) { + for (let i = 0; i < complex.positions.length / 6; i++) { + complex.positions[i * 6 + 5] = this.totalDistance; + } + } + complex.startIndex = complex.positions.length / 6; + return complex; + } + + public simpleExtrude_gaode2(points: number[][], originPoints: number[][]) { + const complex = this.complex; + if (points.length <= 1) { + return complex; + } + this.lastFlip = -1; + this.started = false; + this.normal = null; + this.totalDistance = 0; + // 去除数组里重复的点 + // points = getArrayUnique(points); + const total = points.length; + let count = complex.startIndex; + for (let i = 1; i < total; i++) { + const last = points[i - 1]; + last.push(originPoints[i - 1][2] ?? 0); + // @ts-ignore + const originLast = originPoints[i - 1] as vec3; + + const cur = points[i]; + cur.push(originPoints[i][2] ?? 0); + // @ts-ignore + const originCur = originPoints[i] as vec3; + + const next = + i < points.length - 1 + ? [...points[i + 1], originPoints[i + 1][2] ?? 0] + : null; + const originNext = + i < originPoints.length - 1 ? originPoints[i + 1] : null; + + const amt = this.simpleSegment( + complex, + count, + // @ts-ignore + last as vec3, + // @ts-ignore + cur as vec3, + // @ts-ignore + next as vec3, + // @ts-ignore + originLast, + originCur, + // @ts-ignore + originNext as vec3, + ); + count += amt; + } + if (this.dash) { + for (let i = 0; i < complex.positions.length / 6; i++) { + complex.positions[i * 6 + 5] = this.totalDistance; + } + } + complex.startIndex = complex.positions.length / 6; + return complex; + } + public extrude_gaode2(points: number[][], originPoints: number[][]) { const complex = this.complex; if (points.length <= 1) { @@ -175,6 +261,112 @@ export default class ExtrudePolyline { complex.startIndex = complex.positions.length / 6; return complex; } + + private simpleSegment( + complex: any, + index: number, + last: vec3, + cur: vec3, + next: vec3, + ) { + let count = 0; + const indices = complex.indices; + const positions = complex.positions; + const normals = complex.normals; + const flatCur = aProjectFlat([cur[0], cur[1]]) as [number, number]; + const flatLast = aProjectFlat([last[0], last[1]]) as [number, number]; + // @ts-ignore + direction(lineA, flatCur, flatLast); + let segmentDistance = 0; + if (this.dash) { + // @ts-ignore + segmentDistance = this.lineSegmentDistance(flatCur, flatLast); + this.totalDistance += segmentDistance; + } + + if (!this.normal) { + this.normal = vec2.create(); + computeNormal(this.normal, lineA); + } + if (!this.started) { + this.started = true; + + this.extrusions( + positions, + normals, + last, + this.normal, + this.thickness, + this.totalDistance - segmentDistance, + ); + } + + indices.push(index + 0, index + 1, index + 2); + + if (!next) { + computeNormal(this.normal, lineA); + this.extrusions( + positions, + normals, + cur, + this.normal, + this.thickness, + this.totalDistance, + ); + + indices.push( + ...(this.lastFlip === 1 + ? [index, index + 2, index + 3] + : [index + 2, index + 1, index + 3]), + ); + count += 2; + } else { + const flatNext = aProjectFlat([next[0], next[1]]) as [number, number]; + if (isPointEqual(flatCur, flatNext)) { + vec2.add( + flatNext, + flatCur, + vec2.normalize(flatNext, vec2.subtract(flatNext, flatCur, flatLast)), + ); + } + direction(lineB, flatNext, flatCur); + + // stores tangent & miter + + const [miterLen, miter] = computeMiter( + tangent, + vec2.create(), + lineA, + lineB, + this.thickness, + ); + // normal(tmp, lineA) + + // get orientation + let flip = vec2.dot(tangent, this.normal) < 0 ? -1 : 1; + this.extrusions( + positions, + normals, + cur, + miter, + miterLen, + this.totalDistance, + ); + indices.push( + ...(this.lastFlip === 1 + ? [index, index + 2, index + 3] + : [index + 2, index + 1, index + 3]), + ); + + flip = -1; + + // the miter is now the normal for our next join + vec2.copy(this.normal, miter); + count += 2; + this.lastFlip = flip; + } + return count; + } private segment_gaode2( complex: any, index: number, diff --git a/stories/Map/components/gridTile.tsx b/stories/Map/components/gridTile.tsx index a7c80676a3..4d57af478b 100644 --- a/stories/Map/components/gridTile.tsx +++ b/stories/Map/components/gridTile.tsx @@ -1,9 +1,6 @@ import { LineLayer, Scene, PointLayer } from '@antv/l7'; import { GaodeMap, GaodeMapV2, Map } from '@antv/l7-maps'; import * as React from 'react'; -import { ThreeLayer, ThreeRender } from '@antv/l7-three'; -import * as THREE from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; function getImageData(img: HTMLImageElement) { let canvas: HTMLCanvasElement = document.createElement('canvas'); @@ -70,15 +67,6 @@ function getR(data: Uint8ClampedArray) { return arr; } -function setMaterial(object: any) { - if (object.children && object.children.length && object.children.length > 0) { - object.children.map((child: any) => setMaterial(child)); - } else if (object.material) { - object.material.wireframe = true; - object.material.opacity = 0.6; - } -} - export default class GridTile extends React.Component { // @ts-ignore private scene: Scene; @@ -100,214 +88,6 @@ export default class GridTile extends React.Component { }), }); this.scene = scene; - scene.setBgColor('#000'); - - const airPorts = [ - { - name: '常德桃花源机场', - lng: 111.641101, - lat: 28.91165, - }, - { - name: '芷江机场', - lng: 109.709699, - lat: 27.442172, - }, - { - name: '铜仁凤凰机场', - lng: 109.313971, - lat: 27.880629, - }, - { - name: '永州零陵机场', - lng: 111.616049, - lat: 26.335053, - }, - { - name: '桂林两江国际机场', - lng: 110.049256, - lat: 25.210065, - }, - { - name: '长沙黄花国际机场', - lng: 113.216412, - lat: 28.183613, - }, - { - name: '井冈山机场', - lng: 114.745845, - lat: 26.852646, - }, - ]; - const planeTarget = { - lng2: 111.616049, - lat2: 26.335053, - }; - const airLineData = [ - { - name: '常德桃花源机场', - lng: 111.641101, - lat: 28.91165, - ...planeTarget, - }, - { - name: '芷江机场', - lng: 109.709699, - lat: 27.442172, - ...planeTarget, - }, - { - name: '铜仁凤凰机场', - lng: 109.313971, - lat: 27.880629, - ...planeTarget, - }, - { - name: '桂林两江国际机场', - lng: 110.049256, - lat: 25.210065, - ...planeTarget, - }, - { - name: '长沙黄花国际机场', - lng: 113.216412, - lat: 28.183613, - ...planeTarget, - }, - { - name: '井冈山机场', - lng: 114.745845, - lat: 26.852646, - ...planeTarget, - }, - ]; - - scene.registerRenderService(ThreeRender); - - const threeJSLayer = new ThreeLayer({ - enableMultiPassRenderer: false, - // @ts-ignore - onAddMeshes: (threeScene, layer) => { - threeScene.add(new THREE.AmbientLight(0xffffff)); - const sunlight = new THREE.DirectionalLight(0xffffff, 0.25); - sunlight.position.set(0, 80000000, 100000000); - sunlight.matrixWorldNeedsUpdate = true; - threeScene.add(sunlight); - - // 使用 Three.js glTFLoader 加载模型 - const loader = new GLTFLoader(); - loader.load( - 'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf', - (gltf) => { - const antModel = gltf.scene; - setMaterial(antModel); - layer.adjustMeshToMap(antModel); - layer.setMeshScale(antModel, 8000, 8000, 8000); - layer.setObjectLngLat(antModel, [113, 29], 0); - - const animations = gltf.animations; - if (animations && animations.length) { - const mixer = new THREE.AnimationMixer(antModel); - const animation = animations[1]; - const action = mixer.clipAction(animation); - action.timeScale = 5; - action.play(); - layer.addAnimateMixer(mixer); - } - antModel.rotation.y = Math.PI; - // 向场景中添加模型 - threeScene.add(antModel); - // 重绘图层 - layer.render(); - return ''; - }, - ); - }, - }); - - scene.addImage( - 'plane', - 'https://gw.alipayobjects.com/zos/bmw-prod/96327aa6-7fc5-4b5b-b1d8-65771e05afd8.svg', - ); - const airPrtsLayer = new PointLayer() - .source(airPorts, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('name', 'text') - .color('rgb(22,119,255)') - .size(10); - - const airLineLayer = new LineLayer({ blend: 'normal' }) - .source(airLineData, { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - x1: 'lng2', - y1: 'lat2', - }, - }) - .shape('arc3d') - .size(1) - .color('#f00') - .style({ - sourceColor: 'rgb(22,119,255)', - targetColor: 'rgba(242,246,250,0.1)', - }); - - const airPlaneLayer = new LineLayer({ blend: 'normal', zIndex: 1 }) - .source(airLineData, { - parser: { - type: 'json', - x: 'lng2', - y: 'lat2', - x1: 'lng', - y1: 'lat', - }, - }) - .shape('arc3d') - .texture('plane') - .size(30) - .color('#f00') - .animate({ - duration: 0.2, - interval: 0.2, - trailLength: 0.2, - }) - .style({ - textureBlend: 'replace', - lineTexture: true, // 开启线的贴图功能 - iconStep: 6, // 设置贴图纹理的间距 - }); - - fetch( - 'https://gw.alipayobjects.com/os/bmw-prod/ec5351c9-d22b-4918-ad6c-1838064d3a64.json', - ) - .then((res) => res.json()) - .then((data) => { - const layer = new LineLayer({}) - .source(data) - .size(30000) - .shape('wall') - .style({ - opacity: 0.4, - sourceColor: '#0DCCFF', - targetColor: 'rbga(255,255,255, 0)', - heightfixed: true, - }); - scene.addLayer(layer); - - const nameLayer = new PointLayer({ zIndex: 3 }) - .source(data) - .color('rgb(22,119,255)') - .size(15) - .shape('name', 'text'); - scene.addLayer(nameLayer); - }); const img: HTMLImageElement = new Image(); img.crossOrigin = 'none'; @@ -344,7 +124,9 @@ export default class GridTile extends React.Component { .source(geoData) .size(1) .shape('simple') - .color('rgb(22, 119, 255)') + // .shape('line') + // .color('rgb(22, 119, 255)') + .color('#f00') .style({ vertexHeightScale: 2000, opacity: 0.4, @@ -352,175 +134,7 @@ export default class GridTile extends React.Component { scene.addLayer(layer); }; - const waveLayer = new PointLayer({ zIndex: 2, blend: 'additive' }) - .source( - [ - { lng: 113, lat: 29, size: 10000 }, - { lng: 113.5, lat: 29.5, size: 30000 }, - - { - lng: 110.23681640625, - lat: 29.64509464986076, - size: 74020.50373907911, - }, - { - lng: 115.01586914062499, - lat: 26.88777988202911, - size: 22908.885529976185, - }, - { - lng: 111.181640625, - lat: 28.724313406473463, - size: 73359.37302978932, - }, - { - lng: 112.686767578125, - lat: 29.257648503615542, - size: 18500.90838085843, - }, - { - lng: 114.664306640625, - lat: 28.98892237190413, - size: 20293.183968726793, - }, - { - lng: 113.90075683593749, - lat: 28.17855984939698, - size: 18051.412077639496, - }, - { - lng: 111.51123046875, - lat: 27.45466493898314, - size: 37645.94186119526, - }, - { - lng: 110.67626953125, - lat: 28.004101830368654, - size: 4214.588023703825, - }, - { - lng: 114.43359375, - lat: 29.477861195816843, - size: 61722.01580332115, - }, - { - lng: 110.445556640625, - lat: 26.96124577052697, - size: 70806.75519747598, - }, - { - lng: 113.75244140624999, - lat: 27.88278388425912, - size: 70930.24993464859, - }, - ], - { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }, - ) - .shape('circle') - .color('rgb(22, 119, 255)') - .size('size', (v) => v) - .animate(true) - .style({ - unit: 'meter', - }); - - const barLayer = new PointLayer({ zIndex: 2, depth: false }) - .source( - [ - { lng: 113, lat: 29, size: 10000 }, - { lng: 113.5, lat: 29.5, size: 30000 }, - - { - lng: 110.23681640625, - lat: 29.64509464986076, - size: 74020.50373907911, - }, - { - lng: 115.01586914062499, - lat: 26.88777988202911, - size: 22908.885529976185, - }, - { - lng: 111.181640625, - lat: 28.724313406473463, - size: 73359.37302978932, - }, - { - lng: 112.686767578125, - lat: 29.257648503615542, - size: 18500.90838085843, - }, - { - lng: 114.664306640625, - lat: 28.98892237190413, - size: 20293.183968726793, - }, - { - lng: 113.90075683593749, - lat: 28.17855984939698, - size: 18051.412077639496, - }, - { - lng: 111.51123046875, - lat: 27.45466493898314, - size: 37645.94186119526, - }, - { - lng: 110.67626953125, - lat: 28.004101830368654, - size: 4214.588023703825, - }, - { - lng: 114.43359375, - lat: 29.477861195816843, - size: 61722.01580332115, - }, - { - lng: 110.445556640625, - lat: 26.96124577052697, - size: 70806.75519747598, - }, - { - lng: 113.75244140624999, - lat: 27.88278388425912, - size: 70930.24993464859, - }, - ], - { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }, - ) - .shape('cylinder') - .color('rgb(22, 119, 255)') - .size('size', (v) => [5, 5, v / 350]) - .animate(true) - .style({ - opacityLinear: { - enable: true, // true - false - dir: 'up', // up - down - }, - lightEnable: false, - }); - - scene.on('loaded', () => { - scene.addLayer(waveLayer); - scene.addLayer(barLayer); - scene.addLayer(threeJSLayer); - - scene.addLayer(airPrtsLayer); - scene.addLayer(airLineLayer); - scene.addLayer(airPlaneLayer); - }); + scene.on('loaded', () => {}); } public render() {