diff --git a/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/CloudController/PointCloudLoader.cs b/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/CloudController/PointCloudLoader.cs
index dc8c882..69d4cae 100644
--- a/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/CloudController/PointCloudLoader.cs
+++ b/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/CloudController/PointCloudLoader.cs
@@ -48,10 +48,6 @@ void Start() {
private void LoadHierarchy() {
try {
- if (!cloudPath.EndsWith("/")) {
- cloudPath = cloudPath + "/";
- }
-
PointCloudMetaData metaData = CloudLoader.LoadMetaData(cloudPath, false);
setController.UpdateBoundingBox(this, metaData.boundingBox_transformed, metaData.tightBoundingBox_transformed);
diff --git a/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/Loading/CloudLoader.cs b/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/Loading/CloudLoader.cs
index 459a02a..503e030 100644
--- a/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/Loading/CloudLoader.cs
+++ b/PointCloudRenderer/Assets/Scripts/BAPointCloudRenderer/Loading/CloudLoader.cs
@@ -4,14 +4,21 @@
using System.Text;
using System.Net;
using System;
+using System.Diagnostics;
using UnityEngine;
using System.Linq;
+using Debug = UnityEngine.Debug;
namespace BAPointCloudRenderer.Loading {
///
/// Provides methods for loading point clouds from the file system
///
class CloudLoader {
+ public static bool isCloudOnline;
+
+ public enum FileTypeV2 {
+ HIERARCHY, OCTREE
+ }
/* Loads the metadata from the json-file in the given cloudpath
*/
///
@@ -19,45 +26,37 @@ class CloudLoader {
///
/// Folderpath of the cloud or URL to download the cloud from. In the latter case, it will be downloaded to a /temp folder
/// True, if the center of the cloud should be moved to the origin
- public static PointCloudMetaData LoadMetaData(string cloudPath, bool moveToOrigin = false) {
+ public static PointCloudMetaData LoadMetaData(string fullPath, bool moveToOrigin = false) {
string jsonfile = "";
- //Debug.Log(cloudPath);
- bool isCloudOnline = Uri.IsWellFormedUriString(cloudPath, UriKind.Absolute);
- if (isCloudOnline){
+ isCloudOnline = Uri.IsWellFormedUriString(fullPath, UriKind.Absolute);
+ if (isCloudOnline) {
WebClient client = new WebClient();
- Stream stream = client.OpenRead(cloudPath + "cloud.js");
+ Stream stream = client.OpenRead(fullPath);
StreamReader reader = new StreamReader(stream);
jsonfile = reader.ReadToEnd();
reader.Close();
}else{
- string filePath;
- if (File.Exists(cloudPath + "cloud.js"))
- {
- filePath = cloudPath + "cloud.js";
- }
- else if (File.Exists(cloudPath + "metadata.json"))
- {
- filePath = cloudPath + "metadata.json";
- }
- else
- {
- Debug.LogError("Unable to find neither cloud.js nor metadata.json from " + cloudPath);
- throw new Exception("Unable to find neither cloud.js nor metadata.json from " + cloudPath);
+ if (!File.Exists (fullPath)) {
+ Debug.LogError("Unable to find file from " + fullPath);
+ throw new Exception("Unable to find file from " + fullPath);
}
- if (filePath.Length > 0)
- {
- using (StreamReader reader = new StreamReader(filePath, Encoding.Default))
- {
- jsonfile = reader.ReadToEnd();
- reader.Close();
- }
+ if (fullPath.Length > 0) {
+ using StreamReader reader = new StreamReader(fullPath, Encoding.Default);
+ jsonfile = reader.ReadToEnd();
+ reader.Close();
}
}
+
+ int lastSlashIndex = fullPath.LastIndexOf('/');
+ string cloudPath = fullPath.Substring (0, lastSlashIndex + 1);
+ if (cloudPath == null) {
+ Debug.LogError("Unable to find directory from " + fullPath);
+ throw new Exception("Unable to find file directory " + fullPath);
+ }
PointCloudMetaData metaData = PointCloudMetaDataReader.ReadFromJson(jsonfile, moveToOrigin);
metaData.cloudName = cloudPath.Substring(0, cloudPath.Length-1).Substring(cloudPath.Substring(0, cloudPath.Length - 1).LastIndexOf("/") + 1);
- //Debug.Log(metaData.cloudName);
if (isCloudOnline){
metaData.cloudUrl = cloudPath;
@@ -116,12 +115,13 @@ public static void LoadPointsForNode(Node node) {
///
///
///
- private static void LoadHierarchy(PointCloudMetaData metaData, ref Node node)
+ ///
+ private static void LoadHierarchy (PointCloudMetaData metaData, ref Node node)
{
// sanitycheck.
if (node.hierarchyByteSize > 0)
{
- byte[] data = ReadFromFile(metaData.cloudPath + "hierarchy.bin", (long)node.hierarchyByteOffset, node.hierarchyByteSize);
+ byte[] data = ReadFromFile(isCloudOnline ? metaData.cloudUrl : metaData.cloudPath, (long)node.hierarchyByteOffset, node.hierarchyByteSize, FileTypeV2.HIERARCHY, isCloudOnline);
if (data.Length == (int)node.hierarchyByteSize)
{
ParseHierarchy(ref node, data);
@@ -306,18 +306,21 @@ private static BoundingBox CalculateBoundingBox(BoundingBox parent, int index) {
///
///
///
- private static void LoadPoints(string dataRPath, PointCloudMetaData metaData, Node node) {
+ ///
+ private static void LoadPoints (string dataRPath, PointCloudMetaData metaData, Node node) {
// in potree v2 type 2 nodes are proxies and their hierarchy
// yearns to be loaded just-in-time.
if (metaData.version == "2.0" && node.type == 2)
{
LoadHierarchy(metaData, ref node);
}
- byte[] data = metaData.version switch
- {
- "2.0" => ReadFromFile(metaData.cloudPath + "octree.bin", (long)node.byteOffset, node.byteSize),
- _ => FindAndLoadFile(dataRPath, metaData, node.Name, ".bin"),
- };
+ byte[] data = null;
+
+ if (metaData.version.Equals ("2.0")) {
+ data = ReadFromFile (isCloudOnline ? metaData.cloudUrl : metaData.cloudPath, (long) node.byteOffset, node.byteSize, FileTypeV2.OCTREE, isCloudOnline);
+ } else {
+ data = FindAndLoadFile (dataRPath, metaData, node.Name, ".bin");
+ }
int pointByteSize = metaData.pointByteSize;
int numPoints = data.Length / pointByteSize;
int offset = 0, toSetOff = 0;
@@ -429,27 +432,63 @@ private static byte[] FindAndLoadFile(string dataRPath, PointCloudMetaData metaD
}
return null;
}
+
///
/// used only for Potree v2. for now.
///
///
///
///
+ ///
+ ///
///
- private static byte[] ReadFromFile(string fileNameWithPath, long offset, UInt64 size)
+ private static byte[] ReadFromFile (string fileNameWithPath, long offset, ulong size, FileTypeV2 fileType, bool isURL = false)
{
+ switch (fileType) {
+ case FileTypeV2.HIERARCHY :
+ fileNameWithPath = fileNameWithPath + "hierarchy.bin";
+ break;
+ case FileTypeV2.OCTREE :
+ fileNameWithPath = fileNameWithPath + "octree.bin";
+ break;
+ }
+
if (size == 0)
{
return new byte[] { };
}
byte[] returnable = new byte[size];
-
- if (File.Exists(fileNameWithPath))
- {
- using FileStream stream = File.OpenRead(fileNameWithPath);
- stream.Seek(offset, SeekOrigin.Begin);
- stream.Read(returnable, 0, (int)size);
- stream.Close();
+
+ if (!isURL) {
+ if (File.Exists(fileNameWithPath))
+ {
+ using FileStream stream = File.OpenRead(fileNameWithPath);
+ stream.Seek(offset, SeekOrigin.Begin);
+ stream.Read(returnable, 0, (int)size);
+ stream.Close();
+ }
+ } else {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fileNameWithPath);
+ request.AddRange(offset, offset + (long)size - 1);
+
+ try {
+ using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+ using Stream stream = response.GetResponseStream();
+ if (stream == null)
+ return null;
+
+ int bytesRead = 0, totalBytesRead = 0;
+
+ while ((bytesRead = stream.Read(returnable, totalBytesRead, (int)size - totalBytesRead)) > 0)
+ {
+ totalBytesRead += bytesRead;
+ }
+ }
+ catch (WebException ex)
+ {
+ Debug.Log($"Error downloading data: {ex.Message}");
+ return null;
+ }
}
return returnable;
diff --git a/README.md b/README.md
index f7e076d..af3fa46 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,11 @@ PointCloud-BachelorThesis
Project files for my bachelor thesis on rendering large point clouds in Unity.
+
+## Range request
+
+We have to do range request to get the part of the remote file we want, so we're using range request as Potree is doing.
+
## Ressources
Please refer to the code documentation for details about the classes and scripts (Folder "/doc").
For details about the algorithms please refer to the bachelor thesis (https://www.cg.tuwien.ac.at/research/publications/2017/FRAISS-2017-PCU/).
@@ -10,6 +15,26 @@ Below you will find a Getting-Started-Guide
Download the current version: https://github.com/SFraissTU/BA_PointCloud/releases/
+### Version PullRequest PotreeRemoveV2 (13/08/2024)
+
+#### Remote URL
+
+We would like to use the PotreeV2 format for remote url, mainly because we might have to handle several Go of data.
+
+#### Remote/local URL handling with v1/v2 version
+
+For this we had to transform the URL given to the Cloud loader :
+
+Potree1 :
+Clouds/Lion -> Clouds/Lion/cloud.js
+https://remoteurl.com/Lion -> https://remoteurl.com/Lion/cloud.js
+
+Potree2 :
+Clouds/Lion2 -> Clouds/Lion2/metadata.json
+https://remoteurl.com/Lion2 -> https://remoteurl.com/Lion2/metadata.json
+
+We did this so codebase can handle in a easier way the remote/local and v1/v2 cases.
+
### Version 1.6 (09.07.2023)
Changes:
* Support for Potree Format V2 (Provided by [cognitivedata](https://github.com/cognitivedata))