Merge pull request #49 from antvis/encode

feat(layers): add polygon3d , pointimagelayer
This commit is contained in:
@thinkinggis 2019-10-30 10:23:44 +08:00 committed by GitHub
commit 7d81f2287b
23 changed files with 912 additions and 136 deletions

View File

@ -246,7 +246,6 @@ export default class StyleAttributeService implements IStyleAttributeService {
const attributes: { const attributes: {
[attributeName: string]: IAttribute; [attributeName: string]: IAttribute;
} = {}; } = {};
descriptors.forEach((descriptor, attributeIdx) => { descriptors.forEach((descriptor, attributeIdx) => {
if (descriptor) { if (descriptor) {
// IAttribute 参数透传 // IAttribute 参数透传

View File

@ -24,6 +24,7 @@
"@l7/utils": "^0.0.1", "@l7/utils": "^0.0.1",
"@turf/meta": "^6.0.2", "@turf/meta": "^6.0.2",
"@types/d3-color": "^1.2.2", "@types/d3-color": "^1.2.2",
"inversify": "^5.0.1",
"d3-array": "^2.3.1", "d3-array": "^2.3.1",
"d3-color": "^1.4.0", "d3-color": "^1.4.0",
"d3-scale": "^3.1.0", "d3-scale": "^3.1.0",

View File

@ -103,6 +103,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
protected layerSource: Source; protected layerSource: Source;
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
private encodedData: IEncodeFeature[]; private encodedData: IEncodeFeature[];
private configSchema: object; private configSchema: object;
@ -117,9 +120,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
@lazyInject(TYPES.IShaderModuleService) @lazyInject(TYPES.IShaderModuleService)
private readonly shaderModuleService: IShaderModuleService; private readonly shaderModuleService: IShaderModuleService;
@lazyInject(TYPES.IRendererService)
private readonly rendererService: IRendererService;
@lazyInject(TYPES.IMapService) @lazyInject(TYPES.IMapService)
private readonly map: IMapService; private readonly map: IMapService;

View File

@ -0,0 +1,65 @@
export type IPosition = [number, number, number] | [number, number];
export type IPath = IPosition[];
export enum ShapeType3D {
CYLINDER = 'cylinder',
SQUARECOLUMN = 'squareColumn',
TRIANGLECOLUMN = 'triangleColumn',
HEXAGONCOLUMN = 'hexagonColumn',
PENTAGONCOLUMN = 'pentagonColumn',
}
export enum ShapeType2D {
CIRCLE = 'circle',
SQUARE = 'square',
TRIANGLE = 'triangle',
HEXAGON = 'hexagon',
PENTAGON = 'pentagon',
}
/**
*
* @param pointCount 3 =>
* @param start
*/
export function polygonPath(pointCount: number, start: number = 0): IPath {
const step = (Math.PI * 2) / pointCount;
const line = [];
for (let i = 0; i < pointCount; i++) {
line.push(step * i + (start * Math.PI) / 12);
}
const path: IPath = line.map((t) => {
const x = Math.sin(t + Math.PI / 4);
const y = Math.cos(t + Math.PI / 4);
return [x, y, 0];
});
// path.push(path[0]);
return path;
}
export function circle(): IPath {
return polygonPath(30);
}
export function square(): IPath {
return polygonPath(4);
}
export function triangle(): IPath {
return polygonPath(3);
}
export function hexagon(): IPath {
return polygonPath(6);
}
export function pentagon(): IPath {
return polygonPath(5);
}
export const geometryShape = {
[ShapeType2D.CIRCLE]: circle,
[ShapeType2D.HEXAGON]: hexagon,
[ShapeType2D.TRIANGLE]: triangle,
[ShapeType2D.SQUARE]: square,
[ShapeType2D.PENTAGON]: pentagon,
[ShapeType3D.CYLINDER]: circle,
[ShapeType3D.HEXAGONCOLUMN]: hexagon,
[ShapeType3D.TRIANGLECOLUMN]: triangle,
[ShapeType3D.SQUARECOLUMN]: square,
[ShapeType3D.PENTAGONCOLUMN]: pentagon,
};

View File

@ -0,0 +1,83 @@
import earcut from 'earcut';
import { IPath } from './Path';
export interface IExtrudeGeomety {
positions: number[];
index: number[];
}
/**
*
* @param paths
* @param extrude
*/
export default function extrudePolygon(path: IPath[]): IExtrudeGeomety {
const p1 = path[0][0];
const p2 = path[0][path[0].length - 1];
if (p1[0] === p2[0] && p1[1] === p2[1]) {
path[0] = path[0].slice(0, path[0].length - 1);
}
const n = path[0].length;
const flattengeo = earcut.flatten(path);
const { vertices, dimensions } = flattengeo;
const positions = [];
const indexArray = [];
// 设置顶部z值
for (let j = 0; j < vertices.length / dimensions; j++) {
if (dimensions === 2) {
positions.push(vertices[j * 2], vertices[j * 2 + 1], 1);
} else {
positions.push(vertices[j * 3], vertices[j * 3 + 1], 1);
}
}
const triangles = earcut(
flattengeo.vertices,
flattengeo.holes,
flattengeo.dimensions,
);
indexArray.push(...triangles);
for (let i = 0; i < n; i++) {
const prePoint = flattengeo.vertices.slice(
i * dimensions,
(i + 1) * dimensions,
);
let nextPoint = flattengeo.vertices.slice(
(i + 2) * dimensions,
(i + 3) * dimensions,
);
if (nextPoint.length === 0) {
nextPoint = flattengeo.vertices.slice(0, dimensions);
}
const indexOffset = positions.length / 3;
positions.push(
prePoint[0],
prePoint[1],
1,
nextPoint[0],
nextPoint[1],
1,
prePoint[0],
prePoint[1],
0,
nextPoint[0],
nextPoint[1],
0,
);
indexArray.push(...[1, 2, 0, 3, 2, 1].map((v) => v + indexOffset));
}
return {
positions,
index: indexArray,
};
}
export function fillPolygon(points: IPath[]) {
const flattengeo = earcut.flatten(points);
const triangles = earcut(
flattengeo.vertices,
flattengeo.holes,
flattengeo.dimensions,
);
return {
positions: flattengeo.vertices,
index: triangles,
};
}

View File

@ -1,11 +1,21 @@
import { IEncodeFeature } from '@l7/core'; import { IEncodeFeature } from '@l7/core';
import { vec3 } from 'gl-matrix'; import { vec3 } from 'gl-matrix';
import getNormals from '../utils/polylineNormal';
import extrudePolygon, { IExtrudeGeomety } from './shape/extrude'; import extrudePolygon, { IExtrudeGeomety } from './shape/extrude';
import { geometryShape, ShapeType2D, ShapeType3D } from './shape/Path'; import {
geometryShape,
IPosition,
ShapeType2D,
ShapeType3D,
} from './shape/Path';
interface IGeometryCache { interface IGeometryCache {
[key: string]: IExtrudeGeomety; [key: string]: IExtrudeGeomety;
} }
const GeometryCache: IGeometryCache = {}; const GeometryCache: IGeometryCache = {};
/**
* 2D
* @param feature feature
*/
export function PointFillTriangulation(feature: IEncodeFeature) { export function PointFillTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[]; const coordinates = feature.coordinates as number[];
return { return {
@ -15,6 +25,10 @@ export function PointFillTriangulation(feature: IEncodeFeature) {
}; };
} }
/**
* 3D
* @param feature feature
*/
export function PointExtrudeTriangulation(feature: IEncodeFeature) { export function PointExtrudeTriangulation(feature: IEncodeFeature) {
const { shape } = feature; const { shape } = feature;
const { positions, index } = getGeometry(shape as ShapeType3D); const { positions, index } = getGeometry(shape as ShapeType3D);
@ -26,6 +40,46 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
}; };
} }
/**
*
* @param feature feature
*/
export function PointImageTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[];
return {
vertices: [...coordinates],
indices: [0],
size: coordinates.length,
};
}
/**
* 线
* @param feature feature
*/
export function LineTriangulation(feature: IEncodeFeature) {
const { coordinates } = feature;
const line = getNormals(coordinates as number[][], false, 0);
return {
vertices: line.attrPos, // [ x,y,z, distance, miter ]
indices: line.attrIndex,
normals: line.normals,
size: 5,
};
}
export function PolygonExtrudeTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as IPosition[][];
const { positions, index } = extrudePolygon(coordinates);
return {
vertices: positions, // [ x, y, z ]
indices: index,
normals: Array.from(computeVertexNormals(positions, index)),
size: 3,
};
}
function getGeometry(shape: ShapeType3D): IExtrudeGeomety { function getGeometry(shape: ShapeType3D): IExtrudeGeomety {
if (GeometryCache && GeometryCache[shape]) { if (GeometryCache && GeometryCache[shape]) {
return GeometryCache[shape]; return GeometryCache[shape];
@ -37,6 +91,7 @@ function getGeometry(shape: ShapeType3D): IExtrudeGeomety {
GeometryCache[shape] = geometry; GeometryCache[shape] = geometry;
return geometry; return geometry;
} }
function computeVertexNormals( function computeVertexNormals(
positions: number[], positions: number[],
indexArray: number[], indexArray: number[],
@ -75,6 +130,7 @@ function computeVertexNormals(
normalizeNormals(normals); normalizeNormals(normals);
return normals; return normals;
} }
function normalizeNormals(normals: Float32Array) { function normalizeNormals(normals: Float32Array) {
for (let i = 0, li = normals.length; i < li; i += 3) { for (let i = 0, li = normals.length; i < li; i += 3) {
const normal = vec3.fromValues(normals[i], normals[i + 1], normals[i + 2]); const normal = vec3.fromValues(normals[i], normals[i + 1], normals[i + 2]);
@ -83,3 +139,9 @@ function normalizeNormals(normals: Float32Array) {
normals.set(newNormal, i); normals.set(newNormal, i);
} }
} }
function checkIsClosed(points: number[][][]) {
const p1 = points[0][0];
const p2 = points[0][points[0].length - 1];
return p1[0] === p2[0] && p1[1] === p2[1];
}

View File

@ -1,11 +1,13 @@
import { container, ILayerPlugin, TYPES } from '@l7/core'; import { container, ILayerPlugin, TYPES } from '@l7/core';
import BaseLayer from './core/BaseLayer'; import BaseLayer from './core/BaseLayer';
import Point3dLayer from './point/extrude';
// import HeatMapLayer from './heatmap'; // import HeatMapLayer from './heatmap';
// import Line from './line'; import LineLayer from './line/index';
import Point3dLayer from './point/extrude';
import PointImageLayer from './point/image';
import PointLayer from './point/index'; import PointLayer from './point/index';
// import Point from './point/point'; // import Point from './point/point';
import PolygonLayer from './polygon'; import PolygonLayer from './polygon';
import Polygon3DLayer from './polygon/polygon3D';
// import ImageLayer from './raster'; // import ImageLayer from './raster';
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin'; import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
@ -65,7 +67,9 @@ export {
PointLayer, PointLayer,
PolygonLayer, PolygonLayer,
Point3dLayer, Point3dLayer,
// Point, PointImageLayer,
LineLayer,
Polygon3DLayer,
// Line, // Line,
// ImageLayer, // ImageLayer,
// HeatMapLayer, // HeatMapLayer,

View File

@ -1,102 +1,154 @@
// import { import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
// gl, import BaseLayer from '../core/BaseLayer';
// IRendererService, import { LineTriangulation } from '../core/triangulation';
// IShaderModuleService, import line_frag from './shaders/line_frag.glsl';
// lazyInject, import line_vert from './shaders/line_vert.glsl';
// TYPES, interface IPointLayerStyleOptions {
// } from '@l7/core'; opacity: number;
// import BaseLayer from '../core/BaseLayer'; }
// import LineBuffer from './buffers/line'; export default class LineLayer extends BaseLayer<IPointLayerStyleOptions> {
// import line_frag from './shaders/line_frag.glsl'; public name: string = 'LineLayer';
// import line_vert from './shaders/line_vert.glsl';
// export default class LineLayer extends BaseLayer {
// public name: string = 'LineLayer';
// @lazyInject(TYPES.IShaderModuleService)
// private readonly shaderModule: IShaderModuleService;
// @lazyInject(TYPES.IRendererService) protected getConfigSchema() {
// private readonly renderer: IRendererService; return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
// protected renderModels() { protected renderModels() {
// this.models.forEach((model) => const { opacity } = this.getStyleOptions();
// model.draw({ this.models.forEach((model) =>
// uniforms: { model.draw({
// u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], uniforms: {
// }, u_Opacity: opacity || 0,
// }), },
// ); }),
// return this; );
// } return this;
// protected buildModels(): void { }
// this.shaderModule.registerModule('line', {
// vs: line_vert,
// fs: line_frag,
// });
// this.models = []; protected buildModels() {
// const { vs, fs, uniforms } = this.shaderModule.getModule('line'); this.registerBuiltinAttributes(this);
// const buffer = new LineBuffer({ this.models = [
// data: this.getEncodedData(), this.buildLayerModel({
// style: this.styleOption, moduleName: 'line',
// }); vertexShader: line_vert,
// const { fragmentShader: line_frag,
// createAttribute, triangulation: LineTriangulation,
// createBuffer, blend: {
// createElements, enable: true,
// createModel, func: {
// } = this.renderer; srcRGB: gl.SRC_ALPHA,
srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1,
},
},
}),
];
}
// this.models.push( private registerBuiltinAttributes(layer: ILayer) {
// createModel({ // point layer size;
// attributes: { layer.styleAttributeService.registerStyleAttribute({
// a_Position: createAttribute({ name: 'size',
// buffer: createBuffer({ type: AttributeType.Attribute,
// data: buffer.attributes.positions, descriptor: {
// type: gl.FLOAT, name: 'a_Size',
// }), buffer: {
// size: 3, // give the WebGL driver a hint that this buffer may change
// }), usage: gl.DYNAMIC_DRAW,
// a_normal: createAttribute({ data: [],
// buffer: createBuffer({ type: gl.FLOAT,
// data: buffer.attributes.normals, },
// type: gl.FLOAT, size: 1,
// }), update: (
// size: 3, feature: IEncodeFeature,
// }), featureIdx: number,
// a_color: createAttribute({ vertex: number[],
// buffer: createBuffer({ attributeIdx: number,
// data: buffer.attributes.colors, ) => {
// type: gl.FLOAT, const { size } = feature;
// }), return Array.isArray(size) ? [size[0]] : [size as number];
// size: 4, },
// }), },
// a_size: createAttribute({ });
// buffer: createBuffer({
// data: buffer.attributes.sizes, // point layer size;
// type: gl.FLOAT, layer.styleAttributeService.registerStyleAttribute({
// }), name: 'normal',
// size: 1, type: AttributeType.Attribute,
// }), descriptor: {
// a_miter: createAttribute({ name: 'a_Normal',
// buffer: createBuffer({ buffer: {
// data: buffer.attributes.miters, // give the WebGL driver a hint that this buffer may change
// type: gl.FLOAT, usage: gl.STATIC_DRAW,
// }), data: [],
// size: 1, type: gl.FLOAT,
// }), },
// }, size: 3,
// uniforms: { update: (
// ...uniforms, feature: IEncodeFeature,
// u_opacity: this.styleOption.opacity as number, featureIdx: number,
// }, vertex: number[],
// fs, attributeIdx: number,
// vs, normal: number[],
// count: buffer.indexArray.length, ) => {
// elements: createElements({ return normal;
// data: buffer.indexArray, },
// type: gl.UNSIGNED_INT, },
// }), });
// }),
// ); layer.styleAttributeService.registerStyleAttribute({
// } name: 'miter',
// } type: AttributeType.Attribute,
descriptor: {
name: 'a_Miter',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[4]];
},
},
});
layer.styleAttributeService.registerStyleAttribute({
name: 'distance',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Distance',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[3]];
},
},
});
}
}

