// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.elevation;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.openstreetmap.josm.tools.CheckParameterUtil;
/**
* Provides a set of color maps to map an elevation value to a color.
* @author Olli
*
*/
public final class ColorMap {
private List<ColorMapEntry> colorList;
private String name;
private static HashMap<String, ColorMap> colorMaps;
static {
colorMaps = new HashMap<>();
}
// Private ctor to enforce use of create
private ColorMap() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* Gets the color according to the given elevation value.
*
* @param elevation the elevation
* @return the color
*/
public Color getColor(int elevation) {
// empty color map?
if (colorList == null || colorList.size() == 0) {
return Color.white;
}
// out of range?
if (elevation < colorList.get(0).ele) {
return colorList.get(0).getColor();
}
int last = colorList.size() - 1;
if (elevation > colorList.get(last).ele) {
return colorList.get(last).getColor();
}
// find elevation section
for (int i = 0; i < last; i++) {
ColorMapEntry e1 = colorList.get(i);
ColorMapEntry e2 = colorList.get(i + 1);
// elevation within range?
if (e1.getEle() <= elevation && e2.getEle() >= elevation) {
// interpolate color between both
double val = (elevation - e1.getEle()) / (double) (e2.getEle() - e1.getEle());
return interpolate(e1.getColor(), e2.getColor(), val);
}
}
// here we should never end!
throw new RuntimeException("Inconsistent color map - found no entry for elevation " + elevation);
}
/**
* Gets the color map with the given name.
*
* @param name the name
* @return the map or <code>null</code>, if no such map exists
*/
public static ColorMap getMap(String name) {
if (colorMaps.containsKey(name)) {
return colorMaps.get(name);
}
return null;
}
/**
* Gets the number of available color maps.
*
* @return the int
*/
public static int size() {
return colorMaps != null ? colorMaps.size() : 0;
}
/**
* Gets the available color map names.
*
* @param name the name
* @return the map or <code>null</code>, if no such map exists
*/
public static String[] getNames() {
return colorMaps.keySet().toArray(new String[size()]);
}
private static void registerColorMap(ColorMap newMap) {
CheckParameterUtil.ensureParameterNotNull(newMap);
colorMaps.put(newMap.getName(), newMap);
}
public static void unregisterColorMap(String name) {
if (colorMaps.containsKey(name)) {
colorMaps.remove(name);
}
}
public static Color interpolate(java.awt.Color c1, java.awt.Color c2, double ratio) {
double r1 = 1 -ratio;
// clip
if (r1 < 0) r1 = 0d;
if (r1 > 1) r1 = 1d;
double r2 = 1 - r1;
int r = (int) Math.round((r1 * c1.getRed()) + (r2 * c2.getRed()));
int g = (int) Math.round((r1 * c1.getGreen()) + (r2 * c2.getGreen()));
int b = (int) Math.round((r1 * c1.getBlue()) + (r2 * c2.getBlue()));
return new Color(r, g, b);
}
/**
* Creates a color map using the given colors/elevation values.
* Both arrays must have same length.
*
* @param name the name of the color map
* @param colors the array containing the colors
* @param ele the elevation values
* @return the color map
*/
public static ColorMap create(String name, Color[] colors, int[] ele) {
CheckParameterUtil.ensureParameterNotNull(colors);
CheckParameterUtil.ensureParameterNotNull(ele);
if (colors.length != ele.length) {
throw new IllegalArgumentException("Arrays colors and ele must have same length: " + colors.length + " vs " + ele.length);
}
ColorMap map = new ColorMap();
map.colorList = new ArrayList<>();
map.name = name;
for (int i = 0; i < ele.length; i++) {
map.colorList.add(new ColorMapEntry(colors[i], ele[i]));
}
// sort by elevation
Collections.sort(map.colorList);
registerColorMap(map);
return map;
}
static class ColorMapEntry implements Comparable<ColorMapEntry> {
private final int ele; // limit
private final Color color;
ColorMapEntry(Color color, int ele) {
super();
this.color = color;
this.ele = ele;
}
public int getEle() {
return ele;
}
public Color getColor() {
return color;
}
@Override
public int compareTo(ColorMapEntry o) {
return this.ele - o.ele;
}
}
}