<commit_before>#include "Binary.hpp"

#include <stdexcept>
#include <algorithm>

#include "constants.hpp"
#include "Tree.hpp"

using namespace std;

int safe_fclose(FILE* fptr) { return fptr ? fclose(fptr) : 0; }

Binary::Binary(const string& binary_file_path) : bin_fptr_(nullptr, safe_fclose)
{
  // open the binary file
  pll_binary_header_t header;
  bin_fptr_ = unique_fptr(pllmod_binary_open(binary_file_path.c_str(), &header), safe_fclose);

  if (!bin_fptr_)
    throw runtime_error{"Could not open binary file for reading."};

  if (header.access_type != PLLMOD_BIN_ACCESS_RANDOM)
    throw runtime_error{"Binary file must be random access enabled."};

  if (header.n_blocks <= 0)
    throw runtime_error{string("Binary file header must have nonzero positive number of blocks: ")
              + to_string(header.n_blocks)};

  // proccess the random access map
  unsigned int n_blocks;
  pll_block_map_t* block_map;
  block_map = pllmod_binary_get_map(bin_fptr_.get(), &n_blocks);

  assert(block_map);
  assert(n_blocks);

  for (size_t i = 0; i < n_blocks; i++)
  {
    map_.push_back(block_map[i]);
  }

  free(block_map);
}

static long int get_offset(vector<pll_block_map_t>& map, const int block_id)
{
  auto item = map.begin();
  while (item != map.end())
  {
    if (item->block_id == block_id)
      break;
    item++;
  }

  if(item == map.end())
    throw runtime_error{string("Map does not contain block_id: ") + to_string(block_id)};
  return item->block_offset;
}

void Binary::load_clv(pll_partition_t * partition, const unsigned int clv_index)
{
  assert(bin_fptr_);
  assert(clv_index < partition->clv_buffers + partition->tips);
  if (partition->attributes & PLL_ATTRIB_PATTERN_TIP)
    assert(clv_index >= partition->tips);

  if (!(partition->clv[clv_index]))
  {
    size_t clv_size = partition->sites * partition->states_padded *
                      partition->rate_cats*sizeof(double);
    partition->clv[clv_index] = (double*) pll_aligned_alloc(clv_size, partition->alignment);
    if (!partition->clv[i])
      throw runtime_error{"Could not allocate CLV memory"};
  }

  unsigned int attributes;
  auto err = pllmod_binary_clv_load(
    bin_fptr_.get(),
    0,
    partition,
    clv_index,
    &attributes,
    get_offset(map_, clv_index));

  if (err != PLL_SUCCESS)
    throw runtime_error{string("Loading CLV failed: ") + pll_errmsg};

}

void Binary::load_tipchars(pll_partition_t * partition, const unsigned int tipchars_index)
{
  assert(bin_fptr_);
  assert(tipchars_index < partition->tips);
  assert(partition->attributes & PLL_ATTRIB_PATTERN_TIP);

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load(bin_fptr_.get(), 0, &size, &type, &attributes, get_offset(map_, tipchars_index));
  if (!ptr)
    throw runtime_error{string("Loading tipchar failed: ") + pll_errmsg};

  partition->tipchars[tipchars_index] = (unsigned char*)ptr;
}

void Binary::load_scaler(pll_partition_t * partition, const unsigned int scaler_index)
{
  assert(bin_fptr_);
  assert(scaler_index < partition->scale_buffers);

  auto block_offset = partition->clv_buffers + partition->tips;

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load(bin_fptr_.get(), 0,
    &size, &type, &attributes, get_offset(map_, block_offset + scaler_index));
  if (!ptr)
    throw runtime_error{string("Loading scaler failed: ") + pll_errmsg};

  partition->scale_buffer[scaler_index] = (unsigned int*)ptr;
}

static pll_partition_t* skeleton_partition()
{
  auto attributes = PLL_ATTRIB_ARCH_SSE;
#ifdef __AVX
  attributes = PLL_ATTRIB_ARCH_AVX;
#endif

  attributes |= PLL_ATTRIB_PATTERN_TIP;

  auto partition = pll_partition_create(
    3, // number of tip nodes
    1, // number of extra clv buffers
    STATES,
    1, // number of sites
    1, // number of concurrent subs. models
    1, // number of probabillity matrices
    RATE_CATS,
    1, // number of scale buffers
    //pll_map_nt,
    attributes);

  if (!partition)
    throw runtime_error{string("Creating skeleton partition: ") + pll_errmsg};

  // ensure clv, tipchar and scaler fields are only shallowly allocated
  // TODO

  return partition;
}

static void dealloc_buffers(pll_partition_t* part)
{
  // dealloc clvs and tipchars
  if (part->tipchars)
    for (size_t i = 0; i < part->tips; ++i)
    {
      pll_aligned_free(part->tipchars[i]);
      part->tipchars[i] = nullptr;
    }

  if (part->clv)
  {
    size_t start = (part->attributes & PLL_ATTRIB_PATTERN_TIP) ? part->tips : 0;
    for (size_t i = start; i < part->clv_buffers + part->tips; ++i)
    {
      pll_aligned_free(part->clv[i]);
      part->clv[i] = nullptr;
    }
  }

  if (part->scale_buffer)
  {
    for (size_t i = 0; i < part->scale_buffers; ++i)
    {
      free(part->scale_buffer[i]);
      part->scale_buffer[i] = nullptr;
    }
  }
}

pll_partition_t* Binary::load_partition()
{
  // make skeleton partition that only allocates the pointers to the clv/tipchar buffers
  auto skelly = nullptr;// skeleton_partition();
  unsigned int attributes = PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;
  auto partition =  pllmod_binary_partition_load(bin_fptr_.get(), 0, skelly, &attributes,
    get_offset(map_, -1));

  if (!partition)
    throw runtime_error{string("Error loading partition: ") + pll_errmsg};

  // free up buffers for things we want to load on demand
  // TODO never alloc in the first place
  dealloc_buffers(partition);

  return partition;
}

pll_utree_t* Binary::load_utree()
{
  unsigned int attributes = 0;
  auto tree =  pllmod_binary_utree_load(bin_fptr_.get(), 0, &attributes, get_offset(map_, -2));
  if (!tree)
    throw runtime_error{string("Loading tree: ") + pll_errmsg};
  return tree;
}

/**
  Writes the structures and data encapsulated in Tree to the specified file in the binary format.
  Writes them in such a way that the Binary class can read them.
*/
void dump_to_binary(Tree& tree, const string& file)
{
  auto num_clvs = tree.partition()->clv_buffers;
  auto num_tips = tree.partition()->tips;
  auto num_scalers = tree.partition()->scale_buffers;
  auto max_clv_index = num_clvs + num_tips;

  pll_binary_header_t header;
  auto fptr =  pllmod_binary_create(
    file.c_str(),
    &header,
    PLLMOD_BIN_ACCESS_RANDOM,
    2 + num_clvs + num_tips + num_scalers);

  if(!fptr)
    throw runtime_error{string("Opening binary file for writing: ") + pll_errmsg};

  unsigned int attributes = PLLMOD_BIN_ATTRIB_UPDATE_MAP | PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;

  int block_id = -2;
  bool use_tipchars = tree.partition()->attributes & PLL_ATTRIB_PATTERN_TIP;

  // dump the utree structure
  if(!pllmod_binary_utree_dump(fptr, block_id++, tree.tree(), num_tips, attributes))
    throw runtime_error{string("Dumping the utree to binary: ") + pll_errmsg};

  // dump the partition
  if(!pllmod_binary_partition_dump(fptr, block_id++, tree.partition(), attributes))
    throw runtime_error{string("Dumping partition to binary: ") + pll_errmsg};

  // dump the tipchars, but only if partition uses them
  unsigned int tip_index = 0;
  if (use_tipchars)
  {
    for (tip_index = 0; tip_index < num_tips; tip_index++)
    {
      if(!pllmod_binary_custom_dump(fptr, block_id++, tree.partition()->tipchars[tip_index],
      tree.partition()->sites * sizeof(char), attributes))
        throw runtime_error{string("Dumping tipchars to binary: ") + pll_errmsg};
    }
  }

  // dump the clvs
  for (unsigned int clv_index = tip_index; clv_index < max_clv_index; clv_index++)
  {
    if(!pllmod_binary_clv_dump(fptr, block_id++, tree.partition(), clv_index, attributes))
      throw runtime_error{string("Dumping clvs to binary: ") + pll_errmsg};
  }

  // dump the scalers
  for (unsigned int scaler_index = 0; scaler_index < num_scalers; scaler_index++)
  {
    if(!pllmod_binary_custom_dump(fptr, block_id++, tree.partition()->scale_buffer[scaler_index],
      tree.partition()->sites * sizeof(unsigned int), attributes))
      throw runtime_error{string("Dumping scalers to binary: ") + pll_errmsg};
  }

  fclose(fptr);
}
<commit_msg>fixed incorrect index<commit_after>#include "Binary.hpp"

#include <stdexcept>
#include <algorithm>

#include "constants.hpp"
#include "Tree.hpp"

using namespace std;

int safe_fclose(FILE* fptr) { return fptr ? fclose(fptr) : 0; }

