<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_OPERATOR_ELLIPTIC_HH
#define DUNE_GDT_OPERATOR_ELLIPTIC_HH

#include <type_traits>

#include <dune/stuff/la/container/interfaces.hh>
#include <dune/stuff/functions/interfaces.hh>

#include <dune/gdt/space/interface.hh>
#include <dune/gdt/localevaluation/elliptic.hh>
#include <dune/gdt/localoperator/codim0.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {
namespace Operator {

// forward, to be used in the traits
template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp                                                              = typename SourceSpaceImp::GridViewType>
class EllipticCG;

template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp                                                              = typename SourceSpaceImp::GridViewType>
class EllipticCGTraits
{
  static_assert(std::is_base_of<Stuff::LocalizableFunctionInterface<
                                    typename DiffusionImp::EntityType, typename DiffusionImp::DomainFieldType,
                                    DiffusionImp::dimDomain, typename DiffusionImp::RangeFieldType,
                                    DiffusionImp::dimRange, DiffusionImp::dimRangeCols>,
                                DiffusionImp>::value,
                "DiffusionImp has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of<Stuff::LA::MatrixInterface<typename MatrixImp::Traits>, MatrixImp>::value,
                "MatrixImp has to be derived from Stuff::LA::MatrixInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename SourceSpaceImp::Traits>, SourceSpaceImp>::value,
                "SourceSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename RangeSpaceImp::Traits>, RangeSpaceImp>::value,
                "RangeSpaceImp has to be derived from SpaceInterface!");

public:
  typedef EllipticCG<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp> derived_type;
  typedef MatrixImp MatrixType;
  typedef SourceSpaceImp SourceSpaceType;
  typedef RangeSpaceImp RangeSpaceType;
  typedef GridViewImp GridViewType;

private:
  typedef DiffusionImp DiffusionType;

public:
  typedef LocalOperator::Codim0Integral<LocalEvaluation::Elliptic<DiffusionType>> LocalOperatorType;

private:
  friend class EllipticCG<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp>;
}; // class EllipticTraits

template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp>
class EllipticCG : public AssemblableVolumeOperatorBase<EllipticCGTraits<DiffusionImp, MatrixImp, SourceSpaceImp,
                                                                         RangeSpaceImp, GridViewImp>>
{
public:
  typedef EllipticCGTraits<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp> Traits;

private:
  typedef AssemblableVolumeOperatorBase<Traits> BaseType;

  typedef typename Traits::DiffusionType DiffusionType;
  typedef typename Traits::LocalOperatorType LocalOperatorType;

public:
  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::SourceSpaceType SourceSpaceType;
  typedef typename Traits::RangeSpaceType RangeSpaceType;
  typedef typename Traits::GridViewType GridViewType;

  using BaseType::pattern;

  static Stuff::LA::SparsityPatternDefault pattern(const RangeSpaceType& range_space,
                                                   const SourceSpaceType& source_space, const GridViewType& grid_view)
  {
    return range_space.compute_volume_pattern(grid_view, source_space);
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space,
             const RangeSpaceType& range_space, const GridViewType& grid_view)
    : BaseType(matrix, source_space, range_space, grid_view)
    , local_operator_(diffusion)
  {
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space,
             const RangeSpaceType& range_space)
    : BaseType(matrix, source_space, range_space)
    , local_operator_(diffusion)
  {
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space)
    : BaseType(matrix, source_space)
    , local_operator_(diffusion)
  {
  }

private:
  virtual const LocalOperatorType& local_operator() const
  {
    return local_operator_;
  }

  const LocalOperatorType local_operator_;
}; // class EllipticCG

} // namespace Operator
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_OPERATOR_ELLIPTIC_HH
<commit_msg>[operator.elliptic] update<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_OPERATOR_ELLIPTIC_HH
#define DUNE_GDT_OPERATOR_ELLIPTIC_HH

#include <type_traits>

#include <dune/stuff/la/container/interfaces.hh>
#include <dune/stuff/functions/interfaces.hh>

#include <dune/gdt/space/interface.hh>
#include <dune/gdt/localevaluation/elliptic.hh>
#include <dune/gdt/localoperator/codim0.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Operator {

// forward, to be used in the traits
template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp                                                              = typename SourceSpaceImp::GridViewType>
class EllipticCG;

template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp                                                              = typename SourceSpaceImp::GridViewType>
class EllipticCGTraits
{
  static_assert(std::is_base_of<Stuff::LocalizableFunctionInterface<
                                    typename DiffusionImp::EntityType, typename DiffusionImp::DomainFieldType,
                                    DiffusionImp::dimDomain, typename DiffusionImp::RangeFieldType,
                                    DiffusionImp::dimRange, DiffusionImp::dimRangeCols>,
                                DiffusionImp>::value,
                "DiffusionImp has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of<Stuff::LA::MatrixInterface<typename MatrixImp::Traits>, MatrixImp>::value,
                "MatrixImp has to be derived from Stuff::LA::MatrixInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename SourceSpaceImp::Traits>, SourceSpaceImp>::value,
                "SourceSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename RangeSpaceImp::Traits>, RangeSpaceImp>::value,
                "RangeSpaceImp has to be derived from SpaceInterface!");

public:
  typedef EllipticCG<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp> derived_type;
  typedef MatrixImp MatrixType;
  typedef SourceSpaceImp SourceSpaceType;
  typedef RangeSpaceImp RangeSpaceType;
  typedef GridViewImp GridViewType;

private:
  typedef DiffusionImp DiffusionType;

public:
  typedef LocalOperator::Codim0Integral<LocalEvaluation::Elliptic<DiffusionType>> LocalOperatorType;

private:
  friend class EllipticCG<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp>;
}; // class EllipticTraits

template <class DiffusionImp, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp>
class EllipticCG : public Operator::AssemblableVolumeBase<EllipticCGTraits<DiffusionImp, MatrixImp, SourceSpaceImp,
                                                                           RangeSpaceImp, GridViewImp>>
{
public:
  typedef EllipticCGTraits<DiffusionImp, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp> Traits;

private:
  typedef Operator::AssemblableVolumeBase<Traits> BaseType;

  typedef typename Traits::DiffusionType DiffusionType;
  typedef typename Traits::LocalOperatorType LocalOperatorType;

public:
  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::SourceSpaceType SourceSpaceType;
  typedef typename Traits::RangeSpaceType RangeSpaceType;
  typedef typename Traits::GridViewType GridViewType;

  using BaseType::pattern;

  static Stuff::LA::SparsityPatternDefault pattern(const RangeSpaceType& range_space,
                                                   const SourceSpaceType& source_space, const GridViewType& grid_view)
  {
    return range_space.compute_volume_pattern(grid_view, source_space);
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space,
             const RangeSpaceType& range_space, const GridViewType& grid_view)
    : BaseType(matrix, source_space, range_space, grid_view)
    , local_operator_(diffusion)
  {
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space,
             const RangeSpaceType& range_space)
    : BaseType(matrix, source_space, range_space)
    , local_operator_(diffusion)
  {
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space)
    : BaseType(matrix, source_space)
    , local_operator_(diffusion)
  {
  }

private:
  virtual const LocalOperatorType& local_operator() const DS_OVERRIDE DS_FINAL
  {
    return local_operator_;
  }

  const LocalOperatorType local_operator_;
}; // class EllipticCG

} // namespace Operator
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_OPERATOR_ELLIPTIC_HH
<|endoftext|>


<commit_before>#ifndef SOLUTION_HPP
#define SOLUTION_HPP

#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>

using namespace std;

