// Auteurs
// Matthieu Aubry
// Anthony Combe
// Licence
// Domaine publique
Unit insapetanque_unit;

interface

// on inclue les unit de niveau inf�ieur
uses outils_unit,image_unit,mesure_unit, comptage_unit;

// Constantes
CONST IMAGE_CHIFFRES='photos/nombres.ppm'; // image contenant 0123456789
CONST BOULE_DIAMETRE=7; // diam�re boule de p�anque en cm
CONST COCHONNET_DIAMETRE=3; // diam�re cochonnet en cm
CONST SB_MINI = (BOULE_DIAMETRE  * BOULE_DIAMETRE DIV 4) * 3.14; // surface mini de la boule (en cm)

// type RGB
type rgb = (rouge, vert, bleu);

function applique_seuil_composante(img: pTimage; composante : rgb; arg: integer) : pTimage;
function get_cochonnet(pdeb2 : pliste_objets):comp_objet;
function get_moyenne_largeur(pdeb : pliste_objets): integer;

procedure trace_trait_objets_cochonnet(var img : pTimage; pdeb : pliste_objets; cochonnet : comp_objet);

implementation

// 
// trace un segment entre 2 points sur une image
// @param img : image cible
// @param x1,y1 et x2,y2 : les 2 points du segment �tracer
// @param red, green, blue : couleur du trait �tracer
procedure trace_ligne(img : pTimage ; x1,y1,x2,y2 : integer; red,green,blue : byte);
var a,b : real;
    x,y,xinf,xsup,yinf,ysup:integer;
begin
    //equation y=x
    if(x1 = x2) then
    begin
        if(y1<y2) then
        begin
            yinf:=y1;
            ysup:=y2;
        end
        else
        begin
            yinf:=y2;
            ysup:=y1;
        end;
        
        for y := yinf to ysup-1 do
            write_pixel(x1,y,img,red,green,blue);
    end
    
    else
    begin
        a := (y1 - y2) / (x1 - x2);
        b := y1 - a * x1;
    
    
        if (a >= -1) and (a <= 1) then
        begin
            if(x1<x2) then
            begin
                xinf:=x1;
                xsup:=x2;
            end
            else 
            begin
                xinf:=x2;
                xsup:=x1;
            end;
            
            for x := xinf to xsup-1 do
                write_pixel(x,round(a*x+b),img, red,green,blue);
        end
    
        else
        begin
            if(y1<y2) then
            begin
                yinf:=y1;
                ysup:=y2;
            end
            else 
            begin
                yinf:=y2;
                ysup:=y1;
            end;
            
            for y := yinf to ysup-1 do  
                write_pixel(round((y-b) / a) , y, img, red,green,blue);
        end;
    end;
end;

// 
// renvoie l'image du nombre pass� en param�re
// @param longint n : nombre source de type 
// @return pointeur vers l'image obtenue
function get_image_nombre(n : longint) : pTimage;
var img, imgnombre : pTimage;
    strnb : string;
    k, i, j, debut, largeur_digit : integer;
    comp : byte;
begin
    // on load l'image contenant les chiffres
    imgnombre := read_image(IMAGE_CHIFFRES);
    
    strnb:='';
    // on fait du nombre une chaine de caract�e
    str(n, strnb);
    // largeur d'un digit
    largeur_digit := imgnombre^.largeur div 10;
    
    // on cr� l'image qui va recevoir le nombre
    img := new_image;
    img^.largeur := (largeur_digit + 2 ) * length(strnb);
    img^.hauteur := imgnombre^.hauteur;
    
    // on remplit l'image de pixels blancs
    for i:=0 to img^.largeur do
        for j:=0 to img^.hauteur do
            write_pixel(i, j, img, 255, 255, 255);
    
    // on parcourt tous les chiffres du nombre contenu dans la chaine
    for k:=0 to length(strnb)-1 do
        begin
        // abscisse du caract�e �copier
        debut := (ord(strnb[k+1])-48) * largeur_digit;
       
        // on copie les pixels un par un
        for i:= debut to debut+largeur_digit-1 do
            for j:=0 to imgnombre^.hauteur do
                begin
                // lecture du pixel source
                comp :=read_pixel(i ,j , imgnombre ).red;
                // �riture du pixel dans l'image finale
                write_pixel( (i-debut)+k*(largeur_digit+2), j, img, comp, comp, comp);    
            
                end;
        end;
    
    get_image_nombre := img;
end;