Binary::Binary(const string& binary_file_path) : bin_fptr_(nullptr, safe_fclose)
{
  // open the binary file
  pll_binary_header_t header;
  bin_fptr_ = unique_fptr(pllmod_binary_open(binary_file_path.c_str(), &header), safe_fclose);

  if (!bin_fptr_)
    throw runtime_error{"Could not open binary file for reading."};

  if (header.access_type != PLLMOD_BIN_ACCESS_RANDOM)
    throw runtime_error{"Binary file must be random access enabled."};

  if (header.n_blocks <= 0)
    throw runtime_error{string("Binary file header must have nonzero positive number of blocks: ")
              + to_string(header.n_blocks)};

  // proccess the random access map
  unsigned int n_blocks;
  pll_block_map_t* block_map;
  block_map = pllmod_binary_get_map(bin_fptr_.get(), &n_blocks);

  assert(block_map);
  assert(n_blocks);

  for (size_t i = 0; i < n_blocks; i++)
  {
    map_.push_back(block_map[i]);
  }

  free(block_map);
}

static long int get_offset(vector<pll_block_map_t>& map, const int block_id)
{
  auto item = map.begin();
  while (item != map.end())
  {
    if (item->block_id == block_id)
      break;
    item++;
  }

  if(item == map.end())
    throw runtime_error{string("Map does not contain block_id: ") + to_string(block_id)};
  return item->block_offset;
}

void Binary::load_clv(pll_partition_t * partition, const unsigned int clv_index)
{
  assert(bin_fptr_);
  assert(clv_index < partition->clv_buffers + partition->tips);
  if (partition->attributes & PLL_ATTRIB_PATTERN_TIP)
    assert(clv_index >= partition->tips);

  if (!(partition->clv[clv_index]))
  {
    size_t clv_size = partition->sites * partition->states_padded *
                      partition->rate_cats*sizeof(double);
    partition->clv[clv_index] = (double*) pll_aligned_alloc(clv_size, partition->alignment);
    if (!partition->clv[clv_index])
      throw runtime_error{"Could not allocate CLV memory"};
  }

  unsigned int attributes;
  auto err = pllmod_binary_clv_load(
    bin_fptr_.get(),
    0,
    partition,
    clv_index,
    &attributes,
    get_offset(map_, clv_index));

  if (err != PLL_SUCCESS)
    throw runtime_error{string("Loading CLV failed: ") + pll_errmsg};

}

void Binary::load_tipchars(pll_partition_t * partition, const unsigned int tipchars_index)
{
  assert(bin_fptr_);
  assert(tipchars_index < partition->tips);
  assert(partition->attributes & PLL_ATTRIB_PATTERN_TIP);

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load(bin_fptr_.get(), 0, &size, &type, &attributes, get_offset(map_, tipchars_index));
  if (!ptr)
    throw runtime_error{string("Loading tipchar failed: ") + pll_errmsg};

  partition->tipchars[tipchars_index] = (unsigned char*)ptr;
}

void Binary::load_scaler(pll_partition_t * partition, const unsigned int scaler_index)
{
  assert(bin_fptr_);
  assert(scaler_index < partition->scale_buffers);

  auto block_offset = partition->clv_buffers + partition->tips;

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load(bin_fptr_.get(), 0,
    &size, &type, &attributes, get_offset(map_, block_offset + scaler_index));
  if (!ptr)
    throw runtime_error{string("Loading scaler failed: ") + pll_errmsg};

  partition->scale_buffer[scaler_index] = (unsigned int*)ptr;
}

static pll_partition_t* skeleton_partition()
{
  auto attributes = PLL_ATTRIB_ARCH_SSE;
#ifdef __AVX
  attributes = PLL_ATTRIB_ARCH_AVX;
#endif

  attributes |= PLL_ATTRIB_PATTERN_TIP;

  auto partition = pll_partition_create(
    3, // number of tip nodes
    1, // number of extra clv buffers
    STATES,
    1, // number of sites
    1, // number of concurrent subs. models
    1, // number of probabillity matrices
    RATE_CATS,
    1, // number of scale buffers
    //pll_map_nt,
    attributes);

  if (!partition)
    throw runtime_error{string("Creating skeleton partition: ") + pll_errmsg};

  // ensure clv, tipchar and scaler fields are only shallowly allocated
  // TODO

  return partition;
}

static void dealloc_buffers(pll_partition_t* part)
{
  // dealloc clvs and tipchars
  if (part->tipchars)
    for (size_t i = 0; i < part->tips; ++i)
    {
      pll_aligned_free(part->tipchars[i]);
      part->tipchars[i] = nullptr;
    }

  if (part->clv)
  {
    size_t start = (part->attributes & PLL_ATTRIB_PATTERN_TIP) ? part->tips : 0;
    for (size_t i = start; i < part->clv_buffers + part->tips; ++i)
    {
      pll_aligned_free(part->clv[i]);
      part->clv[i] = nullptr;
    }
  }

  if (part->scale_buffer)
  {
    for (size_t i = 0; i < part->scale_buffers; ++i)
    {
      free(part->scale_buffer[i]);
      part->scale_buffer[i] = nullptr;
    }
  }
}

pll_partition_t* Binary::load_partition()
{
  // make skeleton partition that only allocates the pointers to the clv/tipchar buffers
  auto skelly = nullptr;// skeleton_partition();
  unsigned int attributes = PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;
  auto partition =  pllmod_binary_partition_load(bin_fptr_.get(), 0, skelly, &attributes,
    get_offset(map_, -1));

  if (!partition)
    throw runtime_error{string("Error loading partition: ") + pll_errmsg};

  // free up buffers for things we want to load on demand
  // TODO never alloc in the first place
  dealloc_buffers(partition);

  return partition;
}

pll_utree_t* Binary::load_utree()
{
  unsigned int attributes = 0;
  auto tree =  pllmod_binary_utree_load(bin_fptr_.get(), 0, &attributes, get_offset(map_, -2));
  if (!tree)
    throw runtime_error{string("Loading tree: ") + pll_errmsg};
  return tree;
}