class Solution {
 public:
  vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
    auto arrsum = [&nums](int a, int b) {
      int s = 0;
      for (int i = a; i < b; ++i) {
        s += nums[i];
      }
      return s;
    };
    const int N = nums.size();
    const int inf = 0x3f3f3f3f;
    vector<int> dp_(3 * N, -inf);
    auto dp = (int(*)[N])(&dp_[0]);
    vector<int> idx_(3 * N * 3, 0);
    auto idx = (int(*)[N][3])(&idx_[0]);
    int ans[3] = {inf, inf, inf};
    for (int t = 0; t < 3; ++t) {
      int x = t % 2;
      int start = (t + 1) * k - 1;
      ans[t] = start;
      for (int a = start; a < N;
           ++a) {  // index where the new subarray may end
        dp[t][a] = a > start ? dp[t][a - 1] : -inf; // init as the prev sum
        if (a > start) {
          copy(begin(idx[t][a - 1]), end(idx[t][a - 1]), begin(idx[t][a]));
        }
        // max sum when array is placed
        int es = -inf;
        if (t == 0) {
          es = arrsum(a - k + 1, a + 1);
        } else {
          int prev = dp[t - 1][a - k];
          if (prev != -inf) {
            es = arrsum(a - k + 1, a + 1) + prev;
          }
        }
        // ---
        if (es > dp[t][a]) {
          //cout << "(t, a) = " << '(' << t << ", " << a << ')' << '\n';
          //cout << "(es, dp[t][a]) = " << '(' << es << ", " << dp[t][a] << ')' << '\n';
          if (t > 0) {
            copy(begin(idx[t - 1][a - k]), end(idx[t - 1][a - k]), begin(idx[t][a]));
          }
          idx[t][a][t] = a - k + 1;
          copy(begin(idx[t][a]), end(idx[t][a]), begin(ans));
          dp[t][a] = es;
        }
      }
      //cout << "idx:\n";
      for (int t = 0; t < 3; ++t) {
        for (int a = 0; a < N; ++a) {
          for (int i = 0; i < 3; ++i) {
            //cout << idx[t][a][i] << ",";
          }
          //cout << "| ";
        }
        //cout << '\n';
      }
      //cout << '\n';
      //cout << "ans:\n";
      for (int a = 0; a < 3; ++a) {
        //cout << ans[a] << ", ";
      }
      //cout << '\n';
    }
    //cout << "dp:\n";
    for (int t = 0; t < 3; ++t) {
      for (int a = 0; a < N; ++a) {
        //cout << dp[t][a] << ", ";
      }
      //cout << '\n';
    }
    //cout << '\n';
    return {ans[0], ans[1], ans[2]};
  }
};

#endif /* SOLUTION_HPP */
<commit_msg>simplify "Maximum Sum of 3 Non-Overlapping Subarrays"<commit_after>#ifndef SOLUTION_HPP
#define SOLUTION_HPP

#include <algorithm>
#include <numeric>
#include <vector>

using namespace std;

class Solution {
 public:
  vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
    auto arrsum = [&nums](int a, int b) {
      return accumulate(begin(nums) + a, begin(nums) + b, 0);
    };
    const int N = nums.size();
    const int inf = 0x3f3f3f3f;
    vector<vector<int>> dp(3, vector<int>(N, -inf));
    for (int t = 0; t < 3; ++t) {
      int start = (t + 1) * k - 1;
      for (int a = start; a < N; ++a) {
        // 'a' is the index where the new subarray may end
        // max sum when array is placed ending with index a; still ok event if
        // it's some -inf + sth
        int max_end_here =
            arrsum(a - k + 1, a + 1) + (t > 0 ? dp[t - 1][a - k] : -inf);
        int prev = a > start ? dp[t][a - 1] : -inf;
        dp[t][a] = max({dp[t][a], max_end_here, prev});
      }
    }
    int ans[4] = {N, N, N, N - 1 + k};
    for (int t = 2; t >= 0; --t) {
      auto it = max_element(begin(dp[t]), begin(dp[t]) + ans[t + 1] - k + 1);
      ans[t] = distance(begin(dp[t]), it);
    }
    return {ans[0] - k + 1, ans[1] - k + 1, ans[2] - k + 1};
  }
};

#endif /* SOLUTION_HPP */
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkBinaryThresholdTool.h"

#include "mitkBoundingObjectToSegmentationFilter.h"
#include "mitkToolManager.h"

#include "mitkColorProperty.h"
#include "mitkDataStorage.h"
#include "mitkLevelWindowProperty.h"
#include "mitkOrganTypeProperty.h"
#include "mitkProperties.h"
#include "mitkRenderingManager.h"
#include "mitkVtkResliceInterpolationProperty.h"
#include <mitkCoreObjectFactory.h>

#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkImageStatisticsHolder.h"
#include "mitkImageTimeSelector.h"
#include "mitkLabelSetImage.h"
#include "mitkMaskAndCutRoiImageFilter.h"
#include "mitkPadImageFilter.h"
#include <itkBinaryThresholdImageFilter.h>
#include <itkImageRegionIterator.h>

// us
#include "usGetModuleContext.h"
#include "usModule.h"
#include "usModuleResource.h"

namespace mitk
{
  MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdTool, "Thresholding tool");
}

mitk::BinaryThresholdTool::BinaryThresholdTool()
  : m_SensibleMinimumThresholdValue(-100),
    m_SensibleMaximumThresholdValue(+100),
    m_CurrentThresholdValue(0.0),
    m_IsFloatImage(false)
{
  m_ThresholdFeedbackNode = DataNode::New();
  m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0));
  m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback"));
  m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3));
  m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true));
  m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true));
}

mitk::BinaryThresholdTool::~BinaryThresholdTool()
{
}

const char **mitk::BinaryThresholdTool::GetXPM() const
{
  return NULL;
}

us::ModuleResource mitk::BinaryThresholdTool::GetIconResource() const
{
  us::Module *module = us::GetModuleContext()->GetModule();
  us::ModuleResource resource = module->GetResource("Threshold_48x48.png");
  return resource;
}

const char *mitk::BinaryThresholdTool::GetName() const
{
  return "Threshold";
}

void mitk::BinaryThresholdTool::Activated()
{
  Superclass::Activated();

  m_ToolManager->RoiDataChanged +=
    mitk::MessageDelegate<mitk::BinaryThresholdTool>(this, &mitk::BinaryThresholdTool::OnRoiDataChanged);

  m_OriginalImageNode = m_ToolManager->GetReferenceData(0);
  m_NodeForThresholding = m_OriginalImageNode;

  if (m_NodeForThresholding.IsNotNull())
  {
    SetupPreviewNode();
  }
  else
  {
    m_ToolManager->ActivateTool(-1);
  }
}

void mitk::BinaryThresholdTool::Deactivated()
{
  m_ToolManager->RoiDataChanged -=
    mitk::MessageDelegate<mitk::BinaryThresholdTool>(this, &mitk::BinaryThresholdTool::OnRoiDataChanged);
  m_NodeForThresholding = NULL;
  m_OriginalImageNode = NULL;
  try
  {
    if (DataStorage *storage = m_ToolManager->GetDataStorage())
    {
      storage->Remove(m_ThresholdFeedbackNode);
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
  catch (...)
  {
    // don't care
  }
  m_ThresholdFeedbackNode->SetData(NULL);

  Superclass::Deactivated();
}

void mitk::BinaryThresholdTool::SetThresholdValue(double value)
{
  if (m_ThresholdFeedbackNode.IsNotNull())
  {
    m_CurrentThresholdValue = value;
    // Bug 19250: The range of 0.01 is rather random. It was 0.001 before and probably due to rounding error propagation
    // in VTK code
    // it leads to strange banding effects on floating point images with a huge range (like -40000 - 40000). 0.01 lowers
    // this effect
    // enough to work with our images. Might not work on images with really huge ranges, though. Anyways, still seems to
    // be low enough
    // to work for floating point images with a range between 0 and 1. A better solution might be to dynamically
    // calculate the value
    // based on the value range of the current image (as big as possible, as small as necessary).
    // m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New(
    // LevelWindow(m_CurrentThresholdValue, 0.01) ) );
    UpdatePreview();
  }
}

void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue()
{
  CreateNewSegmentationFromThreshold(m_NodeForThresholding);

  RenderingManager::GetInstance()->RequestUpdateAll();
  m_ToolManager->ActivateTool(-1);
}

void mitk::BinaryThresholdTool::CancelThresholding()
{
  m_ToolManager->ActivateTool(-1);
}

void mitk::BinaryThresholdTool::SetupPreviewNode()
{
  itk::RGBPixel<float> pixel;
  pixel[0] = 0.0f;
  pixel[1] = 1.0f;
  pixel[2] = 0.0f;

  if (m_NodeForThresholding.IsNotNull())
  {
    Image::Pointer image = dynamic_cast<Image *>(m_NodeForThresholding->GetData());
    Image::Pointer originalImage = dynamic_cast<Image *>(m_OriginalImageNode->GetData());

    if (image.IsNotNull())
    {
      mitk::LabelSetImage::Pointer workingImage =
        dynamic_cast<mitk::LabelSetImage *>(m_ToolManager->GetWorkingData(0)->GetData());

      if (workingImage.IsNotNull())
      {
        m_ThresholdFeedbackNode->SetData(workingImage->Clone());
        m_IsOldBinary = false;

        // Let's paint the feedback node green...
        mitk::LabelSetImage::Pointer previewImage =
          dynamic_cast<mitk::LabelSetImage *>(m_ThresholdFeedbackNode->GetData());

        if (previewImage.IsNull())
        {
          MITK_ERROR << "Cannot create helper objects.";
          return;
        }

        previewImage->GetActiveLabel()->SetColor(pixel);
        previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue());
      }
      else
      {
        mitk::Image::Pointer workingImageBin = dynamic_cast<mitk::Image *>(m_ToolManager->GetWorkingData(0)->GetData());
        if (workingImageBin)
        {
          m_ThresholdFeedbackNode->SetData(workingImageBin->Clone());
          m_IsOldBinary = true;
        }
        else
          m_ThresholdFeedbackNode->SetData(mitk::Image::New());
      }

      m_ThresholdFeedbackNode->SetColor(pixel);
      m_ThresholdFeedbackNode->SetOpacity(0.5);

      int layer(50);
      m_NodeForThresholding->GetIntProperty("layer", layer);
      m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1);

      if (DataStorage *ds = m_ToolManager->GetDataStorage())
      {
        if (!ds->Exists(m_ThresholdFeedbackNode))
          ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode);
      }

      if (image.GetPointer() == originalImage.GetPointer())
      {
        Image::StatisticsHolderPointer statistics = originalImage->GetStatistics();
        m_SensibleMinimumThresholdValue = static_cast<double>(statistics->GetScalarValueMin());
        m_SensibleMaximumThresholdValue = static_cast<double>(statistics->GetScalarValueMax());
      }

      if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) &&
          (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT ||
           originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE))
        m_IsFloatImage = true;
      else
        m_IsFloatImage = false;

      m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0;

      IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, m_IsFloatImage);
      ThresholdingValueChanged.Send(m_CurrentThresholdValue);
    }
  }
}

template <typename TPixel, unsigned int VImageDimension>
static void ITKSetVolume(itk::Image<TPixel, VImageDimension> *originalImage,
                         mitk::Image *segmentation,
                         unsigned int timeStep)
{
  segmentation->SetVolume((void *)originalImage->GetPixelContainer()->GetBufferPointer(), timeStep);
}

void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold(DataNode *node)
{
  if (node)
  {
    Image::Pointer feedBackImage = dynamic_cast<Image *>(m_ThresholdFeedbackNode->GetData());
    if (feedBackImage.IsNotNull())
    {
      DataNode::Pointer emptySegmentation = GetTargetSegmentationNode();

      if (emptySegmentation)
      {
        // actually perform a thresholding and ask for an organ type
        for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep)
        {
          try
          {
            ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
            timeSelector->SetInput(feedBackImage);
            timeSelector->SetTimeNr(timeStep);
            timeSelector->UpdateLargestPossibleRegion();
            Image::Pointer image3D = timeSelector->GetOutput();

            if (image3D->GetDimension() == 2)
            {
              AccessFixedDimensionByItk_2(
                image3D, ITKSetVolume, 2, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
            }
            else
            {
              AccessFixedDimensionByItk_2(
                image3D, ITKSetVolume, 3, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
            }
          }
          catch (...)
          {
            Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation.");
          }
        }

        if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer())
        {
          mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New();

          padFilter->SetInput(0, dynamic_cast<mitk::Image *>(emptySegmentation->GetData()));
          padFilter->SetInput(1, dynamic_cast<mitk::Image *>(m_OriginalImageNode->GetData()));
          padFilter->SetBinaryFilter(true);
          padFilter->SetUpperThreshold(1);
          padFilter->SetLowerThreshold(1);
          padFilter->Update();

          emptySegmentation->SetData(padFilter->GetOutput());
        }

        m_ToolManager->SetWorkingData(emptySegmentation);
        m_ToolManager->GetWorkingData(0)->Modified();
      }
    }
  }
}

void mitk::BinaryThresholdTool::OnRoiDataChanged()
{
  mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0);

  if (node.IsNotNull())
  {
    mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New();
    mitk::Image::Pointer image = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());

    if (image.IsNull())
      return;

    roiFilter->SetInput(image);
    roiFilter->SetRegionOfInterest(node->GetData());
    roiFilter->Update();

    mitk::DataNode::Pointer tmpNode = mitk::DataNode::New();
    tmpNode->SetData(roiFilter->GetOutput());

    m_SensibleMaximumThresholdValue = static_cast<double>(roiFilter->GetMaxValue());
    m_SensibleMinimumThresholdValue = static_cast<double>(roiFilter->GetMinValue());

    m_NodeForThresholding = tmpNode;
  }
  else
  {
    m_NodeForThresholding = m_OriginalImageNode;
  }

  this->SetupPreviewNode();
  this->UpdatePreview();
}

template <typename TPixel, unsigned int VImageDimension>
void mitk::BinaryThresholdTool::ITKThresholding(itk::Image<TPixel, VImageDimension> *originalImage,
                                                Image *segmentation,
                                                double thresholdValue,
                                                unsigned int timeStep)
{
  typedef itk::Image<TPixel, VImageDimension> ImageType;
  typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;

  typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New();
  filter->SetInput(originalImage);
  filter->SetLowerThreshold(thresholdValue);
  filter->SetUpperThreshold(m_SensibleMaximumThresholdValue);
  filter->SetInsideValue(1);
  filter->SetOutsideValue(0);
  filter->Update();

  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
}

template <typename TPixel, unsigned int VImageDimension>
void mitk::BinaryThresholdTool::ITKThresholdingOldBinary(itk::Image<TPixel, VImageDimension> *originalImage,
                                                         Image *segmentation,
                                                         double thresholdValue,
                                                         unsigned int timeStep)
{
  typedef itk::Image<TPixel, VImageDimension> ImageType;
  typedef itk::Image<unsigned char, VImageDimension> SegmentationType;
  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;

  typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New();
  filter->SetInput(originalImage);
  filter->SetLowerThreshold(thresholdValue);
  filter->SetUpperThreshold(m_SensibleMaximumThresholdValue);
  filter->SetInsideValue(1);
  filter->SetOutsideValue(0);
  filter->Update();

  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
}

void mitk::BinaryThresholdTool::UpdatePreview()
{
  mitk::Image::Pointer thresholdImage = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());
  mitk::Image::Pointer previewImage = dynamic_cast<mitk::Image *>(m_ThresholdFeedbackNode->GetData());
  if (thresholdImage && previewImage)
  {
    for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep)
    {
      ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
      timeSelector->SetInput(thresholdImage);
      timeSelector->SetTimeNr(timeStep);
      timeSelector->UpdateLargestPossibleRegion();
      Image::Pointer feedBackImage3D = timeSelector->GetOutput();

      if (m_IsOldBinary)
      {
        AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, timeStep));
      }
      else
      {
        AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, timeStep));
      }
    }

    RenderingManager::GetInstance()->RequestUpdateAll();
  }
}
<commit_msg>Fix crash on Threshold<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkBinaryThresholdTool.h"

#include "mitkBoundingObjectToSegmentationFilter.h"
#include "mitkToolManager.h"

#include "mitkColorProperty.h"
#include "mitkDataStorage.h"
#include "mitkLevelWindowProperty.h"
#include "mitkOrganTypeProperty.h"
#include "mitkProperties.h"
#include "mitkRenderingManager.h"
#include "mitkVtkResliceInterpolationProperty.h"
#include <mitkCoreObjectFactory.h>

#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkImageStatisticsHolder.h"
#include "mitkImageTimeSelector.h"
#include "mitkLabelSetImage.h"
#include "mitkMaskAndCutRoiImageFilter.h"
#include "mitkPadImageFilter.h"
#include <itkBinaryThresholdImageFilter.h>
#include <itkImageRegionIterator.h>

// us
#include "usGetModuleContext.h"
#include "usModule.h"
#include "usModuleResource.h"

namespace mitk
{
  MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdTool, "Thresholding tool");
}

mitk::BinaryThresholdTool::BinaryThresholdTool()
  : m_SensibleMinimumThresholdValue(-100),
    m_SensibleMaximumThresholdValue(+100),
    m_CurrentThresholdValue(0.0),
    m_IsFloatImage(false)
{
  m_ThresholdFeedbackNode = DataNode::New();
  m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0));
  m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback"));
  m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3));
  m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true));
  m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true));
}

mitk::BinaryThresholdTool::~BinaryThresholdTool()
{
}

const char **mitk::BinaryThresholdTool::GetXPM() const
{
  return NULL;
}

us::ModuleResource mitk::BinaryThresholdTool::GetIconResource() const
{
  us::Module *module = us::GetModuleContext()->GetModule();
  us::ModuleResource resource = module->GetResource("Threshold_48x48.png");
  return resource;
}

const char *mitk::BinaryThresholdTool::GetName() const
{
  return "Threshold";
}