// 
// fonction qui copie une image vers une autre �une adresse donn� x/y (image d'un nombre noir sur blanc)
// @param img : pointeur vers l'image source
// @param imgnb : image du nombre �copier sur l'image source
// @param x,y : adresse o �rire le nombre sur l'image
// @param red, green, blue : couleur du nombre �afficher
// @return pointeur vers l'image obtenue
function print_nombre(img, imgnb : pTimage; x,y:integer; red,green,blue:byte) : pTimage;
var img2 : pTimage;
i, j :integer;
comp : byte;
begin
    
    img2 := new_image;
    img2^.hauteur := img^.hauteur;
    img2^.largeur := img^.largeur;
    
    
    for i:=0 to img^.largeur do
        for j:=0 to img^.hauteur do
            write_pixel(i, j, img2, read_pixel(i, j, img).red, read_pixel(i, j, img).green,  read_pixel(i, j, img).blue);
    
    for i:=0 to imgnb^.largeur do
        for j:=0 to imgnb^.hauteur-1 do
        begin
            comp := read_pixel(i, j, imgnb).red;
            if comp<>255 then
                write_pixel(i+x, j+y, img2, red, green, blue);  
        end;
        
    print_nombre := img2; 
end;

// 
// fonction applique_seuil_composante applique un seuil mais sur une image couleur pour une composante donn�
// @param img : pointeur vers l'image source
// @param composante : red green ou blue
// @param arg : valeur seuil de la composante
// @return pointeur vers l'image obtenue, les objets seuill� apparaissent blanc sur fond noir
function applique_seuil_composante(img: pTimage; composante : rgb; arg: integer) : pTimage;
var img2: pTimage;
    i,j : integer;
    comp : byte;
begin
img2 := new_image;
img2^.hauteur := img^.hauteur;
img2^.largeur := img^.largeur;

for i:=0 to img^.largeur Do
    for j:= 0 to img^.hauteur Do
    begin


        case composante of
        
        rouge:
        comp := read_pixel(i,j,img).red;
        
        vert:
        comp := read_pixel(i,j,img).green;
        
        bleu:
        comp := read_pixel(i,j,img).blue;
        end;
    
        if comp <= arg then
        write_pixel(i,j,img2, 255, 255, 255)
        else write_pixel(i,j,img2, 0, 0, 0);

    end;


applique_seuil_composante := img2;
end;

//
// prend la moyenne des largeurs des objets de la liste
// @param pdeb : poiteur de d�ut de liste des objets 
// @return : moyenne de leur largeur
function get_moyenne_largeur(pdeb : pliste_objets): integer;
var somme,i:integer;
    pl:pliste_objets;
begin
    pl := pdeb;
    somme:=0;
    i:=0;
    while not is_empty(pl)do
    begin
        
       somme := round(lire_mesure_objet(@(pl^.objet), largeur)) + somme;
       inc(i);
       pl:=pl^.psuivant;
    end;
    get_moyenne_largeur := somme DIV i;
end;

//
// trace les traits entre boules et cochonnets, affiche la distance en centim�res
// @param img : image �compl�er
// @param pdeb : poiteur de d�ut de liste des objets de type boules de p�anque
// @param cochonnet : objet cochonnet
procedure trace_trait_objets_cochonnet(var img : pTimage; pdeb : pliste_objets; cochonnet : comp_objet);
var pl : pliste_objets;
    xb,xc,yb,yc,distance : integer;    
    k:integer;
begin
    pl := pdeb;
        
    // on prend les largeurs en PIXELS et on moyenne
    k := get_moyenne_largeur(pdeb);
        
    while not is_empty(pl)do
    begin
         
        // boule
        xb := (pl^.objet.x1 - pl^.objet.x0) DIV 2 + pl^.objet.x0;
        yb := (pl^.objet.y1 - pl^.objet.y0) DIV 2 + pl^.objet.y0;
        
        // cochonnet
        xc := (cochonnet.x1 - cochonnet.x0) DIV 2 + cochonnet.x0;
        yc := (cochonnet.y1 - cochonnet.y0) DIV 2 + cochonnet.y0;
        
        // trace la ligne reliant boule et cochonnet
        trace_ligne(img, xb, yb, xc, yc, 255,0,0);
                
        // distance entre centre boule et centre cochonnet en pixels
        distance := round(sqrt( (xb-xc)*(xb-xc) + (yb-yc)*(yb-yc) ));
        
        // conversion en cm pour l'affichage
        distance := round(distance *  BOULE_DIAMETRE / k);
        
        // on affiche le nombre sur l'image
        img := print_nombre(img, get_image_nombre(distance), xb, yb , 255, 255, 0);
        
        // on parcourt la liste
        pl := pl^.psuivant;
    end;
    
end;

//
// retourne l'objet de plus grande surface de la liste
// @param pdeb2 : poiteur de d�ut de liste
// @return : objet
function get_cochonnet(pdeb2 : pliste_objets):comp_objet;
var cochonnet : comp_objet;
begin
    cochonnet := pdeb2^.objet;
        
    while not is_empty(pdeb2) do
    begin
        if( pdeb2^.objet.surface > cochonnet.surface) then 
            cochonnet := pdeb2^.objet;
        pdeb2 := pdeb2^.psuivant;
    end;
    dispose(pdeb2);
    
    get_cochonnet := cochonnet;
