#include "hausdorff.h"

#define NORMA <=150


hausdorff::hausdorff(my_image * image,bool mod)
{
this->img_ref=NULL;
this->voroni_ref=NULL;
this->img=NULL;
this->voroni=NULL;

this->registruj_mod=mod;

this->img_ref=new my_image(image);


//show_image(this->voroni_ref);

if(this->registruj_mod){
    std::cout<<"registruji \n"<<std::endl;
    this->body_img_ref=this->registruj(this->img_ref);
    std::cout<< "registrovano "<<this->body_img_ref.size()<<" bodu REF obrazku\n"<<std::endl;
}else {
    std::cout<<"pocitam voroniho mapu\n"<<std::endl;
    this->voroni_ref=this->image2voroni(this->img_ref);
    std::cout<<"Prepocet mapy dokoncen\n"<<std::endl;
}

}

hausdorff::~hausdorff(){
    if(this->img_ref!=NULL)
        delete this->img_ref;
    if(this->voroni_ref!=NULL)
        delete this->voroni_ref;
    this->del_image();
}

void hausdorff::del_image(){
    if(this->img!=NULL)
        delete this->img;

    if(this->voroni!=NULL)
        delete this->voroni;
}


my_image *  hausdorff::image2voroni(my_image *image){

my_image * voro=new my_image(image);
voro->white_all();//nastavim obraz na bilou

for(int x=0;x<voro->Width();x++)
    for(int y=0;y<voro->Height();y++)
    {
        if(image->get(x,y) NORMA)
        {
            std::cout<<"pixel  "<<x<<" x "<<y<<" je cerny \n";
            this->flood(x,y,voro);
            voro->set(x,y,0);
        }
    }

return voro;
}


void hausdorff::flood(int x, int y, my_image *voro){
    int max_vzdal=500;
    voro->set(x,y,0);
    //kontrola hranic obrazu
        //levy horni roh
        int min_x=x-max_vzdal;
        if(min_x<0)min_x=0;
        int min_y=y-max_vzdal;
        if(min_y<0)min_y=0;
        //pravy spodni roh
        int max_x=x+max_vzdal;
        if(max_x>voro->Width())max_x=voro->Width();
        int max_y=y+max_vzdal;
        if(max_y>voro->Height())max_y=voro->Height();

        int act_vzdal;
   for(int i=min_x;i<max_x;i++)
       for(int j=min_y;j<max_y;j++){
                  act_vzdal=this->find_distant(x,y,i,j);
                  if(act_vzdal<voro->get(i,j)){//pokud je aktualni bod bliz, tak zapisu novou akt. vzdalenost
                      voro->set(i,j,act_vzdal);
                  }
        }
}





int hausdorff::find_distant(int x1,int y1,int x2,int y2) {
    int vzdalenost=0;
    int delta_x=abs(x1-x2);
    int delta_y=abs(y1-y2);


    //vzdalenost=delta_x+delta_y;//menhattan
    vzdalenost=(int)sqrt((double)pow(delta_x,2)+pow(delta_y,2));//euklid
    //vzdalenost=(delta_x > delta_y) ? delta_x : delta_y;//cheesboard

    return vzdalenost;
}


void hausdorff::find(my_image *image){
    this->del_image();//smaze posledni nacteny obraz
    this->img=new my_image(image);


    //show_image(this->voroni);
    if(this->registruj_mod){
        std::cout<<"registruji vstupni obraz\n";
        this->body_img=this->registruj(this->img);
        std::cout<< "registrovano "<<this->body_img_ref.size()<<" bodu REF a "<<this->body_img.size()<<"body obrazku\n"<<std::endl;
        this->H_ab_reg();
    }else {
        std::cout<<"pocitam voroniho pro vstupni obraz\n";
        std::cout<<"to neni potreba->preskakuju\n";
        //this->voroni=this->image2voroni(this->img);
        std::cout<<"voroniho prevod byl dokoncen\n"<<std::endl;
        this->H_ab();
    }


    std::cout<<"min vzdalenost je "<<this->location.val<<" na souradnicich "<<this->location.x<<" x " <<this->location.y<<"\n";
    std::cout<<"HD skoncila hledani\n"<<std::endl;
}


