Using Potree from code written in TypeScript 2

masanori_msl

Masui Masanori

Posted on September 29, 2024

Using Potree from code written in TypeScript 2

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;
}
Enter fullscreen mode Exit fullscreen mode

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();
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
...
Enter fullscreen mode Exit fullscreen mode

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);
            }
        });
    }
}
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
masanori_msl
Masui Masanori

Posted on September 29, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related