/* -*- c++ -*- */
/*
 * Copyright 2013 Free Software Foundation, Inc.
 *
 * This file is part of GNU Radio
 *
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GNU Radio 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/filter/pfb_arb_resampler.h>
#include <gnuradio/logger.h>
#include <cstdio>
#include <stdexcept>
#include <boost/math/special_functions/round.hpp>

namespace gr {
  namespace filter {
    namespace kernel {

      pfb_arb_resampler_ccf::pfb_arb_resampler_ccf(float rate,
                                                   const std::vector<float> &taps,
                                                   unsigned int filter_size)
      {
        d_acc = 0; // start accumulator at 0

        /* The number of filters is specified by the user as the
           filter size; this is also the interpolation rate of the
           filter. We use it and the rate provided to determine the
           decimation rate. This acts as a rational resampler. The
           flt_rate is calculated as the residual between the integer
           decimation rate and the real decimation rate and will be
           used to determine to interpolation point of the resampling
           process.
        */
        d_int_rate = filter_size;
        set_rate(rate);

        d_last_filter = (taps.size()/2) % filter_size;

        d_filters = std::vector<fir_filter_ccf*>(d_int_rate);
        d_diff_filters = std::vector<fir_filter_ccf*>(d_int_rate);

        // Create an FIR filter for each channel and zero out the taps
        std::vector<float> vtaps(0, d_int_rate);
        for(unsigned int i = 0; i < d_int_rate; i++) {
          d_filters[i] = new fir_filter_ccf(1, vtaps);
          d_diff_filters[i] = new fir_filter_ccf(1, vtaps);
        }

        // Now, actually set the filters' taps
        set_taps(taps);

        // Delay is based on number of taps per filter arm. Round to
        // the nearest integer.
        float delay = rate * (taps_per_filter() - 1.0) / 2.0;
        d_delay = static_cast<int>(boost::math::iround(delay));

        // This calculation finds the phase offset induced by the
        // arbitrary resampling. It's based on which filter arm we are
        // at the filter's group delay plus the fractional offset
        // between the samples. Calculated here based on the rotation
        // around nfilts starting at start_filter.
        float accum = d_delay * d_flt_rate;
        int   accum_int = static_cast<int>(accum);
        float accum_frac = accum - accum_int;
        int end_filter = static_cast<int>
          (boost::math::iround(fmodf(d_last_filter + d_delay * d_dec_rate + accum_int, \
                                     static_cast<float>(d_int_rate))));

        d_est_phase_change = d_last_filter - (end_filter + accum_frac);
      }

      pfb_arb_resampler_ccf::~pfb_arb_resampler_ccf()
      {
        for(unsigned int i = 0; i < d_int_rate; i++) {
          delete d_filters[i];
          delete d_diff_filters[i];
        }
      }

      void
      pfb_arb_resampler_ccf::create_taps(const std::vector<float> &newtaps,
                                         std::vector< std::vector<float> > &ourtaps,
                                         std::vector<fir_filter_ccf*> &ourfilter)
      {
        unsigned int ntaps = newtaps.size();
        d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate);

        // Create d_numchan vectors to store each channel's taps
        ourtaps.resize(d_int_rate);

        // Make a vector of the taps plus fill it out with 0's to fill
        // each polyphase filter with exactly d_taps_per_filter
        std::vector<float> tmp_taps;
        tmp_taps = newtaps;
        while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
          tmp_taps.push_back(0.0);
        }

        for(unsigned int i = 0; i < d_int_rate; i++) {
          // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
          ourtaps[i] = std::vector<float>(d_taps_per_filter, 0);
          for(unsigned int j = 0; j < d_taps_per_filter; j++) {
            ourtaps[i][j] = tmp_taps[i + j*d_int_rate];
          }

          // Build a filter for each channel and add it's taps to it
          ourfilter[i]->set_taps(ourtaps[i]);
        }
      }

      void
      pfb_arb_resampler_ccf::create_diff_taps(const std::vector<float> &newtaps,
                                              std::vector<float> &difftaps)
      {
        // Calculate the differential taps using a derivative filter
        std::vector<float> diff_filter(2);
        diff_filter[0] = -1;
        diff_filter[1] = 1;

        for(unsigned int i = 0; i < newtaps.size()-1; i++) {
          float tap = 0;
          for(unsigned int j = 0; j < diff_filter.size(); j++) {
            tap += diff_filter[j]*newtaps[i+j];
          }
          difftaps.push_back(tap);
        }
        difftaps.push_back(0);
      }

      void
      pfb_arb_resampler_ccf::set_taps(const std::vector<float> &taps)
      {
        std::vector<float> dtaps;
        create_diff_taps(taps, dtaps);
        create_taps(taps, d_taps, d_filters);
        create_taps(dtaps, d_dtaps, d_diff_filters);
      }

      std::vector<std::vector<float> >
      pfb_arb_resampler_ccf::taps() const
      {
        return d_taps;
      }

      void
      pfb_arb_resampler_ccf::print_taps()
      {
        unsigned int i, j;
        for(i = 0; i < d_int_rate; i++) {
          printf("filter[%d]: [", i);
          for(j = 0; j < d_taps_per_filter; j++) {
            printf(" %.4e", d_taps[i][j]);
          }
          printf("]\n");
        }
      }

      void
      pfb_arb_resampler_ccf::set_rate(float rate)
      {
        d_dec_rate = (unsigned int)floor(d_int_rate/rate);
        d_flt_rate = (d_int_rate/rate) - d_dec_rate;
      }

      void
      pfb_arb_resampler_ccf::set_phase(float ph)
      {
        if((ph < 0) || (ph >= 2.0*M_PI)) {
          throw std::runtime_error("pfb_arb_resampler_ccf: set_phase value out of bounds [0, 2pi).\n");
        }

        float ph_diff = 2.0*M_PI / (float)d_filters.size();
        d_last_filter = static_cast<int>(ph / ph_diff);
      }

      float
      pfb_arb_resampler_ccf::phase() const
      {
        float ph_diff = 2.0*M_PI / static_cast<float>(d_filters.size());
        return d_last_filter * ph_diff;
      }

      unsigned int
      pfb_arb_resampler_ccf::taps_per_filter() const
      {
        return d_taps_per_filter;
      }

      float
      pfb_arb_resampler_ccf::phase_offset(float freq, float fs)
      {
        float adj = (2.0*M_PI)*(freq/fs)/static_cast<float>(d_int_rate);
        return -adj * d_est_phase_change;
      }

      int
      pfb_arb_resampler_ccf::filter(gr_complex *output, gr_complex *input,
                                    int n_to_read, int &n_read)
      {
        int i_out = 0, i_in = 0;
        unsigned int j = d_last_filter;;
        gr_complex o0, o1;

        while(i_in < n_to_read) {
          // start j by wrapping around mod the number of channels
          while(j < d_int_rate) {
            // Take the current filter and derivative filter output
            o0 = d_filters[j]->filter(&input[i_in]);
            o1 = d_diff_filters[j]->filter(&input[i_in]);

            output[i_out] = o0 + o1*d_acc;     // linearly interpolate between samples
            i_out++;

            // Adjust accumulator and index into filterbank
            d_acc += d_flt_rate;
            j += d_dec_rate + (int)floor(d_acc);
            d_acc = fmodf(d_acc, 1.0);
          }
          i_in += (int)(j / d_int_rate);
          j = j % d_int_rate;
        }
        d_last_filter = j; // save last filter state for re-entry

        n_read = i_in;   // return how much we've actually read
        return i_out;    // return how much we've produced
      }

      /****************************************************************/

      pfb_arb_resampler_ccc::pfb_arb_resampler_ccc(float rate,
                                                   const std::vector<gr_complex> &taps,
                                                   unsigned int filter_size)
      {
        d_acc = 0; // start accumulator at 0

        /* The number of filters is specified by the user as the
           filter size; this is also the interpolation rate of the
           filter. We use it and the rate provided to determine the
           decimation rate. This acts as a rational resampler. The
           flt_rate is calculated as the residual between the integer
           decimation rate and the real decimation rate and will be
           used to determine to interpolation point of the resampling
           process.
        */
        d_int_rate = filter_size;
        set_rate(rate);

        d_last_filter = (taps.size()/2) % filter_size;

        d_filters = std::vector<fir_filter_ccc*>(d_int_rate);
        d_diff_filters = std::vector<fir_filter_ccc*>(d_int_rate);

        // Create an FIR filter for each channel and zero out the taps
        std::vector<gr_complex> vtaps(0, d_int_rate);
        for(unsigned int i = 0; i < d_int_rate; i++) {
          d_filters[i] = new fir_filter_ccc(1, vtaps);
          d_diff_filters[i] = new fir_filter_ccc(1, vtaps);
        }

        // Now, actually set the filters' taps
        set_taps(taps);

        // Delay is based on number of taps per filter arm. Round to
        // the nearest integer.
        float delay = rate * (taps_per_filter() - 1.0) / 2.0;
        d_delay = static_cast<int>(boost::math::iround(delay));

        // This calculation finds the phase offset induced by the
        // arbitrary resampling. It's based on which filter arm we are
        // at the filter's group delay plus the fractional offset
        // between the samples. Calculated here based on the rotation
        // around nfilts starting at start_filter.
        float accum = d_delay * d_flt_rate;
        int   accum_int = static_cast<int>(accum);
        float accum_frac = accum - accum_int;
        int end_filter = static_cast<int>
          (boost::math::iround(fmodf(d_last_filter + d_delay * d_dec_rate + accum_int, \
                                     static_cast<float>(d_int_rate))));

        d_est_phase_change = d_last_filter - (end_filter + accum_frac);
      }

      pfb_arb_resampler_ccc::~pfb_arb_resampler_ccc()
      {
        for(unsigned int i = 0; i < d_int_rate; i++) {
          delete d_filters[i];
          delete d_diff_filters[i];
        }
      }

      void
      pfb_arb_resampler_ccc::create_taps(const std::vector<gr_complex> &newtaps,
                                         std::vector< std::vector<gr_complex> > &ourtaps,
                                         std::vector<fir_filter_ccc*> &ourfilter)
      {
        unsigned int ntaps = newtaps.size();
        d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate);

        // Create d_numchan vectors to store each channel's taps
        ourtaps.resize(d_int_rate);

        // Make a vector of the taps plus fill it out with 0's to fill
        // each polyphase filter with exactly d_taps_per_filter
        std::vector<gr_complex> tmp_taps;
        tmp_taps = newtaps;
        while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
          tmp_taps.push_back(0.0);
        }

        for(unsigned int i = 0; i < d_int_rate; i++) {
          // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
          ourtaps[i] = std::vector<gr_complex>(d_taps_per_filter, 0);
          for(unsigned int j = 0; j < d_taps_per_filter; j++) {
            ourtaps[i][j] = tmp_taps[i + j*d_int_rate];
          }

          // Build a filter for each channel and add it's taps to it
          ourfilter[i]->set_taps(ourtaps[i]);
        }
      }

      void
      pfb_arb_resampler_ccc::create_diff_taps(const std::vector<gr_complex> &newtaps,
                                              std::vector<gr_complex> &difftaps)
      {
        // Calculate the differential taps using a derivative filter
        std::vector<gr_complex> diff_filter(2);
        diff_filter[0] = -1;
        diff_filter[1] = 1;

        for(unsigned int i = 0; i < newtaps.size()-1; i++) {
          gr_complex tap = 0;
          for(unsigned int j = 0; j < diff_filter.size(); j++) {
            tap += diff_filter[j]*newtaps[i+j];
          }
          difftaps.push_back(tap);
        }
        difftaps.push_back(0);
      }

      void
      pfb_arb_resampler_ccc::set_taps(const std::vector<gr_complex> &taps)
      {
        std::vector<gr_complex> dtaps;
        create_diff_taps(taps, dtaps);
        create_taps(taps, d_taps, d_filters);
        create_taps(dtaps, d_dtaps, d_diff_filters);
      }

      std::vector<std::vector<gr_complex> >
      pfb_arb_resampler_ccc::taps() const
      {
        return d_taps;
      }

      void
      pfb_arb_resampler_ccc::print_taps()
      {
        unsigned int i, j;
        for(i = 0; i < d_int_rate; i++) {
          printf("filter[%d]: [", i);
          for(j = 0; j < d_taps_per_filter; j++) {
            printf(" %.4e + j%.4e", d_taps[i][j].real(), d_taps[i][j].imag());
          }
          printf("]\n");
        }
      }

      void
      pfb_arb_resampler_ccc::set_rate(float rate)
      {
        d_dec_rate = (unsigned int)floor(d_int_rate/rate);
        d_flt_rate = (d_int_rate/rate) - d_dec_rate;
      }

      void
      pfb_arb_resampler_ccc::set_phase(float ph)
      {
        if((ph < 0) || (ph >= 2.0*M_PI)) {
          throw std::runtime_error("pfb_arb_resampler_ccc: set_phase value out of bounds [0, 2pi).\n");
        }

        float ph_diff = 2.0*M_PI / (float)d_filters.size();
        d_last_filter = static_cast<int>(ph / ph_diff);
      }

      float
      pfb_arb_resampler_ccc::phase() const
      {
        float ph_diff = 2.0*M_PI / static_cast<float>(d_filters.size());
        return d_last_filter * ph_diff;
      }

      unsigned int
      pfb_arb_resampler_ccc::taps_per_filter() const
      {
        return d_taps_per_filter;
      }

      float
      pfb_arb_resampler_ccc::phase_offset(float freq, float fs)
      {
        float adj = (2.0*M_PI)*(freq/fs)/static_cast<float>(d_int_rate);
        return -adj * d_est_phase_change;
      }

      int
      pfb_arb_resampler_ccc::filter(gr_complex *output, gr_complex *input,
                                    int n_to_read, int &n_read)
      {
        int i_out = 0, i_in = 0;
        unsigned int j = d_last_filter;;
        gr_complex o0, o1;

        while(i_in < n_to_read) {
          // start j by wrapping around mod the number of channels
          while(j < d_int_rate) {
            // Take the current filter and derivative filter output
            o0 = d_filters[j]->filter(&input[i_in]);
            o1 = d_diff_filters[j]->filter(&input[i_in]);

            output[i_out] = o0 + o1*d_acc;     // linearly interpolate between samples
            i_out++;

            // Adjust accumulator and index into filterbank
            d_acc += d_flt_rate;
            j += d_dec_rate + (int)floor(d_acc);
            d_acc = fmodf(d_acc, 1.0);
          }
          i_in += (int)(j / d_int_rate);
          j = j % d_int_rate;
        }
        d_last_filter = j; // save last filter state for re-entry

        n_read = i_in;   // return how much we've actually read
        return i_out;    // return how much we've produced
      }

      /****************************************************************/

      pfb_arb_resampler_fff::pfb_arb_resampler_fff(float rate,
                                                   const std::vector<float> &taps,
                                                   unsigned int filter_size)
      {
        d_acc = 0; // start accumulator at 0

        /* The number of filters is specified by the user as the
           filter size; this is also the interpolation rate of the
           filter. We use it and the rate provided to determine the
           decimation rate. This acts as a rational resampler. The
           flt_rate is calculated as the residual between the integer
           decimation rate and the real decimation rate and will be
           used to determine to interpolation point of the resampling
           process.
        */
        d_int_rate = filter_size;
        set_rate(rate);

        d_last_filter = (taps.size()/2) % filter_size;

        d_filters = std::vector<fir_filter_fff*>(d_int_rate);
        d_diff_filters = std::vector<fir_filter_fff*>(d_int_rate);

        // Create an FIR filter for each channel and zero out the taps
        std::vector<float> vtaps(0, d_int_rate);
        for(unsigned int i = 0; i < d_int_rate; i++) {
          d_filters[i] = new fir_filter_fff(1, vtaps);
          d_diff_filters[i] = new fir_filter_fff(1, vtaps);
        }

        // Now, actually set the filters' taps
        set_taps(taps);

        // Delay is based on number of taps per filter arm. Round to
        // the nearest integer.
        float delay = rate * (taps_per_filter() - 1.0) / 2.0;
        d_delay = static_cast<int>(boost::math::iround(delay));

        // This calculation finds the phase offset induced by the
        // arbitrary resampling. It's based on which filter arm we are
        // at the filter's group delay plus the fractional offset
        // between the samples. Calculated here based on the rotation
        // around nfilts starting at start_filter.
        float accum = d_delay * d_flt_rate;
        int   accum_int = static_cast<int>(accum);
        float accum_frac = accum - accum_int;
        int end_filter = static_cast<int>
          (boost::math::iround(fmodf(d_last_filter + d_delay * d_dec_rate + accum_int, \
                                     static_cast<float>(d_int_rate))));

        d_est_phase_change = d_last_filter - (end_filter + accum_frac);
      }

      pfb_arb_resampler_fff::~pfb_arb_resampler_fff()
      {
        for(unsigned int i = 0; i < d_int_rate; i++) {
          delete d_filters[i];
          delete d_diff_filters[i];
        }
      }

      void
      pfb_arb_resampler_fff::create_taps(const std::vector<float> &newtaps,
                                         std::vector< std::vector<float> > &ourtaps,
                                         std::vector<fir_filter_fff*> &ourfilter)
      {
        unsigned int ntaps = newtaps.size();
        d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate);

        // Create d_numchan vectors to store each channel's taps
        ourtaps.resize(d_int_rate);

        // Make a vector of the taps plus fill it out with 0's to fill
        // each polyphase filter with exactly d_taps_per_filter
        std::vector<float> tmp_taps;
        tmp_taps = newtaps;
        while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
          tmp_taps.push_back(0.0);
        }

        for(unsigned int i = 0; i < d_int_rate; i++) {
          // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
          ourtaps[i] = std::vector<float>(d_taps_per_filter, 0);
          for(unsigned int j = 0; j < d_taps_per_filter; j++) {
            ourtaps[i][j] = tmp_taps[i + j*d_int_rate];
          }

          // Build a filter for each channel and add it's taps to it
          ourfilter[i]->set_taps(ourtaps[i]);
        }
      }

      void
      pfb_arb_resampler_fff::create_diff_taps(const std::vector<float> &newtaps,
                                              std::vector<float> &difftaps)
      {
        // Calculate the differential taps using a derivative filter
        std::vector<float> diff_filter(2);
        diff_filter[0] = -1;
        diff_filter[1] = 1;

        for(unsigned int i = 0; i < newtaps.size()-1; i++) {
          float tap = 0;
          for(unsigned int j = 0; j < diff_filter.size(); j++) {
            tap += diff_filter[j]*newtaps[i+j];
          }
          difftaps.push_back(tap);
        }
        difftaps.push_back(0);
      }

      void
      pfb_arb_resampler_fff::set_taps(const std::vector<float> &taps)
      {
        std::vector<float> dtaps;
        create_diff_taps(taps, dtaps);
        create_taps(taps, d_taps, d_filters);
        create_taps(dtaps, d_dtaps, d_diff_filters);
      }

      std::vector<std::vector<float> >
      pfb_arb_resampler_fff::taps() const
      {
        return d_taps;
      }

      void
      pfb_arb_resampler_fff::print_taps()
      {
        unsigned int i, j;
        for(i = 0; i < d_int_rate; i++) {
          printf("filter[%d]: [", i);
          for(j = 0; j < d_taps_per_filter; j++) {
            printf(" %.4e", d_taps[i][j]);
          }
          printf("]\n");
        }
      }

      void
      pfb_arb_resampler_fff::set_rate(float rate)
      {
        d_dec_rate = (unsigned int)floor(d_int_rate/rate);
        d_flt_rate = (d_int_rate/rate) - d_dec_rate;
      }

      void
      pfb_arb_resampler_fff::set_phase(float ph)
      {
        if((ph < 0) || (ph >= 2.0*M_PI)) {
          throw std::runtime_error("pfb_arb_resampler_fff: set_phase value out of bounds [0, 2pi).\n");
        }

        float ph_diff = 2.0*M_PI / (float)d_filters.size();
        d_last_filter = static_cast<int>(ph / ph_diff);
      }

      float
      pfb_arb_resampler_fff::phase() const
      {
        float ph_diff = 2.0*M_PI / static_cast<float>(d_filters.size());
        return d_last_filter * ph_diff;
      }

      unsigned int
      pfb_arb_resampler_fff::taps_per_filter() const
      {
        return d_taps_per_filter;
      }

      float
      pfb_arb_resampler_fff::phase_offset(float freq, float fs)
      {
        float adj = (2.0*M_PI)*(freq/fs)/static_cast<float>(d_int_rate);
        return -adj * d_est_phase_change;
      }

      int
      pfb_arb_resampler_fff::filter(float *output, float *input,
                                    int n_to_read, int &n_read)
      {
        int i_out = 0, i_in = 0;
        unsigned int j = d_last_filter;;
        float o0, o1;

        while(i_in < n_to_read) {
          // start j by wrapping around mod the number of channels
          while(j < d_int_rate) {
            // Take the current filter and derivative filter output
            o0 = d_filters[j]->filter(&input[i_in]);
            o1 = d_diff_filters[j]->filter(&input[i_in]);

            output[i_out] = o0 + o1*d_acc;     // linearly interpolate between samples
            i_out++;

            // Adjust accumulator and index into filterbank
            d_acc += d_flt_rate;
            j += d_dec_rate + (int)floor(d_acc);
            d_acc = fmodf(d_acc, 1.0);
          }
          i_in += (int)(j / d_int_rate);
          j = j % d_int_rate;
        }
        d_last_filter = j; // save last filter state for re-entry

        n_read = i_in;   // return how much we've actually read
        return i_out;    // return how much we've produced
      }

    } /* namespace kernel */
  } /* namespace filter */
} /* namespace gr */


