Skip to content

Commit

Permalink
Merge pull request #378 from potree/extra_attributes
Browse files Browse the repository at this point in the history
Extra attributes
  • Loading branch information
m-schuetz authored Nov 10, 2019
2 parents 685ef56 + f77c87b commit 08b83dd
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 85 deletions.
4 changes: 3 additions & 1 deletion PotreeConverter/include/BINPointWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class BINPointWriter : public PointWriter{
close();
}

void write(const Point &point){
void write(Point &point){
for(int i = 0; i < attributes.size(); i++){

PointAttribute attribute = attributes[i];
Expand Down Expand Up @@ -129,6 +129,8 @@ class BINPointWriter : public PointWriter{
}
}

writer->write(reinterpret_cast<const char*>(point.extraBytes.data()), point.extraBytes.size());

numPoints++;
}

Expand Down
41 changes: 13 additions & 28 deletions PotreeConverter/include/CloudJS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,43 +124,19 @@ class CloudJS{
Value version(this->version.c_str(), (rapidjson::SizeType)this->version.size());
Value octreeDir("data");
Value projection(this->projection.c_str(), (rapidjson::SizeType)this->projection.size());

Value boundingBox(rapidjson::kObjectType);
{
//Value min(rapidjson::kArrayType);
//min.PushBack(this->boundingBox.min.x, d.GetAllocator());
//min.PushBack(this->boundingBox.min.y, d.GetAllocator());
//min.PushBack(this->boundingBox.min.z, d.GetAllocator());
//
//Value max(rapidjson::kArrayType);
//max.PushBack(this->boundingBox.max.x, d.GetAllocator());
//max.PushBack(this->boundingBox.max.y, d.GetAllocator());
//max.PushBack(this->boundingBox.max.z, d.GetAllocator());
//
//boundingBox.AddMember("min", min, d.GetAllocator());
//boundingBox.AddMember("max", max, d.GetAllocator());

boundingBox.AddMember("lx", this->boundingBox.min.x, d.GetAllocator());
boundingBox.AddMember("ly", this->boundingBox.min.y, d.GetAllocator());
boundingBox.AddMember("lz", this->boundingBox.min.z, d.GetAllocator());
boundingBox.AddMember("ux", this->boundingBox.max.x, d.GetAllocator());
boundingBox.AddMember("uy", this->boundingBox.max.y, d.GetAllocator());
boundingBox.AddMember("uz", this->boundingBox.max.z, d.GetAllocator());
}

Value tightBoundingBox(rapidjson::kObjectType);
{
//Value min(rapidjson::kArrayType);
//min.PushBack(this->tightBoundingBox.min.x, d.GetAllocator());
//min.PushBack(this->tightBoundingBox.min.y, d.GetAllocator());
//min.PushBack(this->tightBoundingBox.min.z, d.GetAllocator());
//
//Value max(rapidjson::kArrayType);
//max.PushBack(this->tightBoundingBox.max.x, d.GetAllocator());
//max.PushBack(this->tightBoundingBox.max.y, d.GetAllocator());
//max.PushBack(this->tightBoundingBox.max.z, d.GetAllocator());
//
//tightBoundingBox.AddMember("min", min, d.GetAllocator());
//tightBoundingBox.AddMember("max", max, d.GetAllocator());

tightBoundingBox.AddMember("lx", this->tightBoundingBox.min.x, d.GetAllocator());
tightBoundingBox.AddMember("ly", this->tightBoundingBox.min.y, d.GetAllocator());
tightBoundingBox.AddMember("lz", this->tightBoundingBox.min.z, d.GetAllocator());
Expand All @@ -174,8 +150,17 @@ class CloudJS{
pointAttributes.SetArray();
for(int i = 0; i < this->pointAttributes.size(); i++){
PointAttribute attribute = this->pointAttributes[i];
Value str(attribute.name.c_str(), d.GetAllocator());
pointAttributes.PushBack(str, d.GetAllocator());


Value vAttribute(rapidjson::kObjectType);
vAttribute.AddMember("name", Value(attribute.name.c_str(), d.GetAllocator()), d.GetAllocator());
vAttribute.AddMember("size", attribute.byteSize, d.GetAllocator());
vAttribute.AddMember("elements", attribute.numElements, d.GetAllocator());
vAttribute.AddMember("elementSize", attribute.byteSize / attribute.numElements, d.GetAllocator());
vAttribute.AddMember("type", Value(attribute.type.c_str(), d.GetAllocator()), d.GetAllocator());
vAttribute.AddMember("description", Value(attribute.description.c_str(), d.GetAllocator()), d.GetAllocator());

pointAttributes.PushBack(vAttribute, d.GetAllocator());
}
}else if(outputFormat == OutputFormat::LAS){
pointAttributes = "LAS";
Expand Down
76 changes: 76 additions & 0 deletions PotreeConverter/include/ExtraBytes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

#pragma once

#include <unordered_map>

using std::unordered_map;

// see LAS spec 1.4
// https://www.asprs.org/wp-content/uploads/2010/12/LAS_1_4_r13.pdf
// total of 192 bytes
struct ExtraBytesRecord {
unsigned char reserved[2];
unsigned char data_type;
unsigned char options;
char name[32];
unsigned char unused[4];
int64_t no_data[3]; // 24 = 3*8 bytes // hack: not really int, can be double too
int64_t min[3]; // 24 = 3*8 bytes // hack: not really int, can be double too
int64_t max[3]; // 24 = 3*8 bytes // hack: not really int, can be double too
double scale[3];
double offset[3];
char description[32];
};

struct ExtraType {
string type = "";
int size = 0;
int numElements = 0;
};

//ExtraType extraTypeFromID(int id) {
// if (id == 0) {
// return ExtraType{ "undefined", 0, 1 };
// }else if (id == 1) {
// return ExtraType{ "uint8", 1, 1 };
// }else if (id == 2) {
// return ExtraType{ "int8", 1, 1 };
// }else if (id == 3) {
// return ExtraType{ "uint16", 2, 1 };
// }else if (id == 4) {
// return ExtraType{ "int16", 2, 1 };
// }else if (id == 5) {
// return ExtraType{ "uint32", 4, 1 };
// }else if (id == 6) {
// return ExtraType{ "int32", 4, 1 };
// }else if (id == 7) {
// return ExtraType{ "uint64", 8, 1 };
// }else if (id == 8) {
// return ExtraType{ "int64", 8, 1 };
// }else if (id == 9) {
// return ExtraType{ "float", 4, 1 };
// }else if (id == 10) {
// return ExtraType{ "double", 8, 1 };
// }
//
// cout << "ERROR: unsupported extra type: " << id << endl;
// exit(123);
//}

const unordered_map<unsigned char, ExtraType> typeToExtraType = {
{0, ExtraType{"undefined", 0, 1}},
{1, ExtraType{"uint8", 1, 1}},
{2, ExtraType{"int8", 1, 1}},
{3, ExtraType{"uint16", 2, 1}},
{4, ExtraType{"int16", 2, 1}},
{5, ExtraType{"uint32", 4, 1}},
{6, ExtraType{"int32", 4, 1}},
{7, ExtraType{"uint64", 8, 1}},
{8, ExtraType{"int64", 8, 1}},
{9, ExtraType{"float", 4, 1}},
{10, ExtraType{"double", 8, 1}},
};




9 changes: 7 additions & 2 deletions PotreeConverter/include/LASPointReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Point.h"
#include "PointReader.h"
#include "stuff.h"
#include "ExtraBytes.hpp"

using std::string;

Expand Down Expand Up @@ -54,6 +55,7 @@ class LIBLASReader{

laszip_BOOL request_reader = 1;
laszip_request_compatibility_mode(laszip_reader, request_reader);


{// read first x points to find if color is 1 or 2 bytes
laszip_BOOL is_compressed = iEndsWith(path, ".laz") ? 1 : 0;
Expand All @@ -66,7 +68,7 @@ class LIBLASReader{
laszip_get_point_pointer(laszip_reader, &point);

colorScale = 1;
for(int i = 0; i < 100000 && i < npoints; i++){
for(int i = 0; i < 100'000 && i < npoints; i++){
laszip_read_point(laszip_reader);

auto r = point->rgb[0];
Expand Down Expand Up @@ -124,6 +126,10 @@ class LIBLASReader{
p.pointSourceID = point->point_source_ID;
p.gpsTime = point->gps_time;

if (point->num_extra_bytes > 0) {
p.extraBytes = vector<uint8_t>(point->extra_bytes, point->extra_bytes + point->num_extra_bytes);
}

return p;
}
void close(){
Expand All @@ -133,7 +139,6 @@ class LIBLASReader{
AABB getAABB();
};


class LASPointReader : public PointReader{
private:
AABB aabb;
Expand Down
2 changes: 1 addition & 1 deletion PotreeConverter/include/LASPointWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class LASPointWriter : public PointWriter{
close();
}

void write(const Point &point);
void write(Point &point);

void close(){

Expand Down
4 changes: 3 additions & 1 deletion PotreeConverter/include/Point.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#include "Vector3.h"

#include <iostream>
#include <vector>

using std::ostream;
using std::vector;

namespace Potree{

Expand All @@ -22,7 +24,7 @@ class Point{
unsigned char numberOfReturns = 0;
unsigned short pointSourceID = 0;
double gpsTime = 0.0;

vector<uint8_t> extraBytes;

Point() = default;

Expand Down
31 changes: 30 additions & 1 deletion PotreeConverter/include/PointAttributes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,38 @@

#include <string>
#include <vector>
#include <unordered_map>

using std::string;
using std::vector;
using std::unordered_map;

namespace Potree{

#define ATTRIBUTE_TYPE_INT8 "int8"
#define ATTRIBUTE_TYPE_INT16 "int16"
#define ATTRIBUTE_TYPE_INT32 "int32"
#define ATTRIBUTE_TYPE_INT64 "int64"
#define ATTRIBUTE_TYPE_UINT8 "uint8"
#define ATTRIBUTE_TYPE_UINT16 "uint16"
#define ATTRIBUTE_TYPE_UINT32 "uint32"
#define ATTRIBUTE_TYPE_UINT64 "uint64"
#define ATTRIBUTE_TYPE_FLOAT "float"
#define ATTRIBUTE_TYPE_DOUBLE "double"

const unordered_map<string, int> attributeTypeSize = {
{ATTRIBUTE_TYPE_INT8, 1},
{ATTRIBUTE_TYPE_INT16, 2},
{ATTRIBUTE_TYPE_INT32, 4},
{ATTRIBUTE_TYPE_INT64, 8},
{ATTRIBUTE_TYPE_UINT8, 1},
{ATTRIBUTE_TYPE_UINT16, 2},
{ATTRIBUTE_TYPE_UINT32, 4},
{ATTRIBUTE_TYPE_UINT64, 8},
{ATTRIBUTE_TYPE_FLOAT, 4},
{ATTRIBUTE_TYPE_DOUBLE, 8}
};

class PointAttribute{
public:
static const PointAttribute POSITION_CARTESIAN;
Expand All @@ -27,12 +53,15 @@ class PointAttribute{

int ordinal;
string name;
string description;
string type;
int numElements;
int byteSize;

PointAttribute(int ordinal, string name, int numElements, int byteSize){
PointAttribute(int ordinal, string name, string type, int numElements, int byteSize){
this->ordinal = ordinal;
this->name = name;
this->type = type;
this->numElements = numElements;
this->byteSize = byteSize;
}
Expand Down
2 changes: 1 addition & 1 deletion PotreeConverter/include/PointWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PointWriter{

virtual ~PointWriter(){};

virtual void write(const Point &point) = 0;
virtual void write(Point &point) = 0;

virtual void close() = 0;

Expand Down
7 changes: 6 additions & 1 deletion PotreeConverter/include/PotreeConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ namespace Potree{

class SparseGrid;

struct FileInfos {
AABB aabb;
uint64_t numPoints = 0;
};

class PotreeConverter{

private:
Expand All @@ -30,7 +35,7 @@ class PotreeConverter{

PointReader *createPointReader(string source, PointAttributes pointAttributes);
void prepare();
AABB calculateAABB();
FileInfos computeInfos();
void generatePage(string name);

public:
Expand Down
9 changes: 8 additions & 1 deletion PotreeConverter/include/Vector3.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <math.h>
#include <iostream>
#include <iomanip>
#include <sstream>

using std::ostream;
#ifndef _MSC_VER
Expand Down Expand Up @@ -79,7 +81,12 @@ class Vector3{
}

friend ostream &operator<<( ostream &output, const Vector3<T> &value ){
output << "[" << value.x << ", " << value.y << ", " << value.z << "]" ;
std::stringstream ss;
ss << std::setprecision(6) << std::fixed;
ss << "[" << value.x << ", " << value.y << ", " << value.z << "]";

output << ss.str();

return output;
}
};
Expand Down
4 changes: 3 additions & 1 deletion PotreeConverter/src/LASPointWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ using std::vector;

namespace Potree{

void LASPointWriter::write(const Point &point){
void LASPointWriter::write(Point &point){

coordinates[0] = point.position.x;
coordinates[1] = point.position.y;
Expand All @@ -23,6 +23,8 @@ void LASPointWriter::write(const Point &point){
this->point->return_number = point.returnNumber;
this->point->number_of_returns = point.numberOfReturns;
this->point->point_source_ID = point.pointSourceID;
this->point->extra_bytes = reinterpret_cast<laszip_U8*>(&point.extraBytes[0]);
this->point->num_extra_bytes = point.extraBytes.size();

laszip_set_point(writer, this->point);
laszip_write_point(writer);
Expand Down
22 changes: 11 additions & 11 deletions PotreeConverter/src/PointAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

namespace Potree{

const PointAttribute PointAttribute::POSITION_CARTESIAN = PointAttribute(0, "POSITION_CARTESIAN", 3, 12);
const PointAttribute PointAttribute::COLOR_PACKED = PointAttribute(1, "COLOR_PACKED", 4, 4);
const PointAttribute PointAttribute::INTENSITY = PointAttribute(2, "INTENSITY", 1, 2);
const PointAttribute PointAttribute::CLASSIFICATION = PointAttribute(3, "CLASSIFICATION", 1, 1);
const PointAttribute PointAttribute::RETURN_NUMBER = PointAttribute(4, "RETURN_NUMBER", 1, 1);
const PointAttribute PointAttribute::NUMBER_OF_RETURNS = PointAttribute(5, "NUMBER_OF_RETURNS", 1, 1);
const PointAttribute PointAttribute::SOURCE_ID = PointAttribute(6, "SOURCE_ID", 1, 2);
const PointAttribute PointAttribute::GPS_TIME = PointAttribute(7, "GPS_TIME", 1, 8);
const PointAttribute PointAttribute::NORMAL_SPHEREMAPPED = PointAttribute(8, "NORMAL_SPHEREMAPPED", 2, 2);
const PointAttribute PointAttribute::NORMAL_OCT16 = PointAttribute(9, "NORMAL_OCT16", 2, 2);
const PointAttribute PointAttribute::NORMAL = PointAttribute(10, "NORMAL", 3, 12);
const PointAttribute PointAttribute::POSITION_CARTESIAN = PointAttribute(0, "POSITION_CARTESIAN", ATTRIBUTE_TYPE_INT32, 3, 12);
const PointAttribute PointAttribute::COLOR_PACKED = PointAttribute(1, "RGBA", ATTRIBUTE_TYPE_UINT8, 4, 4);
const PointAttribute PointAttribute::INTENSITY = PointAttribute(2, "intensity", ATTRIBUTE_TYPE_UINT16, 1, 2);
const PointAttribute PointAttribute::CLASSIFICATION = PointAttribute(3, "classification", ATTRIBUTE_TYPE_UINT8, 1, 1);
const PointAttribute PointAttribute::RETURN_NUMBER = PointAttribute(4, "return number", ATTRIBUTE_TYPE_UINT8, 1, 1);
const PointAttribute PointAttribute::NUMBER_OF_RETURNS = PointAttribute(5, "number of returns", ATTRIBUTE_TYPE_UINT8, 1, 1);
const PointAttribute PointAttribute::SOURCE_ID = PointAttribute(6, "source id", ATTRIBUTE_TYPE_UINT16, 1, 2);
const PointAttribute PointAttribute::GPS_TIME = PointAttribute(7, "gps-time", ATTRIBUTE_TYPE_DOUBLE, 1, 8);
const PointAttribute PointAttribute::NORMAL_SPHEREMAPPED = PointAttribute(8, "NORMAL_SPHEREMAPPED", ATTRIBUTE_TYPE_INT8, 2, 2);
const PointAttribute PointAttribute::NORMAL_OCT16 = PointAttribute(9, "NORMAL_OCT16", ATTRIBUTE_TYPE_INT8, 2, 2);
const PointAttribute PointAttribute::NORMAL = PointAttribute(10, "NORMAL", ATTRIBUTE_TYPE_FLOAT, 3, 12);

PointAttribute PointAttribute::fromString(string name){
if(name == "POSITION_CARTESIAN"){
Expand Down
Loading

0 comments on commit 08b83dd

Please sign in to comment.