refactor: line & polygon buffer

This commit is contained in:
thinkinggis 2019-07-23 21:43:52 +08:00
parent f451fd6cce
commit d2cb9cf4d1
40 changed files with 918 additions and 239 deletions

View File

@ -31,6 +31,7 @@ const scene = new L7.Scene({
});
window.scene = scene;
scene.on('loaded', () => {
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/xxvoBnsYNEPiAXGRmlPD.json', city => {
citylayer = scene.PolygonLayer()
@ -39,7 +40,7 @@ scene.on('loaded', () => {
.shape('extrude')
.size('max',(value)=>{
if(value<0)value =0;
if(value<0)value =1;
return value * 1000;
})
.active(true)
@ -48,7 +49,6 @@ scene.on('loaded', () => {
})
.render();
const citylayer2 = scene.PolygonLayer()
.source(city)
.shape('line')
@ -56,7 +56,7 @@ scene.on('loaded', () => {
.style({
opacity: 1
})
.render();
.render();
});
});

0
demos/greatCircle.html Normal file
View File

View File

@ -1,53 +1,60 @@
<!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>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="geometry" content="diagram">
<link rel="stylesheet" href="./assets/common.css">
<title>hexagon demo</title>
<style>
#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='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<script src="./assets/jquery-3.2.1.min.js"></script>
<script src="./assets/dat.gui.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) {
const color1 = [ 'rgba(37, 140, 249, 0.8)', 'rgba(14, 241, 242, 0.8)', 'rgba(255, 255, 255, 0.8)' ];
const scene = new L7.Scene({
id: 'map',
mapStyle: 'dark', // 样式URL
center: [ 116.2825, 39.9 ],
pitch: 0,
zoom: 3
});
scene.on('loaded', () => {
$.get('https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt', data => {
scene.LineLayer({
zIndex: 2
}).source(data, {
parser:{
type:'csv',
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();
});
}
})
.shape('greatCircle')
.size(0.8)
.color('rgb(13,64,140)')
.style({
opacity:0.6,
})
.render();
});
});
</script>
</body>
</html>

View File

@ -47,14 +47,21 @@ scene.on('loaded', () => {
parser:{
type: 'mvt',
sourceLayer:'county',
idField:'id',
maxZoom: 9,
idField:'id',
maxZoom: 9
}
})
})
.scale({
'OBJECTID':{
min:0,
max:3000,
type:'linear'
}
})
.shape('fill')
.size(2)
.active(false)
.color('red')
.color('OBJECTID',['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'])
.style({
opacity:1.0
})

View File

@ -58,12 +58,13 @@ scene.on('loaded', () => {
}
})
.shape('fill')
.size(1000000)
.active(false)
.color('OBJECTID',['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'])
.style({
opacity:1.0
})
.render();
.render();
const layer2 = scene.PolygonLayer({
zIndex:10,
})
@ -81,7 +82,7 @@ scene.on('loaded', () => {
.style({
opacity:1.0
})
.render();
.render();
});

View File

