Potree

From OpenStreetMap Wiki
Jump to navigation Jump to search

Description

Potree is a FOSS WebGL based point cloud renderer for large point clouds, developed at the Institute of Computer Graphics and Algorithms, TU Wien

Examples

Click on this link to view a short YouTube video on the usage of Potree and 3D point clouds for OpenStreetMap.
Or another video showing navigating through the interface click here

1. Installation and setup[1]

There's many either outdated tutorials or expect the novice user to know everything already about Linux. Further on YouTube quite some videos on this topic that give errors, at least to me. So I decided here on OpenStreetMap wiki to add a tutorial how to set up a point cloud server for mapping purposes.

Please note this if for Ubuntu 22.04 LTS Server

  1. cd ~ Go to your home folder
  2. mkdir build
  3. cd build
  4. git clone https://github.com/potree/potree.git
  5. cd potree
  6. sudo apt -yy install npm
  7. npm install
  8. cd ..
  9. mkdir deploy
  10. cp -R potree/build deploy/
  11. cp -R potree/libs deploy/
  12. cp -R potree/examples deploy/
  13. cp -R potree/docs deploy/
  14. mkdir deploy/template
  15. cd deploy
  16. zip -rq ../../deploy.zip *
  17. clear



At this point you created a deploy.zip file in your home folder which you can unzip[2] unzip deploy.zip -d destination_folder, wherever you feel it's appropriate, might also unzip it into your Apache html directory, or a virtual [https:Apache_HTTP_Server Apache] server for alternative ports. Also the build folder you created under step 2 can be deleted at this point.

If you don't have Apache or similar running you can simply use python] to run a |web server instance

  • python3 -m http.server 8080

After completing to populate the data to the server you can access the 3D point cloud data by using your browser and go to

For the next part of this tutorial we assume you used Entwine to turn your LAZ files into Entwine Point Tile data aka ept-data.

2. Apache configuration

We already installed successfully Apache while doing our Mantis installation, feel free to check up on that one. For Potree we need to configure this installation a bit[3]

But in short: we're running Potree on port 8084 and should be set accordingly in the /etc/apache2/ports.conf

# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf

Listen 8082
Listen 8084

<IfModule ssl_module>
        #Listen 443
        Listen 8442
        Listen 8445
        Listen 8447
</IfModule>

<IfModule mod_gnutls.c>
        #Listen 443
        Listen 8445
        Listen 8447
</IfModule>



Further you need to enable the Potree site on the Apache, we also set alias so we can use the common space of the nextcloud storage and avoid to duplicate data. Since 3D point clouds are huge amounts of data, you would want to minimize the footprint on your drives.

To create the file for apache to use enter following command vi /etc/apache2/sites-enabled/potree.conf and enter the following data (according to your needs, remember this is just an example which works for us)

<VirtualHost *:8084>
        ServerAdmin admin@email.com
        DocumentRoot "/srv/potree"

        Alias   "/pointcloud" "/var/snap/nextcloud/common/nextcloud/data/Vincent/files/survey/uav/output/pointcloud/"
        <Directory "/var/snap/nextcloud/common/nextcloud/data/Vincent/files/survey/uav/output/pointcloud/">
                Require all granted
        </Directory>

        ErrorLog "/var/log/apache2/potree-error_log"
        TransferLog "/var/log/apache2/potree-access_log"
        <Directory "/srv/potree/">
                DirectoryIndex index.php index.html
                Options FollowSymLinks
                AllowOverride None
                Require all granted
                Options MultiViews FollowSymlinks
        </Directory>
</VirtualHost>



3. Front

There are several drone management solutions out there. DroneDB one of the most well-known, which includes Potree. So one could argue it's a management package build around Potree, although it's actually a lot more.

While DroneDB is really great and I can recommend it after setting it up myself (it's open-source and freeware for non-commercial use, if you're okay with installation. If you opt for the hosting on their platform, you save yourself the hassle of setup and maintenance but you gotta pay for that)

