<commit_before>/* -*- c-basic-offset: 2 -*- */
/*
  Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>

  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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "mrn_query_parser.hpp"

#include <mrn_variables.hpp>

extern "C" {
  /* Groonga's internal functions */
  int grn_atoi(const char *nptr, const char *end, const char **rest);
  uint grn_atoui(const char *nptr, const char *end, const char **rest);
}

#define MRN_CLASS_NAME "mrn::QueryParser"

namespace mrn {
  QueryParser::QueryParser(grn_ctx *ctx,
                           THD *thd,
                           grn_obj *expression,
                           grn_obj *default_column,
                           uint n_sections,
                           grn_obj *match_columns)
    : ctx_(ctx),
      thd_(thd),
      expression_(expression),
      default_column_(default_column),
      n_sections_(n_sections),
      match_columns_(match_columns) {
  }

  QueryParser::~QueryParser() {
  }

  grn_rc QueryParser::parse(const char *query, size_t query_length) {
    MRN_DBUG_ENTER_METHOD();

    const char *raw_query = NULL;
    size_t raw_query_length = 0;
    grn_operator default_operator = GRN_OP_OR;
    grn_expr_flags expression_flags = 0;
    parse_pragma(query,
                 query_length,
                 &raw_query,
                 &raw_query_length,
                 &default_operator,
                 &expression_flags);

    grn_obj *default_column = default_column_;
    if (match_columns_) {
      default_column = match_columns_;
    }
    grn_rc rc = grn_expr_parse(ctx_,
                               expression_,
                               raw_query,
                               raw_query_length,
                               default_column,
                               GRN_OP_MATCH,
                               default_operator,
                               expression_flags);
    if (rc != GRN_SUCCESS) {
      char error_message[MRN_MESSAGE_BUFFER_SIZE];
      snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
               "failed to parse fulltext search keyword: <%.*s>: <%s>",
               static_cast<int>(query_length),
               query,
               ctx_->errbuf);
      variables::ActionOnError action =
        variables::get_action_on_fulltext_query_error(thd_);
      switch (action) {
      case variables::ACTION_ON_ERROR_ERROR:
        my_message(ER_PARSE_ERROR, error_message, MYF(0));
        break;
      case variables::ACTION_ON_ERROR_ERROR_AND_LOG:
        my_message(ER_PARSE_ERROR, error_message, MYF(0));
        GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
        break;
      case variables::ACTION_ON_ERROR_IGNORE:
        break;
      case variables::ACTION_ON_ERROR_IGNORE_AND_LOG:
        GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
        break;
      }
    }

    DBUG_RETURN(rc);
  }

  void QueryParser::parse_pragma(const char *query,
                                 size_t query_length,
                                 const char **raw_query,
                                 size_t *raw_query_length,
                                 grn_operator *default_operator,
                                 grn_expr_flags *flags) {
    MRN_DBUG_ENTER_METHOD();

    const char *current_query = query;
    size_t current_query_length = query_length;

    *default_operator = GRN_OP_OR;

    if (current_query_length >= 4 && memcmp(current_query, "*SS ", 4) == 0) {
      *raw_query = current_query + 4;
      *raw_query_length = current_query_length - 4;
      *flags = GRN_EXPR_SYNTAX_SCRIPT;
      DBUG_VOID_RETURN;
    }

    bool weight_specified = false;
    *raw_query = query;
    *raw_query_length = query_length;
    *flags = default_expression_flags();
    if (current_query_length >= 2 && current_query[0] == '*') {
      bool parsed = false;
      bool done = false;
      current_query++;
      current_query_length--;
      while (!done) {
        size_t consumed_query_length = 0;
        switch (current_query[0]) {
        case 'D':
          if (parse_pragma_d(current_query + 1,
                             current_query_length - 1,
                             default_operator,
                             &consumed_query_length)) {
            parsed = true;
            consumed_query_length += 1;
            current_query += consumed_query_length;
            current_query_length -= consumed_query_length;
          } else {
            done = true;
          }
          break;
        case 'W':
          if (parse_pragma_w(current_query + 1,
                             current_query_length - 1,
                             &consumed_query_length)) {
            parsed = true;
            weight_specified = true;
            consumed_query_length += 1;
            current_query += consumed_query_length;
            current_query_length -= consumed_query_length;
          } else {
            done = true;
          }
          break;
        default:
          done = true;
          break;
        }
      }
      if (parsed) {
        *raw_query = current_query;
        *raw_query_length = current_query_length;
      }
    }

    // WORKAROUND: ignore the first '+' to support "+apple macintosh" pattern.
    while (*raw_query_length > 0 && (*raw_query)[0] == ' ') {
      (*raw_query)++;
      (*raw_query_length)--;
    }
    if (*raw_query_length > 0 && (*raw_query)[0] == '+') {
      (*raw_query)++;
      (*raw_query_length)--;
    }
    if (!weight_specified && match_columns_) {
      grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
    }

    DBUG_VOID_RETURN;
  }

  bool QueryParser::parse_pragma_w(const char *query,
                                   size_t query_length,
                                   size_t *consumed_query_length) {
    MRN_DBUG_ENTER_METHOD();

    *consumed_query_length = 0;

    grn_obj section_value_buffer;
    GRN_UINT32_INIT(&section_value_buffer, 0);

    MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(bool, specified_sections, n_sections_);
    for (uint i = 0; i < n_sections_; ++i) {
      specified_sections[i] = false;
    }

    uint n_weights = 0;
    while (query_length >= 1) {
      if (n_weights >= 1) {
        if (query[0] != ',') {
          break;
        }
        size_t n_used_query_length = 1;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
        if (query_length == 0) {
          break;
        }
      }

      uint section = 0;
      if ('1' <= query[0] && query[0] <= '9') {
        const char *section_start = query;
        const char *query_end = query + query_length;
        const char *query_rest;
        section = grn_atoui(section_start, query_end, &query_rest);
        if (section_start == query_rest) {
          break;
        }
        if (!(0 < section && section <= n_sections_)) {
          break;
        }
        section -= 1;
        specified_sections[section] = true;
        size_t n_used_query_length = query_rest - query;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
      } else {
        break;
      }

      int weight = 1;
      if (query_length >= 2 && query[0] == ':') {
        const char *weight_start = query + 1;
        const char *query_end = query + query_length;
        const char *query_rest;
        weight = grn_atoi(weight_start, query_end, &query_rest);
        if (weight_start == query_rest) {
          break;
        }
        size_t n_used_query_length = query_rest - query;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
      }

      n_weights++;

      append_section(section,
                     &section_value_buffer,
                     weight,
                     n_weights);
    }

    for (uint section = 0; section < n_sections_; ++section) {
      if (specified_sections[section]) {
        continue;
      }

      ++n_weights;

      int default_weight = 1;
     append_section(section,
                    &section_value_buffer,
                    default_weight,
                    n_weights);
    }
    MRN_FREE_VARIABLE_LENGTH_ARRAYS(specified_sections);

    GRN_OBJ_FIN(ctx_, &section_value_buffer);

    DBUG_RETURN(n_weights > 0);
  }

  void QueryParser::append_section(uint section,
                                   grn_obj *section_value_buffer,
                                   int weight,
                                   uint n_weights) {
    MRN_DBUG_ENTER_METHOD();

    if (!match_columns_) {
      DBUG_VOID_RETURN;
    }

    grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
    GRN_UINT32_SET(ctx_, section_value_buffer, section);
    grn_expr_append_const(ctx_, match_columns_, section_value_buffer,
                          GRN_OP_PUSH, 1);
    grn_expr_append_op(ctx_, match_columns_, GRN_OP_GET_MEMBER, 2);

    if (weight != 1) {
      grn_expr_append_const_int(ctx_, match_columns_, weight, GRN_OP_PUSH, 1);
      grn_expr_append_op(ctx_, match_columns_, GRN_OP_STAR, 2);
    }

    if (n_weights >= 2) {
      grn_expr_append_op(ctx_, match_columns_, GRN_OP_OR, 2);
    }

    DBUG_VOID_RETURN;
  }

  bool QueryParser::parse_pragma_d(const char *query,
                                   size_t query_length,
                                   grn_operator *default_operator,
                                   size_t *consumed_query_length) {
    MRN_DBUG_ENTER_METHOD();

    bool succeeded = true;
    if (query_length >= 1 && query[0] == '+') {
      *default_operator = GRN_OP_AND;
      *consumed_query_length = 1;
    } else if (query_length >= 1 && query[0] == '-') {
      *default_operator = GRN_OP_AND_NOT;
      *consumed_query_length = 1;
    } else if (query_length >= 2 && memcmp(query, "OR", 2) == 0) {
      *default_operator = GRN_OP_OR;
      *consumed_query_length = 2;
    } else {
      succeeded = false;
    }

    DBUG_RETURN(succeeded);
  }

  grn_expr_flags QueryParser::default_expression_flags() {
    MRN_DBUG_ENTER_METHOD();

    ulonglong syntax_flags = variables::get_boolean_mode_syntax_flags(thd_);
    grn_expr_flags expression_flags = 0;
    if (syntax_flags == variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT) {
      expression_flags = GRN_EXPR_SYNTAX_QUERY | GRN_EXPR_ALLOW_LEADING_NOT;
    } else {
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_SCRIPT) {
        expression_flags |= GRN_EXPR_SYNTAX_SCRIPT;
      } else {
        expression_flags |= GRN_EXPR_SYNTAX_QUERY;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_COLUMN) {
        expression_flags |= GRN_EXPR_ALLOW_COLUMN;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_UPDATE) {
        expression_flags |= GRN_EXPR_ALLOW_UPDATE;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_LEADING_NOT) {
        expression_flags |= GRN_EXPR_ALLOW_LEADING_NOT;
      }
    }

    DBUG_RETURN(expression_flags);
  }
}
<commit_msg>Fix indent<commit_after>/* -*- c-basic-offset: 2 -*- */
/*
  Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>

  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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "mrn_query_parser.hpp"

#include <mrn_variables.hpp>

extern "C" {
  /* Groonga's internal functions */
  int grn_atoi(const char *nptr, const char *end, const char **rest);
  uint grn_atoui(const char *nptr, const char *end, const char **rest);
}

#define MRN_CLASS_NAME "mrn::QueryParser"