int hausdorff::H_ab(){
    int min=9999,temp;
    int half_size_x=this->img->Width()/2;
    int half_size_y=this->img->Height()/2;
    this->body.erase(body.begin(),body.end());
    for(int i=0;i<this->voroni_ref->Width()-this->img->Width();i++){
        for(int j=0;j<this->voroni_ref->Height()-this->img->Height();j++){
            temp=this->h_ab(i,j,this->img,this->voroni_ref);
            if(temp<min){
                min=temp;
                this->location.x=i;
                this->location.y=j;
                this->location.val=min;
                std::cout<<"nove minimum  "<<this->location.val<<" na souradnicich "<<this->location.x<<" x " <<this->location.y<<"\n";
                //this->body.push_back(BOD(i,j,min));
                this->body.insert(this->body.begin(),BOD(i+half_size_x,j+half_size_y,min));
              //  this->body.insert(this->body.begin(),BOD(i,j,min));
            }
        }
    }

    return min;
}



int hausdorff::h_ab(int posun_x, int posun_y, my_image *imageA, my_image *voroB){//posun je posuna ref. obrazu
    int max=0;
    int max_w=imageA->Width();
    int max_h=imageA->Height();

    for(int i=0;i<max_w;i++){
        for(int j=0;j<max_h;j++){
            if(imageA->get(i,j) NORMA){//pokud je bod, potom najdi nejmensi vzdalenost (voroni)
                if(max<voroB->get(i+posun_x,j+posun_y)){//pokud je nejmensi vzdalenost vetsi nez max, uloz max
                    max=voroB->get(i+posun_x,j+posun_y);
                }
            }
        }
    }

    return max;
}




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////ALGORITMUS S REGISTRACI NORMOVANYCH BODU:///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



std::vector<BOD> hausdorff::registruj(my_image *image){
    int max_w=image->Width();
    int max_h=image->Height();
    uchar val;
    std::vector<BOD> ret;

    for(int i=0;i<max_w;i++){
        for(int j=0;j<max_h;j++){
            val=image->get(i,j);
            if(val NORMA){//pokud je bod
                ret.push_back(BOD(i,j,val));
            }
        }
    }
    return ret;
}


void hausdorff::H_ab_reg(){
    float min=9999,temp;
    int half_size_x=this->img->Width()/2;
    int half_size_y=this->img->Height()/2;
    int max_w=this->img_ref->Width()-this->img->Width();
    int max_h=this->img_ref->Height()-this->img->Height();
    this->act_min_posun=min;

    this->body.erase(body.begin(),body.end());


    for(int i=0;i<max_w;i++){
        for(int j=0;j<max_h;j++){
        //    std::cout<<"zjistuji pro posun "<<i<<" x "<<j<<"\n"<<std::endl;
            temp=this->h_ab_reg(i,j,this->img,this->img_ref);

            if(temp<min){
                min=temp;
                this->act_min_posun=min;
                this->location.x=i;
                this->location.y=j;
                this->location.val=min;
                std::cout<<"nove minimum  "<<this->location.val<<" na souradnicich "<<this->location.x<<" x " <<this->location.y<<"\n";
                //this->body.push_back(BOD(i,j,min));
                this->body.insert(this->body.begin(),BOD(i+half_size_x,j+half_size_y,min));
              //  this->body.insert(this->body.begin(),BOD(i,j,min));

            }
        }
    }//*/

}



float hausdorff::h_ab_reg(int posun_x, int posun_y, my_image *imageA, my_image *imageB){
    int max_iter=this->body_img.size();

    float max=0,max_act;

    for(int i=0;i<max_iter;i++){
            if(this->act_min_posun<max)//zrychleni algoritmu
                return max;
               max_act=this->Find_Nearest_Point_reg(BOD(this->body_img[i].x+posun_x,this->body_img[i].y+posun_y),imageB );
               if(max_act>max){
                    max=max_act;
               }
    }

    return max;

}

float hausdorff::Find_Nearest_Point_reg(BOD stred,my_image * image){
    float min=9999,temp;
    int max_iter=this->body_img_ref.size();

    for(int i=0;i<max_iter;i++){
        //temp=this->find_distant(stred.x,stred.y,image,this->body_img_ref[i].x,this->body_img_ref[i].y);
        temp=this->find_distant(stred.x,stred.y,this->body_img_ref[i].x,this->body_img_ref[i].y);
        if(temp<min)
           min=temp;
    }

return min;
}



