sascha@424: package de.intevation.gnv.raster; sascha@424: sascha@424: import org.w3c.dom.Document; sascha@424: import org.w3c.dom.Element; sascha@424: import org.w3c.dom.NodeList; sascha@424: sascha@424: import java.util.Arrays; sascha@424: sascha@424: import java.awt.Color; sascha@424: sascha@447: import org.apache.log4j.Logger; sascha@447: sascha@424: import de.intevation.gnv.raster.Raster.ValueToIndex; sascha@424: sascha@424: /** sascha@424: * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) sascha@424: */ sascha@424: public class Palette sascha@424: implements ValueToIndex sascha@447: { sascha@447: private static Logger log = Logger.getLogger(Palette.class); sascha@447: sascha@424: public static final class Entry sascha@424: implements Comparable sascha@424: { sascha@424: private Entry left; sascha@424: private Entry right; sascha@424: sascha@424: private int index; sascha@424: sascha@424: private double from; sascha@424: private double to; sascha@424: sascha@424: private String description; sascha@424: sascha@424: private Color color; sascha@424: sascha@424: public Entry() { sascha@424: } sascha@424: sascha@435: public Entry(Entry other) { sascha@435: index = other.index; sascha@435: from = other.from; sascha@435: to = other.to; sascha@435: description = other.description; sascha@435: color = other.color; sascha@435: } sascha@435: sascha@424: public Entry( sascha@424: int index, sascha@424: double from, sascha@424: double to, sascha@424: Color color, sascha@424: String description sascha@424: ) { sascha@424: this.index = index; sascha@424: this.from = from; sascha@424: this.to = to; sascha@424: this.color = color; sascha@424: this.description = description; sascha@424: } sascha@424: sascha@424: public int compareTo(Object other) { sascha@424: Entry e = (Entry)other; sascha@424: if (from < e.from) return -1; sascha@424: if (from > e.from) return +1; sascha@424: return 0; sascha@424: } sascha@424: sascha@448: public double getFrom() { sascha@448: return from; sascha@448: } sascha@448: sascha@448: public double getTo() { sascha@448: return to; sascha@448: } sascha@448: sascha@449: public Color getColor() { sascha@449: return color; sascha@449: } sascha@449: sascha@424: public Entry locateEntry(double value) { sascha@424: Entry current = this; sascha@424: while (current != null) { sascha@424: boolean b = value >= current.from; sascha@424: if (b && value <= current.to) { sascha@424: return current; sascha@424: } sascha@424: current = b sascha@424: ? current.right sascha@424: : current.left; sascha@424: } sascha@424: return null; sascha@424: } sascha@424: sascha@424: public int locate(double value) { sascha@424: Entry entry = locateEntry(value); sascha@424: return entry != null sascha@424: ? entry.index sascha@424: : -1; sascha@424: } sascha@424: sascha@424: public Entry findByIndex(int index) { sascha@424: Entry current = this; sascha@424: while (current != null) { sascha@424: if (current.index == index) { sascha@424: break; sascha@424: } sascha@424: current = index < current.index sascha@424: ? current.left sascha@424: : current.right; sascha@424: } sascha@424: return current; sascha@424: } sascha@424: sascha@424: public String getDescription() { sascha@424: return description; sascha@424: } sascha@435: sascha@435: public boolean isInfinity() { sascha@435: return from == -Double.MAX_VALUE sascha@435: || to == Double.MAX_VALUE; sascha@435: } sascha@424: } // class Entry sascha@424: sascha@424: protected Entry [] entries; sascha@424: protected Entry lookup; sascha@424: protected Color [] rgbs; sascha@424: sascha@424: private Entry buildLookup(Entry [] entries, int lo, int hi) { sascha@424: if (lo > hi) { sascha@424: return null; sascha@424: } sascha@424: int mid = (lo + hi)/2; sascha@424: Entry entry = entries[mid]; sascha@424: entry.left = buildLookup(entries, lo, mid-1); sascha@424: entry.right = buildLookup(entries, mid+1, hi); sascha@424: return entry; sascha@424: } sascha@424: sascha@424: public Palette() { sascha@424: } sascha@424: sascha@424: public Palette(Document document) { sascha@424: sascha@424: NodeList rangeNodes = document.getElementsByTagName("range"); sascha@424: sascha@424: entries = new Entry[rangeNodes.getLength()]; sascha@424: rgbs = new Color[entries.length]; sascha@424: sascha@424: for (int i = 0; i < entries.length; ++i) { sascha@424: Element rangeElement = (Element)rangeNodes.item(i); sascha@424: double from = doubleValue(rangeElement.getAttribute("from")); sascha@424: double to = doubleValue(rangeElement.getAttribute("to")); sascha@424: Color color = color(rangeElement.getAttribute("rgb")); sascha@426: String desc = rangeElement.getAttribute("description"); sascha@424: if (from > to) { double t = from; from = to; to = t; } sascha@426: entries[i] = new Entry(i, from, to, color, desc); sascha@424: rgbs[i] = color; sascha@424: } sascha@424: sascha@424: buildLookup(); sascha@424: } sascha@424: sascha@435: public Palette(Palette original, int N) { sascha@435: if (N < 2) { sascha@435: throw new IllegalArgumentException("N < 2"); sascha@435: } sascha@435: sascha@435: Entry [] origEntries = original.entries; sascha@435: sascha@435: int newSize = 0; sascha@435: for (int i = 0; i < origEntries.length; ++i) { sascha@435: // cannot split infinity intervals sascha@435: newSize += origEntries[i].isInfinity() ? 1 : N; sascha@435: } sascha@435: sascha@435: entries = new Entry[newSize]; sascha@435: rgbs = new Color[newSize]; sascha@435: sascha@435: for (int i = 0, j = 0; i < origEntries.length; ++i) { sascha@435: Entry origEntry = origEntries[i]; sascha@435: if (origEntry.isInfinity()) { sascha@435: // infinity intervals are just copied sascha@435: Entry nEntry = new Entry(origEntry); sascha@435: entries[j] = nEntry; sascha@435: rgbs[j] = nEntry.color; sascha@435: nEntry.index = j++; sascha@435: } sascha@435: else { sascha@435: // split interval into N parts sascha@435: double from = origEntry.from; sascha@435: double to = origEntry.to; sascha@435: double delta = (to - from)/N; sascha@447: for (int k = 0; k < N; ++k) { sascha@435: Entry nEntry = new Entry(origEntry); sascha@435: nEntry.from = from; sascha@435: nEntry.to = from + delta; sascha@435: from += delta; sascha@435: entries[j] = nEntry; sascha@435: rgbs[j] = nEntry.color; sascha@435: nEntry.index = j++; sascha@435: } sascha@435: } // limited interval sascha@435: } // for all original entries sascha@435: sascha@435: buildLookup(); sascha@435: } sascha@435: sascha@424: private static final double doubleValue(String s) { sascha@424: if (s == null || (s = s.trim()).length() == 0) { sascha@424: return 0d; sascha@424: } sascha@424: if ((s = s.toLowerCase()).startsWith("-inf")) { sascha@424: return -Double.MAX_VALUE; // XXX: Not using Double.NEGATIVE_INFINITY! sascha@424: } sascha@424: sascha@424: if (s.startsWith("inf")) { sascha@424: return Double.MAX_VALUE; // XXX: Not using Double.NEGATIVE_INFINITY! sascha@424: } sascha@424: sascha@424: return Double.parseDouble(s); sascha@424: } sascha@424: sascha@424: private static final Color color(String s) { sascha@424: if (s == null || (s = s.trim()).length() == 0) { sascha@424: return null; sascha@424: } sascha@424: return Color.decode(s); sascha@424: } sascha@424: sascha@424: sascha@424: protected void buildLookup() { sascha@424: Arrays.sort(entries); sascha@424: lookup = buildLookup(entries, 0, entries.length-1); sascha@424: } sascha@424: sascha@435: public Palette subdivide(int N) { sascha@435: return new Palette(this, N); sascha@435: } sascha@435: sascha@424: public int getSize() { sascha@424: return rgbs.length; sascha@424: } sascha@424: sascha@424: public Color getColor(int index) { sascha@424: return rgbs[index]; sascha@424: } sascha@424: sascha@424: public int indexToRGB(int index) { sascha@424: return rgbs[index].getRGB(); sascha@424: } sascha@424: sascha@424: public int toIndex(double value) { sascha@424: return lookup.locate(value); sascha@424: } sascha@424: sascha@424: public Entry getEntry(double value) { sascha@424: return lookup.locateEntry(value); sascha@424: } sascha@424: sascha@424: public Entry getEntryByIndex(int index) { sascha@424: return lookup.findByIndex(index); sascha@424: } sascha@424: } sascha@424: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: