/*
XPAGES pour WebJaxe

Copyright (C) 2007 Observatoire de Paris-Meudon

Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux dispositions de la Licence Publique Générale GNU, telle que publiée par la Free Software Foundation ; version 2 de la licence, ou encore (à votre choix) toute version ultérieure.

Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence Publique Générale GNU .

Vous devez avoir reçu un exemplaire de la Licence Publique Générale GNU en même temps que ce programme ; si ce n'est pas le cas, écrivez à la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis.
*/

package xpages;

import java.util.ArrayList;

/**
 * Optimisation de l'opération de recherche d'index de couleur dans une table de couleurs
 * à partir d'une couleur RVB donnée
 */
public class CartePalette {
    ArrayList<Integer>[][][] cube; // tableau 3D de ArrayList de Integer - liens coordonnées RVB -> index ds la table
    int[] palette;
    int indtrans;
    int dim;
    
    /**
     * création de la carte à partir de la palette avec les couleurs RVB sous forme de int
     * dimension suggérée: 10 (pour un cube de 10x10x10) pour des images de taille > 32x32
     * indtrans = index de la couleur de transparence, ou -1 s'il n'y en a pas
     */
    public CartePalette(int[] palette, int indtrans, int dim) {
        this.palette = palette;
        this.indtrans = indtrans;
        this.dim = dim;
        cube = (ArrayList<Integer>[][][]) new ArrayList[dim][dim][dim];
        remplirCube();
    }
    
    protected void remplirCube() {
        double ddiag = 3*(256.0/dim)*(256.0/dim); // diagonale du cube au carré
        for (int ir=0; ir<dim; ir++)
            for (int iv=0; iv<dim; iv++)
                for (int ib=0; ib<dim; ib++) {
                    int r = (ir*255+128)/dim;
                    int v = (iv*255+128)/dim;
                    int b = (ib*255+128)/dim;
                    cube[ir][iv][ib] = rechercheIndex(r, v, b, ddiag);
                }
    }
    
    protected ArrayList<Integer> rechercheIndex(int r, int v, int b, double maxdiff) {
        int rvbi, ri, vi, bi;
        long diff;
        ArrayList<Integer> tindex = null;
        int besti = -1;
        long bestdiff = 0;
        for (int i=0; i<palette.length; i++)
            if (i != indtrans) {
                rvbi = palette[i];
                ri = ((rvbi >> 16) & 0xFF) - r;
                vi = ((rvbi >> 8) & 0xFF) - v;
                bi = (rvbi & 0xFF) - b;
                diff = ri*ri + vi*vi + bi*bi;
                if (besti == -1 || diff < bestdiff) {
                    besti = i;
                    bestdiff = diff;
                }
                if (diff < maxdiff) {
                    if (tindex == null)
                        tindex = new ArrayList<Integer>();
                    tindex.add(new Integer(i));
                }
            }
        if (tindex == null)
            tindex = new ArrayList<Integer>();
        boolean trouve = false;
        for (int i=0; i<tindex.size(); i++)
            if (tindex.get(i).intValue() == besti)
                trouve = true;
        if (!trouve)
            tindex.add(new Integer(besti));
        return(tindex);
    }
    
    public int index(int couleur) {
        int r = (couleur >> 16) & 0xFF;
        int v = (couleur >> 8) & 0xFF;
        int b = couleur & 0xFF;
        ArrayList<Integer> tindex = cube[(int)(r*(dim-0.1)/255)][(int)(v*(dim-0.1)/255)][(int)(b*(dim-0.1)/255)];
        if (tindex.size() == 1)
            return(tindex.get(0).intValue());
        int besti = -1;
        long diff, bestdiff = 0;
        int rvbi, ri, vi, bi;
        for (int i=0; i<tindex.size(); i++) {
            rvbi = palette[tindex.get(i).intValue()];
            ri = ((rvbi >> 16) & 0xFF) - r;
            vi = ((rvbi >> 8) & 0xFF) - v;
            bi = (rvbi & 0xFF) - b;
            diff = ri*ri + vi*vi + bi*bi;
            if (besti == -1 || diff < bestdiff) {
                besti = i;
                bestdiff = diff;
            }
        }
        return(tindex.get(besti).intValue());
    }
}