View File

@ -1,11 +1,11 @@
attribute float a_miter; attribute float a_Miter;
attribute vec4 a_color; attribute vec4 a_Color;
attribute float a_size; attribute float a_Size;
attribute float a_distance; attribute float a_Distance;
attribute float a_dash_array; attribute float a_dash_array;
attribute float a_total_distance; attribute float a_total_distance;
attribute vec3 a_normal; attribute vec3 a_Normal;
attribute vec3 a_Position; attribute vec3 a_Position;
uniform mat4 u_ModelMatrix; uniform mat4 u_ModelMatrix;
@ -14,9 +14,9 @@ varying float v_dash_array;
varying vec3 v_normal; varying vec3 v_normal;
#pragma include "projection" #pragma include "projection"
void main() { void main() {
v_normal = a_normal; v_normal = a_Normal;
v_color = a_color; v_color = a_Color;
vec3 size = a_miter * a_size * v_normal; vec3 size = a_Miter * a_Size * v_normal;
vec2 offset = project_pixel(size.xy); vec2 offset = project_pixel(size.xy);
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0)); vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0, 1.0)); gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0, 1.0));

View File

@ -40,7 +40,9 @@ export default class RegisterStyleAttributePlugin implements ILayerPlugin {
featureIdx: number, featureIdx: number,
vertex: number[], vertex: number[],
) => { ) => {
return vertex.length === 3 ? vertex : [vertex[0], vertex[1], 0]; return vertex.length === 2
? [vertex[0], vertex[1], 0]
: [vertex[0], vertex[1], vertex[2]];
}, },
}, },
}); });

