#include "abstract_stream.h" #include "stlb.h" #include "abstract_task_progress.h" #include #include // Read tools template NUMERIC fromLittleEndian(const foug::UInt8* bytes) { return 0; } template<> foug::UInt16 fromLittleEndian(const foug::UInt8* bytes) { // |BB|AA| -> 0xAABB return (bytes[1] << 8) | bytes[0]; } template<> foug::UInt32 fromLittleEndian(const foug::UInt8* bytes) { // |DD|CC|BB|AA| -> 0xAABBCCDD return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); } template<> foug::Real32 fromLittleEndian(const foug::UInt8* bytes) { union { foug::UInt32 asInteger; foug::Real32 asFloat; } helper; helper.asInteger = fromLittleEndian(bytes); return helper.asFloat; } // Write tools template void toLittleEndian(NUMERIC n, foug::UInt8* bytes) { union { NUMERIC asNumeric; foug::UInt8 asBytes[sizeof(NUMERIC)]; } helper; helper.asNumeric = n; // std::copy(helper.asBytes, helper.asBytes + sizeof(NUMERIC), bytes); for (unsigned i = 0; i < sizeof(NUMERIC); ++i) bytes[i] = helper.asBytes[i]; } namespace foug { namespace stl { namespace bin { static const int stlHeaderSize = 80; static const int stlFacetSize = 50; static const int stlMinFileSize = 284; static const int stlTriangleDataSize = (4 * 3) * sizeof(foug::Real32) + sizeof(foug::UInt16); void AbstractGeometryBuilder::header(const Header& /*data*/) { } void AbstractGeometryBuilder::beginTriangles(UInt32 /*count*/) { } void AbstractGeometryBuilder::endTriangles() { } Io::ReadError streamRead(AbstractStream* stream, char* buffer, Int64 size) { const Int64 result = stream->read(buffer, size); if (result == -1) return Io::StreamReadError; else if (result != size) return Io::UnexpectedSizeReadError; return Io::NoReadError; } Io::ReadError getReadError(Int64 readResult, Int64 expectedSize) { if (readResult == -1) return Io::StreamReadError; else if (readResult != expectedSize) return Io::UnexpectedSizeReadError; else return Io::NoReadError; } Io::Io(AbstractStream *stream) : IoBase(stream) { } Io::ReadError Io::read(AbstractGeometryBuilder* builder) { // // Check file size // const qint64 fileSize = stream->size(); // if (((fileSize - stlHeaderSize - stlFacetCountSize) % stlFacetSize != 0) // || fileSize < stlMinFileSize) { // cpp::checkedAssign(err, WrongFileSizeBinaryStlLoadError); // return false; // } // const int facetCount = (fileSize - stlHeaderSize - stlFacetCountSize) / stlFacetSize; AbstractStream* istream = this->stream(); AbstractTaskProgress* progress = this->taskProgress(); // Io::ReadError readErr = Io::NoReadError; UInt8 buffer[8192]; char* charBuffer = reinterpret_cast(buffer); // Read header Header headerData; istream->read(reinterpret_cast(&headerData), 80); // if ((readErr = streamRead(istream, reinterpret_cast(&headerData), 80)) != NoReadError) // return readErr; builder->header(headerData); // Read facet count istream->read(charBuffer, sizeof(UInt32)); // if ((readErr = streamRead(istream, charBuffer, sizeof(UInt32))) != NoReadError) // return readErr; const UInt32 facetCount = ::fromLittleEndian(buffer); builder->beginTriangles(facetCount); if (progress != 0) { progress->reset(); progress->setRange(0., facetCount); } // Read triangles Triangle triangle; for (UInt32 facet = 0; facet < facetCount; ++facet) { istream->read(charBuffer, stlTriangleDataSize); // if ((readErr = streamRead(istream, charBuffer, stlTriangleDataSize)) != NoReadError) // return readErr; // Read normal triangle.normal.x = ::fromLittleEndian(buffer); triangle.normal.y = ::fromLittleEndian(buffer + 1*sizeof(Real32)); triangle.normal.z = ::fromLittleEndian(buffer + 2*sizeof(Real32)); // Read vertex1 triangle.v1.x = ::fromLittleEndian(buffer + 3*sizeof(Real32)); triangle.v1.y = ::fromLittleEndian(buffer + 4*sizeof(Real32)); triangle.v1.z = ::fromLittleEndian(buffer + 5*sizeof(Real32)); // Read vertex2 triangle.v2.x = ::fromLittleEndian(buffer + 6*sizeof(Real32)); triangle.v2.y = ::fromLittleEndian(buffer + 7*sizeof(Real32)); triangle.v2.z = ::fromLittleEndian(buffer + 8*sizeof(Real32)); // Read vertex3 triangle.v3.x = ::fromLittleEndian(buffer + 9*sizeof(Real32)); triangle.v3.y = ::fromLittleEndian(buffer + 10*sizeof(Real32)); triangle.v3.z = ::fromLittleEndian(buffer + 11*sizeof(Real32)); // Attribute byte count const UInt16 attributeByteCount = ::fromLittleEndian(buffer + 12*sizeof(Real32)); // Add triangle builder->nextTriangle(triangle, attributeByteCount); if (progress != 0) progress->setValue(facet + 1); } builder->endTriangles(); return NoReadError; } Io::WriteError Io::write(const AbstractGeometry& geom, const AbstractGeometryExtraData* extraData) { AbstractStream* ostream = this->stream(); AbstractTaskProgress* progress = this->taskProgress(); UInt8 buffer[128]; // Write header Header headerData; if (extraData != 0) extraData->getHeaderData(headerData); else std::fill(headerData, headerData + 80, 0); ostream->write(reinterpret_cast(&headerData), 80); // Write facet count const UInt32 facetCount = geom.triangleCount(); ::toLittleEndian(facetCount, buffer); ostream->write(reinterpret_cast(&buffer), sizeof(UInt32)); if (progress != 0) { progress->reset(); progress->setRange(0., facetCount); } // Write triangles Triangle triangle; for (UInt32 facet = 0; facet < facetCount; ++facet) { geom.getTriangle(facet, &triangle); // Write normal ::toLittleEndian(triangle.normal.x, buffer); ::toLittleEndian(triangle.normal.y, buffer + 1*sizeof(Real32)); ::toLittleEndian(triangle.normal.z, buffer + 2*sizeof(Real32)); // Write vertex1 ::toLittleEndian(triangle.v1.x, buffer + 3*sizeof(Real32)); ::toLittleEndian(triangle.v1.y, buffer + 4*sizeof(Real32)); ::toLittleEndian(triangle.v1.z, buffer + 5*sizeof(Real32)); // Write vertex2 ::toLittleEndian(triangle.v2.x, buffer + 6*sizeof(Real32)); ::toLittleEndian(triangle.v2.y, buffer + 7*sizeof(Real32)); ::toLittleEndian(triangle.v2.z, buffer + 8*sizeof(Real32)); // Write vertex3 ::toLittleEndian(triangle.v3.x, buffer + 9*sizeof(Real32)); ::toLittleEndian(triangle.v3.y, buffer + 10*sizeof(Real32)); ::toLittleEndian(triangle.v3.z, buffer + 11*sizeof(Real32)); // Attribute byte count const UInt16 attrByteCount = extraData != 0 ? extraData->attributeByteCount(facet) : 0; ::toLittleEndian(attrByteCount, buffer + 12*sizeof(Real32)); // Write to stream ostream->write(reinterpret_cast(buffer), stlTriangleDataSize); if (progress != 0) progress->setValue(facet + 1); } return NoWriteError; } } // namespace bin } // namespace stl } // namespace foug