/**
  Writes the structures and data encapsulated in Tree to the specified file in the binary format.
  Writes them in such a way that the Binary class can read them.
*/
void dump_to_binary(Tree& tree, const string& file)
{
  auto num_clvs = tree.partition()->clv_buffers;
  auto num_tips = tree.partition()->tips;
  auto num_scalers = tree.partition()->scale_buffers;
  auto max_clv_index = num_clvs + num_tips;

  pll_binary_header_t header;
  auto fptr =  pllmod_binary_create(
    file.c_str(),
    &header,
    PLLMOD_BIN_ACCESS_RANDOM,
    2 + num_clvs + num_tips + num_scalers);

  if(!fptr)
    throw runtime_error{string("Opening binary file for writing: ") + pll_errmsg};

  unsigned int attributes = PLLMOD_BIN_ATTRIB_UPDATE_MAP | PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;

  int block_id = -2;
  bool use_tipchars = tree.partition()->attributes & PLL_ATTRIB_PATTERN_TIP;

  // dump the utree structure
  if(!pllmod_binary_utree_dump(fptr, block_id++, tree.tree(), num_tips, attributes))
    throw runtime_error{string("Dumping the utree to binary: ") + pll_errmsg};

  // dump the partition
  if(!pllmod_binary_partition_dump(fptr, block_id++, tree.partition(), attributes))
    throw runtime_error{string("Dumping partition to binary: ") + pll_errmsg};

  // dump the tipchars, but only if partition uses them
  unsigned int tip_index = 0;
  if (use_tipchars)
  {
    for (tip_index = 0; tip_index < num_tips; tip_index++)
    {
      if(!pllmod_binary_custom_dump(fptr, block_id++, tree.partition()->tipchars[tip_index],
      tree.partition()->sites * sizeof(char), attributes))
        throw runtime_error{string("Dumping tipchars to binary: ") + pll_errmsg};
    }
  }

  // dump the clvs
  for (unsigned int clv_index = tip_index; clv_index < max_clv_index; clv_index++)
  {
    if(!pllmod_binary_clv_dump(fptr, block_id++, tree.partition(), clv_index, attributes))
      throw runtime_error{string("Dumping clvs to binary: ") + pll_errmsg};
  }

  // dump the scalers
  for (unsigned int scaler_index = 0; scaler_index < num_scalers; scaler_index++)
  {
    if(!pllmod_binary_custom_dump(fptr, block_id++, tree.partition()->scale_buffer[scaler_index],
      tree.partition()->sites * sizeof(unsigned int), attributes))
      throw runtime_error{string("Dumping scalers to binary: ") + pll_errmsg};
  }

  fclose(fptr);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbStreamingStatisticsMapFromLabelImageFilter.h"
#include "otbLabelImageSmallRegionMergingFilter.h"
#include "itkChangeLabelImageFilter.h"

#include "otbStopwatch.h"

namespace otb
{
namespace Wrapper
{
class SmallRegionsMerging : public Application
{
public:
  typedef SmallRegionsMerging Self;
  typedef Application Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  typedef FloatVectorImageType              ImageType;
  typedef ImageType::InternalPixelType      ImagePixelType;
  typedef UInt32ImageType                   LabelImageType;
  typedef LabelImageType::InternalPixelType LabelImagePixelType;

  typedef otb::StreamingStatisticsMapFromLabelImageFilter
      <ImageType, LabelImageType> StatisticsMapFromLabelImageFilterType;

  typedef otb::LabelImageSmallRegionMergingFilter<LabelImageType>
                                  LabelImageSmallRegionMergingFilterType;

  typedef itk::ChangeLabelImageFilter<LabelImageType,LabelImageType>
                                  ChangeLabelImageFilterType;

  itkNewMacro(Self);
  itkTypeMacro(Merging, otb::Application);

private:
  ChangeLabelImageFilterType::Pointer m_ChangeLabelFilter;

  void DoInit() override
  {
    SetName("SmallRegionsMerging");
    SetDescription("This application merges small regions of a segmentation "
      "result to connected region.");

    SetDocName("Small Region Merging");
    SetDocLongDescription("Given a segmentation result and the original image,"
                          " it will merge segments whose size in pixels is"
                          " lower than minsize parameter with the adjacent"
                          " segments with the adjacent segment with closest"
                          " radiometry and acceptable size. \n\n"
                          "Small segments will be processed by increasing size:"
                          " first all segments for which area is equal to 1"
                          " pixel will be merged with adjacent segments, then"
                          " all segments of area equal to 2 pixels will be"
                          " processed, until segments of area minsize.");

    SetDocLimitations( "None") ;

    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("Segmentation");
    AddDocTag(Tags::Segmentation);

    AddParameter(ParameterType_InputImage,  "in", "Input image");
    SetParameterDescription( "in", "The input image, containing initial"
      " spectral signatures corresponding to the segmented image (inseg)." );
    AddParameter(ParameterType_InputImage, "inseg", "Segmented image");
    SetParameterDescription( "inseg", "Segmented image where each pixel value"
    " is the unique integer label of the segment it belongs to." );

    AddParameter(ParameterType_OutputImage, "out", "Output Image");
    SetParameterDescription( "out", "The output image. The output image is the"
    " segmented image where the minimal segments have been merged." );
    SetDefaultOutputPixelType("out",ImagePixelType_uint32);

    AddParameter(ParameterType_Int, "minsize", "Minimum Segment Size");
    SetParameterDescription("minsize", "Minimum Segment Size. If, after the "
    " segmentation, a segment is of size strictly lower than this criterion,"
    " the segment is merged with the segment that has the closest sepctral"
    " signature.");

    SetDefaultParameterInt("minsize", 50);
    SetMinimumParameterIntValue("minsize", 1);
    MandatoryOff("minsize");

    AddRAMParameter();

    // Doc example parameter settings
    SetDocExampleParameterValue("in","smooth.tif");
    SetDocExampleParameterValue("inseg","segmentation.tif");
    SetDocExampleParameterValue("out","merged.tif");
    SetDocExampleParameterValue("minsize","50");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() override
  {
  }

  void DoExecute() override
  {
    // Start Timer for the application
    auto Timer = Stopwatch::StartNew();

    unsigned int minSize     = GetParameterInt("minsize");

    //Acquisition of the input image dimensions
    ImageType::Pointer imageIn = GetParameterImage("in");

    LabelImageType::Pointer labelIn = GetParameterUInt32Image("inseg");

    // Compute statistics for each segment
    auto labelStatsFilter = StatisticsMapFromLabelImageFilterType::New();
    labelStatsFilter->SetInput(imageIn);
    labelStatsFilter->SetInputLabelImage(labelIn);
    AddProcess(labelStatsFilter->GetStreamer() , "Computing stats on input"
      " image ...");
    labelStatsFilter->Update();

    // Convert Map to Unordered map

    auto  labelPopulationMap = labelStatsFilter->GetLabelPopulationMap();
    std::unordered_map< unsigned int,double> labelPopulation;
    for (auto population : labelPopulationMap)
      {
      labelPopulation[population.first]=population.second;
      }
    auto  meanValueMap = labelStatsFilter->GetMeanValueMap();
    std::unordered_map< unsigned int, itk::VariableLengthVector<double> >
      meanValues;
    for (const auto & mean : meanValueMap)
      {
      meanValues[mean.first] = mean.second;
      }

    // Compute the LUT from the original label image to the merged output
    // label image.
    auto regionMergingFilter = LabelImageSmallRegionMergingFilterType::New();
    regionMergingFilter->SetInputLabelImage( labelIn );
    regionMergingFilter->SetLabelPopulation( labelPopulation );
    regionMergingFilter->SetLabelStatistic( meanValues );
    regionMergingFilter->SetMinSize( minSize);

    AddProcess(regionMergingFilter, "Computing LUT ...");
    regionMergingFilter->Update();

    // Relabelling using the LUT
    auto changeLabelFilter = ChangeLabelImageFilterType::New();
    changeLabelFilter->SetInput(labelIn);

    const auto & LUT = regionMergingFilter->GetLUT();

    for (auto label : LUT)
    {
      if (label.first != label.second)
      {
        changeLabelFilter->SetChange(label.first, label.second);
      }
    }
    SetParameterOutputImage("out", changeLabelFilter->GetOutput());
    RegisterPipeline();

    Timer.Stop();
    otbAppLogINFO( "Total elapsed time: "<< float(Timer.GetElapsedMilliseconds())/1000 <<" seconds.");

  }

};
}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::SmallRegionsMerging)

<commit_msg>STYLE : 80 char rule for timer<commit_after>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbStreamingStatisticsMapFromLabelImageFilter.h"
#include "otbLabelImageSmallRegionMergingFilter.h"
#include "itkChangeLabelImageFilter.h"

#include "otbStopwatch.h"

namespace otb
{
namespace Wrapper
{
class SmallRegionsMerging : public Application
{
public:
  typedef SmallRegionsMerging Self;
  typedef Application Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  typedef FloatVectorImageType              ImageType;
  typedef ImageType::InternalPixelType      ImagePixelType;
  typedef UInt32ImageType                   LabelImageType;
  typedef LabelImageType::InternalPixelType LabelImagePixelType;

  typedef otb::StreamingStatisticsMapFromLabelImageFilter
      <ImageType, LabelImageType> StatisticsMapFromLabelImageFilterType;

  typedef otb::LabelImageSmallRegionMergingFilter<LabelImageType>
                                  LabelImageSmallRegionMergingFilterType;

  typedef itk::ChangeLabelImageFilter<LabelImageType,LabelImageType>
                                  ChangeLabelImageFilterType;

  itkNewMacro(Self);
  itkTypeMacro(Merging, otb::Application);

private:
  ChangeLabelImageFilterType::Pointer m_ChangeLabelFilter;

  void DoInit() override
  {
    SetName("SmallRegionsMerging");
    SetDescription("This application merges small regions of a segmentation "
      "result to connected region.");

    SetDocName("Small Region Merging");
    SetDocLongDescription("Given a segmentation result and the original image,"
                          " it will merge segments whose size in pixels is"
                          " lower than minsize parameter with the adjacent"
                          " segments with the adjacent segment with closest"
                          " radiometry and acceptable size. \n\n"
                          "Small segments will be processed by increasing size:"
                          " first all segments for which area is equal to 1"
                          " pixel will be merged with adjacent segments, then"
                          " all segments of area equal to 2 pixels will be"
                          " processed, until segments of area minsize.");

    SetDocLimitations( "None") ;

    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("Segmentation");
    AddDocTag(Tags::Segmentation);

    AddParameter(ParameterType_InputImage,  "in", "Input image");
    SetParameterDescription( "in", "The input image, containing initial"
      " spectral signatures corresponding to the segmented image (inseg)." );
    AddParameter(ParameterType_InputImage, "inseg", "Segmented image");
    SetParameterDescription( "inseg", "Segmented image where each pixel value"
    " is the unique integer label of the segment it belongs to." );

    AddParameter(ParameterType_OutputImage, "out", "Output Image");
    SetParameterDescription( "out", "The output image. The output image is the"
    " segmented image where the minimal segments have been merged." );
    SetDefaultOutputPixelType("out",ImagePixelType_uint32);

    AddParameter(ParameterType_Int, "minsize", "Minimum Segment Size");
    SetParameterDescription("minsize", "Minimum Segment Size. If, after the "
    " segmentation, a segment is of size strictly lower than this criterion,"
    " the segment is merged with the segment that has the closest sepctral"
    " signature.");

    SetDefaultParameterInt("minsize", 50);
    SetMinimumParameterIntValue("minsize", 1);
    MandatoryOff("minsize");

    AddRAMParameter();

    // Doc example parameter settings
    SetDocExampleParameterValue("in","smooth.tif");
    SetDocExampleParameterValue("inseg","segmentation.tif");
    SetDocExampleParameterValue("out","merged.tif");
    SetDocExampleParameterValue("minsize","50");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() override
  {
  }

  void DoExecute() override
  {
    // Start Timer for the application
    auto Timer = Stopwatch::StartNew();

    unsigned int minSize     = GetParameterInt("minsize");

    //Acquisition of the input image dimensions
    ImageType::Pointer imageIn = GetParameterImage("in");

    LabelImageType::Pointer labelIn = GetParameterUInt32Image("inseg");

    // Compute statistics for each segment
    auto labelStatsFilter = StatisticsMapFromLabelImageFilterType::New();
    labelStatsFilter->SetInput(imageIn);
    labelStatsFilter->SetInputLabelImage(labelIn);
    AddProcess(labelStatsFilter->GetStreamer() , "Computing stats on input"
      " image ...");
    labelStatsFilter->Update();

    // Convert Map to Unordered map

    auto  labelPopulationMap = labelStatsFilter->GetLabelPopulationMap();
    std::unordered_map< unsigned int,double> labelPopulation;
    for (auto population : labelPopulationMap)
      {
      labelPopulation[population.first]=population.second;
      }
    auto  meanValueMap = labelStatsFilter->GetMeanValueMap();
    std::unordered_map< unsigned int, itk::VariableLengthVector<double> >
      meanValues;
    for (const auto & mean : meanValueMap)
      {
      meanValues[mean.first] = mean.second;
      }

    // Compute the LUT from the original label image to the merged output
    // label image.
    auto regionMergingFilter = LabelImageSmallRegionMergingFilterType::New();
    regionMergingFilter->SetInputLabelImage( labelIn );
    regionMergingFilter->SetLabelPopulation( labelPopulation );
    regionMergingFilter->SetLabelStatistic( meanValues );
    regionMergingFilter->SetMinSize( minSize);

    AddProcess(regionMergingFilter, "Computing LUT ...");
    regionMergingFilter->Update();

    // Relabelling using the LUT
    auto changeLabelFilter = ChangeLabelImageFilterType::New();
    changeLabelFilter->SetInput(labelIn);

    const auto & LUT = regionMergingFilter->GetLUT();

    for (auto label : LUT)
    {
      if (label.first != label.second)
      {
        changeLabelFilter->SetChange(label.first, label.second);
      }
    }
    SetParameterOutputImage("out", changeLabelFilter->GetOutput());
    RegisterPipeline();

    Timer.Stop();
    otbAppLogINFO( "Total elapsed time: "<<
      float(Timer.GetElapsedMilliseconds())/1000 <<" seconds.");

  }

};
}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::SmallRegionsMerging)

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkSigmoidImageFilter.h"

int itkSigmoidImageFilterTest(int, char* [] )
{

  // Define the dimension of the images
  const unsigned int ImageDimension = 3;

  // Declare the types of the images
  typedef float       InputPixelType;
  typedef float       OutputPixelType;

  typedef itk::Image<InputPixelType,  ImageDimension>  InputImageType;
  typedef itk::Image<OutputPixelType, ImageDimension>  OutputImageType;

  // Declare Iterator types apropriated for each image
  typedef itk::ImageRegionIteratorWithIndex<
                                  InputImageType>  InputIteratorType;
  typedef itk::ImageRegionIteratorWithIndex<
                                  OutputImageType> OutputIteratorType;

  // Declare the type of the index to access images
  typedef itk::Index<ImageDimension>         IndexType;

  // Declare the type of the size
  typedef itk::Size<ImageDimension>          SizeType;

  // Declare the type of the Region
  typedef itk::ImageRegion<ImageDimension>   RegionType;

  // Create two images
  InputImageType::Pointer inputImage  = InputImageType::New();

  // Define their size, and start index
  SizeType size;
  size[0] = 2;
  size[1] = 2;
  size[2] = 2;

  IndexType start;
  start[0] = 0;
  start[1] = 0;
  start[2] = 0;

  RegionType region;
  region.SetIndex( start );
  region.SetSize( size );

  // Initialize Image A
  inputImage->SetLargestPossibleRegion( region );
  inputImage->SetBufferedRegion( region );
  inputImage->SetRequestedRegion( region );
  inputImage->Allocate();
  // Create one iterator for the Input Image (this is a light object)
  InputIteratorType it( inputImage, inputImage->GetBufferedRegion() );

  // Initialize the content of Image A
  const double value = 30;
  std::cout << "Content of the Input " << std::endl;
  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    it.Set( value );
    std::cout << it.Get() << std::endl;
    ++it;
  }

  // Declare the type for the Sigmoid filter
  typedef itk::SigmoidImageFilter< InputImageType,
                               OutputImageType  >  FilterType;

  // Create a Filter
  FilterType::Pointer filter = FilterType::New();

  // Connect the input images
  filter->SetInput( inputImage );

  // Set alpha and beta parameters
  const double alpha = 2.0;
  const double beta  = 3.0;

  filter->SetAlpha( alpha );
  filter->SetBeta(  beta  );

  const OutputPixelType maximum =  1.0;
  const OutputPixelType minimum = -1.0;

  filter->SetOutputMinimum( minimum );
  filter->SetOutputMaximum( maximum );

  // Get the Smart Pointer to the Filter Output
  OutputImageType::Pointer outputImage = filter->GetOutput();

  // Execute the filter
  filter->Update();
  filter->SetFunctor(filter->GetFunctor());

  // Create an iterator for going through the image output
  OutputIteratorType ot(outputImage, outputImage->GetRequestedRegion());

  //  Check the content of the result image
  std::cout << "Verification of the output " << std::endl;
  const OutputImageType::PixelType epsilon = 1e-6;
  ot.GoToBegin();
  it.GoToBegin();
  while( !ot.IsAtEnd() )
    {
    const InputImageType::PixelType  input  = it.Get();
    const OutputImageType::PixelType output = ot.Get();
    const double x1 = ( input - beta ) / alpha;
    const double x2 = ( maximum - minimum )*( 1.0 / ( 1.0 + std::exp( -x1 ) ) ) + minimum;
    const OutputImageType::PixelType sigmoid  =
            static_cast<OutputImageType::PixelType>( x2 );
    if( std::fabs( sigmoid - output ) > epsilon )
      {
      std::cerr << "Error in itkSigmoidImageFilterTest " << std::endl;
      std::cerr << " simoid( " << input << ") = " << sigmoid << std::endl;
      std::cerr << " differs from " << output;
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++ot;
    ++it;
    }

  return EXIT_SUCCESS;
}
<commit_msg>ENH: Improve itkSigmoidImageFilter coverage.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkMath.h"
#include "itkSigmoidImageFilter.h"
#include "itkTestingMacros.h"

int itkSigmoidImageFilterTest( int, char* [] )
{

  // Define the dimension of the images
  const unsigned int ImageDimension = 3;

  // Declare the types of the images
  typedef float       InputPixelType;
  typedef float       OutputPixelType;

  typedef itk::Image< InputPixelType,  ImageDimension >  InputImageType;
  typedef itk::Image< OutputPixelType, ImageDimension >  OutputImageType;

  // Declare appropriate Iterator types for each image
  typedef itk::ImageRegionIteratorWithIndex<
                                  InputImageType>  InputIteratorType;
  typedef itk::ImageRegionIteratorWithIndex<
                                  OutputImageType> OutputIteratorType;

  // Declare the type of the index to access images
  typedef itk::Index< ImageDimension >         IndexType;

  // Declare the type of the size
  typedef itk::Size< ImageDimension >          SizeType;

  // Declare the type of the Region
  typedef itk::ImageRegion< ImageDimension >   RegionType;

  // Create the input images
  InputImageType::Pointer inputImage = InputImageType::New();

  // Define their size, and start index
  SizeType size;
  size[0] = 2;
  size[1] = 2;
  size[2] = 2;

  IndexType start;
  start[0] = 0;
  start[1] = 0;
  start[2] = 0;

  RegionType region;
  region.SetIndex( start );
  region.SetSize( size );

  // Initialize the input image
  inputImage->SetLargestPossibleRegion( region );
  inputImage->SetBufferedRegion( region );
  inputImage->SetRequestedRegion( region );
  inputImage->Allocate();

  // Create one iterator for the input image (this is a light object)
  InputIteratorType it( inputImage, inputImage->GetBufferedRegion() );

  // Initialize the content of the input image
  const double value = 30;
  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    it.Set( value );
    ++it;
  }

  // Declare the type for the Sigmoid filter
  typedef itk::SigmoidImageFilter< InputImageType,
                               OutputImageType > FilterType;

  // Create the filter
  FilterType::Pointer filter = FilterType::New();

  EXERCISE_BASIC_OBJECT_METHODS( filter, SigmoidImageFilter,
    UnaryFunctorImageFilter );

  // Set the input image
  filter->SetInput( inputImage );

  // Set the filter parameters
  const double alpha = 2.0;
  const double beta  = 3.0;

  filter->SetAlpha( alpha );
  TEST_SET_GET_VALUE( alpha, filter->GetAlpha() );

  filter->SetBeta( beta );
  TEST_SET_GET_VALUE( beta, filter->GetBeta() );

  const OutputPixelType maximum =  1.0;
  const OutputPixelType minimum = -1.0;

  filter->SetOutputMinimum( minimum );
  TEST_SET_GET_VALUE( minimum, filter->GetOutputMinimum() );

  filter->SetOutputMaximum( maximum );
  TEST_SET_GET_VALUE( maximum, filter->GetOutputMaximum() );

  filter->SetFunctor( filter->GetFunctor() );

  // Execute the filter
  filter->Update();

  // Get the filter output
  OutputImageType::Pointer outputImage = filter->GetOutput();

  // Create an iterator for going through the image output
  OutputIteratorType ot( outputImage, outputImage->GetRequestedRegion() );

  // Check the content of the result image
  const OutputImageType::PixelType epsilon = 1e-6;
  ot.GoToBegin();
  it.GoToBegin();
  while( !ot.IsAtEnd() )
    {
    const InputImageType::PixelType  input  = it.Get();
    const OutputImageType::PixelType output = ot.Get();
    const double x1 = ( input - beta ) / alpha;
    const double x2 = ( maximum - minimum )*( 1.0 / ( 1.0 + std::exp( -x1 ) ) ) + minimum;
    const OutputImageType::PixelType sigmoid =
            static_cast<OutputImageType::PixelType>( x2 );
    if( !itk::Math::FloatAlmostEqual( sigmoid, output, 10, epsilon ) )
      {
      std::cerr.precision( static_cast< int >( itk::Math::abs( std::log10( epsilon ) ) ) );
      std::cerr << "Error in itkSigmoidImageFilterTest " << std::endl;
      std::cerr << " simoid( " << input << ") = " << sigmoid << std::endl;
      std::cerr << " differs from " << output;
      std::cerr << " by more than " << epsilon << std::endl;
      return EXIT_FAILURE;
      }
    ++ot;
    ++it;
    }

  return EXIT_SUCCESS;
}
<|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 "mitkComputeContourSetNormalsFilter.h"

#include "mitkImagePixelReadAccessor.h"
#include "mitkIOUtil.h"

mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter()
  : m_SegmentationBinaryImage(NULL)
  , m_MaxSpacing(5)
  , m_NegativeNormalCounter(0)
  , m_PositiveNormalCounter(0)
  , m_UseProgressBar(false)
  , m_ProgressStepSize(1)
{
  mitk::Surface::Pointer output = mitk::Surface::New();
  this->SetNthOutput(0, output.GetPointer());
}

mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter()
{
}

void mitk::ComputeContourSetNormalsFilter::GenerateData()
{
  unsigned int numberOfInputs = this->GetNumberOfIndexedInputs();

  //Iterating over each input
  for(unsigned int i = 0; i < numberOfInputs; i++)
  {
    //Getting the inputs polydata and polygons
    Surface* currentSurface = const_cast<Surface*>( this->GetInput(i) );
    vtkPolyData* polyData = currentSurface->GetVtkPolyData();

    vtkSmartPointer<vtkCellArray> existingPolys = polyData->GetPolys();

    vtkSmartPointer<vtkPoints> existingPoints = polyData->GetPoints();

    existingPolys->InitTraversal();

    vtkIdType* cell (NULL);
    vtkIdType cellSize (0);

    //The array that contains all the vertex normals of the current polygon
    vtkSmartPointer<vtkDoubleArray> normals = vtkSmartPointer<vtkDoubleArray>::New();
    normals->SetNumberOfComponents(3);
    normals->SetNumberOfTuples(polyData->GetNumberOfPoints());

    //If the current contour is an inner contour then the direction is -1
    //A contour lies inside another one if the pixel values in the direction of the normal is 1
    m_NegativeNormalCounter = 0;
    m_PositiveNormalCounter = 0;
    vtkIdType offSet (0);

    //Iterating over each polygon
    for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);)
    {
      if(cellSize < 3)continue;

      //First we calculate the current polygon's normal
      double polygonNormal[3] = {0.0};

      double p1[3];
      double p2[3];

      double v1[3];
      double v2[3];

      existingPoints->GetPoint(cell[0], p1);
      unsigned int index = cellSize*0.5;
      existingPoints->GetPoint(cell[index], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      for (vtkIdType k = 2; k < cellSize; k++)
      {
        index = cellSize*0.25;
        existingPoints->GetPoint(cell[index], p1);
        index = cellSize*0.75;
        existingPoints->GetPoint(cell[index], p2);

        v2[0] = p2[0]-p1[0];
        v2[1] = p2[1]-p1[1];
        v2[2] = p2[2]-p1[2];

        vtkMath::Cross(v1,v2,polygonNormal);
        if (vtkMath::Norm(polygonNormal) != 0)
          break;
      }

      vtkMath::Normalize(polygonNormal);

      //Now we start computing the normal for each vertex

      double vertexNormalTemp[3];
      existingPoints->GetPoint(cell[0], p1);
      existingPoints->GetPoint(cell[1], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      vtkMath::Cross(v1,polygonNormal,vertexNormalTemp);

      vtkMath::Normalize(vertexNormalTemp);

      double vertexNormal[3];

      for (vtkIdType j = 0; j < cellSize-2; j++)
      {
        existingPoints->GetPoint(cell[j+1], p1);
        existingPoints->GetPoint(cell[j+2], p2);

        v1[0] = p2[0]-p1[0];
        v1[1] = p2[1]-p1[1];
        v1[2] = p2[2]-p1[2];

        vtkMath::Cross(v1,polygonNormal,vertexNormal);

        vtkMath::Normalize(vertexNormal);

        double finalNormal[3];

        finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5;
        finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5;
        finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5;
        vtkMath::Normalize(finalNormal);

        //Here we determine the direction of the normal
        if (m_SegmentationBinaryImage)
        {
          Point3D worldCoord;
          worldCoord[0] = p1[0]+finalNormal[0]*m_MaxSpacing;
          worldCoord[1] = p1[1]+finalNormal[1]*m_MaxSpacing;
          worldCoord[2] = p1[2]+finalNormal[2]*m_MaxSpacing;

          double val = 0.0;

          mitk::ImagePixelReadAccessor<unsigned char> readAccess(m_SegmentationBinaryImage);
          itk::Index<3> idx;
          m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx);
          try
          {
            val = readAccess.GetPixelByIndexSafe(idx);
          }
          catch (mitk::Exception e)
          {
            // If value is outside the image's region ignore it
          }

          if (val == 0.0)
          {
              //MITK_INFO << "val equals zero.";
              ++m_PositiveNormalCounter;
          }
          else
          {
            //MITK_INFO << "val does not equal zero.";
              ++m_NegativeNormalCounter;
          }
        }

        vertexNormalTemp[0] = vertexNormal[0];
        vertexNormalTemp[1] = vertexNormal[1];
        vertexNormalTemp[2] = vertexNormal[2];

        vtkIdType id = cell[j+1];
        normals->SetTuple(id,finalNormal);
      }

      existingPoints->GetPoint(cell[0], p1);
      existingPoints->GetPoint(cell[1], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      vtkMath::Cross(v1,polygonNormal,vertexNormal);

      vtkMath::Normalize(vertexNormal);

      vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5;
      vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5;
      vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5;
      vtkMath::Normalize(vertexNormal);

      vtkIdType id = cell[0];
      normals->SetTuple(id,vertexNormal);
      id = cell[cellSize-1];
      normals->SetTuple(id,vertexNormal);

      if(m_NegativeNormalCounter > m_PositiveNormalCounter)
      {
          for(vtkIdType n = 0; n < cellSize; n++)
          {
              double normal[3];
              normals->GetTuple(offSet+n, normal);
              normal[0] = (-1)*normal[0];
              normal[1] = (-1)*normal[1];
              normal[2] = (-1)*normal[2];
              normals->SetTuple(offSet+n, normal);
          }
      }

      m_NegativeNormalCounter = 0;
      m_PositiveNormalCounter = 0;
      offSet += cellSize;

    }//end for all cells

    Surface::Pointer surface = this->GetOutput(i);
    surface->GetVtkPolyData()->GetCellData()->SetNormals(normals);
  }//end for all inputs

  //Setting progressbar
  if (this->m_UseProgressBar)
    mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize);
}

mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface()
{
  //Just for debugging:
  vtkSmartPointer<vtkPolyData> newPolyData = vtkSmartPointer<vtkPolyData>::New();
  vtkSmartPointer<vtkCellArray> newLines = vtkSmartPointer<vtkCellArray>::New();
  vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
  unsigned int idCounter (0);
  //Debug end

  for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++)
  {
    Surface* currentSurface = const_cast<Surface*>( this->GetOutput(i) );
    vtkPolyData* polyData = currentSurface->GetVtkPolyData();

    vtkSmartPointer<vtkDoubleArray> currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals());

    vtkSmartPointer<vtkCellArray> existingPolys = polyData->GetPolys();

    vtkSmartPointer<vtkPoints> existingPoints = polyData->GetPoints();

    existingPolys->InitTraversal();

    vtkIdType* cell (NULL);
    vtkIdType cellSize (0);

    for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);)
    {
      for ( vtkIdType j = 0; j < cellSize; j++ )
      {
        double currentNormal[3];
        currentCellNormals->GetTuple(cell[j], currentNormal);
        vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
        line->GetPointIds()->SetNumberOfIds(2);
        double newPoint[3];
        double p0[3];
        existingPoints->GetPoint(cell[j], p0);
        newPoint[0] = p0[0] + currentNormal[0];
        newPoint[1] = p0[1] + currentNormal[1];
        newPoint[2] = p0[2] + currentNormal[2];

        line->GetPointIds()->SetId(0, idCounter);
        newPoints->InsertPoint(idCounter, p0);
        idCounter++;

        line->GetPointIds()->SetId(1, idCounter);
        newPoints->InsertPoint(idCounter, newPoint);
        idCounter++;

        newLines->InsertNextCell(line);
      }//end for all points
    }//end for all cells
  }//end for all outputs

  newPolyData->SetPoints(newPoints);
  newPolyData->SetLines(newLines);
  newPolyData->BuildCells();

  mitk::Surface::Pointer surface = mitk::Surface::New();
  surface->SetVtkPolyData(newPolyData);

  return surface;

}

