Skip to content

Commit

Permalink
refactor(PointCloudLayer): proj metadata.bounds/boundingBox in view crs
Browse files Browse the repository at this point in the history
  • Loading branch information
ftoromanoff committed Feb 10, 2025
1 parent 86853d6 commit c254d88
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 35 deletions.
19 changes: 17 additions & 2 deletions src/Layer/CopcLayer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from 'three';
import CopcNode from 'Core/CopcNode';
import PointCloudLayer from 'Layer/PointCloudLayer';
import proj4 from 'proj4';

/**
* A layer for [Cloud Optimised Point Cloud](https://copc.io) (COPC) datasets.
Expand Down Expand Up @@ -45,15 +46,29 @@ class CopcLayer extends PointCloudLayer {
this.spacing = source.info.spacing;

this.root = new CopcNode(0, 0, 0, 0, pageOffset, pageLength, this, -1);
this.root.bbox.min.fromArray(cube, 0);
this.root.bbox.max.fromArray(cube, 3);

let forward = (x => x);
if (this.source.crs !== this.crs) {
try {
forward = proj4(this.source.crs, this.crs).forward;
} catch (err) {
throw new Error(`${err} is not defined in proj4`);
}
}

this.minElevationRange = this.minElevationRange ?? source.header.min[2];
this.maxElevationRange = this.maxElevationRange ?? source.header.max[2];

this.scale = new THREE.Vector3(1.0, 1.0, 1.0);
this.offset = new THREE.Vector3(0.0, 0.0, 0.0);

const bounds = [
...forward(cube.slice(0, 3)),
...forward(cube.slice(3, 6)),
];

this.root.bbox.setFromArray(bounds);

return this.root.loadOctree().then(resolve);
});
}
Expand Down
24 changes: 18 additions & 6 deletions src/Layer/EntwinePointTileLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as THREE from 'three';
import EntwinePointTileNode from 'Core/EntwinePointTileNode';
import PointCloudLayer from 'Layer/PointCloudLayer';
import Extent from 'Core/Geographic/Extent';
import proj4 from 'proj4';

const bboxMesh = new THREE.Mesh();
const box3 = new THREE.Box3();
Expand Down Expand Up @@ -37,9 +38,6 @@ class EntwinePointTileLayer extends PointCloudLayer {
* contains three elements `name, protocol, extent`, these elements will be
* available using `layer.name` or something else depending on the property
* name. See the list of properties to know which one can be specified.
* @param {string} [config.crs='ESPG:4326'] - The CRS of the {@link View} this
* layer will be attached to. This is used to determine the extent of this
* layer. Default to `EPSG:4326`.
*/
constructor(id, config) {
super(id, config);
Expand All @@ -65,12 +63,26 @@ class EntwinePointTileLayer extends PointCloudLayer {

this.root = new EntwinePointTileNode(0, 0, 0, 0, this, -1);

this.root.bbox.min.fromArray(this.source.boundsConforming, 0);
this.root.bbox.max.fromArray(this.source.boundsConforming, 3);
let forward = (x => x);
if (this.source.crs !== this.crs) {
try {
forward = proj4(this.source.crs, this.crs).forward;
} catch (err) {
throw new Error(`${err} is not defined in proj4`);
}
}

this.minElevationRange = this.minElevationRange ?? this.source.boundsConforming[2];
this.maxElevationRange = this.maxElevationRange ?? this.source.boundsConforming[5];

this.extent = Extent.fromBox3(config.crs || 'EPSG:4326', this.root.bbox);
const bounds = [
...forward(this.source.bounds.slice(0, 3)),
...forward(this.source.bounds.slice(3, 6)),
];

this.root.bbox.setFromArray(bounds);

this.extent = Extent.fromBox3(this.crs, this.root.bbox);

return this.root.loadOctree().then(resolve);
});
Expand Down
27 changes: 20 additions & 7 deletions src/Layer/Potree2Layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ of the authors and should not be interpreted as representing official policies,
import * as THREE from 'three';
import PointCloudLayer from 'Layer/PointCloudLayer';
import Potree2Node from 'Core/Potree2Node';
import proj4 from 'proj4';
import Extent from 'Core/Geographic/Extent';

