itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
250 lines (191 loc) • 11.3 kB
HTML
<html>
<head>
<title>iTowns - Potree</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">
<link rel="stylesheet" type="text/css" href="../potree/build/potree/potree.css">
<link rel="stylesheet" type="text/css" href="../potree/libs/jquery-ui/jquery-ui.min.css">
<link rel="stylesheet" type="text/css" href="../potree/libs/spectrum/spectrum.css">
<link rel="stylesheet" type="text/css" href="../potree/libs/jstree/themes/mixed/style.css">
<style type="text/css">
tr { color: white; }
</style>
</head>
<body>
<div class="potree_container" style="position: absolute; width: 100%; height: 100%; left: 0px; top: 0px; ">
<div id="potree_render_area"></div>
<div id="potree_sidebar_container"></div>
</div>
<!-- Import iTowns source code -->
<script src="../dist/itowns.js"></script>
<script src="../dist/debug.js"></script>
<!-- Import iTowns LoadingScreen pluggin -->
<script src="js/GUI/LoadingScreen.js"></script>
<!-- Define THREE and proj4 constants so that Potree may access them. Otherwise, we would need to access them
with `itowns.THREE` or `itowns.proj4`. -->
<script type="text/javascript">
const THREE = itowns.THREE;
THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
const proj4 = itowns.proj4;
</script>
<!-- Import Potree source code -->
<script src="../potree/libs/jquery/jquery-3.1.1.min.js"></script>
<script src="../potree/libs/i18next/i18next.js"></script>
<script src="../potree/libs/jstree/jstree.min.js"></script>
<script src="../potree/libs/plasio/js/laslaz.js"></script>
<script src="../potree/build/potree/potree.js"></script>
<script type="text/javascript">
// `viewerDiv` contains both iTowns and Potree rendering area (`<canvas>`)
const viewerDiv = document.getElementById('potree_render_area');
// ---------- CREATE A POTREE VIEWER FOR SUPPORTING POINT CLOUD VISUALIZATION : ----------
const coordinates = new itowns.Coordinates('EPSG:4978');
// Define crs projection of the point cloud data (taken from https://epsg.io/2154, Proj4js section)
proj4.defs(
'EPSG:2154',
'+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80'
+ ' towgs84=0,0,0,0,0,0,0 +units=m +no_defs'
);
const pointCloudCRS = 'EPSG:2154';
Potree.setTHREEShaderChunk(itowns.ShaderChunk.target);
// Create a Potree Viewer to support point cloud visualization
const potreeViewer = new Potree.Viewer(viewerDiv, {
dynamicNearFar: false,
isGeocentric: true,
crs: pointCloudCRS,
// Callback to transform coordinates displayed by Potree `Point measurement` in `EPSG:2154`
measureCoordinateCallback: (position) => {
return coordinates.setFromVector3(position).as(pointCloudCRS).toVector3();
},
});
potreeViewer.setEDLEnabled(true);
potreeViewer.setControls(null);
potreeViewer.setBackground('black');
potreeViewer.loadGUI();
// Override Potree area measure method. The original Potree method gives a planar area delimited from given
// points (summits of the area). The area returned by the method is computed from `x` and `y` components of
// the points coordinates.
//
// By default, the points coordinates passed to the method are in iTowns viewer CRS, which is geocentric.
// Therefore, computing an area over the `x` and `y` components of these coordinates is incorrect - it
// actualy computes its orthogonal projection on the equatorial plane.
//
// To fix this, we transform each coordinates of the area summits in the point cloud CRS, which is
// geographic. We store each transformed coordinates in an array. Finally we override Potree area measure
// method so that it computes area from this array.
potreeViewer.scene.addEventListener('measurement_added', (e) => {
const { measurement } = e;
if(measurement.name === "Area") {
// Array containing the geographic coordinates of each area summits
const areaPoints = [new itowns.Coordinates(pointCloudCRS)];
// Add a Coordinates to the array when an area summit is created.
measurement.addEventListener('marker_added', () => {
areaPoints.push(new itowns.Coordinates(pointCloudCRS));
}, false)
// Translate the area summit coordinates from itowns viewer CRS to geographic CRS when the summit is
// moved. It also happens when the summit is created.
measurement.addEventListener('marker_moved', (event) => {
coordinates.setFromVector3(event.position).as(pointCloudCRS, areaPoints[event.index]);
}, false);
// Clear the coordinates array when we remove an area summit.
measurement.addEventListener('marker_removed', () => {
areaPoints.splice(areaPoints.length - 1, 1);
}, false);
// Override potree `Measure.getArea` method to use projected coordinates to compute area
measurement.getArea = () => {
let area = 0;
let j = areaPoints.length - 1;
for (let i = 0; i < areaPoints.length; i++) {
let p1 = areaPoints[i];
let p2 = areaPoints[j];
area += (p2.x + p1.x) * (p1.y - p2.y);
j = i
}
return Math.abs(area / 2);
};
}
});
// ---------- CREATE A GlobeView FOR SUPPORTING ORTHO-PHOTOGRAPHIES AND DEM VISUALIZATION : ----------
// Define camera initial position.
const placement = {
heading: -35,
tilt: 30,
}
// Create a GlobeView.
const itownsViewer = new itowns.GlobeView(viewerDiv, placement, {
renderer: potreeViewer.renderer,
scene3D: potreeViewer.scene.scene,
});
// Setup loading screen.
setupLoadingScreen(viewerDiv, itownsViewer);
// Make atmosphere realistic.
itownsViewer.getLayerById('atmosphere').setRealisticOn(true);
// Controls and camera specific setting.
itownsViewer.controls.minDistanceCollision = 0.01;
itownsViewer.controls.minDistance = 20;
view.camera3D.near = 0.1;
// ---------- TWEAK ITOWNS VIEWER TO SUPPORT POTREE VISUALIZATION : ----------
itownsViewer.render = () => {};
// Force iTowns viewer to resize when changing #potree_render_area div size.
// This allows the viewer resizing when toggling potree menu.
new ResizeObserver(() => itownsViewer.resize()).observe(viewerDiv);
// Disable iTowns controls when hovering Potree tool (such as a vertex of a displayed polygon).
// This prevents iTowns camera from moving when we want to displace a Potree tool marker.
viewerDiv.addEventListener('mousemove', () => {
itownsViewer.controls.states.enabled = potreeViewer.inputHandler.hoveredElements.length === 0;
})
// Set Potree viewer camera as iTowns viewer camera.
view.camera3D.zoomTo = () => {};
potreeViewer.scene.cameraP = view.camera3D;
// TODO : should be moved to Label2DRenderer constructor
itownsViewer.mainLoop.gfxEngine.label2dRenderer.domElement.style.pointerEvents = 'none';
// ---------- DISPLAY CONTEXTUAL DATA USING ITOWNS : ----------
// Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be
// defined as a plain js object. See `Layer` documentation for more info.
itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
config.source.zoom = { max: 19, min: 3 };
itownsViewer.addLayer(
new itowns.ColorLayer(config.id, config),
);
});
// Add two elevaion layers, each with a different level of detail. Here again, each layer's properties are
// defined in a json file.
function addElevationLayerFromConfig(config) {
config.source = new itowns.WMTSSource(config.source);
itownsViewer.addLayer(
new itowns.ElevationLayer(config.id, config),
);
}
itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig);
itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig);
// ---------- DISPLAY POINT CLOUD DATA USING POTREE : ----------
const pointcloudUrl = `${location.protocol}//lidarhd.pocgpf.ovh/data/`;
itowns.Fetcher.json(
pointcloudUrl + 'metadata/pivotTHREE.json'
).then(
(pivot) => new THREE.ObjectLoader().parse(pivot)
).then(
(pivotTHREE) => {
Potree.loadPointCloud(pointcloudUrl + 'ept/ept.json', 'pointcloud', function(e) {
const pointcloud = e.pointcloud;
const material = pointcloud.material;
potreeViewer.scene.addPointCloud(pointcloud);
pointcloud.getAttribute('intensity').range = [0, 10000];
material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
material.shape = Potree.PointShape.CIRCLE;
pointcloud.position.copy(pivotTHREE.position);
pointcloud.quaternion.copy(pivotTHREE.quaternion);
pointcloud.updateMatrixWorld(true);
// Move itowns viewer camera to the center of the point cloud
itownsViewer.controls.lookAtCoordinate({
coord: new itowns.Coordinates('EPSG:4978').setFromVector3(pivotTHREE.position),
range: 1500
}, false);
});
}
);
</script>
</body>
</html>