#include <cstdlib>
#include <iostream>
#include <QtGui>
#include "bsprofileitem.h"
#include "directionalscanner.h"

using namespace std;



const int BSProfileItem::DISPLAY_INTENSITY = 1;
const int BSProfileItem::DISPLAY_GRADIENT = 2;
const int BSProfileItem::DISPLAY_CORRELATION_MEAN_1D = 3;
const int BSProfileItem::DISPLAY_CORRELATION_FULL_2D = 4;
const int BSProfileItem::DISPLAY_CORRELATION_MEAN_2D = 5;
const int BSProfileItem::DISPLAY_MIN = DISPLAY_INTENSITY;
const int BSProfileItem::DISPLAY_MAX = DISPLAY_CORRELATION_MEAN_2D;

const int BSProfileItem::MIN_SCAN = 8;



BSProfileItem::BSProfileItem ()
{
  profileWidth = 400;
  profileRatio = 3;
  gradientUnRatio = 40;
  gradientLow = 0;

  stripeWidth = 200;
  stripeMargin = 5;
  stripeResol = 4;

  widWidth = profileWidth + stripeWidth + 2 * stripeMargin;
  widHeight = 610;
  profileLow = (256 - (widHeight / profileRatio)) / 2;

  image = NULL;
  imageWidth = 0;
  imageHeight = 0;
  gMap = NULL;

  displayItem = DISPLAY_INTENSITY;
  stripe = 0;
  correlWidth = 7;
  correlThick = 3;
  correlRatio = 4;
}


QRectF BSProfileItem::boundingRect () const
{
  return QRectF (0, 0, widWidth, widHeight);
}


void BSProfileItem::paint (QPainter *painter,
                           const QStyleOptionGraphicsItem *option,
                           QWidget *widget)
{
  Q_UNUSED (option);
  Q_UNUSED (widget);

  paintStripes (painter);
  switch (displayItem)
  {
    case DISPLAY_INTENSITY :
      paintIntensityProfile (painter);
      break;

    case DISPLAY_GRADIENT :
      paintGradientProfile (painter);
      break;

    case DISPLAY_CORRELATION_MEAN_1D :
      if (setMeanCorrelationStripes ())
        paintCorrelationProfile (painter);
      painter->drawText (100, 20, QString ("W : Correl width = ")
                                  + QString::number (correlWidth));
      painter->drawText (100, 40, QString ("T : Correl thick = ")
                                  + QString::number (correlThick));
      break;

    case DISPLAY_CORRELATION_FULL_2D :
      if (setFull2dCorrelationStripes ())
        paintCorrelationProfile (painter);
      painter->drawText (100, 20, QString ("W : Correl width = ")
                                  + QString::number (correlWidth));
      painter->drawText (100, 40, QString ("T : Correl thick = ")
                                  + QString::number (correlThick));
      break;

    case DISPLAY_CORRELATION_MEAN_2D :
      if (setMean2dCorrelationStripes ())
        paintCorrelationProfile (painter);
      painter->drawText (100, 20, QString ("W : Correl width = ")
                                  + QString::number (correlWidth));
      painter->drawText (100, 40, QString ("T : Correl thick = ")
                                  + QString::number (correlThick));
      break;
  }
}


void BSProfileItem::setImage (QImage *image, VMap *idata)
{
  this->image = image;
  this->gMap = idata;
  this->imageWidth = image->width ();
  this->imageHeight = image->height ();
  scanp.setSize (image->width (), image->height ());
}


void BSProfileItem::buildScans (Pt2i p1, Pt2i p2)
{
  // Updates the central scan end points for parallel display
  this->pt1 = p1;
  this->pt2 = p2;

  // Resets the profiles
  rightscan.clear ();
  leftscan.clear ();
  rightCorrel.clear ();
  leftCorrel.clear ();
  rightReCorrel.clear ();
  leftReCorrel.clear ();
  stripe = 0;

  // Gets a scan iterator
  DirectionalScanner *ds = scanp.getScanner (p1, p2);

  // Extracts the left scan (with central one)
  vector<Pt2i> pix;
  if (ds->first (pix) < MIN_SCAN) { delete ds; return;}
  leftscan.push_back (pix);

  bool leftScanOn = true;
  maxStripe = 0;
  while (leftScanOn)
  {
    vector<Pt2i> scan;
    if (ds->nextOnLeft (scan) < MIN_SCAN) leftScanOn = false;
    else
    {
      leftscan.push_back (scan);
      maxStripe ++;
    }
  }

  // Extracts the right scans
  bool rightScanOn = true;
  minStripe = 1;
  while (rightScanOn)
  {
    vector<Pt2i> scan;
    if (ds->nextOnRight (scan) < MIN_SCAN) rightScanOn = false;
    else
    {
      rightscan.push_back (scan);
      minStripe --;
    }
  }

  // Frees the scan iterator
  delete ds;
}


