<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbImageKeywordlist.h"

#include <cassert>

#include "otbMacro.h"

#include "ossim/base/ossimKeywordlist.h"
#include "ossim/base/ossimString.h"
#include "ossim/ossimPluginProjectionFactory.h"
#include "ossim/imaging/ossimImageHandlerRegistry.h"
#include "ossim/ossimTileMapModel.h"
#include "ossim/projection/ossimProjectionFactoryRegistry.h"

#include "otbSensorModelAdapter.h"

namespace otb
{

ImageKeywordlist
::ImageKeywordlist()
{
}

ImageKeywordlist
::ImageKeywordlist(const Self& p) : m_Keywordlist(p.m_Keywordlist)
{
}

ImageKeywordlist
::~ImageKeywordlist()
{
}

void
ImageKeywordlist::
operator =(const Self& p)
{
  m_Keywordlist = p.m_Keywordlist;
}

void
ImageKeywordlist::
SetKeywordlist(const ossimKeywordlist& kwl)
{
  m_Keywordlist.clear();
  for (ossimKeywordlist::KeywordMap::const_iterator it = kwl.getMap().begin();
       it != kwl.getMap().end();
       ++it)
    {
    std::string first(it->first);
    std::string second(it->second);
    m_Keywordlist[first] = second;
    }
}

const std::string&
ImageKeywordlist::
GetMetadataByKey(const std::string& key) const
{
  // Search for the key in the output map
  KeywordlistMap::const_iterator it = m_Keywordlist.find(key);

  // If the key can not be found, throw an exception
  if (it == m_Keywordlist.end())
    {
    itkExceptionMacro(<< "Keywordlist has no output with key " << key);
    }

  // Then if everything is ok, return the ossinString
  return it->second;
}

bool
ImageKeywordlist::
HasKey(const std::string& key) const
{
  KeywordlistMap::const_iterator it = m_Keywordlist.find(key);
  return (it != m_Keywordlist.end());
}

void
ImageKeywordlist::
ClearMetadataByKey(const std::string& key)
{
  m_Keywordlist[key] = "";
}

void
ImageKeywordlist::
AddKey(const std::string& key, const std::string& value)
{
  m_Keywordlist[key] = value;
}

void
ImageKeywordlist::
convertToOSSIMKeywordlist(ossimKeywordlist& kwl) const
{
  ossimKeywordlist::KeywordMap ossimMap;
  for(KeywordlistMap::const_iterator it = m_Keywordlist.begin();
      it != m_Keywordlist.end();
      ++it)
    {
    ossimMap[it->first] = it->second;
    }
  kwl.getMap() = ossimMap;
}

void
ImageKeywordlist::
Print(std::ostream& os, itk::Indent indent) const
{
  this->PrintSelf(os, indent.GetNextIndent());
}

void
ImageKeywordlist::
PrintSelf(std::ostream& os, itk::Indent indent) const
{
  ossimKeywordlist kwl;
  convertToOSSIMKeywordlist(kwl);
  os << indent << " Ossim Keyword list:" << std::endl;
  os << indent << kwl;
}

std::ostream &
operator <<(std::ostream& os, const ImageKeywordlist& kwl)
{
  kwl.Print(os);
  return os;
}

ImageKeywordlist
ReadGeometry(const std::string& filename)
{
  return ReadGeometryFromImage(filename);
}

ImageKeywordlist
ReadGeometryFromImage(const std::string& filename)
{
  // Trying to read ossim MetaData
  bool             hasMetaData = false;
  ossimKeywordlist geom_kwl; // = new ossimKeywordlist();
  ImageKeywordlist otb_kwl;

  // Test the plugins factory
  /** Before, the pluginfactory was tested if the ossim one returned false.
      But in the case TSX, the images tif were considered as ossimQuickbirdTiffTileSource
      thus a TSX tif image wasn't read with TSX Model. We don't use the ossimRegisteryFactory
      because the default include factory contains ossimQuickbirdTiffTileSource. */
  ossimProjection * projection = ossimplugins::ossimPluginProjectionFactory::instance()
                                 ->createProjection(ossimFilename(filename.c_str()), 0);

  if (!projection)
    {
    otbMsgDevMacro(<< "OSSIM Instantiate projection FAILED ! ");
    }
  else
    {
    otbMsgDevMacro(<< "OSSIM Instantiate projection SUCCESS ! ");

    hasMetaData = projection->saveState(geom_kwl);
    otb_kwl.SetKeywordlist(geom_kwl);

    // Free memory
    delete projection;
    }

  if (!hasMetaData)
    {
    ossimImageHandler* handler = ossimImageHandlerRegistry::instance()
                                 ->open(ossimFilename(filename.c_str()));
    if (!handler)
      {
      otbMsgDevMacro(<< "OSSIM Open Image FAILED ! ");

      // In some corner cases, ossim is unable to create a ossimImageHandler
      // instance for the provided file.
      // This can happen for TIFF+geom files where the ossimTiffTileSource
      // fails when trying to open the TIFF file (for example
      // because ossim is compiled with a libtiff without BigTIFF support
      // and when the actual TIFF file exceeds the Large File limit).
      // In such cases, we don't actually need ossim to interpret the TIFF file,
      // and just want a valid ossimKeywordlist corresponding to a sensor model.

      // Here is implemented a shortcut used as a fallback scenario,
      // where we bypass the ossimImageHandlerRegistry
      // and directly create a ossimKeywordlist from the ".geom" file.

      // We then verify it is a valid sensor model by using otb::SensorModelAdapter
      // which uses ossimSensorModelFactory and ossimPluginProjectionFactory internally,
      // thus by-passing the need for a valid ossimImageHandler.

      // Try to find a ".geom" file next to 'filename'
      ossimFilename ossimGeomFile = ossimFilename(filename).setExtension(".geom");

      otb_kwl = ReadGeometryFromGEOMFile(ossimGeomFile);
      }
    else
      {
      otbMsgDevMacro(<< "OSSIM Open Image SUCCESS ! ");

      // Add ossimPlugins model
      ossimProjectionFactoryRegistry::instance()->registerFactory(ossimplugins::ossimPluginProjectionFactory::instance());

      //     hasMetaData = handler->getImageGeometry(geom_kwl);
      ossimRefPtr<ossimImageGeometry> geom = handler->getImageGeometry();

      if (geom.valid())
        {
        ossimProjection* projection = geom->getProjection();
        if (projection)
          {
          hasMetaData = projection->saveState(geom_kwl);
          otb_kwl.SetKeywordlist(geom_kwl);
          }
        }

      // If still no metadata, try the ".geom" file
      if (!hasMetaData && otb_kwl.GetSize() == 0)
        {
        ossimFilename ossimGeomFile = ossimFilename(filename).setExtension(".geom");
        otb_kwl = ReadGeometryFromGEOMFile(ossimGeomFile);
        }

      }
    // Free memory
    delete handler;
    }

  if (!hasMetaData)
    {
    otbMsgDevMacro(<< "OSSIM MetaData not present ! ");
    }
  else
    {
    otbMsgDevMacro(<< "OSSIM MetaData present ! ");
    otbMsgDevMacro(<< geom_kwl);
    }

  return otb_kwl;
}

ImageKeywordlist
ReadGeometryFromGEOMFile(const std::string& filename)
{
  ossimKeywordlist geom_kwl;
  ImageKeywordlist otb_kwl;
  ossimFilename ossimGeomFile = ossimFilename(filename);

  if (ossimGeomFile.exists() && ossimGeomFile.isFile())
    {
    // Interpret the geom file as a KWL
    ossimKeywordlist kwl(ossimGeomFile);

    // Check that the geom file results in a valid ossimKeywordlist
    if (kwl.getErrorStatus() == ossimErrorCodes::OSSIM_OK)
      {
//       // Be sure there is a corresponding instance of ossimSensorModel
//       // which understands this kwl
//       SensorModelAdapter::Pointer sensorModel = SensorModelAdapter::New();
//       ImageKeywordlist otbkwl;
//       otbkwl.SetKeywordlist(kwl);
//       sensorModel->CreateProjection(otbkwl);
//
//       if (sensorModel->IsValidSensorModel())
//         {
//         geom_kwl = kwl;
//         }
      geom_kwl = kwl;
      }
    }

  otb_kwl.SetKeywordlist(geom_kwl);

  return otb_kwl;
}

void
WriteGeometry(const ImageKeywordlist& otb_kwl, const std::string& filename)
{
  // Write the image keyword list if any
  ossimKeywordlist geom_kwl;
  otb_kwl.convertToOSSIMKeywordlist(geom_kwl);

  if (geom_kwl.getSize() > 0)
    {
    otbMsgDevMacro(<< "Exporting keywordlist ...");
    ossimFilename geomFileName(filename);
    geomFileName.setExtension(".geom");
    geom_kwl.write(geomFileName.chars());
    }
}

} //namespace otb
<commit_msg>ENH: OTB-608 : reading RPC coefficients in TIFF tag<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbImageKeywordlist.h"

#include <cassert>

#include "otbMacro.h"

#include "ossim/base/ossimKeywordlist.h"
#include "ossim/base/ossimString.h"
#include "ossim/ossimPluginProjectionFactory.h"
#include "ossim/imaging/ossimImageHandlerRegistry.h"
#include "ossim/ossimTileMapModel.h"
#include "ossim/projection/ossimProjectionFactoryRegistry.h"

#include "ossim/imaging/ossimTiffTileSource.h"
#include "ossim/projection/ossimRpcModel.h"
#include "tiffio.h"

#include "otbSensorModelAdapter.h"

