Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PointCloudData reprojection into view CRS ('a la volee') #2272

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a5120f0
fix(geometryLayer): fix opacity magic number
ftoromanoff Jul 18, 2024
781b344
fix(crs): fix proj4 unit 'meter' and add 'foot'
ftoromanoff Apr 30, 2024
e7e6fff
fix(crs): add support for non EPSG projection
ftoromanoff Apr 30, 2024
299215b
refactor(PointCloudLayer): promise.catch/finally instead of then(Call…
ftoromanoff Oct 1, 2024
f7d1bce
refactor(PointCloudLayer): delete onPointsCreated callback
ftoromanoff Sep 24, 2024
1c91cc1
refactor(entwineSource): read crs from metadata.srs
ftoromanoff Oct 2, 2024
a12810a
refactor(CopcSource): use metadata.wkt to set source.crs
ftoromanoff Oct 7, 2024
23c7d32
test(lasparser): add test for parseChunk
ftoromanoff Oct 3, 2024
b196453
refactor(test): change timeout
ftoromanoff Oct 2, 2024
bd12987
refactor(EntwinePointTile): move this.spacing from EntwinePointItleSo…
ftoromanoff Apr 30, 2024
35d1a58
refactor(LASLoader): reproj data during parsing and add elevation att…
ftoromanoff Jul 12, 2024
b507e27
refactor(EntwinePointTileLayer): proj boundsConforming in view crs
ftoromanoff Apr 30, 2024
52b0639
feat(EntwineData): add obb for reprojection in View crs
ftoromanoff Oct 2, 2024
3ef08e4
refactor(entwineLayer): name homogeneisation
ftoromanoff Sep 23, 2024
fceac7a
refactor(OtherPointCloudData): potree1 & 2 & copc -> add obbes
ftoromanoff Apr 30, 2024
bd3b47f
refactor(AllPointCloudLayer): supp this.extent
ftoromanoff Jul 17, 2024
4b1336f
fix(potree): Potree1 and Potree2 -> bbox and obb
ftoromanoff Oct 1, 2024
7e192d4
fix(PotreeSource): add error message whenno crs
ftoromanoff Sep 24, 2024
10d995e
examples(entwine): change linked to reproj and add GrandLyon on entwi…
ftoromanoff Apr 30, 2024
52e1931
test(entwine): update
ftoromanoff Apr 30, 2024
587c025
test(entwine): update with obbes
ftoromanoff Oct 1, 2024
49cbfa0
example(COPC): update linked with reprojection
ftoromanoff Jul 18, 2024
8126c7e
examples(potree): update
ftoromanoff Oct 1, 2024
77f961e
test(potree): Potree1 and Potree2 update
ftoromanoff Sep 24, 2024
c6f7928
refactor(entwine): supp confing.crs
ftoromanoff Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/threeExamples.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default {
'./utils/WorkerPool.js',
'./capabilities/WebGL.js',
'./libs/ktx-parse.module.js',
'./libs/zstddec.module.js'
'./libs/zstddec.module.js',
'./math/OBB.js',
],
};
144 changes: 144 additions & 0 deletions examples/copc_3d_loader.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<html>
<head>
<title>Itowns - COPC 3D loader</title>

<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">

<style type="text/css">
#description {
z-index: 2;
left: 10px;
}
</style>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
</head>
<body>
<div id="description">Specify the URL of a COPC file to load:
<input type="text" id="copc_url" />
<button onclick="readCopcURL()">Load</button>
<button onclick="loadLidarHD()">Load LiDAR HD dataset</button>
<div id="share"></div>
</div>
<div id="viewerDiv">
</div>

<script src="../dist/itowns.js"></script>
<script src="js/GUI/LoadingScreen.js"></script>
<script src="../dist/debug.js"></script>
<script type="text/javascript">
var debugGui = new dat.GUI();
var viewerDiv = document.getElementById('viewerDiv');

var view = new itowns.GlobeView(viewerDiv);

// Add one imagery layer to the scene and the miniView
// This layer is defined in a json file but it could be defined as a plain js
// object. See Layer* for more info.
itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ColorLayer('Ortho', config);
view.addLayer(layer);
});
// Add two elevation layers.
// These will deform iTowns globe geometry to represent terrain elevation.
function addElevationLayerFromConfig(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ElevationLayer(config.id, config);
view.addLayer(layer);
}
itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig);
itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig);

var layer;

function onLayerReady() {
var lookAt = new itowns.THREE.Vector3();
layer.root.bbox.getCenter(lookAt);
var coordLookAt = new itowns.Coordinates(view.referenceCrs, lookAt);

var size = new itowns.THREE.Vector3();
layer.root.bbox.getSize(size);

view.controls.lookAtCoordinate({
coord: coordLookAt,
range: 2 * size.length(),
}, false);
}

