<commit_before>/*
 * Copyright (C) 2017-2019 CS Systemes d'Information (CS SI)
 *
 * 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.
 */

#include "otbMultiImageFileWriter.h"
#include "otbImageIOFactory.h"

namespace otb
{

MultiImageFileWriter::MultiImageFileWriter() : m_NumberOfDivisions(0), m_CurrentDivision(0), m_DivisionProgress(0.0), m_IsObserving(true), m_ObserverID(0)
{
  // By default, we use tiled streaming, with automatic tile size
  // We don't set any parameter, so the memory size is retrieved from the OTB configuration options
  this->SetAutomaticAdaptativeStreaming();
  // add a fake output to drive memory estimation
  this->SetNthOutput(0, FakeOutputType::New());
}

void MultiImageFileWriter::SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
{
  typedef NumberOfDivisionsStrippedStreamingManager<FakeOutputType> NumberOfDivisionsStrippedStreamingManagerType;
  NumberOfDivisionsStrippedStreamingManagerType::Pointer            streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
  streamingManager->SetNumberOfDivisions(nbDivisions);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
{
  typedef NumberOfDivisionsTiledStreamingManager<FakeOutputType> NumberOfDivisionsTiledStreamingManagerType;
  NumberOfDivisionsTiledStreamingManagerType::Pointer            streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
  streamingManager->SetNumberOfDivisions(nbDivisions);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
{
  typedef NumberOfLinesStrippedStreamingManager<FakeOutputType> NumberOfLinesStrippedStreamingManagerType;
  NumberOfLinesStrippedStreamingManagerType::Pointer            streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
  streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenStrippedStreamingManager<FakeOutputType> RAMDrivenStrippedStreamingManagerType;
  RAMDrivenStrippedStreamingManagerType::Pointer            streamingManager = RAMDrivenStrippedStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetTileDimensionTiledStreaming(unsigned int tileDimension)
{
  typedef TileDimensionTiledStreamingManager<FakeOutputType> TileDimensionTiledStreamingManagerType;
  TileDimensionTiledStreamingManagerType::Pointer            streamingManager = TileDimensionTiledStreamingManagerType::New();
  streamingManager->SetTileDimension(tileDimension);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenTiledStreamingManager<FakeOutputType> RAMDrivenTiledStreamingManagerType;
  RAMDrivenTiledStreamingManagerType::Pointer            streamingManager = RAMDrivenTiledStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);
  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenAdaptativeStreamingManager<FakeOutputType> RAMDrivenAdaptativeStreamingManagerType;
  RAMDrivenAdaptativeStreamingManagerType::Pointer            streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);
  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::InitializeStreaming()
{
  //  const ImageBaseType* inputPtr = this->GetInput(0);
  if (m_SinkList.size() == 0)
    itkExceptionMacro("At least one input must be connected to the writer\n");
  const ImageBaseType* inputPtr = m_SinkList[0]->GetInput();
  if (!inputPtr)
    itkExceptionMacro("At least one input must be connected to the writer\n");

  /** Control if the ImageIO is CanStreamWrite */
  m_NumberOfDivisions = 1;
  bool canStream      = true;
  bool isBuffered     = true;
  for (unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
  {
    if (!m_SinkList[inputIndex]->CanStreamWrite())
    {
      canStream = false;
    }
    if (m_SinkList[inputIndex]->GetInput()->GetBufferedRegion() != m_SinkList[inputIndex]->GetInput()->GetLargestPossibleRegion())
    {
      isBuffered = false;
    }
  }
  if (canStream == false)
  {
    otbWarningMacro(<< "One of the selected ImageIO does not support streaming.");
    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
  }

  /** Compare the buffered region  with the inputRegion which is the largest
  * possible region or a user defined region through extended filename
  * Not sure that if this modification is needed  */
  else if (isBuffered)
  {
    otbMsgDevMacro(<< "Buffered region is the largest possible region, there is"
                      " no need for streaming.");
    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
  }
  else
  {
    /**
     * Determine of number of pieces to divide the input.  This will be the
     * first estimated on the fake output, which has the same size as the
     * first input. Then there is a check that each input can be split into
     * this number of pieces.
     */
    FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));
    RegionType      region  = fakeOut->GetLargestPossibleRegion();
    m_StreamingManager->PrepareStreaming(fakeOut, region);
    m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
    // Check this number of division is compatible with all inputs
    bool nbDivValid = false;
    while ((!nbDivValid) && 1 < m_NumberOfDivisions)
    {
      unsigned int smallestNbDiv = m_NumberOfDivisions;
      for (unsigned int i = 0; i < m_SinkList.size(); ++i)
      {
        unsigned int div = m_StreamingManager->GetSplitter()->GetNumberOfSplits(m_SinkList[i]->GetInput()->GetLargestPossibleRegion(), m_NumberOfDivisions);
        smallestNbDiv    = std::min(div, smallestNbDiv);
      }
      if (smallestNbDiv == m_NumberOfDivisions)
      {
        nbDivValid = true;
      }
      else
      {
        m_NumberOfDivisions = smallestNbDiv;
      }
    }
    if (m_NumberOfDivisions == 1)
    {
      otbWarningMacro("Can't find a common split scheme between all inputs, streaming disabled\n");
    }
    otbMsgDebugMacro(<< "Number Of Stream Divisions : " << m_NumberOfDivisions);
  }
}

void MultiImageFileWriter::ResetAllRequestedRegions(ImageBaseType* imagePtr)
{
  RegionType nullRegion = imagePtr->GetLargestPossibleRegion();
  nullRegion.SetSize(0, 0);
  nullRegion.SetSize(1, 0);

  imagePtr->SetRequestedRegion(nullRegion);
  if (imagePtr->GetSource())
  {
    itk::ProcessObject::DataObjectPointerArray inputs = imagePtr->GetSource()->GetInputs();
    for (itk::ProcessObject::DataObjectPointerArray::iterator it = inputs.begin(); it != inputs.end(); ++it)
    {
      ImageBaseType* inputImagePtr = dynamic_cast<ImageBaseType*>(it->GetPointer());
      if (inputImagePtr != NULL)
      {
        ResetAllRequestedRegions(inputImagePtr);
      }
    }
  }
}

void MultiImageFileWriter::UpdateOutputInformation()
{
  for (unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
  {
    m_SinkList[inputIndex]->WriteImageInformation();
  }
  this->GenerateOutputInformation();
}

void MultiImageFileWriter::UpdateOutputData(itk::DataObject* itkNotUsed(output))
{
  /**
   * prevent chasing our tail
   */
  if (this->m_Updating)
  {
    return;
  }

  // Initialize streaming
  this->InitializeStreaming();

  this->SetAbortGenerateData(0);
  this->SetProgress(0.0);
  this->m_Updating = true;

  /**
   * Tell all Observers that the filter is starting
   */
  this->InvokeEvent(itk::StartEvent());

  this->UpdateProgress(0);
  m_CurrentDivision  = 0;
  m_DivisionProgress = 0;

  /** Loop over the number of pieces, set and propagate requested regions then
   * update pipeline upstream
   */
  int numInputs = m_SinkList.size(); // this->GetNumberOfInputs();
  m_StreamRegionList.resize(numInputs);
  itkDebugMacro("Number of streaming divisions: " << m_NumberOfDivisions);

  // Add observer only to first input
  if (numInputs > 0)
  {
    m_IsObserving = false;
    m_ObserverID  = 0;

    typedef itk::MemberCommand<Self> CommandType;
    typedef CommandType::Pointer     CommandPointerType;

    CommandPointerType command = CommandType::New();
    command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);

    itk::ProcessObject* src = this->GetInput(0)->GetSource();
    m_ObserverID            = src->AddObserver(itk::ProgressEvent(), command);
    m_IsObserving           = true;
  }

  for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
       m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
  {
    // Update all stream regions
    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      m_StreamRegionList[inputIndex] = GetStreamRegion(inputIndex);
    }

    // NOTE : this reset was probably designed to work with the next section
    // Where the final requested region is the "union" between the computed
    // requested region and the current requested region.

    // Reset requested regions for all images
    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      ResetAllRequestedRegions(m_SinkList[inputIndex]->GetInput());
    }

    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      ImageBaseType::Pointer inputPtr                    = m_SinkList[inputIndex]->GetInput();
      RegionType             inputRequestedRegion        = m_StreamRegionList[inputIndex];
      const RegionType&      currentInputRequestedRegion = inputPtr->GetRequestedRegion();
      if (currentInputRequestedRegion != inputPtr->GetLargestPossibleRegion() && currentInputRequestedRegion.GetNumberOfPixels() != 0)
      {
        IndexType startIndex = currentInputRequestedRegion.GetIndex();
        IndexType lastIndex  = currentInputRequestedRegion.GetUpperIndex();
        startIndex[0]        = std::min(startIndex[0], inputRequestedRegion.GetIndex(0));
        startIndex[1]        = std::min(startIndex[1], inputRequestedRegion.GetIndex(1));
        lastIndex[0]         = std::max(lastIndex[0], inputRequestedRegion.GetUpperIndex()[0]);
        lastIndex[1]         = std::max(lastIndex[1], inputRequestedRegion.GetUpperIndex()[1]);
        inputRequestedRegion.SetIndex(startIndex);
        inputRequestedRegion.SetUpperIndex(lastIndex);
      }

      inputPtr->SetRequestedRegion(inputRequestedRegion);
      inputPtr->PropagateRequestedRegion();
    }

    /** Call GenerateData to write streams to files if needed */
    this->GenerateData();
  }

  /**
   * If we ended due to aborting, push the progress up to 1.0 (since
   * it probably didn't end there)
   */
  if (!this->GetAbortGenerateData())
  {
    this->UpdateProgress(1.0);
  }

  // Notify end event observers
  this->InvokeEvent(itk::EndEvent());

  if (m_IsObserving)
  {
    ImageBaseType::Pointer inputPtr = m_SinkList[0]->GetInput(); // const_cast<ImageBaseType *>(this->GetInput(0));
    itk::ProcessObject*    source   = inputPtr->GetSource();
    m_IsObserving                   = false;
    source->RemoveObserver(m_ObserverID);
  }

  /**
   * Release any inputs if marked for release
   */
  this->ReleaseInputs();

  // Mark that we are no longer updating the data in this filter
  this->m_Updating = false;
}

void MultiImageFileWriter::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  // Approximate conversion of output requested region into each input,
  // but this is only to have a consistent pipeline memory estimation.
  int numInputs = m_SinkList.size(); // this->GetNumberOfInputs();

  FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));

  if (numInputs)
  {
    RegionType refLargest  = fakeOut->GetLargestPossibleRegion();
    RegionType refRequest  = fakeOut->GetRequestedRegion();
    IndexType  idxLargest  = refLargest.GetIndex();
    SizeType   sizeLargest = refLargest.GetSize();
    IndexType  idxRequest  = refRequest.GetIndex();
    SizeType   sizeRequest = refRequest.GetSize();
    for (int i = 0; i < numInputs; ++i)
    {
      ImageBaseType* inputPtr = m_SinkList[i]->GetInput();
      if (!inputPtr)
      {
        return;
      }
      RegionType region = inputPtr->GetLargestPossibleRegion();
      IndexType  idx    = region.GetIndex();
      SizeType   size   = region.GetSize();
      idx[0] += size[0] * (idxRequest[0] - idxLargest[0]) / sizeLargest[0];
      idx[1] += size[1] * (idxRequest[1] - idxLargest[1]) / sizeLargest[1];
      size[0] *= sizeRequest[0] / sizeLargest[0];
      size[1] *= sizeRequest[1] / sizeLargest[1];
      region.SetIndex(idx);
      region.SetSize(size);
      inputPtr->SetRequestedRegion(region);
    }
  }
}

void MultiImageFileWriter::GenerateData()
{
  int numInputs = m_SinkList.size();
  for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
  {
    m_SinkList[inputIndex]->Write(m_StreamRegionList[inputIndex]);
  }
}

MultiImageFileWriter::RegionType MultiImageFileWriter::GetStreamRegion(int inputIndex)
{
  const SinkBase::Pointer sink   = m_SinkList[inputIndex];
  RegionType              region = sink->GetInput()->GetLargestPossibleRegion();

  m_StreamingManager->GetSplitter()->GetSplit(m_CurrentDivision, m_NumberOfDivisions, region);
  return region;
}

} // end of namespace otb
<commit_msg>BUG: call PrepareStreaming() on the streaming manager before using it even when the image is processed in one block (non streamable writer or buffered input)<commit_after>/*
 * Copyright (C) 2017-2019 CS Systemes d'Information (CS SI)
 *
 * 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.
 */

#include "otbMultiImageFileWriter.h"
#include "otbImageIOFactory.h"

namespace otb
{

MultiImageFileWriter::MultiImageFileWriter() : m_NumberOfDivisions(0), m_CurrentDivision(0), m_DivisionProgress(0.0), m_IsObserving(true), m_ObserverID(0)
{
  // By default, we use tiled streaming, with automatic tile size
  // We don't set any parameter, so the memory size is retrieved from the OTB configuration options
  this->SetAutomaticAdaptativeStreaming();
  // add a fake output to drive memory estimation
  this->SetNthOutput(0, FakeOutputType::New());
}

void MultiImageFileWriter::SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
{
  typedef NumberOfDivisionsStrippedStreamingManager<FakeOutputType> NumberOfDivisionsStrippedStreamingManagerType;
  NumberOfDivisionsStrippedStreamingManagerType::Pointer            streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
  streamingManager->SetNumberOfDivisions(nbDivisions);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
{
  typedef NumberOfDivisionsTiledStreamingManager<FakeOutputType> NumberOfDivisionsTiledStreamingManagerType;
  NumberOfDivisionsTiledStreamingManagerType::Pointer            streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
  streamingManager->SetNumberOfDivisions(nbDivisions);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
{
  typedef NumberOfLinesStrippedStreamingManager<FakeOutputType> NumberOfLinesStrippedStreamingManagerType;
  NumberOfLinesStrippedStreamingManagerType::Pointer            streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
  streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenStrippedStreamingManager<FakeOutputType> RAMDrivenStrippedStreamingManagerType;
  RAMDrivenStrippedStreamingManagerType::Pointer            streamingManager = RAMDrivenStrippedStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetTileDimensionTiledStreaming(unsigned int tileDimension)
{
  typedef TileDimensionTiledStreamingManager<FakeOutputType> TileDimensionTiledStreamingManagerType;
  TileDimensionTiledStreamingManagerType::Pointer            streamingManager = TileDimensionTiledStreamingManagerType::New();
  streamingManager->SetTileDimension(tileDimension);

  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenTiledStreamingManager<FakeOutputType> RAMDrivenTiledStreamingManagerType;
  RAMDrivenTiledStreamingManagerType::Pointer            streamingManager = RAMDrivenTiledStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);
  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
{
  typedef RAMDrivenAdaptativeStreamingManager<FakeOutputType> RAMDrivenAdaptativeStreamingManagerType;
  RAMDrivenAdaptativeStreamingManagerType::Pointer            streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
  streamingManager->SetAvailableRAMInMB(availableRAM);
  streamingManager->SetBias(bias);
  m_StreamingManager = streamingManager;
}

void MultiImageFileWriter::InitializeStreaming()
{
  //  const ImageBaseType* inputPtr = this->GetInput(0);
  if (m_SinkList.size() == 0)
    itkExceptionMacro("At least one input must be connected to the writer\n");
  const ImageBaseType* inputPtr = m_SinkList[0]->GetInput();
  if (!inputPtr)
    itkExceptionMacro("At least one input must be connected to the writer\n");

  /** Control if the ImageIO is CanStreamWrite */
  m_NumberOfDivisions = 1;
  bool canStream      = true;
  bool isBuffered     = true;
  for (unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
  {
    if (!m_SinkList[inputIndex]->CanStreamWrite())
    {
      canStream = false;
    }
    if (m_SinkList[inputIndex]->GetInput()->GetBufferedRegion() != m_SinkList[inputIndex]->GetInput()->GetLargestPossibleRegion())
    {
      isBuffered = false;
    }
  }
  if (canStream == false)
  {
    otbWarningMacro(<< "One of the selected ImageIO does not support streaming.");
    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
    FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));
    RegionType      region  = fakeOut->GetLargestPossibleRegion();
    m_StreamingManager->PrepareStreaming(fakeOut, region);
  }

  /** Compare the buffered region  with the inputRegion which is the largest
  * possible region or a user defined region through extended filename
  * Not sure that if this modification is needed  */
  else if (isBuffered)
  {
    otbMsgDevMacro(<< "Buffered region is the largest possible region, there is"
                      " no need for streaming.");
    this->SetNumberOfDivisionsStrippedStreaming(m_NumberOfDivisions);
    FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));
    RegionType      region  = fakeOut->GetLargestPossibleRegion();
    m_StreamingManager->PrepareStreaming(fakeOut, region);
  }
  else
  {
    /**
     * Determine of number of pieces to divide the input.  This will be the
     * first estimated on the fake output, which has the same size as the
     * first input. Then there is a check that each input can be split into
     * this number of pieces.
     */
    FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));
    RegionType      region  = fakeOut->GetLargestPossibleRegion();
    m_StreamingManager->PrepareStreaming(fakeOut, region);
    m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
    // Check this number of division is compatible with all inputs
    bool nbDivValid = false;
    while ((!nbDivValid) && 1 < m_NumberOfDivisions)
    {
      unsigned int smallestNbDiv = m_NumberOfDivisions;
      for (unsigned int i = 0; i < m_SinkList.size(); ++i)
      {
        unsigned int div = m_StreamingManager->GetSplitter()->GetNumberOfSplits(m_SinkList[i]->GetInput()->GetLargestPossibleRegion(), m_NumberOfDivisions);
        smallestNbDiv    = std::min(div, smallestNbDiv);
      }
      if (smallestNbDiv == m_NumberOfDivisions)
      {
        nbDivValid = true;
      }
      else
      {
        m_NumberOfDivisions = smallestNbDiv;
      }
    }
    if (m_NumberOfDivisions == 1)
    {
      otbWarningMacro("Can't find a common split scheme between all inputs, streaming disabled\n");
    }
    otbMsgDebugMacro(<< "Number Of Stream Divisions : " << m_NumberOfDivisions);
  }
}

void MultiImageFileWriter::ResetAllRequestedRegions(ImageBaseType* imagePtr)
{
  RegionType nullRegion = imagePtr->GetLargestPossibleRegion();
  nullRegion.SetSize(0, 0);
  nullRegion.SetSize(1, 0);

  imagePtr->SetRequestedRegion(nullRegion);
  if (imagePtr->GetSource())
  {
    itk::ProcessObject::DataObjectPointerArray inputs = imagePtr->GetSource()->GetInputs();
    for (itk::ProcessObject::DataObjectPointerArray::iterator it = inputs.begin(); it != inputs.end(); ++it)
    {
      ImageBaseType* inputImagePtr = dynamic_cast<ImageBaseType*>(it->GetPointer());
      if (inputImagePtr != NULL)
      {
        ResetAllRequestedRegions(inputImagePtr);
      }
    }
  }
}