#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "Components.h"
#include <vector>
#include "Object.h"
#include <fstream>
#include <string>
#include "Transform.hpp"

#include <GL/glu.h>
#include <GLFW/glfw3.h>
#include <armadillo>

//Vectors that will be used as auxiliaries to send them to the figures.
vector <Vertex> verts;
vector<Edge> edgs;
vector<Face>fcs;
vector<Object> models;

//function prototypes
void readFile(string* nombre, string* archivo, string enter);
int paintModels2();
int inicializacion(GLFWwindow* window);
vector <Vertex> bezier(double x);
int main(int argc, char** argv)
{
	//Variables that will be used as auxiliaries to temporarily save the data and then send them to the figures
	string nombre;
	string archivo;
	readFile(&nombre, &archivo, "BMX.obj");
	Object model = Object(nombre, archivo, verts, edgs, fcs);
	models.push_back(model);
	nombre = "";archivo = "";verts.clear();edgs.clear();fcs.clear();
	paintModels2();

	return 0;
}//main (END).

/*The following function reads the data of the obj file receiving as parameters nombre and archivo these are by reference and
  an enter string that is the name of the file to read this goes by value.*/
void readFile(string* nombre, string* archivo, string enter) {
	char cadena[500];
	float a, b, c;
	int d, e, f, aux = 0;
	string dcadena, ecadena, fcadena;
	int indiVer = 1;
	ifstream fe(enter);
	fe >> cadena;
	//Assign the file name to the archivo variable
	*archivo = cadena;
	fe >> cadena;
	fe >> cadena;
	fe >> cadena;
	//Assign the name to the nombre variable
	*nombre = cadena;
	//While not end of file
	while (!fe.eof()) {
		fe >> cadena;
		//Verify that only vertices are read
		if (cadena[1] != 'n' && fe.eof() == 0 && cadena[0] == 'v') {
			fe >> cadena;
			a = atof(cadena);
			fe >> cadena;
			b = atof(cadena);
			fe >> cadena;
			c = atof(cadena);
			//A temporary vertex is created and added to the array of vertices.
			Vertex v(a, b, c, indiVer);
			verts.push_back(v);
			indiVer++;
		}
		//Verify that only the faces are read.
		else if (cadena[1] != 'n' && fe.eof() == 0 && cadena[0] == 'f') {
			vector<Vertex> vertic;
			vector<Edge> edgaux;
			fe >> cadena;
			d = atof(cadena);
			vertic.push_back(verts[d - 1]);
			fe >> cadena;
			e = atof(cadena);
			vertic.push_back(verts[e - 1]);
			fe >> cadena;
			f = atof(cadena);
			vertic.push_back(verts[f - 1]);
			//The three edges are deducted and added to the edge vector.
			Edge j(verts[d - 1], verts[e - 1]);
			Edge k(verts[e - 1], verts[f - 1]);
			Edge l(verts[f - 1], verts[d - 1]);
			edgs.push_back(j);
			edgs.push_back(k);
			edgs.push_back(l);
			//Those same edges are sent to the edgaux temporary vector that will be sent to the face that will be formed by a vector of vertices and one of edges.
			edgaux.push_back(j);
			edgaux.push_back(k);
			edgaux.push_back(l);
			Face fac(vertic, edgaux);
			fcs.push_back(fac);
		}
		else
		{
			fe >> cadena;
			fe >> cadena;
			fe >> cadena;
		}
	}
	fe.close();
}