For our use however I found it more applicable to setup our own frontend using simple html code, and below you can expand the code we're using. It includes a navigation menu and examples - bases on the default version from the Potree Github distribution.

<html>
	<head>
	<style>
	body{
		background: #ECE9E9;
		padding: 30px;
	}

	.thumb{
		background-size: 140px 140px;
		width: 140px;
		height: 140px;
		border-radius: 5px;
		border: 1px solid black;
		box-shadow: 3px 3px 3px 0px #555;
		margin: 0px;
		float: left;
	}

	.thumb-label{
		font-size: large;
		text-align: center;
		font-weight: bold;
		color: #FFF;
		text-shadow:black 0 0 5px, black 0 0 5px, black 0 0 5px, black 0 0 5px, black 0 0 5px, black 0 0 5px;
		height: 100%;
	}

	.unhandled_container{
		max-width: 1200px;
		margin: auto;
		margin-top: 50px;

	}

	.unhandled{
		width: 30%;
		padding-top:8px;
		padding-bottom:8px;
		padding-left: 10px;
		float:left;
		font-family: "Helvetica Neue", "Lucida Grande", Arial;
		font-size: 13px;
		border: 1px solid rgba(0, 0, 0, 0);

	}

	.unhandled:hover{
		border: 1px solid rgba(200, 200, 200, 1);
		border-radius: 4px;
		background: white;
	}

	a{
		color: #555555;
	}

	h1{
		font-weight: 500;
		color: rgb(51, 51, 51);
		font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
	}

	#main_container{
		display: grid;
		grid-template-columns: 70% 30%;
		grid-gap: 10px;
		grid-template-rows: auto auto;

		max-width: 1300px;
		margin: auto;
	}


	#top_container{
		grid-column-start: 1;
		grid-column-end: 1;
		grid-row-start: 1;
		grid-row-end: 1;

		max-width: 1200px;
		margin: auto;
		margin-top: 20px
	}

	#cityanddistricts_container{
		grid-column-start: 2;
		grid-column-end: 2;
		grid-row-start: 1;
		grid-row-end: span 2;

		margin-top: 20px
	}

	#outerbarangays_container{
		grid-column-start: 1;
		grid-column-end: 1;
		grid-row-start: 2;
		grid-row-end: 2;

		max-width: 1200px;
		margin: auto;
		margin-top: 20px;
	}
	
	.navbar {
		overflow: hidden;
		background-color: #333;
	}

	.navbar a {
		float: left;
		font-size: 16px;
		color: white;
		text-align: center;
		padding: 14px 16px;
		text-decoration: none;
	}

	.dropdown {
		float: left;
		overflow: hidden;
	}

	.dropdown .dropbtn {
		font-size: 16px;  
		border: none;
		outline: none;
		color: white;
		padding: 14px 16px;
		background-color: inherit;
		font-family: inherit;
		margin: 0;
	}

	.navbar a:hover, .dropdown:hover .dropbtn {
		background-color: red;
	}

	.dropdown-content {
		display: none;
		position: absolute;
		background-color: #f9f9f9;
		min-width: 160px;
		box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
		z-index: 1;
	}

	.dropdown-content a {
		float: none;
		color: black;
		padding: 12px 16px;
		text-decoration: none;
		display: block;
		text-align: left;
	}

	.dropdown-content a:hover {
		background-color: #ddd;
	}

	.dropdown:hover .dropdown-content {
		display: block;						
	}
	</style>
	</head>
	<body>
	
		<div class="navbar">
			<a href="index.html">Home</a>
			<div class="dropdown">
				<button class="dropbtn">Years 
					<i class="fa fa-caret-down"></i>
				</button>
				<div class="dropdown-content">
					<a href="html/2021.html">2021</a>
					<a href="html/2022.html">2022</a>
					<a href="html/2023.html">2023</a>
					<a href="html/2024.html">2024</a>
					<a href="html/2025.html">2025</a>
					<a href="html/2026.html">2026</a>
				</div>
			</div> 
		</div>
			
		<div id="main_container">
			<div id="top_container">
				<h1>Click on the 'Years' in the menu for individual, more detailed surveys</h1>
				<a href="html/city_2021-2024.html" target="_blank" style="display: inline-block">
					<div class="thumb" style="background-image: url('thumbnails/city_2021-2024.jpg'); ">
						<div class="thumb-label">Baguio Surveys 2021 - 2024</div>
					</div>
				</a>
			</div>
		</div>
		<div class="unhandled_container">
			<h1>Other links</h1>
			<a href="html/test.html" target="_blank" style="display: inline-block">
					<div class="thumb" style="background-image: url('thumbnails/.jpg'); ">
						<div class="thumb-label">Laz Test</div>
					</div>
				</a>
		</div>
	</body>
