Using Potree from code written in TypeScript 2
Masui Masanori
Posted on September 29, 2024
Intro
This time, I will try rotating objects and cameras first.
I will also try replacing the previously loaded point cloud data with newly loaded point cloud data.
ts/types/potree/index.d.ts
namespace Potree {
const PointSizeType = {
FIXED: 0,
ATTENUATED: 1,
ADAPTIVE: 2
};
const PointShape = {
SQUARE: 0,
CIRCLE: 1,
PARABOLOID: 2
};
class Viewer {
scene: Scene;
renderer: THREE.WebGLRenderer;
orbitControls: OrbitControls;
constructor(element: HTMLElement);
setPointBudget(budget: number): void;
loadPointCloud(path: string, name: string, callback?: (e: PointCloudEventVariable) => void): void;
setEDLEnabled(enabled: boolean): void;
setFOV(fov: number): void;
setBackground(color: string): void;
fitToScreen(): void;
loadSettingsFromURL(): void;
zoomTo(node, factor, animationDuration = 0): void;
}
class PointCloudEventVariable {
pointcloud: PointCloudOctree;
}
class PointCloudOctree {
name: string;
position: THREE.Vector3;
scale: THREE.Vector3;
rotation: THREE.Vector3;
material: PointCloudMaterial;
updateMatrixWorld(force: boolean = false): void;
}
class Scene {
constructor(renderer: any);
addPointCloud(pointcloud: PointCloudOctree): void;
pointclouds: PointCloudOctree[];
scene: THREE.Scene;
scenePointCloud: THREE.Scene;
}
class PointCloudMaterial {
size: number;
pointSizeType: PointSizeType;
shape: PointShape;
materials: THREE.WebGLMaterials;
}
class OrbitControls {
yawDelta: number;
pitchDelta: number;
}
function loadPointCloud(
path: string,
name: string,
callback: (e: PointCloudEventVariable) => void
): void;
}
Rotation
Rotating point clouds
In this time, I will use "requestAnimationFrame" to rotate loaded point cloud data and camera.
After changing the angle of the point cloud data, I need to call "updateMatrixWorld".
potreeAccessor.ts
export class PotreeAccessor {
private viewer: Potree.Viewer;
public constructor() {
this.viewer = new Potree.Viewer(document.getElementById("potree_render_area") as HTMLElement);
this.viewer.setEDLEnabled(false);
this.viewer.setFOV(60);
this.viewer.setPointBudget(1_000_000);
this.viewer.loadSettingsFromURL();
this.viewer.setBackground("");
this.loadPointCloud("http://localhost:3000/lion_takanawa_normals/cloud.js", true);
// Change the point cloud data angles per frame.
requestAnimationFrame(() => this.rotatePointCloud());
}
private loadPointCloud(cloudURL: string, fitToScreen: boolean) {
Potree.loadPointCloud(cloudURL, "cloud", e => {
const pointcloud = e.pointcloud;
const material = pointcloud.material;
material.size = 1;
material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
material.shape = Potree.PointShape.SQUARE;
this.viewer.scene.addPointCloud(pointcloud);
this.viewer.fitToScreen();
});
}
private rotatePointCloud() {
requestAnimationFrame(() => this.rotatePointCloud());
if(this.lastPointCloud == null) {
return;
}
// Rotate
this.lastPointCloud.rotation.x += 0.01;
this.lastPointCloud.updateMatrixWorld();
}
}
Rotating camera
I also can rotate camera.
When I drag the parent element for rendering the point cloud with left mouse button, the camera will be rotated.
This function is implemented in Potree's navigation/OrbitControls.js.
Similarly, I can rotate the camera by changing the yawDelta and pitchDelta values of navigation/OrbitControls.js.
potreeAccessor.ts
...
private rotatePointCloud() {
requestAnimationFrame(() => this.rotatePointCloud());
this.viewer.orbitControls.yawDelta += 0.01;
}
...
Replacing point cloud data
To replace previously loaded point cloud data with newly loaded point cloud data, delete the previous one first, and then load the new one.
export class PotreeAccessor {
private viewer: Potree.Viewer;
private currentIndex = -1;
private lastPointCloud: Potree.PointCloudOctree|null = null;
private urls = [
"http://localhost:3000/PotreeData/metadata.json",
"http://localhost:3000/vol_total/cloud.js",
"http://localhost:3000/lion_takanawa_laz/cloud.js",
"http://localhost:3000/lion_takanawa_las/cloud.js",
"http://localhost:3000/lion_takanawa/cloud.js"
];
public constructor() {
this.viewer = new Potree.Viewer(document.getElementById("potree_render_area") as HTMLElement);
this.viewer.setEDLEnabled(false);
this.viewer.setFOV(60);
this.viewer.setPointBudget(1_000_000);
this.viewer.loadSettingsFromURL();
this.viewer.setBackground("");
this.loadPointCloud("http://localhost:3000/lion_takanawa_normals/cloud.js", true);
requestAnimationFrame(() => this.rotatePointCloud());
setInterval(() => {
this.currentIndex += 1;
if(this.currentIndex >= this.urls.length) {
this.currentIndex = 0;
}
this.clearLastPointCloud();
this.loadPointCloud(this.urls[this.currentIndex]!, false);
}, 3000);
}
private rotatePointCloud() {
...
}
private clearLastPointCloud() {
// removing last loaded point cloud data.
if(this.lastPointCloud == null) {
return;
}
this.viewer.scene.scenePointCloud.remove(this.lastPointCloud);
if(this.lastPointCloud.material?.materials != null) {
this.lastPointCloud.material.materials.forEach((m: { dispose: () => void; }) => {
m.dispose();
});
}
this.viewer.scene.pointclouds = this.viewer.scene.pointclouds.filter(p => p.name !== "cloud");
}
private loadPointCloud(cloudURL: string, fitToScreen: boolean) {
Potree.loadPointCloud(cloudURL, "cloud", e => {
const pointcloud = e.pointcloud;
const material = pointcloud.material;
material.size = 1;
material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
material.shape = Potree.PointShape.SQUARE;
this.viewer.scene.addPointCloud(pointcloud);
this.lastPointCloud = pointcloud;
if (fitToScreen) {
this.viewer.fitToScreen();
} else {
this.viewer.zoomTo(pointcloud, 1);
}
});
}
}
Posted on September 29, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.