int paintModels2() {
	arma::frowvec eye = { 0.0, 0.0, 10.0 };
	arma::frowvec camera = { 0.0, 0.0, 0.0 };

	if (!glfwInit())
	{
		fprintf(stderr, "Fallo al inicializar GLFW\n");
		getchar();
		return -1;
	}
	GLFWwindow* window;
	window = glfwCreateWindow(1024, 768, "Motocicleta Freestyle", NULL, NULL);
	if (window == NULL) {
		fprintf(stderr, "Fallo al abrir la ventana de GLFW.\n");
		getchar();
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetInputMode(window, GLFW_STICKY_KEYS,GL_TRUE);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

	//  Proyecciones
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	int width, height;
	glfwGetFramebufferSize(window, &width, &height);
	float ar = width / height;

	//  Proyecci�n en paralelo
	glViewport(0, 0, width, height);
	glOrtho(-ar, ar, -1.0, 1.0, -20.0, 20.0);
	//  Proyecci�n en perspectiva
	//    glFrustum(-ar, ar, -ar, ar, 2.0, 4.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	Transform Tr = Transform();
	double t_angle = 0.0f;
	int cont = 0;
	int bcont = 0;
	double dt = 13.0;
	std::vector< Vertex > p_vertices;
	for (int f = 0; f < models[0].getSizevectorface();f++) {
		//Cycle to pass each vertex
		for (int v = 0;v < 3;v++) {
			p_vertices.push_back(models[0].getFace(f).getVert(v));
		}
	}

	vector <Vertex> vet = bezier(1.0);
	do {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		/*gluLookAt(eye[0], eye[1], eye[2],
			camera[0], camera[1], camera[2],
			0.0, 1.0, 0.0);*/

	    // Dibujar la moto
		arma::dmat transd;
		if (dt > 1) {
			transd = Tr.S(0.05, 0.05, 0.05) * Tr.R(0.0, 0.5, 0.0, 180.0) * Tr.T(dt, 0.0, 0.0);
			dt -= 0.3;
		}
		else{
			if (bcont < 20)
			{
				transd = Tr.S(0.05, 0.05, 0.05) * Tr.R(0.0, 0.5, 0.0, 180.0) * Tr.T(vet[bcont].getX(), vet[bcont].getY(), vet[bcont].getZ());
				dt = vet[bcont].getX();
				bcont++;
			}
			else {

				transd = Tr.S(0.05, 0.05, 0.05) * Tr.R(0.0, 0.5, 0.0, 180.0) * Tr.T(dt, 0.0, 0.0);
				dt -= 0.3;
			}
		}

		std::vector< Vertex > moto_vertices;
		for (unsigned int i = 0; i < p_vertices.size(); i++) {
			arma::dcolvec v = p_vertices[i].h();
			arma::dcolvec vp = transd * v;
			Vertex rv = Vertex();
			rv.set_value(arma::trans(vp));
			moto_vertices.push_back(rv);
		}
		glColor3f(1.0, 1.0, 0.0);
		glBegin(GL_TRIANGLES);
		for (unsigned int i = 0; i < moto_vertices.size(); i++) {
			glVertex3d(moto_vertices[i].getX(), moto_vertices[i].getY(), moto_vertices[i].getZ());
		}
		glEnd();

		glfwSwapBuffers(window);
		glfwPollEvents();

	} while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
		glfwWindowShouldClose(window) == 0);

	glfwTerminate();
	return 0;
}

vector <Vertex> bezier(double x) {

	vector<Vertex> vertic;
	arma::dmat MB = { {-1.0, 3.0, -3.0, 1.0},
				  {3.0, -6.0, 3.0, 0.0},
				  {-3.0, 3.0, 0.0, 0.0},
				  {1.0, 0.0, 0.0, 0.0} };
	//MH.print();

	//cout << endl;

	arma::dmat GH = { {x, 0.0, 0.0},
					  {-1.0, 5.0, 0.0},
					  {-3.0,4.0,0.0},
					  {-5.0, 0.0, 0.0} };
	//GH.print();

	double dt = 0.05;
	arma::dmat Qt;
	for (double t = 0.0; t <= 1.0 + dt; t += dt) {
		arma::drowvec T = { powf(t, 3.0), powf(t,2.0), t, 1.0 };
		Qt = T * MB * GH;
		Qt.print();
		Vertex vert(Qt[0], Qt[1], Qt[2], 1.0);
		vertic.push_back(vert);
	}
	return vertic;
}


	/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Core/Algorithms/Base/AlgorithmPreconditions.h>
#include <Core/GeometryPrimitives/Point.h>
#include <Core/GeometryPrimitives/Vector.h>
#include <Core/Datatypes/DenseMatrix.h>
#include <Core/Algorithms/BrainStimulator/ElectrodeCoilSetupAlgorithm.h>
#include <Core/Algorithms/Legacy/Fields/DistanceField/CalculateSignedDistanceField.h>
#include <Core/Algorithms/Legacy/Fields/FieldData/ConvertFieldBasisType.h>
#include <Core/Algorithms/Legacy/Fields/FieldData/GetFieldData.h>
#include <Core/Algorithms/Legacy/Fields/MeshDerivatives/SplitByConnectedRegion.h>
#include <Core/Algorithms/Legacy/Fields/DomainFields/SplitFieldByDomainAlgo.h>
#include <Core/Algorithms/Legacy/Fields/MeshDerivatives/GetFieldBoundaryAlgo.h>
#include <Core/Algorithms/Legacy/Fields/MeshData/GetMeshNodes.h>
#include <Core/Datatypes/Legacy/Field/Field.h>
#include <Core/Datatypes/Legacy/Field/VField.h>
#include <Core/Datatypes/Legacy/Field/VMesh.h>
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Datatypes/Matrix.h>
#include <Core/Datatypes/MatrixTypeConversions.h>
#include <Core/Datatypes/MatrixComparison.h>
#include <string>
#include <boost/range/algorithm/count.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/format.hpp>
#include <boost/assign.hpp>
#include <math.h>
#include <Core/Math/MiscMath.h>
#include <iostream>

using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core::Algorithms::BrainStimulator;
using namespace SCIRun::Core::Algorithms::Fields;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Core::Geometry;
using namespace SCIRun;
using namespace boost;
using namespace boost::assign;
using namespace  Eigen;

ALGORITHM_PARAMETER_DEF(BrainStimulator, NumberOfPrototypes);
ALGORITHM_PARAMETER_DEF(BrainStimulator, TableValues);
ALGORITHM_PARAMETER_DEF(BrainStimulator, ProtoTypeInputCheckbox);
ALGORITHM_PARAMETER_DEF(BrainStimulator, AllInputsTDCS);
ALGORITHM_PARAMETER_DEF(BrainStimulator, ProtoTypeInputComboBox);
ALGORITHM_PARAMETER_DEF(BrainStimulator, ElectrodethicknessCheckBox);
ALGORITHM_PARAMETER_DEF(BrainStimulator, ElectrodethicknessSpinBox);

const AlgorithmOutputName ElectrodeCoilSetupAlgorithm::FINAL_ELECTRODES_FIELD("FINAL_ELECTRODES_FIELD");
const AlgorithmOutputName ElectrodeCoilSetupAlgorithm::MOVED_ELECTRODES_FIELD("MOVED_ELECTRODES_FIELD");
const AlgorithmInputName ElectrodeCoilSetupAlgorithm::SCALP_SURF("SCALP_SURF");
const AlgorithmInputName ElectrodeCoilSetupAlgorithm::ELECTRODECOILPROTOTYPES("ELECTRODECOILPROTOTYPES");
const AlgorithmOutputName ElectrodeCoilSetupAlgorithm::ELECTRODE_SPONGE_LOCATION_AVR("ELECTRODE_SPONGE_LOCATION_AVR");
const AlgorithmOutputName ElectrodeCoilSetupAlgorithm::COILS_FIELD("COILS_FIELD");
const AlgorithmInputName ElectrodeCoilSetupAlgorithm::LOCATIONS("LOCATIONS");

const int ElectrodeCoilSetupAlgorithm::unknown_stim_type = 0;
const int ElectrodeCoilSetupAlgorithm::TMS_stim_type     = 1;
const int ElectrodeCoilSetupAlgorithm::tDCS_stim_type    = 2;
const double ElectrodeCoilSetupAlgorithm::direction_bound = -0.99;

const AlgorithmParameterName ElectrodeCoilSetupAlgorithm::columnNames[] =
{ Name("Input #"),
Name("Type"),
Name("X"),
Name("Y"),
Name("Z"),
Name("Angle"),
Name("NX"),
Name("NY"),
Name("NZ"),
Name("thickness")
};

ElectrodeCoilSetupAlgorithm::ElectrodeCoilSetupAlgorithm()
{
 using namespace Parameters;
 {
  addParameter(MOVED_ELECTRODES_FIELD, 0);
  addParameter(NumberOfPrototypes, 0);
  addParameter(TableValues, 0);
  addParameter(ProtoTypeInputCheckbox, false);
  addParameter(ProtoTypeInputComboBox, false);
  addParameter(AllInputsTDCS, false);
  addParameter(ElectrodethicknessCheckBox, false);
  addParameter(ElectrodethicknessSpinBox, 1.0);
 }
}

VariableHandle ElectrodeCoilSetupAlgorithm::fill_table(FieldHandle scalp, DenseMatrixHandle locations, const std::vector<FieldHandle>& input) const
{
  Variable::List table;
  if (locations->ncols()!=3)
  {
   THROW_ALGORITHM_PROCESSING_ERROR(" LOCATIONS needs to have dimensions such as: (#CoilsOrElectrodes) x 3 ");
  }

  auto tab_values = get(Parameters::TableValues).toVector();

  for (int i=0;i<locations->nrows();i++)
  {

   Variable::List tmp;

   if (tab_values.size()<locations->nrows())
   {
   tmp +=
     Variable(columnNames[0], boost::str(boost::format("%s") % "0")),
     Variable(columnNames[1], boost::str(boost::format("%s") % "0")),
     Variable(columnNames[2], boost::str(boost::format("%.3f") % (* locations)(i,0))),
     Variable(columnNames[3], boost::str(boost::format("%.3f") % (* locations)(i,1))),
     Variable(columnNames[4], boost::str(boost::format("%.3f") % (* locations)(i,2))),
     Variable(columnNames[5], boost::str(boost::format("???"))),
     Variable(columnNames[6], std::string("???")),
     Variable(columnNames[7], std::string("???")),
     Variable(columnNames[8], std::string("???")),
     Variable(columnNames[9], std::string("???"));

   } else
   {
      auto col = tab_values[i].toVector();

     if (col.size()==number_of_columns)
     {
      std::string str1=col[0].toString();
      std::string str2=col[1].toString();
      std::string str3=col[2].toString();
      std::string str4=col[3].toString();
      std::string str5=col[4].toString();
      std::string str6=col[5].toString();
      std::string str7=col[6].toString();
      std::string str8=col[7].toString();
      std::string str9=col[8].toString();
      std::string str10=col[9].toString();

      Variable var1=makeVariable("Input #", boost::str(boost::format("%s") % str1));
      Variable var2=makeVariable("Type",   boost::str(boost::format("%s") % str2));

      Variable var3,var4,var5;

      if (str3.compare("???")==0)
       var3=makeVariable("X",     boost::str(boost::format("%.3f") % (* locations)(i,0)));
        else
         var3=makeVariable("X",   boost::str(boost::format("%s") % str3));

      if (str4.compare("???")==0)
       var4=makeVariable("Y",     boost::str(boost::format("%.3f") % (* locations)(i,1)));
	else
	 var4=makeVariable("Y",   boost::str(boost::format("%s") % str4));

      if (str5.compare("???")==0)
       var5=makeVariable("Y",     boost::str(boost::format("%.3f") % (* locations)(i,2)));
	else
         var5=makeVariable("Z",   boost::str(boost::format("%s") % str5));

      Variable var6=makeVariable("Angle",  boost::str(boost::format("%s") % str6));

      ///if this table row was selected as tDCS -> project point to scalp surface and put its normal in table (NX,NY,NZ)
      Variable var7=makeVariable("NX", boost::str(boost::format("%s") % str7));
      Variable var8=makeVariable("NY", boost::str(boost::format("%s") % str8));
      Variable var9=makeVariable("NZ", boost::str(boost::format("%s") % str9));
      Variable var10=makeVariable("thickness",boost::str(boost::format("%s") % str10));
      tmp += var1,var2,var3,var4,var5,var6,var7,var8,var9,var10;

     }
   }

   table.push_back(makeVariable("row" + boost::lexical_cast<std::string>(i), tmp));
  }
  VariableHandle output(new Variable(Name("Table"), table));

  return output;
}

