/* $Id: Generator.h 1136 2006-09-06 08:05:31Z olau $ */

/* Copyright (C) 2006 Oliver Lau <ola@ctmagazin.de>, Heise Zeitschriften Verlag */

#ifndef __GENERATOR_H_
#define __GENERATOR_H_

#include <cstdlib>

#include "iso.h"

#include "tbb/blocked_range.h"


class Generator {
#ifdef USE_GD
  gdImagePtr m_img; /* "Isobaren"-Grafik */
  size_t m_imgWidth; /* Breite der "Isobaren"-Grafik */
  size_t m_imgHeight; /* Höhe der "Isobaren"-Grafik */
  int *m_imgColors; /* Farbpalette */
#endif /* USE_GD */
  double *m_matrix; /* double[][] */
  size_t m_width; /* Breite von m_matrix[][] */
  size_t m_height; /* Höhe von m_matrix[][] */
  MEASUREMENT *m_m; /* MEASUREMENT [] */
  int m_numMeasurements; /* Anzahl der Messpunkte */
  double D;
  inline bool isMeasuringPoint(size_t x, size_t y) const
  {
    for (int i = 0; i < m_numMeasurements; ++i)
      if (m_m[i].x == x && m_m[i].y == y)
        return true;
    return false;
  }

public:
  Generator(double *matrix, size_t width, size_t height, MEASUREMENT *measurement
#ifdef USE_GD
    , gdImagePtr img, int imgWidth, int imgHeight, int *imgColors
#endif /* USE_GD */
    )
    : m_matrix(matrix), m_width(width), m_height(height), m_m(measurement),
#ifdef USE_GD
    m_img(img), m_imgWidth(imgWidth), m_imgHeight(imgHeight), m_imgColors(imgColors),
#endif /* USE_GD */
    D(1.0)
  {
    m_numMeasurements = 0;
    while (m_m[m_numMeasurements].x >= 0)
      ++m_numMeasurements;
  }

  void operator() (const tbb::blocked_range<size_t>& r) const 
  {
    size_t x_size = r.size();
    for (size_t y = 0; y < m_height; ++y) {
      for (size_t x = r.begin(); x != r.end(); ++x) {
        /* Messpunkte aussparen */
        if (!isMeasuringPoint(x, y)) {
          double sum = 0.0;
          double weight = 0.0;
          /* gewichtete Mittelwerte über alle Messpunkte berechnen */
          for (int i = 0; i < m_numMeasurements; ++i) {
            double distance;
#if defined (MANHATTAN_DISTANCE)
            distance = D * (abs(x - m_m[i].x) + abs(y - m_m[i].y));
#elif defined (DIAGONAL_DISTANCE)
            distance = D * max(abs(x - m_m[i].x), abs(y - m_m[i].y));
#elif defined (EUCLIDEAN_DISTANCE)
            distance = D * sqrt((double) (sqr(x - m_m[i].x) + sqr(y - m_m[i].y)));
#else // EUCLIDEAN_DISTANCE_SQUARED
            distance = D * (sqr(x - m_m[i].x) + sqr(y - m_m[i].y));
#endif
            sum += m_m[i].value / distance;
            weight += 1.0 / distance;
          }
          m_matrix[x + y * x_size] = sum / weight;
#ifdef USE_GD
          gdImageSetPixel(m_img, (int) (m_imgWidth * x / m_width),
            (int) (m_imgHeight * y / m_height),
            m_imgColors[(int) (sum / weight)]);
#endif /* USE_GD */
        }
      }
    }
  }
};

#endif /* __GENERATOR_H_ */
