mirror of https://gitee.com/antv-l7/antv-l7
Merge branch 'master' of https://github.com/antvis/L7
This commit is contained in:
commit
d1af7b023b
|
@ -3,6 +3,12 @@ import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
|
|||
import earcut from 'earcut';
|
||||
// @ts-ignore
|
||||
import { mat4, vec3 } from 'gl-matrix';
|
||||
import {
|
||||
EARTH_RADIUS,
|
||||
EARTH_SEGMENTS,
|
||||
lglt2xyz,
|
||||
primitiveSphere,
|
||||
} from '../earth/utils';
|
||||
import ExtrudePolyline from '../utils/extrude_polyline';
|
||||
import { calculateCentroid } from '../utils/geo';
|
||||
import extrudePolygon, {
|
||||
|
@ -22,9 +28,6 @@ interface IGeometryCache {
|
|||
}
|
||||
const GeometryCache: IGeometryCache = {};
|
||||
|
||||
// 地球网格半径
|
||||
const EARTH_RADIUS = 100;
|
||||
const EARTH_SEGMENTS = 36;
|
||||
/**
|
||||
* 计算2D 填充点图顶点
|
||||
* @param feature 映射feature
|
||||
|
@ -52,33 +55,12 @@ export function GlobelPointFillTriangulation(feature: IEncodeFeature) {
|
|||
};
|
||||
}
|
||||
|
||||
function torad(deg: number) {
|
||||
return (deg / 180) * Math.acos(-1);
|
||||
}
|
||||
/**
|
||||
* 经纬度转xyz
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @param radius 半径
|
||||
*/
|
||||
function lglt2xyz(lnglat: [number, number]) {
|
||||
// TODO: + Math.PI/2 是为了对齐坐标
|
||||
const lng = torad(lnglat[0]) + Math.PI / 2;
|
||||
const lat = torad(lnglat[1]);
|
||||
|
||||
const z = EARTH_RADIUS * Math.cos(lat) * Math.cos(lng);
|
||||
const x = EARTH_RADIUS * Math.cos(lat) * Math.sin(lng);
|
||||
const y = EARTH_RADIUS * Math.sin(lat);
|
||||
return [x, y, z];
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3D 拉伸点图
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
||||
const { shape } = feature;
|
||||
// console.log('PointExtrudeTriangulation', feature)
|
||||
const { positions, index, normals } = getGeometry(
|
||||
shape as ShapeType3D,
|
||||
false,
|
||||
|
@ -329,7 +311,6 @@ function getGeometry(shape: ShapeType3D, needFlat = false): IExtrudeGeomety {
|
|||
: geometryShape.cylinder();
|
||||
const geometry = extrude_PolygonNormal([path], needFlat);
|
||||
GeometryCache[shape] = geometry;
|
||||
// console.log('geometry', geometry)
|
||||
return geometry;
|
||||
}
|
||||
|
||||
|
@ -425,8 +406,8 @@ function addDir(dirX: number, dirY: number) {
|
|||
* @returns
|
||||
*/
|
||||
export function earthTriangulation() {
|
||||
const mesh = primitiveSphere(EARTH_RADIUS, { segments: EARTH_SEGMENTS });
|
||||
const { positionsArr, indicesArr, normalArr } = mesh;
|
||||
const earthmesh = primitiveSphere(EARTH_RADIUS, { segments: EARTH_SEGMENTS });
|
||||
const { positionsArr, indicesArr, normalArr } = earthmesh;
|
||||
return {
|
||||
vertices: positionsArr,
|
||||
indices: indicesArr,
|
||||
|
@ -434,119 +415,3 @@ export function earthTriangulation() {
|
|||
normals: normalArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建地球球体网格
|
||||
* @param radius
|
||||
* @param opt
|
||||
* @returns
|
||||
*/
|
||||
function primitiveSphere(
|
||||
radius: number,
|
||||
opt: {
|
||||
segments: number;
|
||||
},
|
||||
) {
|
||||
const matRotY = mat4.create();
|
||||
const matRotZ = mat4.create();
|
||||
const up = vec3.fromValues(0, 1, 0);
|
||||
const tmpVec3 = vec3.fromValues(0, 0, 0);
|
||||
|
||||
opt = opt || {};
|
||||
radius = typeof radius !== 'undefined' ? radius : 1;
|
||||
const segments = typeof opt.segments !== 'undefined' ? opt.segments : 32;
|
||||
|
||||
const totalZRotationSteps = 2 + segments;
|
||||
const totalYRotationSteps = 2 * totalZRotationSteps;
|
||||
|
||||
const indices = [];
|
||||
const indicesArr = [];
|
||||
const positions = [];
|
||||
const positionsArr = [];
|
||||
const normals = [];
|
||||
const normalArr = [];
|
||||
const uvs = [];
|
||||
|
||||
for (
|
||||
let zRotationStep = 0;
|
||||
zRotationStep <= totalZRotationSteps;
|
||||
zRotationStep++
|
||||
) {
|
||||
const normalizedZ = zRotationStep / totalZRotationSteps;
|
||||
const angleZ = normalizedZ * Math.PI;
|
||||
|
||||
for (
|
||||
let yRotationStep = 0;
|
||||
yRotationStep <= totalYRotationSteps;
|
||||
yRotationStep++
|
||||
) {
|
||||
const normalizedY = yRotationStep / totalYRotationSteps;
|
||||
const angleY = normalizedY * Math.PI * 2;
|
||||
|
||||
mat4.identity(matRotZ);
|
||||
mat4.rotateZ(matRotZ, matRotZ, -angleZ);
|
||||
|
||||
mat4.identity(matRotY);
|
||||
mat4.rotateY(matRotY, matRotY, angleY);
|
||||
|
||||
vec3.transformMat4(tmpVec3, up, matRotZ);
|
||||
vec3.transformMat4(tmpVec3, tmpVec3, matRotY);
|
||||
|
||||
vec3.scale(tmpVec3, tmpVec3, -radius);
|
||||
|
||||
positions.push(tmpVec3.slice());
|
||||
positionsArr.push(...tmpVec3.slice());
|
||||
|
||||
vec3.normalize(tmpVec3, tmpVec3);
|
||||
normals.push(tmpVec3.slice());
|
||||
normalArr.push(...tmpVec3.slice());
|
||||
|
||||
uvs.push([normalizedY, 1 - normalizedZ]);
|
||||
|
||||
// position 和 uv 一起存储
|
||||
positionsArr.push(normalizedY, 1 - normalizedZ);
|
||||
}
|
||||
|
||||
if (zRotationStep > 0) {
|
||||
const verticesCount = positions.length;
|
||||
let firstIndex = verticesCount - 2 * (totalYRotationSteps + 1);
|
||||
for (
|
||||
;
|
||||
firstIndex + totalYRotationSteps + 2 < verticesCount;
|
||||
firstIndex++
|
||||
) {
|
||||
indices.push([
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
]);
|
||||
|
||||
indicesArr.push(
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
);
|
||||
indices.push([
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
]);
|
||||
indicesArr.push(
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
cells: indices,
|
||||
positions,
|
||||
normals,
|
||||
uvs,
|
||||
positionsArr,
|
||||
indicesArr,
|
||||
normalArr,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
import { mat4, vec3 } from 'gl-matrix';
|
||||
// 该文件专门记录地球模式的数值
|
||||
|
||||
// 地球网格半径
|
||||
export const EARTH_RADIUS = 100;
|
||||
export const EARTH_SEGMENTS = 36;
|
||||
|
||||
/**
|
||||
* 角度转弧度
|
||||
* @param deg
|
||||
* @returns
|
||||
*/
|
||||
function torad(deg: number) {
|
||||
return (deg / 180) * Math.acos(-1);
|
||||
}
|
||||
/**
|
||||
* 经纬度转xyz
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @param radius 半径
|
||||
*/
|
||||
export function lglt2xyz(lnglat: [number, number]) {
|
||||
// TODO: + Math.PI/2 是为了对齐坐标
|
||||
const lng = torad(lnglat[0]) + Math.PI / 2;
|
||||
const lat = torad(lnglat[1]);
|
||||
|
||||
const z = EARTH_RADIUS * Math.cos(lat) * Math.cos(lng);
|
||||
const x = EARTH_RADIUS * Math.cos(lat) * Math.sin(lng);
|
||||
const y = EARTH_RADIUS * Math.sin(lat);
|
||||
return [x, y, z];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建地球球体网格
|
||||
* @param radius
|
||||
* @param opt
|
||||
* @returns
|
||||
*/
|
||||
export function primitiveSphere(
|
||||
radius: number,
|
||||
opt: {
|
||||
segments: number;
|
||||
},
|
||||
) {
|
||||
const matRotY = mat4.create();
|
||||
const matRotZ = mat4.create();
|
||||
const up = vec3.fromValues(0, 1, 0);
|
||||
const tmpVec3 = vec3.fromValues(0, 0, 0);
|
||||
|
||||
opt = opt || {};
|
||||
radius = typeof radius !== 'undefined' ? radius : 1;
|
||||
const segments = typeof opt.segments !== 'undefined' ? opt.segments : 32;
|
||||
|
||||
const totalZRotationSteps = 2 + segments;
|
||||
const totalYRotationSteps = 2 * totalZRotationSteps;
|
||||
|
||||
const indices = [];
|
||||
const indicesArr = [];
|
||||
const positions = [];
|
||||
const positionsArr = [];
|
||||
const normals = [];
|
||||
const normalArr = [];
|
||||
const uvs = [];
|
||||
|
||||
for (
|
||||
let zRotationStep = 0;
|
||||
zRotationStep <= totalZRotationSteps;
|
||||
zRotationStep++
|
||||
) {
|
||||
const normalizedZ = zRotationStep / totalZRotationSteps;
|
||||
const angleZ = normalizedZ * Math.PI;
|
||||
|
||||
for (
|
||||
let yRotationStep = 0;
|
||||
yRotationStep <= totalYRotationSteps;
|
||||
yRotationStep++
|
||||
) {
|
||||
const normalizedY = yRotationStep / totalYRotationSteps;
|
||||
const angleY = normalizedY * Math.PI * 2;
|
||||
|
||||
mat4.identity(matRotZ);
|
||||
mat4.rotateZ(matRotZ, matRotZ, -angleZ);
|
||||
|
||||
mat4.identity(matRotY);
|
||||
mat4.rotateY(matRotY, matRotY, angleY);
|
||||
|
||||
vec3.transformMat4(tmpVec3, up, matRotZ);
|
||||
vec3.transformMat4(tmpVec3, tmpVec3, matRotY);
|
||||
|
||||
vec3.scale(tmpVec3, tmpVec3, -radius);
|
||||
|
||||
positions.push(tmpVec3.slice());
|
||||
positionsArr.push(...tmpVec3.slice());
|
||||
|
||||
vec3.normalize(tmpVec3, tmpVec3);
|
||||
normals.push(tmpVec3.slice());
|
||||
normalArr.push(...tmpVec3.slice());
|
||||
|
||||
uvs.push([normalizedY, 1 - normalizedZ]);
|
||||
|
||||
// position 和 uv 一起存储
|
||||
positionsArr.push(normalizedY, 1 - normalizedZ);
|
||||
}
|
||||
|
||||
if (zRotationStep > 0) {
|
||||
const verticesCount = positions.length;
|
||||
let firstIndex = verticesCount - 2 * (totalYRotationSteps + 1);
|
||||
for (
|
||||
;
|
||||
firstIndex + totalYRotationSteps + 2 < verticesCount;
|
||||
firstIndex++
|
||||
) {
|
||||
indices.push([
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
]);
|
||||
|
||||
indicesArr.push(
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
);
|
||||
indices.push([
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
]);
|
||||
indicesArr.push(
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
cells: indices,
|
||||
positions,
|
||||
normals,
|
||||
uvs,
|
||||
positionsArr,
|
||||
indicesArr,
|
||||
normalArr,
|
||||
};
|
||||
}
|
|
@ -2,6 +2,7 @@ import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core';
|
|||
import { isNumber } from 'lodash';
|
||||
import BaseModel, { styleOffset, styleSingle } from '../../core/BaseModel';
|
||||
import { PointExtrudeTriangulation } from '../../core/triangulation';
|
||||
import { lglt2xyz } from '../../earth/utils';
|
||||
import { calculateCentroid } from '../../utils/geo';
|
||||
import pointExtrudeFrag from '../shaders/extrude_frag.glsl';
|
||||
import pointExtrudeVert from '../shaders/extrude_vert.glsl';
|
||||
|
@ -51,6 +52,9 @@ export default class ExtrudeModel extends BaseModel {
|
|||
});
|
||||
}
|
||||
return {
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
u_globel: this.mapService.version === 'GLOBEL' ? 1 : 0,
|
||||
|
||||
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
|
||||
u_cellTypeLayout: this.getCellTypeLayout(),
|
||||
// u_opacity: opacity || 1.0,
|
||||
|
@ -70,6 +74,7 @@ export default class ExtrudeModel extends BaseModel {
|
|||
fragmentShader: pointExtrudeFrag,
|
||||
triangulation: PointExtrudeTriangulation,
|
||||
blend: this.getBlend(),
|
||||
// primitive: gl.POINTS,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
@ -77,6 +82,8 @@ export default class ExtrudeModel extends BaseModel {
|
|||
this.dataTexture?.destroy();
|
||||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
const isGlobel = this.mapService.version === 'GLOBEL';
|
||||
// point layer size;
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
|
@ -104,7 +111,7 @@ export default class ExtrudeModel extends BaseModel {
|
|||
size.length === 2 ? [size[0], size[0], size[1]] : size;
|
||||
}
|
||||
if (!Array.isArray(size)) {
|
||||
buffersize = [size];
|
||||
buffersize = [size, size, size];
|
||||
}
|
||||
return buffersize;
|
||||
} else {
|
||||
|
@ -152,7 +159,16 @@ export default class ExtrudeModel extends BaseModel {
|
|||
size: 3,
|
||||
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||
const coordinates = calculateCentroid(feature.coordinates);
|
||||
if (isGlobel) {
|
||||
// TODO: 在地球模式下需要将传入 shader 的经纬度转化成对应的 xyz 坐标
|
||||
return lglt2xyz([coordinates[0], coordinates[1]]) as [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
];
|
||||
} else {
|
||||
return [coordinates[0], coordinates[1], 0];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
precision highp float;
|
||||
|
||||
#define pi 3.1415926535
|
||||
#define ambientRatio 0.5
|
||||
#define diffuseRatio 0.3
|
||||
#define specularRatio 0.2
|
||||
|
@ -10,6 +11,7 @@ attribute vec4 a_Color;
|
|||
attribute vec3 a_Size;
|
||||
attribute vec3 a_Normal;
|
||||
|
||||
uniform float u_globel;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
varying vec4 v_color;
|
||||
|
@ -25,6 +27,22 @@ varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样
|
|||
#pragma include "light"
|
||||
#pragma include "picking"
|
||||
|
||||
float getYRadian(float x, float z) {
|
||||
if(x > 0.0 && z > 0.0) {
|
||||
return atan(x/z);
|
||||
} else if(x > 0.0 && z <= 0.0){
|
||||
return atan(-z/x) + pi/2.0;
|
||||
} else if(x <= 0.0 && z <= 0.0) {
|
||||
return pi + atan(x/z); //atan(x/z) +
|
||||
} else {
|
||||
return atan(z/-x) + pi*3.0/2.0;
|
||||
}
|
||||
}
|
||||
|
||||
float getXRadian(float y, float r) {
|
||||
return atan(y/r);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
// cal style mapping - 数据纹理映射部分的计算
|
||||
|
@ -70,5 +88,32 @@ void main() {
|
|||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(pos);
|
||||
}
|
||||
|
||||
if(u_globel > 0.0) {
|
||||
// 在地球模式下,将原本垂直于 xy 平面的圆柱调整姿态到适应圆的角度
|
||||
//旋转矩阵mx,创建绕x轴旋转矩阵
|
||||
float r = sqrt(a_Pos.z*a_Pos.z + a_Pos.x*a_Pos.x);
|
||||
float xRadian = getXRadian(a_Pos.y, r);
|
||||
float xcos = cos(xRadian);//求解旋转角度余弦值
|
||||
float xsin = sin(xRadian);//求解旋转角度正弦值
|
||||
mat4 mx = mat4(
|
||||
1,0,0,0,
|
||||
0,xcos,-xsin,0,
|
||||
0,xsin,xcos,0,
|
||||
0,0,0,1);
|
||||
|
||||
//旋转矩阵my,创建绕y轴旋转矩阵
|
||||
float yRadian = getYRadian(a_Pos.x, a_Pos.z);
|
||||
float ycos = cos(yRadian);//求解旋转角度余弦值
|
||||
float ysin = sin(yRadian);//求解旋转角度正弦值
|
||||
mat4 my = mat4(
|
||||
ycos,0,-ysin,0,
|
||||
0,1,0,0,
|
||||
ysin,0,ycos,0,
|
||||
0,0,0,1);
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * vec4(( my * mx * vec4(a_Position * a_Size, 1.0)).xyz + a_Pos, 1.0);
|
||||
}
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -93,6 +93,9 @@ void main() {
|
|||
gl_FragColor = vec4(gl_FragColor.xyz, intensity);
|
||||
}
|
||||
|
||||
// TODO: 避免多余片元绘制,同时也能避免有用片元在透明且重叠的情况下无法写入
|
||||
if(gl_FragColor.a <= 0.0) discard;
|
||||
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
|
||||
}
|
||||
|
|
|
@ -258,6 +258,9 @@ export default class ScaleComponent extends React.Component {
|
|||
.source(
|
||||
d,
|
||||
// [
|
||||
// {"lng":120,"lat":30}
|
||||
// ],
|
||||
// [
|
||||
// {"lng":10,"lat":0},
|
||||
// {"lng":20,"lat":0},
|
||||
// {"lng":30,"lat":0},
|
||||
|
@ -310,6 +313,26 @@ export default class ScaleComponent extends React.Component {
|
|||
// {"lng":0,"lat":80},
|
||||
// {"lng":0,"lat":90},
|
||||
|
||||
// {"lng":0,"lat":100},
|
||||
// {"lng":0,"lat":110},
|
||||
// {"lng":0,"lat":120},
|
||||
// {"lng":0,"lat":130},
|
||||
// {"lng":0,"lat":140},
|
||||
// {"lng":0,"lat":150},
|
||||
// {"lng":0,"lat":160},
|
||||
// {"lng":0,"lat":170},
|
||||
// {"lng":0,"lat":180},
|
||||
|
||||
// {"lng":0,"lat":190},
|
||||
// {"lng":0,"lat":200},
|
||||
// {"lng":0,"lat":210},
|
||||
// {"lng":0,"lat":220},
|
||||
// {"lng":0,"lat":230},
|
||||
// {"lng":0,"lat":240},
|
||||
// {"lng":0,"lat":250},
|
||||
// {"lng":0,"lat":260},
|
||||
// {"lng":0,"lat":270},
|
||||
|
||||
// {"lng":0,"lat":-10},
|
||||
// {"lng":0,"lat":-20},
|
||||
// {"lng":0,"lat":-30},
|
||||
|
@ -328,13 +351,15 @@ export default class ScaleComponent extends React.Component {
|
|||
},
|
||||
},
|
||||
)
|
||||
.shape('circle')
|
||||
// .shape('cylinder')
|
||||
// .shape('circle')
|
||||
.shape('cylinder')
|
||||
.color('#f00')
|
||||
.size(10)
|
||||
.size('', () => [1, 1, 10])
|
||||
// .size(20)
|
||||
.style({
|
||||
opacity: 0.6,
|
||||
// opacity: 0.6,
|
||||
})
|
||||
.animate(true)
|
||||
.active(true);
|
||||
|
||||
// scene.addLayer(pointlayer);
|
||||
|
@ -387,6 +412,7 @@ export default class ScaleComponent extends React.Component {
|
|||
scene.on('loaded', () => {
|
||||
scene.addLayer(earthlayer);
|
||||
scene.addLayer(pointlayer);
|
||||
// console.log(pointlayer)
|
||||
|
||||
earthlayer.setEarthTime(4.0);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue