commit 6f7bfd31e6b25f7528cd3fd1ca057235e094462e Author: Hugues Delorme Date: Tue Feb 28 20:27:32 2012 +0100 Initial import diff --git a/qmake.build/compiler_config.pri b/qmake.build/compiler_config.pri new file mode 100644 index 0000000..36ad93c --- /dev/null +++ b/qmake.build/compiler_config.pri @@ -0,0 +1,21 @@ +CONFIG *= debug_and_release +CONFIG *= warn_on stl rtti exceptions + +QT -= core gui + +CONFIG(debug, debug|release) { + DEFINES *= _DEBUG_CONFIG_ + CONFIG *= console +} +else { + CONFIG -= console +} + +CONFIG(warn_on) { + *-g++*:QMAKE_CXXFLAGS *= -Wextra +} + +win32-msvc20*:QMAKE_CXXFLAGS *= -wd4996 -wd4290 -wd4503 +win32-msvc*:DEFINES *= NOMINMAX +# This explicitely defines INTXX_C() and UINTXX_C() macros in +DEFINES *= __STDC_CONSTANT_MACROS diff --git a/qmake.build/config.pri b/qmake.build/config.pri new file mode 100644 index 0000000..e3158f3 --- /dev/null +++ b/qmake.build/config.pri @@ -0,0 +1,7 @@ +include(compiler_config.pri) +CONFIG(debug, debug|release) { + TARGET_SUFFIX = .debug +} else { + TARGET_SUFFIX = .release +} +CONFIG *= build_all debug_and_release diff --git a/qmake.build/foug_dataex.pro b/qmake.build/foug_dataex.pro new file mode 100644 index 0000000..729669f --- /dev/null +++ b/qmake.build/foug_dataex.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +CONFIG *= ordered + +SUBDIRS += libstl diff --git a/src/abstract_stream.h b/src/abstract_stream.h new file mode 100644 index 0000000..ec69e63 --- /dev/null +++ b/src/abstract_stream.h @@ -0,0 +1,24 @@ +#ifndef FOUG_ABSTRACT_STREAM_H +#define FOUG_ABSTRACT_STREAM_H + +#include "foug_global.h" + +namespace foug { + +class AbstractStream +{ +public: + virtual bool atEnd() const = 0; + + virtual bool isWritable() const = 0; + virtual bool isReadable() const = 0; + virtual bool isSequential() const = 0; + + virtual bool seek(foug::Int64 pos) = 0; + virtual Int64 read(char* data, Int64 maxSize) = 0; + virtual Int64 write(const char* data, Int64 maxSize) = 0; +}; + +} // namespace foug + +#endif // FOUG_ABSTRACT_STREAM_H diff --git a/src/abstract_task_progress.cpp b/src/abstract_task_progress.cpp new file mode 100644 index 0000000..bf02f6b --- /dev/null +++ b/src/abstract_task_progress.cpp @@ -0,0 +1,112 @@ +#include "abstract_task_progress.h" + +#include +#include + +namespace foug { + +namespace internal { + +class AbstractTaskProgressPrivate +{ +public: + AbstractTaskProgressPrivate() + : m_stepId(-1), + m_value(-1.), + m_rangeMin(-1.), + m_rangeMax(-2.), + m_rangeLength(0.), + m_progressThreshold(0.01) // Notifies each percent only + { + } + + int m_stepId; + double m_value; + double m_rangeMin; + double m_rangeMax; + double m_rangeLength; + double m_progressThreshold; +}; + +} // namespace internal + +AbstractTaskProgress::AbstractTaskProgress() + : d(new internal::AbstractTaskProgressPrivate) +{ +} + +AbstractTaskProgress::~AbstractTaskProgress() +{ + delete d; +} + +double AbstractTaskProgress::rangeMin() const +{ + return d->m_rangeMin; +} + +double AbstractTaskProgress::rangeMax() const +{ + return d->m_rangeMax; +} + +void AbstractTaskProgress::setRange(double min, double max) +{ + d->m_rangeMin = min; + d->m_rangeMax = max; + d->m_rangeLength = max - min; +} + +int AbstractTaskProgress::stepId() const +{ + return d->m_stepId; +} + +void AbstractTaskProgress::setStepId(int id) +{ + d->m_stepId = id; +} + +double AbstractTaskProgress::progress() const +{ + const double result = (d->m_value - d->m_rangeMin) / d->m_rangeLength; + return std::fabs(result); +} + +double AbstractTaskProgress::value() const +{ + return d->m_value; +} + +void AbstractTaskProgress::setValue(double v) +{ + if (std::fabs(v - d->m_value) > std::fabs(d->m_progressThreshold * d->m_rangeLength)) { + d->m_value = v; + this->handleProgressUpdate(); + } +} + +double AbstractTaskProgress::progressUpdateThreshold() const +{ + return d->m_progressThreshold; +} + +void AbstractTaskProgress::setProgressUpdateThreshold(double v) +{ + d->m_progressThreshold = v; +} + +bool AbstractTaskProgress::isStopRequested() const +{ + return false; +} + +void AbstractTaskProgress::reset() +{ + d->m_stepId = -1; + d->m_value = -1.; + d->m_rangeMin = -1.; + d->m_rangeMax = -2.; +} + +} // namespace foug diff --git a/src/abstract_task_progress.h b/src/abstract_task_progress.h new file mode 100644 index 0000000..1066920 --- /dev/null +++ b/src/abstract_task_progress.h @@ -0,0 +1,38 @@ +#ifndef FOUG_ABSTRACT_TASK_PROGRESS_H +#define FOUG_ABSTRACT_TASK_PROGRESS_H + +namespace foug { + +namespace internal { class AbstractTaskProgressPrivate; } + +class AbstractTaskProgress +{ +public: + AbstractTaskProgress(); + virtual ~AbstractTaskProgress(); + + double rangeMin() const; + double rangeMax() const; + void setRange(double min, double max); + + int stepId() const; + void setStepId(int id); + + double progress() const; + double value() const; + void setValue(double v); + + double progressUpdateThreshold() const; + void setProgressUpdateThreshold(double v); + + virtual bool isStopRequested() const; + virtual void handleProgressUpdate() = 0; + virtual void reset(); + +private: + internal::AbstractTaskProgressPrivate* const d; +}; + +} // namespace foug + +#endif // FOUG_ABSTRACT_TASK_PROGRESS_H diff --git a/src/foug_global.h b/src/foug_global.h new file mode 100644 index 0000000..9649e9b --- /dev/null +++ b/src/foug_global.h @@ -0,0 +1,39 @@ +#ifndef FOUG_GLOBAL_H +#define FOUG_GLOBAL_H + +#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) + || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# define FOUG_DECL_EXPORT __declspec(dllexport) +# define FOUG_DECL_IMPORT __declspec(dllimport) +#else +# define FOUG_DECL_EXPORT +# define FOUG_DECL_IMPORT +#endif // WIN + +//#include + +namespace foug { + +typedef char Int8; +typedef unsigned char UInt8; + +typedef short Int16; +typedef unsigned short UInt16; + +typedef int Int32; +typedef unsigned int UInt32; + +#ifdef _MSC_VER +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long Int64; +typedef unsigned long long UInt64; +#endif // _MSC_VER + +typedef float Real32; +typedef double Real64; + +} // namespace foug + +#endif // FOUG_GLOBAL_H diff --git a/src/io_base.cpp b/src/io_base.cpp new file mode 100644 index 0000000..31b33c9 --- /dev/null +++ b/src/io_base.cpp @@ -0,0 +1,90 @@ +#include "io_base.h" + +#include "abstract_stream.h" +#include "abstract_task_progress.h" + +namespace foug { + +namespace internal { + +class IoBasePrivate +{ +public: + IoBasePrivate() + : m_stream(0), + m_taskProgress(0), + m_autoDeleteStream(true), + m_autoDeleteTaskProgress(true) + { + } + + AbstractStream* m_stream; + AbstractTaskProgress* m_taskProgress; + bool m_autoDeleteStream; + bool m_autoDeleteTaskProgress; +}; + +} // namespace internal + +IoBase::IoBase(AbstractStream *stream) + : d(new internal::IoBasePrivate) +{ + d->m_stream = stream; +} + +IoBase::~IoBase() +{ + if (this->autoDeleteStream() && d->m_stream != 0) + delete d->m_stream; + + if (this->autoDeleteTaskProgress() && d->m_taskProgress != 0) + delete d->m_taskProgress; + + delete d; +} + +AbstractStream* IoBase::stream() const +{ + return d->m_stream; +} + +void IoBase::setStream(AbstractStream* stream) +{ + if (this->autoDeleteStream() && d->m_stream != 0 && d->m_stream != stream) + delete d->m_stream; + d->m_stream = stream; +} + +AbstractTaskProgress* IoBase::taskProgress() const +{ + return d->m_taskProgress; +} + +void IoBase::setTaskProgress(AbstractTaskProgress* progress) +{ + if (this->autoDeleteTaskProgress() && d->m_taskProgress != 0 && d->m_taskProgress != progress) + delete d->m_taskProgress; + d->m_taskProgress = progress; +} + +bool IoBase::autoDeleteStream() const +{ + return d->m_autoDeleteStream; +} + +void IoBase::setAutoDeleteStream(bool on) +{ + d->m_autoDeleteStream = on; +} + +bool IoBase::autoDeleteTaskProgress() const +{ + return d->m_autoDeleteTaskProgress; +} + +void IoBase::setAutoDeleteTaskProgress(bool on) const +{ + d->m_autoDeleteTaskProgress = on; +} + +} // namespace foug diff --git a/src/io_base.h b/src/io_base.h new file mode 100644 index 0000000..730c7ad --- /dev/null +++ b/src/io_base.h @@ -0,0 +1,35 @@ +#ifndef FOUG_IO_BASE_H +#define FOUG_IO_BASE_H + +namespace foug { + +class AbstractStream; +class AbstractTaskProgress; + +namespace internal { class IoBasePrivate; } + +class IoBase +{ +public: + IoBase(AbstractStream* stream = 0); + virtual ~IoBase(); + + AbstractStream* stream() const; + void setStream(AbstractStream* stream); + + AbstractTaskProgress* taskProgress() const; + void setTaskProgress(AbstractTaskProgress* progress); + + bool autoDeleteStream() const; + void setAutoDeleteStream(bool on); + + bool autoDeleteTaskProgress() const; + void setAutoDeleteTaskProgress(bool on) const; + +private: + internal::IoBasePrivate* const d; +}; + +} // namespace foug + +#endif // FOUG_IO_BASE_H diff --git a/src/libstl/abstract_geometry.h b/src/libstl/abstract_geometry.h new file mode 100644 index 0000000..5698469 --- /dev/null +++ b/src/libstl/abstract_geometry.h @@ -0,0 +1,40 @@ +#ifndef FOUG_STL_ABSTRACT_GEOMETRY_H +#define FOUG_STL_ABSTRACT_GEOMETRY_H + +#include "stl_global.h" + +namespace foug { + +template +struct Coords3d +{ + NUMERIC x; + NUMERIC y; + NUMERIC z; +}; + +template +struct Triangle +{ + COORDS normal; + COORDS v1; + COORDS v2; + COORDS v3; +}; + +namespace stl { + +typedef Coords3d Coords; +typedef Triangle Triangle; + +class FOUG_STL_EXPORT AbstractGeometry +{ +public: + virtual UInt32 triangleCount() const = 0; + virtual void getTriangle(UInt32 index, Triangle* triangle) const = 0; +}; + +} // namespace stl +} // namespace foug + +#endif // FOUG_STL_ABSTRACT_GEOMETRY_H diff --git a/src/libstl/stl_global.h b/src/libstl/stl_global.h new file mode 100644 index 0000000..6891586 --- /dev/null +++ b/src/libstl/stl_global.h @@ -0,0 +1,16 @@ +#ifndef FOUG_STL_GLOBAL_H +#define FOUG_STL_GLOBAL_H + +#include "foug_global.h" + +#ifdef FOUG_STL_DLL +# ifdef FOUG_STL_MAKE_DLL +# define FOUG_STL_EXPORT FOUG_DECL_EXPORT +# else +# define FOUG_STL_EXPORT FOUG_DECL_IMPORT +# endif // FOUG_STL_MAKE_DLL +#else +# define FOUG_STL_EXPORT +#endif // FOUG_STL_DLL + +#endif // FOUG_STL_GLOBAL_H diff --git a/src/libstl/stla.cpp b/src/libstl/stla.cpp new file mode 100644 index 0000000..c736176 --- /dev/null +++ b/src/libstl/stla.cpp @@ -0,0 +1,30 @@ +#include "abstract_stream.h" +#include "stla.h" + +#include + +namespace foug { +namespace stl { +namespace asc { + +bool Io::read(AbstractGeometryBuilder* builder, Int64 streamSize) +{ + return false; +} + +bool Io::write(const AbstractGeometry& geom, const std::string& solidName) +{ + return false; +} + +void AbstractGeometryBuilder::beginSolid(const std::string& /*name*/) +{ +} + +void AbstractGeometryBuilder::endSolid(const std::string& /*name*/) +{ +} + +} // namespace asc +} // namespace stl +} // namespace foug diff --git a/src/libstl/stla.h b/src/libstl/stla.h new file mode 100644 index 0000000..2901c7a --- /dev/null +++ b/src/libstl/stla.h @@ -0,0 +1,34 @@ +#ifndef FOUG_STLA_H +#define FOUG_STLA_H + +#include "stl_global.h" +#include "abstract_geometry.h" +#include "io_base.h" +#include + +namespace foug { +namespace stl { +namespace asc { + +class FOUG_STL_EXPORT AbstractGeometryBuilder +{ +public: + virtual void beginSolid(const std::string& name); + virtual void nextTriangle(const Triangle& triangle) = 0; + virtual void endSolid(const std::string& name); +}; + +class FOUG_STL_EXPORT Io : public IoBase +{ +public: + Io(AbstractStream* stream = 0); + + bool read(AbstractGeometryBuilder* builder, Int64 streamSize = -1); + bool write(const AbstractGeometry& geom, const std::string& solidName); +}; + +} // namespace asc +} // namespace stl +} // namespace foug + +#endif // FOUG_STLA_H diff --git a/src/libstl/stlb.cpp b/src/libstl/stlb.cpp new file mode 100644 index 0000000..7a52011 --- /dev/null +++ b/src/libstl/stlb.cpp @@ -0,0 +1,251 @@ +#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 diff --git a/src/libstl/stlb.h b/src/libstl/stlb.h new file mode 100644 index 0000000..b2bcaab --- /dev/null +++ b/src/libstl/stlb.h @@ -0,0 +1,55 @@ +#ifndef FOUG_STLB_H +#define FOUG_STLB_H + +#include "stl_global.h" +#include "abstract_geometry.h" +#include "io_base.h" +#include + +namespace foug { +namespace stl { +namespace bin { + +typedef UInt8 Header[80]; + +class FOUG_STL_EXPORT AbstractGeometryBuilder +{ +public: + virtual void header(const Header& data); + virtual void beginTriangles(UInt32 count); + virtual void nextTriangle(const stl::Triangle& triangle, UInt16 attributeByteCount) = 0; + virtual void endTriangles(); +}; + +class FOUG_STL_EXPORT AbstractGeometryExtraData +{ +public: + virtual void getHeaderData(Header& data) const = 0; + virtual UInt16 attributeByteCount(UInt32 triangleIndex) const = 0; +}; + +class FOUG_STL_EXPORT Io : public IoBase +{ +public: + Io(AbstractStream* stream = 0); + + enum ReadError + { + NoReadError, + StreamReadError, + UnexpectedSizeReadError + }; + ReadError read(AbstractGeometryBuilder* builder); + + enum WriteError + { + NoWriteError + }; + WriteError write(const AbstractGeometry& geom, const AbstractGeometryExtraData* extraData = 0); +}; + +} // namespace bin +} // namespace stl +} // namespace foug + +#endif // FOUG_STLB_H diff --git a/src/streams/qt4_stream.cpp b/src/streams/qt4_stream.cpp new file mode 100644 index 0000000..862363e --- /dev/null +++ b/src/streams/qt4_stream.cpp @@ -0,0 +1,48 @@ +#include "qt4_stream.h" + +#include +#include + +namespace foug { + +Qt4Stream::Qt4Stream(QIODevice *device) + : m_device(device) +{ +} + +bool Qt4Stream::atEnd() const +{ + return m_device->atEnd(); +} + +bool Qt4Stream::isWritable() const +{ + return m_device != 0 ? m_device->isWritable() : false; +} + +bool Qt4Stream::isReadable() const +{ + return m_device != 0 ? m_device->isReadable() : false; +} + +bool Qt4Stream::isSequential() const +{ + return m_device != 0 ? m_device->isSequential() : false; +} + +bool Qt4Stream::seek(Int64 pos) +{ + return m_device->seek(pos); +} + +Int64 Qt4Stream::read(char *data, Int64 maxSize) +{ + return m_device->read(data, maxSize); +} + +Int64 Qt4Stream::write(const char *data, Int64 maxSize) +{ + return m_device->write(data, maxSize); +} + +} // namespace foug diff --git a/src/streams/qt4_stream.h b/src/streams/qt4_stream.h new file mode 100644 index 0000000..8b1412b --- /dev/null +++ b/src/streams/qt4_stream.h @@ -0,0 +1,30 @@ +#ifndef FOUG_QT4_STREAM_H +#define FOUG_QT4_STREAM_H + +#include "abstract_stream.h" +class QIODevice; + +namespace foug { + +class Qt4Stream : public AbstractStream +{ +public: + Qt4Stream(QIODevice* device); + + bool atEnd() const; + + bool isWritable() const; + bool isReadable() const; + bool isSequential() const; + + bool seek(foug::Int64 pos); + Int64 read(char* data, Int64 maxSize); + Int64 write(const char* data, Int64 maxSize); + +private: + QIODevice* m_device; +}; + +} // namespace foug + +#endif // FOUG_QT4_STREAM_H diff --git a/src/streams/std_io_stream.cpp b/src/streams/std_io_stream.cpp new file mode 100644 index 0000000..68601e1 --- /dev/null +++ b/src/streams/std_io_stream.cpp @@ -0,0 +1,29 @@ +#include "std_io_stream.h" + +namespace foug { + +StdIoStream::StdIoStream(std::iostream* iostr) + : m_iostr(iostr) +{ +} + +Int64 StdIoStream::read(char* data, Int64 maxSize) +{ + if (!m_iostr->eof()) + return 0; + + m_iostr->read(data, maxSize); + if (!m_iostr->good()) + return -1; + return maxSize; +} + +Int64 StdIoStream::write(const char* data, Int64 maxSize) +{ + m_iostr->write(data, maxSize); + if (!m_iostr->good()) + return -1; + return maxSize; +} + +} // namespace foug diff --git a/src/streams/std_io_stream.h b/src/streams/std_io_stream.h new file mode 100644 index 0000000..5736099 --- /dev/null +++ b/src/streams/std_io_stream.h @@ -0,0 +1,114 @@ +#ifndef FOUG_STD_IO_STREAM_H +#define FOUG_STD_IO_STREAM_H + +#include "abstract_stream.h" + +namespace foug { + +template +class StdInputStream : public AbstractStream +{ +public: + StdInputStream(STD_STREAM* istr) + : m_istr(istr) + { + } + + bool atEnd() const + { + return m_istr->eof(); + } + + bool isWritable() const + { + return false; + } + + bool isReadable() const + { + return true; + } + + bool isSequential() const + { + return false; + } + + bool seek(foug::Int64 pos) + { + m_istr->seekg(pos); + return m_istr->good(); + } + + Int64 read(char* data, Int64 maxSize) + { + m_istr->read(data, maxSize); + if (!m_istr->eof() && (m_istr->fail())) + return -1; + return m_istr->gcount(); + } + + Int64 write(const char* /*data*/, Int64 /*maxSize*/) + { + return -1; + } + +private: + STD_STREAM* m_istr; +}; + +template +class StdOutputStream : public AbstractStream +{ +public: + StdOutputStream(STD_STREAM* ostr) + : m_ostr(ostr) + { + } + + bool atEnd() const + { + return m_ostr->eof(); + } + + bool isWritable() const + { + return true; + } + + bool isReadable() const + { + return false; + } + + bool isSequential() const + { + return false; + } + + bool seek(foug::Int64 pos) + { + m_ostr->seekp(pos); + return m_ostr->good(); + } + + Int64 read(char* /*data*/, Int64 /*maxSize*/) + { + return -1; + } + + Int64 write(const char* data, Int64 maxSize) + { + m_ostr->write(data, maxSize); + if (!m_ostr->good()) + return -1; + return maxSize; + } + +private: + STD_STREAM* m_ostr; +}; + +} // namespace foug + +#endif // FOUG_STD_IO_STREAM_H diff --git a/tests/bench_occ/bench_occ.pro b/tests/bench_occ/bench_occ.pro new file mode 100644 index 0000000..d4b7932 --- /dev/null +++ b/tests/bench_occ/bench_occ.pro @@ -0,0 +1,17 @@ +include(../../qmake.build/config.pri) +include(_local_config.pri) +include(occ.pri) + +TEMPLATE = app +TARGET = bench_occ$$TARGET_SUFFIX + +QT *= core + +HEADERS += + +SOURCES += main.cpp + +LIBS *= -lTKSTL -lTKernel + +INCLUDEPATH += ../../src +LIBS += -L../../bin -lfougstl$$TARGET_SUFFIX diff --git a/tests/bench_occ/main.cpp b/tests/bench_occ/main.cpp new file mode 100644 index 0000000..f3caae4 --- /dev/null +++ b/tests/bench_occ/main.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "streams/qt4_stream.h" +#include "libstl/stlb.h" + +namespace internal { + +class OccStlMeshBuilder : public foug::stl::bin::AbstractGeometryBuilder +{ +public: + void beginTriangles(foug::UInt32 count) + { + Q_UNUSED(count); + m_stlMesh = new StlMesh_Mesh; + m_stlMesh->AddDomain(); + } + + void nextTriangle(const foug::stl::Triangle& triangle, foug::UInt16 attributeByteCount) + { + Q_UNUSED(attributeByteCount); + const int uId = m_stlMesh->AddOnlyNewVertex(triangle.v1.x, triangle.v1.y, triangle.v1.z); + const int vId = m_stlMesh->AddOnlyNewVertex(triangle.v2.x, triangle.v2.y, triangle.v2.z); + const int wId = m_stlMesh->AddOnlyNewVertex(triangle.v3.x, triangle.v3.y, triangle.v3.z); + const foug::stl::Coords& n = triangle.normal; + m_stlMesh->AddTriangle(uId, vId, wId, n.x, n.y, n.z); + } + + Handle_StlMesh_Mesh stlMesh() const + { + return m_stlMesh; + } + +private: + Handle_StlMesh_Mesh m_stlMesh; +}; + +} // namespace internal + +int main(int argc, char** argv) +{ + QStringList filePaths; + for (int i = 1; i < argc; ++i) + filePaths.append(argv[i]); + + const int benchCount = 1; + QTime time; + time.start(); + + qDebug() << sizeof(foug::stl::Triangle); + + for (int i = 0; i < benchCount; ++i) { + foreach (const QString& filePath, filePaths) { + Handle_StlMesh_Mesh stlMesh = RWStl::ReadBinary(OSD_Path(filePath.toAscii().constData())); + } + } + + qDebug() << QString("OCC read time : %1sec").arg(time.elapsed() / 1000.); + + + time.restart(); + + internal::OccStlMeshBuilder occStlMeshBuilder; + foug::stl::bin::Io io; + io.setAutoDeleteStream(false); + for (int i = 0; i < benchCount; ++i) { + foreach (const QString& filePath, filePaths) { + QFile file(filePath); + if (file.open(QIODevice::ReadOnly)) { + foug::Qt4Stream stream(&file); + io.setStream(&stream); + io.read(&occStlMeshBuilder); + Handle_StlMesh_Mesh stlMesh = occStlMeshBuilder.stlMesh(); + } + } + } + + qDebug() << QString("FougSTL read time : %1sec").arg(time.elapsed() / 1000.); + + return 0; +} diff --git a/tests/bench_occ/occ.pri b/tests/bench_occ/occ.pri new file mode 100644 index 0000000..1e7a84b --- /dev/null +++ b/tests/bench_occ/occ.pri @@ -0,0 +1,32 @@ +use_oce { + INCLUDEPATH += $$CASCADE_ROOT/include/oce + !isEmpty(OCE_VERSION) { + LIBS += -L$$CASCADE_ROOT/lib/$$OCE_VERSION + } +} +else { + INCLUDEPATH += $$CASCADE_ROOT/inc +} + +linux-*:DEFINES *= HAVE_CONFIG_H \ + HAVE_FSTREAM \ + HAVE_IOSTREAM \ + HAVE_LIMITS_H + +win32-*:DEFINES *= WNT +linux-*:DEFINES *= LIN LININTEL OCC_CONVERT_SIGNALS +*-64:DEFINES *= _OCC64 + +linux-*:LIBS += -L$$CASCADE_ROOT/lib +win32-*:LIBS += -L$$CASCADE_ROOT/win32/lib + +# There is a weird bug with qmake on windows : it fails to correctly link with +# TKSTEP209 due to the name of library mixing characters and digits. +# Or maybe nmake is the problem ? +# Note : you have to rename TKSTEP209 to TKSTEP_tzn in $CASROOT/win32/lib +win32-msvc* { + OCC_TKSTEP = TKSTEP_tzn +} +else { + OCC_TKSTEP = TKSTEP209 +} diff --git a/tests/cmd/cmd.pro b/tests/cmd/cmd.pro new file mode 100644 index 0000000..dccdcdb --- /dev/null +++ b/tests/cmd/cmd.pro @@ -0,0 +1,13 @@ +include(../../qmake.build/config.pri) + +TEMPLATE = app +TARGET = cmd$$TARGET_SUFFIX + +QT *= core + +HEADERS += + +SOURCES += main.cpp + +INCLUDEPATH += ../../src +LIBS += -L../../bin -lfougstl$$TARGET_SUFFIX diff --git a/tests/cmd/main.cpp b/tests/cmd/main.cpp new file mode 100644 index 0000000..7386bf8 --- /dev/null +++ b/tests/cmd/main.cpp @@ -0,0 +1,234 @@ +#include +#include +#include +#include + +#include "abstract_task_progress.h" +#include "libstl/abstract_geometry.h" +#include "libstl/stlb.h" +#include "streams/qt4_stream.h" + +#include +#include "streams/std_io_stream.h" + +#include +#include +#include +#include + +#define USE_QT4STREAM +//#define USE_STDSTREAM + +namespace internal { + +class ConsoleTaskProgress : public foug::AbstractTaskProgress +{ +public: + void handleProgressUpdate() + { + qDebug() << this->progress(); + } +}; + +class DummyGeometryBuilder : public foug::stl::bin::AbstractGeometryBuilder +{ +public: + void header(const foug::stl::bin::Header& data) + { + qDebug() << "HEADER : \n" << QString::fromAscii(reinterpret_cast(data), 79); + } + + void beginTriangles(foug::UInt32 count) + { + m_triangleCounter = 0; + qDebug() << "Triangle count" << count; + } + + void nextTriangle(const foug::stl::Triangle& triangle, foug::UInt16 attributeByteCount) + { + // qDebug() << "TRIANGLE " << m_triangleCounter++; + // qDebug() << " normal" << triangle.normal.x << triangle.normal.y << triangle.normal.z; + // qDebug() << " v1" << triangle.v1.x << triangle.v1.y << triangle.v1.z; + // qDebug() << " v2" << triangle.v2.x << triangle.v2.y << triangle.v2.z; + // qDebug() << " v3" << triangle.v3.x << triangle.v3.y << triangle.v3.z; + // qDebug() << " attr" << attributeByteCount; + } + +private: + foug::UInt32 m_triangleCounter; +}; + +class BasicGeometryHelper : + public foug::stl::AbstractGeometry, + public foug::stl::bin::AbstractGeometryBuilder, + public foug::stl::bin::AbstractGeometryExtraData +{ +public: + struct TriangleData + { + foug::stl::Triangle triangle; + foug::UInt16 attributeByteCount; + }; + + QVector triangles() const + { + return m_triangles; + } + + // -- foug::stl::bin::AbstractGeometryBuilder + + void header(const foug::stl::bin::Header& data) + { + std::memcpy(m_header, data, 80); + } + + void beginTriangles(foug::UInt32 count) + { + m_triangles.reserve(count); + m_triangles.clear(); + m_triangles.resize(0); + } + + void nextTriangle(const foug::stl::Triangle& triangle, foug::UInt16 attributeByteCount) + { + TriangleData data; + data.triangle = triangle; + data.attributeByteCount = attributeByteCount; + m_triangles.append(data); + } + + // -- foug::stl::bin::AbstractGeometryExtraData + + void getHeaderData(foug::stl::bin::Header& data) const + { + std::memcpy(data, m_header, 80); + } + + foug::UInt16 attributeByteCount(foug::UInt32 triangleIndex) const + { + return m_triangles[triangleIndex].attributeByteCount; + } + + // -- foug::stl::AbstractGeometry + + foug::UInt32 triangleCount() const + { + return m_triangles.size(); + } + + void getTriangle(foug::UInt32 index, foug::stl::Triangle* triangle) const + { + *triangle = m_triangles[index].triangle; + } + +private: + QVector m_triangles; + foug::stl::bin::Header m_header; +}; + +} // namespace internal + +int main(int argc, char** argv) +{ + using namespace foug::stl; + + QString inputFilePath; + QString outputFilePath; + int iarg = 1; + while (iarg < argc) { + if (!std::strcmp(argv[iarg], "-i")) + inputFilePath = argv[++iarg]; + else if (!std::strcmp(argv[iarg], "-o")) + outputFilePath = argv[++iarg]; + ++iarg; + } + + if (inputFilePath.isEmpty()) { + qCritical() << "No input files"; + return -1; + } + + bin::Io io; + // internal::ConsoleTaskProgress taskProgress; + // io.setTaskProgress(&taskProgress); + // io.setAutoDeleteTaskProgress(false); + +#ifdef USE_STDSTREAM + std::ifstream inputFile(inputFilePath.toStdString().c_str(), std::ios::binary); + if (!inputFile.is_open()) { + qCritical() << "Failed to open input file"; + return -2; + } + io.setStream(new foug::StdInputStream(&inputFile)); +#elif defined(USE_QT4STREAM) + QFile inputFile(inputFilePath); + if (!inputFile.open(QIODevice::ReadOnly)) { + qCritical() << "Failed to open input file :" << inputFile.errorString(); + return -2; + } + io.setStream(new foug::Qt4Stream(&inputFile)); +#endif + + { // BENCH READ + QTime time; + time.start(); + + internal::DummyGeometryBuilder geomBuilder; + const int benchCount = 100; + for (int i = 0; i < benchCount; ++i) { + io.stream()->seek(0); + io.read(&geomBuilder); + } + + qDebug() << QString("Total read time : %1sec").arg(time.elapsed() / 1000.); + qDebug() << QString("Test read time : %1sec") + .arg(time.elapsed() / 1000. / static_cast(benchCount)); + } + + if (outputFilePath.isEmpty()) + return 0; + +#ifdef USE_STDSTREAM + std::ofstream outputFile(outputFilePath.toStdString().c_str(), std::ios::out | std::ios::binary); + //std::ofstream outputFile(outputFilePath.toStdString().c_str(), std::ios::binary); + if (!outputFile.is_open()) { + qCritical() << "Failed to open output file"; + return -3; + } +#elif defined(USE_QT4STREAM) + QFile outputFile(outputFilePath); + if (!outputFile.open(QIODevice::WriteOnly)) { + qCritical() << "Failed to open output file :" << outputFile.errorString(); + return -3; + } +#endif + + internal::BasicGeometryHelper geomHelper; + { // READ GEOMETRY + io.stream()->seek(0); + io.read(&geomHelper); + } + + { // BENCH WRITE +#ifdef USE_STDSTREAM + io.setStream(new foug::StdOutputStream(&outputFile)); +#elif defined(USE_QT4STREAM) + io.setStream(new foug::Qt4Stream(&outputFile)); +#endif + + QTime time; + time.start(); + + const int benchCount = 100; + for (int i = 0; i < benchCount; ++i) { + io.stream()->seek(0); + io.write(geomHelper, &geomHelper); + } + + qDebug() << QString("Total write time : %1sec").arg(time.elapsed() / 1000.); + qDebug() << QString("Test write time : %1sec") + .arg(time.elapsed() / 1000. / static_cast(benchCount)); + } + + return 0; +}