kopia lustrzana https://github.com/robhawkes/vizicities
Merge pull request #171 from UDST/feature/web-workers-polylines
Add polyline support to Web Worker layersfeature/threejs-update
commit
98f9e27f63
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>Web Workers All The Things ViziCities Example</title>
|
||||
<link rel="stylesheet" href="main.css">
|
||||
<link rel="stylesheet" href="../../dist/vizicities.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="world"></div>
|
||||
|
||||
<script src="../vendor/three.min.js"></script>
|
||||
<script src="../vendor/TweenMax.min.js"></script>
|
||||
<script src="../../dist/vizicities.min.js"></script>
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
* { margin: 0; padding: 0; }
|
||||
html, body { height: 100%; overflow: hidden;}
|
||||
|
||||
#world { height: 100%; }
|
|
@ -0,0 +1,78 @@
|
|||
// London
|
||||
var coords = [51.505, -0.09];
|
||||
|
||||
var world = VIZI.world('world', {
|
||||
skybox: true,
|
||||
postProcessing: true
|
||||
}).setView(coords);
|
||||
|
||||
// Set position of sun in sky
|
||||
world._environment._skybox.setInclination(0.3);
|
||||
|
||||
// Add controls
|
||||
VIZI.Controls.orbit().addTo(world);
|
||||
|
||||
// Leave a single CPU for the main browser thread
|
||||
world.createWorkers(7).then(() => {
|
||||
console.log('Workers ready');
|
||||
|
||||
// CartoDB basemap
|
||||
VIZI.imageTileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="http://cartodb.com/attributions">CartoDB</a>'
|
||||
}).addTo(world);
|
||||
|
||||
// Buildings and roads from Mapzen (polygons and linestrings)
|
||||
var topoJSONTileLayer = VIZI.topoJSONTileLayer('https://vector.mapzen.com/osm/buildings,roads/{z}/{x}/{y}.topojson?api_key=vector-tiles-NT5Emiw', {
|
||||
workers: true,
|
||||
interactive: false,
|
||||
style: function(feature) {
|
||||
var height;
|
||||
|
||||
if (feature.properties.height) {
|
||||
height = feature.properties.height;
|
||||
} else {
|
||||
height = 10 + Math.random() * 10;
|
||||
}
|
||||
|
||||
return {
|
||||
height: height,
|
||||
lineColor: '#f7c616',
|
||||
lineWidth: 1,
|
||||
lineTransparent: true,
|
||||
lineOpacity: 0.2,
|
||||
lineBlending: THREE.AdditiveBlending,
|
||||
lineRenderOrder: 2
|
||||
};
|
||||
},
|
||||
filter: function(feature) {
|
||||
// Don't show points
|
||||
return feature.geometry.type !== 'Point';
|
||||
},
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://whosonfirst.mapzen.com#License">Who\'s On First</a>.'
|
||||
}).addTo(world);
|
||||
|
||||
// London Underground lines
|
||||
VIZI.geoJSONWorkerLayer('https://rawgit.com/robhawkes/4acb9d6a6a5f00a377e2/raw/30ae704a44e10f2e13fb7e956e80c3b22e8e7e81/tfl_lines.json', {
|
||||
output: true,
|
||||
interactive: true,
|
||||
style: function(feature) {
|
||||
var colour = feature.properties.lines[0].colour || '#ffffff';
|
||||
|
||||
return {
|
||||
lineColor: colour,
|
||||
lineHeight: 20,
|
||||
lineWidth: 3,
|
||||
lineTransparent: true,
|
||||
lineOpacity: 0.5,
|
||||
lineBlending: THREE.AdditiveBlending,
|
||||
lineRenderOrder: 2
|
||||
};
|
||||
},
|
||||
// onEachFeature: function(feature, layer) {
|
||||
// layer.on('click', function(layer, point2d, point3d, intersects) {
|
||||
// console.log(layer, point2d, point3d, intersects);
|
||||
// });
|
||||
// },
|
||||
attribution: '© Transport for London.'
|
||||
}).addTo(world);
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
importScripts('../vendor/three.min.js');
|
||||
|
||||
// Special version of ViziCities without controls (no DOM errors)
|
||||
importScripts('../../dist/vizicities-worker.min.js');
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
if (DEBUG) { console.log('Worker started', performance.now()); }
|
||||
|
||||
// Send startup message to main thread
|
||||
postMessage({
|
||||
type: 'startup',
|
||||
payload: performance.now()
|
||||
});
|
||||
|
||||
// Recieve message from main thread
|
||||
onmessage = (event) => {
|
||||
if (!event.data.method) {
|
||||
postMessage({
|
||||
type: 'error',
|
||||
payload: 'No method provided'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var time = performance.now();
|
||||
if (DEBUG) { console.log('Message received from main thread', time, event.data); }
|
||||
// if (DEBUG) console.log('Time to receive message', time - event.data);
|
||||
|
||||
// Run method
|
||||
// if (!methods[event.data.method]) {
|
||||
// postMessage({
|
||||
// type: 'error',
|
||||
// payload: 'Method not found'
|
||||
// });
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
var methods = event.data.method.split('.');
|
||||
|
||||
var _method = VIZI[methods[0]];
|
||||
|
||||
if (methods.length > 1) {
|
||||
for (var i = 1; i < methods.length; i++) {
|
||||
_method = _method[methods[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Call method with given arguments
|
||||
_method.apply(this, event.data.args).then((result) => {
|
||||
console.log('Message sent from worker', performance.now());
|
||||
|
||||
// Return results
|
||||
postMessage({
|
||||
type: 'result',
|
||||
payload: result.data
|
||||
}, result.transferrables);
|
||||
});
|
||||
};
|
|
@ -178,6 +178,12 @@ class GeoJSONLayer extends LayerGroup {
|
|||
var polygonFlat = true;
|
||||
|
||||
var polylineAttributes = [];
|
||||
var polylineAttributeLengths = {
|
||||
positions: 3,
|
||||
colors: 3
|
||||
};
|
||||
var polylineFlat = true;
|
||||
|
||||
var pointAttributes = [];
|
||||
|
||||
this._layers.forEach(layer => {
|
||||
|
@ -193,6 +199,14 @@ class GeoJSONLayer extends LayerGroup {
|
|||
}
|
||||
} else if (layer instanceof PolylineLayer) {
|
||||
polylineAttributes.push(layer.getBufferAttributes());
|
||||
|
||||
if (polylineFlat && !layer.isFlat()) {
|
||||
polylineFlat = false;
|
||||
}
|
||||
|
||||
if (this._options.interactive) {
|
||||
polylineAttributeLengths.pickingIds = 1;
|
||||
}
|
||||
} else if (layer instanceof PointLayer) {
|
||||
pointAttributes.push(layer.getBufferAttributes());
|
||||
}
|
||||
|
@ -205,15 +219,21 @@ class GeoJSONLayer extends LayerGroup {
|
|||
this.add(this._polygonMesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (polylineAttributes.length > 0) {
|
||||
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
|
||||
this._setPolylineMesh(mergedPolylineAttributes);
|
||||
this.add(this._polylineMesh);
|
||||
this._setPolylineMesh(mergedPolylineAttributes, polylineAttributeLengths, polylineFlat).then((result) => {
|
||||
this._polylineMesh = result.mesh;
|
||||
this.add(this._polylineMesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pointAttributes.length > 0) {
|
||||
|
@ -247,72 +267,12 @@ class GeoJSONLayer extends LayerGroup {
|
|||
return PolygonLayer.SetMesh(attributes, attributeLengths, flat, style, this._options, this._world._environment._skybox);
|
||||
}
|
||||
|
||||
_setPolylineMesh(attributes) {
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
|
||||
// itemSize = 3 because there are 3 values (components) per vertex
|
||||
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
|
||||
|
||||
if (attributes.normals) {
|
||||
geometry.addAttribute('normal', new THREE.BufferAttribute(attributes.normals, 3));
|
||||
}
|
||||
|
||||
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
|
||||
|
||||
if (attributes.pickingIds) {
|
||||
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
|
||||
}
|
||||
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
_setPolylineMesh(attributes, attributeLengths, flat) {
|
||||
// TODO: Make this work when style is a function per feature
|
||||
var style = (typeof this._options.style === 'function') ? this._options.style(this._geojson.features[0]) : this._options.style;
|
||||
style = extend({}, GeoJSON.defaultStyle, style);
|
||||
|
||||
var material;
|
||||
if (this._options.polylineMaterial && this._options.polylineMaterial instanceof THREE.Material) {
|
||||
material = this._options.polylineMaterial;
|
||||
} else {
|
||||
material = new THREE.LineBasicMaterial({
|
||||
vertexColors: THREE.VertexColors,
|
||||
linewidth: style.lineWidth,
|
||||
transparent: style.lineTransparent,
|
||||
opacity: style.lineOpacity,
|
||||
blending: style.lineBlending
|
||||
});
|
||||
}
|
||||
|
||||
var mesh;
|
||||
|
||||
// Pass mesh through callback, if defined
|
||||
if (typeof this._options.onPolylineMesh === 'function') {
|
||||
mesh = this._options.onPolylineMesh(geometry, material);
|
||||
} else {
|
||||
mesh = new THREE.LineSegments(geometry, material);
|
||||
|
||||
if (style.lineRenderOrder !== undefined) {
|
||||
material.depthWrite = false;
|
||||
mesh.renderOrder = style.lineRenderOrder;
|
||||
}
|
||||
|
||||
mesh.castShadow = true;
|
||||
// mesh.receiveShadow = true;
|
||||
}
|
||||
|
||||
// TODO: Allow this to be overridden, or copy mesh instead of creating a new
|
||||
// one just for picking
|
||||
if (this._options.interactive && this._pickingMesh) {
|
||||
material = new PickingMaterial();
|
||||
// material.side = THREE.BackSide;
|
||||
|
||||
// Make the line wider / easier to pick
|
||||
material.linewidth = style.lineWidth + material.linePadding;
|
||||
|
||||
var pickingMesh = new THREE.LineSegments(geometry, material);
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
}
|
||||
|
||||
this._polylineMesh = mesh;
|
||||
return PolylineLayer.SetMesh(attributes, attributeLengths, flat, style, this._options);
|
||||
}
|
||||
|
||||
_setPointMesh(attributes) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import Worker from '../util/Worker';
|
|||
import Buffer from '../util/Buffer';
|
||||
import Stringify from '../util/Stringify';
|
||||
import PolygonLayer from './geometry/PolygonLayer';
|
||||
import PolylineLayer from './geometry/PolylineLayer';
|
||||
import {latLon as LatLon} from '../geo/LatLon';
|
||||
import {point as Point} from '../geo/Point';
|
||||
import Geo from '../geo/Geo';
|
||||
|
@ -97,107 +98,12 @@ class GeoJSONWorkerLayer extends Layer {
|
|||
Worker.exec('GeoJSONWorkerLayer.Process', [geojson, topojson, headers, originPoint, style, interactive], transferrables).then((results) => {
|
||||
console.timeEnd('Worker round trip');
|
||||
|
||||
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
|
||||
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
|
||||
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
|
||||
|
||||
var splitProperties;
|
||||
if (results.properties) {
|
||||
splitProperties = Buffer.splitUint8Array(results.properties);
|
||||
if (results.polygons) {
|
||||
this._processPolygonResults(results.polygons);
|
||||
}
|
||||
|
||||
var flats = results.flats;
|
||||
|
||||
var objects = [];
|
||||
var obj;
|
||||
var pickingId;
|
||||
var pickingIds;
|
||||
var properties;
|
||||
|
||||
var polygonAttributeLengths = {
|
||||
positions: 3,
|
||||
normals: 3,
|
||||
colors: 3
|
||||
};
|
||||
|
||||
for (var i = 0; i < splitPositions.length; i++) {
|
||||
if (splitProperties && splitProperties[i]) {
|
||||
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
|
||||
} else {
|
||||
properties = {};
|
||||
}
|
||||
|
||||
// WORKERS: obj.attributes should actually an array of polygons for
|
||||
// the feature, though the current logic isn't aware of that
|
||||
obj = {
|
||||
attributes: [{
|
||||
positions: splitPositions[i],
|
||||
normals: splitNormals[i],
|
||||
colors: splitColors[i]
|
||||
}],
|
||||
properties: properties,
|
||||
flat: flats[i]
|
||||
};
|
||||
|
||||
// WORKERS: If interactive, generate unique ID for each feature, create
|
||||
// the buffer attributes and set up event listeners
|
||||
if (this._options.interactive) {
|
||||
pickingId = this.getPickingId();
|
||||
|
||||
pickingIds = new Float32Array(splitPositions[i].length / 3);
|
||||
pickingIds.fill(pickingId);
|
||||
|
||||
obj.attributes[0].pickingIds = pickingIds;
|
||||
|
||||
polygonAttributeLengths.pickingIds = 1;
|
||||
|
||||
this._addPicking(pickingId, properties);
|
||||
}
|
||||
|
||||
if (typeof this._options.onAddAttributes === 'function') {
|
||||
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
|
||||
var customAttribute;
|
||||
for (var key in customAttributes) {
|
||||
customAttribute = customAttributes[key];
|
||||
obj.attributes[0][key] = customAttribute.value;
|
||||
polygonAttributeLengths[key] = customAttribute.length;
|
||||
}
|
||||
}
|
||||
|
||||
objects.push(obj);
|
||||
}
|
||||
|
||||
var polygonAttributes = [];
|
||||
|
||||
var polygonFlat = true;
|
||||
|
||||
var obj;
|
||||
for (var i = 0; i < objects.length; i++) {
|
||||
obj = objects[i];
|
||||
|
||||
if (polygonFlat && !obj.flat) {
|
||||
polygonFlat = false;
|
||||
}
|
||||
|
||||
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
|
||||
polygonAttributes.push(bufferAttributes);
|
||||
};
|
||||
|
||||
if (polygonAttributes.length > 0) {
|
||||
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
|
||||
|
||||
// TODO: Make this work when style is a function per feature
|
||||
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
|
||||
style = extend({}, GeoJSON.defaultStyle, style);
|
||||
|
||||
this._setPolygonMesh(mergedPolygonAttributes, polygonAttributeLengths, style, polygonFlat).then((result) => {
|
||||
this._polygonMesh = result.mesh;
|
||||
this.add(this._polygonMesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
}
|
||||
});
|
||||
if (results.polylines) {
|
||||
this._processPolylineResults(results.polylines);
|
||||
}
|
||||
|
||||
resolve();
|
||||
|
@ -205,6 +111,217 @@ class GeoJSONWorkerLayer extends Layer {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: Dedupe with polyline method
|
||||
_processPolygonResults(results) {
|
||||
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
|
||||
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
|
||||
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
|
||||
|
||||
var splitProperties;
|
||||
if (results.properties) {
|
||||
splitProperties = Buffer.splitUint8Array(results.properties);
|
||||
}
|
||||
|
||||
var flats = results.flats;
|
||||
|
||||
var objects = [];
|
||||
var obj;
|
||||
var pickingId;
|
||||
var pickingIds;
|
||||
var properties;
|
||||
|
||||
var polygonAttributeLengths = {
|
||||
positions: 3,
|
||||
normals: 3,
|
||||
colors: 3
|
||||
};
|
||||
|
||||
for (var i = 0; i < splitPositions.length; i++) {
|
||||
if (splitProperties && splitProperties[i]) {
|
||||
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
|
||||
} else {
|
||||
properties = {};
|
||||
}
|
||||
|
||||
// WORKERS: obj.attributes should actually an array of polygons for
|
||||
// the feature, though the current logic isn't aware of that
|
||||
obj = {
|
||||
attributes: [{
|
||||
positions: splitPositions[i],
|
||||
normals: splitNormals[i],
|
||||
colors: splitColors[i]
|
||||
}],
|
||||
properties: properties,
|
||||
flat: flats[i]
|
||||
};
|
||||
|
||||
// WORKERS: If interactive, generate unique ID for each feature, create
|
||||
// the buffer attributes and set up event listeners
|
||||
if (this._options.interactive) {
|
||||
pickingId = this.getPickingId();
|
||||
|
||||
pickingIds = new Float32Array(splitPositions[i].length / 3);
|
||||
pickingIds.fill(pickingId);
|
||||
|
||||
obj.attributes[0].pickingIds = pickingIds;
|
||||
|
||||
polygonAttributeLengths.pickingIds = 1;
|
||||
|
||||
this._addPicking(pickingId, properties);
|
||||
}
|
||||
|
||||
// TODO: Make this specific to polygon attributes
|
||||
if (typeof this._options.onAddAttributes === 'function') {
|
||||
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
|
||||
var customAttribute;
|
||||
for (var key in customAttributes) {
|
||||
customAttribute = customAttributes[key];
|
||||
obj.attributes[0][key] = customAttribute.value;
|
||||
polygonAttributeLengths[key] = customAttribute.length;
|
||||
}
|
||||
}
|
||||
|
||||
objects.push(obj);
|
||||
}
|
||||
|
||||
var polygonAttributes = [];
|
||||
|
||||
var polygonFlat = true;
|
||||
|
||||
var obj;
|
||||
for (var i = 0; i < objects.length; i++) {
|
||||
obj = objects[i];
|
||||
|
||||
if (polygonFlat && !obj.flat) {
|
||||
polygonFlat = false;
|
||||
}
|
||||
|
||||
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
|
||||
polygonAttributes.push(bufferAttributes);
|
||||
};
|
||||
|
||||
if (polygonAttributes.length > 0) {
|
||||
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
|
||||
|
||||
// TODO: Make this work when style is a function per feature
|
||||
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
|
||||
style = extend({}, GeoJSON.defaultStyle, style);
|
||||
|
||||
this._setPolygonMesh(mergedPolygonAttributes, polygonAttributeLengths, style, polygonFlat).then((result) => {
|
||||
this._polygonMesh = result.mesh;
|
||||
this.add(this._polygonMesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Dedupe with polygon method
|
||||
_processPolylineResults(results) {
|
||||
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
|
||||
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
|
||||
|
||||
var splitProperties;
|
||||
if (results.properties) {
|
||||
splitProperties = Buffer.splitUint8Array(results.properties);
|
||||
}
|
||||
|
||||
var flats = results.flats;
|
||||
|
||||
var objects = [];
|
||||
var obj;
|
||||
var pickingId;
|
||||
var pickingIds;
|
||||
var properties;
|
||||
|
||||
var polylineAttributeLengths = {
|
||||
positions: 3,
|
||||
colors: 3
|
||||
};
|
||||
|
||||
for (var i = 0; i < splitPositions.length; i++) {
|
||||
if (splitProperties && splitProperties[i]) {
|
||||
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
|
||||
} else {
|
||||
properties = {};
|
||||
}
|
||||
|
||||
// WORKERS: obj.attributes should actually an array of polygons for
|
||||
// the feature, though the current logic isn't aware of that
|
||||
obj = {
|
||||
attributes: [{
|
||||
positions: splitPositions[i],
|
||||
colors: splitColors[i]
|
||||
}],
|
||||
properties: properties,
|
||||
flat: flats[i]
|
||||
};
|
||||
|
||||
// WORKERS: If interactive, generate unique ID for each feature, create
|
||||
// the buffer attributes and set up event listeners
|
||||
if (this._options.interactive) {
|
||||
pickingId = this.getPickingId();
|
||||
|
||||
pickingIds = new Float32Array(splitPositions[i].length / 3);
|
||||
pickingIds.fill(pickingId);
|
||||
|
||||
obj.attributes[0].pickingIds = pickingIds;
|
||||
|
||||
polylineAttributeLengths.pickingIds = 1;
|
||||
|
||||
this._addPicking(pickingId, properties);
|
||||
}
|
||||
|
||||
// TODO: Make this specific to polyline attributes
|
||||
if (typeof this._options.onAddAttributes === 'function') {
|
||||
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
|
||||
var customAttribute;
|
||||
for (var key in customAttributes) {
|
||||
customAttribute = customAttributes[key];
|
||||
obj.attributes[0][key] = customAttribute.value;
|
||||
polylineAttributeLengths[key] = customAttribute.length;
|
||||
}
|
||||
}
|
||||
|
||||
objects.push(obj);
|
||||
}
|
||||
|
||||
var polylineAttributes = [];
|
||||
|
||||
var polylineFlat = true;
|
||||
|
||||
var obj;
|
||||
for (var i = 0; i < objects.length; i++) {
|
||||
obj = objects[i];
|
||||
|
||||
if (polylineFlat && !obj.flat) {
|
||||
polylineFlat = false;
|
||||
}
|
||||
|
||||
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
|
||||
polylineAttributes.push(bufferAttributes);
|
||||
};
|
||||
|
||||
if (polylineAttributes.length > 0) {
|
||||
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
|
||||
|
||||
// TODO: Make this work when style is a function per feature
|
||||
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
|
||||
style = extend({}, GeoJSON.defaultStyle, style);
|
||||
|
||||
this._setPolylineMesh(mergedPolylineAttributes, polylineAttributeLengths, style, polylineFlat).then((result) => {
|
||||
this._polylineMesh = result.mesh;
|
||||
this.add(this._polylineMesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: At some point this needs to return all the features to the main thread
|
||||
// so it can generate meshes and output to the scene, as well as perhaps creating
|
||||
// individual layers / components for each feature to track things like picking
|
||||
|
@ -228,6 +345,7 @@ class GeoJSONWorkerLayer extends Layer {
|
|||
|
||||
var pointScale;
|
||||
var polygons = [];
|
||||
var polylines = [];
|
||||
|
||||
// Deserialise style function if provided
|
||||
if (typeof _style === 'string') {
|
||||
|
@ -295,105 +413,248 @@ class GeoJSONWorkerLayer extends Layer {
|
|||
polygons.push(polygon);
|
||||
}
|
||||
|
||||
if (geometry.type === 'LineString' || geometry.type === 'MultiLineString') {}
|
||||
if (geometry.type === 'LineString' || geometry.type === 'MultiLineString') {
|
||||
coordinates = (PolylineLayer.isSingle(coordinates)) ? [coordinates] : coordinates;
|
||||
|
||||
var converted = coordinates.map(_coordinates => {
|
||||
return _coordinates.map(coordinate => {
|
||||
return LatLon(coordinate[1], coordinate[0]);
|
||||
});
|
||||
});
|
||||
|
||||
var point;
|
||||
var projected = converted.map((_coordinates) => {
|
||||
return _coordinates.map((latlon) => {
|
||||
point = Geo.latLonToPoint(latlon)._subtract(originPoint);
|
||||
|
||||
if (!pointScale) {
|
||||
pointScale = Geo.pointScale(latlon);
|
||||
}
|
||||
|
||||
return point;
|
||||
});
|
||||
});
|
||||
|
||||
var polyline = {
|
||||
projected: projected,
|
||||
options: {
|
||||
pointScale: pointScale,
|
||||
style: style
|
||||
}
|
||||
};
|
||||
|
||||
if (_properties) {
|
||||
polyline.properties = feature.properties;
|
||||
}
|
||||
|
||||
polylines.push(polyline);
|
||||
}
|
||||
|
||||
if (geometry.type === 'Point' || geometry.type === 'MultiPoint') {}
|
||||
};
|
||||
|
||||
var bufferPromises = [];
|
||||
var polygonBufferPromises = [];
|
||||
var polylineBufferPromises = [];
|
||||
|
||||
var polygon;
|
||||
for (var i = 0; i < polygons.length; i++) {
|
||||
polygon = polygons[i];
|
||||
bufferPromises.push(PolygonLayer.SetBufferAttributes(polygon.projected, polygon.options));
|
||||
polygonBufferPromises.push(PolygonLayer.SetBufferAttributes(polygon.projected, polygon.options));
|
||||
};
|
||||
|
||||
Promise.all(bufferPromises).then((results) => {
|
||||
var transferrables = [];
|
||||
var transferrablesSize = 0;
|
||||
var polyline;
|
||||
for (var i = 0; i < polylines.length; i++) {
|
||||
polyline = polylines[i];
|
||||
polylineBufferPromises.push(PolylineLayer.SetBufferAttributes(polyline.projected, polyline.options));
|
||||
};
|
||||
|
||||
var positions = [];
|
||||
var normals = [];
|
||||
var colors = [];
|
||||
// var pickingIds = [];
|
||||
var data = {};
|
||||
var transferrables = [];
|
||||
|
||||
var properties = [];
|
||||
// TODO: Make this work with polylines too
|
||||
// TODO: Make this so it's not a nest of promises
|
||||
GeoJSONWorkerLayer.ProcessPolygons(polygonBufferPromises, polygons, _properties).then((result) => {
|
||||
data.polygons = result.data;
|
||||
transferrables = transferrables.concat(result.transferrables);
|
||||
|
||||
var flats = [];
|
||||
var polygon;
|
||||
GeoJSONWorkerLayer.ProcessPolylines(polylineBufferPromises, polylines, _properties).then((result) => {
|
||||
data.polylines = result.data;
|
||||
transferrables = transferrables.concat(result.transferrables);
|
||||
|
||||
var result;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
result = results[i];
|
||||
|
||||
polygon = polygons[i];
|
||||
|
||||
// WORKERS: Making this a typed array will speed up transfer time
|
||||
// As things stand this adds on a few milliseconds
|
||||
flats.push(result.flat);
|
||||
|
||||
// WORKERS: result.attributes is actually an array of polygons for each
|
||||
// feature, though the current logic isn't keeping these all together
|
||||
|
||||
var attributes;
|
||||
for (var j = 0; j < result.attributes.length; j++) {
|
||||
attributes = result.attributes[j];
|
||||
|
||||
positions.push(attributes.positions);
|
||||
normals.push(attributes.normals);
|
||||
colors.push(attributes.colors);
|
||||
|
||||
if (_properties) {
|
||||
properties.push(Buffer.stringToUint8Array(JSON.stringify(polygon.properties)));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var mergedAttributes = {
|
||||
positions: Buffer.mergeFloat32Arrays(positions),
|
||||
normals: Buffer.mergeFloat32Arrays(normals),
|
||||
colors: Buffer.mergeFloat32Arrays(colors)
|
||||
};
|
||||
|
||||
transferrables.push(mergedAttributes.positions[0].buffer);
|
||||
transferrables.push(mergedAttributes.positions[1].buffer);
|
||||
|
||||
transferrables.push(mergedAttributes.normals[0].buffer);
|
||||
transferrables.push(mergedAttributes.normals[1].buffer);
|
||||
|
||||
transferrables.push(mergedAttributes.colors[0].buffer);
|
||||
transferrables.push(mergedAttributes.colors[1].buffer);
|
||||
|
||||
var mergedProperties;
|
||||
if (_properties) {
|
||||
mergedProperties = Buffer.mergeUint8Arrays(properties);
|
||||
|
||||
transferrables.push(mergedProperties[0].buffer);
|
||||
transferrables.push(mergedProperties[1].buffer);
|
||||
}
|
||||
|
||||
var output = {
|
||||
attributes: mergedAttributes,
|
||||
flats: flats
|
||||
};
|
||||
|
||||
if (_properties) {
|
||||
output.properties = mergedProperties;
|
||||
}
|
||||
|
||||
// TODO: Also return GeoJSON features that can be mapped to objects on
|
||||
// the main thread. Allow user to provide filter / toggles to only return
|
||||
// properties from the GeoJSON that they need (eg. don't return geometry,
|
||||
// or don't return properties.height)
|
||||
resolve({
|
||||
data: output,
|
||||
transferrables: transferrables
|
||||
resolve({
|
||||
data: data,
|
||||
transferrables: transferrables
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static ProcessPolygons(polygonPromises, polygons, _properties) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Promise.all(polygonPromises).then((results) => {
|
||||
var transferrables = [];
|
||||
|
||||
var positions = [];
|
||||
var normals = [];
|
||||
var colors = [];
|
||||
|
||||
var properties = [];
|
||||
|
||||
var flats = [];
|
||||
var polygon;
|
||||
|
||||
var result;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
result = results[i];
|
||||
|
||||
polygon = polygons[i];
|
||||
|
||||
// WORKERS: Making this a typed array will speed up transfer time
|
||||
// As things stand this adds on a few milliseconds
|
||||
flats.push(result.flat);
|
||||
|
||||
// WORKERS: result.attributes is actually an array of polygons for each
|
||||
// feature, though the current logic isn't keeping these all together
|
||||
|
||||
var attributes;
|
||||
for (var j = 0; j < result.attributes.length; j++) {
|
||||
attributes = result.attributes[j];
|
||||
|
||||
positions.push(attributes.positions);
|
||||
normals.push(attributes.normals);
|
||||
colors.push(attributes.colors);
|
||||
|
||||
if (_properties) {
|
||||
properties.push(Buffer.stringToUint8Array(JSON.stringify(polygon.properties)));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var mergedAttributes = {
|
||||
positions: Buffer.mergeFloat32Arrays(positions),
|
||||
normals: Buffer.mergeFloat32Arrays(normals),
|
||||
colors: Buffer.mergeFloat32Arrays(colors)
|
||||
};
|
||||
|
||||
transferrables.push(mergedAttributes.positions[0].buffer);
|
||||
transferrables.push(mergedAttributes.positions[1].buffer);
|
||||
|
||||
transferrables.push(mergedAttributes.normals[0].buffer);
|
||||
transferrables.push(mergedAttributes.normals[1].buffer);
|
||||
|
||||
transferrables.push(mergedAttributes.colors[0].buffer);
|
||||
transferrables.push(mergedAttributes.colors[1].buffer);
|
||||
|
||||
var mergedProperties;
|
||||
if (_properties) {
|
||||
mergedProperties = Buffer.mergeUint8Arrays(properties);
|
||||
|
||||
transferrables.push(mergedProperties[0].buffer);
|
||||
transferrables.push(mergedProperties[1].buffer);
|
||||
}
|
||||
|
||||
var output = {
|
||||
attributes: mergedAttributes,
|
||||
flats: flats
|
||||
};
|
||||
|
||||
if (_properties) {
|
||||
output.properties = mergedProperties;
|
||||
}
|
||||
|
||||
// TODO: Also return GeoJSON features that can be mapped to objects on
|
||||
// the main thread. Allow user to provide filter / toggles to only return
|
||||
// properties from the GeoJSON that they need (eg. don't return geometry,
|
||||
// or don't return properties.height)
|
||||
resolve({
|
||||
data: output,
|
||||
transferrables: transferrables
|
||||
});
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
static ProcessPolylines(polylinePromises, polylines, _properties) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Promise.all(polylinePromises).then((results) => {
|
||||
var transferrables = [];
|
||||
|
||||
var positions = [];
|
||||
var colors = [];
|
||||
|
||||
var properties = [];
|
||||
|
||||
var flats = [];
|
||||
var polyline;
|
||||
|
||||
var result;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
result = results[i];
|
||||
|
||||
polyline = polylines[i];
|
||||
|
||||
// WORKERS: Making this a typed array will speed up transfer time
|
||||
// As things stand this adds on a few milliseconds
|
||||
flats.push(result.flat);
|
||||
|
||||
// WORKERS: result.attributes is actually an array of polygons for each
|
||||
// feature, though the current logic isn't keeping these all together
|
||||
|
||||
var attributes;
|
||||
for (var j = 0; j < result.attributes.length; j++) {
|
||||
attributes = result.attributes[j];
|
||||
|
||||
positions.push(attributes.positions);
|
||||
colors.push(attributes.colors);
|
||||
|
||||
if (_properties) {
|
||||
properties.push(Buffer.stringToUint8Array(JSON.stringify(polyline.properties)));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var mergedAttributes = {
|
||||
positions: Buffer.mergeFloat32Arrays(positions),
|
||||
colors: Buffer.mergeFloat32Arrays(colors)
|
||||
};
|
||||
|
||||
transferrables.push(mergedAttributes.positions[0].buffer);
|
||||
transferrables.push(mergedAttributes.positions[1].buffer);
|
||||
|
||||
transferrables.push(mergedAttributes.colors[0].buffer);
|
||||
transferrables.push(mergedAttributes.colors[1].buffer);
|
||||
|
||||
var mergedProperties;
|
||||
if (_properties) {
|
||||
mergedProperties = Buffer.mergeUint8Arrays(properties);
|
||||
|
||||
transferrables.push(mergedProperties[0].buffer);
|
||||
transferrables.push(mergedProperties[1].buffer);
|
||||
}
|
||||
|
||||
var output = {
|
||||
attributes: mergedAttributes,
|
||||
flats: flats
|
||||
};
|
||||
|
||||
if (_properties) {
|
||||
output.properties = mergedProperties;
|
||||
}
|
||||
|
||||
// TODO: Also return GeoJSON features that can be mapped to objects on
|
||||
// the main thread. Allow user to provide filter / toggles to only return
|
||||
// properties from the GeoJSON that they need (eg. don't return geometry,
|
||||
// or don't return properties.height)
|
||||
resolve({
|
||||
data: output,
|
||||
transferrables: transferrables
|
||||
});
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
static ProcessGeoJSON(geojson, headers) {
|
||||
if (typeof geojson === 'string') {
|
||||
return GeoJSONWorkerLayer.RequestGeoJSON(geojson, headers);
|
||||
|
@ -418,6 +679,10 @@ class GeoJSONWorkerLayer extends Layer {
|
|||
return PolygonLayer.SetMesh(attributes, attributeLengths, flat, style, this._options, this._world._environment._skybox);
|
||||
}
|
||||
|
||||
_setPolylineMesh(attributes, attributeLengths, style, flat) {
|
||||
return PolylineLayer.SetMesh(attributes, attributeLengths, flat, style, this._options);
|
||||
}
|
||||
|
||||
// Set up and re-emit interaction events
|
||||
_addPicking(pickingId, properties) {
|
||||
this._world.on('pick-click-' + pickingId, (pickingId, point2d, point3d, intersects) => {
|
||||
|
|
|
@ -33,8 +33,8 @@ class PolygonLayer extends Layer {
|
|||
// Custom material override
|
||||
//
|
||||
// TODO: Should this be in the style object?
|
||||
material: null,
|
||||
onMesh: null,
|
||||
polygonMaterial: null,
|
||||
onPolygonMesh: null,
|
||||
onBufferAttributes: null,
|
||||
// This default style is separate to Util.GeoJSON.defaultStyle
|
||||
style: {
|
||||
|
@ -97,7 +97,7 @@ class PolygonLayer extends Layer {
|
|||
this.add(result.mesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ class PolygonLayer extends Layer {
|
|||
this._offset.x = -1 * point.x;
|
||||
this._offset.y = -1 * point.y;
|
||||
|
||||
this._pointScale = this._world.pointScale(latlon);
|
||||
this._options.pointScale = this._world.pointScale(latlon);
|
||||
}
|
||||
|
||||
return point;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
import Layer from '../Layer';
|
||||
import extend from 'lodash.assign';
|
||||
import THREE from 'three';
|
||||
import Geo from '../../geo/Geo';
|
||||
import {latLon as LatLon} from '../../geo/LatLon';
|
||||
import {point as Point} from '../../geo/Point';
|
||||
import PickingMaterial from '../../engine/PickingMaterial';
|
||||
|
@ -32,8 +33,8 @@ class PolylineLayer extends Layer {
|
|||
// Custom material override
|
||||
//
|
||||
// TODO: Should this be in the style object?
|
||||
material: null,
|
||||
onMesh: null,
|
||||
polylineMaterial: null,
|
||||
onPolylineMesh: null,
|
||||
onBufferAttributes: null,
|
||||
// This default style is separate to Util.GeoJSON.defaultStyle
|
||||
style: {
|
||||
|
@ -59,34 +60,57 @@ class PolylineLayer extends Layer {
|
|||
}
|
||||
|
||||
_onAdd(world) {
|
||||
this._setCoordinates();
|
||||
return new Promise((resolve, reject) => {
|
||||
this._setCoordinates();
|
||||
|
||||
if (this._options.interactive) {
|
||||
// Only add to picking mesh if this layer is controlling output
|
||||
//
|
||||
// Otherwise, assume another component will eventually add a mesh to
|
||||
// the picking scene
|
||||
if (this.isOutput()) {
|
||||
this._pickingMesh = new THREE.Object3D();
|
||||
this.addToPicking(this._pickingMesh);
|
||||
if (this._options.interactive) {
|
||||
// Only add to picking mesh if this layer is controlling output
|
||||
//
|
||||
// Otherwise, assume another component will eventually add a mesh to
|
||||
// the picking scene
|
||||
if (this.isOutput()) {
|
||||
this._pickingMesh = new THREE.Object3D();
|
||||
this.addToPicking(this._pickingMesh);
|
||||
}
|
||||
|
||||
this._setPickingId();
|
||||
this._addPickingEvents();
|
||||
}
|
||||
|
||||
this._setPickingId();
|
||||
this._addPickingEvents();
|
||||
}
|
||||
// Store geometry representation as instances of THREE.BufferAttribute
|
||||
PolylineLayer.SetBufferAttributes(this._projectedCoordinates, this._options).then((result) => {
|
||||
this._bufferAttributes = Buffer.mergeAttributes(result.attributes);
|
||||
this._flat = result.flat;
|
||||
|
||||
// Store geometry representation as instances of THREE.BufferAttribute
|
||||
this._setBufferAttributes();
|
||||
var attributeLengths = {
|
||||
positions: 3,
|
||||
colors: 3
|
||||
};
|
||||
|
||||
if (this.isOutput()) {
|
||||
// Set mesh if not merging elsewhere
|
||||
this._setMesh(this._bufferAttributes);
|
||||
if (this._options.interactive) {
|
||||
attributeLengths.pickingIds = 1;
|
||||
}
|
||||
|
||||
// Output mesh
|
||||
this.add(this._mesh);
|
||||
}
|
||||
if (this.isOutput()) {
|
||||
var style = this._options.style;
|
||||
|
||||
return Promise.resolve(this);
|
||||
// Set mesh if not merging elsewhere
|
||||
PolylineLayer.SetMesh(this._bufferAttributes, attributeLengths, this._flat, style, this._options).then((result) => {
|
||||
// Output mesh
|
||||
this.add(result.mesh);
|
||||
|
||||
if (result.pickingMesh) {
|
||||
this._pickingMesh.add(result.pickingMesh);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
result.attributes = null;
|
||||
result = null;
|
||||
|
||||
resolve(this);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Return center of polyline as a LatLon
|
||||
|
@ -118,28 +142,22 @@ class PolylineLayer extends Layer {
|
|||
});
|
||||
}
|
||||
|
||||
// Create and store reference to THREE.BufferAttribute data for this layer
|
||||
_setBufferAttributes() {
|
||||
var attributes;
|
||||
|
||||
// Only use this if you know what you're doing
|
||||
if (typeof this._options.onBufferAttributes === 'function') {
|
||||
// TODO: Probably want to pass something less general as arguments,
|
||||
// though passing the instance will do for now (it's everything)
|
||||
attributes = this._options.onBufferAttributes(this);
|
||||
} else {
|
||||
static SetBufferAttributes(coordinates, options) {
|
||||
return new Promise((resolve) => {
|
||||
var height = 0;
|
||||
|
||||
// Convert height into world units
|
||||
if (this._options.style.lineHeight) {
|
||||
height = this._world.metresToWorld(this._options.style.lineHeight, this._pointScale);
|
||||
if (options.style.lineHeight) {
|
||||
height = Geo.metresToWorld(options.style.lineHeight, options.pointScale);
|
||||
}
|
||||
|
||||
var colour = new THREE.Color();
|
||||
colour.set(this._options.style.lineColor);
|
||||
colour.set(options.style.lineColor);
|
||||
|
||||
var flat = true;
|
||||
|
||||
// For each line
|
||||
attributes = this._projectedCoordinates.map(_projectedCoordinates => {
|
||||
var attributes = coordinates.map(_projectedCoordinates => {
|
||||
var _vertices = [];
|
||||
var _colours = [];
|
||||
|
||||
|
@ -164,20 +182,20 @@ class PolylineLayer extends Layer {
|
|||
verticesCount: _vertices.length
|
||||
};
|
||||
|
||||
if (this._options.interactive && this._pickingId) {
|
||||
if (options.interactive && options.pickingId) {
|
||||
// Inject picking ID
|
||||
line.pickingId = this._pickingId;
|
||||
line.pickingId = options.pickingId;
|
||||
}
|
||||
|
||||
// Convert line representation to proper attribute arrays
|
||||
return this._toAttributes(line);
|
||||
return PolylineLayer.ToAttributes(line);
|
||||
});
|
||||
}
|
||||
|
||||
this._bufferAttributes = Buffer.mergeAttributes(attributes);
|
||||
|
||||
// Original attributes are no longer required so free the memory
|
||||
attributes = null;
|
||||
resolve({
|
||||
attributes: attributes,
|
||||
flat: flat
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getBufferAttributes() {
|
||||
|
@ -203,32 +221,18 @@ class PolylineLayer extends Layer {
|
|||
this._projectedCoordinates = null;
|
||||
}
|
||||
|
||||
// Create and store mesh from buffer attributes
|
||||
//
|
||||
// This is only called if the layer is controlling its own output
|
||||
_setMesh(attributes) {
|
||||
static SetMesh(attributes, attributeLengths, flat, style, options) {
|
||||
var geometry = new THREE.BufferGeometry();
|
||||
|
||||
// itemSize = 3 because there are 3 values (components) per vertex
|
||||
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
|
||||
|
||||
if (attributes.normals) {
|
||||
geometry.addAttribute('normal', new THREE.BufferAttribute(attributes.normals, 3));
|
||||
}
|
||||
|
||||
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
|
||||
|
||||
if (attributes.pickingIds) {
|
||||
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
|
||||
for (var key in attributes) {
|
||||
geometry.addAttribute(key.slice(0, -1), new THREE.BufferAttribute(attributes[key], attributeLengths[key]));
|
||||
}
|
||||
|
||||
geometry.computeBoundingBox();
|
||||
|
||||
var style = this._options.style;
|
||||
var material;
|
||||
|
||||
if (this._options.material && this._options.material instanceof THREE.Material) {
|
||||
material = this._options.material;
|
||||
if (options.polylineMaterial && options.polylineMaterial instanceof THREE.Material) {
|
||||
material = options.polylineMaterial;
|
||||
} else {
|
||||
material = new THREE.LineBasicMaterial({
|
||||
vertexColors: THREE.VertexColors,
|
||||
|
@ -242,8 +246,8 @@ class PolylineLayer extends Layer {
|
|||
var mesh;
|
||||
|
||||
// Pass mesh through callback, if defined
|
||||
if (typeof this._options.onMesh === 'function') {
|
||||
mesh = this._options.onMesh(geometry, material);
|
||||
if (typeof options.onPolylineMesh === 'function') {
|
||||
mesh = options.onPolylineMesh(geometry, material);
|
||||
} else {
|
||||
mesh = new THREE.LineSegments(geometry, material);
|
||||
|
||||
|
@ -256,9 +260,7 @@ class PolylineLayer extends Layer {
|
|||
// mesh.receiveShadow = true;
|
||||
}
|
||||
|
||||
// TODO: Allow this to be overridden, or copy mesh instead of creating a new
|
||||
// one just for picking
|
||||
if (this._options.interactive && this._pickingMesh) {
|
||||
if (options.interactive) {
|
||||
material = new PickingMaterial();
|
||||
// material.side = THREE.BackSide;
|
||||
|
||||
|
@ -266,10 +268,12 @@ class PolylineLayer extends Layer {
|
|||
material.linewidth = style.lineWidth + material.linePadding;
|
||||
|
||||
var pickingMesh = new THREE.LineSegments(geometry, material);
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
}
|
||||
|
||||
this._mesh = mesh;
|
||||
return Promise.resolve({
|
||||
mesh: mesh,
|
||||
pickingMesh: pickingMesh
|
||||
});
|
||||
}
|
||||
|
||||
// Convert and project coordinates
|
||||
|
@ -315,7 +319,7 @@ class PolylineLayer extends Layer {
|
|||
this._offset.x = -1 * point.x;
|
||||
this._offset.y = -1 * point.y;
|
||||
|
||||
this._pointScale = this._world.pointScale(latlon);
|
||||
this._options.pointScale = this._world.pointScale(latlon);
|
||||
}
|
||||
|
||||
return point;
|
||||
|
@ -323,11 +327,7 @@ class PolylineLayer extends Layer {
|
|||
});
|
||||
}
|
||||
|
||||
// Transform line representation into attribute arrays that can be used by
|
||||
// THREE.BufferGeometry
|
||||
//
|
||||
// TODO: Can this be simplified? It's messy and huge
|
||||
_toAttributes(line) {
|
||||
static ToAttributes(line) {
|
||||
// Three components per vertex
|
||||
var vertices = new Float32Array(line.verticesCount * 3);
|
||||
var colours = new Float32Array(line.verticesCount * 3);
|
||||
|
@ -341,13 +341,6 @@ class PolylineLayer extends Layer {
|
|||
var _vertices = line.vertices;
|
||||
var _colour = line.colours;
|
||||
|
||||
var normals;
|
||||
var _normals;
|
||||
if (line.normals) {
|
||||
normals = new Float32Array(line.verticesCount * 3);
|
||||
_normals = line.normals;
|
||||
}
|
||||
|
||||
var _pickingId;
|
||||
if (pickingIds) {
|
||||
_pickingId = line.pickingId;
|
||||
|
@ -360,27 +353,12 @@ class PolylineLayer extends Layer {
|
|||
var ay = _vertices[i][1];
|
||||
var az = _vertices[i][2];
|
||||
|
||||
var nx;
|
||||
var ny;
|
||||
var nz;
|
||||
if (_normals) {
|
||||
nx = _normals[i][0];
|
||||
ny = _normals[i][1];
|
||||
nz = _normals[i][2];
|
||||
}
|
||||
|
||||
var c1 = _colour[i];
|
||||
|
||||
vertices[lastIndex * 3 + 0] = ax;
|
||||
vertices[lastIndex * 3 + 1] = ay;
|
||||
vertices[lastIndex * 3 + 2] = az;
|
||||
|
||||
if (normals) {
|
||||
normals[lastIndex * 3 + 0] = nx;
|
||||
normals[lastIndex * 3 + 1] = ny;
|
||||
normals[lastIndex * 3 + 2] = nz;
|
||||
}
|
||||
|
||||
colours[lastIndex * 3 + 0] = c1[0];
|
||||
colours[lastIndex * 3 + 1] = c1[1];
|
||||
colours[lastIndex * 3 + 2] = c1[2];
|
||||
|
@ -393,14 +371,10 @@ class PolylineLayer extends Layer {
|
|||
}
|
||||
|
||||
var attributes = {
|
||||
vertices: vertices,
|
||||
colours: colours
|
||||
positions: vertices,
|
||||
colors: colours
|
||||
};
|
||||
|
||||
if (normals) {
|
||||
attributes.normals = normals;
|
||||
}
|
||||
|
||||
if (pickingIds) {
|
||||
attributes.pickingIds = pickingIds;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue