/**
    \file main.cpp
    Main program to test distance transform algorithms.

    \author George J. Grevera, Ph.D., ggrevera@sju.edu

    Copyright (C) 2002, George J. Grevera

    This program 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.

    This program 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 mor
    e details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
    USA or from http://www.gnu.org/licenses/gpl.txt.

    This General Public License does not permit incorporating this
    code into proprietary programs.  (So a hypothetical company such
    as GH (Generally Hectic) should NOT incorporate this code into
    their proprietary programs.)
 */

static const int  size         = 500;  ///< 2D images of size x size
static const int  iterCount    =    1;
static const int  borderOffset =   10;

typedef    unsigned char    uchar;

//#define CenterPointTest
#define  PointTest

#ifdef  PointTest
  #if 0
    //the original "dreaded" test
    static const int ptCount  = 3;
    static const int ptOffset = size/2;
    static int pt[ptCount][2] = { { 0+ptOffset, 2+ptOffset },    // x,y
                                  { 1+ptOffset, 6+ptOffset },
                                  { 2+ptOffset, 8+ptOffset } };
  #endif
  #if 0
    //a reflection of the original "dreaded" test
    static const int ptCount  = 3;
    static const int ptOffset = size/2;
    static int pt[ptCount][2] = { { ptOffset-0, 2+ptOffset },    // x,y
                                  { ptOffset-1, 6+ptOffset },
                                  { ptOffset-2, 8+ptOffset } };
  #endif
  #if 0
    //one point in the center
    static const int ptCount  = 1;
    static int       pt[ptCount][2] = { { size/2, size/2 } };  // x,y
  #endif
  #if 1
    #define RandomTest
    static const int ptCount = size*size/4;
    static int       pt[ptCount][2];  //will be randomly filled in
  #endif
#endif

#include <assert.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <typeinfo>

#include "DistanceTransform.h"
#include "Chamfer2D_3x3.h"
#include "Chamfer2D_5x5.h"
#include "Chamfer2D_7x7.h"
#include "Chessboard2D.h"
#include "Cityblock2D.h"
#include "DeadReckoning_3x3.h"
#include "DeadReckoning_7x7.h"
#include "DijkstraVectors.h"
#include "Euclidean2D.h"
#include "FourSED.h"
#include "EightSED.h"
#include "EightSED_modified.h"
#include "ModifiedDijkstra.h"
#include "Simple.h"
#include "SimpleList.h"
#include "CSED.h"
#include "errorfreeCSED.h"

#ifdef WIN32
#  include <windows.h>
#  include <winbase.h>
#endif

#include "Timer.h"
#include "TIFFWriter.h"

using namespace std;
//----------------------------------------------------------------------
/// Normal class which samples random numbers from a normal distribution using the Box-Muller transform.
class Normal {
private:
    bool    mValid;  ///< has the second random number been cached?
    double  mX2;     ///< this method generates pairs of random numbers, caching the second one here.

    /// this method returns a random number in the range [0.0 ... 1.0].
    double Random ( ) {
        const double  r = rand();
        return r / RAND_MAX;
    }

public:
    /// class constructor.
    Normal ( ) {
        mValid = false;
        mX2    = 0;
        srand( time(NULL) );
    }