void BSProfileItem::incStripe (int inc)
{
  stripe += inc;
  if (stripe > maxStripe) stripe = maxStripe;
  else if (stripe < minStripe) stripe = minStripe;
}


void BSProfileItem::incCorrelWidth (int down)
{
  if (displayItem <= DISPLAY_CORRELATION_MEAN_2D
          && displayItem >= DISPLAY_CORRELATION_MEAN_1D)
  {
    if (down)
    {
      if (correlWidth >= 5) correlWidth -= 2;
    }
    else if (correlWidth <= 19) correlWidth += 2;
  }
}


void BSProfileItem::incCorrelThick (int down)
{
  if (displayItem <= DISPLAY_CORRELATION_MEAN_2D
          && displayItem >= DISPLAY_CORRELATION_MEAN_1D)
  {
    if (down)
    {
      if (correlThick >= 3) correlThick -= 2;
    }
    else if (correlThick <= 17) correlThick += 2;
  }
}


void BSProfileItem::incCorrelRatio (int down)
{
  if (displayItem <= DISPLAY_CORRELATION_MEAN_2D
          && displayItem >= DISPLAY_CORRELATION_MEAN_1D)
  {
    if (down)
    {
      if (correlRatio > 1) correlRatio /= 2;
    }
    else correlRatio *= 2;
  }
}


void BSProfileItem::toggleDisplay (bool next)
{
  if (displayItem == DISPLAY_CORRELATION_FULL_2D) correlRatio *= 4;
  displayItem += (next ? 1 : -1);
  if (displayItem > DISPLAY_MAX) displayItem = DISPLAY_MIN;
  else if (displayItem < DISPLAY_MIN) displayItem = DISPLAY_MAX;
  if (displayItem == DISPLAY_CORRELATION_FULL_2D) correlRatio /= 4;
}




/**
 * Correlation calculation (first release).
 * Compares portions of scan bars with a profile extracted at
 * the first scan centered on the blurred segment.
 */
void BSProfileItem::setCorrelationStripes (Pt2i p1, Pt2i p2, int segwidth)
{
  leftCorrel.clear ();
  rightCorrel.clear ();
  leftReCorrel.clear ();
  rightReCorrel.clear ();
  int correlWidth = segwidth;
  if (correlWidth > (int) leftscan.at(0).size ())
  {
    cerr << "Can't get correlation stripes" << endl;
    return;
  }

  // Gets the central index
  Pt2i pc ((p1.x () + p2.x ()) / 2, (p1.y () + p2.y ()) / 2);
  vector<Pt2i>::iterator it = leftscan.at(0).begin ();
  int dist, pos = 0, minPos = 0;
  int minDist = (pc.x() - (*it).x()) * (pc.x() - (*it).x())
                + (pc.y() - (*it).y()) * (pc.y() - (*it).y());
  it ++;
  while (it != leftscan.at(0).end ())
  {
    dist = (pc.x() - (*it).x()) * (pc.x() - (*it).x())
           + (pc.y() - (*it).y()) * (pc.y() - (*it).y());
    if (dist < minDist)
    {
      minDist = dist;
      minPos = pos;
    }
    it ++;
    pos ++;
  }
  if (minPos - correlWidth / 2 < 0
      || minPos + correlWidth / 2 >= (int) leftscan.size ())
  {
    cerr << "Excentred stripe" << endl;
    return;
  }

  // Gets the central template
  int *centralShape = new int[correlWidth];
  for (int i = 0; i < correlWidth; i++)
  {
    Pt2i pix = leftscan.at(0).at(minPos-correlWidth/2+i);
    centralShape[i] = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ();
  }

  // Computes the left correlation stripes
  vector <vector <Pt2i> >::iterator scit = leftscan.begin ();
  while (scit != leftscan.end ())
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((*scit).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (*scit).size ()) - correlWidth + 1; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          Pt2i pix = (*scit).at(j+k);
          int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ()
                     - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    leftCorrel.push_back (corr);
    leftReCorrel.push_back (recorr);
    scit ++;
  }

  // Computes the right correlation stripes
  scit = rightscan.begin ();
  while (scit != rightscan.end ())
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((*scit).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (*scit).size ()) - correlWidth + 1; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          Pt2i pix = (*scit).at(j+k);
          int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ()
                     - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    rightCorrel.push_back (corr);
    rightReCorrel.push_back (recorr);
    scit ++;
  }
}