DenseMatrixHandle ElectrodeCoilSetupAlgorithm::make_rotation_matrix(const double angle, const std::vector<double>& normal) const
{
 DenseMatrixHandle result(new DenseMatrix(3, 3));

  double normal_vector_norm=sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]);
  Vector3d normal_vector((double)normal[0]/normal_vector_norm, (double)normal[1]/normal_vector_norm, (double)normal[2]/normal_vector_norm);

  Vector3d tan_vector1, tan_vector2;
  if (normal_vector(0)!=0 || normal_vector(2)!=0)
  {
   tan_vector1(0)= normal_vector(2);
   tan_vector1(1)= 0.0;
   if (normal_vector(0)==0)
    tan_vector1(2) = 0.0;
     else
       tan_vector1(2)= -1*normal_vector(0);
   } else
  {
   tan_vector1(0)= normal_vector(1);
   tan_vector1(1)= 0.0;
   tan_vector1(2)= 0.0;
  }

 normal_vector_norm=sqrt(tan_vector1(0)*tan_vector1(0)+tan_vector1(1)*tan_vector1(1)+tan_vector1(2)*tan_vector1(2));
 tan_vector1(0)/=normal_vector_norm; tan_vector1(1)/=normal_vector_norm; tan_vector1(2)/=normal_vector_norm;
 tan_vector2 = normal_vector.cross(tan_vector1);
 normal_vector_norm=sqrt(tan_vector2(0)*tan_vector2(0)+tan_vector2(1)*tan_vector2(1)+tan_vector2(2)*tan_vector2(2));
 tan_vector2(0)/=normal_vector_norm; tan_vector2(1)/=normal_vector_norm; tan_vector2(2)/=normal_vector_norm;
 DenseMatrixHandle rotation_matrix2;
 Matrix3d rotation_matrix(3,3), rotation_matrix1(3,3);

 (*result)(0,2)=normal_vector(0);
 (*result)(1,2)=normal_vector(1);
 (*result)(2,2)=normal_vector(2);
 (*result)(0,1)=tan_vector2(0);
 (*result)(1,1)=tan_vector2(1);
 (*result)(2,1)=tan_vector2(2);
 (*result)(0,0)=tan_vector1(0);
 (*result)(1,0)=tan_vector1(1);
 (*result)(2,0)=tan_vector1(2);

 return result;
}

DenseMatrixHandle ElectrodeCoilSetupAlgorithm::make_rotation_matrix_around_axis(double angle, std::vector<double>& axis_vector) const
{
   DenseMatrixHandle result(new DenseMatrix(3, 3));

   angle = angle * M_PI / 180.0;
   double cos_angle = cos(angle);
   double sin_angle = sin(angle);
   double ux=axis_vector[0],uy=axis_vector[1], uz=axis_vector[2];
   (*result)(0,0)=cos_angle+ux*ux*(1-cos_angle);
   (*result)(0,1)=ux*uy*(1-cos_angle)-uz*sin_angle;
   (*result)(0,2)=ux*uz*(1-cos_angle)+uy*sin_angle;
   (*result)(1,0)=uy*ux*(1-cos_angle)+uz*sin_angle;
   (*result)(1,1)=cos_angle+uy*uy*(1-cos_angle);
   (*result)(1,2)=uy*uz*(1-cos_angle)-ux*sin_angle;
   (*result)(2,0)=uz*ux*(1-cos_angle)-uy*sin_angle;
   (*result)(2,1)=uz*uy*(1-cos_angle)+ux*sin_angle;
   (*result)(2,2)=cos_angle+uz*uz*(1-cos_angle);

  return result;
}

FieldHandle ElectrodeCoilSetupAlgorithm::make_tms(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& coil_prototyp_map, const std::vector<double>& coil_x, const std::vector<double>& coil_y, const std::vector<double>& coil_z, const std::vector<double>& coil_angle_rotation, const std::vector<double>& coil_nx, const std::vector<double>& coil_ny, const std::vector<double>& coil_nz) const
{
  FieldInformation fieldinfo("PointCloudMesh", 0, "Vector");
  FieldHandle tms_coils_field = CreateField(fieldinfo);
  VMesh* tms_coils_vmesh = tms_coils_field->vmesh();
  VField* tms_coils_vfld  = tms_coils_field->vfield();
  std::vector<Point> tms_coils_field_values;

  for (int i=0; i<coil_prototyp_map.size(); i++)
  {
   if (coil_prototyp_map[i]<=elc_coil_proto.size() && coil_prototyp_map[i]>=0)
   {
    if( !(coil_x.size()-1>=i && coil_y.size()-1>=i && coil_z.size()-1>=i))
     {
       THROW_ALGORITHM_PROCESSING_ERROR("Internal error: definition of coil (x,y,z) seems to be empty.");
     }

    /// 1) move coil to predetermined position and orientation
    FieldHandle coil_fld = elc_coil_proto[coil_prototyp_map[i]-1];
    if (!coil_fld)
    {
      THROW_ALGORITHM_PROCESSING_ERROR("Internal error: coil field .");
    }

    FieldInformation fi(coil_fld);
    if(fi.is_pointcloudmesh())
    {
     GetFieldDataAlgo algo_getfielddata;
     DenseMatrixHandle fielddata;
     try
     {
      fielddata  = algo_getfielddata.run(coil_fld);
     }
     catch (...)
     {
     }

     GetMeshNodesAlgo algo_getfieldnodes;
     DenseMatrixHandle fieldnodes;
     try
     {
      algo_getfieldnodes.run(coil_fld,fieldnodes);
     }
     catch (...)
     {
      THROW_ALGORITHM_PROCESSING_ERROR("Internal error: could not retrieve positions from  ");
     }

     DenseMatrixHandle magnetic_dipoles(boost::make_shared<DenseMatrix>(fielddata->nrows(),3));

     /// subtract the mean from the coil positions to move them accourding to GUI table entries
     double mean_loc_x=0,mean_loc_y=0,mean_loc_z=0;
     for(int j=0; j<fieldnodes->nrows(); j++)
     {
      mean_loc_x+=(*fieldnodes)(j,0);
      mean_loc_y+=(*fieldnodes)(j,1);
      mean_loc_z+=(*fieldnodes)(j,2);
     }
     mean_loc_x/=fieldnodes->nrows();
     mean_loc_y/=fieldnodes->nrows();
     mean_loc_z/=fieldnodes->nrows();

     for(int j=0; j<fieldnodes->nrows(); j++)
     {
      (*fieldnodes)(j,0)-=mean_loc_x;
      (*fieldnodes)(j,1)-=mean_loc_y;
      (*fieldnodes)(j,2)-=mean_loc_z;
     }

     /// 2) create normals and rotate if needed
     if (coil_nx.size()-1>=i && coil_ny.size()-1>=i && coil_nz.size()-1>=i && coil_angle_rotation.size()-1>=i)
     {
      double angle = coil_angle_rotation[i];
      DenseMatrixHandle rotation_matrix,rotation_matrix1,rotation_matrix2;
      // 2.1) create rotation matrices
      std::vector<double> coil_vector;
      coil_vector.push_back(coil_nx[i]);
      coil_vector.push_back(coil_ny[i]);
      coil_vector.push_back(coil_nz[i]);

      rotation_matrix1 = make_rotation_matrix(angle, coil_vector);

      if (angle!=0) /// test it !
      {
       std::vector<double> axis;
       axis.push_back(coil_nx[i]);
       axis.push_back(coil_ny[i]);
       axis.push_back(coil_nz[i]);
       rotation_matrix2 = make_rotation_matrix_around_axis(angle, axis);
       rotation_matrix = boost::make_shared<DenseMatrix>((*rotation_matrix2) * (*rotation_matrix1));
      }

      /// 2.2) apply rotation and move points
      for(int j=0; j<fieldnodes->nrows(); j++)
      {
       if(coil_x.size()-1>=i && coil_y.size()-1>=i && coil_z.size()-1>=i)
       {
        DenseMatrixHandle pos_vec (boost::make_shared<DenseMatrix>(3,1));

       (*pos_vec)(0,0)=(*fieldnodes)(j,0);
       (*pos_vec)(1,0)=(*fieldnodes)(j,1);
       (*pos_vec)(2,0)=(*fieldnodes)(j,2);

       DenseMatrixHandle rotated_positions;

       if (angle==0)
        rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix1) * (*pos_vec));
	 else
	   rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix) * (*pos_vec));

       (*fieldnodes)(j,0)=(*rotated_positions)(0,0)+coil_x[i];
       (*fieldnodes)(j,1)=(*rotated_positions)(1,0)+coil_y[i];
       (*fieldnodes)(j,2)=(*rotated_positions)(2,0)+coil_z[i];

      } else
      {
       THROW_ALGORITHM_PROCESSING_ERROR("Internal error: definition of coil (x,y,z) seems to be empty.");
      }
    }

   /// 2.3) use normal as magnetic dipole orientation if there are no normals defined at prototyp
   if(coil_nx.size()-1>=i && coil_ny.size()-1>=i && coil_nz.size()-1>=i)
    {
     if(fielddata->ncols()==1) /// if there are no dipoles but only scalar values use GUI normal
     {
      for (int j=0; j<fielddata->nrows(); j++)
      {
       (*magnetic_dipoles)(j,0)=(*fielddata)(j,0)*coil_nx[i];
       (*magnetic_dipoles)(j,1)=(*fielddata)(j,0)*coil_ny[i];
       (*magnetic_dipoles)(j,2)=(*fielddata)(j,0)*coil_nz[i];
      }
     } else
      if(fielddata->ncols()==3) /// roatate magnetic dipoles
      {
       for (int j=0; j<fielddata->nrows(); j++)
       {
    	 DenseMatrixHandle pos_vec(boost::make_shared<DenseMatrix>(3,1));
         (*pos_vec)(0,0)=(*fielddata)(j,0);
         (*pos_vec)(1,0)=(*fielddata)(j,1);
         (*pos_vec)(2,0)=(*fielddata)(j,2);

	 DenseMatrixHandle rotated_positions;
	 if (angle==0 || IsNan(angle))
	 {
          rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix1) * (*pos_vec));
	 }
	   else
	     rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix) * (*pos_vec));

 	(*magnetic_dipoles)(j,0)=(*rotated_positions)(0,0);
	(*magnetic_dipoles)(j,1)=(*rotated_positions)(1,0);
	(*magnetic_dipoles)(j,2)=(*rotated_positions)(2,0);
       }
      }
      if (fielddata->ncols()!=3)
      {
       std::ostringstream ostr4;
       ostr4 << " Trying to generate magnetic dipoles for TMS coil defined in table row " << i+1 << " could not find any prototyp normals - using (NX,NY,NZ) from GUI instead! " << std::endl;
       remark(ostr4.str());
      }
    }
   } else
   {
     THROW_ALGORITHM_PROCESSING_ERROR("Internal error: coil normals or coil prototype or coil angle rotation did not make it to algorithm. ");
   }

    /// 4) join coil to output coil Field
    for (VMesh::index_type j=0; j<fieldnodes->nrows(); j++)
    {
      Point p((*fieldnodes)(j,0),(*fieldnodes)(j,1),(*fieldnodes)(j,2));
      tms_coils_vmesh->add_point(p);
      Point vec((*magnetic_dipoles)(j,0),(*magnetic_dipoles)(j,1),(*magnetic_dipoles)(j,2));
      tms_coils_field_values.push_back(vec);
    }
   } else
   {
     std::ostringstream ostr3;
     ostr3 << " TMS coil definition for " << i+1 << ". row needs be a point cloud (with defined scalar or vectors data)." << std::endl;
     remark(ostr3.str());
     continue;
   }
  } else
  {
     THROW_ALGORITHM_PROCESSING_ERROR("Internal error: coil definition inconsistent. ");
  }
 }

  VMesh::Node::iterator it, it_end;
  tms_coils_vmesh->begin(it);
  tms_coils_vmesh->end(it_end);
  index_type j = 0;
  tms_coils_vfld->resize_values();
  while (it!=it_end)
  {
   Vector vec(tms_coils_field_values[j].x(),tms_coils_field_values[j].y(),tms_coils_field_values[j].z());
   tms_coils_vfld->set_value(vec,*it);
   j++;
   ++it;
  }

  return tms_coils_field;
}

boost::tuple<Variable::List,double, double, double> ElectrodeCoilSetupAlgorithm::make_table_row(int i, double x, double y, double z, double nx, double ny, double nz) const
{
 Variable::List tmp;
 double out_nx, out_ny, out_nz;
 auto tab_values = get(Parameters::TableValues).toVector();
 auto col = tab_values[i].toVector();
 std::string str1=col[0].toString();
 std::string str2=col[1].toString();
 std::string str3=col[2].toString();
 std::string str4=col[3].toString();
 std::string str5=col[4].toString();
 std::string str6=col[5].toString();

 std::string str7=col[6].toString();
 std::string str8=col[7].toString();
 std::string str9=col[8].toString();

 std::string str10=col[9].toString();

 if (str7.compare("???")==0)
 {
  str7 = boost::str(boost::format("%.3f") % nx);
  out_nx=nx;
 } else
 {
  try
  {
   out_nx = boost::lexical_cast<double>(col[6].toString());
  } catch(bad_lexical_cast&) { }
 }

 if (str8.compare("???")==0)
 {
  str8 = boost::str(boost::format("%.3f") % ny);
  out_ny=ny;
 } else
 {
  try
  {
   out_ny = boost::lexical_cast<double>(col[7].toString());
  } catch(bad_lexical_cast&) { }
 }

 if (str9.compare("???")==0)
 {
  str9 = boost::str(boost::format("%.3f") % nz);
  out_nz=nz;
 } else
 {
  try
  {
   out_nz = boost::lexical_cast<double>(col[8].toString());
  } catch(bad_lexical_cast&) { }
 }

 Variable var1=makeVariable("Input #", boost::str(boost::format("%s") % str1));
 Variable var2=makeVariable("Type",   boost::str(boost::format("%s") % str2));

 Variable var3,var4,var5;

 if (str3.compare("???")==0)
  var3=makeVariable("X",     boost::str(boost::format("%.3f") % x));
  else
    var3=makeVariable("X",   boost::str(boost::format("%s") % str3));

 if (str4.compare("???")==0)
  var4=makeVariable("Y",     boost::str(boost::format("%.3f") % y));
   else
    var4=makeVariable("Y",   boost::str(boost::format("%s") % str4));

 if (str5.compare("???")==0)
  var5=makeVariable("Y",     boost::str(boost::format("%.3f") % z));
   else
    var5=makeVariable("Z",   boost::str(boost::format("%s") % str5));

 Variable var6=makeVariable("Angle",  boost::str(boost::format("%s") % str6));

 ///if this table row was selected as tDCS -> project point to scalp surface and put its normal in table (NX,NY,NZ)
 Variable var7=makeVariable("NX", boost::str(boost::format("%s") % str7));
 Variable var8=makeVariable("NY", boost::str(boost::format("%s") % str8));
 Variable var9=makeVariable("NZ", boost::str(boost::format("%s") % str9));

 Variable var10=makeVariable("thickness",boost::str(boost::format("%s") % str10));
 tmp += var1,var2,var3,var4,var5,var6,var7,var8,var9,var10;

 return boost::make_tuple(tmp, out_nx, out_ny, out_nz);
}

boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle, VariableHandle> ElectrodeCoilSetupAlgorithm::make_tdcs_electrodes(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& elc_prototyp_map, const std::vector<double>& elc_x, const std::vector<double>& elc_y, const std::vector<double>& elc_z, const std::vector<double>& elc_angle_rotation, const std::vector<double>& elc_thickness, VariableHandle table) const
{
 int nr_elc_sponge_triangles=0, num_valid_electrode_definition=0, nr_elc_sponge_triangles_on_scalp=0;
 std::vector<double> field_values, field_values_elc_on_scalp;
 std::vector<int> valid_electrode_definition;
 FieldInformation fieldinfo("TriSurfMesh", CONSTANTDATA_E, "int");
 FieldHandle electrode_field = CreateField(fieldinfo);
 VMesh* tdcs_vmesh = electrode_field->vmesh();
 VField* tdcs_vfld  = electrode_field->vfield();
 FieldInformation fieldinfo3("TriSurfMesh", CONSTANTDATA_E, "int");
 FieldHandle output = CreateField(fieldinfo3);
 VMesh* output_vmesh = output->vmesh();
 VField* output_vfld = output->vfield();
 Variable::List new_table;
 DenseMatrixHandle elc_sponge_locations;
 auto tab_values = get(Parameters::TableValues).toVector();
 bool flip_normal=false;
 if (tab_values.size()==elc_prototyp_map.size() && elc_thickness.size()==elc_prototyp_map.size() && elc_x.size()==elc_prototyp_map.size() && elc_y.size()==elc_prototyp_map.size() && elc_z.size()==elc_prototyp_map.size() && elc_angle_rotation.size()==elc_prototyp_map.size())
 {
  VMesh* scalp_vmesh = scalp->vmesh();
  VField* scalp_vfld = scalp->vfield();
  valid_electrode_definition.resize(elc_prototyp_map.size());
  for (int i=0; i<elc_prototyp_map.size(); i++)
  {
   if (elc_thickness[i]<=0 || IsNan(elc_thickness[i]))
   {
    continue;
   }
   double distance=0;
   bool skip_current_iteration=false;
   VMesh::Node::index_type didx;
   Point elc(elc_x[i],elc_y[i],elc_z[i]),r;
   scalp_vmesh->synchronize(Mesh::NODE_LOCATE_E);
   scalp_vmesh->find_closest_node(distance,r,didx,elc);  /// project GUI (x,y,z) onto scalp and ...
   Vector norm;
   scalp_vmesh->synchronize(Mesh::NORMALS_E);
   scalp_vmesh->get_normal(norm,didx); /// ... get its normal
   //update GUI table normals
   double nx,ny,nz;
   Variable::List new_row;
   boost::tie(new_row,nx,ny,nz)=make_table_row(i,elc_x[i],elc_y[i],elc_z[i],norm.x(),norm.y(),norm.z());
   new_table.push_back(makeVariable("row" + boost::lexical_cast<std::string>(i), new_row));
   if (!(nx==0.0 && ny==0.0 && nz==0.0))
   {
    Vector norm2(nx,ny,nz);
    double dot_product=Dot(norm, norm2);
    norm = Vector(nx,ny,nz);
    if (dot_product<direction_bound)
    {
      flip_normal=true;
    }
   }

   /// move coil prototype to projected location
   /// first, compute the transfer matrices
   std::vector<double> axis;
   axis.push_back(norm[0]);
   axis.push_back(norm[1]);
   axis.push_back(norm[2]);
   double angle=elc_angle_rotation[i];
   DenseMatrixHandle rotation_matrix,rotation_matrix1,rotation_matrix2;
   rotation_matrix1 = make_rotation_matrix(angle, axis);
   if (elc_angle_rotation[i]!=0)
   {
    rotation_matrix2 = make_rotation_matrix_around_axis(angle, axis);
    rotation_matrix = boost::make_shared<DenseMatrix>((*rotation_matrix2) * (*rotation_matrix1));
   }
   FieldHandle prototype = elc_coil_proto[elc_prototyp_map[i]-1];
   FieldInformation fi(prototype);
   if(fi.is_trisurfmesh())
   {
    GetMeshNodesAlgo algo_getfieldnodes;
    DenseMatrixHandle fieldnodes;
    try
    {
     algo_getfieldnodes.run(prototype,fieldnodes);
    }
    catch (...)
    {
     THROW_ALGORITHM_PROCESSING_ERROR("Internal error: could not retrieve positions from assigned prototype ");
    }

    if (fieldnodes->nrows()<=0) // put this to tms as well
    {
     THROW_ALGORITHM_PROCESSING_ERROR("Internal error: could not retrieve positions from assigned prototype ");
    }

    ///second, subtract the mean of the prototyp positions to center it in origin
    double mean_loc_x=0,mean_loc_y=0,mean_loc_z=0;
    for(int j=0; j<fieldnodes->nrows(); j++)
    {
     mean_loc_x+=(*fieldnodes)(j,0);
     mean_loc_y+=(*fieldnodes)(j,1);
     mean_loc_z+=(*fieldnodes)(j,2);
    }
     mean_loc_x/=fieldnodes->nrows();
     mean_loc_y/=fieldnodes->nrows();
     mean_loc_z/=fieldnodes->nrows();

     for(int j=0; j<fieldnodes->nrows(); j++)
     {
      (*fieldnodes)(j,0)-=mean_loc_x;
      (*fieldnodes)(j,1)-=mean_loc_y;
      (*fieldnodes)(j,2)-=mean_loc_z;
     }

     DenseMatrixHandle rotated_positions;

     for(int j=0; j<fieldnodes->nrows(); j++)
     {
      DenseMatrixHandle pos_vec (boost::make_shared<DenseMatrix>(3,1));

      (*pos_vec)(0,0)=(*fieldnodes)(j,0);
      (*pos_vec)(1,0)=(*fieldnodes)(j,1);
      (*pos_vec)(2,0)=(*fieldnodes)(j,2);

      if (angle==0)
       rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix1) * (*pos_vec));
	 else
	  rotated_positions = boost::make_shared<DenseMatrix>((*rotation_matrix) * (*pos_vec));

      (*fieldnodes)(j,0)=(*rotated_positions)(0,0)+elc_x[i];
      (*fieldnodes)(j,1)=(*rotated_positions)(1,0)+elc_y[i];
      (*fieldnodes)(j,2)=(*rotated_positions)(2,0)+elc_z[i];
     }

     VMesh* prototype_vmesh = prototype->vmesh();

     FieldInformation fieldinfo("TriSurfMesh", CONSTANTDATA_E, "double"); /// this is the final moved prototype for elc i
     FieldHandle tmp_tdcs_elc = CreateField(fieldinfo);
     VMesh*  tmp_tdcs_elc_vmesh = tmp_tdcs_elc->vmesh();
     VField* tmp_tdcs_elc_vfld  = tmp_tdcs_elc->vfield();

     Point p;
     for (int l=0; l<fieldnodes->nrows(); l++)
     {
      Point p((*fieldnodes)(l,0),(*fieldnodes)(l,1),(*fieldnodes)(l,2));
      tdcs_vmesh->add_point(p);
      tmp_tdcs_elc_vmesh->add_point(p);
     }

     for (VMesh::Elem::index_type l=0; l<prototype_vmesh->num_elems(); l++)
     {
      VMesh::Node::array_type onodes(3);
      prototype_vmesh->get_nodes(onodes, l);
      tmp_tdcs_elc_vmesh->add_elem(onodes);
      onodes[0]+=nr_elc_sponge_triangles;
      onodes[1]+=nr_elc_sponge_triangles;
      onodes[2]+=nr_elc_sponge_triangles;
      tdcs_vmesh->add_elem(onodes);
      field_values.push_back(i);
     }
    nr_elc_sponge_triangles+=fieldnodes->nrows();
    valid_electrode_definition[i]=1;
    num_valid_electrode_definition++;

    tmp_tdcs_elc_vfld->set_all_values(0.0);

    /// since the protoype has to be centered around coordinate origin
    /// it will envelop the scalp/electrode sponge surface at its final location (it is now!)
    /// scalp needs to have data stored on nodes for clipping to prevent having frayed electrode sponge corners
    FieldHandle scalp_linear_data;
    ConvertFieldBasisTypeAlgo convert_field_basis;
    if (!scalp_vfld->is_lineardata())
    {
     using namespace SCIRun::Core::Algorithms::Fields::Parameters;
     {
      convert_field_basis.set_option(OutputType, "Linear");
      convert_field_basis.set(BuildBasisMapping, false);
      convert_field_basis.runImpl(scalp, scalp_linear_data);
     }
    }

    CalculateSignedDistanceFieldAlgo algo_sdf;
    FieldHandle sdf_output;
    if(scalp_vfld->is_lineardata())
     algo_sdf.run(scalp, tmp_tdcs_elc, sdf_output);
       else
         algo_sdf.run(scalp_linear_data, tmp_tdcs_elc, sdf_output); /// assumed that CalculateSignedDistanceFieldAlgo output has always values defined on nodes

    VField* tmp_sdf_vfld  = sdf_output->vfield();
    VMesh*  tmp_sdf_vmsh  = sdf_output->vmesh();
    if (!tmp_sdf_vfld || tmp_sdf_vfld->num_values()<=0)
    {
     std::ostringstream ostr3;
     ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode. Make sure that prototype encapsulated scalp." << std::endl;
     remark(ostr3.str());
     skip_current_iteration=true;
     continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
    }

    std::vector<double> tmp_field_bin_values;
    bool found_elc_surf=false;
    tmp_field_bin_values.resize(tmp_sdf_vfld->num_values());
    for (VMesh::Node::index_type l=0; l<tmp_sdf_vfld->num_values(); l++) /// find out which nodes are inside the
    {
     double tmp_sdf_fld_val=std::numeric_limits<double>::quiet_NaN(); /// store binary classification of which scalp nodes are inside prototype and which are outside
     tmp_sdf_vfld->get_value(tmp_sdf_fld_val,l);
     if (tmp_sdf_fld_val <= 0.0)
     {
      tmp_field_bin_values[l]=1.0;
      found_elc_surf=true;
     } else
       tmp_field_bin_values[l]=0.0;
    }
    FieldHandle final_electrode_sponge_surf;

    if(!found_elc_surf)
    {
     std::ostringstream ostr3;
     ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (after sdf binarization). Make sure that prototype encapsulates scalp." << std::endl;
     remark(ostr3.str());
     skip_current_iteration=true;
     continue;/// in that case go to the next electrode -> leave the for loop thats iterating over
    }

    using namespace SCIRun::Core::Algorithms::Fields::Parameters;  /// convert the data values (zero's) to elements
    {
     convert_field_basis.set_option(OutputType, "Constant");
     convert_field_basis.set(BuildBasisMapping, false);
     convert_field_basis.runImpl(sdf_output, final_electrode_sponge_surf);
    }
    VField* final_electrode_sponge_surf_fld = final_electrode_sponge_surf->vfield();
    VMesh*  final_electrode_sponge_surf_msh = final_electrode_sponge_surf->vmesh();

    if (!final_electrode_sponge_surf_fld || final_electrode_sponge_surf_fld->num_values()<=0 || !final_electrode_sponge_surf_msh || final_electrode_sponge_surf_msh->num_elems()<=0)
    {
     std::ostringstream ostr3;
     ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
     remark(ostr3.str());
     skip_current_iteration=true;
     continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
    }

    final_electrode_sponge_surf_fld->set_all_values(0.0); /// Precaution: set data values (defined at elements) to zero
    for (VMesh::Elem::index_type l=0; l<final_electrode_sponge_surf_msh->num_elems(); l++)
    {
      VMesh::Node::array_type onodes(3);
      tmp_sdf_vmsh->get_nodes(onodes, l);
      if (tmp_field_bin_values[onodes[0]]==1.0 && tmp_field_bin_values[onodes[1]]==1.0 && tmp_field_bin_values[onodes[2]]==1.0)
      {
        final_electrode_sponge_surf_fld->set_value(1.0,l);
	found_elc_surf=true;
      }
        else
          final_electrode_sponge_surf_fld->set_value(0.0,l);
    }

    if (!found_elc_surf)
    {
     std::ostringstream ostr3;
     ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
     remark(ostr3.str());
     skip_current_iteration=true;
     continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
    }
     /// are there multiple not connected scalp surfaces that are inside the prototype
     /// use projected point r (that was projected on scalp surface) to differentiate which surface is the one to use
     /// but first splitbydomain to get the surface with tha value 1.0
     SplitFieldByDomainAlgo algo_splitfieldbydomain;
     algo_splitfieldbydomain.setLogger(getLogger());
     FieldList final_electrode_sponge_surf_domainsplit;
     algo_splitfieldbydomain.set(SplitFieldByDomainAlgo::SortBySize, true);
     algo_splitfieldbydomain.set(SplitFieldByDomainAlgo::SortAscending, false);
     algo_splitfieldbydomain.runImpl(final_electrode_sponge_surf, final_electrode_sponge_surf_domainsplit);
     found_elc_surf=false;
     FieldHandle find_elc_surf;
     VMesh::Elem::index_type c_ind=0;
     for(long l=0;l<final_electrode_sponge_surf_domainsplit.size();l++)
     {
      VField* final_electrode_sponge_surf_domainsplit_fld = final_electrode_sponge_surf_domainsplit[l]->vfield();
      double tmp_val=std::numeric_limits<double>::quiet_NaN();
      final_electrode_sponge_surf_domainsplit_fld->get_value(tmp_val,c_ind);
      if(tmp_val==1.0)
      {
       find_elc_surf=final_electrode_sponge_surf_domainsplit[l];
       found_elc_surf=true;
      }
     }

     if(!found_elc_surf)
     {
       std::ostringstream ostr3;
       ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (after domainsplit). Make sure that prototype encapsulates scalp." << std::endl;
       remark(ostr3.str());
       found_elc_surf=false;
       continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
     }

     SplitFieldByConnectedRegionAlgo algo_splitbyconnectedregion;
     algo_splitbyconnectedregion.set(SplitFieldByConnectedRegionAlgo::SortDomainBySize(), true);
     algo_splitbyconnectedregion.set(SplitFieldByConnectedRegionAlgo::SortAscending(), false);
     std::vector<FieldHandle> result = algo_splitbyconnectedregion.run(find_elc_surf);
     found_elc_surf=false;
     double distance=std::numeric_limits<double>::quiet_NaN();
     VMesh::Node::index_type didx;
     for(int l=0;l<result.size();l++)
     {
      FieldHandle tmp_fld = result[l];
      VMesh*  tmp_fld_msh  = tmp_fld->vmesh();

      tmp_fld_msh->synchronize(Mesh::NODE_LOCATE_E);
      tmp_fld_msh->find_closest_node(distance,p,didx,r);

      if (distance==0)
      {
       found_elc_surf=true;
       scalp_vmesh->synchronize(Mesh::NODE_LOCATE_E);
       Point q;
       Vector norm;

       /// create scalp/electrode sponge triangle nodes
       for (VMesh::Node::index_type k=0; k<tmp_fld_msh->num_nodes(); k++)
       {
        tmp_fld_msh->get_center(p,k);
	output_vmesh->add_point(p);
       }
       /// create electrode sponge top triangle nodes
       long count_pts=0;
       for (VMesh::Node::index_type k=0; k<tmp_fld_msh->num_nodes(); k++)
       {
        tmp_fld_msh->get_center(p,k);
	scalp_vmesh->find_closest_node(distance,q,didx,p);
	if (distance==0)
	{
	 scalp_vmesh->synchronize(Mesh::NORMALS_E);
	 scalp_vmesh->get_normal(norm,didx);
	 double x=norm.x(),y=norm.y(),z=norm.z();
	 double normal_mag=sqrt(x*x+y*y+z*z);
	 x/=normal_mag;
         y/=normal_mag;
         z/=normal_mag;
	 Point tmp_pt;
	 if (!flip_normal)
	   tmp_pt=Point(q.x()+x*elc_thickness[i],q.y()+y*elc_thickness[i],q.z()+z*elc_thickness[i]);
	     else
	      tmp_pt=Point(q.x()-x*elc_thickness[i],q.y()-y*elc_thickness[i],q.z()-z*elc_thickness[i]);

	 output_vmesh->add_point(tmp_pt);
	 count_pts++;
	}
       }
       int offset=nr_elc_sponge_triangles_on_scalp;
       for (int iter_tmp=0;iter_tmp<2;iter_tmp++)
       {
        for (VMesh::Elem::index_type k=0; k<tmp_fld_msh->num_elems(); k++)
        {
         VMesh::Node::array_type onodes(3);
         tmp_fld_msh->get_nodes(onodes, k);
         onodes[0]+=offset;
         onodes[1]+=offset;
         onodes[2]+=offset;
         output_vmesh->add_elem(onodes);
         field_values_elc_on_scalp.push_back(i);
        }
	offset+=tmp_fld_msh->num_nodes();
       }

       MatrixHandle mapping;
       GetFieldBoundaryAlgo algo_getfldbnd;
       FieldHandle boundary;
       algo_getfldbnd.run(tmp_fld, boundary, mapping);
       VMesh* boundary_msh  = boundary->vmesh();
       /// connect electrode sponge surfaces
       if (boundary->vmesh()->is_curvemesh())
       {
         tmp_fld_msh->synchronize(Mesh::NODE_LOCATE_E);
	VMesh::Edge::iterator meshEdgeIter;
        VMesh::Edge::iterator meshEdgeEnd;
        VMesh::Node::array_type nodesFromEdge(2);
	boundary_msh->end(meshEdgeEnd);
	for (boundary_msh->begin(meshEdgeIter); meshEdgeIter != meshEdgeEnd; ++meshEdgeIter)
        {
          VMesh::Edge::index_type edgeID = *meshEdgeIter;
	  boundary_msh->get_nodes(nodesFromEdge, edgeID);
	  Point p0, p1;
	  boundary_msh->get_point(p0, nodesFromEdge[0]);
          boundary_msh->get_point(p1, nodesFromEdge[1]);
	  VMesh::Node::index_type idx1;
	  tmp_fld_msh->find_closest_node(distance,r,idx1,p0);
	  if (distance!=0)
	  {
	   std::ostringstream ostr3;
           ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
           remark(ostr3.str());
           break;
	  }
	  VMesh::Node::index_type idx2;
	  tmp_fld_msh->find_closest_node(distance,r,idx2,p1);
	  if (distance!=0)
	  {
	   std::ostringstream ostr3;
           ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
           remark(ostr3.str());
           break;
	  }
	  long i1=(long)idx1, i2=(long)idx2;
	  long i3=i1+tmp_fld_msh->num_nodes(), i4=i2+tmp_fld_msh->num_nodes();
	  VMesh::Node::array_type onodes(3);
	  onodes[0]=i3+nr_elc_sponge_triangles_on_scalp;
	  onodes[1]=i1+nr_elc_sponge_triangles_on_scalp;
	  onodes[2]=i4+nr_elc_sponge_triangles_on_scalp;
	  output_vmesh->add_elem(onodes);
	  field_values_elc_on_scalp.push_back(i);
	  onodes[0]=i4+nr_elc_sponge_triangles_on_scalp;
	  onodes[1]=i1+nr_elc_sponge_triangles_on_scalp;
	  onodes[2]=i2+nr_elc_sponge_triangles_on_scalp;
	  output_vmesh->add_elem(onodes);
	  field_values_elc_on_scalp.push_back(i);
        }

        nr_elc_sponge_triangles_on_scalp+=tmp_fld_msh->num_nodes()+count_pts;
       } else
       {
         std::ostringstream ostr3;
         ostr3 << " Trying to get boundary for scalp peace usind to create electrode " << i+1 << ". Make sure that prototype encapsulates scalp." << std::endl;
         remark(ostr3.str());
         continue;
       }

      }
     }

   } else
   {
    std::ostringstream ostr3;
    ostr3 << " tDCS electrode definition for " << i+1 << ". row needs be a point cloud (with defined scalar or vectors data)." << std::endl;
    remark(ostr3.str());
    skip_current_iteration=true;
    continue;
   }

  tdcs_vfld->resize_values();
  tdcs_vfld->set_values(field_values);
  output_vfld->resize_values();
  output_vfld->set_values(field_values_elc_on_scalp);
  elc_sponge_locations = boost::make_shared<DenseMatrix>(DenseMatrix::Zero(num_valid_electrode_definition,4));
  int count=0;
  for(int j=0;j<valid_electrode_definition.size();j++)
  {
   if(valid_electrode_definition[j]==1)
   {
    if(count<elc_sponge_locations->nrows())
    {
     (*elc_sponge_locations)(count,0)=elc_x[i];
     (*elc_sponge_locations)(count,1)=elc_y[i];
     (*elc_sponge_locations)(count,2)=elc_z[i];
     (*elc_sponge_locations)(count,3)=elc_thickness[i];
     count++;
    }
   }
  }
 }
 } else
 {
  std::ostringstream ostr3;
  ostr3 << " Internal error: tDCS electrode could not be generated. " << std::endl;
  remark(ostr3.str());
 }

 VariableHandle table2(new Variable(Name("Table"), new_table));

 return boost::make_tuple(elc_sponge_locations, electrode_field, output, table2);
}