namespace mrn {
  QueryParser::QueryParser(grn_ctx *ctx,
                           THD *thd,
                           grn_obj *expression,
                           grn_obj *default_column,
                           uint n_sections,
                           grn_obj *match_columns)
    : ctx_(ctx),
      thd_(thd),
      expression_(expression),
      default_column_(default_column),
      n_sections_(n_sections),
      match_columns_(match_columns) {
  }

  QueryParser::~QueryParser() {
  }

  grn_rc QueryParser::parse(const char *query, size_t query_length) {
    MRN_DBUG_ENTER_METHOD();

    const char *raw_query = NULL;
    size_t raw_query_length = 0;
    grn_operator default_operator = GRN_OP_OR;
    grn_expr_flags expression_flags = 0;
    parse_pragma(query,
                 query_length,
                 &raw_query,
                 &raw_query_length,
                 &default_operator,
                 &expression_flags);

    grn_obj *default_column = default_column_;
    if (match_columns_) {
      default_column = match_columns_;
    }
    grn_rc rc = grn_expr_parse(ctx_,
                               expression_,
                               raw_query,
                               raw_query_length,
                               default_column,
                               GRN_OP_MATCH,
                               default_operator,
                               expression_flags);
    if (rc != GRN_SUCCESS) {
      char error_message[MRN_MESSAGE_BUFFER_SIZE];
      snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
               "failed to parse fulltext search keyword: <%.*s>: <%s>",
               static_cast<int>(query_length),
               query,
               ctx_->errbuf);
      variables::ActionOnError action =
        variables::get_action_on_fulltext_query_error(thd_);
      switch (action) {
      case variables::ACTION_ON_ERROR_ERROR:
        my_message(ER_PARSE_ERROR, error_message, MYF(0));
        break;
      case variables::ACTION_ON_ERROR_ERROR_AND_LOG:
        my_message(ER_PARSE_ERROR, error_message, MYF(0));
        GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
        break;
      case variables::ACTION_ON_ERROR_IGNORE:
        break;
      case variables::ACTION_ON_ERROR_IGNORE_AND_LOG:
        GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
        break;
      }
    }

    DBUG_RETURN(rc);
  }

  void QueryParser::parse_pragma(const char *query,
                                 size_t query_length,
                                 const char **raw_query,
                                 size_t *raw_query_length,
                                 grn_operator *default_operator,
                                 grn_expr_flags *flags) {
    MRN_DBUG_ENTER_METHOD();

    const char *current_query = query;
    size_t current_query_length = query_length;

    *default_operator = GRN_OP_OR;

    if (current_query_length >= 4 && memcmp(current_query, "*SS ", 4) == 0) {
      *raw_query = current_query + 4;
      *raw_query_length = current_query_length - 4;
      *flags = GRN_EXPR_SYNTAX_SCRIPT;
      DBUG_VOID_RETURN;
    }

    bool weight_specified = false;
    *raw_query = query;
    *raw_query_length = query_length;
    *flags = default_expression_flags();
    if (current_query_length >= 2 && current_query[0] == '*') {
      bool parsed = false;
      bool done = false;
      current_query++;
      current_query_length--;
      while (!done) {
        size_t consumed_query_length = 0;
        switch (current_query[0]) {
        case 'D':
          if (parse_pragma_d(current_query + 1,
                             current_query_length - 1,
                             default_operator,
                             &consumed_query_length)) {
            parsed = true;
            consumed_query_length += 1;
            current_query += consumed_query_length;
            current_query_length -= consumed_query_length;
          } else {
            done = true;
          }
          break;
        case 'W':
          if (parse_pragma_w(current_query + 1,
                             current_query_length - 1,
                             &consumed_query_length)) {
            parsed = true;
            weight_specified = true;
            consumed_query_length += 1;
            current_query += consumed_query_length;
            current_query_length -= consumed_query_length;
          } else {
            done = true;
          }
          break;
        default:
          done = true;
          break;
        }
      }
      if (parsed) {
        *raw_query = current_query;
        *raw_query_length = current_query_length;
      }
    }

    // WORKAROUND: ignore the first '+' to support "+apple macintosh" pattern.
    while (*raw_query_length > 0 && (*raw_query)[0] == ' ') {
      (*raw_query)++;
      (*raw_query_length)--;
    }
    if (*raw_query_length > 0 && (*raw_query)[0] == '+') {
      (*raw_query)++;
      (*raw_query_length)--;
    }
    if (!weight_specified && match_columns_) {
      grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
    }

    DBUG_VOID_RETURN;
  }

  bool QueryParser::parse_pragma_w(const char *query,
                                   size_t query_length,
                                   size_t *consumed_query_length) {
    MRN_DBUG_ENTER_METHOD();

    *consumed_query_length = 0;

    grn_obj section_value_buffer;
    GRN_UINT32_INIT(&section_value_buffer, 0);

    MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(bool, specified_sections, n_sections_);
    for (uint i = 0; i < n_sections_; ++i) {
      specified_sections[i] = false;
    }

    uint n_weights = 0;
    while (query_length >= 1) {
      if (n_weights >= 1) {
        if (query[0] != ',') {
          break;
        }
        size_t n_used_query_length = 1;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
        if (query_length == 0) {
          break;
        }
      }

      uint section = 0;
      if ('1' <= query[0] && query[0] <= '9') {
        const char *section_start = query;
        const char *query_end = query + query_length;
        const char *query_rest;
        section = grn_atoui(section_start, query_end, &query_rest);
        if (section_start == query_rest) {
          break;
        }
        if (!(0 < section && section <= n_sections_)) {
          break;
        }
        section -= 1;
        specified_sections[section] = true;
        size_t n_used_query_length = query_rest - query;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
      } else {
        break;
      }

      int weight = 1;
      if (query_length >= 2 && query[0] == ':') {
        const char *weight_start = query + 1;
        const char *query_end = query + query_length;
        const char *query_rest;
        weight = grn_atoi(weight_start, query_end, &query_rest);
        if (weight_start == query_rest) {
          break;
        }
        size_t n_used_query_length = query_rest - query;
        *consumed_query_length += n_used_query_length;
        query_length -= n_used_query_length;
        query += n_used_query_length;
      }

      n_weights++;

      append_section(section,
                     &section_value_buffer,
                     weight,
                     n_weights);
    }

    for (uint section = 0; section < n_sections_; ++section) {
      if (specified_sections[section]) {
        continue;
      }

      ++n_weights;

      int default_weight = 1;
      append_section(section,
                     &section_value_buffer,
                     default_weight,
                     n_weights);
    }
    MRN_FREE_VARIABLE_LENGTH_ARRAYS(specified_sections);

    GRN_OBJ_FIN(ctx_, &section_value_buffer);

    DBUG_RETURN(n_weights > 0);
  }

  void QueryParser::append_section(uint section,
                                   grn_obj *section_value_buffer,
                                   int weight,
                                   uint n_weights) {
    MRN_DBUG_ENTER_METHOD();

    if (!match_columns_) {
      DBUG_VOID_RETURN;
    }

    grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
    GRN_UINT32_SET(ctx_, section_value_buffer, section);
    grn_expr_append_const(ctx_, match_columns_, section_value_buffer,
                          GRN_OP_PUSH, 1);
    grn_expr_append_op(ctx_, match_columns_, GRN_OP_GET_MEMBER, 2);

    if (weight != 1) {
      grn_expr_append_const_int(ctx_, match_columns_, weight, GRN_OP_PUSH, 1);
      grn_expr_append_op(ctx_, match_columns_, GRN_OP_STAR, 2);
    }

    if (n_weights >= 2) {
      grn_expr_append_op(ctx_, match_columns_, GRN_OP_OR, 2);
    }

    DBUG_VOID_RETURN;
  }

  bool QueryParser::parse_pragma_d(const char *query,
                                   size_t query_length,
                                   grn_operator *default_operator,
                                   size_t *consumed_query_length) {
    MRN_DBUG_ENTER_METHOD();

    bool succeeded = true;
    if (query_length >= 1 && query[0] == '+') {
      *default_operator = GRN_OP_AND;
      *consumed_query_length = 1;
    } else if (query_length >= 1 && query[0] == '-') {
      *default_operator = GRN_OP_AND_NOT;
      *consumed_query_length = 1;
    } else if (query_length >= 2 && memcmp(query, "OR", 2) == 0) {
      *default_operator = GRN_OP_OR;
      *consumed_query_length = 2;
    } else {
      succeeded = false;
    }

    DBUG_RETURN(succeeded);
  }

  grn_expr_flags QueryParser::default_expression_flags() {
    MRN_DBUG_ENTER_METHOD();

    ulonglong syntax_flags = variables::get_boolean_mode_syntax_flags(thd_);
    grn_expr_flags expression_flags = 0;
    if (syntax_flags == variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT) {
      expression_flags = GRN_EXPR_SYNTAX_QUERY | GRN_EXPR_ALLOW_LEADING_NOT;
    } else {
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_SCRIPT) {
        expression_flags |= GRN_EXPR_SYNTAX_SCRIPT;
      } else {
        expression_flags |= GRN_EXPR_SYNTAX_QUERY;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_COLUMN) {
        expression_flags |= GRN_EXPR_ALLOW_COLUMN;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_UPDATE) {
        expression_flags |= GRN_EXPR_ALLOW_UPDATE;
      }
      if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_LEADING_NOT) {
        expression_flags |= GRN_EXPR_ALLOW_LEADING_NOT;
      }
    }

    DBUG_RETURN(expression_flags);
  }
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageRegistrationMethodTest_13.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkImageRegistrationMethod.h"
#include "itkAffineTransform.h"
#include "itkMutualInformationImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGradientDescentOptimizer.h"

#include "itkTextOutput.h"
#include "itkImageRegionIterator.h"
#include "itkCommandIterationUpdate.h"

namespace
{

double F( itk::Vector<double,3> & v );
}

