feat(line): greatCircle

This commit is contained in:
thinkinggis 2019-07-15 11:35:07 +08:00
parent 3ed7ed4d25
commit 4977426645
13 changed files with 226 additions and 81 deletions

53
demos/greatcircle.html Normal file
View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://gw.alipayobjects.com/os/rmsportal/PqLCOJpqoOUfuPRacUzE.css" />
<title>弧线图</title>
<style> ::-webkit-scrollbar{display:none;}html,body{overflow:hidden;margin:0;}
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>/*Fixing iframe window.innerHeight 0 issue in Safari*/ document.body.clientHeight; </script>
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<script src="../build/L7.js"></script>
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
<style>
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
<script>
var scene = new L7.Scene({
id: 'map',
mapStyle: 'dark', // 样式URL
center: [116.2825, 39.9],
pitch: 0,
zoom: 4
});
scene.on('loaded', function() {
$.get('https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt', function(data) {
scene.LineLayer({
zIndex: 2
}).source(data, {
parser:{
type:'csv',
x: 'lng1',
y: 'lat1',
x1: 'lng2',
y1: 'lat2'
}
}
).color('rgb(13,64,140)').style({
opacity: 0.6
})
.shape('greatCircle')
.size(1)
.render();
});
});
</script>
</body>
</html>

View File