namespace otb
{

ImageKeywordlist
::ImageKeywordlist()
{
}

ImageKeywordlist
::ImageKeywordlist(const Self& p) : m_Keywordlist(p.m_Keywordlist)
{
}

ImageKeywordlist
::~ImageKeywordlist()
{
}

void
ImageKeywordlist::
operator =(const Self& p)
{
  m_Keywordlist = p.m_Keywordlist;
}

void
ImageKeywordlist::
SetKeywordlist(const ossimKeywordlist& kwl)
{
  m_Keywordlist.clear();
  for (ossimKeywordlist::KeywordMap::const_iterator it = kwl.getMap().begin();
       it != kwl.getMap().end();
       ++it)
    {
    std::string first(it->first);
    std::string second(it->second);
    m_Keywordlist[first] = second;
    }
}

const std::string&
ImageKeywordlist::
GetMetadataByKey(const std::string& key) const
{
  // Search for the key in the output map
  KeywordlistMap::const_iterator it = m_Keywordlist.find(key);

  // If the key can not be found, throw an exception
  if (it == m_Keywordlist.end())
    {
    itkExceptionMacro(<< "Keywordlist has no output with key " << key);
    }

  // Then if everything is ok, return the ossinString
  return it->second;
}

bool
ImageKeywordlist::
HasKey(const std::string& key) const
{
  KeywordlistMap::const_iterator it = m_Keywordlist.find(key);
  return (it != m_Keywordlist.end());
}

void
ImageKeywordlist::
ClearMetadataByKey(const std::string& key)
{
  m_Keywordlist[key] = "";
}

void
ImageKeywordlist::
AddKey(const std::string& key, const std::string& value)
{
  m_Keywordlist[key] = value;
}

void
ImageKeywordlist::
convertToOSSIMKeywordlist(ossimKeywordlist& kwl) const
{
  ossimKeywordlist::KeywordMap ossimMap;
  for(KeywordlistMap::const_iterator it = m_Keywordlist.begin();
      it != m_Keywordlist.end();
      ++it)
    {
    ossimMap[it->first] = it->second;
    }
  kwl.getMap() = ossimMap;
}

void
ImageKeywordlist::
Print(std::ostream& os, itk::Indent indent) const
{
  this->PrintSelf(os, indent.GetNextIndent());
}

void
ImageKeywordlist::
PrintSelf(std::ostream& os, itk::Indent indent) const
{
  ossimKeywordlist kwl;
  convertToOSSIMKeywordlist(kwl);
  os << indent << " Ossim Keyword list:" << std::endl;
  os << indent << kwl;
}

std::ostream &
operator <<(std::ostream& os, const ImageKeywordlist& kwl)
{
  kwl.Print(os);
  return os;
}

ImageKeywordlist
ReadGeometry(const std::string& filename)
{
  return ReadGeometryFromImage(filename);
}

ImageKeywordlist
ReadGeometryFromImage(const std::string& filename)
{
  // Trying to read ossim MetaData
  bool             hasMetaData = false;
  ossimKeywordlist geom_kwl; // = new ossimKeywordlist();
  ImageKeywordlist otb_kwl;

  // Test the plugins factory
  /** Before, the pluginfactory was tested if the ossim one returned false.
      But in the case TSX, the images tif were considered as ossimQuickbirdTiffTileSource
      thus a TSX tif image wasn't read with TSX Model. We don't use the ossimRegisteryFactory
      because the default include factory contains ossimQuickbirdTiffTileSource. */
  ossimProjection * projection = ossimplugins::ossimPluginProjectionFactory::instance()
                                 ->createProjection(ossimFilename(filename.c_str()), 0);

  if (!projection)
    {
    otbMsgDevMacro(<< "OSSIM Instantiate projection FAILED ! ");
    }
  else
    {
    otbMsgDevMacro(<< "OSSIM Instantiate projection SUCCESS ! ");

    hasMetaData = projection->saveState(geom_kwl);
    otb_kwl.SetKeywordlist(geom_kwl);

    // Free memory
    delete projection;
    }

  if (!hasMetaData)
    {
    ossimImageHandler* handler = ossimImageHandlerRegistry::instance()
                                 ->open(ossimFilename(filename.c_str()));
    if (!handler)
      {
      otbMsgDevMacro(<< "OSSIM Open Image FAILED ! ");

      // In some corner cases, ossim is unable to create a ossimImageHandler
      // instance for the provided file.
      // This can happen for TIFF+geom files where the ossimTiffTileSource
      // fails when trying to open the TIFF file (for example
      // because ossim is compiled with a libtiff without BigTIFF support
      // and when the actual TIFF file exceeds the Large File limit).
      // In such cases, we don't actually need ossim to interpret the TIFF file,
      // and just want a valid ossimKeywordlist corresponding to a sensor model.

      // Here is implemented a shortcut used as a fallback scenario,
      // where we bypass the ossimImageHandlerRegistry
      // and directly create a ossimKeywordlist from the ".geom" file.

      // We then verify it is a valid sensor model by using otb::SensorModelAdapter
      // which uses ossimSensorModelFactory and ossimPluginProjectionFactory internally,
      // thus by-passing the need for a valid ossimImageHandler.

      // Try to find a ".geom" file next to 'filename'
      ossimFilename ossimGeomFile = ossimFilename(filename).setExtension(".geom");

      otb_kwl = ReadGeometryFromGEOMFile(ossimGeomFile);
      }
    else
      {
      otbMsgDevMacro(<< "OSSIM Open Image SUCCESS ! ");

      // Add ossimPlugins model
      ossimProjectionFactoryRegistry::instance()->registerFactory(ossimplugins::ossimPluginProjectionFactory::instance());

      //     hasMetaData = handler->getImageGeometry(geom_kwl);
      ossimRefPtr<ossimImageGeometry> geom = handler->getImageGeometry();

      if (geom.valid())
        {
        ossimProjection* projection = geom->getProjection();
        if (projection)
          {
          hasMetaData = projection->saveState(geom_kwl);
          otb_kwl.SetKeywordlist(geom_kwl);
          }
        }

      //  try to use GeoTiff RPC tag if present. They will override the
      // standard projection found before
      ossimRefPtr<ossimTiffTileSource> tiffHandler = new ossimTiffTileSource;
      tiffHandler->setOpenOverviewFlag(true);
      if ( tiffHandler->open(handler->getFilename()) )
        {
        TIFF* tiffPtr = tiffHandler->tiffPtr();
        unsigned short  count     = 0;
        void            *tagData  = 0;

        if (TIFFGetField( tiffPtr, 50844, &count, &tagData) && (count == 92) )
          {
          otbMsgDevMacro(<<"RPC Coeff tag found");
          // read RPC coefficients
          double *tagValues = static_cast<double*>(tagData);

          std::vector<double> lineNumCoefs;
          std::vector<double> lineDenCoefs;
          std::vector<double> sampNumCoefs;
          std::vector<double> sampDenCoefs;

          for (unsigned int k=0 ; k<20 ; ++k)
            {
            lineNumCoefs.push_back(*(tagValues + 12 + k));
            lineDenCoefs.push_back(*(tagValues + 32 + k));
            sampNumCoefs.push_back(*(tagValues + 52 + k));
            sampDenCoefs.push_back(*(tagValues + 72 + k));
            }

          ossimRefPtr<ossimRpcModel> rpcModel = new ossimRpcModel;
          rpcModel->setAttributes( *(tagValues + 3),
                                   *(tagValues + 2),
                                   *(tagValues + 8),
                                   *(tagValues + 7),
                                   *(tagValues + 4),
                                   *(tagValues + 5),
                                   *(tagValues + 6),
                                   *(tagValues + 9),
                                   *(tagValues + 10),
                                   *(tagValues + 11),
                                   sampNumCoefs,
                                   sampDenCoefs,
                                   lineNumCoefs,
                                   lineDenCoefs);

          double errorBias = 0.0;
          double errorRand = 0.0;
          if (*(tagValues) >= 0.0) errorBias = *(tagValues);
          if (*(tagValues+1) >= 0.0) errorRand = *(tagValues+1);

          // setup other metadata
          rpcModel->setPositionError(errorBias,errorRand,true);
          ossimDrect rectangle = tiffHandler->getImageRectangle();
          rpcModel->setImageRect(rectangle);

          ossimDpt size;
          size.line = rectangle.height();
          size.samp = rectangle.width();
          rpcModel->setImageSize(size);

          // Compute 4 corners and reference point
          rpcModel->updateModel();
          double heightOffset = *(tagValues + 6);
          ossimGpt ulGpt, urGpt, lrGpt, llGpt;
          ossimGpt refGndPt;

          rpcModel->lineSampleHeightToWorld(rectangle.ul(), heightOffset, ulGpt);
          rpcModel->lineSampleHeightToWorld(rectangle.ur(), heightOffset, urGpt);
          rpcModel->lineSampleHeightToWorld(rectangle.lr(), heightOffset, lrGpt);
          rpcModel->lineSampleHeightToWorld(rectangle.ll(), heightOffset, llGpt);
          rpcModel->setGroundRect(ulGpt,urGpt,lrGpt,llGpt);

          rpcModel->lineSampleHeightToWorld(rectangle.midPoint(), heightOffset, refGndPt);
          rpcModel->setRefGndPt(refGndPt);

          // compute ground sampling distance
          try
            {
            // Method can throw ossimException.
            rpcModel->computeGsd();
            }
          catch (const ossimException& e)
            {
            otbMsgDevMacro(<< "OSSIM Compute ground sampling distance FAILED ! ");
            }

          hasMetaData = rpcModel->saveState(geom_kwl);
          otb_kwl.SetKeywordlist(geom_kwl);
          }
        }

      // If still no metadata, try the ".geom" file
      if (!hasMetaData && otb_kwl.GetSize() == 0)
        {
        ossimFilename ossimGeomFile = ossimFilename(filename).setExtension(".geom");
        otb_kwl = ReadGeometryFromGEOMFile(ossimGeomFile);
        }

      }
    // Free memory
    delete handler;
    }

  if (!hasMetaData)
    {
    otbMsgDevMacro(<< "OSSIM MetaData not present ! ");
    }
  else
    {
    otbMsgDevMacro(<< "OSSIM MetaData present ! ");
    otbMsgDevMacro(<< geom_kwl);
    }

  return otb_kwl;
}

ImageKeywordlist
ReadGeometryFromGEOMFile(const std::string& filename)
{
  ossimKeywordlist geom_kwl;
  ImageKeywordlist otb_kwl;
  ossimFilename ossimGeomFile = ossimFilename(filename);

  if (ossimGeomFile.exists() && ossimGeomFile.isFile())
    {
    // Interpret the geom file as a KWL
    ossimKeywordlist kwl(ossimGeomFile);

    // Check that the geom file results in a valid ossimKeywordlist
    if (kwl.getErrorStatus() == ossimErrorCodes::OSSIM_OK)
      {
//       // Be sure there is a corresponding instance of ossimSensorModel
//       // which understands this kwl
//       SensorModelAdapter::Pointer sensorModel = SensorModelAdapter::New();
//       ImageKeywordlist otbkwl;
//       otbkwl.SetKeywordlist(kwl);
//       sensorModel->CreateProjection(otbkwl);
//
//       if (sensorModel->IsValidSensorModel())
//         {
//         geom_kwl = kwl;
//         }
      geom_kwl = kwl;
      }
    }

  otb_kwl.SetKeywordlist(geom_kwl);

  return otb_kwl;
}

void
WriteGeometry(const ImageKeywordlist& otb_kwl, const std::string& filename)
{
  // Write the image keyword list if any
  ossimKeywordlist geom_kwl;
  otb_kwl.convertToOSSIMKeywordlist(geom_kwl);

  if (geom_kwl.getSize() > 0)
    {
    otbMsgDevMacro(<< "Exporting keywordlist ...");
    ossimFilename geomFileName(filename);
    geomFileName.setExtension(".geom");
    geom_kwl.write(geomFileName.chars());
    }
}

} //namespace otb
<|endoftext|>