import { PointAttribute, Potree2PointAttributes, PointAttributeTypes } from 'Core/Potree2PointAttributes';
Expand Down Expand Up @@ -167,14 +168,26 @@ class Potree2Layer extends PointCloudLayer {
this.material.defines[normal.name] = 1;
}

const min = new THREE.Vector3(...metadata.boundingBox.min);
const max = new THREE.Vector3(...metadata.boundingBox.max);
const boundingBox = new THREE.Box3(min, max);

const root = new Potree2Node(0, 0, this);

root.bbox = boundingBox;
root.boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
let forward = (x => x);
if (this.source.crs !== this.crs) {
try {
forward = proj4(this.source.crs, this.crs).forward;
} catch (err) {
throw new Error(`${err} is not defined in proj4`);
}
}

this.minElevationRange = metadata.boundingBox.min[2];
this.maxElevationRange = metadata.boundingBox.max[2];

const bounds = [
...forward(metadata.boundingBox.min),
...forward(metadata.boundingBox.max),
];

root.bbox.setFromArray(bounds);

this.minElevationRange = this.minElevationRange ?? metadata.boundingBox.min[2];
this.maxElevationRange = this.maxElevationRange ?? metadata.boundingBox.max[2];
Expand All @@ -189,7 +202,7 @@ class Potree2Layer extends PointCloudLayer {

this.root = root;

this.extent = Extent.fromBox3(this.source.crs || 'EPSG:4326', boundingBox);
this.extent = Extent.fromBox3(this.source.crs || 'EPSG:4326', this.root.bbox);
return this.root.loadOctree().then(resolve);
});
}
Expand Down
22 changes: 20 additions & 2 deletions src/Layer/PotreeLayer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from 'three';
import PointCloudLayer from 'Layer/PointCloudLayer';
import PotreeNode from 'Core/PotreeNode';
import proj4 from 'proj4';
import Extent from 'Core/Geographic/Extent';