View File

@ -1,8 +1,8 @@
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core'; import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
import BaseLayer from '../core/BaseLayer'; import BaseLayer from '../core/BaseLayer';
import { PointExtrudeTriangulation } from '../core/triangulation';
import pointExtrudeFrag from './shaders/extrude_frag.glsl'; import pointExtrudeFrag from './shaders/extrude_frag.glsl';
import pointExtrudeVert from './shaders/extrude_vert.glsl'; import pointExtrudeVert from './shaders/extrude_vert.glsl';
import { PointExtrudeTriangulation } from './triangulation';
interface IPointLayerStyleOptions { interface IPointLayerStyleOptions {
opacity: number; opacity: number;
} }

View File

@ -0,0 +1,141 @@
import {
AttributeType,
gl,
IEncodeFeature,
ILayer,
ILayerPlugin,
ILogService,
IStyleAttributeService,
lazyInject,
TYPES,
} from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { PointImageTriangulation } from '../core/triangulation';
import pointImageFrag from './shaders/image_frag.glsl';
import pointImageVert from './shaders/image_vert.glsl';
interface IPointLayerStyleOptions {
opacity: number;
}
export function PointTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[];
return {
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
extrude: [-1, -1, 1, -1, 1, 1, -1, 1],
indices: [0, 1, 2, 2, 3, 0],
size: coordinates.length,
};
}
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
public name: string = 'PointLayer';
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected renderModels() {
const { opacity } = this.getStyleOptions();
const { createTexture2D } = this.rendererService;
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_texture: createTexture2D({
data: this.iconService.getCanvas(),
width: 1024,
height: this.iconService.canvasHeight || 64,
}),
},
}),
);
return this;
}
protected buildModels() {
this.registerBuiltinAttributes(this);
this.iconService.on('imageUpdate', () => {
this.renderModels();
});
this.models = [
this.buildLayerModel({
moduleName: 'pointImage',
vertexShader: pointImageVert,
fragmentShader: pointImageFrag,
triangulation: PointTriangulation,
primitive: gl.POINTS,
depth: { enable: false },
blend: {
enable: true,
func: {
srcRGB: gl.SRC_ALPHA,
srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1,
},
},
}),
];
}
private registerBuiltinAttributes(layer: ILayer) {
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Uv',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 2,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const iconMap = this.iconService.getIconMap();
const { shape } = feature;
const { x, y } = iconMap[shape as string] || { x: 0, y: 0 };
return [x, y];
},
},
});
}
}

