view gnv-artifacts/src/main/java/de/intevation/gnv/raster/Palette.java @ 605:e8ebdbc7f1e3

First step of removing the cache blob. The static part of the describe document will be created by using the input data stored at each state. Some TODOs left (see ChangeLog). gnv-artifacts/trunk@671 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 09 Feb 2010 14:27:55 +0000
parents c8089cd7d777
children 9a828e5a2390
line wrap: on
line source
package de.intevation.gnv.raster;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.util.Arrays;

import java.awt.Color;

import org.apache.log4j.Logger;

import de.intevation.gnv.raster.Raster.ValueToIndex;

/**
 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
 */
public class Palette
implements   ValueToIndex
{   
	private static Logger log = Logger.getLogger(Palette.class);

    public static final class Entry 
    implements                Comparable
    {
        private Entry  left;
        private Entry  right;

        private int    index;

        private int    externalIndex;

        private double from;
        private double to;

        private String description;

        private Color  color;

        public Entry() {
        }

        public Entry(Entry other) {
            index         = other.index;
            externalIndex = other.externalIndex;
            from          = other.from;
            to            = other.to;
            description   = other.description;
            color         = other.color;
        }

        public Entry(
            int    index, 
            int    externalIndex,
            double from, 
            double to, 
            Color  color,
            String description
        ) {
            this.index         = index;
            this.externalIndex = externalIndex;
            this.from          = from;
            this.to            = to;
            this.color         = color;
            this.description   = description;
        }

        public int compareTo(Object other) {
            Entry e = (Entry)other;
            if (from < e.from) return -1;
            if (from > e.from) return +1;
            return 0;
        }

        public double getFrom() {
            return from;
        }

        public double getTo() {
            return to;
        }

        public Color getColor() {
            return color;
        }

        public int getExternalIndex() {
            return externalIndex;
        }

        public Entry locateEntry(double value) {
            Entry current = this;
            while (current != null) {
                boolean b = value >= current.from;
                if (b && value <= current.to) {
                    return current;
                }
                current = b
                    ? current.right
                    : current.left;
            }
            return null;
        }

        public int locate(double value) {
            Entry entry = locateEntry(value);
            return entry != null
                ? entry.index
                : -1;
        }

        public Entry findByIndex(int index) {
            Entry current = this;
            while (current != null) {
                if (current.index == index) {
                    break;
                }
                current = index < current.index
                    ? current.left
                    : current.right;
            }
            return current;
        }

        public String getDescription() {
            return description;
        }

        public boolean isInfinity() {
            return from == -Double.MAX_VALUE
              ||   to   ==  Double.MAX_VALUE;
        }
    } // class Entry

    protected Entry [] entries;
    protected Entry    lookup;
    protected Color [] rgbs;

    private Entry buildLookup(Entry [] entries, int lo, int hi) {
        if (lo > hi) {
            return null;
        }
        int mid = (lo + hi)/2;
        Entry entry = entries[mid];
        entry.left  = buildLookup(entries, lo, mid-1);
        entry.right = buildLookup(entries, mid+1, hi);
        return entry;
    }

    public Palette() {
    }

    public Palette(Document document) {

        NodeList rangeNodes = document.getElementsByTagName("range");

        entries = new Entry[rangeNodes.getLength()];
        rgbs    = new Color[entries.length];

        for (int i = 0; i < entries.length; ++i) {
            Element rangeElement = (Element)rangeNodes.item(i);
            double from     = doubleValue(rangeElement.getAttribute("from"));
            double to       = doubleValue(rangeElement.getAttribute("to"));
            int    extIndex = intValue(rangeElement.getAttribute("index"), i);
            Color  color    = color(rangeElement.getAttribute("rgb"));
            String desc     = rangeElement.getAttribute("description");
            if (from > to) { double t = from; from = to; to = t; }
            entries[i] = new Entry(i, extIndex, from, to, color, desc);
            rgbs[i] = color;
        }

        buildLookup();
    }

    public Palette(Palette original, int N) {
        if (N < 2)  {
            throw new IllegalArgumentException("N < 2");
        }

        Entry [] origEntries = original.entries;

        int newSize = 0;
        for (int i = 0; i < origEntries.length; ++i) {
            // cannot split infinity intervals
            newSize += origEntries[i].isInfinity() ? 1 : N;
        }

        entries = new Entry[newSize];
        rgbs    = new Color[newSize];

        for (int i = 0, j = 0; i < origEntries.length; ++i) {
            Entry origEntry = origEntries[i];
            if (origEntry.isInfinity()) {
                // infinity intervals are just copied
                Entry nEntry = new Entry(origEntry);
                entries[j] = nEntry;
                rgbs[j]    = nEntry.color;
                nEntry.index = j++;
            }
            else {
                // split interval into N parts
                double from  = origEntry.from;
                double to    = origEntry.to;
                double delta = (to - from)/N;
				for (int k = 0; k < N; ++k) {
                    Entry nEntry = new Entry(origEntry);
                    nEntry.from = from;
                    nEntry.to   = from + delta;
                    from += delta;
                    entries[j] = nEntry;
                    rgbs[j]    = nEntry.color;
                    nEntry.index = j++;
                }
            } // limited interval
        } // for all original entries

        buildLookup();
    }

    private static final int intValue(String s, int def) {
        if (s == null || (s = s.trim()).length() == 0) {
            return def;
        }
        try {
            return Integer.parseInt(s);
        }
        catch (NumberFormatException nfe) {
            log.error(nfe.getLocalizedMessage(), nfe);
        }
        return def;
    }

    private static final double doubleValue(String s) {
        if (s == null || (s = s.trim()).length() == 0) {
            return 0d;
        }
        if ((s = s.toLowerCase()).startsWith("-inf")) {
            return -Double.MAX_VALUE; // XXX: Not using Double.NEGATIVE_INFINITY!
        }

        if (s.startsWith("inf")) {
            return Double.MAX_VALUE; // XXX: Not using Double.NEGATIVE_INFINITY!
        }

        return Double.parseDouble(s);
    }

    private static final Color color(String s) {
        if (s == null || (s = s.trim()).length() == 0) {
            return null;
        }
        return Color.decode(s);
    }


    protected void buildLookup() {
        Arrays.sort(entries);
        lookup = buildLookup(entries, 0, entries.length-1);
    }

    public Palette subdivide(int N) {
        return new Palette(this, N);
    }

    public int getSize() {
        return rgbs.length;
    }

    public Color getColor(int index) {
        return rgbs[index];
    }

    public int indexToRGB(int index) {
        return rgbs[index].getRGB();
    }

    public int toIndex(double value) {
        return lookup.locate(value);
    }

    public Entry getEntry(double value) {
        return lookup.locateEntry(value);
    }

    public Entry getEntryByIndex(int index) {
        return lookup.findByIndex(index);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org