function readCopcURL() {
const urlParams = new URL(location.href).searchParams
var url = document.getElementById('copc_url').value || urlParams.get('copc');

if (url) {
const options = {};
urlParams.keys().forEach(key => {
if (key !== 'copc') {
if (key.includes('.')) {
params = key.split('.');
let object = options;
params.forEach((subKey, index) => {
if (!object[subKey]) { object[subKey] = {}; }
if (index === params.length - 1) {
object[subKey] = parseFloat(urlParams.get(key));
}
object = object[subKey];
})
} else {
options[key] = parseFloat(urlParams.get(key));
}

}
});
loadCopc(url, options);

document.getElementById('share').innerHTML = '<a href="' +
location.href.replace(location.search, '?copc=' + url) +
'" target="_blank">Link to share this view</a>';
document.getElementById('copc_url').value = url;
}
}

function loadCopc(url, options) {
const source = new itowns.CopcSource({ url });

if (layer) {
debugGui.removeFolder(layer.debugUI);
view.removeLayer('COPC');
view.notifyChange();
layer.delete();
}

const config = {
source,
crs: view.referenceCrs,
sseThreshold: 2,
pointBudget: 3000000,
...options,
}

layer = new itowns.CopcLayer('COPC', config);

itowns.View.prototype.addLayer.call(view, layer).then(onLayerReady);

layer.whenReady
.then(() => debug.PointCloudDebug.initTools(view, layer, debugGui));
}

function loadLidarHD() {
// const url ="https://storage.sbg.cloud.ovh.net/v1/AUTH_63234f509d6048bca3c9fd7928720ca1/ppk-lidar/ML/LHD_FXX_0746_6509_PTS_C_LAMB93_IGN69.copc.laz"
const url ="https://dl-lidar.ign.fr/ppk-lidar/ML/LHD_FXX_0746_6509_PTS_C_LAMB93_IGN69.copc.laz" //fixed with proxy
const options = {
material: {mode: 2},
opacity: 0.5,
}
loadCopc(url, options);
}

readCopcURL();
</script>
</body>
</html>
37 changes: 20 additions & 17 deletions examples/copc_simple_loader.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<head>
<meta charset="UTF-8">

<title>Itowns - COPC loader</title>
<title>Itowns - COPC simple loader</title>

<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">
Expand Down Expand Up @@ -35,17 +35,20 @@
<script src="../dist/debug.js"></script>
<script type="text/javascript">
let layer; // COPCLayer
let view;
let control;

const uri = new URL(location);

const gui = new dat.GUI();
const crs = {
'autzen-classified': 'EPSG:2992',
sofi: 'EPSG:32611',
millsite: 'EPSG:6341',
}

const viewerDiv = document.getElementById('viewerDiv');
const view = new itowns.View('EPSG:4326', viewerDiv);
const controls = new itowns.PlanarControls(view);
view.mainLoop.gfxEngine.renderer.setClearColor(0xdddddd);
gui = new dat.GUI();

setUrl(uri.searchParams.get('copc'));
const uri = new URL(location);
setView(uri.searchParams.get('copc'));

function onLayerReady(layer) {
const camera = view.camera.camera3D;
Expand All @@ -69,7 +72,6 @@
view.notifyChange(camera);
}


function readURL() {
const url = document.getElementById('url').value;

Expand All @@ -88,20 +90,21 @@
history.replaceState(null, null, `?${uri.searchParams.toString()}`);

input_url.value = url;
load(url);
location.reload()
}

function setView(url) {
const copcId = url.split('/').pop().split('.').shift();

view = new itowns.View(crs[copcId], viewerDiv);
controls = new itowns.PlanarControls(view);
view.mainLoop.gfxEngine.renderer.setClearColor(0xdddddd);
load(url);
}