void mitk::BinaryThresholdTool::Activated()
{
  Superclass::Activated();

  m_ToolManager->RoiDataChanged +=
    mitk::MessageDelegate<mitk::BinaryThresholdTool>(this, &mitk::BinaryThresholdTool::OnRoiDataChanged);

  m_OriginalImageNode = m_ToolManager->GetReferenceData(0);
  m_NodeForThresholding = m_OriginalImageNode;

  if (m_NodeForThresholding.IsNotNull())
  {
    SetupPreviewNode();
  }
  else
  {
    m_ToolManager->ActivateTool(-1);
  }
}

void mitk::BinaryThresholdTool::Deactivated()
{
  m_ToolManager->RoiDataChanged -=
    mitk::MessageDelegate<mitk::BinaryThresholdTool>(this, &mitk::BinaryThresholdTool::OnRoiDataChanged);
  m_NodeForThresholding = NULL;
  m_OriginalImageNode = NULL;
  try
  {
    if (DataStorage *storage = m_ToolManager->GetDataStorage())
    {
      storage->Remove(m_ThresholdFeedbackNode);
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
  catch (...)
  {
    // don't care
  }
  m_ThresholdFeedbackNode->SetData(NULL);

  Superclass::Deactivated();
}

void mitk::BinaryThresholdTool::SetThresholdValue(double value)
{
  if (m_ThresholdFeedbackNode.IsNotNull())
  {
    /* If value is not in the min/max range, do nothing. In that case, this
       method will be called again with a proper value right after. The only
       known case where this happens is with an [0.0, 1.0[ image, where value
       could be an epsilon greater than the max. */
    if (value < m_SensibleMinimumThresholdValue
     || value > m_SensibleMaximumThresholdValue)
    {
      return;
    }

    m_CurrentThresholdValue = value;
    // Bug 19250: The range of 0.01 is rather random. It was 0.001 before and probably due to rounding error propagation
    // in VTK code
    // it leads to strange banding effects on floating point images with a huge range (like -40000 - 40000). 0.01 lowers
    // this effect
    // enough to work with our images. Might not work on images with really huge ranges, though. Anyways, still seems to
    // be low enough
    // to work for floating point images with a range between 0 and 1. A better solution might be to dynamically
    // calculate the value
    // based on the value range of the current image (as big as possible, as small as necessary).
    // m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New(
    // LevelWindow(m_CurrentThresholdValue, 0.01) ) );
    UpdatePreview();
  }
}

void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue()
{
  CreateNewSegmentationFromThreshold(m_NodeForThresholding);

  RenderingManager::GetInstance()->RequestUpdateAll();
  m_ToolManager->ActivateTool(-1);
}

void mitk::BinaryThresholdTool::CancelThresholding()
{
  m_ToolManager->ActivateTool(-1);
}

void mitk::BinaryThresholdTool::SetupPreviewNode()
{
  itk::RGBPixel<float> pixel;
  pixel[0] = 0.0f;
  pixel[1] = 1.0f;
  pixel[2] = 0.0f;

  if (m_NodeForThresholding.IsNotNull())
  {
    Image::Pointer image = dynamic_cast<Image *>(m_NodeForThresholding->GetData());
    Image::Pointer originalImage = dynamic_cast<Image *>(m_OriginalImageNode->GetData());

    if (image.IsNotNull())
    {
      mitk::LabelSetImage::Pointer workingImage =
        dynamic_cast<mitk::LabelSetImage *>(m_ToolManager->GetWorkingData(0)->GetData());

      if (workingImage.IsNotNull())
      {
        m_ThresholdFeedbackNode->SetData(workingImage->Clone());
        m_IsOldBinary = false;

        // Let's paint the feedback node green...
        mitk::LabelSetImage::Pointer previewImage =
          dynamic_cast<mitk::LabelSetImage *>(m_ThresholdFeedbackNode->GetData());

        if (previewImage.IsNull())
        {
          MITK_ERROR << "Cannot create helper objects.";
          return;
        }

        previewImage->GetActiveLabel()->SetColor(pixel);
        previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue());
      }
      else
      {
        mitk::Image::Pointer workingImageBin = dynamic_cast<mitk::Image *>(m_ToolManager->GetWorkingData(0)->GetData());
        if (workingImageBin)
        {
          m_ThresholdFeedbackNode->SetData(workingImageBin->Clone());
          m_IsOldBinary = true;
        }
        else
          m_ThresholdFeedbackNode->SetData(mitk::Image::New());
      }

      m_ThresholdFeedbackNode->SetColor(pixel);
      m_ThresholdFeedbackNode->SetOpacity(0.5);

      int layer(50);
      m_NodeForThresholding->GetIntProperty("layer", layer);
      m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1);

      if (DataStorage *ds = m_ToolManager->GetDataStorage())
      {
        if (!ds->Exists(m_ThresholdFeedbackNode))
          ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode);
      }

      if (image.GetPointer() == originalImage.GetPointer())
      {
        Image::StatisticsHolderPointer statistics = originalImage->GetStatistics();
        m_SensibleMinimumThresholdValue = static_cast<double>(statistics->GetScalarValueMin());
        m_SensibleMaximumThresholdValue = static_cast<double>(statistics->GetScalarValueMax());
      }

      if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) &&
          (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT ||
           originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE))
        m_IsFloatImage = true;
      else
        m_IsFloatImage = false;

      m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0;

      IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, m_IsFloatImage);
      ThresholdingValueChanged.Send(m_CurrentThresholdValue);
    }
  }
}

template <typename TPixel, unsigned int VImageDimension>
static void ITKSetVolume(itk::Image<TPixel, VImageDimension> *originalImage,
                         mitk::Image *segmentation,
                         unsigned int timeStep)
{
  segmentation->SetVolume((void *)originalImage->GetPixelContainer()->GetBufferPointer(), timeStep);
}

void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold(DataNode *node)
{
  if (node)
  {
    Image::Pointer feedBackImage = dynamic_cast<Image *>(m_ThresholdFeedbackNode->GetData());
    if (feedBackImage.IsNotNull())
    {
      DataNode::Pointer emptySegmentation = GetTargetSegmentationNode();

      if (emptySegmentation)
      {
        // actually perform a thresholding and ask for an organ type
        for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep)
        {
          try
          {
            ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
            timeSelector->SetInput(feedBackImage);
            timeSelector->SetTimeNr(timeStep);
            timeSelector->UpdateLargestPossibleRegion();
            Image::Pointer image3D = timeSelector->GetOutput();

            if (image3D->GetDimension() == 2)
            {
              AccessFixedDimensionByItk_2(
                image3D, ITKSetVolume, 2, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
            }
            else
            {
              AccessFixedDimensionByItk_2(
                image3D, ITKSetVolume, 3, dynamic_cast<Image *>(emptySegmentation->GetData()), timeStep);
            }
          }
          catch (...)
          {
            Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation.");
          }
        }

        if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer())
        {
          mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New();

          padFilter->SetInput(0, dynamic_cast<mitk::Image *>(emptySegmentation->GetData()));
          padFilter->SetInput(1, dynamic_cast<mitk::Image *>(m_OriginalImageNode->GetData()));
          padFilter->SetBinaryFilter(true);
          padFilter->SetUpperThreshold(1);
          padFilter->SetLowerThreshold(1);
          padFilter->Update();

          emptySegmentation->SetData(padFilter->GetOutput());
        }

        m_ToolManager->SetWorkingData(emptySegmentation);
        m_ToolManager->GetWorkingData(0)->Modified();
      }
    }
  }
}

void mitk::BinaryThresholdTool::OnRoiDataChanged()
{
  mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0);

  if (node.IsNotNull())
  {
    mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New();
    mitk::Image::Pointer image = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());

    if (image.IsNull())
      return;

    roiFilter->SetInput(image);
    roiFilter->SetRegionOfInterest(node->GetData());
    roiFilter->Update();

    mitk::DataNode::Pointer tmpNode = mitk::DataNode::New();
    tmpNode->SetData(roiFilter->GetOutput());

    m_SensibleMaximumThresholdValue = static_cast<double>(roiFilter->GetMaxValue());
    m_SensibleMinimumThresholdValue = static_cast<double>(roiFilter->GetMinValue());

    m_NodeForThresholding = tmpNode;
  }
  else
  {
    m_NodeForThresholding = m_OriginalImageNode;
  }

  this->SetupPreviewNode();
  this->UpdatePreview();
}

template <typename TPixel, unsigned int VImageDimension>
void mitk::BinaryThresholdTool::ITKThresholding(itk::Image<TPixel, VImageDimension> *originalImage,
                                                Image *segmentation,
                                                double thresholdValue,
                                                unsigned int timeStep)
{
  typedef itk::Image<TPixel, VImageDimension> ImageType;
  typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;

  typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New();
  filter->SetInput(originalImage);
  filter->SetLowerThreshold(thresholdValue);
  filter->SetUpperThreshold(m_SensibleMaximumThresholdValue);
  filter->SetInsideValue(1);
  filter->SetOutsideValue(0);
  filter->Update();

  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
}

template <typename TPixel, unsigned int VImageDimension>
void mitk::BinaryThresholdTool::ITKThresholdingOldBinary(itk::Image<TPixel, VImageDimension> *originalImage,
                                                         Image *segmentation,
                                                         double thresholdValue,
                                                         unsigned int timeStep)
{
  typedef itk::Image<TPixel, VImageDimension> ImageType;
  typedef itk::Image<unsigned char, VImageDimension> SegmentationType;
  typedef itk::BinaryThresholdImageFilter<ImageType, SegmentationType> ThresholdFilterType;

  typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New();
  filter->SetInput(originalImage);
  filter->SetLowerThreshold(thresholdValue);
  filter->SetUpperThreshold(m_SensibleMaximumThresholdValue);
  filter->SetInsideValue(1);
  filter->SetOutsideValue(0);
  filter->Update();

  segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
}

void mitk::BinaryThresholdTool::UpdatePreview()
{
  mitk::Image::Pointer thresholdImage = dynamic_cast<mitk::Image *>(m_NodeForThresholding->GetData());
  mitk::Image::Pointer previewImage = dynamic_cast<mitk::Image *>(m_ThresholdFeedbackNode->GetData());
  if (thresholdImage && previewImage)
  {
    for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep)
    {
      ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
      timeSelector->SetInput(thresholdImage);
      timeSelector->SetTimeNr(timeStep);
      timeSelector->UpdateLargestPossibleRegion();
      Image::Pointer feedBackImage3D = timeSelector->GetOutput();

      if (m_IsOldBinary)
      {
        AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, timeStep));
      }
      else
      {
        AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, timeStep));
      }
    }

    RenderingManager::GetInstance()->RequestUpdateAll();
  }
}
<|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.

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

namespace otb
{
namespace Wrapper
{

QtWidgetOutputFilenameParameter::QtWidgetOutputFilenameParameter(OutputFilenameParameter* param, QtWidgetModel* m)
: QtWidgetParameterBase(param, m),
  m_FilenameParam(param)
{
}

QtWidgetOutputFilenameParameter::~QtWidgetOutputFilenameParameter()
{
}

void QtWidgetOutputFilenameParameter::DoUpdateGUI()
{
  // Update the lineEdit
  QString text( m_FilenameParam->GetValue().c_str() );
  m_Input->setText(text);
}

void QtWidgetOutputFilenameParameter::DoCreateWidget()
{
  // Set up input text edit
  m_HLayout = new QHBoxLayout;
  m_HLayout->setSpacing(0);
  m_HLayout->setContentsMargins(0, 0, 0, 0);
  m_Input = new QLineEdit;
  m_Input->setToolTip( m_FilenameParam->GetDescription() );
  connect( m_Input, SIGNAL(textChanged(const QString&)), this, SLOT(SetFileName(const QString&)) );
  connect( m_Input, SIGNAL(textChanged(const QString&)), GetModel(), SLOT(NotifyUpdate()) );

  m_HLayout->addWidget(m_Input);

  // Set up input text edit
  m_Button = new QPushButton;
  m_Button->setText("...");
  m_Button->setToolTip("Select file...");
  m_Button->setMaximumWidth(m_Button->width());
  connect( m_Button, SIGNAL(clicked()), this, SLOT(SelectFile()) );
  m_HLayout->addWidget(m_Button);

  this->setLayout(m_HLayout);
}

void QtWidgetOutputFilenameParameter::SelectFile()
{
  QFileDialog fileDialog;
  fileDialog.setConfirmOverwrite(true);
  switch(m_FilenameParam->GetRole())
    {
    case Role_Input:
    {
    //fileDialog.setFileMode(QFileDialog::ExistingFile);
    // FIXME: parameter's role is not suitable to separate "input file" names from "output file" names
    fileDialog.setFileMode(QFileDialog::AnyFile);
    }
    break;
    case Role_Output:
    {
    fileDialog.setFileMode(QFileDialog::AnyFile);
    }
    break;
    }

  fileDialog.setNameFilter("File (*)");

  if (fileDialog.exec())
    {
    this->SetFileName(fileDialog.selectedFiles().at(0));
    m_Input->setText(fileDialog.selectedFiles().at(0));
    }
}

void QtWidgetOutputFilenameParameter::SetFileName(const QString& value)
{
  // save value
  m_FilenameParam->SetValue(static_cast<const char*>(value.toAscii()));

  // notify of value change
  QString key( m_FilenameParam->GetKey() );
  emit ParameterChanged(key);
}

}
}
<commit_msg>BUG: avoid cursor to be sent to end after editing OutputFilenameParameter<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 "otbWrapperQtWidgetOutputFilenameParameter.h"

namespace otb
{
namespace Wrapper
{

QtWidgetOutputFilenameParameter::QtWidgetOutputFilenameParameter(OutputFilenameParameter* param, QtWidgetModel* m)
: QtWidgetParameterBase(param, m),
  m_FilenameParam(param)
{
}

QtWidgetOutputFilenameParameter::~QtWidgetOutputFilenameParameter()
{
}

void QtWidgetOutputFilenameParameter::DoUpdateGUI()
{
  // Update the lineEdit
  QString text( m_FilenameParam->GetValue().c_str() );
  if (text != m_Input->text())
    m_Input->setText(text);
}

void QtWidgetOutputFilenameParameter::DoCreateWidget()
{
  // Set up input text edit
  m_HLayout = new QHBoxLayout;
  m_HLayout->setSpacing(0);
  m_HLayout->setContentsMargins(0, 0, 0, 0);
  m_Input = new QLineEdit;
  m_Input->setToolTip( m_FilenameParam->GetDescription() );
  connect( m_Input, SIGNAL(textChanged(const QString&)), this, SLOT(SetFileName(const QString&)) );
  connect( m_Input, SIGNAL(textChanged(const QString&)), GetModel(), SLOT(NotifyUpdate()) );

  m_HLayout->addWidget(m_Input);

  // Set up input text edit
  m_Button = new QPushButton;
  m_Button->setText("...");
  m_Button->setToolTip("Select file...");
  m_Button->setMaximumWidth(m_Button->width());
  connect( m_Button, SIGNAL(clicked()), this, SLOT(SelectFile()) );
  m_HLayout->addWidget(m_Button);

  this->setLayout(m_HLayout);
}

void QtWidgetOutputFilenameParameter::SelectFile()
{
  QFileDialog fileDialog;
  fileDialog.setConfirmOverwrite(true);
  switch(m_FilenameParam->GetRole())
    {
    case Role_Input:
    {
    //fileDialog.setFileMode(QFileDialog::ExistingFile);
    // FIXME: parameter's role is not suitable to separate "input file" names from "output file" names
    fileDialog.setFileMode(QFileDialog::AnyFile);
    }
    break;
    case Role_Output:
    {
    fileDialog.setFileMode(QFileDialog::AnyFile);
    }
    break;
    }

  fileDialog.setNameFilter("File (*)");

  if (fileDialog.exec())
    {
    this->SetFileName(fileDialog.selectedFiles().at(0));
    m_Input->setText(fileDialog.selectedFiles().at(0));
    }
}

void QtWidgetOutputFilenameParameter::SetFileName(const QString& value)
{
  // save value
  m_FilenameParam->SetValue(static_cast<const char*>(value.toAscii()));

  // notify of value change
  QString key( m_FilenameParam->GetKey() );
  emit ParameterChanged(key);
}

}
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

extern "C"
{
#include <png.h>
}

// boost
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/make_shared.hpp>

// mapnik
#include <mapnik/graphics.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/png_io.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_compositing.hpp>

// stl
#include <sstream>

// jpeg
#if defined(HAVE_JPEG)
#include <mapnik/jpeg_io.hpp>
#endif

// cairo
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <cairomm/surface.h>
#include <pycairo.h>
#endif

using mapnik::image_32;
using mapnik::image_reader;
using mapnik::get_image_reader;
using mapnik::type_from_filename;
using mapnik::save_to_file;
using mapnik::save_to_string;

using namespace boost::python;

// output 'raw' pixels
PyObject* tostring1( image_32 const& im)
{
    int size = im.width() * im.height() * 4;
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        ((const char*)im.raw_data(),size);
}

// encode (png,jpeg)
PyObject* tostring2(image_32 const & im, std::string const& format)
{
    std::string s = save_to_string(im, format);
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        (s.data(),s.size());
}

PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal)
{
    std::string s = save_to_string(im, format, pal);
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        (s.data(),s.size());
}

void save_to_file1(mapnik::image_32 const& im, std::string const& filename)
{
    save_to_file(im,filename);
}

void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std::string const& type)
{
    save_to_file(im,filename,type);
}

void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal)
{
    save_to_file(im,filename,type,pal);
}

bool painted(mapnik::image_32 const& im)
{
    return im.painted();
}

void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c)
{
    im.setPixel(x, y, c.rgba());
}

boost::shared_ptr<image_32> open_from_file(std::string const& filename)
{
    boost::optional<std::string> type = type_from_filename(filename);
    if (type)
    {
        std::auto_ptr<image_reader> reader(get_image_reader(filename,*type));
        if (reader.get())
        {

            boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(reader->width(),reader->height());
            reader->read(0,0,image_ptr->data());
            return image_ptr;
        }
        throw mapnik::image_reader_exception("Failed to load: " + filename);
    }
    throw mapnik::image_reader_exception("Unsupported image format:" + filename);
}

void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float opacity)
{
    im.set_rectangle_alpha2(im2.data(),x,y,opacity);
}

void composite(image_32 & im, image_32 & im2, mapnik::composite_mode_e mode)
{
    mapnik::composite(im.data(),im2.data(),mode);
}

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
boost::shared_ptr<image_32> from_cairo(PycairoSurface* surface)
{
    Cairo::RefPtr<Cairo::ImageSurface> s(new Cairo::ImageSurface(surface->surface));
    boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(s);
    return image_ptr;
}
#endif

void export_image()
{
    using namespace boost::python;
    enum_<mapnik::composite_mode_e>("CompositeOp")
        .value("clear", mapnik::clear)
        .value("src", mapnik::src)
        .value("dst", mapnik::dst)
        .value("src_over", mapnik::src_over)
        .value("dst_over", mapnik::dst_over)
        .value("src_in", mapnik::src_in)
        .value("dst_in", mapnik::dst_in)
        .value("src_out", mapnik::src_out)
        .value("dst_out", mapnik::dst_out)
        .value("src_atop", mapnik::src_atop)
        .value("dst_atop", mapnik::dst_atop)
        .value("xor", mapnik::_xor)
        .value("plus", mapnik::plus)
        .value("minus", mapnik::minus)
        .value("multiply", mapnik::multiply)
        .value("screen", mapnik::screen)
        .value("overlay", mapnik::overlay)
        .value("darken", mapnik::darken)
        .value("lighten", mapnik::lighten)
        .value("color_dodge", mapnik::color_dodge)
        .value("color_burn", mapnik::color_burn)
        .value("hard_light", mapnik::hard_light)
        .value("soft_light", mapnik::soft_light)
        .value("difference", mapnik::difference)
        .value("exclusion", mapnik::exclusion)
        .value("contrast", mapnik::contrast)
        .value("invert", mapnik::invert)
        .value("invert_rgb", mapnik::invert_rgb)
        ;

    class_<image_32,boost::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>())
        .def("width",&image_32::width)
        .def("height",&image_32::height)
        .def("view",&image_32::get_view)
        .def("painted",&painted)
        .add_property("background",make_function
                      (&image_32::get_background,return_value_policy<copy_const_reference>()),
                      &image_32::set_background, "The background color of the image.")
        .def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image")
        .def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image")
        .def("set_alpha",&image_32::set_alpha, "Set the overall alpha channel of the Image")
        .def("blend",&blend)
        .def("composite",&composite)
        .def("set_pixel",&set_pixel)
        //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3

        .def("tostring",&tostring1)
        .def("tostring",&tostring2)
        .def("tostring",&tostring3)
        .def("save", &save_to_file1)
        .def("save", &save_to_file2)
        .def("save", &save_to_file3)
        .def("open",open_from_file)
        .staticmethod("open")
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
        .def("from_cairo",&from_cairo)
        .staticmethod("from_cairo")
#endif
        ;

}
<commit_msg>+ remove unused header<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

extern "C"
{
#include <png.h>
}

// boost
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/make_shared.hpp>

// mapnik
#include <mapnik/graphics.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/png_io.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_compositing.hpp>

// jpeg
#if defined(HAVE_JPEG)
#include <mapnik/jpeg_io.hpp>
#endif

// cairo
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <cairomm/surface.h>
#include <pycairo.h>
#endif

using mapnik::image_32;
using mapnik::image_reader;
using mapnik::get_image_reader;
using mapnik::type_from_filename;
using mapnik::save_to_file;
using mapnik::save_to_string;

using namespace boost::python;

// output 'raw' pixels
PyObject* tostring1( image_32 const& im)
{
    int size = im.width() * im.height() * 4;
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        ((const char*)im.raw_data(),size);
}

// encode (png,jpeg)
PyObject* tostring2(image_32 const & im, std::string const& format)
{
    std::string s = save_to_string(im, format);
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        (s.data(),s.size());
}

PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal)
{
    std::string s = save_to_string(im, format, pal);
    return
#if PY_VERSION_HEX >= 0x03000000
        ::PyBytes_FromStringAndSize
#else
        ::PyString_FromStringAndSize
#endif
        (s.data(),s.size());
}

void save_to_file1(mapnik::image_32 const& im, std::string const& filename)
{
    save_to_file(im,filename);
}

void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std::string const& type)
{
    save_to_file(im,filename,type);
}

void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal)
{
    save_to_file(im,filename,type,pal);
}

bool painted(mapnik::image_32 const& im)
{
    return im.painted();
}

void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c)
{
    im.setPixel(x, y, c.rgba());
}

boost::shared_ptr<image_32> open_from_file(std::string const& filename)
{
    boost::optional<std::string> type = type_from_filename(filename);
    if (type)
    {
        std::auto_ptr<image_reader> reader(get_image_reader(filename,*type));
        if (reader.get())
        {

            boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(reader->width(),reader->height());
            reader->read(0,0,image_ptr->data());
            return image_ptr;
        }
        throw mapnik::image_reader_exception("Failed to load: " + filename);
    }
    throw mapnik::image_reader_exception("Unsupported image format:" + filename);
}

void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float opacity)
{
    im.set_rectangle_alpha2(im2.data(),x,y,opacity);
}

void composite(image_32 & im, image_32 & im2, mapnik::composite_mode_e mode)
{
    mapnik::composite(im.data(),im2.data(),mode);
}

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
boost::shared_ptr<image_32> from_cairo(PycairoSurface* surface)
{
    Cairo::RefPtr<Cairo::ImageSurface> s(new Cairo::ImageSurface(surface->surface));
    boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(s);
    return image_ptr;
}
#endif

void export_image()
{
    using namespace boost::python;
    enum_<mapnik::composite_mode_e>("CompositeOp")
        .value("clear", mapnik::clear)
        .value("src", mapnik::src)
        .value("dst", mapnik::dst)
        .value("src_over", mapnik::src_over)
        .value("dst_over", mapnik::dst_over)
        .value("src_in", mapnik::src_in)
        .value("dst_in", mapnik::dst_in)
        .value("src_out", mapnik::src_out)
        .value("dst_out", mapnik::dst_out)
        .value("src_atop", mapnik::src_atop)
        .value("dst_atop", mapnik::dst_atop)
        .value("xor", mapnik::_xor)
        .value("plus", mapnik::plus)
        .value("minus", mapnik::minus)
        .value("multiply", mapnik::multiply)
        .value("screen", mapnik::screen)
        .value("overlay", mapnik::overlay)
        .value("darken", mapnik::darken)
        .value("lighten", mapnik::lighten)
        .value("color_dodge", mapnik::color_dodge)
        .value("color_burn", mapnik::color_burn)
        .value("hard_light", mapnik::hard_light)
        .value("soft_light", mapnik::soft_light)
        .value("difference", mapnik::difference)
        .value("exclusion", mapnik::exclusion)
        .value("contrast", mapnik::contrast)
        .value("invert", mapnik::invert)
        .value("invert_rgb", mapnik::invert_rgb)
        ;

    class_<image_32,boost::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>())
        .def("width",&image_32::width)
        .def("height",&image_32::height)
        .def("view",&image_32::get_view)
        .def("painted",&painted)
        .add_property("background",make_function
                      (&image_32::get_background,return_value_policy<copy_const_reference>()),
                      &image_32::set_background, "The background color of the image.")
        .def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image")
        .def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image")
        .def("set_alpha",&image_32::set_alpha, "Set the overall alpha channel of the Image")
        .def("blend",&blend)
        .def("composite",&composite)
        .def("set_pixel",&set_pixel)
        //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3

        .def("tostring",&tostring1)
        .def("tostring",&tostring2)
        .def("tostring",&tostring3)
        .def("save", &save_to_file1)
        .def("save", &save_to_file2)
        .def("save", &save_to_file3)
        .def("open",open_from_file)
        .staticmethod("open")
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
        .def("from_cairo",&from_cairo)
        .staticmethod("from_cairo")
