Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ Generally speaking, hapPLY uses C++ exceptions to communicate errors-- most of t

## Known issues:
- Writing floating-point values of `inf` or `nan` in ASCII mode is not supported, because the .ply format does not specify how they should be written (C++'s ofstream and ifstream don't even treat them consistently). These values work just fine in binary mode.
- Currently hapPLY does not allow the user to specify a type for the variable which indicates how many elements are in a list; it always uses `uchar` (and throws and error if the data does not fit in a uchar). Note that at least for mesh-like data, popular software only accepts `uchar`.
- Almost all modern computers are little-endian. If you happen to have a big-endian platform, be aware that the codebase has not been tested in a big-endian environment, and might have bugs related to binary reading/writing there. Note that the _platform_ endianness is distinct from the _file_ endianness---reading/writing either big- or little-endian files certainly works just fine as long as you're running the code on a little-endian computer (as you problably are).


Expand Down
68 changes: 45 additions & 23 deletions happly.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,14 +439,28 @@ class TypedListProperty : public Property {
throw std::runtime_error("Attempted property type does not match any type defined by the .ply format.");
}

size_t maxCount = 0;
// Populate list with data
flattenedIndexStart.push_back(0);
for (const std::vector<T>& vec : data_) {
for (const T& val : vec) {
flattenedData.emplace_back(val);
}
if(vec.size() > maxCount)
maxCount = vec.size();
flattenedIndexStart.push_back(flattenedData.size());
}

if(maxCount > std::numeric_limits<uint32_t>::max()) {
throw std::runtime_error(
"List property has an element with more entries than fit in a uint32.");
} else if(maxCount > std::numeric_limits<uint16_t>::max()) {
listCountBytes = 4;
} else if(maxCount > std::numeric_limits<uint8_t>::max()) {
listCountBytes = 2;
} else {
listCountBytes = 1;
}
};

virtual ~TypedListProperty() override{};
Expand Down Expand Up @@ -547,8 +561,14 @@ class TypedListProperty : public Property {
* @param outStream Stream to write to.
*/
virtual void writeHeader(std::ostream& outStream) override {
// NOTE: We ALWAYS use uchar as the list count output type
outStream << "property list uchar " << typeName<T>() << " " << name << "\n";
if(listCountBytes == 1) {
outStream << "property list uchar " << typeName<T>() << " " << name << "\n";
} else if(listCountBytes == 2) {
outStream << "property list ushort " << typeName<T>() << " " << name << "\n";
} else if(listCountBytes == 4) {
outStream << "property list uint " << typeName<T>() << " " << name << "\n";
} else
throw std::runtime_error("Unknown value of listCountBytes.");
}

/**
Expand All @@ -561,13 +581,7 @@ class TypedListProperty : public Property {
size_t dataStart = flattenedIndexStart[iElement];
size_t dataEnd = flattenedIndexStart[iElement + 1];

// Get the number of list elements as a uchar, and ensure the value fits
size_t dataCount = dataEnd - dataStart;
if (dataCount > std::numeric_limits<uint8_t>::max()) {
throw std::runtime_error(
"List property has an element with more entries than fit in a uchar. See note in README.");
}

outStream << dataCount;
outStream.precision(std::numeric_limits<T>::max_digits10);
for (size_t iFlat = dataStart; iFlat < dataEnd; iFlat++) {
Expand All @@ -585,16 +599,20 @@ class TypedListProperty : public Property {
size_t dataStart = flattenedIndexStart[iElement];
size_t dataEnd = flattenedIndexStart[iElement + 1];

// Get the number of list elements as a uchar, and ensure the value fits
size_t dataCount = dataEnd - dataStart;
if (dataCount > std::numeric_limits<uint8_t>::max()) {
throw std::runtime_error(
"List property has an element with more entries than fit in a uchar. See note in README.");
}
uint8_t count = static_cast<uint8_t>(dataCount);
if(listCountBytes == 1) {
uint8_t count = static_cast<uint8_t>(dataCount);
outStream.write((char*)&count, listCountBytes);
} else if(listCountBytes == 2) {
uint16_t count = static_cast<uint16_t>(dataCount);
outStream.write((char*)&count, listCountBytes);
} else if(listCountBytes == 4) {
uint32_t count = static_cast<uint32_t>(dataCount);
outStream.write((char*)&count, listCountBytes);
} else
throw std::runtime_error("Unknown value of listCountBytes.");

outStream.write((char*)&count, sizeof(uint8_t));
outStream.write((char*)&flattenedData[dataStart], count * sizeof(T));
outStream.write((char*)&flattenedData[dataStart], dataCount * sizeof(T));
}

/**
Expand All @@ -607,15 +625,19 @@ class TypedListProperty : public Property {
size_t dataStart = flattenedIndexStart[iElement];
size_t dataEnd = flattenedIndexStart[iElement + 1];

// Get the number of list elements as a uchar, and ensure the value fits
size_t dataCount = dataEnd - dataStart;
if (dataCount > std::numeric_limits<uint8_t>::max()) {
throw std::runtime_error(
"List property has an element with more entries than fit in a uchar. See note in README.");
}
uint8_t count = static_cast<uint8_t>(dataCount);
if(listCountBytes == 1) {
uint8_t count = static_cast<uint8_t>(dataCount);
outStream.write((char*)&count, listCountBytes);
} else if(listCountBytes == 2) {
uint16_t count = swapEndian(static_cast<uint16_t>(dataCount));
outStream.write((char*)&count, listCountBytes);
} else if(listCountBytes == 4) {
uint32_t count = swapEndian(static_cast<uint32_t>(dataCount));
outStream.write((char*)&count, listCountBytes);
} else
throw std::runtime_error("Unknown value of listCountBytes.");

outStream.write((char*)&count, sizeof(uint8_t));
for (size_t iFlat = dataStart; iFlat < dataEnd; iFlat++) {
T value = swapEndian(flattenedData[iFlat]);
outStream.write((char*)&value, sizeof(T));
Expand Down
Loading