boost::tuple<VariableHandle, DenseMatrixHandle, FieldHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgorithm::run(const FieldHandle scalp, const DenseMatrixHandle locations, const std::vector<FieldHandle>& elc_coil_proto) const
{
 VariableHandle table_output = fill_table(scalp, locations, elc_coil_proto);
 DenseMatrixHandle elc_sponge_locations;
 FieldHandle electrodes_field, coils_field, final_electrodes_field;
 auto table = table_output->toVector();

 /// check GUI inputs:
 /// 1) Is there any valid row in the GUI table, so at least one row where both ComboBoxes are set
 ///
 std::vector<double> elc_prototyp_map;
 std::vector<double> elc_thickness;
 std::vector<double> elc_angle_rotation;
 std::vector<double> elc_x;
 std::vector<double> elc_y;
 std::vector<double> elc_z;

 std::vector<double> coil_prototyp_map;
 std::vector<double> coil_angle_rotation;
 std::vector<double> coil_x;
 std::vector<double> coil_y;
 std::vector<double> coil_z;
 std::vector<double> coil_nx;
 std::vector<double> coil_ny;
 std::vector<double> coil_nz;

 /// The rest of the run function checks the validity of the GUI inputs. If there are not valid (="???") it tries to use the prototype inputs and if valid it calls functions make_tdcs_electrodes or make_tms
 for(int i=0;i<table.size();i++)
 {
  auto row = (table[i]).toVector();

  /// the c* integer variables refine the column vales (1,2,3,...,10) for the current row
  int c1=std::numeric_limits<double>::quiet_NaN(),c2=std::numeric_limits<double>::quiet_NaN();
  double c3=std::numeric_limits<double>::quiet_NaN(),c4=std::numeric_limits<double>::quiet_NaN(),c5=std::numeric_limits<double>::quiet_NaN(),
  c6=std::numeric_limits<double>::quiet_NaN(),c7=std::numeric_limits<double>::quiet_NaN(),c8=std::numeric_limits<double>::quiet_NaN(),
  c9=std::numeric_limits<double>::quiet_NaN(),c10=std::numeric_limits<double>::quiet_NaN();

  bool valid_position=true, valid_normal=true, row_valid=true;

  try
  {
   c1 = lexical_cast<int>(row[0].toString());
  } catch(bad_lexical_cast &)
  {
   c1=std::numeric_limits<double>::quiet_NaN();
   row_valid=false;
  }

  try
  {
   c2 = lexical_cast<int>(row[1].toString());
  } catch(bad_lexical_cast &)
  {
   c2=std::numeric_limits<double>::quiet_NaN();
   row_valid=false;
  }

  auto str_x = row[2].toString();
  if (str_x.compare("???")==0)
  {
    valid_position=false;
  } else
  {
   try
   {
     c3 = lexical_cast<double>(str_x);
   } catch(bad_lexical_cast &)
   {
     c3=std::numeric_limits<double>::quiet_NaN();
     valid_position=false;
   }
  }

  auto str_y = row[3].toString();
  if (str_y.compare("???")==0)
  {
   valid_position=false;
  } else
  {
   try  ///get the electrode thickness from GUI
   {
     c4 = lexical_cast<double>(str_y);
   } catch(bad_lexical_cast &)
   {
     c4=std::numeric_limits<double>::quiet_NaN();
     valid_position=false;
   }
  }

  auto str_z = row[4].toString();
  if (str_z.compare("???")==0)
  {
     valid_position=false;
  }  else
  {
   try  ///get the electrode thickness from GUI
   {
     c5 = lexical_cast<double>(str_z);
   } catch(bad_lexical_cast &)
   {
     c5=std::numeric_limits<double>::quiet_NaN();
     valid_position=false;
   }
  }

  c6=-1;
  auto angle = row[5].toString();
  if (angle.compare("???")!=0)
  {
   try
   {
    c6 = lexical_cast<double>(row[5].toString());
   } catch(bad_lexical_cast &)
   {
    c6=std::numeric_limits<double>::quiet_NaN();
   }
  } else
    c6=std::numeric_limits<double>::quiet_NaN();

  if (IsNan(c6))
  {
   c6=0;
  }

  if(row_valid && c1>0 && c2>0)   ///both combo boxes are set up, so this could be a valid row but first check if ...
                     /// its a tDCS electrode and if so if the thickness is provided in the GUI
		     /// or if its a TMS coil check if the prototype has normals - if so lets put the normal in the GUI
  {

     FieldHandle prototyp = elc_coil_proto[c1-1];

     if (!prototyp)
     {
       std::ostringstream ostr1;
       ostr1 << "Module input " << (c1+2) << " seems to be empty" << std::endl;
       THROW_ALGORITHM_PROCESSING_ERROR(ostr1.str());
     }

     GetFieldDataAlgo algo_getfielddata;
     DenseMatrixHandle fielddata;
     try
     {
      fielddata  = algo_getfielddata.run(prototyp);
     }
     catch (...)
     {

     }

     GetMeshNodesAlgo algo_getfieldnodes;
     DenseMatrixHandle fieldnodes;
     try
     {
      algo_getfieldnodes.run(prototyp,fieldnodes);
     }
     catch (...)
     {

     }

     if ( (fieldnodes->nrows()!=fielddata->nrows()) )
     {
      if( !((fieldnodes->nrows()==3 || fieldnodes->nrows()==1) && (fielddata->nrows()==3 || fielddata->nrows()==1)) )
      {
       std::ostringstream ostr_;
       ostr_ << "Module input " << (c1+2) << " (assigned tms coil prototype) does not contain same number of nodes as data values (linear basis)." << std::endl;
       THROW_ALGORITHM_PROCESSING_ERROR(ostr_.str());
      }
     }

     /// get Coil normal from GUI
     /// get NX
     try
     {
       c7 = lexical_cast<double>(row[6].toString());
     } catch(bad_lexical_cast &)
     {
      c7=std::numeric_limits<double>::quiet_NaN();
      valid_normal=false;
     }

     /// get NY
     try
     {
       c8 = lexical_cast<double>(row[7].toString());
     } catch(bad_lexical_cast &)
     {
      c8=std::numeric_limits<double>::quiet_NaN();
      valid_normal=false;
     }

     /// get NZ
     try
     {
       c9 = lexical_cast<double>(row[8].toString());
     } catch(bad_lexical_cast &)
     {
      c9=std::numeric_limits<double>::quiet_NaN();
      valid_normal=false;
     }

     /// get electrode thickness
     try
     {
       c10 = lexical_cast<double>(row[9].toString());
     } catch(bad_lexical_cast &)
     {
      c10=std::numeric_limits<double>::quiet_NaN();
     }

     if (!valid_normal && fielddata->ncols()==3 && fielddata->nrows()>=1) /// use FIRST(!) mag. dipole direction to infer coil orientation. Note that the determined direction could be anti parallel
     {
       double norm=sqrt((*fielddata)(0,0)*(*fielddata)(0,0)+(*fielddata)(0,1)*(*fielddata)(0,1)+(*fielddata)(0,2)*(*fielddata)(0,2)); /// normalize mag. dipole to get coil direction estimate
       c7=(*fielddata)(0,0)/norm;
       c8=(*fielddata)(0,1)/norm;
       c9=(*fielddata)(0,2)/norm;
       valid_normal=true;
     }

     if(c7==0 && c8==0 && c9==0)
     {
      std::ostringstream ostr3;
      ostr3 << " The TMS coil defined in table row " << i+1 << " could not get any valid normal information, found normal contained only zeros (0,0,0). " << std::endl;
      remark(ostr3.str());
      valid_normal=false;
     }

     if (!valid_position && fieldnodes->nrows()>=1 && fieldnodes->ncols()==3)
     {
       double x=0,y=0,z=0;
       for(int j=0;j<fieldnodes->nrows();j++)
        {
	 x+=(*fieldnodes)(j,0);
	 y+=(*fieldnodes)(j,1);
	 z+=(*fieldnodes)(j,2);
	}
       x/=fieldnodes->nrows();
       y/=fieldnodes->nrows();
       z/=fieldnodes->nrows();
       c3=x;
       c4=y;
       c5=z;
       valid_position=true;
     }

    if (c2==tDCS_stim_type) /// tDCS?
    {
     if(valid_position)
     {
      elc_prototyp_map.push_back(c1);
      elc_angle_rotation.push_back(c6);
      elc_x.push_back(c3);
      elc_y.push_back(c4);
      elc_z.push_back(c5);
      elc_thickness.push_back(c10);;
     }

    } else

    if (c2==TMS_stim_type) /// TMS?
    {
     if(valid_normal && valid_position)
     {
      coil_prototyp_map.push_back(c1);
      coil_angle_rotation.push_back(c6);
      coil_x.push_back(c3);
      coil_y.push_back(c4);
      coil_z.push_back(c5);
      coil_nx.push_back(c7);
      coil_ny.push_back(c8);
      coil_nz.push_back(c9);
     } else
        {
	  std::ostringstream ostr3;
	  ostr3 << " The TMS coil defined in table row " << i+1 << " has no normal defined (NX,NY,NZ). Further, no normal could be taken from the linked prototyp field data. " << std::endl;
	  remark(ostr3.str());
	}
    }

  }
 }

  bool valid_tdcs=false, valid_tms=false;
  int t1=elc_angle_rotation.size();
  int t2=elc_thickness.size();
  int t3=elc_x.size();
  int t4=elc_y.size();
  int t5=elc_z.size();
  int t14=elc_coil_proto.size();

  if (t1==t2 && t1==t3 && t1==t4 && t1==t5 && t14>0 && t1>0)
  {
    boost::tie(elc_sponge_locations, electrodes_field, final_electrodes_field, table_output) = make_tdcs_electrodes(scalp, elc_coil_proto, elc_prototyp_map, elc_x, elc_y, elc_z, elc_angle_rotation, elc_thickness, table_output);
    valid_tdcs=true;
  }

  int t6=coil_prototyp_map.size();
  int t7=coil_angle_rotation.size();
  int t8=coil_x.size();
  int t9=coil_y.size();
  int t10=coil_z.size();
  int t11=coil_nx.size();
  int t12=coil_ny.size();
  int t13=coil_nz.size();

  if (t6==t7 && t6==t8 && t6==t9 && t6==t10 && t6==t11 && t6==t12 && t6==t13 && t14>0 && t6>0)
  {
   coils_field = make_tms(scalp, elc_coil_proto, coil_prototyp_map, coil_x, coil_y, coil_z, coil_angle_rotation, coil_nx, coil_ny, coil_nz);
   valid_tms =true;
  }

  if (!valid_tdcs && !valid_tms)
  {
   std::ostringstream ostr0;
   ostr0 << " Not a single table row contains valid information. " << std::endl;
   remark(ostr0.str());
  }

 return boost::make_tuple(table_output, elc_sponge_locations, electrodes_field, final_electrodes_field, coils_field);
}

AlgorithmOutput ElectrodeCoilSetupAlgorithm::run_generic(const AlgorithmInput& input) const
{
  auto scalp = input.get<Field>(SCALP_SURF);
  auto locations = input.get<DenseMatrix>(LOCATIONS);
  auto elc_coil_proto = input.getList<Field>(ELECTRODECOILPROTOTYPES);

  if (!scalp)
  {
    THROW_ALGORITHM_PROCESSING_ERROR(" SCALP_SURF (first input) field empty. ");
  }

  if (!locations)
  {
    THROW_ALGORITHM_PROCESSING_ERROR(" LOCATIONS (second input) matrix empty. ");
  }

  if (!(elc_coil_proto.size()>=1))
  {
    THROW_ALGORITHM_PROCESSING_ERROR(" At least one prototypical coil (POINTMESH) or electrode (TRISURFMESH) definition as a field input must be provided.");
  }

  if(locations->ncols()!=3)
  {
    THROW_ALGORITHM_PROCESSING_ERROR(" Locations (second module input) needs to be a dense matrix input with dimensions lx3 (l being > 0). ");
  }

  VariableHandle table;
  DenseMatrixHandle elc_sponge_loc_avr;
  FieldHandle coils_field,electrodes_field, final_electrode_field;
  boost::tie(table, elc_sponge_loc_avr, electrodes_field, final_electrode_field, coils_field) = run(scalp, locations, elc_coil_proto);

  AlgorithmOutput output;
  output[ELECTRODE_SPONGE_LOCATION_AVR] = elc_sponge_loc_avr;
  output[MOVED_ELECTRODES_FIELD] = electrodes_field;
  output[FINAL_ELECTRODES_FIELD] = final_electrode_field;
  output[COILS_FIELD] = coils_field;
  output.setAdditionalAlgoOutput(table);

  return output;
}