View File

@ -1,18 +1,17 @@
precision highp float; precision highp float;
attribute vec3 a_Position; attribute vec3 a_Position;
attribute vec4 a_color; attribute vec4 a_Color;
attribute vec2 a_uv; attribute vec2 a_Uv;
attribute float a_size; attribute float a_Size;
attribute float a_shape;
varying vec4 v_color; varying vec4 v_color;
varying vec2 v_uv; varying vec2 v_uv;
uniform mat4 u_ModelMatrix; uniform mat4 u_ModelMatrix;
#pragma include "projection" #pragma include "projection"
void main() { void main() {
v_color = a_color; v_color = a_Color;
v_uv = a_uv; v_uv = a_Uv;
vec4 project_pos = project_position(vec4(a_Position, 1.0)); vec4 project_pos = project_position(vec4(a_Position, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0)); gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
gl_PointSize = a_size; gl_PointSize = a_Size;
} }

View File

@ -0,0 +1,107 @@
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { PolygonExtrudeTriangulation } from '../core/triangulation';
import pointExtrudeFrag from './shaders/polygon_extrude_frag.glsl';
import pointExtrudeVert from './shaders/polygon_extrude_vert.glsl';
interface IPointLayerStyleOptions {
opacity: number;
}
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
public name: string = 'PolygonLayer';
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected renderModels() {
const { opacity } = this.getStyleOptions();
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
},
}),
);
return this;
}
protected buildModels() {
this.registerBuiltinAttributes(this);
this.models = [
this.buildLayerModel({
moduleName: 'polygonExtrude',
vertexShader: pointExtrudeVert,
fragmentShader: pointExtrudeFrag,
triangulation: PolygonExtrudeTriangulation,
blend: {
enable: true,
func: {
srcRGB: gl.SRC_ALPHA,
srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1,
},
},
}),
];
}
private registerBuiltinAttributes(layer: ILayer) {
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'normal',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Normal',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 3,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
normal: number[],
) => {
return normal;
},
},
});
layer.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
}
}

