feat(layer): add arc2d layer

This commit is contained in:
thinkinggis 2019-10-30 16:38:59 +08:00
parent dd97c55ac4
commit d5155afcac
8 changed files with 266 additions and 4 deletions

View File

@ -136,7 +136,11 @@ export function RasterImageTriangulation(feature: IEncodeFeature) {
size: 5,
};
}
/**
* 3D弧线顶点
* @param feature
* @param segNum 线线
*/
export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) {
const coordinates = feature.coordinates as IPosition[];
const positions = [];

View File

@ -1,8 +1,9 @@
import { container, ILayerPlugin, TYPES } from '@l7/core';
import BaseLayer from './core/BaseLayer';
import HeatMapGridLayer from './heatmap/grid';
import LineLayer from './line/index';
import ArcLineLayer from './line/arc';
import Arc2DLineLayer from './line/arc2d';
import LineLayer from './line/index';
import Point3dLayer from './point/extrude';
import PointImageLayer from './point/image';
import PointLayer from './point/index';
@ -74,6 +75,7 @@ export {
ImageLayer,
HeatMapGridLayer,
ArcLineLayer,
Arc2DLineLayer,
// Line,
// ImageLayer,
// HeatMapLayer,

View File

@ -0,0 +1,108 @@
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { LineArcTriangulation } from '../core/triangulation';
import line_arc2d_vert from './shaders/line_arc2d_vert.glsl';
import line_arc_frag from './shaders/line_arc_frag.glsl';
interface IArcLayerStyleOptions {
opacity: number;
segmentNumber: number;
}
export default class Arc2DLineLayer extends BaseLayer<IArcLayerStyleOptions> {
public name: string = 'LineLayer';
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 || 1,
segmentNumber: 30,
},
}),
);
return this;
}
protected buildModels() {
this.registerBuiltinAttributes(this);
this.models = [
this.buildLayerModel({
moduleName: 'arc2dline',
vertexShader: line_arc2d_vert,
fragmentShader: line_arc_frag,
triangulation: LineArcTriangulation,
depth: { enable: false },
blend: {
enable: true,
func: {
srcRGB: gl.ONE,
srcAlpha: 1,
dstRGB: gl.ONE,
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];
},
},
});
layer.styleAttributeService.registerStyleAttribute({
name: 'instance', // 弧线起始点信息
type: AttributeType.Attribute,
descriptor: {
name: 'a_Instance',
buffer: {
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 4,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[3], vertex[4], vertex[5], vertex[6]];
},
},
});
}
}

View File

@ -0,0 +1,89 @@
precision mediump float;
attribute vec4 a_Color;
attribute vec3 a_Position;
attribute vec4 a_Instance;
attribute float a_Size;
uniform mat4 u_ModelMatrix;
uniform float segmentNumber;
varying vec4 v_color;
#pragma include "projection"
float maps (float value, float start1, float stop1, float start2, float stop2) {
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
}
float getSegmentRatio(float index) {
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.));
}
float paraboloid(vec2 source, vec2 target, float ratio) {
vec2 x = mix(source, target, ratio);
vec2 center = mix(source, target, 0.5);
float dSourceCenter = distance(source, center);
float dXCenter = distance(x, center);
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
}
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
float vertex_height = paraboloid(source, target, segmentRatio);
return vec3(
mix(source, target, segmentRatio),
sqrt(max(0.0, vertex_height))
);
}
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
// normalized direction of the line
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
return offset;
}
float getAngularDist (vec2 source, vec2 target) {
vec2 delta = source - target;
vec2 sin_half_delta = sin(delta / 2.0);
float a =
sin_half_delta.y * sin_half_delta.y +
cos(source.y) * cos(target.y) *
sin_half_delta.x * sin_half_delta.x;
return 2.0 * atan(sqrt(a), sqrt(1.0 - a));
}
vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) {
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
if(abs(angularDist - PI) < 0.001) {
return (1.0 - t) * source + t * target;
}
float a = sin((1.0 - t) * angularDist) / sin(angularDist);
float b = sin(t * angularDist) / sin(angularDist);
vec2 sin_source = sin(source);
vec2 cos_source = cos(source);
vec2 sin_target = sin(target);
vec2 cos_target = cos(target);
float x = a * cos_source.y * cos_source.x + b * cos_target.y * cos_target.x;
float y = a * cos_source.y * sin_source.x + b * cos_target.y * sin_target.x;
float z = a * sin_source.y + b * sin_target.y;
return vec2(atan(y, x), atan(z, sqrt(x * x + y * y)));
}
void main() {
v_color = a_Color;
vec2 source = radians(a_Instance.rg);
vec2 target = radians(a_Instance.ba);
float angularDist = getAngularDist(source, target);
float segmentIndex = a_Position.x;
float segmentRatio = getSegmentRatio(segmentIndex);
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0));
vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0));
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
}

View File

@ -12,6 +12,7 @@ uniform mat4 u_ModelMatrix;
varying vec4 v_color;
varying float v_dash_array;
varying vec3 v_normal;
#pragma include "projection"
void main() {
v_normal = a_Normal;

View File

@ -1,5 +1,6 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Arc2DLineDemo from './components/Arc2DLine';
import ArcLineDemo from './components/Arcline';
import GridHeatMap from './components/heatMapgrid';
import LineLayer from './components/Line';
@ -16,6 +17,7 @@ storiesOf('图层', module)
.add('图片标注', () => <PointImage />)
.add('面3d图层', () => <Polygon3D />)
.add('线图层', () => <LineLayer />)
.add('弧线', () => <ArcLineDemo />)
.add('3D弧线', () => <ArcLineDemo />)
.add('2D弧线', () => <Arc2DLineDemo />)
.add('网格热力图', () => <GridHeatMap />)
.add('图片', () => <ImageLayerDemo />);

View File

@ -0,0 +1,56 @@
import { Arc2DLineLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
export default class Arc2DLineDemo extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt',
);
const scene = new Scene({
center: [116.2825, 39.9],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/dark-v9',
zoom: 2,
});
const lineLayer = new Arc2DLineLayer({})
.source(await response.text(), {
parser: {
type: 'csv',
x: 'lng1',
y: 'lat1',
x1: 'lng2',
y1: 'lat2',
},
})
.size(0.5)
.shape('arc')
.color('rgb(13,64,140)');
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

@ -2,7 +2,7 @@ import { ArcLineLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
export default class ArxLineDemo extends React.Component {
export default class ArcLineDemo extends React.Component {
private scene: Scene;
public componentWillUnmount() {