<commit_before>#include "creader.h"
#include "../parser/cfiledecoder.h"
#include "../parser/ctextparser.h"
#include "settings/csettings.h"
#include "settings.h"
#include "assert/advanced_assert.h"

#include <math.h>

#include <algorithm>
#include <map>
#include <iterator>

CReader::CReader(ReaderInterface* interface) : _interface(interface)
{
	assert_r(_interface);

	_readingTimer.setSingleShot(true);
	QObject::connect(&_readingTimer, &QTimer::timeout, [this](){
		readNextFragment();
	});

	_speedWpm = CSettings().value(READER_READING_SPEED_SETTING, READER_READING_SPEED_DEFAULT).toUInt();
}

void CReader::load(const std::vector<TextFragment>& textFragments)
{
	resetAndStop();

	_textFragments.clear();
	std::transform(textFragments.cbegin(), textFragments.cend(), std::back_inserter(_textFragments), [this](const TextFragment& fragment) -> TextFragmentWithPause {
		return TextFragmentWithPause{fragment, 0};
	});

	updatePauseValues();
}

bool CReader::loadFromFile(const QString& filePath)
{
	CTextParser parser;
	parser.setAddEmptyFragmentAfterSentence(_clearScreenAfterSentenceEnd);
	load(parser.parse(CFileDecoder::readDataAndDecodeText(filePath)));

	if (!_textFragments.empty())
	{
		_filePath = filePath;
		return true;
	}
	else
		return false;
}

void CReader::setClearScreenAfterSentenceEnd(bool clear)
{
	_clearScreenAfterSentenceEnd = clear;
}

void CReader::setLongWordPauseScaling(unsigned lengthThreshold, float scaleFactor)
{
	if (lengthThreshold != _longWordThreshold || scaleFactor != _longWordDelayScaleFactor)
	{
		_longWordThreshold = lengthThreshold;
		_longWordDelayScaleFactor = scaleFactor;

		updatePauseValues();
	}
}

CReader::State CReader::state() const
{
	return _state;
}

QString CReader::filePath() const
{
	return _filePath;
}

size_t CReader::position() const
{
	return _position;
}

long double CReader::progress() const
{
	const size_t numWords = _textFragments.size();
	return numWords ? _position / (long double)numWords : 0.0;
}

size_t CReader::timeRemainingSeconds() const
{
	//const float basePausePerWordSeconds = 60.0f / _speedWpm;
	//const float theoreticalSeconds = (_textFragments.size() - _position) * basePausePerWordSeconds;
	const float actualSeconds = std::accumulate(_textFragments.cbegin() + _position, _textFragments.cend(), 0.0f, [](float acc, const TextFragmentWithPause& fragment) {
		return acc + fragment._pauseAfter / 1000.0f;
	});

	//const size_t actualWPM = (size_t)(60 * _textFragments.size() / actualSeconds);

	return (size_t)ceilf(actualSeconds);
}

void CReader::updateInterface() const
{
	_interface->stateChanged(_state);
	_interface->updateDisplay(_position);
}

size_t CReader::totalNumWords() const
{
	return _textFragments.size();
}

void CReader::resumeReading()
{
	_state = Reading;
	_interface->stateChanged(_state);
	readNextFragment();
}

void CReader::pauseReading()
{
	_readingTimer.stop();

	_state = Paused;
	_interface->stateChanged(_state);
}

void CReader::togglePause()
{
	if (_state == Reading)
		pauseReading();
	else
		resumeReading();
}

void CReader::resetAndStop()
{
	pauseReading();
	_position = 0;
	_interface->updateInfo();
}

void CReader::goToWord(size_t wordIndex)
{
	_position = wordIndex;
	_interface->updateDisplay(_position);
	_interface->updateInfo();
}

size_t CReader::readingSpeed() const
{
	return _speedWpm;
}

void CReader::setReadingSpeed(size_t wpm)
{
	CSettings().setValue(READER_READING_SPEED_SETTING, (quint64)wpm);
	_speedWpm = wpm;
	updatePauseValues();
}

void CReader::readNextFragment()
{
	if (_position >= _textFragments.size())
	{
		resetAndStop();
	}
	else if (_state == Reading)
	{
		_interface->updateDisplay(_position);
		_interface->updateInfo();
		// Queue up the next word
		_readingTimer.start(_textFragments[_position]._pauseAfter);
		++_position;
	}
}

// Calculates the pause after the specific fragment in ms
size_t CReader::pauseForFragment(const TextFragment& fragment) const
{
	static const std::map<TextFragment::Delimiter, float /*pauseCoefficient*/> pauseForDelimiter {
		{TextFragment::NoDelimiter, 0.0f},
		{TextFragment::Space, 0.88f},
		{TextFragment::Comma, 1.5f},
		{TextFragment::Point, 2.1f},
		{TextFragment::ExclamationMark, 2.1f},
		{TextFragment::QuestionMark, 2.1f},
		{TextFragment::Dash, 1.5f},
		{TextFragment::Colon, 1.8f},
		{TextFragment::Semicolon, 2.1f},
		{TextFragment::Ellipsis, 2.8f},
		{TextFragment::Bracket, 1.5f},
		{TextFragment::Quote, 1.5f},
		{TextFragment::Newline, 0.88f} // All too often TXT files have new lines for line with formatting rather than for actual semantical formatting, so it's best to read them same as space
	};

	const auto it = pauseForDelimiter.find(fragment.delimiter());
	assert(it != pauseForDelimiter.end());

	const float basePause = 60e3f / _speedWpm;
	const unsigned wordLength = (unsigned)fragment.word().length();
	return (size_t)round(it->second * basePause * (wordLength > _longWordThreshold ? (wordLength - _longWordThreshold) * _longWordDelayScaleFactor : 1.0f));
}

// Recalculate all the pauses for the entire text
void CReader::updatePauseValues()
{
	for (auto& fragment: _textFragments)
		fragment._pauseAfter = pauseForFragment(fragment._textFragment);

	_interface->updateInfo();
}<commit_msg>Index validation added to CReader::goToWord<commit_after>#include "creader.h"
#include "../parser/cfiledecoder.h"
#include "../parser/ctextparser.h"
#include "settings/csettings.h"
#include "settings.h"
#include "assert/advanced_assert.h"

#include <math.h>

#include <algorithm>
#include <map>
#include <iterator>

DISABLE_COMPILER_WARNINGS
#include <QDebug>
#include <QTime>
RESTORE_COMPILER_WARNINGS

CReader::CReader(ReaderInterface* interface) : _interface(interface)
{
	assert_r(_interface);

	_readingTimer.setSingleShot(true);
	QObject::connect(&_readingTimer, &QTimer::timeout, [this](){
		readNextFragment();
	});

	_speedWpm = CSettings().value(READER_READING_SPEED_SETTING, READER_READING_SPEED_DEFAULT).toUInt();
}

void CReader::load(const std::vector<TextFragment>& textFragments)
{
	resetAndStop();

	_textFragments.clear();
	std::transform(textFragments.cbegin(), textFragments.cend(), std::back_inserter(_textFragments), [this](const TextFragment& fragment) -> TextFragmentWithPause {
		return TextFragmentWithPause{fragment, 0};
	});

	updatePauseValues();
}

bool CReader::loadFromFile(const QString& filePath)
{
	CTextParser parser;
	parser.setAddEmptyFragmentAfterSentence(_clearScreenAfterSentenceEnd);

	QTime timer;
	timer.start();
	load(parser.parse(CFileDecoder::readDataAndDecodeText(filePath)));
	qDebug() << "Parsing" << filePath << "took" << QString::number(timer.elapsed() / 1000.0f, 'f', 1) << "seconds";

	if (!_textFragments.empty())
	{
		_filePath = filePath;
		return true;
	}
	else
		return false;
}

void CReader::setClearScreenAfterSentenceEnd(bool clear)
{
	_clearScreenAfterSentenceEnd = clear;
}

void CReader::setLongWordPauseScaling(unsigned lengthThreshold, float scaleFactor)
{
	if (lengthThreshold != _longWordThreshold || scaleFactor != _longWordDelayScaleFactor)
	{
		_longWordThreshold = lengthThreshold;
		_longWordDelayScaleFactor = scaleFactor;

		updatePauseValues();
	}
}

CReader::State CReader::state() const
{
	return _state;
}

QString CReader::filePath() const
{
	return _filePath;
}

size_t CReader::position() const
{
	return _position;
}

long double CReader::progress() const
{
	const size_t numWords = _textFragments.size();
	return numWords ? _position / (long double)numWords : 0.0;
}

size_t CReader::timeRemainingSeconds() const
{
	//const float basePausePerWordSeconds = 60.0f / _speedWpm;
	//const float theoreticalSeconds = (_textFragments.size() - _position) * basePausePerWordSeconds;
	const float actualSeconds = std::accumulate(_textFragments.cbegin() + _position, _textFragments.cend(), 0.0f, [](float acc, const TextFragmentWithPause& fragment) {
		return acc + fragment._pauseAfter / 1000.0f;
	});

	//const size_t actualWPM = (size_t)(60 * _textFragments.size() / actualSeconds);

	return (size_t)ceilf(actualSeconds);
}