/** Correlation calculation (second release).
 * Compares portions of scan bars with a mean profile extracted at
 * the center of the first Nth scans (N = correlThick).
 */
bool BSProfileItem::setMeanCorrelationStripes ()
{
  leftCorrel.clear ();
  rightCorrel.clear ();
  leftReCorrel.clear ();
  rightReCorrel.clear ();
  int minPos = (int) leftscan.at(0).size () / 2;
  if (correlWidth > (int) leftscan.at(0).size ())
  {
    cerr << "Can't get correlation stripes" << endl;
    return false;
  }

  // Gets the central template
  int *centralShape = new int[correlWidth];
  for (int i = 0; i < correlWidth; i++)
  {
    centralShape[i] = 0;
    for (int j = 0; j < correlThick; j++)
    {
      Pt2i pix = leftscan.at(j).at(minPos-correlWidth/2+i);
      centralShape[i] += ((QColor) image->pixel (QPoint (pix.x (),
                                    imageHeight - 1 - pix.y ()))).value ();
    }
    centralShape[i] /= correlThick;
  }

  // Computes the left correlation stripes
  vector <vector <Pt2i> >::iterator scit = leftscan.begin ();
  while (scit != leftscan.end ())
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((*scit).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (*scit).size ()) - correlWidth + 1; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          Pt2i pix = (*scit).at(j+k);
          int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ()
                     - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    leftCorrel.push_back (corr);
    leftReCorrel.push_back (recorr);
    scit ++;
  }

  // Computes the right correlation stripes
  scit = rightscan.begin ();
  while (scit != rightscan.end ())
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((*scit).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (*scit).size ()) - correlWidth + 1; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          Pt2i pix = (*scit).at(j+k);
          int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ()
                     - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    rightCorrel.push_back (corr);
    rightReCorrel.push_back (recorr);
    scit ++;
  }
  return true;
}


/** Correlation calculation (third release).
 * Compares 2D portions of scan bars (N = correlThick) with a 2D profile
 * extracted at the center of the first Nth scans (N = correlThick).
 */
bool BSProfileItem::setFull2dCorrelationStripes ()
{
  leftCorrel.clear ();
  rightCorrel.clear ();
  leftReCorrel.clear ();
  rightReCorrel.clear ();
  if ((int) leftscan.size () <= correlThick)
  {
    cerr << "Can't get correlation stripes : not enough left scans" << endl;
    return false;
  }
  int minPos = (int) leftscan.at(0).size () / 2;
  if (correlWidth > (int) leftscan.at(0).size ())
  {
    cerr << "Can't get correlation stripes : scans too narrow" << endl;
    return false;
  }

  // Gets the central template
  int *centralShape = new int[correlThick * correlWidth];
  for (int i = 0; i < correlWidth; i++)
    for (int j = 0; j < correlThick; j++)
    {
      Pt2i pix = leftscan.at(j).at(minPos-correlWidth/2+i);
      centralShape[j * correlWidth + i] = ((QColor) image->pixel (
               QPoint (pix.x (), imageHeight - 1 - pix.y ()))).value ();
    }

  // Computes the left correlation stripes
  for (int i = 0; i < (int) leftscan.size () - correlThick - 2; i++)
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((leftscan.at(i)).size ()) >= correlWidth)
      for (int j = 0; j < ((int) (leftscan.at(i)).size ()) - correlWidth; j++)
      {
        int val = 0;
        for (int cw = 0; cw < correlThick; cw ++)
          for (int k = 0; k < correlWidth; k++)
            if ((int) leftscan.at(i+cw).size () > j+k)
            {
              Pt2i pix = (leftscan.at(i+cw)).at(j+k);
              int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                    imageHeight - 1 - pix.y ()))).value ()
                       - centralShape[cw * correlWidth + k];
              val += (diff < 0 ? - diff : diff);
            }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    leftCorrel.push_back (corr);
    leftReCorrel.push_back (recorr);
  }

  // Computes the right correlation stripes
  for (int i = correlThick - 1; i < (int) rightscan.size () - 1; i++)
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((rightscan.at(i)).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (rightscan.at(i)).size ()) - correlWidth; j++)
      {
        int val = 0;
        for (int cw = 0; cw < correlThick; cw ++)
          for (int k = 0; k < correlWidth; k++)
            if ((int) rightscan.at(i-cw).size () > j+k)
            {
              Pt2i pix = (rightscan.at(i-cw)).at(j+k);
              int diff = ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ()
                     - centralShape[cw * correlWidth + k];
              val += (diff < 0 ? - diff : diff);
            }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    rightCorrel.push_back (corr);
    rightReCorrel.push_back (recorr);
  }
  return true;
}