</html>



4. Template to host Entwine Point Tiles

The following file shows how to host multiple files, this javascript can of course be refined to automatically scan a folder for files and add them, which I'll do at a later stage. As for now it's about the proof of concept to have a working example[4][5]

Sample of an html that combines many 3D point clouds in a single interface, notice the "/pointcloud/" part by which every single LoadPointCloud function starts? That's the alias we set in the potree.conf for the apache setup.

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="utf-8">
        <meta name="description" content="View City RPAV recordings in 3D">
        <meta name="author" content="John Smith">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
        <title>Period 2021 - 2024</title>

        <link rel="stylesheet" type="text/css" href="../../build/potree/potree.css">
        <link rel="stylesheet" type="text/css" href="../../libs/jquery-ui/jquery-ui.min.css">
        <link rel="stylesheet" type="text/css" href="../../libs/openlayers3/ol.css">
        <link rel="stylesheet" type="text/css" href="../../libs/spectrum/spectrum.css">
        <link rel="stylesheet" type="text/css" href="../../libs/jstree/themes/mixed/style.css">
</head>

<body>
        <script src="../../libs/jquery/jquery-3.1.1.min.js"></script>
        <script src="../../libs/spectrum/spectrum.js"></script>
        <script src="../../libs/jquery-ui/jquery-ui.min.js"></script>
        <script src="../../libs/other/BinaryHeap.js"></script>
        <script src="../../libs/tween/tween.min.js"></script>
        <script src="../../libs/d3/d3.js"></script>
        <script src="../../libs/proj4/proj4.js"></script>
        <script src="../../libs/openlayers3/ol.js"></script>
        <script src="../../libs/i18next/i18next.js"></script>
        <script src="../../libs/jstree/jstree.js"></script>
        <script src="../../libs/copc/index.js"></script>
        <script src="../../build/potree/potree.js"></script>
        <script src="../../libs/plasio/js/laslaz.js"></script>

        <!-- INCLUDE ADDITIONAL DEPENDENCIES HERE -->
        <!-- INCLUDE SETTINGS HERE -->

        <div class="potree_container" style="position: absolute; width: 100%; height: 100%; left: 0px; top: 0px; ">
                <div id="potree_render_area" style="background-image: url('');"></div>
                <div id="potree_sidebar_container"> </div>
        </div>
		<script type="module">
			import * as THREE from "../../libs/three.js/build/three.module.js";
				window.viewer = new Potree.Viewer(document.getElementById("potree_render_area"));

				viewer.setEDLEnabled(true);
				viewer.setFOV(60);
				viewer.setPointBudget(50_000_000);
				viewer.loadSettingsFromURL();

				viewer.setDescription("Baguio 2021 - 2024");

				viewer.loadGUI(() => {
					viewer.setLanguage('en');
					$("#menu_appearance").next().show();
				});
				
				Potree.loadPointCloud("/pointcloud/2021/2021-06-01_epsg32651_uc_kennon-road-city-boundary-combi/ept.json", "Kennon", function(e)
				{
					viewer.scene.addPointCloud(e.pointcloud);
					
					let material = e.pointcloud.material;
					material.size = 1;
					material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
				});
				Potree.loadPointCloud("/pointcloud/2021/2021-06-01_epsg32651_uc_santa-escolastica-village/ept.json", "Escolastica", function(e)
				{
					viewer.scene.addPointCloud(e.pointcloud);
				});
				Potree.loadPointCloud("/pointcloud/2021/2021-06-18_epsg32651_ort_ceo_land-id-alleys-imelda-village/ept.json", "Imelda", function(e)
				{
					viewer.scene.addPointCloud(e.pointcloud);
				});