void MultiImageFileWriter::UpdateOutputInformation()
{
  for (unsigned int inputIndex = 0; inputIndex < m_SinkList.size(); ++inputIndex)
  {
    m_SinkList[inputIndex]->WriteImageInformation();
  }
  this->GenerateOutputInformation();
}

void MultiImageFileWriter::UpdateOutputData(itk::DataObject* itkNotUsed(output))
{
  /**
   * prevent chasing our tail
   */
  if (this->m_Updating)
  {
    return;
  }

  // Initialize streaming
  this->InitializeStreaming();

  this->SetAbortGenerateData(0);
  this->SetProgress(0.0);
  this->m_Updating = true;

  /**
   * Tell all Observers that the filter is starting
   */
  this->InvokeEvent(itk::StartEvent());

  this->UpdateProgress(0);
  m_CurrentDivision  = 0;
  m_DivisionProgress = 0;

  /** Loop over the number of pieces, set and propagate requested regions then
   * update pipeline upstream
   */
  int numInputs = m_SinkList.size(); // this->GetNumberOfInputs();
  m_StreamRegionList.resize(numInputs);
  itkDebugMacro("Number of streaming divisions: " << m_NumberOfDivisions);

  // Add observer only to first input
  if (numInputs > 0)
  {
    m_IsObserving = false;
    m_ObserverID  = 0;

    typedef itk::MemberCommand<Self> CommandType;
    typedef CommandType::Pointer     CommandPointerType;

    CommandPointerType command = CommandType::New();
    command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);

    itk::ProcessObject* src = this->GetInput(0)->GetSource();
    m_ObserverID            = src->AddObserver(itk::ProgressEvent(), command);
    m_IsObserving           = true;
  }

  for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
       m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
  {
    // Update all stream regions
    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      m_StreamRegionList[inputIndex] = GetStreamRegion(inputIndex);
    }

    // NOTE : this reset was probably designed to work with the next section
    // Where the final requested region is the "union" between the computed
    // requested region and the current requested region.

    // Reset requested regions for all images
    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      ResetAllRequestedRegions(m_SinkList[inputIndex]->GetInput());
    }

    for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
    {
      ImageBaseType::Pointer inputPtr                    = m_SinkList[inputIndex]->GetInput();
      RegionType             inputRequestedRegion        = m_StreamRegionList[inputIndex];
      const RegionType&      currentInputRequestedRegion = inputPtr->GetRequestedRegion();
      if (currentInputRequestedRegion != inputPtr->GetLargestPossibleRegion() && currentInputRequestedRegion.GetNumberOfPixels() != 0)
      {
        IndexType startIndex = currentInputRequestedRegion.GetIndex();
        IndexType lastIndex  = currentInputRequestedRegion.GetUpperIndex();
        startIndex[0]        = std::min(startIndex[0], inputRequestedRegion.GetIndex(0));
        startIndex[1]        = std::min(startIndex[1], inputRequestedRegion.GetIndex(1));
        lastIndex[0]         = std::max(lastIndex[0], inputRequestedRegion.GetUpperIndex()[0]);
        lastIndex[1]         = std::max(lastIndex[1], inputRequestedRegion.GetUpperIndex()[1]);
        inputRequestedRegion.SetIndex(startIndex);
        inputRequestedRegion.SetUpperIndex(lastIndex);
      }

      inputPtr->SetRequestedRegion(inputRequestedRegion);
      inputPtr->PropagateRequestedRegion();
    }

    /** Call GenerateData to write streams to files if needed */
    this->GenerateData();
  }

  /**
   * If we ended due to aborting, push the progress up to 1.0 (since
   * it probably didn't end there)
   */
  if (!this->GetAbortGenerateData())
  {
    this->UpdateProgress(1.0);
  }

  // Notify end event observers
  this->InvokeEvent(itk::EndEvent());

  if (m_IsObserving)
  {
    ImageBaseType::Pointer inputPtr = m_SinkList[0]->GetInput(); // const_cast<ImageBaseType *>(this->GetInput(0));
    itk::ProcessObject*    source   = inputPtr->GetSource();
    m_IsObserving                   = false;
    source->RemoveObserver(m_ObserverID);
  }

  /**
   * Release any inputs if marked for release
   */
  this->ReleaseInputs();

  // Mark that we are no longer updating the data in this filter
  this->m_Updating = false;
}

void MultiImageFileWriter::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  // Approximate conversion of output requested region into each input,
  // but this is only to have a consistent pipeline memory estimation.
  int numInputs = m_SinkList.size(); // this->GetNumberOfInputs();

  FakeOutputType* fakeOut = static_cast<FakeOutputType*>(this->itk::ProcessObject::GetOutput(0));

  if (numInputs)
  {
    RegionType refLargest  = fakeOut->GetLargestPossibleRegion();
    RegionType refRequest  = fakeOut->GetRequestedRegion();
    IndexType  idxLargest  = refLargest.GetIndex();
    SizeType   sizeLargest = refLargest.GetSize();
    IndexType  idxRequest  = refRequest.GetIndex();
    SizeType   sizeRequest = refRequest.GetSize();
    for (int i = 0; i < numInputs; ++i)
    {
      ImageBaseType* inputPtr = m_SinkList[i]->GetInput();
      if (!inputPtr)
      {
        return;
      }
      RegionType region = inputPtr->GetLargestPossibleRegion();
      IndexType  idx    = region.GetIndex();
      SizeType   size   = region.GetSize();
      idx[0] += size[0] * (idxRequest[0] - idxLargest[0]) / sizeLargest[0];
      idx[1] += size[1] * (idxRequest[1] - idxLargest[1]) / sizeLargest[1];
      size[0] *= sizeRequest[0] / sizeLargest[0];
      size[1] *= sizeRequest[1] / sizeLargest[1];
      region.SetIndex(idx);
      region.SetSize(size);
      inputPtr->SetRequestedRegion(region);
    }
  }
}

void MultiImageFileWriter::GenerateData()
{
  int numInputs = m_SinkList.size();
  for (int inputIndex = 0; inputIndex < numInputs; ++inputIndex)
  {
    m_SinkList[inputIndex]->Write(m_StreamRegionList[inputIndex]);
  }
}

MultiImageFileWriter::RegionType MultiImageFileWriter::GetStreamRegion(int inputIndex)
{
  const SinkBase::Pointer sink   = m_SinkList[inputIndex];
  RegionType              region = sink->GetInput()->GetLargestPossibleRegion();

  m_StreamingManager->GetSplitter()->GetSplit(m_CurrentDivision, m_NumberOfDivisions, region);
  return region;
}

} // end of namespace otb
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Facebook, Inc.
 *
 * 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.
 */

#include <thrift/lib/cpp2/async/Cpp2Channel.h>
#include <thrift/lib/cpp/transport/TTransportException.h>
#include <thrift/lib/cpp/concurrency/Util.h>

#include <folly/io/IOBufQueue.h>
#include <folly/io/Cursor.h>
#include <folly/String.h>

#include <glog/logging.h>

using std::unique_ptr;
using std::pair;
using folly::IOBuf;
using folly::IOBufQueue;
using namespace folly::io;
using namespace apache::thrift::transport;
using apache::thrift::async::TEventBase;
using namespace apache::thrift::concurrency;
using apache::thrift::async::TAsyncTransport;