void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing)
{
    m_MaxSpacing = maxSpacing;
}

void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation()
{
  Superclass::GenerateOutputInformation();
}

void mitk::ComputeContourSetNormalsFilter::Reset()
{
  for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++)
  {
    this->PopBackInput();
  }
  this->SetNumberOfIndexedInputs(0);
  this->SetNumberOfIndexedOutputs(0);

  mitk::Surface::Pointer output = mitk::Surface::New();
  this->SetNthOutput(0, output.GetPointer());
}

void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status)
{
  this->m_UseProgressBar = status;
}

void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize)
{
  this->m_ProgressStepSize = stepSize;
}
<commit_msg>Fix 3D interpolation<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 "mitkComputeContourSetNormalsFilter.h"

#include "mitkImagePixelReadAccessor.h"
#include "mitkIOUtil.h"

mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter()
  : m_SegmentationBinaryImage(NULL)
  , m_MaxSpacing(5)
  , m_NegativeNormalCounter(0)
  , m_PositiveNormalCounter(0)
  , m_UseProgressBar(false)
  , m_ProgressStepSize(1)
{
  mitk::Surface::Pointer output = mitk::Surface::New();
  this->SetNthOutput(0, output.GetPointer());
}

mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter()
{
}

void mitk::ComputeContourSetNormalsFilter::GenerateData()
{
  unsigned int numberOfInputs = this->GetNumberOfIndexedInputs();

  //Iterating over each input
  for(unsigned int i = 0; i < numberOfInputs; i++)
  {
    //Getting the inputs polydata and polygons
    Surface* currentSurface = const_cast<Surface*>( this->GetInput(i) );
    vtkPolyData* polyData = currentSurface->GetVtkPolyData();

    vtkSmartPointer<vtkCellArray> existingPolys = polyData->GetPolys();

    vtkSmartPointer<vtkPoints> existingPoints = polyData->GetPoints();

    existingPolys->InitTraversal();

    vtkIdType* cell (NULL);
    vtkIdType cellSize (0);

    //The array that contains all the vertex normals of the current polygon
    vtkSmartPointer<vtkDoubleArray> normals = vtkSmartPointer<vtkDoubleArray>::New();
    normals->SetNumberOfComponents(3);
    normals->SetNumberOfTuples(polyData->GetNumberOfPoints());

    //If the current contour is an inner contour then the direction is -1
    //A contour lies inside another one if the pixel values in the direction of the normal is 1
    m_NegativeNormalCounter = 0;
    m_PositiveNormalCounter = 0;
    vtkIdType offSet (0);

    //Iterating over each polygon
    for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);)
    {
      if(cellSize < 3)continue;

      //First we calculate the current polygon's normal
      double polygonNormal[3] = {0.0};

      double p1[3];
      double p2[3];

      double v1[3];
      double v2[3];

      existingPoints->GetPoint(cell[0], p1);
      unsigned int index = cellSize*0.5;
      existingPoints->GetPoint(cell[index], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      for (vtkIdType k = 2; k < cellSize; k++)
      {
        index = cellSize*0.25;
        existingPoints->GetPoint(cell[index], p1);
        index = cellSize*0.75;
        existingPoints->GetPoint(cell[index], p2);

        v2[0] = p2[0]-p1[0];
        v2[1] = p2[1]-p1[1];
        v2[2] = p2[2]-p1[2];

        vtkMath::Cross(v1,v2,polygonNormal);
        if (vtkMath::Norm(polygonNormal) != 0)
          break;
      }

      vtkMath::Normalize(polygonNormal);

      //Now we start computing the normal for each vertex

      double vertexNormalTemp[3];
      existingPoints->GetPoint(cell[0], p1);
      existingPoints->GetPoint(cell[1], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      vtkMath::Cross(v1,polygonNormal,vertexNormalTemp);

      vtkMath::Normalize(vertexNormalTemp);

      double vertexNormal[3];

      for (vtkIdType j = 0; j < cellSize-2; j++)
      {
        existingPoints->GetPoint(cell[j+1], p1);
        existingPoints->GetPoint(cell[j+2], p2);

        v1[0] = p2[0]-p1[0];
        v1[1] = p2[1]-p1[1];
        v1[2] = p2[2]-p1[2];

        vtkMath::Cross(v1,polygonNormal,vertexNormal);

        vtkMath::Normalize(vertexNormal);

        double finalNormal[3];

        finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5;
        finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5;
        finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5;
        vtkMath::Normalize(finalNormal);

        //Here we determine the direction of the normal
        if (m_SegmentationBinaryImage)
        {
          Point3D worldCoord;
          worldCoord[0] = p1[0]+finalNormal[0]*m_MaxSpacing;
          worldCoord[1] = p1[1]+finalNormal[1]*m_MaxSpacing;
          worldCoord[2] = p1[2]+finalNormal[2]*m_MaxSpacing;

          double val = 0.0;

          itk::Index<3> idx;
          m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx);
          try
          {
            if (m_SegmentationBinaryImage->GetPixelType().GetPixelType() == itk::ImageIOBase::UCHAR)
            {
              mitk::ImagePixelReadAccessor<unsigned char> readAccess(m_SegmentationBinaryImage);
              val = readAccess.GetPixelByIndexSafe(idx);
            }
            else if (m_SegmentationBinaryImage->GetPixelType().GetPixelType() == itk::ImageIOBase::USHORT)
            {
              mitk::ImagePixelReadAccessor<unsigned short> readAccess(m_SegmentationBinaryImage);
              val = readAccess.GetPixelByIndexSafe(idx);
            }
          }
          catch (mitk::Exception e)
          {
            // If value is outside the image's region ignore it
            MITK_WARN<<e.what();
          }

          if (val == 0.0)
          {
              //MITK_INFO << "val equals zero.";
              ++m_PositiveNormalCounter;
          }
          else
          {
            //MITK_INFO << "val does not equal zero.";
              ++m_NegativeNormalCounter;
          }
        }

        vertexNormalTemp[0] = vertexNormal[0];
        vertexNormalTemp[1] = vertexNormal[1];
        vertexNormalTemp[2] = vertexNormal[2];

        vtkIdType id = cell[j+1];
        normals->SetTuple(id,finalNormal);
      }

      existingPoints->GetPoint(cell[0], p1);
      existingPoints->GetPoint(cell[1], p2);

      v1[0] = p2[0]-p1[0];
      v1[1] = p2[1]-p1[1];
      v1[2] = p2[2]-p1[2];

      vtkMath::Cross(v1,polygonNormal,vertexNormal);

      vtkMath::Normalize(vertexNormal);

      vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5;
      vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5;
      vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5;
      vtkMath::Normalize(vertexNormal);

      vtkIdType id = cell[0];
      normals->SetTuple(id,vertexNormal);
      id = cell[cellSize-1];
      normals->SetTuple(id,vertexNormal);

      if(m_NegativeNormalCounter > m_PositiveNormalCounter)
      {
          for(vtkIdType n = 0; n < cellSize; n++)
          {
              double normal[3];
              normals->GetTuple(offSet+n, normal);
              normal[0] = (-1)*normal[0];
              normal[1] = (-1)*normal[1];
              normal[2] = (-1)*normal[2];
              normals->SetTuple(offSet+n, normal);
          }
      }

      m_NegativeNormalCounter = 0;
      m_PositiveNormalCounter = 0;
      offSet += cellSize;

    }//end for all cells

    Surface::Pointer surface = this->GetOutput(i);
    surface->GetVtkPolyData()->GetCellData()->SetNormals(normals);
  }//end for all inputs

  //Setting progressbar
  if (this->m_UseProgressBar)
    mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize);
}

mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface()
{
  //Just for debugging:
  vtkSmartPointer<vtkPolyData> newPolyData = vtkSmartPointer<vtkPolyData>::New();
  vtkSmartPointer<vtkCellArray> newLines = vtkSmartPointer<vtkCellArray>::New();
  vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
  unsigned int idCounter (0);
  //Debug end

  for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++)
  {
    Surface* currentSurface = const_cast<Surface*>( this->GetOutput(i) );
    vtkPolyData* polyData = currentSurface->GetVtkPolyData();

    vtkSmartPointer<vtkDoubleArray> currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals());

    vtkSmartPointer<vtkCellArray> existingPolys = polyData->GetPolys();

    vtkSmartPointer<vtkPoints> existingPoints = polyData->GetPoints();

    existingPolys->InitTraversal();

    vtkIdType* cell (NULL);
    vtkIdType cellSize (0);

    for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);)
    {
      for ( vtkIdType j = 0; j < cellSize; j++ )
      {
        double currentNormal[3];
        currentCellNormals->GetTuple(cell[j], currentNormal);
        vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
        line->GetPointIds()->SetNumberOfIds(2);
        double newPoint[3];
        double p0[3];
        existingPoints->GetPoint(cell[j], p0);
        newPoint[0] = p0[0] + currentNormal[0];
        newPoint[1] = p0[1] + currentNormal[1];
        newPoint[2] = p0[2] + currentNormal[2];

        line->GetPointIds()->SetId(0, idCounter);
        newPoints->InsertPoint(idCounter, p0);
        idCounter++;

        line->GetPointIds()->SetId(1, idCounter);
        newPoints->InsertPoint(idCounter, newPoint);
        idCounter++;

        newLines->InsertNextCell(line);
      }//end for all points
    }//end for all cells
  }//end for all outputs

  newPolyData->SetPoints(newPoints);
  newPolyData->SetLines(newLines);
  newPolyData->BuildCells();

  mitk::Surface::Pointer surface = mitk::Surface::New();
  surface->SetVtkPolyData(newPolyData);

  return surface;

}