void CReader::updateInterface() const
{
	_interface->stateChanged(_state);
	_interface->updateDisplay(_position);
}

size_t CReader::totalNumWords() const
{
	return _textFragments.size();
}

void CReader::resumeReading()
{
	_state = Reading;
	_interface->stateChanged(_state);
	readNextFragment();
}

void CReader::pauseReading()
{
	_readingTimer.stop();

	_state = Paused;
	_interface->stateChanged(_state);
}

void CReader::togglePause()
{
	if (_state == Reading)
		pauseReading();
	else
		resumeReading();
}

void CReader::resetAndStop()
{
	pauseReading();
	_position = 0;
	_interface->updateInfo();
}

void CReader::goToWord(size_t wordIndex)
{
	if (_position >= _textFragments.size())
		return;

	_position = wordIndex;
	_interface->updateDisplay(_position);
	_interface->updateInfo();
}

size_t CReader::readingSpeed() const
{
	return _speedWpm;
}

void CReader::setReadingSpeed(size_t wpm)
{
	CSettings().setValue(READER_READING_SPEED_SETTING, (quint64)wpm);
	_speedWpm = wpm;
	updatePauseValues();
}

void CReader::readNextFragment()
{
	if (_position >= _textFragments.size())
	{
		resetAndStop();
	}
	else if (_state == Reading)
	{
		_interface->updateDisplay(_position);
		_interface->updateInfo();
		// Queue up the next word
		_readingTimer.start(_textFragments[_position]._pauseAfter);
		++_position;
	}
}

// Calculates the pause after the specific fragment in ms
size_t CReader::pauseForFragment(const TextFragment& fragment) const
{
	static const std::map<TextFragment::Delimiter, float /*pauseCoefficient*/> pauseForDelimiter {
		{TextFragment::NoDelimiter, 0.0f},
		{TextFragment::Space, 0.88f},
		{TextFragment::Comma, 1.5f},
		{TextFragment::Point, 2.1f},
		{TextFragment::ExclamationMark, 2.1f},
		{TextFragment::QuestionMark, 2.1f},
		{TextFragment::Dash, 1.5f},
		{TextFragment::Colon, 1.8f},
		{TextFragment::Semicolon, 2.1f},
		{TextFragment::Ellipsis, 2.8f},
		{TextFragment::Bracket, 1.5f},
		{TextFragment::Quote, 1.5f},
		{TextFragment::Newline, 0.88f} // All too often TXT files have new lines for line with formatting rather than for actual semantical formatting, so it's best to read them same as space
	};

	const auto it = pauseForDelimiter.find(fragment.delimiter());
	assert(it != pauseForDelimiter.end());

	const float basePause = 60e3f / _speedWpm;
	const unsigned wordLength = (unsigned)fragment.word().length();
	return (size_t)round(it->second * basePause * (wordLength > _longWordThreshold ? (wordLength - _longWordThreshold) * _longWordDelayScaleFactor : 1.0f));
}

// Recalculate all the pauses for the entire text
void CReader::updatePauseValues()
{
	for (auto& fragment: _textFragments)
		fragment._pauseAfter = pauseForFragment(fragment._textFragment);

	_interface->updateInfo();
}<|endoftext|>