@ -136,12 +136,6 @@ export default class Layer extends Base {
cfg.mapType = this.scene.mapType; cfg.mapType = this.scene.mapType;
cfg.zoom = this.scene.getZoom(); cfg.zoom = this.scene.getZoom();
this.layerSource = new source(cfg); this.layerSource = new source(cfg);
// this.scene.workerPool.runTask({
// command: 'geojson',
// data: cfg
// }).then(data => {
// console.log(data);
// });
return this; return this;
} }
color(field, values) { color(field, values) {

View File

@ -25,8 +25,8 @@ export default class Scene extends Base {
_initEngine(mapContainer) { _initEngine(mapContainer) {
this._engine = new Engine(mapContainer, this); this._engine = new Engine(mapContainer, this);
this.registerMapEvent(); // this.registerMapEvent();
// this._engine.run(); this._engine.run();
// this.workerPool = new WorkerPool(); // this.workerPool = new WorkerPool();
compileBuiltinModules(); compileBuiltinModules();
} }

View File

@ -3,11 +3,7 @@ import { lineShape } from '../shape';
export default class LineBuffer extends BufferBase { export default class LineBuffer extends BufferBase {
geometryBuffer() { geometryBuffer() {
const layerData = this.get('layerData');
const shapeType = this.shapeType = this.get('shapeType'); const shapeType = this.shapeType = this.get('shapeType');
const positions = [];
const positionsIndex = [];
const instances = [];
if (shapeType === 'line') { if (shapeType === 'line') {
this.attributes = this._getMeshLineAttributes(); this.attributes = this._getMeshLineAttributes();
return; return;
@ -15,22 +11,6 @@ export default class LineBuffer extends BufferBase {
this.attributes = this._getArcLineAttributes(); this.attributes = this._getArcLineAttributes();
return; return;
} }
layerData.forEach((item, index) => {
const props = item;
const attrData = this._getShape(item.coordinates, props, index);
positions.push(...attrData.positions);
positionsIndex.push(...attrData.indexes);
if (attrData.hasOwnProperty('instances')) {
instances.push(...attrData.instances);
}
});
this.bufferStruct.style = layerData;
this.bufferStruct.verts = positions;
this.bufferStruct.indexs = positionsIndex;
if (instances.length > 0) {
this.bufferStruct.instances = instances;
}
this.attributes = this._toAttributes(this.bufferStruct);
} }
_getShape(geo, props, index) { _getShape(geo, props, index) {
@ -55,6 +35,7 @@ export default class LineBuffer extends BufferBase {
const indexArray = []; const indexArray = [];
const sizes = []; const sizes = [];
const instances = []; const instances = [];
const pickingIds = [];
layerData.forEach(item => { layerData.forEach(item => {
const props = item; const props = item;
const positionCount = positions.length / 3; const positionCount = positions.length / 3;
@ -64,8 +45,10 @@ export default class LineBuffer extends BufferBase {
indexArray.push(...attrData.indexArray); indexArray.push(...attrData.indexArray);
instances.push(...attrData.instances); instances.push(...attrData.instances);
sizes.push(...attrData.sizes); sizes.push(...attrData.sizes);
pickingIds.push(...attrData.pickingIds);
}); });
return { return {
pickingIds,
positions, positions,
colors, colors,
indexArray, indexArray,
@ -111,38 +94,4 @@ export default class LineBuffer extends BufferBase {
attrDashArray attrDashArray
}; };
} }
_toAttributes(bufferStruct) {
const vertCount = bufferStruct.verts.length;
const vertices = new Float32Array(vertCount * 3);
const pickingIds = new Float32Array(vertCount);
const inposs = new Float32Array(vertCount * 4);
const colors = new Float32Array(vertCount * 4);
for (let i = 0; i < vertCount; i++) {
const index = bufferStruct.indexs[i];
const color = bufferStruct.style[index].color;
const id = bufferStruct.style[index].id;
vertices[i * 3] = bufferStruct.verts[i][0];
vertices[i * 3 + 1] = bufferStruct.verts[i][1];
vertices[i * 3 + 2] = bufferStruct.verts[i][2];
colors[i * 4] = color[0];
pickingIds[i] = id;
colors[i * 4 + 1] = color[1];
colors[i * 4 + 2] = color[2];
colors[i * 4 + 3] = color[3];
if (bufferStruct.instances) { // 弧线
inposs[i * 4] = bufferStruct.instances[i][0];
inposs[i * 4 + 1] = bufferStruct.instances[i][1];
inposs[i * 4 + 2] = bufferStruct.instances[i][2];
inposs[i * 4 + 3] = bufferStruct.instances[i][3];
}
}
return {
pickingIds,
vertices,
colors,
inposs
};
}
} }

View File

@ -1,8 +1,6 @@
import * as THREE from '../../core/three'; import * as THREE from '../../core/three';
import Material from './material'; import Material from './material';
import { getModule, wrapUniforms } from '../../util/shaderModule'; import { getModule, wrapUniforms } from '../../util/shaderModule';
import arcline_frag from '../shader/arcline_frag.glsl';
import arcline_vert from '../shader/arcline_vert.glsl';
import merge from '@antv/util/lib/deep-mix'; import merge from '@antv/util/lib/deep-mix';
export function LineMaterial(options) { export function LineMaterial(options) {
@ -23,17 +21,22 @@ export function LineMaterial(options) {
return material; return material;
} }
export function ArcLineMaterial(options) { export function ArcLineMaterial(options) {
let moduleName = 'arcline';
if (options.shapeType === 'greatCircle') {
moduleName = 'greatcircle';
}
const { vs, fs } = getModule(moduleName);
const material = new Material({ const material = new Material({
uniforms: { uniforms: {
u_opacity: { value: options.u_opacity || 1.0 }, u_opacity: { value: options.u_opacity || 1.0 },
segmentNumber: { value: 49 }, segmentNumber: { value: 29 },
u_time: { value: 0 }, u_time: { value: 0 },
u_zoom: { value: options.u_zoom || 10 }, u_zoom: { value: options.u_zoom || 10 },
u_activeId: { value: options.activeId || 0 }, u_activeId: { value: options.activeId || 0 },
u_activeColor: { value: options.activeColor || [ 1.0, 0, 0, 1.0 ] } u_activeColor: { value: options.activeColor || [ 1.0, 0, 0, 1.0 ] }
}, },
vertexShader: arcline_vert, vertexShader: vs,
fragmentShader: arcline_frag, fragmentShader: fs,
transparent: true, transparent: true,
blending: THREE.AdditiveBlending blending: THREE.AdditiveBlending
}); });

View File

@ -4,6 +4,8 @@ attribute vec4 a_instance;
attribute float a_size; attribute float a_size;
uniform float u_zoom; uniform float u_zoom;
uniform float u_time; uniform float u_time;
uniform float u_activeId : 0;
uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
uniform mat4 matModelViewProjection; uniform mat4 matModelViewProjection;
uniform float segmentNumber; uniform float segmentNumber;
varying vec4 v_color; varying vec4 v_color;
@ -42,7 +44,6 @@ vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
void main() { void main() {
float visindex =mod(u_time *10.,segmentNumber);
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix; mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
vec2 source = a_instance.rg; vec2 source = a_instance.rg;
vec2 target = a_instance.ba; vec2 target = a_instance.ba;
@ -55,13 +56,11 @@ void main() {
vec3 next = getPos(source, target, nextSegmentRatio); vec3 next = getPos(source, target, nextSegmentRatio);
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, position.y); vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, position.y);
gl_Position =matModelViewProjection * vec4(vec3(curr + vec3(offset, 0.0)),1.0); gl_Position =matModelViewProjection * vec4(vec3(curr + vec3(offset, 0.0)),1.0);
// float apha = 0.;
// if( position.x> 0. && position.x <visindex)
// apha =1.0;
// vec3 c1 = vec3(0.929,0.972,0.917);
// vec3 c2 = vec3(0.062,0.325,0.603);
// v_color = mix(c1, c2, segmentRatio);
v_color = a_color; v_color = a_color;
// picking
if(pickingId == u_activeId) {
v_color = u_activeColor;
}
worldId = id_toPickColor(pickingId);
} }

View File

@ -0,0 +1,95 @@
#define PI 3.1415926535
precision mediump float;
attribute vec4 a_color;
attribute vec4 a_instance;
attribute float a_size;
uniform float u_zoom;
uniform float u_time;
uniform float u_activeId : 0;
uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
uniform mat4 matModelViewProjection;
uniform float segmentNumber;
varying vec4 v_color;
#pragma include "project"
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.0));
}
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 * pow(2.0,20.0-u_zoom) / 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() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
vec2 source = radians(unProjectFlat(a_instance.rg));
vec2 target = radians(unProjectFlat(a_instance.ba));
float angularDist = getAngularDist(source, target);
float segmentIndex = position.x;
float segmentRatio = getSegmentRatio(segmentIndex);
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
vec3 curr = vec3(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0);
vec3 next = vec3(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0);
vec2 offset = getExtrusionOffset((ProjectFlat(next.xy) - ProjectFlat(curr.xy)) * indexDir, position.y);
gl_Position =matModelViewProjection * vec4(vec3(vec3(ProjectFlat(curr.xy),2.) + vec3(offset, 0.0)),1.0);
v_color = a_color;
// picking
if(pickingId == u_activeId) {
v_color = u_activeColor;
}
worldId = id_toPickColor(pickingId);
}

View File

@ -17,6 +17,12 @@ import point_line_vert from '../shader/point_meshLine_vert.glsl';
import mesh_line_frag from '../shader/meshline_frag.glsl'; import mesh_line_frag from '../shader/meshline_frag.glsl';
import mesh_line_vert from '../shader/meshline_vert.glsl'; import mesh_line_vert from '../shader/meshline_vert.glsl';
// arc line
import arc_line_frag from '../shader/arcline_frag.glsl';
import arc_line_vert from '../shader/arcline_vert.glsl';
import great_circle_line_vert from '../shader/great_circle_line_vert.glsl';
// 原生线 // 原生线
import line_frag from '../shader/line_frag.glsl'; import line_frag from '../shader/line_frag.glsl';
import line_vert from '../shader/line_vert.glsl'; import line_vert from '../shader/line_vert.glsl';
@ -54,6 +60,7 @@ import pick_color from './shaderChunks/pick_color.glsl';
import decode from './shaderChunks/decode.glsl'; import decode from './shaderChunks/decode.glsl';
import lighting from './shaderChunks/lighting.glsl'; import lighting from './shaderChunks/lighting.glsl';
import sdf_2d from './shaderChunks/sdf_2d.glsl'; import sdf_2d from './shaderChunks/sdf_2d.glsl';
import project from './shaderChunks/project.glsl';
export function compileBuiltinModules() { export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag }); registerModule('point', { vs: point_vert, fs: point_frag });
@ -61,6 +68,7 @@ export function compileBuiltinModules() {
registerModule('decode', { vs: decode, fs: '' }); registerModule('decode', { vs: decode, fs: '' });
registerModule('lighting', { vs: lighting, fs: '' }); registerModule('lighting', { vs: lighting, fs: '' });
registerModule('sdf_2d', { vs: '', fs: sdf_2d }); registerModule('sdf_2d', { vs: '', fs: sdf_2d });
registerModule('project', { vs: project, fs: '' });
registerModule('pick_color', { vs: pick_color, fs: pick_color }); registerModule('pick_color', { vs: pick_color, fs: pick_color });
registerModule('circle', { vs: circle_vert, fs: circle_frag }); registerModule('circle', { vs: circle_vert, fs: circle_frag });
registerModule('polygon', { vs: polygon_vert, fs: polygon_frag }); registerModule('polygon', { vs: polygon_vert, fs: polygon_frag });
@ -68,6 +76,8 @@ export function compileBuiltinModules() {
registerModule('hexagon', { vs: hexagon_vert, fs: hexagon_frag }); registerModule('hexagon', { vs: hexagon_vert, fs: hexagon_frag });
registerModule('pointline', { vs: point_line_vert, fs: point_line_frag }); registerModule('pointline', { vs: point_line_vert, fs: point_line_frag });
registerModule('meshline', { vs: mesh_line_vert, fs: mesh_line_frag }); registerModule('meshline', { vs: mesh_line_vert, fs: mesh_line_frag });
registerModule('arcline', { vs: arc_line_vert, fs: arc_line_frag });
registerModule('greatcircle', { vs: great_circle_line_vert, fs: arc_line_frag });
registerModule('line', { vs: line_vert, fs: line_frag }); registerModule('line', { vs: line_vert, fs: line_frag });
registerModule('heatmap_color', { vs: heatmap_color_vert, fs: heatmap_color_frag }); registerModule('heatmap_color', { vs: heatmap_color_vert, fs: heatmap_color_frag });
registerModule('heatmap_intensity', { vs: heatmap_intensity_vert, fs: heatmap_intensity_frag }); registerModule('heatmap_intensity', { vs: heatmap_intensity_vert, fs: heatmap_intensity_frag });

View File

@ -20,7 +20,6 @@ uniform float u_duration : 2.0;
uniform float u_interval : 1.0; uniform float u_interval : 1.0;
uniform float u_trailLength : 0.2; uniform float u_trailLength : 0.2;
#endif #endif
void main() { void main() {
v_color = a_color; v_color = a_color;
v_distance = a_distance; v_distance = a_distance;

View File

@ -0,0 +1,35 @@
#define PI 3.1415926535
#define E 2.718281828459045
vec2 ProjectFlat(vec2 lnglat){
float maxs=85.0511287798;
float lat=max(min(maxs,lnglat.y),-maxs);
float scale= 268435456.;
float d=PI/180.;
float x=lnglat.x*d;
float y=lat*d;
y=log(tan((PI/4.)+(y/2.)));
float a=.5/PI,
b=.5,
c=-.5/PI;
d=.5;
x=scale*(a*x+b)-215440491.;
y=scale*(c*y+d)-106744817.;
return vec2(x,y);
}
vec2 unProjectFlat(vec2 px){
float a=.5/PI;
float b=.5;
float c=-.5/PI;
float d=.5;
float scale = 268435456.;
float x=((px.x+215440491.)/scale-b)/a;
float y=((px.y+106744817.)/scale-d)/c;
y=(atan(pow(E,y))-(PI/4.))*2.;
d=PI/180.;
float lat=y/d;
float lng=x/d;
return vec2(lng,lat);
}

View File

@ -9,12 +9,13 @@ import flatten from '@antv/util/lib/flatten';
*/ */
export function arc(geo, props, positionsIndex) { export function arc(geo, props, positionsIndex) {
const segNum = 50; const segNum = 30;
const posArray = []; const posArray = [];
const instanceArray = []; const instanceArray = [];
const sizes = []; const sizes = [];
const colors = []; const colors = [];
const { size, color } = props; const pickingIds = [];
const { size, color, id } = props;
const defaultInstance = [ geo[0][0], geo[0][1], geo[1][0], geo[1][1] ]; const defaultInstance = [ geo[0][0], geo[0][1], geo[1][0], geo[1][1] ];
const indexArray = []; const indexArray = [];
let c = 0; let c = 0;
@ -27,6 +28,8 @@ export function arc(geo, props, positionsIndex) {
sizes.push(size, size); sizes.push(size, size);
colors.push(...color); colors.push(...color);
colors.push(...color); colors.push(...color);
pickingIds.push(id);
pickingIds.push(id);
if (i !== segNum - 1) { if (i !== segNum - 1) {
indexArray[c++] = index + 0; indexArray[c++] = index + 0;
indexArray[c++] = index + 1; indexArray[c++] = index + 1;
@ -39,6 +42,7 @@ export function arc(geo, props, positionsIndex) {
} }
return { return {
pickingIds,
positions: posArray, positions: posArray,
indexArray, indexArray,
instances: instanceArray, instances: instanceArray,

View File

@ -15,6 +15,7 @@ import DrawArcLine from './line/drawArc';
registerRender('line', 'line', DrawMeshLine); registerRender('line', 'line', DrawMeshLine);
registerRender('line', 'arc', DrawArcLine); registerRender('line', 'arc', DrawArcLine);
registerRender('line', 'greatCircle', DrawArcLine);
// point // point
import DrawPointFill from './point/drawFill'; import DrawPointFill from './point/drawFill';

View File

@ -2,23 +2,26 @@ import * as THREE from '../../../core/three';
import { LineBuffer } from '../../../geom/buffer/index'; import { LineBuffer } from '../../../geom/buffer/index';
import { ArcLineMaterial } from '../../../geom/material/lineMaterial'; import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawArcLine(layerdata, layer) { export default function DrawArcLine(layerdata, layer) {
const style = this.get('styleOptions'); const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions'); const activeOption = layer.get('activedOptions');
const { attributes } = new LineBuffer({ const { attributes } = new LineBuffer({
layerdata, layerData: layerdata,
shapeType: 'arc', shapeType: 'arc',
style style
}); });
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray); geometry.setIndex(attributes.indexArray);
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3)); geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4)); geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('a_instance', new THREE.Float32BufferAttribute(attributes.instances, 4)); geometry.addAttribute('a_instance', new THREE.Float32BufferAttribute(attributes.instances, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1)); geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const lineMaterial = new ArcLineMaterial({ const lineMaterial = new ArcLineMaterial({
u_opacity: style.opacity, u_opacity: style.opacity,
u_zoom: layer.scene.getZoom(), u_zoom: layer.scene.getZoom(),
activeColor: activeOption.fill activeColor: activeOption.fill,
shapeType: layer.shapeType
}, { }, {
SHAPE: false SHAPE: false
}); });