@ -8,7 +8,7 @@ export default class Renderer {
}
initRender() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
antialias: false,
alpha: true,
autoClear: false
});
@ -17,7 +17,7 @@ export default class Renderer {
this.renderer.setPixelRatio(this.pixelRatio);
this.renderer.gammaInput = true;
this.renderer.gammaOutput = true;
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.enabled = false;
this.container.appendChild(this.renderer.domElement);
}
updateSize() {

View File

@ -479,6 +479,7 @@ export default class Layer extends Base {
this.scene.on('pick-' + this.layerId, e => {
let { featureId, point2d, type } = e;
// TODO 瓦片图层获取选中数据信息
const lnglat = this.scene.containerToLngLat(point2d);
let feature = null;
let style = null;

View File

@ -77,12 +77,7 @@ export default class Scene extends Base {
return this.style.getSource(id);
}
on(type, hander) {
if (this.map && type !== 'loaded') {
this.map.on(type, hander);
return;
}
if (this.map) { this.map.on(type, hander); }
super.on(type, hander);
}
off(type, hander) {

View File

@ -33,7 +33,9 @@ export default class Source extends Base {
// 数据转换 统计,聚合,分类
this._executeTrans();
// 坐标转换
this._projectCoords();
if (!this.get('projected')) {
this._projectCoords();
}
}
setData(data, cfg = {}) {
Object.assign(this._attrs, cfg);
@ -60,7 +62,7 @@ export default class Source extends Base {
// dataArray: clone(this.originData.dataArray)
// }; // TODO 关闭数据备份
this.data = this.originData;
if (this.data !== null) {
if (this.data !== null && !this.get('projected')) {
this.data.extent = extent(this.data.dataArray);
}
}

View File

@ -45,6 +45,9 @@ export {
export { InstancedBufferAttribute } from 'three/src/core/InstancedBufferAttribute'
// export * from '../../build/three.js';
function Float32BufferAttribute( array, itemSize, normalized ) {
if(Array.isArray( array )){
array = new Float32Array( array )
}
BufferAttribute.call( this, array, itemSize, normalized );
}

117
src/geom/buffer/buffer.js Normal file
View File

@ -0,0 +1,117 @@
import Base from '../../core/base';
export default class BufferBase extends Base {
constructor(cfg) {
super(cfg);
this.attributes = {
};
this.verticesCount = 0;
this.indexCount = 0;
this.indexArray = new Int32Array(0);
this._init();
}
_init() {
this._calculateFeatures();
this._initAttributes();
this._buildFeatures();
}
_initAttributes() {
this.attributes.positions = new Float32Array(this.verticesCount * 3);
this.attributes.colors = new Float32Array(this.verticesCount * 4);
this.attributes.pickingIds = new Float32Array(this.verticesCount);
this.attributes.sizes = new Float32Array(this.verticesCount);
this.attributes.pickingIds = new Float32Array(this.verticesCount);
if (this.get('uv')) {
this.attributes.uv = new Float32Array(this.verticesCount * 2);
}
this.indexArray = new Int32Array(this.indexCount);
}
addFeature() {
}
// 更新渲染
upload() {
}
destroy() {
}
resize() {
}
checkIsClosed(points) {
const p1 = points[0][0];
const p2 = points[0][points[0].length - 1];
return (p1[0] === p2[0] && p1[1] === p2[1]);
}
concat(arrayType, arrays) {
let totalLength = 0;
for (const arr of arrays) {
totalLength += arr.length;
}
const arrayBuffer = new ArrayBuffer(totalLength * arrayType.BYTES_PER_ELEMENT);
let offset = 0;
const result = new arrayType(arrayBuffer);
for (const arr of arrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
_encodeArray(feature, num) {
const { color, id, pattern, size } = feature;
const { verticesOffset } = feature.bufferInfo;
const imagePos = this.get('imagePos');
const start1 = verticesOffset;
for (let i = 0; i < num; i++) {
if (feature.hasOwnProperty('color')) {
this.attributes.colors[start1 * 4 + i * 4] = color[0];
this.attributes.colors[start1 * 4 + i * 4 + 1] = color[1];
this.attributes.colors[start1 * 4 + i * 4 + 2] = color[2];
this.attributes.colors[start1 * 4 + i * 4 + 3] = color[3];
}
if (feature.hasOwnProperty('id')) {
this.attributes.pickingIds[start1 + i] = id;
}
if (feature.hasOwnProperty('size')) {
this.attributes.sizes[start1 + i ] = size[0] || size;
}
if (feature.hasOwnProperty('pattern')) {
const patternPos = imagePos[pattern] || { x: 0, y: 0 };
this.attributes.patterns[start1 * 2 + i * 2 ] = patternPos.x;
this.attributes.patterns[start1 * 2 + i * 2 + 1] = patternPos.y;
}
}
}
_calculateWall(feature) {
const size = feature.size;
const { vertices, indexOffset, verticesOffset, faceNum } = feature.bufferInfo;
this._encodeArray(feature, faceNum * 4);
for (let i = 0; i < faceNum; i++) {
const prePoint = vertices.slice(i * 3, i * 3 + 3);
const nextPoint = vertices.slice(i * 3 + 3, i * 3 + 6);
this._calculateExtrudeFace(prePoint, nextPoint, verticesOffset + i * 4, indexOffset + i * 6, size);
feature.bufferInfo.verticesOffset += 4;
feature.bufferInfo.indexOffset += 6;
}
}
_calculateExtrudeFace(prePoint, nextPoint, positionOffset, indexOffset, size) {
this.attributes.positions.set([
prePoint[0], prePoint[1], size,
nextPoint[0], nextPoint[1], size,
prePoint[0], prePoint[1], 0,
nextPoint[0], nextPoint[1], 0
],
positionOffset * 3);
const indexArray = [ 1, 2, 0, 3, 2, 1 ].map(v => { return v + positionOffset; });
if (this.get('uv')) {
this.attributes.uv.set([ 0.1, 0, 0, 0, 0.1, size / 2000, 0, size / 2000 ], positionOffset * 2);
}
this.indexArray.set(indexArray, indexOffset);
}
}

View File

@ -65,18 +65,12 @@ export default class BufferBase extends Base {
return mergedAttributes;
}
_toPolygonAttributes(polygon) {
// Three components per vertex per face (3 x 3 = 9)
const { style, indices, position, indexCount } = polygon;
const vertices = new Float32Array(indexCount * 3);
const normals = new Float32Array(indexCount * 3);
const colors = new Float32Array(indexCount * 4);
const pickingIds = new Float32Array(indexCount);
const pA = new Vector3();
const pB = new Vector3();
const pC = new Vector3();
const cb = new Vector3();
const ab = new Vector3();
let lastIndex = 0;
indices.forEach((indice, pIndex) => {
for (let i = 0; i < indice.length / 3; i++) {
@ -94,72 +88,48 @@ export default class BufferBase extends Base {
const cx = position[pIndex][index][0];
const cy = position[pIndex][index][1];
const cz = position[pIndex][index][2];
vertices.set([ ax, ay, az, bx, by, bz, cx, cy, cz ], lastIndex * 9);
colors.set([ color[0], color[1], color[2], color[3], color[0], color[1], color[2], color[3], color[0], color[1], color[2], color[3] ], lastIndex * 12);
pickingIds.fill(_pickingId, lastIndex * 3 + 0, lastIndex * 3 + 3);
// vertices[lastIndex * 9 + 0] = ax;
// vertices[lastIndex * 9 + 1] = ay;
// vertices[lastIndex * 9 + 2] = az;
pA.set(ax, ay, az);
pB.set(bx, by, bz);
pC.set(cx, cy, cz);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
cb.normalize();
const nx = cb.x;
const ny = cb.y;
const nz = cb.z;
vertices[lastIndex * 9 + 0] = ax;
vertices[lastIndex * 9 + 1] = ay;
vertices[lastIndex * 9 + 2] = az;
normals[lastIndex * 9 + 0] = nx;
normals[lastIndex * 9 + 1] = ny;
normals[lastIndex * 9 + 2] = nz;
colors[lastIndex * 12 + 0] = color[0];
colors[lastIndex * 12 + 1] = color[1];
colors[lastIndex * 12 + 2] = color[2];
colors[lastIndex * 12 + 3] = color[3];
// colors[lastIndex * 12 + 0] = color[0];
// colors[lastIndex * 12 + 1] = color[1];
// colors[lastIndex * 12 + 2] = color[2];
// colors[lastIndex * 12 + 3] = color[3];
vertices[lastIndex * 9 + 3] = bx;
vertices[lastIndex * 9 + 4] = by;
vertices[lastIndex * 9 + 5] = bz;
// vertices[lastIndex * 9 + 3] = bx;
// vertices[lastIndex * 9 + 4] = by;
// vertices[lastIndex * 9 + 5] = bz;
normals[lastIndex * 9 + 3] = nx;
normals[lastIndex * 9 + 4] = ny;
normals[lastIndex * 9 + 5] = nz;
// colors[lastIndex * 12 + 4] = color[0];
// colors[lastIndex * 12 + 5] = color[1];
// colors[lastIndex * 12 + 6] = color[2];
// colors[lastIndex * 12 + 7] = color[3];
colors[lastIndex * 12 + 4] = color[0];
colors[lastIndex * 12 + 5] = color[1];
colors[lastIndex * 12 + 6] = color[2];
colors[lastIndex * 12 + 7] = color[3];
// vertices[lastIndex * 9 + 6] = cx;
// vertices[lastIndex * 9 + 7] = cy;
// vertices[lastIndex * 9 + 8] = cz;
vertices[lastIndex * 9 + 6] = cx;
vertices[lastIndex * 9 + 7] = cy;
vertices[lastIndex * 9 + 8] = cz;
// colors[lastIndex * 12 + 8] = color[0];
// colors[lastIndex * 12 + 9] = color[1];
// colors[lastIndex * 12 + 10] = color[2];
// colors[lastIndex * 12 + 11] = color[3];
normals[lastIndex * 9 + 6] = nx;
normals[lastIndex * 9 + 7] = ny;
normals[lastIndex * 9 + 8] = nz;
colors[lastIndex * 12 + 8] = color[0];
colors[lastIndex * 12 + 9] = color[1];
colors[lastIndex * 12 + 10] = color[2];
colors[lastIndex * 12 + 11] = color[3];
pickingIds[lastIndex * 3 + 0] = _pickingId;
pickingIds[lastIndex * 3 + 1] = _pickingId;
pickingIds[lastIndex * 3 + 2] = _pickingId;
// pickingIds[lastIndex * 3 + 0] = _pickingId;
// pickingIds[lastIndex * 3 + 1] = _pickingId;
// pickingIds[lastIndex * 3 + 2] = _pickingId;
lastIndex++;
}
});
console.timeEnd(indexCount+':buffer');
const attributes = {
vertices,
normals,
colors,
pickingIds,
faceUv: new Float32Array(polygon.faceUv),

View File

@ -1,10 +1,23 @@
import PolygonBuffer from './polygon';
import LineBuffer from './line';
// export { default as textBuffer } from './textBuffer';
// Polygon
import FillBuffer from './polygon/fill_buffer';
import LineBuffer from './polygon/line_buffer';
import ExtrudeBuffer from './polygon/extrude_buffer';
// Line
import MeshLineBuffer from './line/meshline';
import ArcLineBuffer from './line/arcline';
import { registerBuffer, getBuffer } from './factory';
registerBuffer('polygon', 'fill', PolygonBuffer);
registerBuffer('polygon', 'extrude', PolygonBuffer);
registerBuffer('polygon', 'line', PolygonBuffer);
registerBuffer('line', 'line', LineBuffer);
registerBuffer('polygon', 'fill', FillBuffer);
registerBuffer('polygon', 'extrude', ExtrudeBuffer);
registerBuffer('polygon', 'line', LineBuffer);
// line
registerBuffer('line', 'line', MeshLineBuffer);
registerBuffer('line', 'arc', ArcLineBuffer);
registerBuffer('line', 'greatCircle', ArcLineBuffer);
export { getBuffer };

View File

@ -0,0 +1,35 @@
import BufferBase from '../buffer';
export default class ArcLineBuffer extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
layerData.forEach((feature, index) => {
this._calculateArc(feature, index);
});
}
_initAttributes() {
super._initAttributes();
this.attributes.instanceArray = new Float32Array(this.verticesCount * 4);
}
_calculateArc(feature, offset) {
const { segNum = 30 } = this.get('style');
const { coordinates } = feature;
for (let i = 0; i < segNum; i++) {
this.attributes.positions.set([ i, 1, i, i, -1, i ], offset * segNum * 6 + i * 6);
this.attributes.instanceArray.set([ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1],
coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ], offset * segNum * 8 + i * 8);
if (i !== segNum - 1) {
const indexArray = [ 0, 1, 2, 1, 3, 2 ].map(v => { return offset * segNum * 2 + i * 2 + v; });
this.indexArray.set(indexArray, offset * segNum * 6 + i * 6 - offset * 6);
}
}
feature.bufferInfo = { verticesOffset: offset * segNum * 2 };
this._encodeArray(feature, segNum * 2);
}
_calculateFeatures() {
const layerData = this.get('layerData');
const segNum = this.get('segNum') || 30;
this.verticesCount = layerData.length * segNum * 2;
this.indexCount = this.verticesCount * 3 - layerData.length * 6;
}
}

View File

@ -0,0 +1,60 @@
import BufferBase from '../buffer';
import getNormals from '../../../util/polyline-normals';
export default class MeshLineBuffer extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
layerData.forEach(feature => {
this._calculateLine(feature);
delete feature.bufferInfo;
});
}
_initAttributes() {
super._initAttributes();
this.attributes.dashArray = new Float32Array(this.verticesCount);
this.attributes.attrDistance = new Float32Array(this.verticesCount);
this.attributes.totalDistances = new Float32Array(this.verticesCount);
this.attributes.patterns = new Float32Array(this.verticesCount * 2);
this.attributes.miters = new Float32Array(this.verticesCount);
this.attributes.normals = new Float32Array(this.verticesCount * 3);
}
_calculateFeatures() {
const layerData = this.get('layerData');
// 计算长
layerData.forEach(feature => {
const bufferInfo = {};
const { coordinates } = feature;
const { normals, attrIndex, attrPos, attrDistance, miters } = getNormals(coordinates, false, this.verticesCount);
bufferInfo.normals = normals;
bufferInfo.arrayIndex = attrIndex;
bufferInfo.positions = attrPos;
bufferInfo.attrDistance = attrDistance;
bufferInfo.miters = miters;
bufferInfo.verticesOffset = this.verticesCount;
bufferInfo.indexOffset = this.indexCount;
this.verticesCount += attrPos.length / 3;
this.indexCount += attrIndex.length;
feature.bufferInfo = bufferInfo;
});
}
_calculateLine(feature) {
const { normals, arrayIndex, positions, attrDistance, miters, verticesOffset, indexOffset } = feature.bufferInfo;
const { dashArray = 200 } = this.get('style');
this._encodeArray(feature, positions.length / 3);
const totalLength = attrDistance[attrDistance.length - 1];
// 增加长度
const totalDistances = Array(positions.length / 3).fill(totalLength);
// 虚线比例
const ratio = dashArray / totalLength;
const dashArrays = Array(positions.length / 3).fill(ratio);
this.attributes.positions.set(positions, verticesOffset * 3);
this.indexArray.set(arrayIndex, indexOffset);
this.attributes.miters.set(miters, verticesOffset);
this.attributes.normals.set(normals, verticesOffset * 3);
this.attributes.attrDistance.set(attrDistance, verticesOffset);
this.attributes.totalDistances.set(totalDistances, verticesOffset);
this.attributes.dashArray.set(dashArrays, verticesOffset);
}
}

View File

@ -4,6 +4,7 @@ export default class PolygonBuffer extends BufferBase {
geometryBuffer() {
const layerData = this.get('layerData');
const shape = this.get('shape');
const needFaceUv = this.get('faceUv');
const positions = [];
const faceUv = [];
const sizes = [];
@ -24,7 +25,7 @@ export default class PolygonBuffer extends BufferBase {
}
positions.push(extrudeData.positions);
if (shape !== 'line') {
if (needFaceUv) {
// faceUv.push(...extrudeData.faceUv);
const count = extrudeData.faceUv.length / 2;
for (let i = 0; i < count; i++) {
@ -54,7 +55,6 @@ export default class PolygonBuffer extends BufferBase {
} else {
this.attributes = this._toPolygonLineAttributes(this.bufferStruct);
}
}

View File

@ -0,0 +1,55 @@
import BufferBase from '../buffer';
import earcut from 'earcut';
export default class ExtrudeButffer extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
layerData.forEach(feature => {
this._calculateTop(feature);
this._calculateWall(feature);
delete feature.bufferInfo;
});
}
_calculateFeatures() {
const layerData = this.get('layerData');
// 计算长
layerData.forEach(feature => {
const { coordinates } = feature;
const bufferInfo = {};
const flattengeo = earcut.flatten(coordinates);
const n = this.checkIsClosed(coordinates[0]) ? coordinates[0].length - 1 : coordinates[0].length;
const { vertices, dimensions, holes } = flattengeo;
const indexArray = earcut(vertices, holes, dimensions).map(v => { return this.verticesCount + v; });
bufferInfo.vertices = vertices;
bufferInfo.indexArray = indexArray;
bufferInfo.verticesOffset = this.verticesCount + 0;
bufferInfo.indexOffset = this.indexCount + 0;
bufferInfo.faceNum = n;
this.indexCount += indexArray.length + n * 6;
this.verticesCount += vertices.length / 3 + n * 4;
feature.bufferInfo = bufferInfo;
});
}
_calculateTop(feature) {
const size = feature.size;
const { indexArray, vertices, indexOffset, verticesOffset } = feature.bufferInfo;
const pointCount = vertices.length / 3;
this._encodeArray(feature, vertices.length / 3);
// 添加顶点
for (let i = 0; i < pointCount; i++) {
this.attributes.positions.set([ vertices[ i * 3 ], vertices[i * 3 + 1 ], size ], (verticesOffset + i) * 3);
// 顶部文理坐标计算
if (this.get('uv')) {
// TODO 用过BBox计算纹理坐标
this.attributes.uv.set([ -1, -1 ], (verticesOffset + i) * 2);
}
}
feature.bufferInfo.verticesOffset += pointCount;
// 添加顶点索引
this.indexArray.set(indexArray, indexOffset); // 顶部坐标
feature.bufferInfo.indexOffset += indexArray.length;
}
}

View File

@ -0,0 +1,51 @@
import BufferBase from '../buffer';
import earcut from 'earcut';
export default class FillBuffer extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
layerData.forEach(feature => {
this._calculateFill(feature);
delete feature.bufferInfo;
});
}
_calculateFill(feature) {
const { indexArray, vertices, indexOffset, verticesOffset } = feature.bufferInfo;
const pointCount = vertices.length / 3;
this._encodeArray(feature, vertices.length / 3);
// 添加顶点
for (let i = 0; i < pointCount; i++) {
this.attributes.positions.set([ vertices[ i * 3 ], vertices[i * 3 + 1 ], 0 ], (verticesOffset + i) * 3);
if (this.get('uv')) {
// TODO 用过BBox计算纹理坐标
this.attributes.uv.set([ 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 ], (verticesOffset + i) * 3);
}
}
feature.bufferInfo.verticesOffset += pointCount;
// 添加顶点索引
this.indexArray.set(indexArray, indexOffset); // 顶部坐标
feature.bufferInfo.indexOffset += indexArray.length;
}
_calculateFeatures() {
const layerData = this.get('layerData');
// 计算长
layerData.forEach(feature => {
const { coordinates } = feature;
const bufferInfo = {};
const flattengeo = earcut.flatten(coordinates);
const { vertices, dimensions, holes } = flattengeo;
const indexArray = earcut(vertices, holes, dimensions).map(v => { return this.verticesCount + v; });
bufferInfo.vertices = vertices;
bufferInfo.indexArray = indexArray;
bufferInfo.verticesOffset = this.verticesCount + 0;
bufferInfo.indexOffset = this.indexCount + 0;
this.indexCount += indexArray.length;
this.verticesCount += vertices.length / 3;
feature.bufferInfo = bufferInfo;
});
}
}

View File

@ -0,0 +1,77 @@
import BufferBase from '../buffer';
export default class LineBuffer extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
let offsetVertices = 0;
let offsetIndex = 0;
let offset = 0;
layerData.forEach(feature => {
const { coordinates } = feature;
coordinates.forEach(coord => {
const n = coord.length;
feature.bufferInfo = {
verticesOffset: offsetVertices
};
this._encodeArray(feature, n);
for (let i = 0; i < n; i++) {
this.attributes.positions[offsetVertices * 3] = coord[i][0];
this.attributes.positions[offsetVertices * 3 + 1] = coord[i][1];
this.attributes.positions[offsetVertices * 3 + 2] = coord[i][2];
this.indexArray[offsetIndex * 2] = i + offset;
this.indexArray[offsetIndex * 2 + 1] = i + offset + 1;
if (i === n - 1) {
this.indexArray[offsetIndex * 2 + 1] = offsetVertices - n + 1;
}
offsetVertices++;
offsetIndex++;
}
offset += n;
});
});
}
_calculateBufferLength() {
const layerData = this.get('layerData');
layerData.forEach(feature => {
const { coordinates } = feature;
coordinates.forEach(coord => {
this.verticesCount += coord.length;
this.indexCount += (coord.length * 2 - 2);
});
});
}
_calculateFeatures() {
const layerData = this.get('layerData');
layerData.forEach(feature => {
const { coordinates } = feature;
coordinates.forEach(coord => {
this.verticesCount += coord.length;
this.indexCount += (coord.length * 2);
});
});
}
_calculateLine(feature) {
let { indexOffset, verticesOffset } = feature.bufferInfo;
feature.coordinates.forEach(coord => {
const n = coord.length;
this._encodeArray(feature, n);
for (let i = 0; i < n; i++) {
this.attributes.positions[(verticesOffset + i) * 3] = coord[i][0];
this.attributes.positions[(verticesOffset + i) * 3 + 1] = coord[i][1];
this.attributes.positions[(verticesOffset + i) * 3 + 2] = coord[i][2];
this.indexArray[(indexOffset + i) * 2] = i + verticesOffset * 2;
this.indexArray[(indexOffset + i) * 2 + 1] = i + verticesOffset * 2 + 1;
if (i === n - 1) {
this.indexArray[(indexOffset + i) * 2 + 1] = verticesOffset + 1;
}
}
verticesOffset += n;
indexOffset += n;
});
}
}

View File

@ -14,7 +14,6 @@ export default function extrudePolygon(points, extrude) {
if (p1[0] === p2[0] && p1[1] === p2[1]) {
points[0] = points[0].slice(0, points[0].length - 1);
}
const n = points[0].length;
const flattengeo = earcut.flatten(points);
const positions = [];

View File

@ -16,7 +16,7 @@ varying vec4 v_color;
uniform float u_zoom : 0;
uniform float u_opacity : 1.0;
uniform float u_activeId : 0;
uniform float u_activeId : -1;
uniform vec4 u_activeColor : [1.0, 0.0, 0.0, 1.0];
#pragma include "lighting"
@ -37,7 +37,7 @@ void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position + offset, 1.);
#ifdef LIGHTING
if (normal != vec3(0., 0., 1.)) {
if (normal != vec3(0., 0., 1.0)) {
vec3 viewDir = normalize(cameraPosition - position);
v_color.rgb *= calc_lighting(position, normal, viewDir);
}

View File

@ -1,4 +1,4 @@
precision highp float;
void main() {
gl_FragColor = vec4(1.0);
gl_FragColor = vec4(0.0,0.,0.,1.0);
}

View File

@ -18,7 +18,7 @@ export default class LineLayer extends Layer {
}
draw() {
this.type = 'line';
this.add(getRender('line', this.shapeType || 'line')(this.layerData, this, this.layerSource));
this.add(getRender('line', this.shapeType || 'line')(this.layerData, this));
}
}
LineLayer.type = 'line';

View File

@ -1,20 +1,24 @@
import * as THREE from '../../../core/three';
import LineBuffer from '../../../geom/buffer/line';
import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawArcLine(layerdata, layer) {
import { getBuffer } from '../../../geom/buffer/';
export default function DrawArcLine(layerData, layer, buffer) {
const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
const { attributes } = new LineBuffer({
layerData: layerdata,
shapeType: 'arc',
style
});
if (!buffer) {
const geometryBuffer = getBuffer(layer.type, layer.shapeType);
buffer = new geometryBuffer({
layerData,
shapeType: layer.shapeType,
style
});
}
const { attributes, indexArray } = buffer;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
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.instanceArray, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const lineMaterial = new ArcLineMaterial({

View File

@ -1,8 +1,8 @@
import * as THREE from '../../../core/three';
import LineBuffer from '../../../geom/buffer/line';
import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
import { getBuffer } from '../../../geom/buffer/';
export default function DrawLine(layerData, layer) {
export default function DrawLine(layerData, layer, buffer) {
const style = layer.get('styleOptions');
const animateOptions = layer.get('animateOptions');
@ -12,25 +12,31 @@ export default function DrawLine(layerData, layer) {
const hasPattern = layerData.some(layer => {
return layer.pattern;
});
const { attributes } = new LineBuffer({
layerData,
shapeType: 'line',
style,
imagePos: layer.scene.image.imagePos
});
if (!buffer) {
const geometryBuffer = getBuffer(layer.type, layer.shapeType);
buffer = new geometryBuffer({
layerData,
shapeType: 'line',
style,
imagePos: layer.scene.image.imagePos
});
}
const { attributes, indexArray } = buffer;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miters, 1));
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
geometry.addAttribute('a_dash_array', new THREE.Float32BufferAttribute(attributes.attrDashArray, 1));
geometry.addAttribute('a_texture_coord', new THREE.Float32BufferAttribute(attributes.textureCoord, 2));
geometry.addAttribute('a_total_distance', new THREE.Float32BufferAttribute(attributes.totalDistance, 1));
geometry.addAttribute('a_dash_array', new THREE.Float32BufferAttribute(attributes.dashArray, 1));
geometry.addAttribute('a_texture_coord', new THREE.Float32BufferAttribute(attributes.patterns, 2));
geometry.addAttribute('a_total_distance', new THREE.Float32BufferAttribute(attributes.totalDistances, 1));
const lineMaterial = new MeshLineMaterial({
u_opacity: style.opacity,
u_zoom: layer.scene.getZoom(),

View File

@ -1,24 +1,33 @@
import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
import { getBuffer } from '../../../geom/buffer/';
import { generateLightingUniforms } from '../../../util/shaderModule';
export default function DrawAnimate(layerData, layer) {
export default function DrawAnimate(layerData, layer, buffer) {
const style = layer.get('styleOptions');
const { near, far } = layer.map.getCameraState();
layer.scene.startAnimate();
const { attributes } = new PolygonBuffer({
shape: 'extrude',
layerData
});
if (!buffer) {
const geometryBuffer = getBuffer(layer.type, 'extrude');
buffer = new geometryBuffer({
layerData,
uv: true
});
}
const { attributes, indexArray } = buffer;
const { opacity, baseColor, brightColor, windowColor, lights } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
if (indexArray) {
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
}
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.addAttribute('faceUv', new THREE.Float32BufferAttribute(attributes.faceUv, 2));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
geometry.addAttribute('faceUv', new THREE.Float32BufferAttribute(attributes.uv, 2));
// geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
geometry.computeVertexNormals();
const material = new PolygonMaterial({
u_opacity: opacity,
u_baseColor: baseColor,

View File

@ -1,7 +1,7 @@
import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
import { generateLightingUniforms } from '../../../util/shaderModule';
import { getBuffer } from '../../../geom/buffer/';
export default function DrawPolygonFill(layerData, layer, buffer) {
const style = layer.get('styleOptions');
@ -11,18 +11,22 @@ export default function DrawPolygonFill(layerData, layer, buffer) {
activeColor: activeOption.fill
};
const { opacity, activeColor, lights } = config;
let attributes = buffer;
if (!attributes) {
attributes = new PolygonBuffer({
shape: layer.shape,
if (!buffer) {
const geometryBuffer = getBuffer(layer.type, layer.shape);
buffer = new geometryBuffer({
layerData
}).attributes;
});
}
const { attributes, indexArray } = buffer;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
if (indexArray) {
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
}
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.computeVertexNormals();
const material = new PolygonMaterial({
u_opacity: opacity,
u_activeColor: activeColor,

View File

@ -9,7 +9,7 @@ export default function DrawPolygonLine(layerData, layer, buffer) {
activeColor: activeOption.fill
};
const { opacity } = config;
let attributes = buffer;
let { attributes, indexArray } = buffer;
if (!attributes) {
attributes = new PolygonBuffer({
shape: layer.shape,
@ -17,7 +17,10 @@ export default function DrawPolygonLine(layerData, layer, buffer) {
}).attributes;
}
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
if (indexArray) {
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
}
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
const lineMaterial = new LineMaterial({

View File

@ -27,7 +27,6 @@ export default class Tile extends Base {
this._object3D.onBeforeRender = () => {
};
this._isLoaded = false;
console.time(this._tile);
this.requestTileAsync(data => this._init(data));
}
_init(data) {
@ -41,7 +40,6 @@ export default class Tile extends Base {
this.isValid = true;
this._initControllers();
this._createMesh();
console.timeEnd(this._tile);
}
repaint() {
this._initControllers();

View File

@ -1,6 +1,7 @@
import { destoryObject, updateObjecteUniform } from '../../util/object3d-util';
import * as THREE from '../../core/three';
import MaskMaterial from '../../geom/material/tile/maskMaterial';
import { aProjectFlat } from '../../geo/project';
import { toLngLatBounds, toBounds } from '@antv/geo-coord';
import { getRender } from '../render/index';
const r2d = 180 / Math.PI;
@ -18,8 +19,10 @@ export default class VectorTileMesh {
this._centerLnglat = this._tileLnglatBounds.getCenter();
this._init(data);
this.maskScene = new THREE.Scene();
const tileMesh = this._tileMaskMesh();
// this._object3D.add(tileMesh);
this.maskScene.add(tileMesh);
}
_init(data) {
@ -30,8 +33,8 @@ export default class VectorTileMesh {
if (this.layer.get('type') === 'point') {
this.layer.shape = this.layer._getShape(layerData);
}
this.mesh = getRender(this.layer.get('type'), this.layer.shape)(null, this.layer, data.attributes);
this.mesh.frustumCulled = false;
this.mesh = getRender(this.layer.get('type'), this.layer.shape)(null, this.layer, data.buffer);
// this._setTilePositon();
if (this.mesh.type !== 'composer') { // 热力图的情况
this.mesh.onBeforeRender = renderer => {
this._renderMask(renderer);
@ -52,14 +55,9 @@ export default class VectorTileMesh {
}
_renderMask(renderer) {
const zoom = this.layer.scene.getZoom();
updateObjecteUniform(this.mesh, {
u_time: this.layer.scene._engine.clock.getElapsedTime(),
u_zoom: zoom
});
if (this.layer.get('layerType') === 'point') { // 点图层目前不需要mask
return;
}
// if (this.layer.get('layerType') === 'point') { // 点图层目前不需要mask
// return;
// }
const context = renderer.context;
renderer.autoClear = false;
renderer.clearDepth();
@ -81,6 +79,16 @@ export default class VectorTileMesh {
context.stencilFunc(context.EQUAL, 1, 0xffffffff); // draw if == 1
context.stencilOp(context.KEEP, context.KEEP, context.KEEP);
}
_setTilePositon() {
const tr = this._tileLnglatBounds.getNorthWest();
const zoom = this.layer.scene.getZoom();
// const centerPoint = this.layer.scene.crs.lngLatToPoint(tr, 20);
const position = aProjectFlat([ tr.lng, tr.lat ]);
// this.mesh.position.x = position.x;
// this.mesh.position.y = position.y;
// this.mesh.scale.x = 2 << (20 - this._tile[2]);
// this.mesh.scale.y = 2 << (20 - this._tile[2]);
}
_tileMaskMesh() {
const tilebound = this._tileBounds;
const bl = [ tilebound.getBottomLeft().x, tilebound.getBottomLeft().y, 0 ];

View File

@ -6,6 +6,7 @@ import csv from './parser/csv';
import json from './parser/json';
import raster from './parser/raster';
import mvt from './parser/mvt';
import vector from './parser/vector';
import { registerTransform, registerParser } from './factory';
import { aggregatorToGrid } from './transform/grid';
@ -18,6 +19,7 @@ registerParser('csv', csv);
registerParser('json', json);
registerParser('raster', raster);
registerParser('mvt', mvt);
registerParser('vector', vector);
// 注册transform
registerTransform('grid', aggregatorToGrid);

View File

@ -4,9 +4,8 @@ import { djb2hash } from '../../util/bkdr-hash';
import rewind from '@mapbox/geojson-rewind';
export default function geoJSON(data, cfg) {
// 矢量瓦片图层不做 rewind
if (!cfg.hasOwnProperty('sourceLayer')) {
rewind(data, true);
}
rewind(data, true);
const resultData = [];
const featureKeys = {};
data.features = data.features.filter(item => {

View File

@ -0,0 +1,82 @@
import { djb2hash } from '../../util/bkdr-hash';
const Extent = 4096;
export default function vector(data, cfg) {
const tile = cfg.tile;
const resultdata = [];
const featureKeys = {};
const x0 = Extent * tile[0];
const y0 = Extent * tile[1];
function covertP20(points) {
return points.map(point => {
const x1 = (x0 + point.x << 20 - tile[2] - 4) - 215440491;
const y2 = (y0 + point.y << 20 - tile[2] - 4) - 106744817;
return [ x1, -y2, 0 ];
});
}
for (let i = 0; i < data.length; i++) {
const feature = data.feature(i);
const coords = feature.loadGeometry();
const properties = feature.properties;
let id = i + 1;
if (cfg.idField && properties[cfg.idField]) {
const value = properties[cfg.idField];
id = djb2hash(value) % 1000019;
featureKeys[id] = {
index: i++,
idField: value
};
}
const geocoords = classifyRings(coords);
for (let j = 0; j < geocoords.length; j++) {
const geo = geocoords[j].map(coord => {
return covertP20(coord);
});
resultdata.push({
...properties,
_id: feature.id || id,
coordinates: geo
});
}
}
return {
dataArray: resultdata,
featureKeys
};
}
function signedArea(ring) {
let sum = 0;
for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
p1 = ring[i];
p2 = ring[j];
sum += (p2.x - p1.x) * (p1.y + p2.y);
}
return sum;
}
function classifyRings(rings) {
const len = rings.length;
if (len <= 1) return [ rings ];
const polygons = [];
let polygon;
let ccw;
for (let i = 0; i < len; i++) {
const area = signedArea(rings[i]);
if (area === 0) continue;
if (ccw === undefined) ccw = area < 0;
if (ccw === area < 0) {
if (polygon) polygons.push(polygon);
polygon = [ rings[i] ];
} else {
polygon.push(rings[i]);
}
}
if (polygon) polygons.push(polygon);
return polygons;
}

View File

@ -10,7 +10,7 @@ export default class SouceCache extends Base {
cacheLimit: 50,
minZoom: 0,
maxZoom: 18,
keepBuffer: 1,
keepBuffer: 0,
...cfg
});
this._tileMap = {};// 视野内瓦片坐标序列
@ -88,7 +88,7 @@ export default class SouceCache extends Base {
_calculateTileIDs() {
this._tileMap = {};
this.updateTileList = [];
const zoom = Math.floor(this.scene.getZoom()) - 1; // zoom - 1
const zoom = Math.floor(this.scene.getZoom()); // - window.window.devicePixelRatio + 1; // zoom - 1
const minSourceZoom = this.get('minZoom');
const maxSourceZoom = this.get('maxZoom');
this.tileZoom = zoom > maxSourceZoom ? maxSourceZoom : zoom;

View File

@ -0,0 +1,159 @@
/**
* 对于 polyline-normal 的改进
* 超过阈值miter 转成 bevel 接头
* 要注意 Three.js 中默认 THREE.FrontFaceDirectionCCW
* @see https://zhuanlan.zhihu.com/p/59541559
*/
import { direction, normal, computeMiter } from 'polyline-miter-util';
import { create, copy, dot } from 'gl-vec2';
function extrusions(positions, out, point, normal, scale) {
addNext(out, normal, -scale);
addNext(out, normal, scale);
positions.push(point);
positions.push(point);
}
function addNext(out, normal, length) {
out.push([[ normal[0], normal[1] ], length ]);
}
function lineSegmentDistance(end, start) {
const dx = start[0] - end[0];
const dy = start[1] - end[1];
const dz = start[2] - end[2];
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
export default function(points, closed, indexOffset) {
const lineA = [ 0, 0 ];
const lineB = [ 0, 0 ];
const tangent = [ 0, 0 ];
const miter = [ 0, 0 ];
let _lastFlip = -1;
let _started = false;
let _normal = null;
const tmp = create();
let count = indexOffset || 0;
const miterLimit = 3;
const out = [];
const attrPos = [];
const attrIndex = [];
const attrDistance = [ 0, 0 ];
if (closed) {
points = points.slice();
points.push(points[0]);
}
const total = points.length;
for (let i = 1; i < total; i++) {
const index = count;
const last = points[i - 1];
const cur = points[i];
const next = i < points.length - 1 ? points[i + 1] : null;
const d = lineSegmentDistance(cur, last) + attrDistance[attrDistance.length - 1];
direction(lineA, cur, last);
if (!_normal) {
_normal = [ 0, 0 ];
normal(_normal, lineA);
}
if (!_started) {
_started = true;
extrusions(attrPos, out, last, _normal, 1);
}
attrIndex.push([ index + 0, index + 2, index + 1 ]);
// no miter, simple segment
if (!next) {
// reset normal
normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
count += 2;
} else {
// get unit dir of next line
direction(lineB, next, cur);
// stores tangent & miter
let miterLen = computeMiter(tangent, miter, lineA, lineB, 1);
// get orientation
const flip = (dot(tangent, _normal) < 0) ? -1 : 1;
const bevel = Math.abs(miterLen) > miterLimit;
// 处理前后两条线段重合的情况这种情况不需要使用任何接头miter/bevel
// 理论上这种情况下 miterLen = Infinity本应通过 isFinite(miterLen) 判断,
// 但是 AMap 投影变换后丢失精度只能通过一个阈值1000判断。
if (Math.abs(miterLen) > 1000) {
normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d);
attrIndex.push(
_lastFlip === 1 ? [ index + 1, index + 3, index + 2 ]
: [ index, index + 2, index + 3 ]
);
// 避免在 Material 中使用 THREE.DoubleSide
attrIndex.push([ index + 2, index + 3, index + 4 ]);
count += 2;
_lastFlip = -1;
continue;
}
if (bevel) {
miterLen = miterLimit;
// next two points in our first segment
extrusions(attrPos, out, cur, _normal, 1);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
// now add the bevel triangle
attrIndex.push(flip === 1 ? [ index + 2, index + 4, index + 5 ] : [ index + 4, index + 5, index + 3 ]);
normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round
extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d, d, d);
// the miter is now the normal for our next join
count += 4;
} else {
// next two points in our first segment
extrusions(attrPos, out, cur, _normal, 1);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
// now add the miter triangles
addNext(out, miter, miterLen * -flip);
attrPos.push(cur);
attrIndex.push([ index + 2, index + 4, index + 3 ]);
attrIndex.push([ index + 4, index + 5, index + 6 ]);
normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round
extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d, d, d, d);
// the miter is now the normal for our next join
count += 5;
}
_lastFlip = flip;
}
}
return {
normals: out,
attrIndex,
attrPos,
attrDistance
};
}

View File

@ -7,15 +7,16 @@
import { direction, normal, computeMiter } from 'polyline-miter-util';
import { create, copy, dot } from 'gl-vec2';
function extrusions(positions, out, point, normal, scale) {
addNext(out, normal, -scale);
addNext(out, normal, scale);
positions.push(point);
positions.push(point);
function extrusions(positions, out, miters, point, normal, scale) {
addNext(out, miters, normal, -scale);
addNext(out, miters, normal, scale);
positions.push(...point);
positions.push(...point);
}
function addNext(out, normal, length) {
out.push([[ normal[0], normal[1] ], length ]);
function addNext(out, miters, normal, length) {
out.push(normal[0], normal[1], 0);
miters.push(length);
}
function lineSegmentDistance(end, start) {
@ -40,6 +41,7 @@ export default function(points, closed, indexOffset) {
const out = [];
const attrPos = [];
const attrIndex = [];
const miters = [];
const attrDistance = [ 0, 0 ];
if (closed) {
points = points.slice();
@ -64,18 +66,18 @@ export default function(points, closed, indexOffset) {
if (!_started) {
_started = true;
extrusions(attrPos, out, last, _normal, 1);
extrusions(attrPos, out, miters, last, _normal, 1);
}
attrIndex.push([ index + 0, index + 2, index + 1 ]);
attrIndex.push(index + 0, index + 2, index + 1);
// no miter, simple segment
if (!next) {
// reset normal
normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrDistance.push(d, d);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
attrIndex.push(index + 1, index + 2, index + 3);
count += 2;
} else {
// get unit dir of next line
@ -93,15 +95,14 @@ export default function(points, closed, indexOffset) {
// 但是 AMap 投影变换后丢失精度只能通过一个阈值1000判断。
if (Math.abs(miterLen) > 1000) {
normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrDistance.push(d, d);
attrIndex.push(
_lastFlip === 1 ? [ index + 1, index + 3, index + 2 ]
: [ index, index + 2, index + 3 ]
);
const indexData = _lastFlip === 1 ? [ index + 1, index + 3, index + 2 ]
: [ index, index + 2, index + 3 ];
attrIndex.push(...indexData);
// 避免在 Material 中使用 THREE.DoubleSide
attrIndex.push([ index + 2, index + 3, index + 4 ]);
attrIndex.push(index + 2, index + 3, index + 4);
count += 2;
_lastFlip = -1;
@ -112,35 +113,35 @@ export default function(points, closed, indexOffset) {
miterLen = miterLimit;
// next two points in our first segment
extrusions(attrPos, out, cur, _normal, 1);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
attrIndex.push(index + 1, index + 2, index + 3);
// now add the bevel triangle
attrIndex.push(flip === 1 ? [ index + 2, index + 4, index + 5 ] : [ index + 4, index + 5, index + 3 ]);
attrIndex.push(...(flip === 1 ? [ index + 2, index + 4, index + 5 ] : [ index + 4, index + 5, index + 3 ]));
normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round
extrusions(attrPos, out, cur, _normal, 1);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrDistance.push(d, d, d, d);
// the miter is now the normal for our next join
count += 4;
} else {
// next two points in our first segment
extrusions(attrPos, out, cur, _normal, 1);
attrIndex.push([ index + 1, index + 2, index + 3 ]);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrIndex.push(index + 1, index + 2, index + 3);
// now add the miter triangles
addNext(out, miter, miterLen * -flip);
attrPos.push(cur);
attrIndex.push([ index + 2, index + 4, index + 3 ]);
attrIndex.push([ index + 4, index + 5, index + 6 ]);
addNext(out, miters, miter, miterLen * -flip);
attrPos.push(...cur);
attrIndex.push(index + 2, index + 4, index + 3);
attrIndex.push(index + 4, index + 5, index + 6);
normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round
extrusions(attrPos, out, cur, _normal, 1);
extrusions(attrPos, out, miters, cur, _normal, 1);
attrDistance.push(d, d, d, d, d);
// the miter is now the normal for our next join
@ -154,6 +155,7 @@ export default function(points, closed, indexOffset) {
normals: out,
attrIndex,
attrPos,
attrDistance
attrDistance,
miters
};
}

View File

@ -16,37 +16,33 @@ export default class WorkerTile {
const sourceLayerData = {};
// 数据源解析
for (const sourcelayer in sourceStyle) { // sourceLayer
const features = [];
const vectorLayer = data.layers[sourcelayer];
if (vectorLayer === undefined) {
return null;
}
for (let i = 0; i < vectorLayer.length; i++) {
const feature = vectorLayer.feature(i);
const geofeature = feature.toGeoJSON(tile[0], tile[1], tile[2]);
features.push(geofeature);
}
const geodata = {
type: 'FeatureCollection',
features
};
delete data.layers[sourcelayer];
const style = sourceStyle[sourcelayer][0];
style.sourceOption.parser.type = 'vector';
style.sourceOption.parser.tile = tile;
const tileSource2 = new Source({
...style.sourceOption,
mapType: style.mapType,
projected: true,
data: data.layers[sourcelayer]
});
for (let i = 0; i < sourceStyle[sourcelayer].length; i++) {
const style = sourceStyle[sourcelayer][i];
style.sourceOption.parser.type = 'geojson';
const tileSource = new Source({
...style.sourceOption,
mapType: style.mapType,
data: geodata
});
const tileMapping = new TileMapping(tileSource, style);
const tileMapping = new TileMapping(tileSource2, style);
const geometryBuffer = getBuffer(style.type, style.shape);
const buffer = new geometryBuffer({
layerData: tileMapping.layerData,
shape: style.shape
});
sourceLayerData[style.layerId] = {
attributes: buffer.attributes,
buffer: {
attributes: buffer.attributes,
indexArray: buffer.indexArray
},
// layerData: tileMapping.layerData,
// sourceData: tileSource.data,
layerId: style.layerId,

View File

@ -35,5 +35,4 @@ export default class WorkerPool {
}
}
WorkerPool.workerCount = 1;
// Math.max(Math.floor(window.navigator.hardwareConcurrency / 2), 1);
WorkerPool.workerCount = Math.max(Math.floor(window.navigator.hardwareConcurrency / 2), 1);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
import { expect } from 'chai';
import FillBuffer from '../../../../../src/geom/buffer/polygon/fill_buffer';
import { layerData } from '../../../../asset/data/layer_data';
describe('FillBuffer', () => {
it('fill buffer', () => {
console.time('buffer');
const fillBuffer = new FillBuffer({
layerData
});
console.timeEnd('buffer');
console.log(fillBuffer);
});
});