<commit_before>/** \file    rewrite_keywords_and_authors_from_authority_data
 *  \brief   Update fields with references to authority data with potentially
             more current authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

namespace {

unsigned int record_count;
unsigned int modified_count;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--input-format=(marc-21|marc-xml)] master_marc_input authority_data_marc_input.mrc marc_output\n"
                           << "The Authority data must be in the MARC-21 format.\n";
    std::exit(EXIT_FAILURE);
}

// Create a list of PPNs and File Offsets
void CreateAuthorityOffsets(MARC::Reader * const authority_reader, std::map<std::string, off_t> * const authority_offsets) {
   off_t record_offset(authority_reader->tell());
   while (const MARC::Record record = authority_reader->read()) {
      authority_offsets->emplace(record.getControlNumber(), record_offset);
      // Shift to next record
      record_offset = authority_reader->tell();
   }
}

// Return the first matching primary field (Vorzugsbenennung) from authority data
// This implicitly assumes that the correct tag can be uniquely identified from the PPN
MARC::Record::const_iterator GetFirstPrimaryField(const MARC::Record& authority_record) {
     const std::vector<std::string> tags_to_check {"100", "151", "150", "110", "111", "130", "153"} ;
     for (const auto &tag_to_check : tags_to_check) {
         MARC::Record::const_iterator primary_field(authority_record.findTag(tag_to_check));
         if (primary_field != authority_record.end())
             return primary_field;
     }
     return authority_record.end();
}

bool GetAuthorityRecordFromPPN(const std::string &bsz_authority_ppn, MARC::Record * const authority_record, MARC::Reader * const authority_reader,
                               const std::map<std::string, off_t> &authority_offsets)
{
    auto authority_offset(authority_offsets.find(bsz_authority_ppn));
    if (authority_offset != authority_offsets.end()) {
        off_t authority_record_offset(authority_offset->second);
        if (authority_reader->seek(authority_record_offset)) {
            *authority_record = authority_reader->read();
            if (authority_record->getControlNumber() != bsz_authority_ppn)
                LOG_ERROR("We got a wrong PPN " + authority_record->getControlNumber() +
                          " instead of " + bsz_authority_ppn);
            else
                return true;
        } else
            LOG_ERROR("Unable to seek to record for authority PPN " + bsz_authority_ppn);
    } else {
        LOG_WARNING("Unable to find offset for authority PPN " + bsz_authority_ppn);
        return false;
    }
    std::runtime_error("Logical flaw in GetAuthorityRecordFromPPN");
}

void UpdateTitleField(MARC::Record::Field * const field, const MARC::Record authority_record) {
     auto authority_primary_field(GetFirstPrimaryField(authority_record));
     if (authority_primary_field == authority_record.end())
         LOG_ERROR("Could not find appropriate Tag for authority PPN " + authority_record.getControlNumber());
     MARC::Subfields subfields(field->getSubfields());
     // We have to make sure that the order of the subfields is inherited from the authority data
     // so delete the subfields to be replaced first
     for (auto &authority_subfield : authority_primary_field->getSubfields())
	  subfields.deleteAllSubfieldsWithCode(authority_subfield.code_);
     for (auto &authority_subfield : authority_primary_field->getSubfields())
          subfields.appendSubfield(authority_subfield.code_, authority_subfield.value_);
     field->setContents(subfields, field->getIndicator1(), field->getIndicator2());
}

void AugmentAuthors(MARC::Record * const record, MARC::Reader * const authority_reader, const std::map<std::string, off_t> &authority_offsets,
                    RegexMatcher * const matcher, bool * const modified_record)
{
    std::vector<std::string> tags_to_check({"100", "110", "111", "700", "710", "711"});
    for (auto tag_to_check : tags_to_check) {
        for (auto &field : record->getTagRange(tag_to_check)) {
            std::string _author_content(field.getContents());
            if (matcher->matched(_author_content)) {
                MARC::Record authority_record(std::string(MARC::Record::LEADER_LENGTH, ' '));
                if (GetAuthorityRecordFromPPN((*matcher)[1], &authority_record, authority_reader, authority_offsets)) {
                    UpdateTitleField(&field, authority_record);
                    *modified_record = true;
                }
            }
        }
    }
}

void AugmentKeywords(MARC::Record * const record, MARC::Reader * const authority_reader, const std::map<std::string, off_t> &authority_offsets,
                    RegexMatcher * const matcher, bool * const modified_record)
{
    for (auto &field : record->getTagRange("689")) {
        std::string _689_content(field.getContents());
        if (matcher->matched(_689_content)) {
             MARC::Record authority_record(std::string(MARC::Record::LEADER_LENGTH, ' '));
             if (GetAuthorityRecordFromPPN((*matcher)[1], &authority_record, authority_reader, authority_offsets)) {
                 UpdateTitleField(&field, authority_record);
                 *modified_record = true;
             }
        }
    }
}

void AugmentKeywordsAndAuthors(MARC::Reader * const marc_reader, MARC::Reader * const authority_reader, MARC::Writer * const marc_writer,
                               const std::map<std::string, off_t>& authority_offsets) {
    std::string err_msg;
    RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("\x1F""0\\(DE-576\\)([^\x1F]+).*\x1F?", &err_msg));

    if (matcher == nullptr)
        LOG_ERROR("Failed to compile standardized keywords regex matcher: " + err_msg);

    while (MARC::Record record = marc_reader->read()) {
       ++record_count;
       bool modified_record(false);
       AugmentAuthors(&record, authority_reader, authority_offsets, matcher, &modified_record);
       AugmentKeywords(&record, authority_reader, authority_offsets, matcher, &modified_record);
       modified_count = modified_record ? ++modified_count : modified_count;
       marc_writer->write(record);
    }
}

} // unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4 and argc != 5)
        Usage();

    MARC::FileType reader_type(MARC::FileType::AUTO);
    if (argc == 5) {
        if (std::strcmp(argv[1], "--input-format=marc-21") == 0)
            reader_type = MARC::FileType::BINARY;
        else if (std::strcmp(argv[1], "--input-format=marc-xml") == 0)
            reader_type = MARC::FileType::XML;
        else
            Usage();
        ++argv, --argc;
    }

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        LOG_ERROR("Authority data input file name equals output file name!");

    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, reader_type));
        std::unique_ptr<MARC::Reader> authority_reader(MARC::Reader::Factory(authority_data_marc_input_filename,
                                                                             MARC::FileType::BINARY));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename));
        std::map<std::string, off_t> authority_offsets;

        CreateAuthorityOffsets(authority_reader.get(), &authority_offsets);
        AugmentKeywordsAndAuthors(marc_reader.get(), authority_reader.get(), marc_writer.get(), authority_offsets);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";

    return 0;
}

<commit_msg>Adding special logic for worktitle keywords<commit_after>/** \file    rewrite_keywords_and_authors_from_authority_data
 *  \brief   Update fields with references to authority data with potentially
             more current authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

namespace {

unsigned int record_count;
unsigned int modified_count;

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--input-format=(marc-21|marc-xml)] master_marc_input authority_data_marc_input.mrc marc_output\n"
                           << "The Authority data must be in the MARC-21 format.\n";
    std::exit(EXIT_FAILURE);
}

// Create a list of PPNs and File Offsets
void CreateAuthorityOffsets(MARC::Reader * const authority_reader, std::map<std::string, off_t> * const authority_offsets) {
   off_t record_offset(authority_reader->tell());
   while (const MARC::Record record = authority_reader->read()) {
      authority_offsets->emplace(record.getControlNumber(), record_offset);
      // Shift to next record
      record_offset = authority_reader->tell();
   }
}

// Return the first matching primary field (Vorzugsbenennung) from authority data
// This implicitly assumes that the correct tag can be uniquely identified from the PPN
MARC::Record::const_iterator GetFirstPrimaryField(const MARC::Record& authority_record) {
     const std::vector<std::string> tags_to_check {"100", "151", "150", "110", "111", "130", "153"} ;
     for (const auto &tag_to_check : tags_to_check) {
         MARC::Record::const_iterator primary_field(authority_record.findTag(tag_to_check));
         if (primary_field != authority_record.end())
             return primary_field;
     }
     return authority_record.end();
}

bool GetAuthorityRecordFromPPN(const std::string &bsz_authority_ppn, MARC::Record * const authority_record, MARC::Reader * const authority_reader,
                               const std::map<std::string, off_t> &authority_offsets)
{
    auto authority_offset(authority_offsets.find(bsz_authority_ppn));
    if (authority_offset != authority_offsets.end()) {
        off_t authority_record_offset(authority_offset->second);
        if (authority_reader->seek(authority_record_offset)) {
            *authority_record = authority_reader->read();
            if (authority_record->getControlNumber() != bsz_authority_ppn)
                LOG_ERROR("We got a wrong PPN " + authority_record->getControlNumber() +
                          " instead of " + bsz_authority_ppn);
            else
                return true;
        } else
            LOG_ERROR("Unable to seek to record for authority PPN " + bsz_authority_ppn);
    } else {
        LOG_WARNING("Unable to find offset for authority PPN " + bsz_authority_ppn);
        return false;
    }
    std::runtime_error("Logical flaw in GetAuthorityRecordFromPPN");
}

bool IsWorkTitleField(MARC::Subfields &subfields) {
    return subfields.hasSubfieldWithValue('D', "u");
}

void UpdateTitleField(MARC::Record::Field * const field, const MARC::Record authority_record) {
    auto authority_primary_field(GetFirstPrimaryField(authority_record));
    if (authority_primary_field == authority_record.end())
        LOG_ERROR("Could not find appropriate Tag for authority PPN " + authority_record.getControlNumber());
    MARC::Subfields subfields(field->getSubfields());
    // We have to make sure that the order of the subfields is inherited from the authority data
    // so delete the subfields to be replaced first
    // Moreover there is a special case with "Werktitel". These are in $a
    // in the authority data but must be mapped to $t in the title data
    for (auto &authority_subfield : authority_primary_field->getSubfields()) {
        if (IsWorkTitleField(subfields) and authority_subfield.code_ == 'a')
            subfields.deleteAllSubfieldsWithCode('t');
        else
            subfields.deleteAllSubfieldsWithCode(authority_subfield.code_);
    }
    for (auto &authority_subfield : authority_primary_field->getSubfields()){
        if (IsWorkTitleField(subfields) and authority_subfield.code_ == 'a')
            subfields.appendSubfield('t', authority_subfield.value_);
        else
            subfields.appendSubfield(authority_subfield.code_, authority_subfield.value_);
    }
    field->setContents(subfields, field->getIndicator1(), field->getIndicator2());
}

void AugmentAuthors(MARC::Record * const record, MARC::Reader * const authority_reader, const std::map<std::string, off_t> &authority_offsets,
                    RegexMatcher * const matcher, bool * const modified_record)
{
    std::vector<std::string> tags_to_check({"100", "110", "111", "700", "710", "711"});
    for (auto tag_to_check : tags_to_check) {
        for (auto &field : record->getTagRange(tag_to_check)) {
            std::string _author_content(field.getContents());
            if (matcher->matched(_author_content)) {
                MARC::Record authority_record(std::string(MARC::Record::LEADER_LENGTH, ' '));
                if (GetAuthorityRecordFromPPN((*matcher)[1], &authority_record, authority_reader, authority_offsets)) {
                    UpdateTitleField(&field, authority_record);
                    *modified_record = true;
                }
            }
        }
    }
}

void AugmentKeywords(MARC::Record * const record, MARC::Reader * const authority_reader, const std::map<std::string, off_t> &authority_offsets,
                    RegexMatcher * const matcher, bool * const modified_record)
{
    for (auto &field : record->getTagRange("689")) {
        std::string _689_content(field.getContents());
        if (matcher->matched(_689_content)) {
             MARC::Record authority_record(std::string(MARC::Record::LEADER_LENGTH, ' '));
             if (GetAuthorityRecordFromPPN((*matcher)[1], &authority_record, authority_reader, authority_offsets)) {
                 UpdateTitleField(&field, authority_record);
                 *modified_record = true;
             }
        }
    }
}

void AugmentKeywordsAndAuthors(MARC::Reader * const marc_reader, MARC::Reader * const authority_reader, MARC::Writer * const marc_writer,
                               const std::map<std::string, off_t>& authority_offsets) {
    std::string err_msg;
    RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("\x1F""0\\(DE-576\\)([^\x1F]+).*\x1F?", &err_msg));

    if (matcher == nullptr)
        LOG_ERROR("Failed to compile standardized keywords regex matcher: " + err_msg);

    while (MARC::Record record = marc_reader->read()) {
       ++record_count;
       bool modified_record(false);
       AugmentAuthors(&record, authority_reader, authority_offsets, matcher, &modified_record);
       AugmentKeywords(&record, authority_reader, authority_offsets, matcher, &modified_record);
       modified_count = modified_record ? ++modified_count : modified_count;
       marc_writer->write(record);
    }
}

} // unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4 and argc != 5)
        Usage();

    MARC::FileType reader_type(MARC::FileType::AUTO);
    if (argc == 5) {
        if (std::strcmp(argv[1], "--input-format=marc-21") == 0)
            reader_type = MARC::FileType::BINARY;
        else if (std::strcmp(argv[1], "--input-format=marc-xml") == 0)
            reader_type = MARC::FileType::XML;
        else
            Usage();
        ++argv, --argc;
    }

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        LOG_ERROR("Authority data input file name equals output file name!");

    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, reader_type));
        std::unique_ptr<MARC::Reader> authority_reader(MARC::Reader::Factory(authority_data_marc_input_filename,
                                                                             MARC::FileType::BINARY));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename));
        std::map<std::string, off_t> authority_offsets;

        CreateAuthorityOffsets(authority_reader.get(), &authority_offsets);
        AugmentKeywordsAndAuthors(marc_reader.get(), authority_reader.get(), marc_writer.get(), authority_offsets);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";

    return 0;
}

<|endoftext|>


<commit_before>#ifndef SJTU_AUXNODE_HPP
#define SJTU_AUXNODE_HPP

#include "TNode.hpp"

namespace sjtu{

template<class T, class A, class M>
class AuxNode : TNode<T, A, M>{
private:
	T tagTree;
	bool haveTagTree;
	AuxNode *child[2], *father;
	void makeDelta(const T &value);

public:
	void pushdown();
	void update();

};

#include "source/AuxNode.cpp"

}

#endif
<commit_msg>Changed.<commit_after>#ifndef SJTU_AUXNODE_HPP
#define SJTU_AUXNODE_HPP

#include "TNode.hpp"

namespace sjtu{

template<class T, class A, class M>
class AuxNode : TNode<T, A, M>{
private:
	T tagTree;
	bool haveTagTree;
	AuxNode *child[2], *father;
	void makeDelta(const T &value);

public:
	void pushTagTree();
	void update();

};

#include "source/AuxNode.cpp"

}

#endif
<|endoftext|>


<commit_before>#pragma once
#include "Common/CdcConstants.hpp"
#include "Vector.hpp"

namespace Kvasir{
namespace Cdc{

class DefaultConfig {
	static constexpr int maxEpBufSize{64};
	//declare inPipe here
	//declare outPipe here
};

template<typename TConfig>
class Core {
	static void EpIn(Vector<unsigned char,TConfig::maxEpBufSize>& data){
		data.resize(0); 							//should we make this an invariant?
		auto size = TConfig::inPipe::sizeWas();
		if(size > TConfig::maxEpBufSize){
			data.resize(TConfig::maxEpBufSize);
		}
		else if(size > 0){
			data.resize(size);
		}
		TConfig::inPipe::pop(data.begin(),data.end());
	}
	static void EpOut(Vector<unsigned char,TConfig::maxEpBufSize>& data){
		TConfig::outPipe::push(data.begin(),data.end());
	}
	static bool controlIn(){

	}
	static bool controlOut(){

	}
};

}
}

#endif  /* __CDCUSER_H__ */

<commit_msg>unused #endif removed<commit_after>#pragma once
#include "Common/CdcConstants.hpp"
#include "Vector.hpp"