//  Copyright John Maddock 2005-2006.
//  Use, modification and distribution are subject to the
//  Boost Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_MATH_TOOLS_PRECISION_INCLUDED
#define BOOST_MATH_TOOLS_PRECISION_INCLUDED

#ifdef _MSC_VER
#pragma once
#endif

#include <boost/limits.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/math/policies/policy.hpp>

// These two are for LDBL_MAN_DIG:
#include <limits.h>
#include <math.h>

namespace boost{ namespace math
{
namespace tools
{
// If T is not specialized, the functions digits, max_value and min_value,
// all get synthesised automatically from std::numeric_limits.
// However, if numeric_limits is not specialised for type RealType,
// for example with NTL::RR type, then you will get a compiler error
// when code tries to use these functions, unless you explicitly specialise them.

// For example if the precision of RealType varies at runtime,
// then numeric_limits support may not be appropriate,
// see boost/math/tools/ntl.hpp  for examples like
// template <> NTL::RR max_value<NTL::RR> ...
// See  Conceptual Requirements for Real Number Types.

template <class T>
inline BOOST_MATH_CONSTEXPR int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) BOOST_NOEXCEPT
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
   BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::radix == 2 || ::std::numeric_limits<T>::radix == 10);
#else
   BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
   BOOST_ASSERT(::std::numeric_limits<T>::radix == 2 || ::std::numeric_limits<T>::radix == 10);
#endif
   return std::numeric_limits<T>::radix == 2
      ? std::numeric_limits<T>::digits
      : ((std::numeric_limits<T>::digits + 1) * 1000L) / 301L;
}

template <class T>
inline BOOST_MATH_CONSTEXPR T max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))  BOOST_MATH_NOEXCEPT(T)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
#else
   BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
#endif
   return (std::numeric_limits<T>::max)();
} // Also used as a finite 'infinite' value for - and +infinity, for example:
// -max_value<double> = -1.79769e+308, max_value<double> = 1.79769e+308.

template <class T>
inline BOOST_MATH_CONSTEXPR T min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
#else
   BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
#endif
   return (std::numeric_limits<T>::min)();
}

namespace detail{
//
// Logarithmic limits come next, note that although
// we can compute these from the log of the max value
// that is not in general thread safe (if we cache the value)
// so it's better to specialise these:
//
// For type float first:
//
template <class T>
inline BOOST_MATH_CONSTEXPR T log_max_value(const boost::integral_constant<int, 128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return 88.0f;
}

template <class T>
inline BOOST_MATH_CONSTEXPR T log_min_value(const boost::integral_constant<int, 128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return -87.0f;
}
//
// Now double:
//
template <class T>
inline BOOST_MATH_CONSTEXPR T log_max_value(const boost::integral_constant<int, 1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return 709.0;
}

template <class T>
inline BOOST_MATH_CONSTEXPR T log_min_value(const boost::integral_constant<int, 1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return -708.0;
}
//
// 80 and 128-bit long doubles:
//
template <class T>
inline BOOST_MATH_CONSTEXPR T log_max_value(const boost::integral_constant<int, 16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return 11356.0L;
}

template <class T>
inline BOOST_MATH_CONSTEXPR T log_min_value(const boost::integral_constant<int, 16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return -11355.0L;
}

template <class T>
inline T log_max_value(const boost::integral_constant<int, 0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
{
   BOOST_MATH_STD_USING
#ifdef __SUNPRO_CC
   static const T m = boost::math::tools::max_value<T>();
   static const T val = log(m);
#else
   static const T val = log(boost::math::tools::max_value<T>());
#endif
   return val;
}

template <class T>
inline T log_min_value(const boost::integral_constant<int, 0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
{
   BOOST_MATH_STD_USING
#ifdef __SUNPRO_CC
   static const T m = boost::math::tools::min_value<T>();
   static const T val = log(m);
#else
   static const T val = log(boost::math::tools::min_value<T>());
#endif
   return val;
}

template <class T>
inline BOOST_MATH_CONSTEXPR T epsilon(const boost::true_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_MATH_NOEXCEPT(T)
{
   return std::numeric_limits<T>::epsilon();
}

#if defined(__GNUC__) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106))
template <>
inline BOOST_MATH_CONSTEXPR long double epsilon<long double>(const boost::true_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(long double)) BOOST_MATH_NOEXCEPT(long double)
{
   // numeric_limits on Darwin (and elsewhere) tells lies here:
   // the issue is that long double on a few platforms is
   // really a "double double" which has a non-contiguous
   // mantissa: 53 bits followed by an unspecified number of
   // zero bits, followed by 53 more bits.  Thus the apparent
   // precision of the type varies depending where it's been.
   // Set epsilon to the value that a 106 bit fixed mantissa
   // type would have, as that will give us sensible behaviour everywhere.
   //
   // This static assert fails for some unknown reason, so
   // disabled for now...
   // BOOST_STATIC_ASSERT(std::numeric_limits<long double>::digits == 106);
   return 2.4651903288156618919116517665087e-32L;
}
#endif

template <class T>
inline T epsilon(const boost::false_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
{
   // Note: don't cache result as precision may vary at runtime:
   BOOST_MATH_STD_USING  // for ADL of std names
   return ldexp(static_cast<T>(1), 1-policies::digits<T, policies::policy<> >());
}

template <class T>
struct log_limit_traits
{
   typedef typename mpl::if_c<
      (std::numeric_limits<T>::radix == 2) &&
      (std::numeric_limits<T>::max_exponent == 128
         || std::numeric_limits<T>::max_exponent == 1024
         || std::numeric_limits<T>::max_exponent == 16384),
      boost::integral_constant<int, (std::numeric_limits<T>::max_exponent > INT_MAX ? INT_MAX : static_cast<int>(std::numeric_limits<T>::max_exponent))>,
      boost::integral_constant<int, 0>
   >::type tag_type;
   BOOST_STATIC_CONSTANT(bool, value = tag_type::value ? true : false);
   BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized || (value == 0));
};

template <class T, bool b> struct log_limit_noexcept_traits_imp : public log_limit_traits<T> {};
template <class T> struct log_limit_noexcept_traits_imp<T, false> : public boost::integral_constant<bool, false> {};

template <class T>
struct log_limit_noexcept_traits : public log_limit_noexcept_traits_imp<T, BOOST_MATH_IS_FLOAT(T)> {};

} // namespace detail

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4309)
#endif

template <class T>
inline BOOST_MATH_CONSTEXPR T log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_NOEXCEPT_IF(detail::log_limit_noexcept_traits<T>::value)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   return detail::log_max_value<T>(typename detail::log_limit_traits<T>::tag_type());
#else
   BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
   BOOST_MATH_STD_USING
   static const T val = log((std::numeric_limits<T>::max)());
   return val;
#endif
}

template <class T>
inline BOOST_MATH_CONSTEXPR T log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) BOOST_NOEXCEPT_IF(detail::log_limit_noexcept_traits<T>::value)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   return detail::log_min_value<T>(typename detail::log_limit_traits<T>::tag_type());
#else
   BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
   BOOST_MATH_STD_USING
   static const T val = log((std::numeric_limits<T>::min)());
   return val;
#endif
}

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

template <class T>
inline BOOST_MATH_CONSTEXPR T epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) BOOST_MATH_NOEXCEPT(T)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
   return detail::epsilon<T>(boost::integral_constant<bool, ::std::numeric_limits<T>::is_specialized>());
#else
   return ::std::numeric_limits<T>::is_specialized ?
      detail::epsilon<T>(boost::true_type()) :
      detail::epsilon<T>(boost::false_type());
#endif
}

namespace detail{

template <class T>
inline BOOST_MATH_CONSTEXPR T root_epsilon_imp(const boost::integral_constant<int, 24>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.00034526698300124390839884978618400831996329879769945L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T root_epsilon_imp(const T*, const boost::integral_constant<int, 53>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.1490116119384765625e-7L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T root_epsilon_imp(const T*, const boost::integral_constant<int, 64>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.32927225399135962333569506281281311031656150598474e-9L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T root_epsilon_imp(const T*, const boost::integral_constant<int, 113>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.1387778780781445675529539585113525390625e-16L);
}

template <class T, class Tag>
inline T root_epsilon_imp(const T*, const Tag&)
{
   BOOST_MATH_STD_USING
   static const T r_eps = sqrt(tools::epsilon<T>());
   return r_eps;
}

template <class T>
inline T root_epsilon_imp(const T*, const boost::integral_constant<int, 0>&)
{
   BOOST_MATH_STD_USING
   return sqrt(tools::epsilon<T>());
}

template <class T>
inline BOOST_MATH_CONSTEXPR T cbrt_epsilon_imp(const boost::integral_constant<int, 24>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.0049215666011518482998719164346805794944150447839903L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T cbrt_epsilon_imp(const T*, const boost::integral_constant<int, 53>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(6.05545445239333906078989272793696693569753008995e-6L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T cbrt_epsilon_imp(const T*, const boost::integral_constant<int, 64>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(4.76837158203125e-7L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T cbrt_epsilon_imp(const T*, const boost::integral_constant<int, 113>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(5.7749313854154005630396773604745549542403508090496e-12L);
}

template <class T, class Tag>
inline T cbrt_epsilon_imp(const T*, const Tag&)
{
   BOOST_MATH_STD_USING;
   static const T cbrt_eps = pow(tools::epsilon<T>(), T(1) / 3);
   return cbrt_eps;
}

template <class T>
inline T cbrt_epsilon_imp(const T*, const boost::integral_constant<int, 0>&)
{
   BOOST_MATH_STD_USING;
   return pow(tools::epsilon<T>(), T(1) / 3);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T forth_root_epsilon_imp(const T*, const boost::integral_constant<int, 24>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.018581361171917516667460937040007436176452688944747L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T forth_root_epsilon_imp(const T*, const boost::integral_constant<int, 53>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.0001220703125L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T forth_root_epsilon_imp(const T*, const boost::integral_constant<int, 64>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.18145860519450699870567321328132261891067079047605e-4L);
}

template <class T>
inline BOOST_MATH_CONSTEXPR T forth_root_epsilon_imp(const T*, const boost::integral_constant<int, 113>&) BOOST_MATH_NOEXCEPT(T)
{
   return static_cast<T>(0.37252902984619140625e-8L);
}

template <class T, class Tag>
inline T forth_root_epsilon_imp(const T*, const Tag&)
{
   BOOST_MATH_STD_USING
   static const T r_eps = sqrt(sqrt(tools::epsilon<T>()));
   return r_eps;
}

template <class T>
inline T forth_root_epsilon_imp(const T*, const boost::integral_constant<int, 0>&)
{
   BOOST_MATH_STD_USING
   return sqrt(sqrt(tools::epsilon<T>()));
}

template <class T>
struct root_epsilon_traits
{
   typedef boost::integral_constant<int, (::std::numeric_limits<T>::radix == 2) && (::std::numeric_limits<T>::digits != INT_MAX) ? std::numeric_limits<T>::digits : 0> tag_type;
   BOOST_STATIC_CONSTANT(bool, has_noexcept = (tag_type::value == 113) || (tag_type::value == 64) || (tag_type::value == 53) || (tag_type::value == 24));
};

}

template <class T>
inline BOOST_MATH_CONSTEXPR T root_epsilon() BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && detail::root_epsilon_traits<T>::has_noexcept)
{
   return detail::root_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type());
}

template <class T>
inline BOOST_MATH_CONSTEXPR T cbrt_epsilon() BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && detail::root_epsilon_traits<T>::has_noexcept)
{
   return detail::cbrt_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type());
}

template <class T>
inline BOOST_MATH_CONSTEXPR T forth_root_epsilon() BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && detail::root_epsilon_traits<T>::has_noexcept)
{
   return detail::forth_root_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type());
}

} // namespace tools
} // namespace math
} // namespace boost

#endif // BOOST_MATH_TOOLS_PRECISION_INCLUDED