#endif
        ;

}
<|endoftext|>


<commit_before>
#include <util/util.h>

#include "grammar-builder.h"
#include "../declaration.h"
#include "../type.h"
#include "../grammar.h"
#include "../production.h"
#include "../attribute.h"
#include "../expression.h"
#include "../constant.h"

using namespace binpac;
using namespace binpac::passes;

GrammarBuilder::GrammarBuilder(std::ostream& out)
    : ast::Pass<AstInfo, shared_ptr<Production>>("binpac::GrammarBuilder", false), _debug_out(out)
{
}

GrammarBuilder::~GrammarBuilder()
{
}

bool GrammarBuilder::run(shared_ptr<ast::NodeBase> ast)
{
    _in_decl = 0;;
    _counters.clear();
    return processAllPreOrder(ast);
}

void GrammarBuilder::enableDebug()
{
    _debug = true;
}

GrammarBuilder::production_map GrammarBuilder::_compiled;

shared_ptr<Production> GrammarBuilder::compileOne(shared_ptr<Node> n)
{
    auto p = _compiled.find(n);

    if ( p != _compiled.end() )
        return p->second;

    _compiled.insert(std::make_pair(n, std::make_shared<production::Unknown>(n)));

    shared_ptr<Production> production = nullptr;
    bool success = processOne(n, &production);
    assert(success);
    assert(production);

    _compiled.erase(n);
    _compiled.insert(std::make_pair(n, production));

    return production;
}

void GrammarBuilder::_resolveUnknown(shared_ptr<Production> production)
{
    auto unknown = ast::tryCast<production::Unknown>(production);

    if ( unknown ) {
        auto n = unknown->node();
        auto p = _compiled.find(n);
        assert( p != _compiled.end());
        production->replace(n);
    }

    for ( auto c : production->childs() ) {
        if ( ast::isA<Production>(c) )
             _resolveUnknown(c->sharedPtr<binpac::Production>());
    }
}

string GrammarBuilder::counter(const string& key)
{
    auto cnt = 1;
    auto i = _counters.find(key);

    if ( i != _counters.end() )
        cnt = i->second;

    string s = util::fmt("%s%d", key.c_str(), cnt++);

    _counters[key] = cnt;

    return s;
}

void GrammarBuilder::visit(declaration::Type* d)
{
    // We are only interested in unit declarations.
    auto unit = ast::tryCast<type::Unit>(d->type());

    if ( ! unit )
        return;

    ++_in_decl;
    auto production = compileOne(unit);
    --_in_decl;

    _resolveUnknown(production);

    auto grammar = std::make_shared<Grammar>(d->id()->name(), production);

    if ( _debug )
        grammar->printTables(_debug_out, true);

    unit->setGrammar(grammar);
}

void GrammarBuilder::visit(type::Unit* u)
{
    if ( ! _in_decl )
        return;

    auto prods = Production::production_list();

    for ( auto f : u->fields() )
        prods.push_back(compileOne(f));

    string name;

    if ( u->id() )
        name = u->id()->name();
    else
        name = util::fmt("unit%d", _unit_counter++);

    auto unit = std::make_shared<production::Sequence>(name, prods, u->sharedPtr<type::Unit>(), u->location());
    setResult(unit);
}

void GrammarBuilder::visit(type::unit::item::field::Constant* c)
{
    if ( ! _in_decl )
        return;

    auto sym = "const:" + c->id()->name();
    auto prod = std::make_shared<production::Constant>(sym, c->constant());
    prod->pgMeta()->field = c->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Ctor* c)
{
    if ( ! _in_decl )
        return;

    auto sym = "ctor:" + c->id()->name();
    auto prod = std::make_shared<production::Ctor>(sym, c->ctor());
    prod->pgMeta()->field = c->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Switch* s)
{
    if ( ! _in_decl )
        return;

    production::Switch::case_list cases;
    shared_ptr<Production> default_ = nullptr;

    for ( auto c : s->cases() ) {
        if ( c->default_() ) {
            default_ = compileOne(c);
            continue;
        }

        auto pcase = std::make_pair(c->expressions(), compileOne(c));
        cases.push_back(pcase);
    }

    auto sym = "switch:" + s->id()->name();
    auto prod = std::make_shared<production::Switch>(sym, s->expression(), cases, default_, s->location());
    prod->pgMeta()->field = s->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::AtomicType* t)
{
    if ( ! _in_decl )
        return;

    shared_ptr<Production> prod;

    if ( ast::isA<type::EmbeddedObject>(t->type()) ) {
        // Not quite clear if there's a nicer way to present these than
        // special-casing them here.
        auto sym = "type:" + t->id()->name();
        prod = std::make_shared<production::TypeLiteral>(sym, t->type());
    }

    else {
        auto sym = "var:" + t->id()->name();
        prod = std::make_shared<production::Variable>(sym, t->type());
    }

    prod->pgMeta()->field = t->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Unit* u)
{
    if ( ! _in_decl )
        return;

    ++_in_decl;
    auto chprod = compileOne(u->type());
    --_in_decl;

    string name;

    if ( u->id() )
        name = u->id()->name();
    else
        name = util::fmt("unit%d", _unit_counter++);

    assert(ast::isA<Production>(chprod));
    auto child = std::make_shared<production::ChildGrammar>(name, chprod, ast::checkedCast<type::Unit>(u->type()), u->location());
    child->pgMeta()->field = u->sharedPtr<type::unit::item::field::Unit>();
    setResult(child);
}

void GrammarBuilder::visit(type::unit::item::field::switch_::Case* c)
{
    if ( ! _in_decl )
        return;

    auto prods = Production::production_list();

    for ( auto i : c->items() )
        prods.push_back(compileOne(i));

    auto name = util::fmt("case%d", _case_counter++);
    auto seq = std::make_shared<production::Sequence>(name, prods, nullptr, c->location());
    setResult(seq);
}

void GrammarBuilder::visit(type::unit::item::field::container::List* l)
{
    if ( ! _in_decl )
        return;

    auto until = l->attributes()->lookup("until");
    auto until_including = l->attributes()->lookup("until_including");
    auto while_ = l->attributes()->lookup("while");
    auto count = l->attributes()->lookup("count");
    auto length = l->attributes()->lookup("length");

    auto sym = "list:" + l->id()->name();

    ++_in_decl;
    auto field = compileOne(l->field());
    field->setContainer(l->sharedPtr<type::unit::item::field::Container>());
    --_in_decl;

    if ( until || while_ || until_including ) {
        // We use a Loop production here. type::Container installs a &foreach
        // hook that stops the iteration once the condition is satisfied.
        // Doing it this way allows the condition to run in the hook's scope,
        // with access to "$$".
        auto l1 = std::make_shared<production::Loop>(sym, field, false, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l1);
    }

    else if ( count ) {
        auto l1 = std::make_shared<production::Counter>(sym, count->value(), field, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l1);
    }

    else if ( length ) {
        auto l1 = std::make_shared<production::Loop>(sym, field, true, l->location());
        auto l2 = std::make_shared<production::ByteBlock>(sym, length->value(), l1, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l2);
    }

    else {
        // No attributes, use look-ahead to figure out when to stop parsing.
        //
        // Left-factored & right-recursive.
        //
        // List1 -> Item List2
        // List2 -> Epsilon | List1

        auto epsilon = std::make_shared<production::Epsilon>(l->location());
        auto l1 = std::make_shared<production::Sequence>(sym + ":l1", Production::production_list(), nullptr, l->location());
        auto l2 = std::make_shared<production::LookAhead>(sym + ":l2", epsilon, l1, l->location());

        l1->add(field);
        l1->add(l2);

        auto c = std::make_shared<production::Enclosure>(sym, l2, l->location());
        c->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        field->pgMeta()->for_each = c->pgMeta()->field;

        setResult(c);
    }
}

void GrammarBuilder::visit(type::unit::item::field::container::Vector* v)
{
    if ( ! _in_decl )
        return;

    auto length = v->length();
    auto sym = "vector:" + v->id()->name();

    ++_in_decl;
    auto field = compileOne(v->field());
    field->setContainer(v->sharedPtr<type::unit::item::field::Container>());
    --_in_decl;

    auto l1 = std::make_shared<production::Counter>(sym, v->length(), field, v->location());
    l1->pgMeta()->field = v->sharedPtr<type::unit::item::Field>();
    setResult(l1);
}
<commit_msg>Fixing regression introduced with sync support.<commit_after>
#include <util/util.h>