void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing)
{
    m_MaxSpacing = maxSpacing;
}

void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation()
{
  Superclass::GenerateOutputInformation();
}

void mitk::ComputeContourSetNormalsFilter::Reset()
{
  for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++)
  {
    this->PopBackInput();
  }
  this->SetNumberOfIndexedInputs(0);
  this->SetNumberOfIndexedOutputs(0);

  mitk::Surface::Pointer output = mitk::Surface::New();
  this->SetNthOutput(0, output.GetPointer());
}

void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status)
{
  this->m_UseProgressBar = status;
}

void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize)
{
  this->m_ProgressStepSize = stepSize;
}
<|endoftext|>


<commit_before>/**
 * @file lldrawpoolwlsky.cpp
 * @brief LLDrawPoolWLSky class implementation
 *
 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lldrawpoolwlsky.h"

#include "llerror.h"
#include "llgl.h"
#include "pipeline.h"
#include "llviewercamera.h"
#include "llimage.h"
#include "llwlparammanager.h"
#include "llviewershadermgr.h"
#include "llglslshader.h"
#include "llsky.h"
#include "llvowlsky.h"
#include "llviewerregion.h"
#include "llface.h"
#include "llrender.h"

LLPointer<LLViewerTexture> LLDrawPoolWLSky::sCloudNoiseTexture = NULL;

LLPointer<LLImageRaw> LLDrawPoolWLSky::sCloudNoiseRawImage = NULL;

static LLGLSLShader* cloud_shader = NULL;
static LLGLSLShader* sky_shader = NULL;

LLDrawPoolWLSky::LLDrawPoolWLSky(void) :
	LLDrawPool(POOL_WL_SKY)
{
	const std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", "clouds2.tga"));
	llinfos << "loading WindLight cloud noise from " << cloudNoiseFilename << llendl;

	LLPointer<LLImageFormatted> cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename));

	if(cloudNoiseFile.isNull()) {
		llerrs << "Error: Failed to load cloud noise image " << cloudNoiseFilename << llendl;
	}

	if(cloudNoiseFile->load(cloudNoiseFilename))
	{
		sCloudNoiseRawImage = new LLImageRaw();

		if(cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f))
		{
			//debug use
			llinfos << "cloud noise raw image width: " << sCloudNoiseRawImage->getWidth() << " : height: " << sCloudNoiseRawImage->getHeight() << " : components: " <<
				(S32)sCloudNoiseRawImage->getComponents() << " : data size: " << sCloudNoiseRawImage->getDataSize() << llendl ;
			llassert_always(sCloudNoiseRawImage->getData()) ;

			sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
		}
		else
		{
			sCloudNoiseRawImage = NULL ;
		}
	}

	LLWLParamManager::getInstance()->propagateParameters();
}

LLDrawPoolWLSky::~LLDrawPoolWLSky()
{
	//llinfos << "destructing wlsky draw pool." << llendl;
	sCloudNoiseTexture = NULL;
	sCloudNoiseRawImage = NULL;
}

LLViewerTexture *LLDrawPoolWLSky::getDebugTexture()
{
	return NULL;
}

void LLDrawPoolWLSky::beginRenderPass( S32 pass )
{
	sky_shader =
		LLPipeline::sUnderWaterRender ?
			&gObjectSimpleWaterProgram :
			&gWLSkyProgram;

	cloud_shader =
			LLPipeline::sUnderWaterRender ?
				&gObjectSimpleWaterProgram :
				&gWLCloudProgram;
}

void LLDrawPoolWLSky::endRenderPass( S32 pass )
{
}

void LLDrawPoolWLSky::beginDeferredPass(S32 pass)
{
	sky_shader = &gDeferredWLSkyProgram;
	cloud_shader = &gDeferredWLCloudProgram;
}

void LLDrawPoolWLSky::endDeferredPass(S32 pass)
{

}

void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) const
{
	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();

	llassert_always(NULL != shader);

	glPushMatrix();

	//chop off translation
	if (LLPipeline::sReflectionRender && origin.mV[2] > 256.f)
	{
		glTranslatef(origin.mV[0], origin.mV[1], 256.f-origin.mV[2]*0.5f);
	}
	else
	{
		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
	}

	// the windlight sky dome works most conveniently in a coordinate system
	// where Y is up, so permute our basis vectors accordingly.
	glRotatef(120.f, 1.f / F_SQRT3, 1.f / F_SQRT3, 1.f / F_SQRT3);

	glScalef(0.333f, 0.333f, 0.333f);

	glTranslatef(0.f,-camHeightLocal, 0.f);

	// Draw WL Sky
	shader->uniform3f("camPosLocal", 0.f, camHeightLocal, 0.f);

	gSky.mVOWLSkyp->drawDome();

	glPopMatrix();
}

void LLDrawPoolWLSky::renderSkyHaze(F32 camHeightLocal) const
{
	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		LLGLDisable blend(GL_BLEND);

		sky_shader->bind();

		/// Render the skydome
		renderDome(camHeightLocal, sky_shader);

		sky_shader->unbind();
	}
}

void LLDrawPoolWLSky::renderStars(void) const
{
	LLGLSPipelineSkyBox gls_sky;
	LLGLEnable blend(GL_BLEND);
	gGL.setSceneBlendType(LLRender::BT_ALPHA);

	// *NOTE: have to have bound the cloud noise texture already since register
	// combiners blending below requires something to be bound
	// and we might as well only bind once.
	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	gPipeline.disableLights();

	// *NOTE: we divide by two here and GL_ALPHA_SCALE by two below to avoid
	// clamping and allow the star_alpha param to brighten the stars.
	bool error;
	LLColor4 star_alpha(LLColor4::black);
	star_alpha.mV[3] = LLWLParamManager::getInstance()->mCurParams.getFloat("star_brightness", error) / 2.f;
	llassert_always(!error);

	gGL.getTexUnit(0)->bind(gSky.mVOSkyp->getBloomTex());

	gGL.pushMatrix();
	glRotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f);
	// gl_FragColor.rgb = gl_Color.rgb;
	// gl_FragColor.a = gl_Color.a * star_alpha.a;
	if (LLGLSLShader::sNoFixedFunction)
	{
		gCustomAlphaProgram.bind();
		gCustomAlphaProgram.uniform1f("custom_alpha", star_alpha.mV[3]);
	}
	else
	{
		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT_X2, LLTexUnit::TBS_CONST_ALPHA, LLTexUnit::TBS_TEX_ALPHA);
		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV);
	}

	gSky.mVOWLSkyp->drawStars();

	gGL.popMatrix();

	if (LLGLSLShader::sNoFixedFunction)
	{
		gCustomAlphaProgram.unbind();
	}
	else
	{
		// and disable the combiner states
		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
	}
}

void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const
{
	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && sCloudNoiseTexture.notNull())
	{
		LLGLEnable blend(GL_BLEND);
		gGL.setSceneBlendType(LLRender::BT_ALPHA);
		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);

		gGL.getTexUnit(0)->bind(sCloudNoiseTexture);

		cloud_shader->bind();

		/// Render the skydome
		renderDome(camHeightLocal, cloud_shader);

		cloud_shader->unbind();
	}
}

void LLDrawPoolWLSky::renderHeavenlyBodies()
{
	LLGLSPipelineSkyBox gls_skybox;
	LLGLEnable blend_on(GL_BLEND);
	gPipeline.disableLights();

#if 0 // when we want to re-add a texture sun disc, here's where to do it.
	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN];
	if (gSky.mVOSkyp->getSun().getDraw() && face->getGeomCount())
	{
		LLViewerTexture * tex  = face->getTexture();
		gGL.getTexUnit(0)->bind(tex);
		LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor());
		LLFacePool::LLOverrideFaceColor color_override(this, color);
		face->renderIndexed();
	}
#endif

	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON];

	if (gSky.mVOSkyp->getMoon().getDraw() && face->getGeomCount())
	{
		if (gPipeline.canUseVertexShaders())
		{
			gUIProgram.bind();
		}
		// *NOTE: even though we already bound this texture above for the
		// stars register combiners, we bind again here for defensive reasons,
		// since LLImageGL::bind detects that it's a noop, and optimizes it out.
		gGL.getTexUnit(0)->bind(face->getTexture());
		LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor());
		F32 a = gSky.mVOSkyp->getMoon().getDirection().mV[2];
		if (a > 0.f)
		{
			a = a*a*4.f;
		}

		color.mV[3] = llclamp(a, 0.f, 1.f);

		LLFacePool::LLOverrideFaceColor color_override(this, color);
		face->renderIndexed();

		if (gPipeline.canUseVertexShaders())
		{
			gUIProgram.unbind();
		}
	}
}

void LLDrawPoolWLSky::renderDeferred(S32 pass)
{
	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		return;
	}
	LLFastTimer ftm(FTM_RENDER_WL_SKY);

	const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();

	LLGLSNoFog disableFog;
	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
	LLGLDisable clip(GL_CLIP_PLANE0);

	gGL.setColorMask(true, false);

	LLGLSquashToFarClip far_clip(glh_get_current_projection());

	renderSkyHaze(camHeightLocal);

	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
	glPushMatrix();

		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);

		gDeferredStarProgram.bind();
		// *NOTE: have to bind a texture here since register combiners blending in
		// renderStars() requires something to be bound and we might as well only
		// bind the moon's texture once.
		gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture());

		renderHeavenlyBodies();

		renderStars();

		gDeferredStarProgram.unbind();

	glPopMatrix();

	renderSkyClouds(camHeightLocal);

	gGL.setColorMask(true, true);
	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);

}

void LLDrawPoolWLSky::render(S32 pass)
{
	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		return;
	}
	LLFastTimer ftm(FTM_RENDER_WL_SKY);

	const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();

	LLGLSNoFog disableFog;
	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
	LLGLDisable clip(GL_CLIP_PLANE0);

	LLGLSquashToFarClip far_clip(glh_get_current_projection());

	renderSkyHaze(camHeightLocal);

	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
	glPushMatrix();

		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);

		// *NOTE: have to bind a texture here since register combiners blending in
		// renderStars() requires something to be bound and we might as well only
		// bind the moon's texture once.
		gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture());

		renderHeavenlyBodies();

		renderStars();

	glPopMatrix();

	renderSkyClouds(camHeightLocal);

	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}

void LLDrawPoolWLSky::prerender()
{
	//llinfos << "wlsky prerendering pass." << llendl;
}

LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool()
{
	return new LLDrawPoolWLSky();
}

LLViewerTexture* LLDrawPoolWLSky::getTexture()
{
	return NULL;
}

void LLDrawPoolWLSky::resetDrawOrders()
{
}

//static
void LLDrawPoolWLSky::cleanupGL()
{
	sCloudNoiseTexture = NULL;
}

//static
void LLDrawPoolWLSky::restoreGL()
{
	if(sCloudNoiseRawImage.notNull())
	{
		sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
	}
}
<commit_msg>a trivial change: use lldebugs to replace llinfos for STORM-1417.<commit_after>/**
 * @file lldrawpoolwlsky.cpp
 * @brief LLDrawPoolWLSky class implementation
 *
 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lldrawpoolwlsky.h"

#include "llerror.h"
#include "llgl.h"
#include "pipeline.h"
#include "llviewercamera.h"
#include "llimage.h"
#include "llwlparammanager.h"
#include "llviewershadermgr.h"
#include "llglslshader.h"
#include "llsky.h"
#include "llvowlsky.h"
#include "llviewerregion.h"
#include "llface.h"
#include "llrender.h"

LLPointer<LLViewerTexture> LLDrawPoolWLSky::sCloudNoiseTexture = NULL;

LLPointer<LLImageRaw> LLDrawPoolWLSky::sCloudNoiseRawImage = NULL;

static LLGLSLShader* cloud_shader = NULL;
static LLGLSLShader* sky_shader = NULL;

LLDrawPoolWLSky::LLDrawPoolWLSky(void) :
	LLDrawPool(POOL_WL_SKY)
{
	const std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", "clouds2.tga"));
	llinfos << "loading WindLight cloud noise from " << cloudNoiseFilename << llendl;

	LLPointer<LLImageFormatted> cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename));

	if(cloudNoiseFile.isNull()) {
		llerrs << "Error: Failed to load cloud noise image " << cloudNoiseFilename << llendl;
	}

	if(cloudNoiseFile->load(cloudNoiseFilename))
	{
		sCloudNoiseRawImage = new LLImageRaw();

		if(cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f))
		{
			//debug use
			lldebugs << "cloud noise raw image width: " << sCloudNoiseRawImage->getWidth() << " : height: " << sCloudNoiseRawImage->getHeight() << " : components: " <<
				(S32)sCloudNoiseRawImage->getComponents() << " : data size: " << sCloudNoiseRawImage->getDataSize() << llendl ;
			llassert_always(sCloudNoiseRawImage->getData()) ;

			sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
		}
		else
		{
			sCloudNoiseRawImage = NULL ;
		}
	}

	LLWLParamManager::getInstance()->propagateParameters();
}

LLDrawPoolWLSky::~LLDrawPoolWLSky()
{
	//llinfos << "destructing wlsky draw pool." << llendl;
	sCloudNoiseTexture = NULL;
	sCloudNoiseRawImage = NULL;
}

LLViewerTexture *LLDrawPoolWLSky::getDebugTexture()
{
	return NULL;
}

void LLDrawPoolWLSky::beginRenderPass( S32 pass )
{
	sky_shader =
		LLPipeline::sUnderWaterRender ?
			&gObjectSimpleWaterProgram :
			&gWLSkyProgram;

	cloud_shader =
			LLPipeline::sUnderWaterRender ?
				&gObjectSimpleWaterProgram :
				&gWLCloudProgram;
}

void LLDrawPoolWLSky::endRenderPass( S32 pass )
{
}

void LLDrawPoolWLSky::beginDeferredPass(S32 pass)
{
	sky_shader = &gDeferredWLSkyProgram;
	cloud_shader = &gDeferredWLCloudProgram;
}

void LLDrawPoolWLSky::endDeferredPass(S32 pass)
{

}

void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) const
{
	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();

	llassert_always(NULL != shader);

	glPushMatrix();

	//chop off translation
	if (LLPipeline::sReflectionRender && origin.mV[2] > 256.f)
	{
		glTranslatef(origin.mV[0], origin.mV[1], 256.f-origin.mV[2]*0.5f);
	}
	else
	{
		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
	}

	// the windlight sky dome works most conveniently in a coordinate system
	// where Y is up, so permute our basis vectors accordingly.
	glRotatef(120.f, 1.f / F_SQRT3, 1.f / F_SQRT3, 1.f / F_SQRT3);

	glScalef(0.333f, 0.333f, 0.333f);

	glTranslatef(0.f,-camHeightLocal, 0.f);

	// Draw WL Sky
	shader->uniform3f("camPosLocal", 0.f, camHeightLocal, 0.f);

	gSky.mVOWLSkyp->drawDome();

	glPopMatrix();
}

void LLDrawPoolWLSky::renderSkyHaze(F32 camHeightLocal) const
{
	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		LLGLDisable blend(GL_BLEND);

		sky_shader->bind();

		/// Render the skydome
		renderDome(camHeightLocal, sky_shader);

		sky_shader->unbind();
	}
}

void LLDrawPoolWLSky::renderStars(void) const
{
	LLGLSPipelineSkyBox gls_sky;
	LLGLEnable blend(GL_BLEND);
	gGL.setSceneBlendType(LLRender::BT_ALPHA);

	// *NOTE: have to have bound the cloud noise texture already since register
	// combiners blending below requires something to be bound
	// and we might as well only bind once.
	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	gPipeline.disableLights();

	// *NOTE: we divide by two here and GL_ALPHA_SCALE by two below to avoid
	// clamping and allow the star_alpha param to brighten the stars.
	bool error;
	LLColor4 star_alpha(LLColor4::black);
	star_alpha.mV[3] = LLWLParamManager::getInstance()->mCurParams.getFloat("star_brightness", error) / 2.f;
	llassert_always(!error);

	gGL.getTexUnit(0)->bind(gSky.mVOSkyp->getBloomTex());

	gGL.pushMatrix();
	glRotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f);
	// gl_FragColor.rgb = gl_Color.rgb;
	// gl_FragColor.a = gl_Color.a * star_alpha.a;
	if (LLGLSLShader::sNoFixedFunction)
	{
		gCustomAlphaProgram.bind();
		gCustomAlphaProgram.uniform1f("custom_alpha", star_alpha.mV[3]);
	}
	else
	{
		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR);
		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT_X2, LLTexUnit::TBS_CONST_ALPHA, LLTexUnit::TBS_TEX_ALPHA);
		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV);
	}

	gSky.mVOWLSkyp->drawStars();

	gGL.popMatrix();

	if (LLGLSLShader::sNoFixedFunction)
	{
		gCustomAlphaProgram.unbind();
	}
	else
	{
		// and disable the combiner states
		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
	}
}

void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const
{
	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && sCloudNoiseTexture.notNull())
	{
		LLGLEnable blend(GL_BLEND);
		gGL.setSceneBlendType(LLRender::BT_ALPHA);
		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);

		gGL.getTexUnit(0)->bind(sCloudNoiseTexture);

		cloud_shader->bind();

		/// Render the skydome
		renderDome(camHeightLocal, cloud_shader);

		cloud_shader->unbind();
	}
}

void LLDrawPoolWLSky::renderHeavenlyBodies()
{
	LLGLSPipelineSkyBox gls_skybox;
	LLGLEnable blend_on(GL_BLEND);
	gPipeline.disableLights();

#if 0 // when we want to re-add a texture sun disc, here's where to do it.
	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN];
	if (gSky.mVOSkyp->getSun().getDraw() && face->getGeomCount())
	{
		LLViewerTexture * tex  = face->getTexture();
		gGL.getTexUnit(0)->bind(tex);
		LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor());
		LLFacePool::LLOverrideFaceColor color_override(this, color);
		face->renderIndexed();
	}
#endif

	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON];

	if (gSky.mVOSkyp->getMoon().getDraw() && face->getGeomCount())
	{
		if (gPipeline.canUseVertexShaders())
		{
			gUIProgram.bind();
		}
		// *NOTE: even though we already bound this texture above for the
		// stars register combiners, we bind again here for defensive reasons,
		// since LLImageGL::bind detects that it's a noop, and optimizes it out.
		gGL.getTexUnit(0)->bind(face->getTexture());
		LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor());
		F32 a = gSky.mVOSkyp->getMoon().getDirection().mV[2];
		if (a > 0.f)
		{
			a = a*a*4.f;
		}

		color.mV[3] = llclamp(a, 0.f, 1.f);

		LLFacePool::LLOverrideFaceColor color_override(this, color);
		face->renderIndexed();

		if (gPipeline.canUseVertexShaders())
		{
			gUIProgram.unbind();
		}
	}
}

void LLDrawPoolWLSky::renderDeferred(S32 pass)
{
	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		return;
	}
	LLFastTimer ftm(FTM_RENDER_WL_SKY);

	const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();

	LLGLSNoFog disableFog;
	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
	LLGLDisable clip(GL_CLIP_PLANE0);

	gGL.setColorMask(true, false);

	LLGLSquashToFarClip far_clip(glh_get_current_projection());

	renderSkyHaze(camHeightLocal);

	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
	glPushMatrix();

		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);

		gDeferredStarProgram.bind();
		// *NOTE: have to bind a texture here since register combiners blending in
		// renderStars() requires something to be bound and we might as well only
		// bind the moon's texture once.
		gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture());

		renderHeavenlyBodies();

		renderStars();

		gDeferredStarProgram.unbind();

	glPopMatrix();

	renderSkyClouds(camHeightLocal);

	gGL.setColorMask(true, true);
	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);

}

void LLDrawPoolWLSky::render(S32 pass)
{
	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
	{
		return;
	}
	LLFastTimer ftm(FTM_RENDER_WL_SKY);

	const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();

	LLGLSNoFog disableFog;
	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
	LLGLDisable clip(GL_CLIP_PLANE0);

	LLGLSquashToFarClip far_clip(glh_get_current_projection());

	renderSkyHaze(camHeightLocal);

	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
	glPushMatrix();

		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);

		// *NOTE: have to bind a texture here since register combiners blending in
		// renderStars() requires something to be bound and we might as well only
		// bind the moon's texture once.
		gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture());

		renderHeavenlyBodies();

		renderStars();

	glPopMatrix();

	renderSkyClouds(camHeightLocal);

	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}

void LLDrawPoolWLSky::prerender()
{
	//llinfos << "wlsky prerendering pass." << llendl;
}

LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool()
{
	return new LLDrawPoolWLSky();
}

LLViewerTexture* LLDrawPoolWLSky::getTexture()
{
	return NULL;
}

void LLDrawPoolWLSky::resetDrawOrders()
{
}

//static
void LLDrawPoolWLSky::cleanupGL()
{
	sCloudNoiseTexture = NULL;
}

//static
void LLDrawPoolWLSky::restoreGL()
{
	if(sCloudNoiseRawImage.notNull())
	{
		sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
	}
}
<|endoftext|>