    /// given a mean m and std dev s, return a sample from a normal distribution.
    double sample ( double m=0.0, double s=1.0 ) {
        // normal distribution with mean m and standard deviation s
        if (mValid) {     // we have a valid result from last call
            mValid = false;
            return mX2 * s + m;
        }
    
        // make two normally distributed variates by Box-Muller transformation
        double  x1;  // first random coordinate (second one is class member)
        double  w;   // radius
        do {
            x1  = 2.0 * Random() - 1.0;  // -1..1
            mX2 = 2.0 * Random() - 1.0;  // -1..1
            w = x1*x1 + mX2*mX2;
        } while (w >= 1.0 || w < 1E-30);
        w = sqrt(log(w)*(-2.0/w));
        x1     *= w;
        mX2    *= w;     // x1 and x2 are independent, normally distributed variables
        mValid =  true;  // cache x2 for next call
        return x1 * s + m;
    }
};
//----------------------------------------------------------------------
static void writeDistance ( const char* const fname, DistanceTransform* dt )
{
    // cout << endl << "writeDistance: skip writing distance." << endl;  return;
    double*  d = (double*)malloc(size*size*sizeof(double));    assert(d!=NULL);
    int  i=0;
    for (int y=0; y< ::size; y++) {
        for (int x=0; x< ::size; x++) {
            double  v = dt->getD(x,y);
            if (v<0)  v = -v;
            if (v >= dt->IntInfinity || v >= dt->FloatInfinity)    v = 0;
            d[i++] = v;
        }
    }
    TIFFWriter::write_tiff_double_grey( d, size, size, fname );
    free(d);   d=NULL;
}
//----------------------------------------------------------------------
static void writeBinaryImage ( const char* const fname, const uchar* const I )
{
    //save a tiff image of the original binary image data
    uchar*  uc = (uchar*)malloc( size*size*sizeof(uchar) );    assert( uc!=NULL );
    for (int i=0; i< ::size*::size; i++) {
        if (I[i])    uc[i]=255;
        else         uc[i]=  0;
    }
    FILE*  fp = fopen( "original.tif", "wb" );
    assert( fp!=NULL );
    TIFFWriter::write_tiff_data8_grey( uc, ::size, ::size, fp, 1 );
    fclose( fp );    fp=NULL;
    free( uc );      uc=NULL;
}
//----------------------------------------------------------------------
static void getMinMax ( DistanceTransform* dt ) {
    double min =  dt->FloatInfinity;
    double max = -dt->FloatInfinity;
    for (int y=::borderOffset; y<size-::borderOffset; y++) {
        for (int x=::borderOffset; x<size-::borderOffset; x++) {
            const double d = dt->getD(x,y);
            if (d >=  dt->IntInfinity || d >=  dt->FloatInfinity)  continue;
            if (d <= -dt->IntInfinity || d <= -dt->FloatInfinity)  continue;
            if (d>max)  max=d;
            if (d<min)  min=d;
        }
    }
    cout << "    min=" << min << ", max=" << max << endl;
}
//----------------------------------------------------------------------
static uchar getData ( const uchar* const I, const int x, const int y ) {
    if (x<0 || y<0 || x>=size || y>=size)    return 0;
    return I[y*size + x];
}
//----------------------------------------------------------------------
static inline bool isBorderElement ( const uchar* const I, const int x,
                                     const int y )
{
    const uchar center = getData(I, x, y);
    uchar other;

    other = getData(I, x-1, y);
    if (center != other)  return true;
    other = getData(I, x+1, y);
    if (center != other)  return true;
    other = getData(I, x,   y-1);
    if (center != other)  return true;
    other = getData(I, x,   y+1);
    if (center != other)  return true;
    return false;
}
//----------------------------------------------------------------------
static void checkError ( const uchar* const I,
                         const DistanceTransform* const dt,
                         const char* const diffFileName,
                         const DistanceTransform* const gold ) {
#ifdef PointTest
    double*  diffImage = (double*)malloc(size*size*sizeof(double));
    assert( diffImage!=NULL );
    for (int i=0; i<size*size; i++)    diffImage[i]=0;

    double  maxDiff   = 0;
    int     maxDiffX  =-1;
    int     maxDiffY  =-1;
    double  err       = 0;
    long    count     = 0;
    long    diffCount = 0;

    for (int y=::borderOffset; y<size-::borderOffset; y++) {
        for (int x=::borderOffset; x<size-::borderOffset; x++) {
            const double  d  = dt->getD(x,y);
            const double  gd = gold->getD(x,y);
            if (d==dt->IntInfinity || d==dt->FloatInfinity) {
                cout << "checkError: infinite distance at ("
                     << x << "," << y << ") ignored." << endl;
                continue;
            }

            ++count;
            double  magDiff = fabs(d - gd);
            diffImage[y*size + x] = magDiff;
            if (magDiff > 0) {
                ++diffCount;
                err += (d-gd)*(d-gd);
                if (magDiff > maxDiff) {
                    maxDiff  = magDiff;
                    maxDiffX = x;
                    maxDiffY = y;
                }
            }

        }
    }

    err /= count;
    err =  sqrt(err);
    cout << ", rmse=" << err << ", max diff=" << maxDiff
         << " at (" << maxDiffX << "," << maxDiffY << "), diff count="
         << diffCount
         << endl;

    TIFFWriter::write_tiff_double_grey( diffImage, size, size, diffFileName );
    free(diffImage);    diffImage=NULL;
#endif
}
//----------------------------------------------------------------------
static void checkError ( const uchar* const I,
                         const DistanceTransform* const dt,
                         const char* const diffFileName ) {
#ifdef PointTest
    double* diffImage = (double*)malloc(size*size*sizeof(double));
    assert(diffImage!=NULL);
    for (int i=0; i<size*size; i++)    diffImage[i]=0;

    double maxDiff   = 0;
    int    maxDiffX  =-1;
    int    maxDiffY  =-1;
    double err       = 0;
    long   count     = 0;
    long   diffCount = 0;

    for (int y=::borderOffset; y<size-::borderOffset; y++) {
        for (int x=::borderOffset; x<size-::borderOffset; x++) {
            //is the point an element of the border?
            if (isBorderElement(I, x, y)) {
                //yes, so its distance should be 0
                const double d = fabs( dt->getD(x,y) );
                if (d==dt->IntInfinity || d==dt->FloatInfinity) {
                    // cout << "checkError: "
                    //      << "infinite distance for border element at ("
                    //      << x << "," << y << ")" << endl;
                    continue;
                }
                if (d!=0.0) {
                    cout << "checkError: non zero distance=" << d
                         << " for border element at "
                         << "(" << x << "," << y << ")"
                         << endl;
                    ++diffCount;
                }
                diffImage[y*size + x] = d;
                err += d*d;
                ++count;
            } else {
                const double d = fabs( dt->getD(x,y) );
                if (d==dt->IntInfinity || d==dt->FloatInfinity) {
                    // cout << "checkError: "
                    //      << "infinite distance for non border element at ("
                    //      << x << "," << y << ")" << endl;
                    continue;
                }
                ++count;
                //calc min distance from this point to points on the 
                // border points in the list
                double min = dt->FloatInfinity;
                for (int r=0; r<ptCount; r++) {
                    int iex, iey;

                    iex = pt[r][0]-1,    iey = pt[r][1];
                    if (isBorderElement(I, iex, iey)) {
                        const double tmp = sqrt( (double)((x-iex)*(x-iex) +
                                                 (y-iey)*(y-iey)) );
                        if (tmp<min)  min=tmp;
                    }

                    iex = pt[r][0]+1,    iey = pt[r][1];
                    if (isBorderElement(I, iex, iey)) {
                        const double tmp = sqrt( (double)((x-iex)*(x-iex) +
                                                 (y-iey)*(y-iey)) );
                        if (tmp<min)  min=tmp;
                    }

                    iex = pt[r][0],    iey = pt[r][1]-1;
                    if (isBorderElement(I, iex, iey)) {
                        const double tmp = sqrt( (double)((x-iex)*(x-iex) +
                                                 (y-iey)*(y-iey)) );
                        if (tmp<min)  min=tmp;
                    }

                    iex = pt[r][0],    iey = pt[r][1]+1;
                    if (isBorderElement(I, iex, iey)) {
                        const double tmp = sqrt( (double)((x-iex)*(x-iex) +
                                                 (y-iey)*(y-iey)) );
                        if (tmp<min)  min=tmp;
                    }
                }
                double tmpDiff = (d-min)*(d-min);
                err += tmpDiff;
                tmpDiff = sqrt(tmpDiff);
                if (tmpDiff>maxDiff) {
                    maxDiff  = tmpDiff;
                    maxDiffX = x;
                    maxDiffY = y;
                }

                diffImage[y*size + x] = fabs(d - min);
                // diffImage[y*size + x] = (!(d == min));
                // diffImage[y*size + x] = (!(d == min));
                if (!(d==min)) {
                    ++diffCount;
                    //int px, py;
                    // if ( dt->getP(x, y, px, py) )
                    //     cout << "    p(" << x << "," << y << ")=(" << px
                    //     << "," << py << ")" << endl;
                }
            }

        }
    }

    err /= count;
    err =  sqrt(err);
    cout << ", rmse=" << err << ", max diff=" << maxDiff
         << " at (" << maxDiffX << "," << maxDiffY << "), diff count="
         << diffCount
         << endl;

    TIFFWriter::write_tiff_double_grey( diffImage, size, size, diffFileName );
    free(diffImage);    diffImage=NULL;
#endif
}
//----------------------------------------------------------------------
static void checkCenterPointError ( DistanceTransform* dt ) {
  #ifdef CenterPointTest
    const int c=size/2;

    assert( dt->getD(c,  c)   == 0 );
    assert( dt->getD(c-1,c)   == 0 );
    assert( dt->getD(c+1,c)   == 0 );
    assert( dt->getD(c,  c-1) == 0 );
    assert( dt->getD(c,  c+1) == 0 );

    double err2=0, maxErr=0;
    int    maxX=-1, maxY=-1;
    int    count=0;
    double A=0, B=0;  //to calc variance
    int y;
    //const int off  = 10;
    for (y=::borderOffset; y<size-::borderOffset; y++) {
        for (int x=::borderOffset; x<size-::borderOffset; x++) {
            if (y==c && x==c)  continue;
            const double d = fabs( dt->getD(x,y) );
            if (d==dt->IntInfinity || d==dt->FloatInfinity)  continue;

            ++count;
            //calc min distance from this point to points on the 
            // immediate exterior (which also have 0 assigned to them)
            int    iex=c-1, iey=c;
            double min = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );

            iex=c+1,  iey=c;
            double tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            iex=c,  iey=c-1;
            tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            iex=c,  iey=c+1;
            tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            A += (d-min)*(d-min);
            B += (d-min);
            const double e2=(d-min)*(d-min);
            err2 += e2;
            if (e2>maxErr) {
                maxErr = e2;
                maxX   = x;
                maxY   = y;
            }
        }
    }
    cout << "checkCenterPointError: total ie error^2=" << err2
         << ", mse=" << err2/count << " (rmse=" << sqrt(err2/count) << ")";
    const double var = (A - B*B/count)/(count-1);
    cout << ", total ie variance=" << var << ", max err=" << sqrt(maxErr)
         << " @ (" << maxX << "," << maxY << ")";
    if (maxX!=-1 && maxY!=-1)    cout << "=" << dt->getD(maxX,maxY);
    cout << endl << endl;