namespace apache { namespace thrift {

Cpp2Channel::Cpp2Channel(
  const std::shared_ptr<TAsyncTransport>& transport,
  std::unique_ptr<FramingHandler> framingHandler,
  std::unique_ptr<ProtectionHandler> protectionHandler)
    : transport_(transport)
    , queue_(new IOBufQueue(IOBufQueue::cacheChainLength()))
    , recvCallback_(nullptr)
    , eofInvoked_(false)
    , protectionHandler_(std::move(protectionHandler))
    , framingHandler_(std::move(framingHandler)) {
  if (!protectionHandler_) {
    protectionHandler_.reset(new ProtectionHandler);
  }
  framingHandler_->setProtectionHandler(protectionHandler_.get());
  pipeline_.reset(new Pipeline(
      TAsyncTransportHandler(transport),
      folly::wangle::OutputBufferingHandler(),
      protectionHandler_,
      framingHandler_,
      this));
  // Let the pipeline know that this handler owns the pipeline itself.
  // The pipeline will then avoid destruction order issues.
  // CHECK that this operation is successful.
  CHECK(pipeline_->setOwner(this));
  pipeline_->transportActive();
  // TODO getHandler() with no index should return first valid handler?
  transportHandler_ = pipeline_->getHandler<TAsyncTransportHandler>(0);
}

folly::Future<folly::Unit> Cpp2Channel::close(Context* ctx) {
  DestructorGuard dg(this);
  processReadEOF();
  return ctx->fireClose();
}

void Cpp2Channel::closeNow() {
  // closeNow can invoke callbacks
  DestructorGuard dg(this);

  if (pipeline_) {
    if (transport_) {
      pipeline_->close();
    }
  }

  // Note that close() above might kill the pipeline_, so let's check again.
  if (pipeline_) {
    pipeline_.reset();
  }
}

void Cpp2Channel::destroy() {
  closeNow();
  MessageChannel::destroy();
}

void Cpp2Channel::attachEventBase(
  TEventBase* eventBase) {
  transportHandler_->attachEventBase(eventBase);
}

void Cpp2Channel::detachEventBase() {
  transportHandler_->detachEventBase();
}

TEventBase* Cpp2Channel::getEventBase() {
  return transport_->getEventBase();
}

void Cpp2Channel::read(Context* ctx, folly::IOBufQueue& q) {
  DestructorGuard dg(this);

  if (recvCallback_ && recvCallback_->shouldSample() && !sample_) {
    sample_.reset(new RecvCallback::sample);
    sample_->readBegin = Util::currentTimeUsec();
  }

  if (!recvCallback_) {
    LOG(INFO) << "Received a message, but no recvCallback_ installed!";
    return;
  }

  if (sample_) {
    sample_->readEnd = Util::currentTimeUsec();
  }

  recvCallback_->messageReceived(q.move(), std::move(sample_));
}

void Cpp2Channel::readEOF(Context* ctx) {
  processReadEOF();
}

void Cpp2Channel::readException(Context* ctx, folly::exception_wrapper e)  {
  DestructorGuard dg(this);
  VLOG(5) << "Got a read error: " << folly::exceptionStr(e);
  if (recvCallback_) {
    recvCallback_->messageReceiveErrorWrapped(std::move(e));
  }
  processReadEOF();
}

void Cpp2Channel::writeSuccess() noexcept {
  assert(sendCallbacks_.size() > 0);

  DestructorGuard dg(this);
  auto* cb = sendCallbacks_.front();
  if (cb) {
    cb->messageSent();
  }
  sendCallbacks_.pop_front();
}

void Cpp2Channel::writeError(size_t bytesWritten,
                               const TTransportException& ex) noexcept {
  assert(sendCallbacks_.size() > 0);

  // Pop last write request, call error callback

  DestructorGuard dg(this);
  VLOG(5) << "Got a write error: " << folly::exceptionStr(ex);
  auto* cb = sendCallbacks_.front();
  if (cb) {
    cb->messageSendError(
        folly::make_exception_wrapper<TTransportException>(ex));
  }
  sendCallbacks_.pop_front();
}

void Cpp2Channel::processReadEOF() noexcept {
  transport_->setReadCallback(nullptr);

  VLOG(5) << "Got an EOF on channel";
  if (recvCallback_ && !eofInvoked_) {
    eofInvoked_ = true;
    recvCallback_->messageChannelEOF();
  }
}

// Low level interface
void Cpp2Channel::sendMessage(SendCallback* callback,
                                std::unique_ptr<folly::IOBuf>&& buf) {
  // Callback may be null.
  assert(buf);

  if (!transport_->good()) {
    VLOG(5) << "Channel is !good() in sendMessage";
    // Callback must be last thing in sendMessage, or use guard
    if (callback) {
      callback->messageSendError(
          folly::make_exception_wrapper<TTransportException>(
            "Channel is !good()"));
    }
    return;
  }

  if (callback) {
    callback->sendQueued();
  }
  sendCallbacks_.push_back(callback);

  DestructorGuard dg(this);

  auto future = pipeline_->write(std::move(buf));
  future.then([this,dg](folly::Try<folly::Unit>&& t) {
    if (t.withException<TTransportException>(
          [&](const TTransportException& ex) {
            writeError(0, ex);
          }) ||
        t.withException<std::exception>(
          [&](const std::exception& ex) {
            writeError(0, TTransportException(ex.what()));
          })) {
      return;
    } else {
      writeSuccess();
    }
  });
}

void Cpp2Channel::setReceiveCallback(RecvCallback* callback) {
  if (recvCallback_ == callback) {
    return;
  }

  // Still want to set recvCallback_ for outstanding EOFs
  recvCallback_ = callback;

  if (!transport_->good()) {
    transport_->setReadCallback(nullptr);
    return;
  }

  if (callback) {
    transportHandler_->attachReadCallback();
  } else {
    transportHandler_->detachReadCallback();
  }
}

}} // apache::thrift
<commit_msg>thrift: async: don't pollute logs if recvCallback_ is uninstalled<commit_after>/*
 * Copyright 2014 Facebook, Inc.
 *
 * 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.
 */

#include <thrift/lib/cpp2/async/Cpp2Channel.h>
#include <thrift/lib/cpp/transport/TTransportException.h>
#include <thrift/lib/cpp/concurrency/Util.h>

#include <folly/io/IOBufQueue.h>
#include <folly/io/Cursor.h>
#include <folly/String.h>

#include <glog/logging.h>

using std::unique_ptr;
using std::pair;
using folly::IOBuf;
using folly::IOBufQueue;
using namespace folly::io;
using namespace apache::thrift::transport;
using apache::thrift::async::TEventBase;
using namespace apache::thrift::concurrency;
using apache::thrift::async::TAsyncTransport;

namespace apache { namespace thrift {

Cpp2Channel::Cpp2Channel(
  const std::shared_ptr<TAsyncTransport>& transport,
  std::unique_ptr<FramingHandler> framingHandler,
  std::unique_ptr<ProtectionHandler> protectionHandler)
    : transport_(transport)
    , queue_(new IOBufQueue(IOBufQueue::cacheChainLength()))
    , recvCallback_(nullptr)
    , eofInvoked_(false)
    , protectionHandler_(std::move(protectionHandler))
    , framingHandler_(std::move(framingHandler)) {
  if (!protectionHandler_) {
    protectionHandler_.reset(new ProtectionHandler);
  }
  framingHandler_->setProtectionHandler(protectionHandler_.get());
  pipeline_.reset(new Pipeline(
      TAsyncTransportHandler(transport),
      folly::wangle::OutputBufferingHandler(),
      protectionHandler_,
      framingHandler_,
      this));
  // Let the pipeline know that this handler owns the pipeline itself.
  // The pipeline will then avoid destruction order issues.
  // CHECK that this operation is successful.
  CHECK(pipeline_->setOwner(this));
  pipeline_->transportActive();
  // TODO getHandler() with no index should return first valid handler?
  transportHandler_ = pipeline_->getHandler<TAsyncTransportHandler>(0);
}

folly::Future<folly::Unit> Cpp2Channel::close(Context* ctx) {
  DestructorGuard dg(this);
  processReadEOF();
  return ctx->fireClose();
}

void Cpp2Channel::closeNow() {
  // closeNow can invoke callbacks
  DestructorGuard dg(this);

  if (pipeline_) {
    if (transport_) {
      pipeline_->close();
    }
  }

  // Note that close() above might kill the pipeline_, so let's check again.
  if (pipeline_) {
    pipeline_.reset();
  }
}

void Cpp2Channel::destroy() {
  closeNow();
  MessageChannel::destroy();
}

void Cpp2Channel::attachEventBase(
  TEventBase* eventBase) {
  transportHandler_->attachEventBase(eventBase);
}

void Cpp2Channel::detachEventBase() {
  transportHandler_->detachEventBase();
}

TEventBase* Cpp2Channel::getEventBase() {
  return transport_->getEventBase();
}

void Cpp2Channel::read(Context* ctx, folly::IOBufQueue& q) {
  DestructorGuard dg(this);

  if (recvCallback_ && recvCallback_->shouldSample() && !sample_) {
    sample_.reset(new RecvCallback::sample);
    sample_->readBegin = Util::currentTimeUsec();
  }

  if (!recvCallback_) {
    VLOG(5) << "Received a message, but no recvCallback_ installed!";
    return;
  }

  if (sample_) {
    sample_->readEnd = Util::currentTimeUsec();
  }

  recvCallback_->messageReceived(q.move(), std::move(sample_));
}

void Cpp2Channel::readEOF(Context* ctx) {
  processReadEOF();
}

void Cpp2Channel::readException(Context* ctx, folly::exception_wrapper e)  {
  DestructorGuard dg(this);
  VLOG(5) << "Got a read error: " << folly::exceptionStr(e);
  if (recvCallback_) {
    recvCallback_->messageReceiveErrorWrapped(std::move(e));
  }
  processReadEOF();
}

void Cpp2Channel::writeSuccess() noexcept {
  assert(sendCallbacks_.size() > 0);

  DestructorGuard dg(this);
  auto* cb = sendCallbacks_.front();
  if (cb) {
    cb->messageSent();
  }
  sendCallbacks_.pop_front();
}

void Cpp2Channel::writeError(size_t bytesWritten,
                               const TTransportException& ex) noexcept {
  assert(sendCallbacks_.size() > 0);

  // Pop last write request, call error callback

  DestructorGuard dg(this);
  VLOG(5) << "Got a write error: " << folly::exceptionStr(ex);
  auto* cb = sendCallbacks_.front();
  if (cb) {
    cb->messageSendError(
        folly::make_exception_wrapper<TTransportException>(ex));
  }
  sendCallbacks_.pop_front();
}

void Cpp2Channel::processReadEOF() noexcept {
  transport_->setReadCallback(nullptr);

  VLOG(5) << "Got an EOF on channel";
  if (recvCallback_ && !eofInvoked_) {
    eofInvoked_ = true;
    recvCallback_->messageChannelEOF();
  }
}

// Low level interface
void Cpp2Channel::sendMessage(SendCallback* callback,
                                std::unique_ptr<folly::IOBuf>&& buf) {
  // Callback may be null.
  assert(buf);

  if (!transport_->good()) {
    VLOG(5) << "Channel is !good() in sendMessage";
    // Callback must be last thing in sendMessage, or use guard
    if (callback) {
      callback->messageSendError(
          folly::make_exception_wrapper<TTransportException>(
            "Channel is !good()"));
    }
    return;
  }

  if (callback) {
    callback->sendQueued();
  }
  sendCallbacks_.push_back(callback);

  DestructorGuard dg(this);

  auto future = pipeline_->write(std::move(buf));
  future.then([this,dg](folly::Try<folly::Unit>&& t) {
    if (t.withException<TTransportException>(
          [&](const TTransportException& ex) {
            writeError(0, ex);
          }) ||
        t.withException<std::exception>(
          [&](const std::exception& ex) {
            writeError(0, TTransportException(ex.what()));
          })) {
      return;
    } else {
      writeSuccess();
    }
  });
}

void Cpp2Channel::setReceiveCallback(RecvCallback* callback) {
  if (recvCallback_ == callback) {
    return;
  }

  // Still want to set recvCallback_ for outstanding EOFs
  recvCallback_ = callback;

  if (!transport_->good()) {
    transport_->setReadCallback(nullptr);
    return;
  }

  if (callback) {
    transportHandler_->attachReadCallback();
  } else {
    transportHandler_->detachReadCallback();
  }
}

}} // apache::thrift
<|endoftext|>