View File

@ -0,0 +1,10 @@
uniform float u_Opacity: 1.0;
varying vec4 v_Color;
#pragma include "picking"
void main() {
gl_FragColor = v_Color;
gl_FragColor.a *= u_Opacity;
gl_FragColor = filterColor(gl_FragColor);
}

View File

@ -0,0 +1,19 @@
attribute vec4 a_Color;
attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute float a_Size;
uniform mat4 u_ModelMatrix;
varying vec4 v_Color;
#pragma include "projection"
#pragma include "picking"
void main() {
v_Color = vec4(a_Normal,1.0);
vec4 project_pos = project_position(vec4(a_Position.xy,a_Position.z * a_Size, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
setPickingColor(a_PickingColor);
}

View File

@ -1,6 +1,7 @@
attribute vec4 a_Color; attribute vec4 a_Color;
attribute vec3 a_Position; attribute vec3 a_Position;
// attribute vec3 a_normal; attribute vec3 a_Normal;
attribute float a_Size;
uniform mat4 u_ModelMatrix; uniform mat4 u_ModelMatrix;
varying vec4 v_Color; varying vec4 v_Color;
@ -9,8 +10,8 @@ varying vec4 v_Color;
#pragma include "picking" #pragma include "picking"
void main() { void main() {
v_Color = a_Color; v_Color =a_Color;
vec4 project_pos = project_position(vec4(a_Position, 1.0)); vec4 project_pos = project_position(vec4(a_Position 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0)); gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
setPickingColor(a_PickingColor); setPickingColor(a_PickingColor);

View File

@ -210,12 +210,20 @@ export default function(
} }
} }
} }
const pickData = [];
for (let i = 0; i < miters.length; i++) {
pickData.push(
attrPos[i * 3],
attrPos[i * 3 + 1],
attrPos[i * 3 + 1],
attrDistance[i],
miters[i],
);
}
return { return {
normals: out, normals: out,
attrIndex, attrIndex,
attrPos, attrPos: pickData, // [x,y,z, distance, miter ]
attrDistance,
miters,
}; };
} }
// [x,y,z, distance, miter ]