/** Correlation calculation (ourth release).
 * Compares mean portions of scan bars (N = correlThick) with a mean
 * profile extracted at the center of the first Nth scans (N = correlThick).
 */
bool BSProfileItem::setMean2dCorrelationStripes ()
{
  leftCorrel.clear ();
  rightCorrel.clear ();
  leftReCorrel.clear ();
  rightReCorrel.clear ();
  if ((int) leftscan.size () <= correlThick)
  {
    cerr << "Can't get correlation stripes : not enough left scans" << endl;
    return false;
  }
  int minPos = (int) leftscan.at(0).size () / 2;
  if (correlWidth > (int) leftscan.at(0).size ())
  {
    cerr << "Can't get correlation stripes : scans too narrow" << endl;
    return false;
  }

  // Gets the central template
  int *centralShape = new int[correlWidth];
  for (int i = 0; i < correlWidth; i++)
  {
    centralShape[i] = 0;
    for (int j = 0; j < correlThick; j++)
    {
      Pt2i pix = leftscan.at(j).at(minPos-correlWidth/2+i);
      centralShape[i] += ((QColor) image->pixel (
               QPoint (pix.x (), imageHeight - 1 - pix.y ()))).value ();
    }
    centralShape[i] /= correlThick;
  }

  // Computes the left correlation stripes
  for (int i = 0; i < (int) leftscan.size () - correlThick - 2; i++)
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((leftscan.at(i)).size ()) >= correlWidth)
      for (int j = 0; j < ((int) (leftscan.at(i)).size ()) - correlWidth; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          int nbval = 0;
          int locval = 0;
          for (int cw = 0; cw < correlThick; cw ++)
          {
            if ((int) leftscan.at(i+cw).size () > j+k)
            {
              nbval ++;
              Pt2i pix = (leftscan.at(i+cw)).at(j+k);
              locval += ((QColor) image->pixel (QPoint (pix.x (),
                                    imageHeight - 1 - pix.y ()))).value ();
            }
          }
          int diff = locval / nbval - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    leftCorrel.push_back (corr);
    leftReCorrel.push_back (recorr);
  }

  // Computes the right correlation stripes
  for (int i = correlThick - 1; i < (int) rightscan.size () - 1; i++)
  {
    vector<int> corr;
    vector<int> recorr;
    if ((int) ((rightscan.at(i)).size ()) >= correlWidth)
    {
      for (int j = 0; j < ((int) (rightscan.at(i)).size ()) - correlWidth; j++)
      {
        int val = 0;
        for (int k = 0; k < correlWidth; k++)
        {
          int nbval = 0;
          int locval = 0;
          for (int cw = 0; cw < correlThick; cw ++)
          {
            if ((int) rightscan.at(i-cw).size () > j+k)
            {
              nbval ++;
              Pt2i pix = (rightscan.at(i-cw)).at(j+k);
              locval += ((QColor) image->pixel (QPoint (pix.x (),
                                  imageHeight - 1 - pix.y ()))).value ();
            }
          }
          int diff = locval / nbval - centralShape[k];
          val += (diff < 0 ? - diff : diff);
        }
        corr.push_back (val);
        recorr.push_back ((int) val);
      }
    }
    rightCorrel.push_back (corr);
    rightReCorrel.push_back (recorr);
  }
  return true;
}


void BSProfileItem::getLocalMinimaIndices (vector<int> &indices,
                                     const vector<int> &signal) const
{
  int ng = signal.size ();
  int offset = 0;
  bool up = true;

  // Gets the first distinct value from start
  while (offset < ng - 1 && signal.at (offset) == signal.at (0))
  {
    if (signal.at (offset) - signal.at (offset + 1) < 0)
    {
      up = true;
      break;
    }
    if (signal.at (offset) - signal.at (offset + 1) > 0)
    {
      up = false;
      break;
    }
    offset++;
  }

  for(int i = offset; i < ng - 1; i++)
  {
    if (up)
    {
      if ((signal.at (i + 1) - signal.at (i)) < 0) up = false;
    }
    else
    {
      if (signal.at (i + 1) - signal.at (i) > 0)
      {
        up = true;
        int k = i;
        while (signal.at (k) == signal.at (i)) k--;
        indices.push_back (k + 1 + (i - k - 1) / 2);
      }
    }
  }
}