namespace Kvasir{
namespace Cdc{

class DefaultConfig {
	static constexpr int maxEpBufSize{64};
	//declare inPipe here
	//declare outPipe here
};

template<typename TConfig>
class Core {
	static void EpIn(Vector<unsigned char,TConfig::maxEpBufSize>& data){
		data.resize(0); 							//should we make this an invariant?
		auto size = TConfig::inPipe::sizeWas();
		if(size > TConfig::maxEpBufSize){
			data.resize(TConfig::maxEpBufSize);
		}
		else if(size > 0){
			data.resize(size);
		}
		TConfig::inPipe::pop(data.begin(),data.end());
	}
	static void EpOut(Vector<unsigned char,TConfig::maxEpBufSize>& data){
		TConfig::outPipe::push(data.begin(),data.end());
	}
	static bool controlIn(){

	}
	static bool controlOut(){

	}
};

}
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {qb_RoadExtract.tif}
//    OUTPUTS: {OBIARadiometricAttribute1.tif}, {qb_ExtractRoad_Radiometry_pretty.jpg}
//    STATS::Ndvi::Mean 0 0.5 16 16 50 1.0
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginLatex
//
//  This example shows the basic approach to perform object based analysis on a image.
//  The input image is firstly segmented using the \doxygen{otb}{MeanShiftImageFilter}
//  Then each segmented region is converted to a Map of labeled objects.
//  Afterwards the \doxygen{otb}{RadiometricAttributesLabelMapFilter} computes
//  radiometric attributes for each object.
//
//  This filter internally applies the
//  \doxygen{otb}{StatisticsAttributesLabelMapFilter} to the following features:
//  \begin{itemize}
//  \item GEMI
//  \item NDVI
//  \item IR
//  \item IC
//  \item IB
//  \item NDWI2
//  \item Intensity
//  \item and original B, G, R and NIR channels
//  \end{itemize}
//  Here we use the \doxygen{otb}{AttributesMapOpeningLabelMapFilter} to extract vegetated areas.
//  Let's get to the source code explanation.
//
//  Software Guide : EndLatex

#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbMeanShiftVectorImageFilter.h"
#include "itkLabelImageToLabelMapFilter.h"
#include "otbAttributesMapLabelObject.h"
#include "itkLabelMap.h"
#include "otbShapeAttributesLabelMapFilter.h"
#include "otbStatisticsAttributesLabelMapFilter.h"
#include "otbRadiometricAttributesLabelMapFilter.h"
#include "otbAttributesMapOpeningLabelMapFilter.h"
#include "itkLabelMapToBinaryImageFilter.h"
#include "otbMultiChannelExtractROI.h"
#include "otbVectorRescaleIntensityImageFilter.h"

int main(int argc, char * argv[])
{
  if (argc != 11)
    {
    std::cerr << "Usage: " << argv[0] <<
    " reffname outfname outprettyfname attribute_name ";
    std::cerr <<
    "lowerThan tresh spatialRadius rangeRadius minregionsize scale" <<
    std::endl;
    return EXIT_FAILURE;
    }

  const char * reffname = argv[1];
  const char * outfname = argv[2];
  const char * outprettyfname = argv[3];
  const char * attr     = argv[4];
  bool         lowerThan       = atoi(argv[5]);
  double       thresh         = atof(argv[6]);

  const unsigned int spatialRadius          = atoi(argv[7]);
  const double       rangeRadius            = atof(argv[8]);
  const unsigned int minRegionSize          = atoi(argv[9]);
  const double       scale                  = atoi(argv[10]);

  const unsigned int Dimension = 2;

  // Labeled image type
  typedef unsigned short                              LabelType;
  typedef double                                      PixelType;
  typedef otb::Image<LabelType, Dimension>            LabeledImageType;
  typedef otb::Image<PixelType, Dimension>            ImageType;
  typedef otb::VectorImage<PixelType, Dimension>      VectorImageType;
  typedef otb::VectorImage<unsigned char, Dimension>  OutputVectorImageType;
  typedef otb::ImageFileReader<LabeledImageType>      LabeledReaderType;
  typedef otb::ImageFileReader<ImageType>             ReaderType;
  typedef otb::ImageFileReader<VectorImageType>       VectorReaderType;
  typedef otb::ImageFileWriter<LabeledImageType>      WriterType;
  typedef otb::ImageFileWriter<OutputVectorImageType> VectorWriterType;
  typedef otb::VectorRescaleIntensityImageFilter
  <VectorImageType, OutputVectorImageType> VectorRescalerType;
  typedef otb::MultiChannelExtractROI<unsigned char,
                                      unsigned char> ChannelExtractorType;
  // Label map typedef
  typedef otb::AttributesMapLabelObject<LabelType, Dimension,
                                        double>
  LabelObjectType;
  typedef itk::LabelMap<LabelObjectType>
  LabelMapType;
  typedef itk::LabelImageToLabelMapFilter<LabeledImageType,
                                          LabelMapType>
  LabelMapFilterType;
  typedef otb::ShapeAttributesLabelMapFilter<LabelMapType>
  ShapeLabelMapFilterType;
  typedef otb::StatisticsAttributesLabelMapFilter<LabelMapType,
                                                  ImageType>
  StatisticsLabelMapFilterType;
  typedef otb::RadiometricAttributesLabelMapFilter<LabelMapType,
                                                   VectorImageType>
  RadiometricLabelMapFilterType;
  typedef otb::AttributesMapOpeningLabelMapFilter<LabelMapType>
  OpeningLabelMapFilterType;
  typedef itk::LabelMapToBinaryImageFilter<LabelMapType,
                                           LabeledImageType>
  LabelMapToBinaryImageFilterType;

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(reffname);

  LabeledReaderType::Pointer lreader = LabeledReaderType::New();
  lreader->SetFileName(reffname);

  VectorReaderType::Pointer vreader = VectorReaderType::New();
  vreader->SetFileName(reffname);
  vreader->Update();
  //  Software Guide : BeginLatex
  //
  // Firstly, segment the input image by using the Mean Shift algorithm (see \ref{sec:MeanShift} for deeper
  // explanations).
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef otb::MeanShiftVectorImageFilter
  <VectorImageType, VectorImageType, LabeledImageType> FilterType;
  FilterType::Pointer filter = FilterType::New();
  filter->SetSpatialRadius(spatialRadius);
  filter->SetRangeRadius(rangeRadius);
  filter->SetMinimumRegionSize(minRegionSize);
  filter->SetScale(scale);
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // The \doxygen{otb}{MeanShiftImageFilter} type is instantiated using the image
  // types.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetInput(vreader->GetOutput());
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // The \doxygen{itk}{LabelImageToLabelMapFilter} type is instantiated using the output
  // of the \doxygen{otb}{MeanShiftImageFilter}. This filter produces a labeled image
  // where each segmented region has a unique label.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  LabelMapFilterType::Pointer labelMapFilter = LabelMapFilterType::New();
  labelMapFilter->SetInput(filter->GetLabeledClusteredOutput());
  labelMapFilter->SetBackgroundValue(itk::NumericTraits<LabelType>::min());
  // Software Guide : EndCodeSnippet

  ShapeLabelMapFilterType::Pointer shapeLabelMapFilter =
    ShapeLabelMapFilterType::New();
  shapeLabelMapFilter->SetInput(labelMapFilter->GetOutput());

  //  Software Guide : BeginLatex
  //
  // Instantiate the  \doxygen{otb}{RadiometricAttributesLabelMapFilter} to
  // compute radiometric value on each label object.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  RadiometricLabelMapFilterType::Pointer radiometricLabelMapFilter
    = RadiometricLabelMapFilterType::New();

  radiometricLabelMapFilter->SetInput1(shapeLabelMapFilter->GetOutput());
  radiometricLabelMapFilter->SetInput2(vreader->GetOutput());
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // Then, we specify the red and the near infrared channels
  // By default, images are supposed to be standard 4-band
  // images (B,G,R,NIR). The index of each channel can
  // be set via the \code{Set***ChannelIndex()} accessors.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  radiometricLabelMapFilter->SetRedChannelIndex(2);
  radiometricLabelMapFilter->SetNIRChannelIndex(3);
  radiometricLabelMapFilter->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // The \doxygen{otb}{AttributesMapOpeningLabelMapFilter} will perform the selection.
  // There are three parameters. \code{AttributeName} specifies the radiometric attribute, \code{Lambda}
  // controls the thresholding of the input and \code{ReverseOrdering} make this filter to remove the
  // object with an attribute value greater than \code{Lambda} instead.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  OpeningLabelMapFilterType::Pointer opening = OpeningLabelMapFilterType::New();
  opening->SetInput(radiometricLabelMapFilter->GetOutput());
  opening->SetAttributeName(attr);
  opening->SetLambda(thresh);
  opening->SetReverseOrdering(lowerThan);
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then, Label objects selected are transform in a Label Image using the
  //  \doxygen{itk}{LabelMapToLabelImageFilter}.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  LabelMapToBinaryImageFilterType::Pointer labelMap2LabeledImage
    = LabelMapToBinaryImageFilterType::New();
  labelMap2LabeledImage->SetInput(opening->GetOutput());
  // Software Guide : EndCodeSnippet

  // Software Guide : BeginLatex
  //
  // And finally, we declare the writer and call its \code{Update()} method to
  // trigger the full pipeline execution.
  //
  // Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outfname);
  writer->SetInput(labelMap2LabeledImage->GetOutput());
  writer->Update();
  // Software Guide : EndCodeSnippet

  OutputVectorImageType::PixelType minimum, maximum;
  minimum.SetSize(vreader->GetOutput()->GetNumberOfComponentsPerPixel());
  maximum.SetSize(vreader->GetOutput()->GetNumberOfComponentsPerPixel());
  minimum.Fill(0);
  maximum.Fill(255);

  VectorRescalerType::Pointer vr = VectorRescalerType::New();
  vr->SetInput(filter->GetClusteredOutput());
  vr->SetOutputMinimum(minimum);
  vr->SetOutputMaximum(maximum);
  vr->SetClampThreshold(0.01);

  ChannelExtractorType::Pointer selecter = ChannelExtractorType::New();
  selecter->SetInput(vr->GetOutput());
  selecter->SetExtractionRegion(vreader->GetOutput()->GetLargestPossibleRegion());
  selecter->SetChannel(3);
  selecter->SetChannel(2);
  selecter->SetChannel(1);

  VectorWriterType::Pointer vectWriter = VectorWriterType::New();
  vectWriter->SetFileName(outprettyfname);
  vectWriter->SetInput(selecter->GetOutput());
  vectWriter->Update();

  return EXIT_SUCCESS;
}

// Software Guide : BeginLatex
//
// Figure~\ref{fig:RADIOMETRIC_LABEL_MAP_FILTER} shows the result of applying
// the object selection based on radiometric attributes.
// \begin{figure} [htbp]
// \center
// \includegraphics[width=0.44\textwidth]{qb_ExtractRoad_Radiometry_pretty.eps}
// \includegraphics[width=0.44\textwidth]{OBIARadiometricAttribute1.eps}
// \itkcaption[Object based extraction based on ]{Vegetation mask resulting from processing.}
// \label{fig:RADIOMETRIC_LABEL_MAP_FILTER}
// \end{figure}
//
// Software Guide : EndLatex
<commit_msg>BUG: Set the number of thread to 1 so as MeanShift filter to output always the same result for regression tests<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {qb_RoadExtract.tif}
//    OUTPUTS: {OBIARadiometricAttribute1.tif}, {qb_ExtractRoad_Radiometry_pretty.jpg}
//    STATS::Ndvi::Mean 0 0.5 16 16 50 1.0
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginLatex
//
//  This example shows the basic approach to perform object based analysis on a image.
//  The input image is firstly segmented using the \doxygen{otb}{MeanShiftImageFilter}
//  Then each segmented region is converted to a Map of labeled objects.
//  Afterwards the \doxygen{otb}{RadiometricAttributesLabelMapFilter} computes
//  radiometric attributes for each object.
//
//  This filter internally applies the
//  \doxygen{otb}{StatisticsAttributesLabelMapFilter} to the following features:
//  \begin{itemize}
//  \item GEMI
//  \item NDVI
//  \item IR
//  \item IC
//  \item IB
//  \item NDWI2
//  \item Intensity
//  \item and original B, G, R and NIR channels
//  \end{itemize}
//  Here we use the \doxygen{otb}{AttributesMapOpeningLabelMapFilter} to extract vegetated areas.
//  Let's get to the source code explanation.
//
//  Software Guide : EndLatex

#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbMeanShiftVectorImageFilter.h"
#include "itkLabelImageToLabelMapFilter.h"
#include "otbAttributesMapLabelObject.h"
#include "itkLabelMap.h"
#include "otbShapeAttributesLabelMapFilter.h"
#include "otbStatisticsAttributesLabelMapFilter.h"
#include "otbRadiometricAttributesLabelMapFilter.h"
#include "otbAttributesMapOpeningLabelMapFilter.h"
#include "itkLabelMapToBinaryImageFilter.h"
#include "otbMultiChannelExtractROI.h"
#include "otbVectorRescaleIntensityImageFilter.h"

int main(int argc, char * argv[])
{
  if (argc != 11)
    {
    std::cerr << "Usage: " << argv[0] <<
    " reffname outfname outprettyfname attribute_name ";
    std::cerr <<
    "lowerThan tresh spatialRadius rangeRadius minregionsize scale" <<
    std::endl;
    return EXIT_FAILURE;
    }

  const char * reffname = argv[1];
  const char * outfname = argv[2];
  const char * outprettyfname = argv[3];
  const char * attr     = argv[4];
  bool         lowerThan       = atoi(argv[5]);
  double       thresh         = atof(argv[6]);

  const unsigned int spatialRadius          = atoi(argv[7]);
  const double       rangeRadius            = atof(argv[8]);
  const unsigned int minRegionSize          = atoi(argv[9]);
  const double       scale                  = atoi(argv[10]);

  const unsigned int Dimension = 2;

  // Labeled image type
  typedef unsigned short                              LabelType;
  typedef double                                      PixelType;
  typedef otb::Image<LabelType, Dimension>            LabeledImageType;
  typedef otb::Image<PixelType, Dimension>            ImageType;
  typedef otb::VectorImage<PixelType, Dimension>      VectorImageType;
  typedef otb::VectorImage<unsigned char, Dimension>  OutputVectorImageType;
  typedef otb::ImageFileReader<LabeledImageType>      LabeledReaderType;
  typedef otb::ImageFileReader<ImageType>             ReaderType;
  typedef otb::ImageFileReader<VectorImageType>       VectorReaderType;
  typedef otb::ImageFileWriter<LabeledImageType>      WriterType;
  typedef otb::ImageFileWriter<OutputVectorImageType> VectorWriterType;
  typedef otb::VectorRescaleIntensityImageFilter
  <VectorImageType, OutputVectorImageType> VectorRescalerType;
  typedef otb::MultiChannelExtractROI<unsigned char,
                                      unsigned char> ChannelExtractorType;
  // Label map typedef
  typedef otb::AttributesMapLabelObject<LabelType, Dimension,
                                        double>
  LabelObjectType;
  typedef itk::LabelMap<LabelObjectType>
  LabelMapType;
  typedef itk::LabelImageToLabelMapFilter<LabeledImageType,
                                          LabelMapType>
  LabelMapFilterType;
  typedef otb::ShapeAttributesLabelMapFilter<LabelMapType>
  ShapeLabelMapFilterType;
  typedef otb::StatisticsAttributesLabelMapFilter<LabelMapType,
                                                  ImageType>
  StatisticsLabelMapFilterType;
  typedef otb::RadiometricAttributesLabelMapFilter<LabelMapType,
                                                   VectorImageType>
  RadiometricLabelMapFilterType;
  typedef otb::AttributesMapOpeningLabelMapFilter<LabelMapType>
  OpeningLabelMapFilterType;
  typedef itk::LabelMapToBinaryImageFilter<LabelMapType,
                                           LabeledImageType>
  LabelMapToBinaryImageFilterType;

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(reffname);

  LabeledReaderType::Pointer lreader = LabeledReaderType::New();
  lreader->SetFileName(reffname);

  VectorReaderType::Pointer vreader = VectorReaderType::New();
  vreader->SetFileName(reffname);
  vreader->Update();
  //  Software Guide : BeginLatex
  //
  // Firstly, segment the input image by using the Mean Shift algorithm (see \ref{sec:MeanShift} for deeper
  // explanations).
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef otb::MeanShiftVectorImageFilter
  <VectorImageType, VectorImageType, LabeledImageType> FilterType;
  FilterType::Pointer filter = FilterType::New();
  filter->SetSpatialRadius(spatialRadius);
  filter->SetRangeRadius(rangeRadius);
  filter->SetMinimumRegionSize(minRegionSize);
  filter->SetScale(scale);
  // Software Guide : EndCodeSnippet

  // For non regression tests, set the number of threads to 1
  // because MeanShift results depends on the number of threads
  filter->SetNumberOfThreads(1);

  //  Software Guide : BeginLatex
  //
  // The \doxygen{otb}{MeanShiftImageFilter} type is instantiated using the image
  // types.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetInput(vreader->GetOutput());
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // The \doxygen{itk}{LabelImageToLabelMapFilter} type is instantiated using the output
  // of the \doxygen{otb}{MeanShiftImageFilter}. This filter produces a labeled image
  // where each segmented region has a unique label.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  LabelMapFilterType::Pointer labelMapFilter = LabelMapFilterType::New();
  labelMapFilter->SetInput(filter->GetLabeledClusteredOutput());
  labelMapFilter->SetBackgroundValue(itk::NumericTraits<LabelType>::min());
  // Software Guide : EndCodeSnippet

  ShapeLabelMapFilterType::Pointer shapeLabelMapFilter =
    ShapeLabelMapFilterType::New();
  shapeLabelMapFilter->SetInput(labelMapFilter->GetOutput());

  //  Software Guide : BeginLatex
  //
  // Instantiate the  \doxygen{otb}{RadiometricAttributesLabelMapFilter} to
  // compute radiometric value on each label object.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  RadiometricLabelMapFilterType::Pointer radiometricLabelMapFilter
    = RadiometricLabelMapFilterType::New();

  radiometricLabelMapFilter->SetInput1(shapeLabelMapFilter->GetOutput());
  radiometricLabelMapFilter->SetInput2(vreader->GetOutput());
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // Then, we specify the red and the near infrared channels
  // By default, images are supposed to be standard 4-band
  // images (B,G,R,NIR). The index of each channel can
  // be set via the \code{Set***ChannelIndex()} accessors.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  radiometricLabelMapFilter->SetRedChannelIndex(2);
  radiometricLabelMapFilter->SetNIRChannelIndex(3);
  radiometricLabelMapFilter->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // The \doxygen{otb}{AttributesMapOpeningLabelMapFilter} will perform the selection.
  // There are three parameters. \code{AttributeName} specifies the radiometric attribute, \code{Lambda}
  // controls the thresholding of the input and \code{ReverseOrdering} make this filter to remove the
  // object with an attribute value greater than \code{Lambda} instead.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  OpeningLabelMapFilterType::Pointer opening = OpeningLabelMapFilterType::New();
  opening->SetInput(radiometricLabelMapFilter->GetOutput());
  opening->SetAttributeName(attr);
  opening->SetLambda(thresh);
  opening->SetReverseOrdering(lowerThan);
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Then, Label objects selected are transform in a Label Image using the
  //  \doxygen{itk}{LabelMapToLabelImageFilter}.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  LabelMapToBinaryImageFilterType::Pointer labelMap2LabeledImage
    = LabelMapToBinaryImageFilterType::New();
  labelMap2LabeledImage->SetInput(opening->GetOutput());
  // Software Guide : EndCodeSnippet

  // Software Guide : BeginLatex
  //
  // And finally, we declare the writer and call its \code{Update()} method to
  // trigger the full pipeline execution.
  //
  // Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outfname);
  writer->SetInput(labelMap2LabeledImage->GetOutput());
  writer->Update();
  // Software Guide : EndCodeSnippet

  OutputVectorImageType::PixelType minimum, maximum;
  minimum.SetSize(vreader->GetOutput()->GetNumberOfComponentsPerPixel());
  maximum.SetSize(vreader->GetOutput()->GetNumberOfComponentsPerPixel());
  minimum.Fill(0);
  maximum.Fill(255);

  VectorRescalerType::Pointer vr = VectorRescalerType::New();
  vr->SetInput(filter->GetClusteredOutput());
  vr->SetOutputMinimum(minimum);
  vr->SetOutputMaximum(maximum);
  vr->SetClampThreshold(0.01);

  ChannelExtractorType::Pointer selecter = ChannelExtractorType::New();
  selecter->SetInput(vr->GetOutput());
  selecter->SetExtractionRegion(vreader->GetOutput()->GetLargestPossibleRegion());
  selecter->SetChannel(3);
  selecter->SetChannel(2);
  selecter->SetChannel(1);

  VectorWriterType::Pointer vectWriter = VectorWriterType::New();
  vectWriter->SetFileName(outprettyfname);
  vectWriter->SetInput(selecter->GetOutput());
  vectWriter->Update();

  return EXIT_SUCCESS;
}

// Software Guide : BeginLatex
//
// Figure~\ref{fig:RADIOMETRIC_LABEL_MAP_FILTER} shows the result of applying
// the object selection based on radiometric attributes.
// \begin{figure} [htbp]
// \center
// \includegraphics[width=0.44\textwidth]{qb_ExtractRoad_Radiometry_pretty.eps}
// \includegraphics[width=0.44\textwidth]{OBIARadiometricAttribute1.eps}
// \itkcaption[Object based extraction based on ]{Vegetation mask resulting from processing.}
// \label{fig:RADIOMETRIC_LABEL_MAP_FILTER}
// \end{figure}
//
// Software Guide : EndLatex
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :    NFMapEx.h
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    ָר,мǣѭԼɾԼ
//
// -------------------------------------------------------------------------

#ifndef NF_MAPEX_H
#define NF_MAPEX_H

#include <map>
#include <list>
#include <string>
#include <iostream>
#include <typeinfo>
#include <memory>
#include "NFCConsistentHash.hpp"
#include "NFComm/NFPluginModule/NFPlatform.h"

template <typename T , typename TD>
class NFMapEx
{
public:
    typedef std::map<T, NF_SHARE_PTR<TD> > NFMapOBJECT;