View File

@ -1,8 +1,15 @@
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import * as React from 'react'; import * as React from 'react';
import LineLayer from './components/Line';
import PointDemo from './components/Point'; import PointDemo from './components/Point';
import Point3D from './components/Point3D'; import Point3D from './components/Point3D';
import PointImage from './components/pointImage';
import Polygon3D from './components/polygon3D';
// @ts-ignore // @ts-ignore
storiesOf('图层', module) storiesOf('图层', module)
.add('点图层', () => <PointDemo />) .add('点图层', () => <PointDemo />)
.add('3D点', () => <Point3D />); .add('3D点', () => <Point3D />)
.add('图片标注', () => <PointImage />)
.add('面3d图层', () => <Polygon3D />)
.add('线图层', () => <LineLayer />);

View File

@ -0,0 +1,80 @@
import { LineLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
export default class Point3D extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json',
);
const testdata = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: [
[91.58203125, 34.95799531086792],
[96.767578125, 34.379712580462204],
[99.228515625, 33.7243396617476],
],
},
},
],
};
const scene = new Scene({
center: [102.602992, 23.107329],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/dark-v9',
zoom: 13,
});
const lineLayer = new LineLayer({})
.source(await response.json())
.size(1)
.shape('line')
.color(
'ELEV',
[
'#E8FCFF',
'#CFF6FF',
'#A1E9ff',
'#65CEF7',
'#3CB1F0',
'#2894E0',
'#1772c2',
'#105CB3',
'#0D408C',
'#002466',
].reverse(),
)
.render();
scene.addLayer(lineLayer);
scene.render();
this.scene = scene;
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,61 @@
import { PointImageLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
import data from '../data/data.json';
export default class PointImage extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public componentDidMount() {
const scene = new Scene({
center: [120.19382669582967, 30.258134],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
zoom: 1,
});
const pointLayer = new PointImageLayer({});
const p1 = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [83.671875, 44.84029065139799],
},
},
],
};
scene.addImage(
'00',
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*kzTMQqS2QdUAAAAAAAAAAABkARQnAQ',
);
pointLayer
.source(data)
.shape('00')
.size(30);
scene.addLayer(pointLayer);
scene.render();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,75 @@
// @ts-ignore
import { Polygon3DLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as React from 'react';
function convertRGB2Hex(rgb: number[]) {
return (
'#' + rgb.map((r) => ('0' + Math.floor(r).toString(16)).slice(-2)).join('')
);
}
export default class Polygon3D extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
this.scene = scene;
const layer = new Polygon3DLayer({});
layer
.source(await response.json())
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 1.0,
});
scene.addLayer(layer);
scene.render();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}