void BSProfileItem::paintStripes (QPainter *painter)
{
  int lx = profileWidth + stripeMargin + stripeWidth / 2 - stripeResol / 2;
  int cx = 0, cy = widHeight / 2;
  vector <vector <Pt2i> >::iterator bigit;

  if (rightscan.size ())
    lx -= rightscan.at(0).size () * stripeResol / 2;
  else if (leftscan.size ())
    lx -= leftscan.at(0).size () * stripeResol / 2;
  painter->setPen (QPen (Qt::red, 2));
  painter->drawRect (profileWidth + stripeMargin - 1, stripeMargin - 1,
                     stripeWidth + 2, widHeight - 2 * stripeMargin + 2);

  // Lower part (right side)
  if (rightscan.size ())
  {
    bigit = rightscan.begin ();
    while (cy <= widHeight - stripeMargin - stripeResol
           && bigit != rightscan.end ())
    {
      cx = lx;
      vector<Pt2i> scan = *bigit;
      vector<Pt2i>::iterator it = scan.begin ();
      while (cx < widWidth - stripeMargin - stripeResol && it != scan.end ())
      {
        if (cx >= profileWidth + stripeMargin)
          painter->fillRect (cx, cy, stripeResol, stripeResol,
             QBrush (image->pixel ((*it).x (), imageHeight - 1 - (*it).y ())));
        it ++;
        cx += stripeResol;
      }
      bigit ++;
      cy += stripeResol;
    }
  }
  
  // Upper part (left side)
  if (leftscan.size ())
  {
    cy = widHeight / 2 - 2 * stripeResol;
    bigit = leftscan.begin ();
    while (cy >= stripeResol + 1 && bigit != leftscan.end ())
    {
      cx = lx;
      vector<Pt2i> scan = *bigit;
      vector<Pt2i>::iterator it = scan.begin ();
      while (cx < widHeight - stripeMargin - stripeResol && it != scan.end ())
      {
        if (cx >= profileWidth + stripeMargin)
          painter->fillRect (cx, cy, stripeResol, stripeResol,
             QBrush (image->pixel ((*it).x (), imageHeight - 1 - (*it).y ())));
        it ++;
        cx += stripeResol;
      }
      bigit ++;
      cy -= stripeResol;
    }
  }

  // Enclosing the central scan
  if (stripe >= 0)
    cy = widHeight / 2 - 1 - 2 * stripeResol - stripe * stripeResol;
  else cy = widHeight / 2 - 1 - (1 + stripe) * stripeResol;
  painter->setPen (QPen (Qt::green, 2));
  painter->drawRect (profileWidth + stripeMargin - 1, cy,
                     stripeWidth + 2, stripeResol + 2);
}


void BSProfileItem::paintIntensityProfile (QPainter *painter)
{
  if (rightscan.size () || leftscan.size ())
  {
    vector<Pt2i> scan;
    if (stripe >= 0) scan = leftscan.at (stripe);
    else scan = rightscan.at (- stripe - 1);
    int h, cx = 0, w = profileWidth / (leftscan.at(0)).size ();
    vector<Pt2i>::iterator it = scan.begin ();
    while (it != scan.end ())
    {
      if ((*it).x () < 0 || (*it).x () >= imageWidth
          || (*it).y () < 0 || (*it).y () >= imageHeight)
        cerr << "OUT OF IMAGE BOUNDS : (" << (*it).x () << ","
             << imageHeight - 1 - (*it).y () << ")" << endl;
      else
      {
        h = ((QColor) image->pixel (QPoint ((*it).x (),
                                    imageHeight - 1 - (*it).y ()))).value ();
        h = (h - profileLow) * profileRatio;
        if (h < 0) h = 0;
        else if (h > widHeight) h = widHeight;
        if (h) painter->fillRect (cx, widHeight - h, w, h, QBrush (Qt::blue));
        it ++;
        cx += w;
      }
    }

    painter->setPen (QPen (Qt::black, 2));
    scan = leftscan.at (0);
    it = scan.begin ();
    int prevh = ((QColor) image->pixel (QPoint ((*it).x (),
                                  imageHeight - 1 - (*it).y ()))).value ();
    prevh = (prevh - profileLow) * profileRatio;
    if (prevh < 0) prevh = 0;
    else if (prevh > widWidth) prevh = widWidth;
    cx = 0;
    while (it != scan.end ())
    {
      h = ((QColor) image->pixel (QPoint ((*it).x (),
                                  imageHeight - 1 - (*it).y ()))).value ();
      h = (h - profileLow) * profileRatio;
      if (h < 0) h = 0;
      else if (h > widWidth) h = widWidth;
      painter->drawLine (cx, widWidth - prevh, cx, widWidth - h);
      painter->drawLine (cx, widWidth - h, cx + w, widWidth - h);
      prevh = h;
      it ++;
      cx += w;
    }
  }
}