#if 0
    for (y=0; y<size; y++) {
        for (int x=0; x<size; x++) {
            if (y==c && x==c)  continue;  //skip the center
            const double d = fabs( dt->getD(x,y) );
            if (d==dt->IntInfinity || d==dt->FloatInfinity)  continue;
            //calc min distance from this point to points on the 
            // immediate exterior (which also have 0  assigned to them)
            int    iex=c-1, iey=c;
            double min = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );

            iex=c+1,  iey=c;
            double tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            iex=c,  iey=c-1;
            tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            iex=c,  iey=c+1;
            tmp = sqrt( (x-iex)*(x-iex) + (y-iey)*(y-iey) );
            if (tmp<min)  min=tmp;

            const double e2=fabs(d-min);
            if (e2>=maxErr) {
                cout << "max ie err        =" << maxErr << " @ (" << x
                     << "," << y << ")" << endl;
            }
        }
    }
#endif
  #endif
}
//----------------------------------------------------------------------
static void colorParent ( const DistanceTransform* const dt,
                          const char* const binFileName,
                          const int px, const int py )
{
    #ifndef PointTest
        return;
    #endif

    double* binImage = (double*)malloc(size*size*sizeof(double));
    assert(binImage!=NULL);
    for (int i=0; i<size*size; i++)    binImage[i]=0;
#ifdef WIN32
    if (true) {
#else
    //doesn't work when using the Windows NiceTry compiler
    if (typeid(*dt) == typeid(DijkstraVectors) ) {
#endif
        const DijkstraVectors* const dv = (const DijkstraVectors* const)dt;
        for (int y=::borderOffset; y<size-::borderOffset; y++) {
            for (int x=::borderOffset; x<size-::borderOffset; x++) {
                int i=0, tx=-1, ty=-1;
                bool foundIt=false;
                while ( dv->getP(x, y, tx, ty, i) ) {
                    if (tx == px && ty == py) {
                        foundIt=true;
                        break;
                    }  //fi
                    i++;
                }  //elihw
                if (foundIt)    binImage[y*size + x] = 1;
            }  //rof x
        }  //for y

        cout << endl << endl << endl;
        int tx, ty;
        dv->getP(26, 31, tx, ty);
        dv->getD(26, 31);
    }  //fi

    TIFFWriter::write_tiff_double_grey( binImage, size, size, binFileName );
    free(binImage);    binImage=NULL;
}
//----------------------------------------------------------------------
int main ( const int argc, const char* const argv[] ) {

    uchar*  I = (uchar*)malloc( size*size*sizeof(*I) );
    assert( I!=NULL );
    int  i;
    for (i=0; i<size*size; i++)  I[i]=0;

    cout << endl << "iteration count = " << ::iterCount << endl;

#ifdef RandomTest
    cout << "random test.  input image size: (" << ::size << "," << ::size
         << "), " << ::ptCount << " random points. "
         << 100.0*((double)::ptCount/(::size * ::size)) << "%." << endl;
    const int tSeed = time(NULL);
    srand( tSeed );
    cout << "random number generator seeded w/ time: " << tSeed << "." << endl;
    // srand( 10 );    cout << "constant random number seed." << endl;
    Normal  norm;
    for (int k=0; k< ::ptCount; k++) {

        int  r1, r2;
        //sample from a uniform distribution
        //r1 = (rand() % (::size - ::borderOffset)) + 5;
        //r2 = (rand() % (::size - ::borderOffset)) + 5;

        //sample from a normal distribution
        r1 = norm.sample( ::size/2, ::size*0.05 );  //0.05 or 0.2
        r2 = norm.sample( ::size/2, ::size*0.05 );

        if (r1 <  ::borderOffset)         r1 = ::borderOffset;
        if (r1 >= ::size-::borderOffset)  r1 = ::size-::borderOffset;
        if (r2 <  ::borderOffset)         r2 = ::borderOffset;
        if (r2 >= ::size-::borderOffset)  r2 = ::size-::borderOffset;
        ::pt[k][0] = r2;  //x
        ::pt[k][1] = r1;  //y
        I[r1*size + r2] = 1;
    }
#endif

#ifdef CenterPointTest
    I[size/2*size + size/2] = 1;  //single point in center
    cout << "center at (" << size/2 << "," << size/2 << ")="
         << (int)I[size/2*size + size/2] << endl;
#endif

#ifdef PointTest
    cout << "point test.  input image size: (" << ::size << "," << ::size
         << ")" << endl;
    for (int r=0; r<ptCount; r++) {
        const int x = ::pt[r][0];
        const int y = ::pt[r][1];
        I[y*size + x] = 1;
    }
#endif

#if !defined(CenterPointTest) && !defined(PointTest)
    I[size/3*size + size/3]   = 1;
    I[size/2*size + 3*size/4] = 1;
    I[3*size/4*size + size/4] = 1;
#endif

    writeBinaryImage( "original.tif", I );
    cout << "gold standard" << endl;
    SimpleList*  gold = new SimpleList(size, size, true);
    gold->doTransform( I );

    {
        cout << "Chamfer2D_3x3 running" << endl;
        Timer* t = new Timer("Chamfer2D_3x3");
            Chamfer2D_3x3* dt = new Chamfer2D_3x3(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Chamfer2D_3x3.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Chamfer2D_3x3_diff.tif", gold);
    }

    {
        cout << "Chamfer2D_3x3_iterate running" << endl;
        Timer* t = new Timer("Chamfer2D_3x3_iterate");
            Chamfer2D_3x3* dt = new Chamfer2D_3x3(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->iterateTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Chamfer2D_3x3_iterate.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Chamfer2D_3x3_iterate_diff.tif", gold);
    }

    {
        cout << "Chamfer2D_5x5 running" << endl;
        Timer* t = new Timer("Chamfer2D_5x5");
            Chamfer2D_5x5* dt = new Chamfer2D_5x5(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Chamfer2D_5x5.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Chamfer2D_5x5_diff.tif", gold);
    }

    {
        cout << "Chamfer2D_7x7 running" << endl;
        Timer* t = new Timer("Chamfer2D_7x7");
            Chamfer2D_7x7* dt = new Chamfer2D_7x7(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Chamfer2D_7x7.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Chamfer2D_7x7_diff.tif", gold);
    }

    {
        cout << "Chessboard2D running" << endl;
        Timer* t = new Timer("Chessboard2D");
            Chessboard2D* dt = new Chessboard2D(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Chessboard2D.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Chessboard2D_diff.tif", gold);
    }

    {
        cout << "Cityblock2D running" << endl;
        Timer* t = new Timer("Cityblock2D");
            Cityblock2D* dt = new Cityblock2D(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Cityblock2D.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Cityblock2D_diff.tif", gold);
    }

    {
        cout << "DeadReckoning_3x3 running" << endl;
        Timer* t = new Timer("DeadReckoning_3x3");
            DeadReckoning_3x3* dt = new DeadReckoning_3x3(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("DeadReckoning_3x3.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "DeadReckoning_3x3_diff.tif", gold);
    }

    {
        cout << "DeadReckoning_7x7 running" << endl;
        Timer* t = new Timer("DeadReckoning_7x7");
            DeadReckoning_7x7* dt = new DeadReckoning_7x7(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("DeadReckoning_7x7.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "DeadReckoning_7x7_diff.tif", gold);
    }

    {
        cout << "Euclidean2D running" << endl;
        Timer* t = new Timer("Euclidean2D");
            Euclidean2D* dt = new Euclidean2D(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Euclidean2D.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Euclidean2D_diff.tif", gold);
    }

    {
        cout << "FourSED running" << endl;
        Timer* t = new Timer("FourSED");
            FourSED* dt = new FourSED(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("FourSED.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "FourSED_diff.tif", gold);
    }

    {
        cout << "EightSED running" << endl;
        Timer* t = new Timer("EightSED");
            EightSED* dt = new EightSED(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("EightSED.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "EightSED_diff.tif", gold);
    }

    {
        cout << "EightSED_modified running" << endl;
        Timer* t = new Timer("EightSED_modified");
            EightSED_modified* dt = new EightSED_modified(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("EightSED_modified.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "EightSED_modified_diff.tif", gold);
    }

    {
        cout << "ModifiedDijkstra running" << endl;
        Timer* t = new Timer("ModifiedDijkstra");
            ModifiedDijkstra* dt = new ModifiedDijkstra(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->modifiedDijkstra(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("ModifiedDijkstra.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "ModifiedDijkstra_diff.tif", gold);
    }

    {
        cout << "ModifiedDijkstra_DeadReckoning running" << endl;
        Timer* t = new Timer("ModifiedDijkstra_DeadReckoning");
            ModifiedDijkstra* dt = new ModifiedDijkstra(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->modifiedDijkstra_DeadReckoning(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("ModifiedDijkstra_DeadReckoning.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "ModifiedDijkstra_DeadReckoning_diff.tif", gold);
    }

    {
        cout << "ModifiedDijkstra_ModifiedDeadReckoning running" << endl;
        Timer* t = new Timer("ModifiedDijkstra_ModifiedDeadReckoning");
            ModifiedDijkstra* dt = new ModifiedDijkstra(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->modifiedDijkstra_ModifiedDeadReckoning(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("ModifiedDijkstra_ModifiedDeadReckoning.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "ModifiedDijkstra_ModifiedDeadReckoning_diff.tif", gold);
    }

    {
        cout << "DijkstraVectors running" << endl;
        Timer* t = new Timer("DijkstraVectors");
            DijkstraVectors* dt = new DijkstraVectors(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("DijkstraVectors.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "DijkstraVectors_diff.tif", gold);
#ifdef PointTest
        colorParent( dt, "DijkstraVectors_parent.tif",
                     ::pt[1][0]+1, ::pt[1][1] );
#endif
    }

    if (false) {
        cout << "Simple running" << endl;
        Timer* t = new Timer("Simple");
            Simple* dt = new Simple(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("Simple.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "Simple_diff.tif", gold);
    } else {
        cout << "Simple not running" << endl;
    }

    if (true) {
        cout << "SimpleList running" << endl;
        Timer* t = new Timer("SimpleList");
            SimpleList* dt = new SimpleList(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("SimpleList.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "SimpleList_diff.tif", gold);
    }

    {
        cout << "CSED running" << endl;
        Timer* t = new Timer("CSED");
            CSED* dt = new CSED(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("CSED.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "CSED_diff.tif", gold);
    }

    if (false) {
        cout << "errorfreeCSED running" << endl;
        Timer* t = new Timer("errorfreeCSED");
            errorfreeCSED* dt = new errorfreeCSED(size, size, true);
            for (i=1; i<=iterCount; i++)    dt->doTransform(I);
        delete t;  t=NULL;
        getMinMax(dt);
        writeDistance("errorfreeCSED.tif", dt);
        //checkCenterPointError(dt);
        checkError(I, dt, "errorfreeCSED_diff.tif", gold);
    }

    return 0;
}
//----------------------------------------------------------------------

