Skip to content

Commit

Permalink
Feature : Add the early support for 3d-tiles Pnts format
Browse files Browse the repository at this point in the history
Issue iTowns#185 tracks the progress
Position and RGB information are supported
  • Loading branch information
NikoSaul committed Jun 12, 2017
1 parent ecb3b54 commit 1a1f337
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/Core/Scheduler/Providers/3dTiles_Provider.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from 'three';
import Provider from './Provider';
import B3dmLoader from '../../../Renderer/ThreeExtended/B3dmLoader';
import PntsLoader from '../../../Renderer/ThreeExtended/PntsLoader';
import Fetcher from './Fetcher';
import BasicMaterial from '../../../Renderer/BasicMaterial';
import OBB from '../../../Renderer/ThreeExtended/OBB';
Expand Down Expand Up @@ -34,6 +35,7 @@ function $3dTiles_Provider(/* options*/) {

Provider.call(this);
this.b3dmLoader = new B3dmLoader();
this.pntsLoader = new PntsLoader();
}

$3dTiles_Provider.prototype = Object.create(Provider.prototype);
Expand Down Expand Up @@ -94,6 +96,12 @@ $3dTiles_Provider.prototype.b3dmToMesh = function b3dmToMesh(data, layer) {
});
};

$3dTiles_Provider.prototype.pntsParse = function pntsParse(data, layer) {
return new Promise((resolve) => {
resolve(this.pntsLoader.parse(data, layer));
});
};

function configureTile(tile, layer, metadata) {
tile.frustumCulled = false;
tile.loaded = true;
Expand Down Expand Up @@ -124,6 +132,7 @@ $3dTiles_Provider.prototype.executeCommand = function executeCommand(command) {

const supportedFormats = {
b3dm: this.b3dmToMesh.bind(this),
pnts: this.pntsParse.bind(this),
};

return Fetcher.arrayBuffer(url).then((result) => {
Expand All @@ -136,6 +145,8 @@ $3dTiles_Provider.prototype.executeCommand = function executeCommand(command) {
layer.tileIndex.extendTileset(result, metadata.tileId, newPrefix);
} else if (magic == 'b3dm') {
func = supportedFormats.b3dm;
} else if (magic == 'pnts') {
func = supportedFormats.pnts;
} else {
Promise.reject(`Unsupported magic code ${magic}`);
}
Expand Down
119 changes: 119 additions & 0 deletions src/Renderer/ThreeExtended/PntsLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import * as THREE from 'three';

function PntsLoader() {
}

/*
Parse the feature table
*/
function parseFeatureBinary(array, byteOffset, FTJSONLength, buffer, layer) {
const subArrayJson = decodeFromCharCode(array.subarray(byteOffset, FTJSONLength + byteOffset));
const parseJSON = JSON.parse(subArrayJson);

const view = new Float32Array(buffer);
let lengthFeature;

if (parseJSON.POINTS_LENGTH) {
lengthFeature = parseJSON.POINTS_LENGTH;
}

if (parseJSON.POSITION)
{
const byteOffsetPos = (parseJSON.POSITION.byteOffset + subArrayJson.length + byteOffset) / 4;
const positionArray = new Float32Array(view.subarray(byteOffsetPos, (lengthFeature * 3) + byteOffsetPos));
if (parseJSON.RGB) {
const byteOffsetCol = parseJSON.RGB.byteOffset + subArrayJson.length + byteOffset;
const colorArray = new Uint8Array(array.subarray(byteOffsetCol, (lengthFeature * 3) + byteOffsetCol));
return createGeometryPoints(positionArray, colorArray, lengthFeature, layer);
}
}
}

/*
create the geometry points with the parse binarytable
*/
function createGeometryPoints(positions, colors, numPoints, layer)
{
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3, true));

const material = new THREE.PointsMaterial({ size: 0.05, vertexColors: THREE.VertexColors, sizeAttenuation: true });
const points = new THREE.Points(geometry, material);

points.layers.set(layer);
points.realPointCount = numPoints;

return points;
}

/*
read Feature table json header
*/
/*
function readTestFT(array, byteOffset, FTJSONLength) {
console.log(decodeFromCharCode(array.subarray(byteOffset, FTJSONLength + byteOffset))); // 28 - 8 byte of header
}
*/

function decodeFromCharCode(value) {
var result = '';
for (var i = 0; i < value.length; i++) {
result += String.fromCharCode(value[i]);
}
return result;
}

PntsLoader.prototype.parse = function parse(buffer, layer) {
if (!buffer) {
throw new Error('No array buffer provided.');
}

const array = new Uint8Array(buffer);
const view = new DataView(buffer);

let byteOffset = 0;
const pntsHeader = {};

// Magic type is unsigned char [4]
pntsHeader.magic = decodeFromCharCode(array.subarray(byteOffset, 4));
byteOffset += 4;

if (pntsHeader.magic) {
// Version, byteLength, batchTableJSONByteLength, batchTableBinaryByteLength and batchTable types are uint32
pntsHeader.version = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.byteLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.FTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.FTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.BTJSONLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

pntsHeader.BTBinaryLength = view.getUint32(byteOffset, true);
byteOffset += Uint32Array.BYTES_PER_ELEMENT;

// binary table
if (pntsHeader.FTBinaryLength > 0) {
// readTestFT(array, byteOffset, pntsHeader.FTJSONLength);
return parseFeatureBinary(array, byteOffset, pntsHeader.FTJSONLength, buffer, layer);
}

// batch table
/*
if (pntsHeader.BTBinaryLength > 0) {
console.log('BTB');
}
*/
} else {
throw new Error('Invalid pnts file.');
}
};

export default PntsLoader;

0 comments on commit 1a1f337

Please sign in to comment.