void BSProfileItem::paintGradientProfile (QPainter *painter)
{
  if (rightscan.size () || leftscan.size ())
  {
    vector<Pt2i> scan;
    if (stripe >= 0) scan = leftscan.at (stripe);
    else scan = rightscan.at (- stripe - 1);
    int cx = 0, w = profileWidth / (leftscan.at(0)).size ();
    int h, prevh;
    vector<Pt2i>::iterator it = scan.begin ();
    while (it != scan.end ())
    {
      if ((*it).x () < 0 || (*it).x () >= imageWidth
          || (*it).y () < 0 || (*it).y () >= imageHeight)
        cerr << "OUT OF IMAGE BOUNDS : (" << (*it).x () << ","
             << imageHeight - 1 - (*it).y () << ")" << endl;
      else
      {
        h = (gMap->magn ((*it).x (), (*it).y ()) - gradientLow)
            / gradientUnRatio;
        if (h < 0) h = 0;
        else if (h > widHeight) h = widHeight;
        if (h) painter->fillRect (cx, widHeight - h, w, h, QBrush (Qt::blue));
        it ++;
        cx += w;
      }
    }

    painter->setPen (QPen (Qt::black, 2));
    scan = leftscan.at (0);
    it = scan.begin ();
    prevh = (gMap->magn ((*it).x (), (*it).y ()) - gradientLow)
            / gradientUnRatio;
    if (prevh < 0) prevh = 0;
    else if (prevh > widWidth) prevh = widWidth;
    cx = 0;
    while (it != scan.end ())
    {
      h = (gMap->magn ((*it).x (), (*it).y ()) - gradientLow)
          / gradientUnRatio;
      if (h < 0) h = 0;
      else if (h > widWidth) h = widWidth;
      painter->drawLine (cx, widWidth - prevh, cx, widWidth - h);
      painter->drawLine (cx, widWidth - h, cx + w, widWidth - h);
      prevh = h;
      it ++;
      cx += w;
    }
  }
}



void BSProfileItem::paintCorrelationProfile (QPainter *painter)
{
  if (rightCorrel.size () || leftCorrel.size ())
  {
    Pt2i gr;
    vector<int> scan;
    vector<int> rescan;
    if (stripe >= 0)
    {
      scan = leftCorrel.at (stripe);
      rescan = leftReCorrel.at (stripe);
    }
    else
    {
      scan = rightCorrel.at (- stripe - 1);
      rescan = rightReCorrel.at (- stripe - 1);
    }

    int h, cx = 0, w = profileWidth / (leftscan.at(0)).size ();
    vector<int>::iterator it = scan.begin ();
    while (it != scan.end ())
    {
      h = (*it) * correlRatio;
      if (h > widHeight) h = widHeight;
      if (h) painter->fillRect (cx, widHeight - h, w, h, QBrush (Qt::blue));
      it ++;
      cx += w;
    }

    vector<int> locs;
    getLocalMinimaIndices (locs, rescan);
    it = locs.begin ();
    while (it != locs.end ())
    {
      h = scan.at(*it) * correlRatio;
      painter->fillRect ((*it) * w + 4, widHeight - h - 14, w - 8, 10,
                         QBrush (Qt::red));
      it ++;
    }

    painter->setPen (QPen (Qt::black, 2));
    scan = leftCorrel.at (0);
    it = scan.begin ();
    int prevh = (*it) * correlRatio;
    if (prevh > widWidth) prevh = widWidth;
    cx = 0;
    while (it != scan.end ())
    {
      h = (*it) * correlRatio;
      if (h > widWidth) h = widWidth;
      painter->drawLine (cx, widWidth - prevh, cx, widWidth - h);
      painter->drawLine (cx, widWidth - h, cx + w, widWidth - h);
      prevh = h;
      it ++;
      cx += w;
    }
  }
}