<commit_before>/// @file
/// @author  Boris Mikic
/// @version 2.0
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#if HAVE_DIRECTSOUND
#include <dsound.h>

#include <hltypes/hstring.h>

#include "DirectSound_AudioManager.h"
#include "DirectSound_Player.h"
#if HAVE_WAV
#include "DirectSound_WAV_Source.h"
#endif
#include "xal.h"

namespace xal
{
	DirectSound_AudioManager::DirectSound_AudioManager(chstr systemName, unsigned long backendId, bool threaded, float updateTime, chstr deviceName) :
		AudioManager(systemName, backendId, threaded, updateTime, deviceName)
	{
		xal::log("initializing DirectSound");
		HRESULT result = DirectSoundCreate(NULL, &this->dsDevice, NULL);
		if (FAILED(result))
		{
			this->dsDevice = NULL;
			xal::log("could not create device");
			return;
		}
		result = this->dsDevice->SetCooperativeLevel((HWND)backendId, DSSCL_NORMAL);
		if (FAILED(result))
		{
			this->dsDevice->Release();
			this->dsDevice = NULL;
			xal::log("could not set cooperative level");
			return;
		}
		this->enabled = true;
		if (threaded)
		{
			this->_setupThread();
		}
	}

	DirectSound_AudioManager::~DirectSound_AudioManager()
	{
		xal::log("destroying DirectSound");
		if (this->dsDevice != NULL)
		{
			this->dsDevice->Release();
			this->dsDevice = NULL;
		}
	}

	Player* DirectSound_AudioManager::_createAudioPlayer(Sound* sound, Buffer* buffer)
	{
		return new DirectSound_Player(sound, buffer);
	}

	Source* DirectSound_AudioManager::_createSource(chstr filename, Format format)
	{
		Source* source;
		switch (format)
		{
#if HAVE_WAV
		case WAV:
			source = new DirectSound_WAV_Source(filename);
			break;
#endif
		default:
			source = AudioManager::_createSource(filename, format);
			break;
		}
		return source;
	}

}
#endif<commit_msg>- disabled DirectSound specific WAV Source implementation because of a problem when reading WAV files that are not 1411 kbps<commit_after>/// @file
/// @author  Boris Mikic
/// @version 2.0
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#if HAVE_DIRECTSOUND
#include <dsound.h>

#include <hltypes/hstring.h>

#include "DirectSound_AudioManager.h"
#include "DirectSound_Player.h"
#if HAVE_WAV
#include "DirectSound_WAV_Source.h"
#endif
#include "xal.h"

namespace xal
{
	DirectSound_AudioManager::DirectSound_AudioManager(chstr systemName, unsigned long backendId, bool threaded, float updateTime, chstr deviceName) :
		AudioManager(systemName, backendId, threaded, updateTime, deviceName)
	{
		xal::log("initializing DirectSound");
		HRESULT result = DirectSoundCreate(NULL, &this->dsDevice, NULL);
		if (FAILED(result))
		{
			this->dsDevice = NULL;
			xal::log("could not create device");
			return;
		}
		result = this->dsDevice->SetCooperativeLevel((HWND)backendId, DSSCL_NORMAL);
		if (FAILED(result))
		{
			this->dsDevice->Release();
			this->dsDevice = NULL;
			xal::log("could not set cooperative level");
			return;
		}
		this->enabled = true;
		if (threaded)
		{
			this->_setupThread();
		}
	}

	DirectSound_AudioManager::~DirectSound_AudioManager()
	{
		xal::log("destroying DirectSound");
		if (this->dsDevice != NULL)
		{
			this->dsDevice->Release();
			this->dsDevice = NULL;
		}
	}

	Player* DirectSound_AudioManager::_createAudioPlayer(Sound* sound, Buffer* buffer)
	{
		return new DirectSound_Player(sound, buffer);
	}

	Source* DirectSound_AudioManager::_createSource(chstr filename, Format format)
	{
		Source* source;
		switch (format)
		{
/*
#if HAVE_WAV
		case WAV:
			source = new DirectSound_WAV_Source(filename);
			break;
#endif
*/
		default:
			source = AudioManager::_createSource(filename, format);
			break;
		}
		return source;
	}

}
#endif<|endoftext|>


<commit_before>
// Qt includes
#include <QDebug>

// QtPropertyBrowser includes
#include <QtVariantPropertyManager>

// Visomics includes
#include "voDataObject.h"
#include "voHierarchicalClustering.h"
#include "vtkExtendedTable.h"
#include "voTableDataObject.h"

// VTK includes
#include <vtkDataSetAttributes.h>
#include <vtkDenseArray.h>
#include <vtkDoubleArray.h>
#include <vtkMutableDirectedGraph.h>
#include <vtkRCalculatorFilter.h>
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkTable.h>
#include <vtkTableToArray.h>
#include <vtkTree.h>

// --------------------------------------------------------------------------
// voHierarchicalClustering methods

// --------------------------------------------------------------------------
voHierarchicalClustering::voHierarchicalClustering():
    Superclass()
{
  // Q_D(voHierarchicalClustering);

}