    NFMapEx() {};
    virtual ~NFMapEx()
    {
    };

	virtual bool ExistElement(const T& name)
	{
		typename NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr != mObjectList.end())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
/*
	virtual NF_SHARE_PTR<TD> AddElement(const T& name)
	{
		typename NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr == mObjectList.end())
		{
			NF_SHARE_PTR<TD> data(NF_NEW TD());
			mObjectList.insert(typename NFMapOBJECT::value_type(name, data));
			return data;
		}

		return NF_SHARE_PTR<TD>();
	}
	*/
    virtual bool AddElement(const T& name, const NF_SHARE_PTR<TD> data)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr == mObjectList.end())
        {
            mObjectList.insert(typename NFMapOBJECT::value_type(name, data));

            return true;
        }

        return false;
    }

    virtual bool RemoveElement(const T& name)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr != mObjectList.end())
        {
            mObjectList.erase(itr);

            return true;
        }

        return false;
    }

    //virtual TD* GetElementNude(const T& name)
    //{
    //    typename NFMapOBJECT::iterator itr = mObjectList.find(name);
    //    if (itr != mObjectList.end())
    //    {
    //        return itr->second.get();
    //    }
    //    else
    //    {
    //        return NULL;
    //    }
    //}

    virtual NF_SHARE_PTR<TD> GetElement(const T& name)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr != mObjectList.end())
        {
            return itr->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual TD* FirstNude(T& name)
    {
        if (mObjectList.size() <= 0)
        {
            return NULL;
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }

    virtual TD* NextNude(T& name)
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NULL;
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }
    virtual TD* FirstNude()
    {
        if (mObjectList.size() <= 0)
        {
            return NULL;
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }
    virtual TD* NextNude()
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NULL;
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }

    virtual NF_SHARE_PTR<TD> First()
    {
        if (mObjectList.size() <= 0)
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> Next()
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NF_SHARE_PTR<TD>();
        }

        ++mObjectCurIter;
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> First(T& name)
    {
        if (mObjectList.size() <= 0)
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> Next(T& name)
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    int Count()
    {
        return (int)mObjectList.size();
    }

    bool ClearAll()
    {
        mObjectList.clear();
        return true;
    }

protected:
    NFMapOBJECT     mObjectList;
    typename NFMapOBJECT::iterator mObjectCurIter;
};

template <typename T, typename TD>
class NFCConsistentHashMapEx : public NFMapEx<T, TD>
{
public:
	virtual void InitHashNodeWeith(const int nWeigh = 500)
	{
		mnWeigh = nWeigh;
	}

	virtual NF_SHARE_PTR<TD> GetElementBySuit()
	{
		NFCVirtualNode<T> vNode;
		if (mxConsistentHash.GetSuitNode(vNode))
		{
			typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(vNode.mxData);
			if (itr != mObjectList.end())
			{
				return itr->second;
			}
		}

		return NULL;
	}

	virtual NF_SHARE_PTR<TD> GetElementBySuit(const T& name)
	{
		NFCVirtualNode<T> vNode;
		if (mxConsistentHash.GetSuitNode(name, vNode))
		{
			typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(vNode.mxData);
			if (itr != mObjectList.end())
			{
				return itr->second;
			}
		}

		return NULL;
	}

	virtual bool AddElement(const T& name, const NF_SHARE_PTR<TD> data)
	{
		typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr == mObjectList.end())
		{
			mObjectList.insert(typename NFMapEx<T, TD>::NFMapOBJECT::value_type(name, data));

			mxConsistentHash.Insert(name);

			return true;
		}

		return false;
	}

	virtual bool RemoveElement(const T& name)
	{
		typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr != mObjectList.end())
		{
			mObjectList.erase(itr);
			mxConsistentHash.Erase(name);

			return true;
		}

		return false;
	}

	bool ClearAll()
	{
		mObjectList.clear();
		mxConsistentHash.ClearAll();
		return true;
	}

