/* * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) * * This file is part of Orfeo Toolbox * * https://www.orfeo-toolbox.org/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef mvdStream_h #define mvdStream_h // // Configuration include. //// Included at first position before any other ones. #include "ConfigureMonteverdi.h" #include "OTBMonteverdiCoreExport.h" /*****************************************************************************/ /* INCLUDE SECTION */ // // Qt includes (sorted by alphabetic order) //// Must be included before system/custom includes. #include // // System includes (sorted by alphabetic order) // // ITK includes (sorted by alphabetic order) #include "itkHistogram.h" #include "itkSize.h" // // OTB includes (sorted by alphabetic order) // // Monteverdi includes (sorted by alphabetic order) #include "mvdAlgorithm.h" #include "mvdSystemError.h" #include "mvdTypes.h" /*****************************************************************************/ /* PRE-DECLARATION SECTION */ // // External classes pre-declaration. namespace { } namespace mvd { /** * \brief TODO. */ enum StreamTag { STREAM_TAG_SIZE = 0, STREAM_TAG_VECTOR, STREAM_TAG_VARIABLE_LENGTH_VECTOR, // STREAM_TAG_COUNT }; /** * \brief TODO. */ extern const char* STREAM_TAG_NAMES[STREAM_TAG_COUNT]; // // Internal classes pre-declaration. } // end of namespace 'mvd'. /*****************************************************************************/ /* FUNCTIONS DECLARATION. */ /*****************************************************************************/ namespace mvd { /** * \brief Check status Qt stream and throw SystemError exception if * status is not Ok. */ inline void CheckStreamStatus(QTextStream& stream); /** * \brief Write a text tag followed by a white space to the stream. * * \param stream Stream to write into. * \param name Tag name to write. * \param enqueueWS Enqueue a whitespace following the tag name. * * \return stream instance. */ inline QTextStream& WriteStreamTag(QTextStream& stream, const QString& name, bool enqueueWS = true); /** * \brief Read a text tag followed by a whitespace from the stream and * check it against an expected value. * * \param stream Stream to read from. * \param tag Text tag which has been read. * \param expected The expected tag name. If non-empty, value read * from stream is checked against expected value; an * std::runtime_exception is thrown if both values doest not match. * \param skipWS Skip whitespace following tag name. * * \return stream instance. */ inline QTextStream& ReadStreamTag(QTextStream& stream, QString& tag, const QString& expected = QString(), bool skipWS = true); /*****************************************************************************/ /** * \brief Write an StreamTag followed by a whitespace separator into a * QTextStream. * * \param stream QTextStream into which to write data. * \param tag StreamTag data to write. * * \return stream instance. */ inline QTextStream& operator<<(QTextStream& stream, StreamTag tag); /** * \brief Read a StreamTag followed by a whitespace from a * QTextStream. * * \param stream QTextStream from which to read data. * \param tag StreamTag to data read. * * \return stream instance. */ inline QTextStream& operator>>(QTextStream& stream, StreamTag& tag); /*****************************************************************************/ /** * \brief Write an std::vector< T, std::allocator< T > > into a QTextStream. * * \param stream QTextStream into which to write data. * \param vector std::vector< T, std::allocator< T > > data to write. * * \return stream instance. */ template inline QTextStream& operator<<(QTextStream& stream, const std::vector>& vector); /** * \brief */ template <> inline QTextStream& operator<<(QTextStream& stream, const std::vector& vector); /** * \brief */ template <> inline QTextStream& operator<<(QTextStream& stream, const std::vector& vector); /** * \brief Read an std::vector< T, Alloc > from a QTextStream. * * \param stream QTextStream from which to read data. * \param vector std::vector< T, Alloc > container to read data into. * * \return stream instance. */ template inline QTextStream& operator>>(QTextStream& stream, std::vector& vector); /*****************************************************************************/ /** * \brief Write an itk::Array< T > into a QTextStream. * * \param stream QTextStream into which to write data. * \param array itk::Array< T > data to write. * * \return stream instance. */ template inline QTextStream& operator<<(QTextStream& stream, const itk::Array& array); /** * \brief Read an itk::Array< T > from a QTextStream. * * \param stream QTextStream from which to read data. * \param array itk::Array< T > container to read data into. * * \return stream instance. */ template inline QTextStream& operator>>(QTextStream& stream, itk::Array& array); /*****************************************************************************/ /** * \brief Write an itk::VariableLengthVector< T > into a QTextStream. * * \param stream QTextStream into which to write data. * \param vector itk::VariableLengthVector< T > data to write. * * \return stream instance. */ template inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector); /** */ template <> inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector); /** */ template <> inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector); /** * \brief Read an itk::VariableLengthVector< T > from a QTextStream. * * \param stream QTextStream from which to read data. * \param vector itk::VariableLengthVector< T > container to read data into. * * \return stream instance. */ template inline QTextStream& operator>>(QTextStream& stream, itk::VariableLengthVector& vector); /*****************************************************************************/ /** * \brief Write an itk::statistics::Histogram< T, FC > into a QTextStream. * * \param stream QTextStream into which to write data. * \param histogram itk::statistics::Histogram< T, FC > data to write. * * \return stream instance. */ template inline QTextStream& operator<<(QTextStream& stream, const itk::Statistics::Histogram& histogram); /** * \brief Read an itk::statistics::Histogram< T, FC > from a QTextStream. * * \param stream QTextStream from which to read data. * \param histogram itk::statistics::Histogram< T, FC > container to * read data into. * * \return stream instance. */ template inline QTextStream& operator>>(QTextStream& stream, itk::Statistics::Histogram& histogram); } // end namespace 'mvd'. /*****************************************************************************/ /* INLINE SECTION */ namespace mvd { /*******************************************************************************/ inline void CheckStreamStatus(QTextStream& stream) { if (stream.status() != QTextStream::Ok) throw SystemError(); } /*******************************************************************************/ inline QTextStream& WriteStreamTag(QTextStream& stream, const QString& name, bool queueWhiteSpace) { stream << name; if (queueWhiteSpace) stream << " "; CheckStreamStatus(stream); return stream; } /*******************************************************************************/ inline QTextStream& ReadStreamTag(QTextStream& stream, QString& name, const QString& expected, bool skipWhiteSpace) { stream >> name; if (skipWhiteSpace) stream >> ws; CheckStreamStatus(stream); if (!expected.isEmpty() && expected.compare(name, Qt::CaseInsensitive) != 0) { throw std::runtime_error( ToStdString(QCoreApplication::translate("mvd::TextStream", "Read tag '%1' does not match expected tag '%2'.").arg(name).arg(expected))); } return stream; } /*******************************************************************************/ inline QTextStream& operator<<(QTextStream& stream, StreamTag tag) { WriteStreamTag(stream, STREAM_TAG_NAMES[tag]); return stream; } /*******************************************************************************/ inline QTextStream& operator>>(QTextStream& stream, StreamTag& tag) { QString name; ReadStreamTag(stream, name); bool found = false; for (int i = 0; i < STREAM_TAG_COUNT && !found; ++i) { if (name.compare(STREAM_TAG_NAMES[i], Qt::CaseInsensitive) == 0) { found = true; tag = static_cast(i); } } if (!found) { throw std::runtime_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Invalid tag name '%1'.").arg(name))); } return stream; } /*******************************************************************************/ template inline QTextStream& operator<<(QTextStream& stream, const std::vector>& vector) { typedef std::vector> Vector; stream << STREAM_TAG_VECTOR << vector.size(); for (typename Vector::const_iterator it(vector.begin()); it != vector.end(); ++it) { stream << " " << *it; } return stream; } /*******************************************************************************/ template <> inline QTextStream& operator<<(QTextStream& stream, const std::vector& vector) { typedef std::vector> Vector; stream << STREAM_TAG_VECTOR << vector.size(); for (Vector::const_iterator it(vector.begin()); it != vector.end(); ++it) { stream << " " << ToQString(*it); } return stream; } /*******************************************************************************/ template <> inline QTextStream& operator<<(QTextStream& stream, const std::vector& vector) { typedef std::vector> Vector; stream << STREAM_TAG_VECTOR << vector.size(); for (Vector::const_iterator it(vector.begin()); it != vector.end(); ++it) { stream << " " << ToQString(*it); } return stream; } /*******************************************************************************/ template inline QTextStream& operator>>(QTextStream& stream, std::vector& vector) { typedef std::vector Vector; QString type; ReadStreamTag(stream, type, STREAM_TAG_NAMES[STREAM_TAG_VECTOR]); typename Vector::size_type size = 0; stream >> size; vector.resize(size); for (typename Vector::iterator it(vector.begin()); it != vector.end(); ++it) { stream >> ws >> *it; } return stream; } /*****************************************************************************/ template inline QTextStream& operator<<(QTextStream& stream, const itk::Array& array) { stream << STREAM_TAG_SIZE << array.GetSize(); CheckStreamStatus(stream); for (CountType i = 0; i < array.GetSize(); ++i) { stream << " " << array[i]; CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template inline QTextStream& operator>>(QTextStream& stream, itk::Array& array) { CountType dimension = 0; QString type; ReadStreamTag(stream, type, STREAM_TAG_NAMES[STREAM_TAG_SIZE]); stream >> dimension; if (dimension != array.GetSize()) { throw std::length_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Array dimension (%1) does not match " "expected dimension (%2).") .arg(dimension) .arg(array.GetSize()))); } for (CountType i = 0; i < array.GetSize(); ++i) { stream >> ws >> array[i]; CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector) { typedef typename itk::VariableLengthVector Vector; // Write number of elements. stream << STREAM_TAG_VARIABLE_LENGTH_VECTOR << vector.Size(); CheckStreamStatus(stream); // Write each element prefixed by a delimitting whitespace. for (typename Vector::ElementIdentifier i = 0; i < vector.Size(); ++i) { stream << " " << vector[i]; CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template <> inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector) { typedef itk::VariableLengthVector Vector; // Write number of elements. stream << STREAM_TAG_VARIABLE_LENGTH_VECTOR << vector.Size(); CheckStreamStatus(stream); // Write each element prefixed by a delimitting whitespace. for (Vector::ElementIdentifier i = 0; i < vector.Size(); ++i) { stream << " " << ToQString(vector[i]); CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template <> inline QTextStream& operator<<(QTextStream& stream, const itk::VariableLengthVector& vector) { typedef itk::VariableLengthVector Vector; // Write number of elements. stream << STREAM_TAG_VARIABLE_LENGTH_VECTOR << vector.Size(); CheckStreamStatus(stream); // Write each element prefixed by a delimitting whitespace. for (Vector::ElementIdentifier i = 0; i < vector.Size(); ++i) { stream << " " << ToQString(vector[i]); CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template inline QTextStream& operator>>(QTextStream& stream, itk::VariableLengthVector& vector) { typedef typename itk::VariableLengthVector Vector; QString type; ReadStreamTag(stream, type, STREAM_TAG_NAMES[STREAM_TAG_VARIABLE_LENGTH_VECTOR]); // Read number of elements. typename Vector::ElementIdentifier size = 0; stream >> size; CheckStreamStatus(stream); // Allocates vector elements. vector.SetSize(size); // Read each element prefixed by a delimitting whitespace. for (typename Vector::ElementIdentifier i = 0; i < vector.Size(); ++i) { stream >> ws >> vector[i]; CheckStreamStatus(stream); } return stream; } /*******************************************************************************/ template inline QTextStream& operator<<(QTextStream& stream, const itk::Statistics::Histogram& histogram) { typedef typename itk::Statistics::Histogram Histogram; WriteStreamTag(stream, "HISTOGRAM", false); stream << endl; WriteStreamTag(stream, "MEASUREMENT"); stream << histogram.GetSize() << endl; #if 1 WriteStreamTag(stream, "MINS"); stream << histogram.GetMins() << endl; WriteStreamTag(stream, "MAXS"); stream << histogram.GetMaxs() << endl; #endif #if 0 typename Histogram::SizeType size( histogram.GetSize() ); for( unsigned int dim=0; dim inline QTextStream& operator>>(QTextStream& stream, itk::Statistics::Histogram& histogram) { typedef itk::Statistics::Histogram Histogram; QString string; unsigned int N = histogram.GetMeasurementVectorSize(); // // Histogram section. ReadStreamTag(stream, string, "HISTOGRAM"); // // Measurement-size section. ReadStreamTag(stream, string, "MEASUREMENT"); typename Histogram::SizeType size; size.SetSize(N); stream >> size; // Dimension of size is checked in operator >> ( QTextStream&, // itk::Size< T > ). histogram.Initialize(size); #if 1 // // Bin mins. ReadStreamTag(stream, string, "MINS"); typename Histogram::BinMinContainerType mins; stream >> mins; // // Bin maxes. ReadStreamTag(stream, string, "MAXS"); typename Histogram::BinMaxContainerType maxs; stream >> maxs; if (mins.size() != N) { throw std::runtime_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Histogram mins dimension (%1) does not match " "expected dimension (%2).") .arg(mins.size()) .arg(N))); } if (maxs.size() != N) { throw std::runtime_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Histogram maxs dimension (%1) does not match " "expected dimension (%2).") .arg(maxs.size()) .arg(N))); } // // Initialize histogram mins & maxs within single pass. for (typename Histogram::BinMaxContainerType::size_type dim = 0; dim < maxs.size(); ++dim) { for (typename Histogram::BinMaxContainerType::value_type::size_type bin = 0; bin < maxs[dim].size(); ++bin) { histogram.SetBinMin(dim, bin, mins[dim][bin]); histogram.SetBinMax(dim, bin, maxs[dim][bin]); } } #endif #if 0 // // Bins. for( unsigned int dim=0; dim> d >> ws; CheckStreamStatus( stream ); if( d!=dim ) { throw std::runtime_error( ToStdString( QCoreApplication::translate( "mvd::TextStream", "Histogram dimension (%1) does not match " "expected dimension (%2)." ) .arg( d ) .arg( dim ) ) ); } // Bin. unsigned long b = 0; stream >> b >> ws; CheckStreamStatus( stream ); if( b!=bin ) { throw std::runtime_error( ToStdString( QCoreApplication::translate( "mvd::TextStream", "Histogram bin count (%1) does not match " "expected bin count (%2)." ) .arg( b ) .arg( bin ) ) ); } // Min. typename Histogram::BinMinContainerType::value_type::value_type min; stream >> min >> ws; CheckStreamStatus( stream ); histogram.SetBinMin( dim, bin, min ); // Max. typename Histogram::BinMaxContainerType::value_type::value_type max; stream >> max >> ws; CheckStreamStatus( stream ); histogram.SetBinMax( dim, bin, max ); // Frequency. typename Histogram::AbsoluteFrequencyType freq( 0 ); stream >> freq; CheckStreamStatus( stream ); typename Histogram::MeasurementType measurement( histogram.GetMeasurement( b, d ) ); typename Histogram::IndexType index( histogram.GetIndex( measurement ) ); histogram.SetFrequency( index, freq ); } } #else CountType samples = 0; ReadStreamTag(stream, string, "SAMPLES"); stream >> samples; CheckStreamStatus(stream); CountType space = histogram.Size(); if (samples != space) { throw std::runtime_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Histogram sample count (%1) does not match " "expected sample count (%2).") .arg(samples) .arg(space))); } CountType i = 0; for (; i < samples; ++i) { typename Histogram::InstanceIdentifier id(0); typename Histogram::AbsoluteFrequencyType freq(0); stream >> id >> ws >> freq; CheckStreamStatus(stream); histogram.SetFrequency(id, freq); } CountType count = 0; ReadStreamTag(stream, string, "COUNT"); stream >> count; CheckStreamStatus(stream); if (count != i) { throw std::runtime_error(ToStdString(QCoreApplication::translate("mvd::TextStream", "Read sample count (histogram) (%1) does not match " "written sample count (%2).") .arg(i) .arg(count))); } #endif return stream; } } // end namespace 'mvd' #endif // mvdStream_h