/**
 *  This program test one instantiation of the itk::ImageRegistrationMethod class
 *
 *  This file tests the combination of:
 *   - MutualInformation
 *   - AffineTransform
 *   - GradientDescentOptimizer
 *   - LinearInterpolateImageFunction
 *
 *  The test image pattern consists of a 3D gaussian in the middle
 *  with some directional pattern on the outside.
 *  One image is scaled and shifted relative to the other.
 *
 * Notes:
 * =======
 * This example performs an affine registration
 * between a moving (source) and fixed (target) image using mutual information.
 * It uses the optimization method of Viola and Wells to find the
 * best affine transform to register the moving image onto the fixed
 * image.
 *
 * The mutual information value and its derivatives are estimated
 * using spatial sampling. The performance
 * of the registration depends on good choices of the parameters
 * used to estimate the mutual information. Refer to the documentation
 * for MutualInformationImageToImageMetric for details on these
 * parameters and how to set them.
 *
 * The registration uses a simple stochastic gradient ascent scheme. Steps
 * are repeatedly taken that are proportional to the approximate
 * deriviative of the mutual information with respect to the affine
 * transform parameters. The stepsize is governed by the LearningRate
 * parameter.
 *
 * Since the parameters of the linear part is different in magnitude
 * to the parameters in the offset part, scaling is required
 * to improve convergence. The scaling can set via the optimizer.
 *
 * NB: In the Viola and Wells paper, the scaling is specified by
 * using different learning rates for the linear and offset part.
 * The following formula translate their scaling parameters to
 * those used in this framework:
 *
 * LearningRate = lambda_R
 * TranslationScale = sqrt( lambda_T / lambda_R );
 *
 * In the optimizer's scale transform set the scaling for
 * all the translation parameters to TranslationScale^{-2}.
 * Set the scale for all other parameters to 1.0.
 *
 * Note: the optimization performance can be improved by
 * setting the image origin to center of mass of the image.
 *
 * Implementaton of this example and related components are based on:
 * Viola, P. and Wells III, W. (1997).
 * "Alignment by Maximization of Mutual Information"
 * International Journal of Computer Vision, 24(2):137-154
 *
 */
int itkImageRegistrationMethodTest_13(int, char* [] )
{

  itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());

  bool pass = true;

  const unsigned int dimension = 3;
  unsigned int j;

  typedef float  PixelType;

  // Fixed Image Type
  typedef itk::Image<PixelType,dimension>               FixedImageType;

  // Moving Image Type
  typedef itk::Image<PixelType,dimension>               MovingImageType;

  // Transform Type
  typedef itk::AffineTransform< double,dimension >  TransformType;

  // Optimizer Type
  typedef itk::GradientDescentOptimizer             OptimizerType;

  // Metric Type
  typedef itk::MutualInformationImageToImageMetric<
                                    FixedImageType,
                                    MovingImageType >    MetricType;

  // Interpolation technique
  typedef itk:: LinearInterpolateImageFunction<
                                    MovingImageType,
                                    double          >    InterpolatorType;

  // Registration Method
  typedef itk::ImageRegistrationMethod<
                                    FixedImageType,
                                    MovingImageType >    RegistrationType;

  MetricType::Pointer         metric        = MetricType::New();
  TransformType::Pointer      transform     = TransformType::New();
  OptimizerType::Pointer      optimizer     = OptimizerType::New();
  FixedImageType::Pointer     fixedImage    = FixedImageType::New();
  MovingImageType::Pointer    movingImage   = MovingImageType::New();
  InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
  RegistrationType::Pointer   registration  = RegistrationType::New();

  /*********************************************************
   * Set up the two input images.
   * One image scaled and shifted with respect to the other.
   **********************************************************/
  double displacement[dimension] = {7,3,2};
  double scale[dimension] = { 0.80, 1.0, 1.0 };

  FixedImageType::SizeType size = {{100,100,40}};
  FixedImageType::IndexType index = {{0,0,0}};
  FixedImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( index );

  fixedImage->SetLargestPossibleRegion( region );
  fixedImage->SetBufferedRegion( region );
  fixedImage->SetRequestedRegion( region );
  fixedImage->Allocate();

  movingImage->SetLargestPossibleRegion( region );
  movingImage->SetBufferedRegion( region );
  movingImage->SetRequestedRegion( region );
  movingImage->Allocate();

  typedef itk::ImageRegionIterator<MovingImageType> MovingImageIterator;
  typedef itk::ImageRegionIterator<FixedImageType> FixedImageIterator;

  itk::Point<double,dimension> center;
  for ( j = 0; j < dimension; j++ )
    {
    center[j] = 0.5 *  (double)region.GetSize()[j];
    }

  itk::Point<double,dimension> p;
  itk::Vector<double,dimension> d;

  MovingImageIterator mIter( movingImage, region );
  FixedImageIterator  fIter( fixedImage, region );

  while( !mIter.IsAtEnd() )
    {
    for ( j = 0; j < dimension; j++ )
      {
      p[j] = mIter.GetIndex()[j];
      }

    d = p - center;

    fIter.Set( (PixelType) F(d) );

    for ( j = 0; j < dimension; j++ )
      {
      d[j] = d[j] * scale[j] + displacement[j];
      }

    mIter.Set( (PixelType) F(d) );

    ++fIter;
    ++mIter;

    }

  // set the image origin to be center of the image
  double transCenter[dimension];
  for ( j = 0; j < dimension; j++ )
    {
    transCenter[j] = -0.5 * double(size[j]);
    }

  movingImage->SetOrigin( transCenter );
  fixedImage->SetOrigin( transCenter );

  /******************************************************************
   * Set up the optimizer.
   ******************************************************************/

  // set the translation scale
  typedef OptimizerType::ScalesType ScalesType;
  ScalesType parametersScales( transform->GetNumberOfParameters() );

  parametersScales.Fill( 1.0 );

  for ( j = 9; j < 12; j++ )
    {
    parametersScales[j] = 0.0001;
    }

  optimizer->SetScales( parametersScales );

  // need to maximize for mutual information
  optimizer->MaximizeOn();

  /******************************************************************
   * Set up the optimizer observer
   ******************************************************************/
  typedef itk::CommandIterationUpdate< OptimizerType > CommandIterationType;
  CommandIterationType::Pointer iterationCommand =
    CommandIterationType::New();

  iterationCommand->SetOptimizer( optimizer );

  /******************************************************************
   * Set up the metric.
   ******************************************************************/
  metric->SetMovingImageStandardDeviation( 5.0 );
  metric->SetFixedImageStandardDeviation( 5.0 );
  metric->SetNumberOfSpatialSamples( 50 );
  metric->SetFixedImageRegion( fixedImage->GetBufferedRegion() );

  /******************************************************************
   * Set up the registrator.
   ******************************************************************/

  // connect up the components
  registration->SetMetric( metric );
  registration->SetOptimizer( optimizer );
  registration->SetTransform( transform );
  registration->SetFixedImage( fixedImage );
  registration->SetMovingImage( movingImage );
  registration->SetInterpolator( interpolator );

  // set initial parameters to identity
  RegistrationType::ParametersType initialParameters(
    transform->GetNumberOfParameters() );

  initialParameters.Fill( 0.0 );
  initialParameters[0] = 1.0;
  initialParameters[4] = 1.0;
  initialParameters[8] = 1.0;

  /***********************************************************
   * Run the registration - reducing learning rate as we go
   ************************************************************/
  const unsigned int numberOfLoops = 3;
  unsigned int iter[numberOfLoops] = { 300, 300, 350 };
  double      rates[numberOfLoops] = { 1e-3, 5e-4, 1e-4 };

  for ( j = 0; j < numberOfLoops; j++ )
    {

    try
      {
        optimizer->SetNumberOfIterations( iter[j] );
        optimizer->SetLearningRate( rates[j] );
        registration->SetInitialTransformParameters( initialParameters );
        registration->Update();

        initialParameters = registration->GetLastTransformParameters();

      }
    catch( itk::ExceptionObject & e )
      {
      std::cout << "Registration failed" << std::endl;
      std::cout << "Reason " << e.GetDescription() << std::endl;
      return EXIT_FAILURE;
      }

    }

  /***********************************************************
   * Check the results
   ************************************************************/
  RegistrationType::ParametersType solution =
    registration->GetLastTransformParameters();

  std::cout << "Solution is: " << solution << std::endl;

  RegistrationType::ParametersType trueParameters(
    transform->GetNumberOfParameters() );
  trueParameters.Fill( 0.0 );
  trueParameters[ 0] = 1/scale[0];
  trueParameters[ 4] = 1/scale[1];
  trueParameters[ 8] = 1/scale[2];
  trueParameters[ 9] = - displacement[0]/scale[0];
  trueParameters[10] = - displacement[1]/scale[1];
  trueParameters[11] = - displacement[2]/scale[2];

  std::cout << "True solution is: " << trueParameters << std::endl;

  for( j = 0; j < 9; j++ )
    {
    if( vnl_math_abs( solution[j] - trueParameters[j] ) > 0.025 )
      {
      std::cout << "Failed " << j << std::endl;
      pass = false;
      }
    }
  for( j = 9; j < 12; j++ )
    {
    if( vnl_math_abs( solution[j] - trueParameters[j] ) > 1.0 )
      {
      std::cout << "Failed " << j << std::endl;
      pass = false;
      }
    }

  if( !pass )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  /*************************************************
   * Check for parzen window exception
   **************************************************/
  double oldValue = metric->GetMovingImageStandardDeviation();
  metric->SetMovingImageStandardDeviation( 0.005 );

  try
    {
    pass = false;
    registration->Update();
    }
  catch(itk::ExceptionObject& err)
    {
    std::cout << "Caught expected ExceptionObject" << std::endl;
    std::cout << err << std::endl;
    pass = true;
    }

  if( !pass )
    {
    std::cout << "Should have caught an exception" << std::endl;
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  metric->SetMovingImageStandardDeviation( oldValue );

  /*************************************************
   * Check for mapped out of image error
   **************************************************/
  solution[5] = 1000;
  registration->SetInitialTransformParameters( solution );

  try
    {
    pass = false;
    registration->Update();
    }
  catch(itk::ExceptionObject& err)
    {
    std::cout << "Caught expected ExceptionObject" << std::endl;
    std::cout << err << std::endl;
    pass = true;
    }

  if( !pass )
    {
    std::cout << "Should have caught an exception" << std::endl;
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}
namespace
{

/**
 * This function defines the test image pattern.
 * The pattern is a 3D gaussian in the middle
 * and some directional pattern on the outside.
 */
double F( itk::Vector<double,3> & v )
{
  double x = v[0];
  double y = v[1];
  double z = v[2];
  const double s = 50;
  double value = 200.0 * vcl_exp( - ( x*x + y*y + z*z )/(s*s) );
  x -= 8; y += 3; z += 0;
  double r = vcl_sqrt( x*x + y*y + z*z );
  if( r > 35 )
    {
    value = 2 * ( vnl_math_abs( x ) +
      0.8 * vnl_math_abs( y ) +
      0.5 * vnl_math_abs( z ) );
    }
  if( r < 4 )
    {
    value = 400;
    }

  return value;

}
}
<commit_msg>COMP: Adjust parameters to get a portable solution.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageRegistrationMethodTest_13.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkImageRegistrationMethod.h"
#include "itkAffineTransform.h"
#include "itkMutualInformationImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGradientDescentOptimizer.h"

#include "itkTextOutput.h"
#include "itkImageRegionIterator.h"
#include "itkCommandIterationUpdate.h"

namespace
{

double F( itk::Vector<double,3> & v );
}

/**
 *  This program test one instantiation of the itk::ImageRegistrationMethod class
 *
 *  This file tests the combination of:
 *   - MutualInformation
 *   - AffineTransform
 *   - GradientDescentOptimizer
 *   - LinearInterpolateImageFunction
 *
 *  The test image pattern consists of a 3D gaussian in the middle
 *  with some directional pattern on the outside.
 *  One image is scaled and shifted relative to the other.
 *
 * Notes:
 * =======
 * This example performs an affine registration
 * between a moving (source) and fixed (target) image using mutual information.
 * It uses the optimization method of Viola and Wells to find the
 * best affine transform to register the moving image onto the fixed
 * image.
 *
 * The mutual information value and its derivatives are estimated
 * using spatial sampling. The performance
 * of the registration depends on good choices of the parameters
 * used to estimate the mutual information. Refer to the documentation
 * for MutualInformationImageToImageMetric for details on these
 * parameters and how to set them.
 *
 * The registration uses a simple stochastic gradient ascent scheme. Steps
 * are repeatedly taken that are proportional to the approximate
 * deriviative of the mutual information with respect to the affine
 * transform parameters. The stepsize is governed by the LearningRate
 * parameter.
 *
 * Since the parameters of the linear part is different in magnitude
 * to the parameters in the offset part, scaling is required
 * to improve convergence. The scaling can set via the optimizer.
 *
 * NB: In the Viola and Wells paper, the scaling is specified by
 * using different learning rates for the linear and offset part.
 * The following formula translate their scaling parameters to
 * those used in this framework:
 *
 * LearningRate = lambda_R
 * TranslationScale = sqrt( lambda_T / lambda_R );
 *
 * In the optimizer's scale transform set the scaling for
 * all the translation parameters to TranslationScale^{-2}.
 * Set the scale for all other parameters to 1.0.
 *
 * Note: the optimization performance can be improved by
 * setting the image origin to center of mass of the image.
 *
 * Implementaton of this example and related components are based on:
 * Viola, P. and Wells III, W. (1997).
 * "Alignment by Maximization of Mutual Information"
 * International Journal of Computer Vision, 24(2):137-154
 *
 */
int itkImageRegistrationMethodTest_13(int, char* [] )
{

  itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());

  bool pass = true;

  const unsigned int dimension = 3;
  unsigned int j;

  typedef float  PixelType;

  // Fixed Image Type
  typedef itk::Image<PixelType,dimension>               FixedImageType;

  // Moving Image Type
  typedef itk::Image<PixelType,dimension>               MovingImageType;

  // Transform Type
  typedef itk::AffineTransform< double,dimension >  TransformType;

  // Optimizer Type
  typedef itk::GradientDescentOptimizer             OptimizerType;

  // Metric Type
  typedef itk::MutualInformationImageToImageMetric<
                                    FixedImageType,
                                    MovingImageType >    MetricType;

  // Interpolation technique
  typedef itk:: LinearInterpolateImageFunction<
                                    MovingImageType,
                                    double          >    InterpolatorType;

  // Registration Method
  typedef itk::ImageRegistrationMethod<
                                    FixedImageType,
                                    MovingImageType >    RegistrationType;

  MetricType::Pointer         metric        = MetricType::New();
  TransformType::Pointer      transform     = TransformType::New();
  OptimizerType::Pointer      optimizer     = OptimizerType::New();
  FixedImageType::Pointer     fixedImage    = FixedImageType::New();
  MovingImageType::Pointer    movingImage   = MovingImageType::New();
  InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
  RegistrationType::Pointer   registration  = RegistrationType::New();

  /*********************************************************
   * Set up the two input images.
   * One image scaled and shifted with respect to the other.
   **********************************************************/
  double displacement[dimension] = {7,3,2};
  double scale[dimension] = { 0.80, 1.0, 1.0 };

  FixedImageType::SizeType size = {{100,100,40}};
  FixedImageType::IndexType index = {{0,0,0}};
  FixedImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( index );

  fixedImage->SetLargestPossibleRegion( region );
  fixedImage->SetBufferedRegion( region );
  fixedImage->SetRequestedRegion( region );
  fixedImage->Allocate();

  movingImage->SetLargestPossibleRegion( region );
  movingImage->SetBufferedRegion( region );
  movingImage->SetRequestedRegion( region );
  movingImage->Allocate();

  typedef itk::ImageRegionIterator<MovingImageType> MovingImageIterator;
  typedef itk::ImageRegionIterator<FixedImageType> FixedImageIterator;

  itk::Point<double,dimension> center;
  for ( j = 0; j < dimension; j++ )
    {
    center[j] = 0.5 *  (double)region.GetSize()[j];
    }

  itk::Point<double,dimension> p;
  itk::Vector<double,dimension> d;

  MovingImageIterator mIter( movingImage, region );
  FixedImageIterator  fIter( fixedImage, region );

  while( !mIter.IsAtEnd() )
    {
    for ( j = 0; j < dimension; j++ )
      {
      p[j] = mIter.GetIndex()[j];
      }

    d = p - center;

    fIter.Set( (PixelType) F(d) );

    for ( j = 0; j < dimension; j++ )
      {
      d[j] = d[j] * scale[j] + displacement[j];
      }

    mIter.Set( (PixelType) F(d) );

    ++fIter;
    ++mIter;

    }

  // set the image origin to be center of the image
  double transCenter[dimension];
  for ( j = 0; j < dimension; j++ )
    {
    transCenter[j] = -0.5 * double(size[j]);
    }

  movingImage->SetOrigin( transCenter );
  fixedImage->SetOrigin( transCenter );

  /******************************************************************
   * Set up the optimizer.
   ******************************************************************/

  // set the translation scale
  typedef OptimizerType::ScalesType ScalesType;
  ScalesType parametersScales( transform->GetNumberOfParameters() );

  parametersScales.Fill( 1.0 );

  for ( j = 9; j < 12; j++ )
    {
    parametersScales[j] = 0.001;
    }

  optimizer->SetScales( parametersScales );

  // need to maximize for mutual information
  optimizer->MaximizeOn();

  /******************************************************************
   * Set up the optimizer observer
   ******************************************************************/
  typedef itk::CommandIterationUpdate< OptimizerType > CommandIterationType;
  CommandIterationType::Pointer iterationCommand =
    CommandIterationType::New();

  iterationCommand->SetOptimizer( optimizer );

  /******************************************************************
   * Set up the metric.
   ******************************************************************/
  metric->SetMovingImageStandardDeviation( 5.0 );
  metric->SetFixedImageStandardDeviation( 5.0 );
  metric->SetNumberOfSpatialSamples( 100 );
  metric->SetFixedImageRegion( fixedImage->GetBufferedRegion() );

  /******************************************************************
   * Set up the registrator.
   ******************************************************************/

  // connect up the components
  registration->SetMetric( metric );
  registration->SetOptimizer( optimizer );
  registration->SetTransform( transform );
  registration->SetFixedImage( fixedImage );
  registration->SetMovingImage( movingImage );
  registration->SetInterpolator( interpolator );

  // set initial parameters to identity
  RegistrationType::ParametersType initialParameters(
    transform->GetNumberOfParameters() );

  initialParameters.Fill( 0.0 );
  initialParameters[0] = 1.0;
  initialParameters[4] = 1.0;
  initialParameters[8] = 1.0;

  /***********************************************************
   * Run the registration - reducing learning rate as we go
   ************************************************************/
  const unsigned int numberOfLoops = 3;
  unsigned int iter[numberOfLoops] = { 300, 300, 350 };
  double      rates[numberOfLoops] = { 1e-3, 5e-4, 1e-4 };

  for ( j = 0; j < numberOfLoops; j++ )
    {

    try
      {
      optimizer->SetNumberOfIterations( iter[j] );
      optimizer->SetLearningRate( rates[j] );
      registration->SetInitialTransformParameters( initialParameters );
      registration->Update();

      initialParameters = registration->GetLastTransformParameters();

      }
    catch( itk::ExceptionObject & e )
      {
      std::cout << "Registration failed" << std::endl;
      std::cout << "Reason " << e.GetDescription() << std::endl;
      return EXIT_FAILURE;
      }

    }

  /***********************************************************
   * Check the results
   ************************************************************/
  RegistrationType::ParametersType solution =
    registration->GetLastTransformParameters();

  std::cout << "Solution is: " << solution << std::endl;

  RegistrationType::ParametersType trueParameters(
    transform->GetNumberOfParameters() );
  trueParameters.Fill( 0.0 );
  trueParameters[ 0] = 1/scale[0];
  trueParameters[ 4] = 1/scale[1];
  trueParameters[ 8] = 1/scale[2];
  trueParameters[ 9] = - displacement[0]/scale[0];
  trueParameters[10] = - displacement[1]/scale[1];
  trueParameters[11] = - displacement[2]/scale[2];

  std::cout << "True solution is: " << trueParameters << std::endl;

  for( j = 0; j < 9; j++ )
    {
    if( vnl_math_abs( solution[j] - trueParameters[j] ) > 0.025 )
      {
      std::cout << "Failed " << j << std::endl;
      pass = false;
      }
    }
  for( j = 9; j < 12; j++ )
    {
    if( vnl_math_abs( solution[j] - trueParameters[j] ) > 1.0 )
      {
      std::cout << "Failed " << j << std::endl;
      pass = false;
      }
    }

  if( !pass )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  /*************************************************
   * Check for parzen window exception
   **************************************************/
  double oldValue = metric->GetMovingImageStandardDeviation();
  metric->SetMovingImageStandardDeviation( 0.005 );

  try
    {
    pass = false;
    registration->Update();
    }
  catch(itk::ExceptionObject& err)
    {
    std::cout << "Caught expected ExceptionObject" << std::endl;
    std::cout << err << std::endl;
    pass = true;
    }

  if( !pass )
    {
    std::cout << "Should have caught an exception" << std::endl;
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  metric->SetMovingImageStandardDeviation( oldValue );

  /*************************************************
   * Check for mapped out of image error
   **************************************************/
  solution[5] = 1000;
  registration->SetInitialTransformParameters( solution );

  try
    {
    pass = false;
    registration->Update();
    }
  catch(itk::ExceptionObject& err)
    {
    std::cout << "Caught expected ExceptionObject" << std::endl;
    std::cout << err << std::endl;
    pass = true;
    }

  if( !pass )
    {
    std::cout << "Should have caught an exception" << std::endl;
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}
namespace
{

/**
 * This function defines the test image pattern.
 * The pattern is a 3D gaussian in the middle
 * and some directional pattern on the outside.
 */
double F( itk::Vector<double,3> & v )
{
  double x = v[0];
  double y = v[1];
  double z = v[2];
  const double s = 50;
  double value = 200.0 * vcl_exp( - ( x*x + y*y + z*z )/(s*s) );
  x -= 8; y += 3; z += 0;
  double r = vcl_sqrt( x*x + y*y + z*z );
  if( r > 35 )
    {
    value = 2 * ( vnl_math_abs( x ) +
      0.8 * vnl_math_abs( y ) +
      0.5 * vnl_math_abs( z ) );
    }
  if( r < 4 )
    {
    value = 400;
    }

  return value;

}
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSymmetricSecondRankTensorImageReadTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <fstream>
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
#include "itkSymmetricSecondRankTensor.h"
#include "itkImageRegionIterator.h"

int itkSymmetricSecondRankTensorImageReadTest( int ac, char* av[] )
{
  if(ac < 1)
    {
    std::cerr << "Usage: " << av[0] << " Input\n";
    return EXIT_FAILURE;
    }

  typedef itk::SymmetricSecondRankTensor<float, 3>    TensorPixelType;
  typedef itk::Image<TensorPixelType, 3>              TensorImageType;

  typedef itk::Matrix<float,3,3>                      MatrixPixelType;
  typedef itk::Image<MatrixPixelType, 3>              MatrixImageType;

  MatrixImageType::Pointer matrixImage = MatrixImageType::New();

  MatrixImageType::SizeType size;
  size.Fill(10);

  MatrixImageType::IndexType start;
  start.Fill(0);

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

  matrixImage->SetRegions( region );
  matrixImage->Allocate();

  MatrixPixelType matrixPixel;

  matrixPixel[0][0] = 1;
  matrixPixel[0][1] = 2;
  matrixPixel[0][2] = 3;

  matrixPixel[1][0] = 2;
  matrixPixel[1][1] = 4;
  matrixPixel[1][2] = 5;

  matrixPixel[2][0] = 3;
  matrixPixel[2][1] = 5;
  matrixPixel[2][2] = 6;

  itk::ImageRegionIterator< MatrixImageType > itr( matrixImage, region );

  itr.GoToBegin();

  while( !itr.IsAtEnd() )
    {
    itr.Set( matrixPixel );
    for(unsigned int i=0; i<3; i++)
      {
      for(unsigned int j=0; j<3; j++)
        {
        matrixPixel[i][j]++;
        }
      }
    ++itr;
    }

  typedef itk::ImageFileWriter< MatrixImageType > MatrixWriterType;

  MatrixWriterType::Pointer matrixWriter = MatrixWriterType::New();

  matrixWriter->SetInput( matrixImage );
  matrixWriter->SetFileName( av[1] );

  try
    {
    matrixWriter->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::ImageFileReader<  TensorImageType > TensorReaderType;

  TensorReaderType::Pointer tensorReader = TensorReaderType::New();

  tensorReader->SetFileName( av[1] );

  try
    {
    tensorReader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }

  TensorImageType::ConstPointer tensorImage = tensorReader->GetOutput();

  // Compare the read values to the original values
  const float tolerance = 1e-5;

  itk::ImageRegionConstIterator< TensorImageType > tItr( tensorImage, region );
  itk::ImageRegionConstIterator< MatrixImageType > mItr( matrixImage, region );

  tItr.GoToBegin();
  mItr.GoToBegin();

  while( !mItr.IsAtEnd() )
    {
    const MatrixPixelType matrixPixel = mItr.Get();
    const TensorPixelType tensorPixel = tItr.Get();

    for(unsigned int i=0; i<3; i++)
      {
      for(unsigned int j=0; j<3; j++)
        {
        if( vcl_abs( matrixPixel[i][j] - tensorPixel(i,j) ) > tolerance )
          {
          std::cerr << "Tensor read does not match expected values " << std::endl;
          std::cerr << "Index " << tItr.GetIndex() << std::endl;
          std::cerr << "Tensor value " << std::endl << tensorPixel << std::endl;
          std::cerr << "Matrix value " << std::endl << matrixPixel << std::endl;
          return EXIT_FAILURE;
          }
        }
      }
    ++mItr;
    ++tItr;
    }

  return EXIT_SUCCESS;

}
<commit_msg>COMP: hidden variable/type warning.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSymmetricSecondRankTensorImageReadTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <fstream>
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
#include "itkSymmetricSecondRankTensor.h"
#include "itkImageRegionIterator.h"

int itkSymmetricSecondRankTensorImageReadTest( int ac, char* av[] )
{
  if(ac < 1)
    {
    std::cerr << "Usage: " << av[0] << " Input\n";
    return EXIT_FAILURE;
    }

  typedef itk::SymmetricSecondRankTensor<float, 3>    TensorPixelType;
  typedef itk::Image<TensorPixelType, 3>              TensorImageType;

  typedef itk::Matrix<float,3,3>                      MatrixPixelType;
  typedef itk::Image<MatrixPixelType, 3>              MatrixImageType;

  MatrixImageType::Pointer matrixImage = MatrixImageType::New();

  MatrixImageType::SizeType size;
  size.Fill(10);

  MatrixImageType::IndexType start;
  start.Fill(0);

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

  matrixImage->SetRegions( region );
  matrixImage->Allocate();

  MatrixPixelType matrixPixel;

  matrixPixel[0][0] = 1;
  matrixPixel[0][1] = 2;
  matrixPixel[0][2] = 3;

  matrixPixel[1][0] = 2;
  matrixPixel[1][1] = 4;
  matrixPixel[1][2] = 5;

  matrixPixel[2][0] = 3;
  matrixPixel[2][1] = 5;
  matrixPixel[2][2] = 6;

  itk::ImageRegionIterator< MatrixImageType > itr( matrixImage, region );

  itr.GoToBegin();

  while( !itr.IsAtEnd() )
    {
    itr.Set( matrixPixel );
    for(unsigned int i=0; i<3; i++)
      {
      for(unsigned int j=0; j<3; j++)
        {
        matrixPixel[i][j]++;
        }
      }
    ++itr;
    }

  typedef itk::ImageFileWriter< MatrixImageType > MatrixWriterType;

  MatrixWriterType::Pointer matrixWriter = MatrixWriterType::New();

  matrixWriter->SetInput( matrixImage );
  matrixWriter->SetFileName( av[1] );

  try
    {
    matrixWriter->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::ImageFileReader<  TensorImageType > TensorReaderType;

  TensorReaderType::Pointer tensorReader = TensorReaderType::New();

  tensorReader->SetFileName( av[1] );

  try
    {
    tensorReader->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << excp << std::endl;
    return EXIT_FAILURE;
    }

  TensorImageType::ConstPointer tensorImage = tensorReader->GetOutput();

  // Compare the read values to the original values
  const float tolerance = 1e-5;

  itk::ImageRegionConstIterator< TensorImageType > tItr( tensorImage, region );
  itk::ImageRegionConstIterator< MatrixImageType > mItr( matrixImage, region );

  tItr.GoToBegin();
  mItr.GoToBegin();

  while( !mItr.IsAtEnd() )
    {
    matrixPixel = mItr.Get();
    const TensorPixelType tensorPixel = tItr.Get();

    for(unsigned int i=0; i<3; i++)
      {
      for(unsigned int j=0; j<3; j++)
        {
        if( vcl_abs( matrixPixel[i][j] - tensorPixel(i,j) ) > tolerance )
          {
          std::cerr << "Tensor read does not match expected values " << std::endl;
          std::cerr << "Index " << tItr.GetIndex() << std::endl;
          std::cerr << "Tensor value " << std::endl << tensorPixel << std::endl;
          std::cerr << "Matrix value " << std::endl << matrixPixel << std::endl;
          return EXIT_FAILURE;
          }
        }
      }
    ++mItr;
    ++tItr;
    }

  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>// Author: Akira Okumura 2011/5/1

/******************************************************************************
 * Copyright (C) 2006-, Akira Okumura                                         *
 * All rights reserved.                                                       *
 *****************************************************************************/

// define useful units
static const Double_t cm = AOpticsManager::cm();
static const Double_t mm = AOpticsManager::mm();
static const Double_t um = AOpticsManager::um();
static const Double_t nm = AOpticsManager::nm();
static const Double_t  m = AOpticsManager::m();

const Double_t kMirrorRad = 1.5.*m;
const Double_t kFocalLength = 3*m;
const Double_t kMirrorSag = kMirrorRad*kMirrorRad/4./kFocalLength;
const Double_t kFocalRad = 20*cm;

AOpticsManager* MakeGeometry()
{
  // Make the geometry of a simple parabolic telescope

  AOpticsManager* manager = new AOpticsManager("manager", "SimpleParabolicTelescope");
  manager->SetNsegments(100); // Set the smoothness of surface drawing. Display use only.

  // Make the world
  TGeoBBox* worldbox = new TGeoBBox("worldbox", 10*m, 10*m, 10*m);
  AOpticalComponent* world = new AOpticalComponent("world", worldbox);
  manager->SetTopVolume(world);

  // Define a paraboloid for the mirror
  TGeoParaboloid* para = new TGeoParaboloid("mirror_para", 0, kMirrorRad, kMirrorSag/2.);

  TGeoTranslation* mirror_tr1 = new TGeoTranslation("mirror_tr1", 0, 0, kMirrorSag/2.);
  mirror_tr1->RegisterYourself();
  TGeoTranslation* mirror_tr2 = new TGeoTranslation("mirror_tr2", 0, 0, kMirrorSag/2. - 1*um);
  mirror_tr2->RegisterYourself();

  // Composite two TGeoParaboloid to make a thin parabolic surface
  TGeoCompositeShape* mirror_comp = new TGeoCompositeShape("mirror_comp", "mirror_para:mirror_tr2 - mirror_para:mirror_tr1");

  // Make a parabolic mirror
  AMirror* mirror = new AMirror("mirror", mirror_comp);
  world->AddNode(mirror, 1);

  // Define a tube for the forcal surface
  TGeoTube* focal_tube = new TGeoTube("focal_tube", 0, kFocalRad, 10*um);

  TGeoTranslation* focal_tr = new TGeoTranslation("focal_tr", 0, 0, kFocalLength + 10*um);
  focal_tr->RegisterYourself();

  // Make a focal surface
  AFocalSurface* focal = new AFocalSurface("focal", focal_tube);
  world->AddNode(focal, 1, focal_tr);

  TGeoTube* obs_tube1 = new TGeoTube("obs_tube1", 0, kFocalRad + 10*um, 10*um);
  TGeoTranslation* obs_tr1 = new TGeoTranslation("obs_tr1", 0, 0, kFocalLength + 30*um);
  obs_tr1->RegisterYourself();

  // Make a dummy obscuration behind the focal plane
  AObscuration* obs1 = new AObscuration("obs1", obs_tube1);
  world->AddNode(obs1, 1, obs_tr1);

  TGeoTube* obs_tube2 = new TGeoTube("obs_tube2", kFocalRad, kFocalRad + 10*um, 10*um);
  TGeoTranslation* obs_tr2 = new TGeoTranslation("obs_tr2", 0, 0, kFocalLength + 10*um);
  obs_tr2->RegisterYourself();

  // Make one more obscuration surrounding the focal plane
  AObscuration* obs2 = new AObscuration("obs2", obs_tube2);
  world->AddNode(obs2, 1, obs_tr2);

  manager->CloseGeometry();

  world->Draw();

  return manager;
}

void SimpleParabolicTelescope()
{
  AOpticsManager* manager = MakeGeometry();

  const Int_t kN = 30;
  TH2D* hist[kN];

  for(Int_t i = 0; i < kN; i++){
    Double_t deg = i*0.1;
    Double_t rad = deg*TMath::DegToRad();

    hist[i] = new TH2D(Form("hist%d", i), Form("#it{#theta} = %.1f (deg);X (cm);Y (cm)", deg), 300, -3, 3, 300, -3, 3);

    TGeoTranslation* raytr = new TGeoTranslation("raytr", -kFocalLength*2*TMath::Sin(rad), 0, kFocalLength*2*TMath::Cos(rad));
    TVector3 dir;
    dir.SetMagThetaPhi(1, TMath::Pi() - rad, 0);
    Double_t lambda = 400*nm; // does not affect the results because we have no lens
    ARayArray* array = ARayShooter::Square(lambda, 5*m, 201, 0, raytr, &dir);

    manager->TraceNonSequential(*array);
    TObjArray* focused = array->GetFocused();

    // Get the mean <x> and <y>
    TH2D mean("", "", 1, -10*m, 10*m, 1, -10*m, 10*m);
    for(Int_t j = 0; j <= focused->GetLast(); j++){
      ARay* ray = (ARay*)(*focused)[j];
      Double_t p[4];
      ray->GetLastPoint(p);
      mean.Fill(p[0], p[1]);
    } // j

    for(Int_t j = 0; j <= focused->GetLast(); j++){
      ARay* ray = (ARay*)(*focused)[j];
      Double_t* first = ray->GetFirstPoint();
      Double_t last[4];
      ray->GetLastPoint(last);

      Double_t x = deg*10*cm;
      hist[i]->Fill(last[0] - mean.GetMean(1), last[1] - mean.GetMean(2));

      // Draw only some selected photons in 3D
      if(((i == 0) || (i == kN - 1)) && (TMath::Abs(first[0]) < 1*cm || TMath::Abs(first[1]) < 1*cm)){
        TPolyLine3D* pol = ray->MakePolyLine3D();
        if(i == 0){
          pol->SetLineColor(3);
        }
        pol->Draw();
      } // ij
    } // if
  } // i

  TCanvas* can_spot = new TCanvas("can_spot", "can_spot", 1200, 1000);
  can_spot->Divide(6, 5, 1e-10, 1e-10);

  TLegend* leg = new TLegend(0.15, 0.6, 0.5, 0.85);
  leg->SetFillStyle(0);
  char title[3][100] = {"#sigma_{x}", "#sigma_{y}", "#sigma"};

  TGraph* gra[3];
  for(Int_t i = 0; i < 3; i++){
    gra[i] = new TGraph();
    gra[i]->SetLineStyle(i + 1);
    gra[i]->SetMarkerStyle(24 + i);
    leg->AddEntry(gra[i], title[i], "lp");
  } // i

  for(Int_t i = 0; i < kN; i++){
    Double_t deg = i*0.1;
    can_spot->cd(i + 1);
    hist[i]->Draw("colz");

    Double_t rmsx = hist[i]->GetRMS(1);
    Double_t rmsy = hist[i]->GetRMS(2);

    gra[0]->SetPoint(i, deg, rmsx);
    gra[1]->SetPoint(i, deg, rmsy);
    gra[2]->SetPoint(i, deg, TMath::Sqrt(rmsx*rmsx + rmsy*rmsy));
  } // i

  TCanvas* can_sigma = new TCanvas("can_sigma", "can_sigma");
  gra[2]->Draw("apl");
  gra[2]->GetXaxis()->SetTitle("Incident Angle (deg)");
  gra[2]->GetYaxis()->SetTitle("Spot Size (cm)");
  gra[0]->Draw("pl same");
  gra[1]->Draw("pl same");
  leg->Draw();
}
<commit_msg>Fix errors that appear in ROOT6 (Cling)<commit_after>// Author: Akira Okumura 2011/5/1

/******************************************************************************
 * Copyright (C) 2006-, Akira Okumura                                         *
 * All rights reserved.                                                       *
 *****************************************************************************/

// define useful units
static const Double_t cm = AOpticsManager::cm();
static const Double_t mm = AOpticsManager::mm();
static const Double_t um = AOpticsManager::um();
static const Double_t nm = AOpticsManager::nm();
static const Double_t  m = AOpticsManager::m();

const Double_t kMirrorRad = 1.5*m;
const Double_t kFocalLength = 3*m;
const Double_t kMirrorSag = kMirrorRad*kMirrorRad/4./kFocalLength;
const Double_t kFocalRad = 20*cm;

AOpticsManager* MakeGeometry()
{
  // Make the geometry of a simple parabolic telescope

  AOpticsManager* manager = new AOpticsManager("manager", "SimpleParabolicTelescope");
  manager->SetNsegments(100); // Set the smoothness of surface drawing. Display use only.

  // Make the world
  TGeoBBox* worldbox = new TGeoBBox("worldbox", 10*m, 10*m, 10*m);
  AOpticalComponent* world = new AOpticalComponent("world", worldbox);
  manager->SetTopVolume(world);

  // Define a paraboloid for the mirror
  TGeoParaboloid* para = new TGeoParaboloid("mirror_para", 0, kMirrorRad, kMirrorSag/2.);

  TGeoTranslation* mirror_tr1 = new TGeoTranslation("mirror_tr1", 0, 0, kMirrorSag/2.);
  mirror_tr1->RegisterYourself();
  TGeoTranslation* mirror_tr2 = new TGeoTranslation("mirror_tr2", 0, 0, kMirrorSag/2. - 1*um);
  mirror_tr2->RegisterYourself();

  // Composite two TGeoParaboloid to make a thin parabolic surface
  TGeoCompositeShape* mirror_comp = new TGeoCompositeShape("mirror_comp", "mirror_para:mirror_tr2 - mirror_para:mirror_tr1");

  // Make a parabolic mirror
  AMirror* mirror = new AMirror("mirror", mirror_comp);
  world->AddNode(mirror, 1);

  // Define a tube for the forcal surface
  TGeoTube* focal_tube = new TGeoTube("focal_tube", 0, kFocalRad, 10*um);

  TGeoTranslation* focal_tr = new TGeoTranslation("focal_tr", 0, 0, kFocalLength + 10*um);
  focal_tr->RegisterYourself();

  // Make a focal surface
  AFocalSurface* focal = new AFocalSurface("focal", focal_tube);
  world->AddNode(focal, 1, focal_tr);

  TGeoTube* obs_tube1 = new TGeoTube("obs_tube1", 0, kFocalRad + 10*um, 10*um);
  TGeoTranslation* obs_tr1 = new TGeoTranslation("obs_tr1", 0, 0, kFocalLength + 30*um);
  obs_tr1->RegisterYourself();

  // Make a dummy obscuration behind the focal plane
  AObscuration* obs1 = new AObscuration("obs1", obs_tube1);
  world->AddNode(obs1, 1, obs_tr1);

  TGeoTube* obs_tube2 = new TGeoTube("obs_tube2", kFocalRad, kFocalRad + 10*um, 10*um);
  TGeoTranslation* obs_tr2 = new TGeoTranslation("obs_tr2", 0, 0, kFocalLength + 10*um);
  obs_tr2->RegisterYourself();

  // Make one more obscuration surrounding the focal plane
  AObscuration* obs2 = new AObscuration("obs2", obs_tube2);
  world->AddNode(obs2, 1, obs_tr2);

  manager->CloseGeometry();

  world->Draw();

  return manager;
}

void SimpleParabolicTelescope()
{
  AOpticsManager* manager = MakeGeometry();

  const Int_t kN = 30;
  TH2D* hist[kN];

  for(Int_t i = 0; i < kN; i++){
    Double_t deg = i*0.1;
    Double_t rad = deg*TMath::DegToRad();

    hist[i] = new TH2D(Form("hist%d", i), Form("#it{#theta} = %.1f (deg);X (cm);Y (cm)", deg), 300, -3, 3, 300, -3, 3);

    TGeoTranslation* raytr = new TGeoTranslation("raytr", -kFocalLength*2*TMath::Sin(rad), 0, kFocalLength*2*TMath::Cos(rad));
    TVector3 dir;
    dir.SetMagThetaPhi(1, TMath::Pi() - rad, 0);
    Double_t lambda = 400*nm; // does not affect the results because we have no lens
    ARayArray* array = ARayShooter::Square(lambda, 5*m, 201, 0, raytr, &dir);

    manager->TraceNonSequential(*array);
    TObjArray* focused = array->GetFocused();

    // Get the mean <x> and <y>
    TH2D mean("", "", 1, -10*m, 10*m, 1, -10*m, 10*m);
    for(Int_t j = 0; j <= focused->GetLast(); j++){
      ARay* ray = (ARay*)(*focused)[j];
      Double_t p[4];
      ray->GetLastPoint(p);
      mean.Fill(p[0], p[1]);
    } // j

    for(Int_t j = 0; j <= focused->GetLast(); j++){
      ARay* ray = (ARay*)(*focused)[j];
      const Double_t* first = ray->GetFirstPoint();
      Double_t last[4];
      ray->GetLastPoint(last);

      Double_t x = deg*10*cm;
      hist[i]->Fill(last[0] - mean.GetMean(1), last[1] - mean.GetMean(2));

      // Draw only some selected photons in 3D
      if(((i == 0) || (i == kN - 1)) && (TMath::Abs(first[0]) < 1*cm || TMath::Abs(first[1]) < 1*cm)){
        TPolyLine3D* pol = ray->MakePolyLine3D();
        if(i == 0){
          pol->SetLineColor(3);
        }
        pol->Draw();
      } // ij
    } // if
  } // i

  TCanvas* can_spot = new TCanvas("can_spot", "can_spot", 1200, 1000);
  can_spot->Divide(6, 5, 1e-10, 1e-10);

  TLegend* leg = new TLegend(0.15, 0.6, 0.5, 0.85);
  leg->SetFillStyle(0);
  char title[3][100] = {"#sigma_{x}", "#sigma_{y}", "#sigma"};

  TGraph* gra[3];
  for(Int_t i = 0; i < 3; i++){
    gra[i] = new TGraph();
    gra[i]->SetLineStyle(i + 1);
    gra[i]->SetMarkerStyle(24 + i);
    leg->AddEntry(gra[i], title[i], "lp");
  } // i

  for(Int_t i = 0; i < kN; i++){
    Double_t deg = i*0.1;
    can_spot->cd(i + 1);
    hist[i]->Draw("colz");

    Double_t rmsx = hist[i]->GetRMS(1);
    Double_t rmsy = hist[i]->GetRMS(2);

    gra[0]->SetPoint(i, deg, rmsx);
    gra[1]->SetPoint(i, deg, rmsy);
    gra[2]->SetPoint(i, deg, TMath::Sqrt(rmsx*rmsx + rmsy*rmsy));
  } // i

  TCanvas* can_sigma = new TCanvas("can_sigma", "can_sigma");
  gra[2]->Draw("apl");
  gra[2]->GetXaxis()->SetTitle("Incident Angle (deg)");
  gra[2]->GetYaxis()->SetTitle("Spot Size (cm)");
  gra[0]->Draw("pl same");
  gra[1]->Draw("pl same");
  leg->Draw();
}
<|endoftext|>


<commit_before>#ifndef POOL_HPP
#define POOL_HPP

#include <atomic>
#include <deque>
#include <future>
#include <mutex>
#include <thread>
#include <vector>

class Pool {
private:
  //Count of threads in the pool
  int count;
  //Mutex when performing actions on the non-thread-safe STL utilities
  std::mutex m;
  //List of our workers
  std::vector<std::thread> threads;
  //Whether or not we're accepting tasks
  std::atomic<bool>* shutdown = new std::atomic<bool>(false);
  //List of pending jobs waiting to be std::move'd by a worker
  std::deque<std::future<void>> jobs;

  void provision() {
    //Lock while we create our threads (do you really think someone will try deleting us that fast? :sad_face:)
    m.lock();
    for (int i = 0; i < count; ++i) {
      //Create a thread bound to the object which owns this pool object (because why not?)
      threads.push_back(std::move(std::thread(&Pool::create_worker, this)));
    }
    m.unlock();
  }

  void create_worker() {
    for (;;) {
      //Die if we're shutting down
      if (shutdown->load()) break;
      //Lock the mutex and check for work
      m.lock();
      if (jobs.empty()) {
        //No work, go back to sleep!
        m.unlock();
        //TODO: condition variable
        std::this_thread::yield();
      } else {
        //Ermahgerd we have work! Leggo.
        auto f = std::move(jobs.front());
        jobs.pop_front();
        m.unlock();

        f.get();
      }
    }
  }

public:
  Pool() : Pool(std::thread::hardware_concurrency() * 3) {}

  Pool(const int& count) {
    this->count = count;
    provision();
  }

  ~Pool() {
    //Signal shutdown to the workers
    shutdown->store(true);
    //Wait for all workers to finish current work
    for (auto i = threads.begin(); i != threads.end(); ++i) i->join();
    //Clean up our atomic variable
    delete shutdown;
  }

  int size() const { return this->count; }

  template <typename F, typename... A>
  std::future<void> v2(F&& f, A&&... a) {
    auto pack = std::packaged_task<decltype(f(a...))>(std::bind(std::forward<F>(f), std::forward<A>(a)...));
  }

  std::future<void> run(std::function<void()> f) {
    std::atomic<bool>* ready = new std::atomic<bool>(false);
    std::promise<void>* p = new std::promise<void>;
    auto task = [ready, p](std::function<void()>&& f) {
      try {
        f();
        p->set_value();
      } catch (...) { p->set_exception(std::current_exception()); }
      ready->store(true);
    };
    auto v = [ready, p]() {
      while (!ready->load()) std::this_thread::yield();
      p->get_future().get();
      delete ready;
      delete p;
    };
    m.lock();
    jobs.emplace_back(std::async(std::launch::deferred, task, std::move(f)));
    m.unlock();
    return std::async(std::launch::deferred, v);
  }

  template <typename... A>
  std::future<void> run(std::function<void(A...)> f, A... a) {
    std::atomic<bool>* ready = new std::atomic<bool>(false);
    std::promise<void>* p = new std::promise<void>;
    auto task = [ready, p](std::function<void(A...)>&& f, A&&... a) {
      try {
        f(a...);
        p->set_value();
      } catch (...) { p->set_exception(std::current_exception()); }
      ready->store(true);
    };
    auto v = [ready, p]() {
      while (!ready->load()) std::this_thread::yield();
      p->get_future().get();
      delete ready;
      delete p;
    };
    m.lock();
    jobs.emplace_back(std::async(std::launch::deferred, task, std::move(f), std::move(a)...));
    m.unlock();
    return std::async(std::launch::deferred, v);
  }

  template <typename R>
  std::future<R> submit(std::function<R()> f) {
    std::atomic<bool>* ready = new std::atomic<bool>(false);
    std::promise<R>* p = new std::promise<R>;
    auto task = [ready, p](std::function<R()>&& f) {
      try {
        p->set_value(f());
      } catch (...) { p->set_exception(std::current_exception()); }
      ready->store(true);
    };
    auto v = [ready, p]() {
      while (!ready->load()) std::this_thread::yield();
      auto r = p->get_future().get();
      delete ready;
      delete p;
      return r;
    };
    m.lock();
    jobs.emplace_back(std::async(std::launch::deferred, task, std::move(f)));
    m.unlock();
    return std::async(std::launch::deferred, v);
  }

  template <typename R, typename... A>
  std::future<R> submit(std::function<R(A...)> f, A... a) {
    std::atomic<bool>* ready = new std::atomic<bool>(false);
    std::promise<R>* p = new std::promise<R>;
    auto task = [ready, p](std::function<R(A...)>&& f, A&&... a) {
      try {
        p->set_value(f(a...));
      } catch (...) { p->set_exception(std::current_exception()); }
      ready->store(true);
    };
    auto v = [ready, p]() {
      while (!ready->load()) std::this_thread::yield();
      auto r = p->get_future().get();
      delete ready;
      delete p;
      return r;
    };
    m.lock();
    jobs.emplace_back(std::async(std::launch::deferred, task, std::move(f), std::move(a)...));
    m.unlock();
    return std::async(std::launch::deferred, v);
  }

  template <typename F>
  auto offer(F&& f) -> std::future<decltype(f())> {
    typedef decltype(f()) R;
    auto p = std::make_shared<std::packaged_task<R()>>(std::forward<F>(f));
    m.lock();
    auto l = [p]() {
      (*p)();
    };
    jobs.emplace_back(std::async(std::launch::deferred, std::move(l)));
    m.unlock();
    return p->get_future();
  }

  template <typename F, typename... A>
  auto offer(F&& f, A&&... a) -> std::future<decltype(f(a...))> {
    typedef decltype(f(a...)) R;
    auto p = std::make_shared<std::packaged_task<R()>>(std::bind(std::forward<F>(f), std::forward<A>(a)...));
    m.lock();
    auto l = [p]() {
      (*p)();
    };
    jobs.emplace_back(std::async(std::launch::deferred, std::move(l)));
    m.unlock();
    return p->get_future();
  }
};

#endif
<commit_msg>Refactor thread pool<commit_after>#ifndef POOL_HPP
#define POOL_HPP

#include <atomic>
#include <deque>
#include <future>
#include <mutex>
#include <thread>
#include <vector>

class Pool {
private:
  //Count of threads in the pool
  int count;
  //Mutex when performing actions on the non-thread-safe STL utilities
  std::mutex m;
  //List of our workers
  std::vector<std::thread> threads;
  //Whether or not we're accepting tasks
  std::atomic<bool>* shutdown = new std::atomic<bool>(false);
  //List of pending jobs waiting to be std::move'd by a worker
  std::deque<std::future<void>> jobs;

  void provision() {
    //Lock while we create our threads (do you really think someone will try deleting us that fast? :sad_face:)
    m.lock();
    for (int i = 0; i < count; ++i) {
      //Create a thread bound to the object which owns this pool object (because why not?)
      threads.push_back(std::move(std::thread(&Pool::create_worker, this)));
    }
    m.unlock();
  }

  void create_worker() {
    for (;;) {
      //Die if we're shutting down
      if (shutdown->load()) break;
      //Lock the mutex and check for work
      m.lock();
      if (jobs.empty()) {
        //No work, go back to sleep!
        m.unlock();
        //TODO: condition variable
        std::this_thread::yield();
      } else {
        //Ermahgerd we have work! Leggo.
        auto f = std::move(jobs.front());
        jobs.pop_front();
        m.unlock();

        f.get();
      }
    }
  }

public:
  Pool() : Pool(std::thread::hardware_concurrency() * 3) {}

  Pool(const int& count) {
    this->count = count;
    provision();
  }

  ~Pool() {
    //Signal shutdown to the workers
    shutdown->store(true);
    //Wait for all workers to finish current work
    for (auto i = threads.begin(); i != threads.end(); ++i) i->join();
    //Clean up our atomic variable
    delete shutdown;
  }

  int size() const { return this->count; }

  template <typename F>
  auto submit(F&& f) -> std::future<decltype(f())> {
    typedef decltype(f()) R;
    auto p = std::make_shared<std::packaged_task<R()>>(std::forward<F>(f));
    m.lock();
    auto l = [p]() {
      (*p)();
    };
    jobs.emplace_back(std::async(std::launch::deferred, std::move(l)));
    m.unlock();
    return p->get_future();
  }

  template <typename F, typename... A>
  auto submit(F&& f, A&&... a) -> std::future<decltype(f(a...))> {
    typedef decltype(f(a...)) R;
    auto p = std::make_shared<std::packaged_task<R()>>(std::bind(std::forward<F>(f), std::forward<A>(a)...));
    m.lock();
    auto l = [p]() {
      (*p)();
    };
    jobs.emplace_back(std::async(std::launch::deferred, std::move(l)));
    m.unlock();
    return p->get_future();
  }
};

#endif
<|endoftext|>


<commit_before>/************************************************************************************\
This source file is part of the Awesome Portable Rendering Interface Library         *
For latest info, see http://libapril.sourceforge.net/                                *
**************************************************************************************
Copyright (c) 2010 Kresimir Spes, Ivan Vucica                                        *
*                                                                                *
* This program is free software; you can redistribute it and/or modify it under      *
* the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php   *
\************************************************************************************/
#ifdef _OPENGL

#ifdef IPHONE_PLATFORM
 #include <OpenGLES/ES1/gl.h>
#elif _OPENGLES1
 #include <GLES/gl.h>
#else
 #ifdef _WIN32
  #include <windows.h>
 #endif

 #ifndef __APPLE__
  #include <GL/gl.h>
  #include <GL/glu.h>
  #if HAVE_GLUT
   #include <GL/glut.h>
  #endif
 #else // __APPLE__
  #include <TargetConditionals.h>
  #if TARGET_OS_IPHONE
   #include <OpenGLES/ES1/gl.h>
   #include <OpenGLES/ES1/glext.h>
  #else
   #include <OpenGL/gl.h>
   #include <OpenGL/glu.h>
   #include <GLUT/glut.h>
  #endif
 #endif // __APPLE__
#endif

#include <hltypes/hstring.h>

#include "ImageSource.h"
#include "OpenGL_Texture.h"

namespace april
{
	unsigned int platformLoadOpenGL_Texture(const char* name, int* w, int* h)
	{
		GLuint texid;
		ImageSource* img = loadImage(name);
		if (!img)
		{
			return 0;
		}
		*w = img->w;
		*h = img->h;
		glGenTextures(1, &texid);
		glBindTexture(GL_TEXTURE_2D, texid);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		switch (img->format)
		{
#if TARGET_OS_IPHONE
		case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
		case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
		{
			int mipmaplevel = 0;
			glCompressedTexImage2D(GL_TEXTURE_2D, mipmaplevel, img->format, img->w, img->h, 0, img->compressedLength, img->data);
			break;
		}
#endif
		default:
			glTexImage2D(GL_TEXTURE_2D, 0, img->bpp == 4 ? GL_RGBA : GL_RGB, img->w,img->h, 0, img->format, GL_UNSIGNED_BYTE,img->data);
			break;
		}
		delete img;

		return texid;
	}

	OpenGL_Texture::OpenGL_Texture(chstr filename, bool dynamic)
	{
		mWidth = 0;
		mHeight = 0;
		mFilename = filename;
		mDynamic = dynamic;
		mTexId = 0;
	}

	OpenGL_Texture::OpenGL_Texture(unsigned char* rgba, int w, int h)
	{
		mWidth = w;
		mHeight = h;
		mDynamic = 0;
		mFilename = "UserTexture";
		glGenTextures(1, &mTexId);
		glBindTexture(GL_TEXTURE_2D, mTexId);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
	}

	OpenGL_Texture::~OpenGL_Texture()
	{
		unload();
	}

	bool OpenGL_Texture::load()
	{
		mUnusedTimer = 0;
		if (mTexId)
		{
			return true;
		}
		april::log("loading GL texture '" + mFilename + "'");
		mTexId = platformLoadOpenGL_Texture(mFilename.c_str(), &mWidth, &mHeight);
		if (!mTexId)
		{
			april::log("Failed to load texture: " + mFilename);
			return false;
		}
		foreach (Texture*, it, mDynamicLinks)
		{
			((OpenGL_Texture*)(*it))->load();
		}
		return true;
	}

	bool OpenGL_Texture::isLoaded()
	{
		return (mTexId != 0);
	}

	void OpenGL_Texture::unload()
	{
		if (mTexId != 0)
		{
			april::log("unloading GL texture '" + mFilename + "'");
			glDeleteTextures(1, &mTexId);
			mTexId = 0;
		}
	}

	int OpenGL_Texture::getSizeInBytes()
	{
		return (mWidth * mHeight * 3);
	}

}

#endif
<commit_msg>opengl load texture from memory fix<commit_after>/************************************************************************************\
This source file is part of the Awesome Portable Rendering Interface Library         *
For latest info, see http://libapril.sourceforge.net/                                *
**************************************************************************************
Copyright (c) 2010 Kresimir Spes, Ivan Vucica                                        *
*                                                                                *
* This program is free software; you can redistribute it and/or modify it under      *
* the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php   *
\************************************************************************************/
#ifdef _OPENGL

#ifdef IPHONE_PLATFORM
 #include <OpenGLES/ES1/gl.h>
#elif _OPENGLES1
 #include <GLES/gl.h>
#else
 #ifdef _WIN32
  #include <windows.h>
 #endif

 #ifndef __APPLE__
  #include <GL/gl.h>
  #include <GL/glu.h>
  #if HAVE_GLUT
   #include <GL/glut.h>
  #endif
 #else // __APPLE__
  #include <TargetConditionals.h>
  #if TARGET_OS_IPHONE
   #include <OpenGLES/ES1/gl.h>
   #include <OpenGLES/ES1/glext.h>
  #else
   #include <OpenGL/gl.h>
   #include <OpenGL/glu.h>
   #include <GLUT/glut.h>
  #endif
 #endif // __APPLE__
#endif

#include <hltypes/hstring.h>

#include "ImageSource.h"
#include "OpenGL_Texture.h"

namespace april
{
	unsigned int platformLoadOpenGL_Texture(const char* name, int* w, int* h)
	{
		GLuint texid;
		ImageSource* img = loadImage(name);
		if (!img)
		{
			return 0;
		}
		*w = img->w;
		*h = img->h;
		glGenTextures(1, &texid);
		glBindTexture(GL_TEXTURE_2D, texid);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		switch (img->format)
		{
#if TARGET_OS_IPHONE
		case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
		case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
		{
			int mipmaplevel = 0;
			glCompressedTexImage2D(GL_TEXTURE_2D, mipmaplevel, img->format, img->w, img->h, 0, img->compressedLength, img->data);
			break;
		}
#endif
		default:
			glTexImage2D(GL_TEXTURE_2D, 0, img->bpp == 4 ? GL_RGBA : GL_RGB, img->w,img->h, 0, img->format, GL_UNSIGNED_BYTE,img->data);
			break;
		}
		delete img;

		return texid;
	}

	OpenGL_Texture::OpenGL_Texture(chstr filename, bool dynamic)
	{
		mWidth = 0;
		mHeight = 0;
		mFilename = filename;
		mDynamic = dynamic;
		mTexId = 0;
	}

	OpenGL_Texture::OpenGL_Texture(unsigned char* rgba, int w, int h)
	{
		mWidth = w;
		mHeight = h;
		mDynamic = 0;
		mFilename = "UserTexture";
		glGenTextures(1, &mTexId);
		glBindTexture(GL_TEXTURE_2D, mTexId);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
	}

	OpenGL_Texture::~OpenGL_Texture()
	{
		unload();
	}

	bool OpenGL_Texture::load()
	{
		mUnusedTimer = 0;
		if (mTexId)
		{
			return true;
		}
		april::log("loading GL texture '" + mFilename + "'");
		mTexId = platformLoadOpenGL_Texture(mFilename.c_str(), &mWidth, &mHeight);
		if (!mTexId)
		{
			april::log("Failed to load texture: " + mFilename);
			return false;
		}
		foreach (Texture*, it, mDynamicLinks)
		{
			((OpenGL_Texture*)(*it))->load();
		}
		return true;
	}

	bool OpenGL_Texture::isLoaded()
	{
		return (mTexId != 0);
	}

	void OpenGL_Texture::unload()
	{
		if (mTexId != 0)
		{
			april::log("unloading GL texture '" + mFilename + "'");
			glDeleteTextures(1, &mTexId);
			mTexId = 0;
		}
	}

	int OpenGL_Texture::getSizeInBytes()
	{
		return (mWidth * mHeight * 3);
	}

}

#endif
<|endoftext|>