// Add as many as you want

				Potree.loadPointCloud("/pointcloud/2024/2024-08-22_epsg32651_ceo_s414_south-central/ept.json", "414 South Central", function(e)
				{
					viewer.scene.addPointCloud(e.pointcloud);
				
					viewer.fitToScreen(1);
				});
				// viewer.fitToScreen has to be at the last entry
		</script>
  </body>
</html>



A sample of an html that only shows a single individual point cloud would then be

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="utf-8">
        <meta name="description" content="View of the City RPAV recordings in 3D">
        <meta name="author" content="John Smith">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
        <title>Quirino Hill 2024</title>

        <link rel="stylesheet" type="text/css" href="../../build/potree/potree.css">
        <link rel="stylesheet" type="text/css" href="../../libs/jquery-ui/jquery-ui.min.css">
        <link rel="stylesheet" type="text/css" href="../../libs/openlayers3/ol.css">
        <link rel="stylesheet" type="text/css" href="../../libs/spectrum/spectrum.css">
        <link rel="stylesheet" type="text/css" href="../../libs/jstree/themes/mixed/style.css">
</head>

<body>
        <script src="../../libs/jquery/jquery-3.1.1.min.js"></script>
        <script src="../../libs/spectrum/spectrum.js"></script>
        <script src="../../libs/jquery-ui/jquery-ui.min.js"></script>
        <script src="../../libs/other/BinaryHeap.js"></script>
        <script src="../../libs/tween/tween.min.js"></script>
        <script src="../../libs/d3/d3.js"></script>
        <script src="../../libs/proj4/proj4.js"></script>
        <script src="../../libs/openlayers3/ol.js"></script>
        <script src="../../libs/i18next/i18next.js"></script>
        <script src="../../libs/jstree/jstree.js"></script>
        <script src="../../libs/copc/index.js"></script>
        <script src="../../build/potree/potree.js"></script>
        <script src="../../libs/plasio/js/laslaz.js"></script>

        <!-- INCLUDE ADDITIONAL DEPENDENCIES HERE -->
        <!-- INCLUDE SETTINGS HERE -->

        <div class="potree_container" style="position: absolute; width: 100%; height: 100%; left: 0px; top: 0px; ">
                <div id="potree_render_area" style="background-image: url('');"></div>
                <div id="potree_sidebar_container"> </div>
        </div>
		<script type="module">
			import * as THREE from "../../libs/three.js/build/three.module.js";
				window.viewer = new Potree.Viewer(document.getElementById("potree_render_area"));

				viewer.setEDLEnabled(true);
				viewer.setFOV(60);
				viewer.setPointBudget(10_000_000);
				viewer.loadSettingsFromURL();

				viewer.setDescription("Quirino Hill 2024");

				viewer.loadGUI(() => {
					viewer.setLanguage('en');
					$("#menu_appearance").next().show();
				});
				
				Potree.loadPointCloud("/pointcloud/2024/2024-02-07_epsg32651_ceo_project-quirino-hill/ept.json", "Quirino Hill", function(e)
				{
					viewer.scene.addPointCloud(e.pointcloud);
					
					let material = e.pointcloud.material;
					material.size = 1;
					material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
					viewer.fitToScreen(0.5);
				});
		</script>
  </body>
</html>



References