const bboxMesh = new THREE.Mesh();
Expand Down Expand Up @@ -67,8 +68,25 @@ class PotreeLayer extends PointCloudLayer {
this.supportsProgressiveDisplay = (this.source.extension === 'cin');

this.root = new PotreeNode(0, 0, this);
this.root.bbox.min.set(cloud.boundingBox.lx, cloud.boundingBox.ly, cloud.boundingBox.lz);
this.root.bbox.max.set(cloud.boundingBox.ux, cloud.boundingBox.uy, cloud.boundingBox.uz);

let forward = (x => x);
if (this.source.crs !== this.crs) {
try {
forward = proj4(this.source.crs, this.crs).forward;
} catch (err) {
throw new Error(`${err} is not defined in proj4`);
}
}

this.minElevationRange = cloud.tightBoundingBox.lz;
this.maxElevationRange = cloud.tightBoundingBox.uz;

const bounds = [
...forward([cloud.boundingBox.lx, cloud.boundingBox.ly, cloud.boundingBox.lz]),
...forward([cloud.boundingBox.ux, cloud.boundingBox.uy, cloud.boundingBox.uz]),
];

this.root.bbox.setFromArray(bounds);

this.minElevationRange = this.minElevationRange ?? cloud.boundingBox.lz;
this.maxElevationRange = this.maxElevationRange ?? cloud.boundingBox.uz;
Expand Down
4 changes: 4 additions & 0 deletions src/Source/Potree2Source.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ class Potree2Source extends Source {
if (!source.file) {
throw new Error('New Potree2Source: file is required');
}
if (!source.crs) {
// with better data and the spec this might be removed
throw new Error('New PotreeSource: crs is required');
}

super(source);
this.file = source.file;
Expand Down
4 changes: 4 additions & 0 deletions src/Source/PotreeSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class PotreeSource extends Source {
if (!source.file) {
throw new Error('New PotreeSource: file is required');
}
if (!source.crs) {
// with better data and the spec this might be removed
throw new Error('New PotreeSource: crs is required');
}

super(source);
this.file = source.file;
Expand Down
17 changes: 9 additions & 8 deletions test/unit/entwine.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import assert from 'assert';
import { Vector3 } from 'three';
import View from 'Core/View';
import GlobeView from 'Core/Prefab/GlobeView';
import Coordinates from 'Core/Geographic/Coordinates';
import EntwinePointTileSource from 'Source/EntwinePointTileSource';
import EntwinePointTileLayer from 'Layer/EntwinePointTileLayer';
import EntwinePointTileNode from 'Core/EntwinePointTileNode';
import LASParser from 'Parser/LASParser';
import sinon from 'sinon';
import Fetcher from 'Provider/Fetcher';
import LASParser from 'Parser/LASParser';
import Renderer from './bootstrap';

import eptFile from '../data/entwine/ept.json';
Expand Down Expand Up @@ -78,18 +79,16 @@ describe('Entwine Point Tile', function () {
});
});

describe('Layer', function () {
describe('Entwine Point Tile Layer', function () {
let renderer;
let placement;
let view;
let layer;
let context;

before(function (done) {
renderer = new Renderer();
placement = { coord: new Coordinates('EPSG:4326', 0, 0), range: 250 };
view = new GlobeView(renderer.domElement, placement, { renderer });
layer = new EntwinePointTileLayer('test', { source }, view);
view = new GlobeView(renderer.domElement, {}, { renderer });
layer = new EntwinePointTileLayer('test', { source });

context = {
camera: view.camera,
Expand Down Expand Up @@ -117,8 +116,10 @@ describe('Entwine Point Tile', function () {
});

it('tries to update on the root and succeeds', function (done) {
const lookAt = new Vector3();
const coord = new Coordinates(view.referenceCrs).setFromVector3(layer.root.bbox.getCenter(lookAt));
view.controls.lookAtCoordinate({
coord: source.center,
coord,
range: 250,
}, false)
.then(() => {
Expand All @@ -135,7 +136,7 @@ describe('Entwine Point Tile', function () {
});
});

describe('Node', function () {
describe('Entwine Point Tile Node', function () {
let root;
before(function () {
const layer = { source: { url: 'http://server.geo', extension: 'laz' } };
Expand Down
1 change: 1 addition & 0 deletions test/unit/potree.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('Potree', function () {
const source = new PotreeSource({
file: fileName,
url: baseurl,
crs: 'EPSG:4978',
});

// Configure Point Cloud layer
Expand Down
14 changes: 8 additions & 6 deletions test/unit/potree2.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ describe('Potree2', function () {

before(function () {
renderer = new Renderer();
viewer = new View('EPSG:3946', renderer.domElement, { renderer });
viewer = new View('EPSG:4978', renderer.domElement, { renderer });
viewer.camera.camera3D.position.copy(new Vector3(0, 0, 10));

// Configure Point Cloud layer
const source = new Potree2Source({
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
crs: 'EPSG:4978',
});
potreeLayer = new Potree2Layer('lion', {
source: new Potree2Source({
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
}),
source,
crs: viewer.referenceCrs,
});

Expand Down
4 changes: 4 additions & 0 deletions test/unit/potree2layerparsing.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('Potree2 Provider', function () {
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
crs: 'EPSG:4978',
metadata,
});

Expand All @@ -65,6 +66,7 @@ describe('Potree2 Provider', function () {
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
crs: 'EPSG:4978',
metadata: {
version: '2.0',
name: 'lion',
Expand Down Expand Up @@ -132,6 +134,7 @@ describe('Potree2 Provider', function () {
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
crs: 'EPSG:4978',
metadata: {
version: '2.0',
name: 'lion',
Expand Down Expand Up @@ -199,6 +202,7 @@ describe('Potree2 Provider', function () {
file: 'metadata.json',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
networkOptions: process.env.HTTPS_PROXY ? { agent: new HttpsProxyAgent(process.env.HTTPS_PROXY) } : {},
crs: 'EPSG:4978',
metadata: {
version: '2.0',
name: 'lion',
Expand Down
16 changes: 12 additions & 4 deletions test/unit/potreelayerparsing.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ describe('Potree Provider', function () {
it('cloud with no normal information', function _it(done) {
// No normals
const cloud = {
boundingBox: { lx: 0, ly: 1, ux: 2, uy: 3 },
boundingBox: { lx: 10, ly: 20, ux: 30, uy: 40 },
tightBoundingBox: { lx: 1, ly: 2, ux: 3, uy: 4 },
scale: 1.0,
pointAttributes: ['POSITION', 'RGB'],
octreeDir: 'data',
Expand All @@ -51,6 +52,7 @@ describe('Potree Provider', function () {
const source = new PotreeSource({
file: fileName,
url: baseurl,
crs: 'EPSG:4978',
cloud,
});

Expand All @@ -66,7 +68,8 @@ describe('Potree Provider', function () {
it('cloud with normals as vector', function _it(done) {
// // // // normals as vector
const cloud = {
boundingBox: { lx: 0, ly: 1, ux: 2, uy: 3 },
boundingBox: { lx: 10, ly: 20, ux: 30, uy: 40 },
tightBoundingBox: { lx: 1, ly: 2, ux: 3, uy: 4 },
scale: 1.0,
pointAttributes: ['POSITION', 'NORMAL', 'CLASSIFICATION'],
octreeDir: 'data',
Expand All @@ -75,6 +78,7 @@ describe('Potree Provider', function () {
const source = new PotreeSource({
file: fileName,
url: baseurl,
crs: 'EPSG:4978',
cloud,
});

Expand All @@ -91,14 +95,16 @@ describe('Potree Provider', function () {
it('cloud with spheremapped normals', function _it(done) {
// // spheremapped normals
const cloud = {
boundingBox: { lx: 0, ly: 1, ux: 2, uy: 3 },
boundingBox: { lx: 10, ly: 20, ux: 30, uy: 40 },
tightBoundingBox: { lx: 1, ly: 2, ux: 3, uy: 4 },
scale: 1.0,
pointAttributes: ['POSITION', 'COLOR_PACKED', 'NORMAL_SPHEREMAPPED'],
octreeDir: 'data',
};
const source = new PotreeSource({
file: fileName,
url: baseurl,
crs: 'EPSG:4978',
cloud,
});
const layer = new PotreeLayer('pointsCloud3', { source, crs: view.referenceCrs });
Expand All @@ -115,7 +121,8 @@ describe('Potree Provider', function () {
it('cloud with oct16 normals', function _it(done) {
// // // oct16 normals
const cloud = {
boundingBox: { lx: 0, ly: 1, ux: 2, uy: 3 },
boundingBox: { lx: 10, ly: 20, ux: 30, uy: 40 },
tightBoundingBox: { lx: 1, ly: 2, ux: 3, uy: 4 },
scale: 1.0,
pointAttributes: ['POSITION', 'COLOR_PACKED', 'CLASSIFICATION', 'NORMAL_OCT16'],
octreeDir: 'data',
Expand All @@ -124,6 +131,7 @@ describe('Potree Provider', function () {
file: fileName,
url: baseurl,
cloud,
crs: 'EPSG:4978',
});
const layer = new PotreeLayer('pointsCloud4', { source, crs: view.referenceCrs });
View.prototype.addLayer.call(view, layer);
Expand Down

0 comments on commit c254d88

Please sign in to comment.