#include "grammar-builder.h"
#include "../declaration.h"
#include "../type.h"
#include "../grammar.h"
#include "../production.h"
#include "../attribute.h"
#include "../expression.h"
#include "../constant.h"

using namespace binpac;
using namespace binpac::passes;

GrammarBuilder::GrammarBuilder(std::ostream& out)
    : ast::Pass<AstInfo, shared_ptr<Production>>("binpac::GrammarBuilder", false), _debug_out(out)
{
}

GrammarBuilder::~GrammarBuilder()
{
}

bool GrammarBuilder::run(shared_ptr<ast::NodeBase> ast)
{
    _in_decl = 0;;
    _counters.clear();
    return processAllPreOrder(ast);
}

void GrammarBuilder::enableDebug()
{
    _debug = true;
}

GrammarBuilder::production_map GrammarBuilder::_compiled;

shared_ptr<Production> GrammarBuilder::compileOne(shared_ptr<Node> n)
{
    auto p = _compiled.find(n);

    if ( p != _compiled.end() )
        return p->second;

    _compiled.insert(std::make_pair(n, std::make_shared<production::Unknown>(n)));

    shared_ptr<Production> production = nullptr;
    bool success = processOne(n, &production);
    assert(success);
    assert(production);

    _compiled.erase(n);
    _compiled.insert(std::make_pair(n, production));

    return production;
}

void GrammarBuilder::_resolveUnknown(shared_ptr<Production> production)
{
    auto unknown = ast::tryCast<production::Unknown>(production);

    if ( unknown ) {
        auto n = unknown->node();
        auto p = _compiled.find(n);
        assert( p != _compiled.end());
        if ( ast::isA<Production>(n) )
            production->replace(n);
    }

    for ( auto c : production->childs() ) {
        if ( ast::isA<Production>(c) )
             _resolveUnknown(c->sharedPtr<binpac::Production>());
    }
}

string GrammarBuilder::counter(const string& key)
{
    auto cnt = 1;
    auto i = _counters.find(key);

    if ( i != _counters.end() )
        cnt = i->second;

    string s = util::fmt("%s%d", key.c_str(), cnt++);

    _counters[key] = cnt;

    return s;
}

void GrammarBuilder::visit(declaration::Type* d)
{
    // We are only interested in unit declarations.
    auto unit = ast::tryCast<type::Unit>(d->type());

    if ( ! unit )
        return;

    ++_in_decl;
    auto production = compileOne(unit);
    --_in_decl;

    _resolveUnknown(production);

    auto grammar = std::make_shared<Grammar>(d->id()->name(), production);

    if ( _debug )
        grammar->printTables(_debug_out, true);

    unit->setGrammar(grammar);
}

void GrammarBuilder::visit(type::Unit* u)
{
    if ( ! _in_decl )
        return;

    auto prods = Production::production_list();

    for ( auto f : u->fields() )
        prods.push_back(compileOne(f));

    string name;

    if ( u->id() )
        name = u->id()->name();
    else
        name = util::fmt("unit%d", _unit_counter++);

    auto unit = std::make_shared<production::Sequence>(name, prods, u->sharedPtr<type::Unit>(), u->location());
    setResult(unit);
}

void GrammarBuilder::visit(type::unit::item::field::Constant* c)
{
    if ( ! _in_decl )
        return;

    auto sym = "const:" + c->id()->name();
    auto prod = std::make_shared<production::Constant>(sym, c->constant());
    prod->pgMeta()->field = c->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Ctor* c)
{
    if ( ! _in_decl )
        return;

    auto sym = "ctor:" + c->id()->name();
    auto prod = std::make_shared<production::Ctor>(sym, c->ctor());
    prod->pgMeta()->field = c->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Switch* s)
{
    if ( ! _in_decl )
        return;

    production::Switch::case_list cases;
    shared_ptr<Production> default_ = nullptr;

    for ( auto c : s->cases() ) {
        if ( c->default_() ) {
            default_ = compileOne(c);
            continue;
        }

        auto pcase = std::make_pair(c->expressions(), compileOne(c));
        cases.push_back(pcase);
    }

    auto sym = "switch:" + s->id()->name();
    auto prod = std::make_shared<production::Switch>(sym, s->expression(), cases, default_, s->location());
    prod->pgMeta()->field = s->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::AtomicType* t)
{
    if ( ! _in_decl )
        return;

    shared_ptr<Production> prod;

    if ( ast::isA<type::EmbeddedObject>(t->type()) ) {
        // Not quite clear if there's a nicer way to present these than
        // special-casing them here.
        auto sym = "type:" + t->id()->name();
        prod = std::make_shared<production::TypeLiteral>(sym, t->type());
    }

    else {
        auto sym = "var:" + t->id()->name();
        prod = std::make_shared<production::Variable>(sym, t->type());
    }

    prod->pgMeta()->field = t->sharedPtr<type::unit::item::Field>();
    setResult(prod);
}

void GrammarBuilder::visit(type::unit::item::field::Unit* u)
{
    if ( ! _in_decl )
        return;

    ++_in_decl;
    auto chprod = compileOne(u->type());
    --_in_decl;

    string name;

    if ( u->id() )
        name = u->id()->name();
    else
        name = util::fmt("unit%d", _unit_counter++);

    assert(ast::isA<Production>(chprod));
    auto child = std::make_shared<production::ChildGrammar>(name, chprod, ast::checkedCast<type::Unit>(u->type()), u->location());
    child->pgMeta()->field = u->sharedPtr<type::unit::item::field::Unit>();
    setResult(child);
}

void GrammarBuilder::visit(type::unit::item::field::switch_::Case* c)
{
    if ( ! _in_decl )
        return;

    auto prods = Production::production_list();

    for ( auto i : c->items() )
        prods.push_back(compileOne(i));

    auto name = util::fmt("case%d", _case_counter++);
    auto seq = std::make_shared<production::Sequence>(name, prods, nullptr, c->location());
    setResult(seq);
}

void GrammarBuilder::visit(type::unit::item::field::container::List* l)
{
    if ( ! _in_decl )
        return;

    auto until = l->attributes()->lookup("until");
    auto until_including = l->attributes()->lookup("until_including");
    auto while_ = l->attributes()->lookup("while");
    auto count = l->attributes()->lookup("count");
    auto length = l->attributes()->lookup("length");

    auto sym = "list:" + l->id()->name();

    ++_in_decl;
    auto field = compileOne(l->field());
    field->setContainer(l->sharedPtr<type::unit::item::field::Container>());
    --_in_decl;

    if ( until || while_ || until_including ) {
        // We use a Loop production here. type::Container installs a &foreach
        // hook that stops the iteration once the condition is satisfied.
        // Doing it this way allows the condition to run in the hook's scope,
        // with access to "$$".
        auto l1 = std::make_shared<production::Loop>(sym, field, false, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l1);
    }

    else if ( count ) {
        auto l1 = std::make_shared<production::Counter>(sym, count->value(), field, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l1);
    }

    else if ( length ) {
        auto l1 = std::make_shared<production::Loop>(sym, field, true, l->location());
        auto l2 = std::make_shared<production::ByteBlock>(sym, length->value(), l1, l->location());
        l1->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        setResult(l2);
    }

    else {
        // No attributes, use look-ahead to figure out when to stop parsing.
        //
        // Left-factored & right-recursive.
        //
        // List1 -> Item List2
        // List2 -> Epsilon | List1

        auto epsilon = std::make_shared<production::Epsilon>(l->location());
        auto l1 = std::make_shared<production::Sequence>(sym + ":l1", Production::production_list(), nullptr, l->location());
        auto l2 = std::make_shared<production::LookAhead>(sym + ":l2", epsilon, l1, l->location());

        l1->add(field);
        l1->add(l2);

        auto c = std::make_shared<production::Enclosure>(sym, l2, l->location());
        c->pgMeta()->field = l->sharedPtr<type::unit::item::Field>();
        field->pgMeta()->for_each = c->pgMeta()->field;

        setResult(c);
    }
}

void GrammarBuilder::visit(type::unit::item::field::container::Vector* v)
{
    if ( ! _in_decl )
        return;

    auto length = v->length();
    auto sym = "vector:" + v->id()->name();

    ++_in_decl;
    auto field = compileOne(v->field());
    field->setContainer(v->sharedPtr<type::unit::item::field::Container>());
    --_in_decl;

    auto l1 = std::make_shared<production::Counter>(sym, v->length(), field, v->location());
    l1->pgMeta()->field = v->sharedPtr<type::unit::item::Field>();
    setResult(l1);
}
<|endoftext|>