end;

//
// redimensionne une image (version 1)
// @param img : image �redimensionner
// @ratio : ratio du redimensionnement
// @return : image redimensionn�
function resize(img : pTimage; ratio : integer):pTimage;
var w1,h1,w2,h2:integer;
    i,j,k:integer;
    img2:pTimage;
    c:byte;
begin
    // cr�r la nouvelle image en m�oire
    img2:=new_image;
    
    // largeurs
    w1:=img^.largeur;
    w2:=w1*ratio;
    
    // hauteurs
    h1:=img^.hauteur;
    h2:=h1*ratio;
    
    // assigne �l'image cible
    img2^.hauteur:=h2;
    img2^.largeur:=w2;
    
    // init
    j:=0;
    
    // agrandissement
    if(ratio > 1) then
    begin
        // on parcourt x et y de l'image cible
        while j < h2 do
        begin
            for i:=0 to w2 do
            begin
                // valeur du pixel d'interpolation
                c:=read_pixel(i DIV ratio,j DIV ratio,img).red;
                
                // que l'on met o c'est n�essaire (on parcourt les y)...
                for k:=0 to ratio-1 do
                begin
                    write_pixel(i,j+k,img2,c,c,c);
                end;
            end;
            j:=j+ratio;
        end;
    end;    
    
    resize:=img2;
end;

//
// redimensionne une image (version 2)
// @param img : image �redimensionner
// @ratio : ratio du redimensionnement
// @return : image redimensionn�
function resize2(img : pTimage; ratio : integer):pTimage;
var w1,h1,w2,h2:integer;
    i,j,k,cint,cint2:integer;
    img2:pTimage;
    c,pix_debut,pix_fin,c2,pix_debut2,pix_fin2:byte;
begin
    // cr�r la nouvelle image en m�oire
    img2:=new_image;
    
    // largeurs
    w1:=img^.largeur;
    w2:=w1*ratio;
    
    // hauteurs
    h1:=img^.hauteur;
    h2:=h1*ratio;
    
    // assigne �l'image cible
    img2^.hauteur:=h2;
    img2^.largeur:=w2;
    
    // bidouille : on copie la derni�e colonne de pixels en dehors de l'image �droite
    // pour un fondu bidon sur les derniers pixels
    for j:=0 to h1 do
    begin
        c:=read_pixel(w1-1,j,img).red;
        write_pixel(w1,j,img,c,c,c);        
    end;
    
    // init
    j:=0;
    
    // agrandissement
    if(ratio > 1) then
    begin
        // on parcourt x et y de l'image cible
        while j < h2 do
        begin
            i:=0;
            while i < w2 do
            begin
                // pixel du d�ut de l'image source
                pix_debut := read_pixel(i DIV ratio,j DIV ratio,img).red;
                
                // pixel de fin de l'image source en X
                pix_fin := read_pixel((i DIV ratio) + 1,j DIV ratio,img).red;
                          
                // on calcule le pixel moyen entre les d�uts et fins
                // on stocke temporairement dans un integer pour ne pas d�asser les bornes du petit byte
                cint := pix_debut - ((pix_debut - pix_fin) DIV ratio) * (i MOD ratio);
                c := cabs(cint);
                
                //if( j mod ratio = 0) then writeln(i,'x',j,': deb:',pix_debut,' fin:', pix_fin,' RESULT : ', c);
                write_pixel(i,j,img2,c,c,c);
                
                inc(i);
                
                // on interpole en y ssi on est au moins �la ratio�e ligne de l'image cible
                if (j >= ratio) then
                begin 
                    // pixel du d�ut de l'image source
                    pix_debut2 := read_pixel(i DIV ratio,(j DIV ratio)-1,img).red;
                    // pixel de fin de l'image source en X
                    pix_fin2 := read_pixel((i DIV ratio) + 1,(j DIV ratio),img).red;
                
                    k:=0;
                    // il s'agit maintenant d'interpoler entre 2 pixels en Y
                    while (j+k < h2) and (k <> ratio) do
                    begin
                        cint2 := pix_debut2 - ((pix_debut2 - pix_fin2) DIV ratio) * k;    
                        c2 := cabs(cint2);
                        
                        //if( j mod ratio = 0) then writeln(i,'x',j,': deb:',pix_debut,' fin:', pix_fin,' RESULT : ', c);
                        write_pixel(i,j+k,img2,c2,c2,c2);
                        inc(k);
                    end;
                end;
            end;
            inc(j);
        end;
    end;    
    
    resize2:=img2;
end;
begin
end.