function load(url) {
const source = new itowns.CopcSource({ url });

if (layer) {
gui.removeFolder(layer.debugUI);
view.removeLayer('COPC');
view.notifyChange();
layer.delete();
}

layer = new itowns.CopcLayer('COPC', {
source,
crs: view.referenceCrs,
Expand Down
20 changes: 14 additions & 6 deletions examples/entwine_3d_loader.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
<div id="description">Specify the URL of a Entwine Point Tree to load:
<input type="text" id="ept_url" />
<button onclick="readEPTURL()">Load</button>
<p>If your dataset is not displaying at the right location,
check that it has been converted in <code>EPSG:4978</code>.</p>
<button onclick="loadGrandLyon()">Load the Grand Lyon
dataset</button>
<div id="share"></div>
</div>
<div id="viewerDiv">
Expand Down Expand Up @@ -71,7 +71,8 @@
}

function readEPTURL() {
var url = document.getElementById('ept_url').value || new URL(location.href).searchParams.get('ept');
const urlParams = new URL(location.href).searchParams
var url = document.getElementById('ept_url').value || urlParams.get('ept');

if (url) {
loadEPT(url);
Expand All @@ -87,18 +88,25 @@
eptSource = new itowns.EntwinePointTileSource({ url });

if (eptLayer) {
view.removeLayer('ept');
debugGui.removeFolder(eptLayer.debugUI);
view.removeLayer('Entwine Point Tile');
view.notifyChange();
eptLayer.delete();
}

eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', {
source: eptSource,
crs: view.referenceCrs,
});

itowns.View.prototype.addLayer.call(view, eptLayer).then(onLayerReady);

debug.PointCloudDebug.initTools(view, eptLayer, debugGui);
eptLayer.whenReady
.then(() => debug.PointCloudDebug.initTools(view, eptLayer, debugGui));
}

function loadGrandLyon() {
document.getElementById('ept_url').value = 'https://download.data.grandlyon.com/files/grandlyon/imagerie/mnt2018/lidar/ept/';
readEPTURL();
}

readEPTURL();
Expand Down
10 changes: 4 additions & 6 deletions examples/entwine_simple_loader.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@
<script src="js/GUI/LoadingScreen.js"></script>
<script src="../dist/debug.js"></script>
<script type="text/javascript">
itowns.proj4.defs('EPSG:3946', '+proj=lcc +lat_0=46 +lon_0=3 +lat_1=45.25 +lat_2=46.75 +x_0=1700000 +y_0=5200000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs');

var debugGui = new dat.GUI();
var viewerDiv = document.getElementById('viewerDiv');
viewerDiv.style.display = 'block';
var view = new itowns.View('EPSG:3946', viewerDiv);

var view = new itowns.View('EPSG:3857', viewerDiv);
view.mainLoop.gfxEngine.renderer.setClearColor(0xcccccc);

const controls = new itowns.PlanarControls(view);
Expand All @@ -52,7 +51,7 @@
view.camera3D.far = 2.0 * size.length();

controls.groundLevel = eptLayer.root.bbox.min.z;
var position = eptLayer.root.bbox.min.clone().add(
var position = eptLayer.root.bbox.max.clone().add(
size.multiply({ x: 0, y: 0, z: size.x / size.z })
);

Expand Down Expand Up @@ -88,15 +87,14 @@
eptSource = new itowns.EntwinePointTileSource({ url });

if (eptLayer) {
debugGUI.removeFolder(eptLayer.debugUI);
debugGui.removeFolder(eptLayer.debugUI);
view.removeLayer('Entwine Point Tile');
view.notifyChange();
eptLayer.delete();
}

const config = {
source: eptSource,
crs: view.referenceCrs,
...options,
}
eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', config);
Expand Down
9 changes: 5 additions & 4 deletions examples/potree_25d_map.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,13 @@
view.mainLoop.gfxEngine.renderer.setClearColor(0xcccccc);

// Configure Point Cloud layer
potreeLayer = new itowns.PotreeLayer('eglise_saint_blaise_arles', {
source: new itowns.PotreeSource({
const potreeSource = new itowns.PotreeSource({
file: 'eglise_saint_blaise_arles.js',
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/eglise_saint_blaise_arles',
crs: view.referenceCrs,
}),
crs: 'EPSG:3946',
});
potreeLayer = new itowns.PotreeLayer('eglise_saint_blaise_arles', {
source: potreeSource,
});

// point selection on double-click
Expand Down
11 changes: 6 additions & 5 deletions examples/potree_3d_map.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@
view.controls.minDistance = 50;

// Configure Point Cloud layer
potreeLayer = new itowns.PotreeLayer('eglise_saint_blaise_arles', {
source: new itowns.PotreeSource({
file: 'eglise_saint_blaise_arles.js',
const potreeSource = new itowns.PotreeSource({
file: 'eglise_saint_blaise_arles.js',
url: 'https://raw.githubusercontent.com/gmaillet/dataset/master/',
crs: view.referenceCrs,
}),
crs: 'EPSG:4978',
});
potreeLayer = new itowns.PotreeLayer('eglise_saint_blaise_arles', {
source: potreeSource,
});

// add potreeLayer to scene
Expand Down
23 changes: 22 additions & 1 deletion src/Core/CopcNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class CopcNode extends PointCloudNode {
}

/**
* Create an (A)xis (A)ligned (B)ounding (B)ox for the given node given
* Create an (A)xis (A)ligned (B)ounding (B)ox for the node given
* `this` is its parent.
* @param {CopcNode} node - The child node
*/
Expand Down Expand Up @@ -90,6 +90,27 @@ class CopcNode extends PointCloudNode {
node.bbox.max.copy(node.bbox.min).add(size);
}

/**
* Create an (O)riented (B)ounding (B)ox for the node given
* `this` is its parent.
* @param {CopcNode} childNode - The child node
*/
createChildOBB(childNode) {
const f = 2 ** (childNode.depth - this.depth);

this.obb.getSize(size).divideScalar(f);

position.copy(this).multiplyScalar(f);

translation.subVectors(childNode, position).multiply(size);

childNode.obb = this.obb.clone();
childNode.obb.halfSize.divideScalar(f);

childNode.obb.center = this.obb.center.clone().add(this.obb.halfSize.clone().multiplyScalar(-0.5)).add(translation);
childNode.obb.position = this.obb.position.clone();
}

/**
* Create a CopcNode from the provided subtree and add it as child
* of the current node.
Expand Down
Loading
Loading