private:
	int mnWeigh = 0;
	NFCConsistentHash<T> mxConsistentHash;
};
#endif<commit_msg>fixed for compile<commit_after>// -------------------------------------------------------------------------
//    @FileName         :    NFMapEx.h
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    ָר,мǣѭԼɾԼ
//
// -------------------------------------------------------------------------

#ifndef NF_MAPEX_H
#define NF_MAPEX_H

#include <map>
#include <list>
#include <string>
#include <iostream>
#include <typeinfo>
#include <memory>
#include "NFCConsistentHash.hpp"
#include "NFComm/NFPluginModule/NFPlatform.h"

template <typename T , typename TD>
class NFMapEx
{
public:
    typedef std::map<T, NF_SHARE_PTR<TD> > NFMapOBJECT;

    NFMapEx() {};
    virtual ~NFMapEx()
    {
    };

	virtual bool ExistElement(const T& name)
	{
		typename NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr != mObjectList.end())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
/*
	virtual NF_SHARE_PTR<TD> AddElement(const T& name)
	{
		typename NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr == mObjectList.end())
		{
			NF_SHARE_PTR<TD> data(NF_NEW TD());
			mObjectList.insert(typename NFMapOBJECT::value_type(name, data));
			return data;
		}

		return NF_SHARE_PTR<TD>();
	}
	*/
    virtual bool AddElement(const T& name, const NF_SHARE_PTR<TD> data)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr == mObjectList.end())
        {
            mObjectList.insert(typename NFMapOBJECT::value_type(name, data));

            return true;
        }

        return false;
    }

    virtual bool RemoveElement(const T& name)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr != mObjectList.end())
        {
            mObjectList.erase(itr);

            return true;
        }

        return false;
    }

    virtual TD* GetElementNude(const T& name)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr != mObjectList.end())
        {
            return itr->second.get();
        }
        else
        {
            return NULL;
        }
    }

    virtual NF_SHARE_PTR<TD> GetElement(const T& name)
    {
        typename NFMapOBJECT::iterator itr = mObjectList.find(name);
        if (itr != mObjectList.end())
        {
            return itr->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual TD* FirstNude(T& name)
    {
        if (mObjectList.size() <= 0)
        {
            return NULL;
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }

    virtual TD* NextNude(T& name)
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NULL;
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }
    virtual TD* FirstNude()
    {
        if (mObjectList.size() <= 0)
        {
            return NULL;
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }
    virtual TD* NextNude()
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NULL;
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second.get();
        }
        else
        {
            return NULL;
        }
    }

    virtual NF_SHARE_PTR<TD> First()
    {
        if (mObjectList.size() <= 0)
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> Next()
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NF_SHARE_PTR<TD>();
        }

        ++mObjectCurIter;
        if (mObjectCurIter != mObjectList.end())
        {
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> First(T& name)
    {
        if (mObjectList.size() <= 0)
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter = mObjectList.begin();
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    virtual NF_SHARE_PTR<TD> Next(T& name)
    {
        if (mObjectCurIter == mObjectList.end())
        {
            return NF_SHARE_PTR<TD>();
        }

        mObjectCurIter++;
        if (mObjectCurIter != mObjectList.end())
        {
            name = mObjectCurIter->first;
            return mObjectCurIter->second;
        }
        else
        {
            return NF_SHARE_PTR<TD>();
        }
    }

    int Count()
    {
        return (int)mObjectList.size();
    }

    bool ClearAll()
    {
        mObjectList.clear();
        return true;
    }

protected:
    NFMapOBJECT     mObjectList;
    typename NFMapOBJECT::iterator mObjectCurIter;
};

template <typename T, typename TD>
class NFCConsistentHashMapEx : public NFMapEx<T, TD>
{
public:
	virtual void InitHashNodeWeith(const int nWeigh = 500)
	{
		mnWeigh = nWeigh;
	}

	virtual NF_SHARE_PTR<TD> GetElementBySuit()
	{
		NFCVirtualNode<T> vNode;
		if (mxConsistentHash.GetSuitNode(vNode))
		{
			typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(vNode.mxData);
			if (itr != mObjectList.end())
			{
				return itr->second;
			}
		}

		return NULL;
	}

	virtual NF_SHARE_PTR<TD> GetElementBySuit(const T& name)
	{
		NFCVirtualNode<T> vNode;
		if (mxConsistentHash.GetSuitNode(name, vNode))
		{
			typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(vNode.mxData);
			if (itr != mObjectList.end())
			{
				return itr->second;
			}
		}

		return NULL;
	}

	virtual bool AddElement(const T& name, const NF_SHARE_PTR<TD> data)
	{
		typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr == mObjectList.end())
		{
			mObjectList.insert(typename NFMapEx<T, TD>::NFMapOBJECT::value_type(name, data));

			mxConsistentHash.Insert(name);

			return true;
		}

		return false;
	}

	virtual bool RemoveElement(const T& name)
	{
		typename NFMapEx<T, TD>::NFMapOBJECT::iterator itr = mObjectList.find(name);
		if (itr != mObjectList.end())
		{
			mObjectList.erase(itr);
			mxConsistentHash.Erase(name);

			return true;
		}

		return false;
	}

	bool ClearAll()
	{
		mObjectList.clear();
		mxConsistentHash.ClearAll();
		return true;
	}

private:
	int mnWeigh = 0;
	NFCConsistentHash<T> mxConsistentHash;
};
#endif<|endoftext|>