// --------------------------------------------------------------------------
voHierarchicalClustering::~voHierarchicalClustering()
{
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setInputInformation()
{
  this->addInputType("input", "vtkExtendedTable");
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setOutputInformation()
{
  this->addOutputType("clusterTree", "vtkTree",
                      "voTreeGraphView", "clusterTree");
  this->addOutputType("cluster", "vtkTable",
                      "voHierarchicalClusteringHeatMapView", "Hierarchical Clustering Heat Map",
                      "voTableView", "Table (Hierarchical Clustering)");
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setParameterInformation()
{
  QList<QtProperty*> hclust_parameters;

  // HClust / Method
  QStringList hclust_methods;
  hclust_methods << "complete" << "average" << "mcquitty" << "median" << "centroid";
  hclust_parameters << this->addEnumParameter("method", tr("Method"), hclust_methods, "average");

  this->addParameterGroup("HClust parameters", hclust_parameters);
}

// --------------------------------------------------------------------------
bool voHierarchicalClustering::execute()
{
  // Q_D(voHierarchicalClustering);

  vtkExtendedTable* extendedTable =  vtkExtendedTable::SafeDownCast(this->input()->data());
  if (!extendedTable)
    {
    qWarning() << "Input is Null";
    return false;
    }

  vtkSmartPointer<vtkTable> table = vtkSmartPointer<vtkTable>::Take(extendedTable->GetDataWithRowHeader());

  // Parameters
  QString hclust_method = this->enumParameter("method");

  vtkSmartPointer< vtkTableToArray > tableToArray = vtkSmartPointer< vtkTableToArray>::New();
  tableToArray->SetInput(table);

  int start = 1;
  int end = table->GetNumberOfColumns();

  for (int ctr=start; ctr<end; ctr++)
    {
    tableToArray->AddColumn(table->GetColumnName(ctr));
    }
  tableToArray->Update();

  //Print ouf the array data for debugging purposes
//  vtkSmartPointer< vtkArrayData > arrayData = vtkSmartPointer< vtkArrayData>::New();
//  arrayData = tableToArray->GetOutput();
//  vtkIdType numberOfArrays = arrayData->GetNumberOfArrays();
//  for( vtkIdType i=0; i < numberOfArrays; i++)
//    {
//    vtkDenseArray<double> *array = vtkDenseArray<double>::SafeDownCast(arrayData->GetArray(i));
//    const vtkArrayExtents extents = array->GetExtents();
//    for(vtkIdType i = extents[0].GetBegin(); i != extents[0].GetEnd(); ++i)
//      {
//      for(vtkIdType j = extents[1].GetBegin(); j != extents[1].GetEnd(); ++j)
//        {
//        std::cout << array->GetValue(vtkArrayCoordinates(i, j)) << "\t";
//        }
//        std::cout << std::endl;
//      }
//    }

  vtkSmartPointer< vtkRCalculatorFilter > calc = vtkSmartPointer< vtkRCalculatorFilter>::New();
  calc->SetRoutput(0);
  calc->SetInput(tableToArray->GetOutput());

  /*
   * hclust class in R has the following attributes
   *
   * labels: labels for each of the objects being clustered.
   *
   * merge: an n-1 by 2 matrix.  Row i of merge describes the
   *       merging of clusters at step i of the clustering.  If an
   *       element j in the row is negative, then observation -j was
   *       merged at this stage.  If j is positive then the merge was
   *      with the cluster formed at the (earlier) stage j of the
   *      algorithm.  Thus negative entries in merge indicate
   *       agglomerations of singletons, and positive entries indicate
   *       agglomerations of non-singletons.
   *
   *
   * height: a set of n-1 non-decreasing real values.  The clustering
   *       _height_: that is, the value of the criterion associated with
   *       the clustering method for the particular agglomeration.
   *
   * order: a vector giving the permutation of the original observations
   *       suitable for plotting, in the sense that a cluster plot using
   *       this ordering and matrix merge will not have crossings
   *       of the branches.
   *
   *
   * labels : labels for each of the objects being clustered.
   *
   */
  calc->PutArray("0", "metabData");
  calc->GetArray("height","height");
  calc->GetArray("order","order");
  calc->GetArray("merge","merge");
  calc->SetRscript(QString(
                     "dEuc<-dist(t(metabData))\n"
                     "cluster<-hclust(dEuc,method=\"%1\")\n"
                     "height<-as.numeric(cluster$height)\n"
                     "order<-as.numeric(cluster$order)\n"
                     "merge<-as.numeric(cluster$merge)\n"
                     ).arg(hclust_method).toLatin1());

  calc->Update();

  vtkArrayData *temp = vtkArrayData::SafeDownCast(calc->GetOutput());
  if (!temp)
    {
    std::cout << "Downcast DID NOT work." << std::endl;
    return 1;
    }

  vtkSmartPointer<vtkArrayData> clustReturn = vtkSmartPointer<vtkArrayData>::New();
  clustReturn->DeepCopy(temp);

  vtkSmartPointer<vtkArrayData> heightData = vtkSmartPointer<vtkArrayData>::New();
  heightData->AddArray(clustReturn->GetArrayByName("height"));

  vtkDenseArray<double> *heigtArray = vtkDenseArray<double>::SafeDownCast(heightData->GetArray(0));
  const vtkArrayExtents heightExtent = heigtArray->GetExtents();

  vtkSmartPointer<vtkArrayData> orderData = vtkSmartPointer<vtkArrayData>::New();
  orderData->AddArray(clustReturn->GetArrayByName("order"));

  vtkSmartPointer<vtkArrayData> mergeData = vtkSmartPointer<vtkArrayData>::New();
  mergeData->AddArray(clustReturn->GetArrayByName("merge"));

  vtkDenseArray<double> *mergeArray = vtkDenseArray<double>::SafeDownCast(mergeData->GetArray(0));

//  const vtkArrayExtents matrixExtent = mergeArray->GetExtents();

  //Start constructing the graph too
  vtkSmartPointer<vtkMutableDirectedGraph> builder = vtkSmartPointer<vtkMutableDirectedGraph>::New();

  //generate array to label the vertices
  vtkSmartPointer<vtkStringArray> clusterLabel = vtkSmartPointer<vtkStringArray>::New();
  clusterLabel->SetName("id");

  //generate array to store the vertices height
  vtkSmartPointer<vtkDoubleArray> distanceArray = vtkSmartPointer<vtkDoubleArray>::New();
  distanceArray->SetName("Height");

  /* Each time we create a parent "id", store the corresponding vertex id */

  vtkstd::map<int,int> clusterMap;

  int clusterIndex=0;

  for(int i = 0; i != heightExtent[0].GetEnd(); ++i)
    {
    int firstClusterIndex;
    int secondClusterIndex;

    /* The following is needed to find the corresponding indices in the matrix */
    firstClusterIndex = i;
    secondClusterIndex = firstClusterIndex + heightExtent[0].GetEnd();

    int firstCluster  =  mergeArray->GetValue(vtkArrayCoordinates(firstClusterIndex));
    int secondCluster =  mergeArray->GetValue(vtkArrayCoordinates(secondClusterIndex));

    /** Three scenario:
    *  if both  values are negative, create two new childs and a new vertex in the tree
    *  if either one is positive,  create a new child and join it with already existing vertex
    *  if both positive, join two already existing vertices in the tree
    */

    if( firstCluster < 0 && secondCluster < 0 )
      {
      vtkIdType parent = builder->AddVertex();
      clusterLabel->InsertNextValue( "" );
      clusterMap[clusterIndex] = parent;
      clusterIndex++;

      double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
      double heightChildrean = heightParent - 0.02; // arbitrary
      distanceArray->InsertNextValue(heightParent);

      vtkIdType child1 = builder->AddVertex();
      clusterLabel->InsertNextValue( table->GetColumnName( abs(firstCluster)) );
      distanceArray->InsertNextValue(heightChildrean);

      vtkIdType child2 = builder->AddVertex();
      clusterLabel->InsertNextValue( table->GetColumnName( abs(secondCluster)) );
      distanceArray->InsertNextValue(heightChildrean);

      builder->AddEdge( parent, child1);
      builder->AddEdge( parent, child2);

      }
    else if( firstCluster > 0 && secondCluster > 0 )
      {
      vtkIdType parent = builder->AddVertex();
      clusterLabel->InsertNextValue ( "");
      clusterMap[clusterIndex] = parent;
      clusterIndex++;

      double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
      // double heightChildrean = heightParent - 0.1; // arbitrary
      distanceArray->InsertNextValue(heightParent);

      int clusterNumber1 = clusterMap[firstCluster - 1];
      int clusterNumber2 = clusterMap[secondCluster - 1];

      builder->AddEdge( parent, clusterNumber1 );
      builder->AddEdge( parent, clusterNumber2 );
      }
    else
      {

      if ( firstCluster < 0 )
        {
        vtkIdType parent = builder->AddVertex();
        clusterLabel->InsertNextValue ( "");
        clusterMap[clusterIndex] = parent;
        clusterIndex++;

        double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
        double heightChildrean = heightParent - 0.1;// arbitrary
        distanceArray->InsertNextValue(heightParent);

        vtkIdType child = builder->AddVertex();
        clusterLabel->InsertNextValue( table->GetColumnName( abs(firstCluster)) );
        distanceArray->InsertNextValue(heightChildrean);

        int clusterNumber  = clusterMap[secondCluster - 1]; // R cluster index starts from 1

        builder->AddEdge( parent, child );
        builder->AddEdge( parent, clusterNumber );
        }
      else
        {
        vtkIdType parent = builder->AddVertex();
        clusterLabel->InsertNextValue ( "");
        clusterMap[clusterIndex] = parent;
        clusterIndex++;

        double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
        double heightChildrean = heightParent-0.1; // arbitrary
        distanceArray->InsertNextValue(heightParent);

        vtkIdType child = builder->AddVertex();
        clusterLabel->InsertNextValue( table->GetColumnName( abs(secondCluster)) );
        distanceArray->InsertNextValue(heightChildrean);

        // int clusterNumber = clusterMap[firstCluster - 1]; // R cluster index start from 1
        builder->AddEdge( parent, child );
        builder->AddEdge( parent, firstCluster );
        }
      }
    }

  vtkSmartPointer<vtkTree> tree = vtkSmartPointer<vtkTree>::New();
  tree->ShallowCopy(builder);

  //Add vertex attributes
  tree->GetVertexData()->AddArray(clusterLabel);
  tree->GetVertexData()->AddArray(distanceArray);

  this->setOutput("clusterTree", new voDataObject("clusterTree", tree));

  vtkSmartPointer<vtkTable> clusterTable = vtkSmartPointer<vtkTable>::New();
  // Set up headers for the rows.
  vtkSmartPointer<vtkStringArray> header = vtkStringArray::SafeDownCast(table->GetColumn(0));
  if (!header)
    {
    std::cout << "Downcast DID NOT work." << std::endl;
    return 1;
    }

  clusterTable->AddColumn(header);

  for (vtkIdType c = 0;c < table->GetNumberOfColumns(); ++c)
    {
    vtkAbstractArray* col = table->GetColumn(c);
    col->SetName(header->GetValue(c));
    clusterTable->AddColumn(col);
    }
  this->setOutput("cluster", new voTableDataObject("cluster", clusterTable));

  return true;
}
<commit_msg>BUG: Remove table visualization for hierarchical clustering<commit_after>
// Qt includes
#include <QDebug>

// QtPropertyBrowser includes
#include <QtVariantPropertyManager>

// Visomics includes
#include "voDataObject.h"
#include "voHierarchicalClustering.h"
#include "vtkExtendedTable.h"
#include "voTableDataObject.h"

// VTK includes
#include <vtkDataSetAttributes.h>
#include <vtkDenseArray.h>
#include <vtkDoubleArray.h>
#include <vtkMutableDirectedGraph.h>
#include <vtkRCalculatorFilter.h>
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkTable.h>
#include <vtkTableToArray.h>
#include <vtkTree.h>

// --------------------------------------------------------------------------
// voHierarchicalClustering methods

// --------------------------------------------------------------------------
voHierarchicalClustering::voHierarchicalClustering():
    Superclass()
{
  // Q_D(voHierarchicalClustering);

}

// --------------------------------------------------------------------------
voHierarchicalClustering::~voHierarchicalClustering()
{
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setInputInformation()
{
  this->addInputType("input", "vtkExtendedTable");
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setOutputInformation()
{
  this->addOutputType("clusterTree", "vtkTree",
                      "voTreeGraphView", "clusterTree");
/*  this->addOutputType("cluster", "vtkTable",
                      "voHierarchicalClusteringHeatMapView", "HeatMap",
                      "voTableView", "Table (Hierarchical Clustering)"); */

  this->addOutputType("cluster", "vtkTable",
                      "voHierarchicalClusteringHeatMapView", "HeatMap");
}

// --------------------------------------------------------------------------
void voHierarchicalClustering::setParameterInformation()
{
  QList<QtProperty*> hclust_parameters;

  // HClust / Method
  QStringList hclust_methods;
  hclust_methods << "complete" << "average" << "mcquitty" << "median" << "centroid";
  hclust_parameters << this->addEnumParameter("method", tr("Method"), hclust_methods, "average");

  this->addParameterGroup("HClust parameters", hclust_parameters);
}

// --------------------------------------------------------------------------
bool voHierarchicalClustering::execute()
{
  // Q_D(voHierarchicalClustering);

  vtkExtendedTable* extendedTable =  vtkExtendedTable::SafeDownCast(this->input()->data());
  if (!extendedTable)
    {
    qWarning() << "Input is Null";
    return false;
    }

  vtkSmartPointer<vtkTable> table = vtkSmartPointer<vtkTable>::Take(extendedTable->GetDataWithRowHeader());

  // Parameters
  QString hclust_method = this->enumParameter("method");

  vtkSmartPointer< vtkTableToArray > tableToArray = vtkSmartPointer< vtkTableToArray>::New();
  tableToArray->SetInput(table);

  int start = 1;
  int end = table->GetNumberOfColumns();

  for (int ctr=start; ctr<end; ctr++)
    {
    tableToArray->AddColumn(table->GetColumnName(ctr));
    }
  tableToArray->Update();

  //Print ouf the array data for debugging purposes
//  vtkSmartPointer< vtkArrayData > arrayData = vtkSmartPointer< vtkArrayData>::New();
//  arrayData = tableToArray->GetOutput();
//  vtkIdType numberOfArrays = arrayData->GetNumberOfArrays();
//  for( vtkIdType i=0; i < numberOfArrays; i++)
//    {
//    vtkDenseArray<double> *array = vtkDenseArray<double>::SafeDownCast(arrayData->GetArray(i));
//    const vtkArrayExtents extents = array->GetExtents();
//    for(vtkIdType i = extents[0].GetBegin(); i != extents[0].GetEnd(); ++i)
//      {
//      for(vtkIdType j = extents[1].GetBegin(); j != extents[1].GetEnd(); ++j)
//        {
//        std::cout << array->GetValue(vtkArrayCoordinates(i, j)) << "\t";
//        }
//        std::cout << std::endl;
//      }
//    }

  vtkSmartPointer< vtkRCalculatorFilter > calc = vtkSmartPointer< vtkRCalculatorFilter>::New();
  calc->SetRoutput(0);
  calc->SetInput(tableToArray->GetOutput());

  /*
   * hclust class in R has the following attributes
   *
   * labels: labels for each of the objects being clustered.
   *
   * merge: an n-1 by 2 matrix.  Row i of merge describes the
   *       merging of clusters at step i of the clustering.  If an
   *       element j in the row is negative, then observation -j was
   *       merged at this stage.  If j is positive then the merge was
   *      with the cluster formed at the (earlier) stage j of the
   *      algorithm.  Thus negative entries in merge indicate
   *       agglomerations of singletons, and positive entries indicate
   *       agglomerations of non-singletons.
   *
   *
   * height: a set of n-1 non-decreasing real values.  The clustering
   *       _height_: that is, the value of the criterion associated with
   *       the clustering method for the particular agglomeration.
   *
   * order: a vector giving the permutation of the original observations
   *       suitable for plotting, in the sense that a cluster plot using
   *       this ordering and matrix merge will not have crossings
   *       of the branches.
   *
   *
   * labels : labels for each of the objects being clustered.
   *
   */
  calc->PutArray("0", "metabData");
  calc->GetArray("height","height");
  calc->GetArray("order","order");
  calc->GetArray("merge","merge");
  calc->SetRscript(QString(
                     "dEuc<-dist(t(metabData))\n"
                     "cluster<-hclust(dEuc,method=\"%1\")\n"
                     "height<-as.numeric(cluster$height)\n"
                     "order<-as.numeric(cluster$order)\n"
                     "merge<-as.numeric(cluster$merge)\n"
                     ).arg(hclust_method).toLatin1());

  calc->Update();

  vtkArrayData *temp = vtkArrayData::SafeDownCast(calc->GetOutput());
  if (!temp)
    {
    std::cout << "Downcast DID NOT work." << std::endl;
    return 1;
    }

  vtkSmartPointer<vtkArrayData> clustReturn = vtkSmartPointer<vtkArrayData>::New();
  clustReturn->DeepCopy(temp);

  vtkSmartPointer<vtkArrayData> heightData = vtkSmartPointer<vtkArrayData>::New();
  heightData->AddArray(clustReturn->GetArrayByName("height"));

  vtkDenseArray<double> *heigtArray = vtkDenseArray<double>::SafeDownCast(heightData->GetArray(0));
  const vtkArrayExtents heightExtent = heigtArray->GetExtents();

  vtkSmartPointer<vtkArrayData> orderData = vtkSmartPointer<vtkArrayData>::New();
  orderData->AddArray(clustReturn->GetArrayByName("order"));

  vtkSmartPointer<vtkArrayData> mergeData = vtkSmartPointer<vtkArrayData>::New();
  mergeData->AddArray(clustReturn->GetArrayByName("merge"));

  vtkDenseArray<double> *mergeArray = vtkDenseArray<double>::SafeDownCast(mergeData->GetArray(0));

//  const vtkArrayExtents matrixExtent = mergeArray->GetExtents();

  //Start constructing the graph too
  vtkSmartPointer<vtkMutableDirectedGraph> builder = vtkSmartPointer<vtkMutableDirectedGraph>::New();

  //generate array to label the vertices
  vtkSmartPointer<vtkStringArray> clusterLabel = vtkSmartPointer<vtkStringArray>::New();
  clusterLabel->SetName("id");

  //generate array to store the vertices height
  vtkSmartPointer<vtkDoubleArray> distanceArray = vtkSmartPointer<vtkDoubleArray>::New();
  distanceArray->SetName("Height");

  /* Each time we create a parent "id", store the corresponding vertex id */

  vtkstd::map<int,int> clusterMap;

  int clusterIndex=0;

  for(int i = 0; i != heightExtent[0].GetEnd(); ++i)
    {
    int firstClusterIndex;
    int secondClusterIndex;

    /* The following is needed to find the corresponding indices in the matrix */
    firstClusterIndex = i;
    secondClusterIndex = firstClusterIndex + heightExtent[0].GetEnd();

    int firstCluster  =  mergeArray->GetValue(vtkArrayCoordinates(firstClusterIndex));
    int secondCluster =  mergeArray->GetValue(vtkArrayCoordinates(secondClusterIndex));

    /** Three scenario:
    *  if both  values are negative, create two new childs and a new vertex in the tree
    *  if either one is positive,  create a new child and join it with already existing vertex
    *  if both positive, join two already existing vertices in the tree
    */

    if( firstCluster < 0 && secondCluster < 0 )
      {
      vtkIdType parent = builder->AddVertex();
      clusterLabel->InsertNextValue( "" );
      clusterMap[clusterIndex] = parent;
      clusterIndex++;

      double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
      double heightChildrean = heightParent - 0.02; // arbitrary
      distanceArray->InsertNextValue(heightParent);

      vtkIdType child1 = builder->AddVertex();
      clusterLabel->InsertNextValue( table->GetColumnName( abs(firstCluster)) );
      distanceArray->InsertNextValue(heightChildrean);

      vtkIdType child2 = builder->AddVertex();
      clusterLabel->InsertNextValue( table->GetColumnName( abs(secondCluster)) );
      distanceArray->InsertNextValue(heightChildrean);

      builder->AddEdge( parent, child1);
      builder->AddEdge( parent, child2);

      }
    else if( firstCluster > 0 && secondCluster > 0 )
      {
      vtkIdType parent = builder->AddVertex();
      clusterLabel->InsertNextValue ( "");
      clusterMap[clusterIndex] = parent;
      clusterIndex++;

      double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
      // double heightChildrean = heightParent - 0.1; // arbitrary
      distanceArray->InsertNextValue(heightParent);

      int clusterNumber1 = clusterMap[firstCluster - 1];
      int clusterNumber2 = clusterMap[secondCluster - 1];

      builder->AddEdge( parent, clusterNumber1 );
      builder->AddEdge( parent, clusterNumber2 );
      }
    else
      {

      if ( firstCluster < 0 )
        {
        vtkIdType parent = builder->AddVertex();
        clusterLabel->InsertNextValue ( "");
        clusterMap[clusterIndex] = parent;
        clusterIndex++;

        double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
        double heightChildrean = heightParent - 0.1;// arbitrary
        distanceArray->InsertNextValue(heightParent);

        vtkIdType child = builder->AddVertex();
        clusterLabel->InsertNextValue( table->GetColumnName( abs(firstCluster)) );
        distanceArray->InsertNextValue(heightChildrean);

        int clusterNumber  = clusterMap[secondCluster - 1]; // R cluster index starts from 1

        builder->AddEdge( parent, child );
        builder->AddEdge( parent, clusterNumber );
        }
      else
        {
        vtkIdType parent = builder->AddVertex();
        clusterLabel->InsertNextValue ( "");
        clusterMap[clusterIndex] = parent;
        clusterIndex++;

        double heightParent =  heigtArray->GetValue(vtkArrayCoordinates(i));
        double heightChildrean = heightParent-0.1; // arbitrary
        distanceArray->InsertNextValue(heightParent);

        vtkIdType child = builder->AddVertex();
        clusterLabel->InsertNextValue( table->GetColumnName( abs(secondCluster)) );
        distanceArray->InsertNextValue(heightChildrean);

        // int clusterNumber = clusterMap[firstCluster - 1]; // R cluster index start from 1
        builder->AddEdge( parent, child );
        builder->AddEdge( parent, firstCluster );
        }
      }
    }

  vtkSmartPointer<vtkTree> tree = vtkSmartPointer<vtkTree>::New();
  tree->ShallowCopy(builder);

  //Add vertex attributes
  tree->GetVertexData()->AddArray(clusterLabel);
  tree->GetVertexData()->AddArray(distanceArray);

  this->setOutput("clusterTree", new voDataObject("clusterTree", tree));

  vtkSmartPointer<vtkTable> clusterTable = vtkSmartPointer<vtkTable>::New();
  // Set up headers for the rows.
  vtkSmartPointer<vtkStringArray> header = vtkStringArray::SafeDownCast(table->GetColumn(0));
  if (!header)
    {
    std::cout << "Downcast DID NOT work." << std::endl;
    return 1;
    }

  clusterTable->AddColumn(header);

  for (vtkIdType c = 0;c < table->GetNumberOfColumns(); ++c)
    {
    vtkAbstractArray* col = table->GetColumn(c);
    col->SetName(header->GetValue(c));
    clusterTable->AddColumn(col);
    }
  this->setOutput("cluster", new voTableDataObject("cluster", clusterTable));

  return true;
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                 OpenSim:  testSerializeOpenSimObjects.cpp                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Ayman Habib                                                     *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>
#include <OpenSim/Common/osimCommon.h>
#include <OpenSim/Simulation/osimSimulation.h>
#include <OpenSim/Actuators/osimActuators.h>
#include <OpenSim/Analyses/osimAnalyses.h>

using namespace OpenSim;
using namespace std;

void testPropertiesDump(const OpenSim::Object& aObject);

static void indent(int nSpaces) {
    for (int i=0; i<nSpaces; ++i) cout << " ";
}

// Recursively dump out contents of an object and its properties.
static void dumpObj(const Object& obj, int nSpaces) {
    indent(nSpaces);
    cout << obj.getConcreteClassName() << " Object "
         << (obj.getName().empty()?"NONAME":obj.getName())
         << endl;
    for (int p=0; p < obj.getNumProperties(); ++p) {
        const AbstractProperty& ap = obj.getPropertyByIndex(p);
        indent(nSpaces+2);
        cout << ap.getName() << "=" << ap.toString() << endl;
        // Check return values from Property API for debugging purposes
        bool t1 = ap.isListProperty();
        bool t2 = ap.isObjectProperty();
        bool t3 = ap.isOneObjectProperty();
        bool t4 = ap.isOneValueProperty();
        string ts = ap.getTypeName();
        indent(nSpaces+2);
        cout << "isList, isObject, isOneObject, isOneValue, typeName = " <<
            t1 <<", "<< t2 <<", "<< t3 <<", "<< t4 <<", "<< ts << endl;
        if (ap.isObjectProperty()) {
            for (int i=0; i < ap.size(); ++i)
                dumpObj(ap.getValueAsObject(i), nSpaces+4);
        }
    }
}

int main()
{
    // Actuators library is not loaded automatically (unless using clang).
    #if !defined(__clang__)
        LoadOpenSimLibrary("osimActuators");
    #endif

    try {
        Model testModel;
        srand((unsigned)time(0));

        //Test serialization for all ModelComponents
        ArrayPtrs<OpenSim::ModelComponent> availableComponentTypes;
        Object::getRegisteredObjectsOfGivenType<OpenSim::ModelComponent>(availableComponentTypes);
        for (int i=0; i< availableComponentTypes.getSize(); i++){
            Object* clone = availableComponentTypes[i]->clone();
            Object* randClone = randomize(clone);
            try {
                testModel.addModelComponent(ModelComponent::safeDownCast(randClone));
            } //Ignore the validity of the property values
            // TODO this should specifically handle "InvalidPropertyValue" exceptions
            // once we have that in place.
            catch (const std::exception&) {
                // const string& errMsg = err.getMessage();
                //std::cout << errMsg << std::endl;
            }
        }

        int nc = testModel.getMiscModelComponentSet().getSize();
        cout << nc << " model components were serialized in testModel." << endl;

        //Serialize all the components
        testModel.print("allComponents.osim");

        // The finalize flag is for testing purposes ONLY. This way we
        // can ignore invalid properties and focus the test on serialization.
        Model deserializedModel("allComponents.osim");

        try {
            deserializedModel.finalizeFromProperties();
        }
        //Ignore the validity of the property values
        // TODO this should specifically handle "InvalidPropertyValue" exceptions
        // once we have that in place.
        catch (const std::exception&) {
            // const string& errMsg = err.getMessage();
            //std::cout << errMsg << std::endl;
        }

        nc = deserializedModel.getMiscModelComponentSet().getSize();
        cout << nc << " model components were deserialized from file." << endl;

        ASSERT(testModel == deserializedModel,
            "deserializedModel FAILED to match original model.");

        //Might as well test cloning and assignment
        Model* cloneModel = testModel.clone();

        ASSERT(testModel == *cloneModel,
            "cloneModel FAILED to match original model.");

        Model assignedModel = *cloneModel;

        delete cloneModel;

        ASSERT(testModel == assignedModel,
            "assignedModel FAILED to match original model.");

    }
    catch (const Exception& e) {
        e.print(cerr);
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}

void testPropertiesDump(const Object& aObject)
{
    dumpObj(aObject, 4);
}
<commit_msg>Revise outdated comment <commit_after>/* -------------------------------------------------------------------------- *
 *                 OpenSim:  testSerializeOpenSimObjects.cpp                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Ayman Habib                                                     *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>
#include <OpenSim/Common/osimCommon.h>
#include <OpenSim/Simulation/osimSimulation.h>
#include <OpenSim/Actuators/osimActuators.h>
#include <OpenSim/Analyses/osimAnalyses.h>

using namespace OpenSim;
using namespace std;

void testPropertiesDump(const OpenSim::Object& aObject);

static void indent(int nSpaces) {
    for (int i=0; i<nSpaces; ++i) cout << " ";
}

// Recursively dump out contents of an object and its properties.
static void dumpObj(const Object& obj, int nSpaces) {
    indent(nSpaces);
    cout << obj.getConcreteClassName() << " Object "
         << (obj.getName().empty()?"NONAME":obj.getName())
         << endl;
    for (int p=0; p < obj.getNumProperties(); ++p) {
        const AbstractProperty& ap = obj.getPropertyByIndex(p);
        indent(nSpaces+2);
        cout << ap.getName() << "=" << ap.toString() << endl;
        // Check return values from Property API for debugging purposes
        bool t1 = ap.isListProperty();
        bool t2 = ap.isObjectProperty();
        bool t3 = ap.isOneObjectProperty();
        bool t4 = ap.isOneValueProperty();
        string ts = ap.getTypeName();
        indent(nSpaces+2);
        cout << "isList, isObject, isOneObject, isOneValue, typeName = " <<
            t1 <<", "<< t2 <<", "<< t3 <<", "<< t4 <<", "<< ts << endl;
        if (ap.isObjectProperty()) {
            for (int i=0; i < ap.size(); ++i)
                dumpObj(ap.getValueAsObject(i), nSpaces+4);
        }
    }
}

int main()
{
    // Actuators library is not loaded automatically (unless using clang).
    #if !defined(__clang__)
        LoadOpenSimLibrary("osimActuators");
    #endif

    try {
        Model testModel;
        srand((unsigned)time(0));

        //Test serialization for all ModelComponents
        ArrayPtrs<OpenSim::ModelComponent> availableComponentTypes;
        Object::getRegisteredObjectsOfGivenType<OpenSim::ModelComponent>(availableComponentTypes);
        for (int i=0; i< availableComponentTypes.getSize(); i++){
            Object* clone = availableComponentTypes[i]->clone();
            Object* randClone = randomize(clone);
            try {
                testModel.addModelComponent(ModelComponent::safeDownCast(randClone));
            } //Ignore the validity of the property values
            // TODO this should specifically handle "InvalidPropertyValue" exceptions
            // once we have that in place.
            catch (const std::exception&) {
                // const string& errMsg = err.getMessage();
                //std::cout << errMsg << std::endl;
            }
        }

        int nc = testModel.getMiscModelComponentSet().getSize();
        cout << nc << " model components were serialized in testModel." << endl;

        //Serialize all the components
        testModel.print("allComponents.osim");

        // Now, deserilaize the Model from file
        Model deserializedModel("allComponents.osim");

        try {
            deserializedModel.finalizeFromProperties();
        }
        //Ignore the validity of the property values
        // TODO this should specifically handle "InvalidPropertyValue" exceptions
        // once we have that in place.
        catch (const std::exception&) {
            // const string& errMsg = err.getMessage();
            //std::cout << errMsg << std::endl;
        }

        nc = deserializedModel.getMiscModelComponentSet().getSize();
        cout << nc << " model components were deserialized from file." << endl;

        ASSERT(testModel == deserializedModel,
            "deserializedModel FAILED to match original model.");

        //Might as well test cloning and assignment
        Model* cloneModel = testModel.clone();

        ASSERT(testModel == *cloneModel,
            "cloneModel FAILED to match original model.");

        Model assignedModel = *cloneModel;

        delete cloneModel;

        ASSERT(testModel == assignedModel,
            "assignedModel FAILED to match original model.");

    }
    catch (const Exception& e) {
        e.print(cerr);
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}

void testPropertiesDump(const Object& aObject)
{
    dumpObj(aObject, 4);
}
<|endoftext|>