/*******************************************************************************
* Copyright 2013 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.common.color;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import au.gov.ga.earthsci.common.color.ColorMap.InterpolationMode;
import au.gov.ga.earthsci.common.color.io.IColorMapReader;
import au.gov.ga.earthsci.common.util.ExtensionRegistryUtil;
import au.gov.ga.earthsci.common.util.ExtensionRegistryUtil.Callback;
/**
* A class that gives static access to commonly used colour maps, and acts as a
* factory for reading/writing colour maps.
* <p/>
* <strong>Important:</strong> This class should be accessed via the static
* methods. Clients should not create instances of this class. The constructor
* is public to allow this class to participate in dependency injection.
*
* @author James Navin (james.navin@ga.gov.au)
*/
@Singleton
public class ColorMaps
{
private static final String READERS_EXTENSION_POINT_ID = "au.gov.ga.earthsci.common.color.colormapreaders"; //$NON-NLS-1$
private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
private static final Logger logger = LoggerFactory.getLogger(ColorMaps.class);
private static final List<ColorMap> maps = new ArrayList<ColorMap>();
private static final ReadWriteLock mapsLock = new ReentrantReadWriteLock();
private static List<IColorMapReader> readers = new ArrayList<IColorMapReader>();
private static ReadWriteLock readersLock = new ReentrantReadWriteLock();
static
{
maps.add(getRGBRainbowMap());
maps.add(getRBGRainbowMap());
}
private static ColorMap RBG_RAINBOW_MAP;
private static ColorMap RGB_RAINBOW_MAP;
/**
* Constructor made public to participate in dependency injection.
* <p/>
* All interactions with this class should go through the its static
* methods.
*/
public ColorMaps()
{
}
/**
* Return a read-only view of the list of registered {@link ColorMaps}
*
* @return The list of registered color maps
*/
public static List<ColorMap> get()
{
return Collections.unmodifiableList(maps);
}
/**
* Add the given {@link ColorMap} to the list of maps maintained by this
* class
*
* @param map
* The color map to add
*/
public static void add(ColorMap map)
{
mapsLock.writeLock().lock();
try
{
maps.add(map);
}
finally
{
mapsLock.writeLock().unlock();
}
}
/**
* Remove the given {@link ColorMap} from the list of maps maintained by
* this class
*
* @param map
* The color map to add
*/
public static void remove(ColorMap map)
{
mapsLock.writeLock().lock();
try
{
maps.remove(map);
}
finally
{
mapsLock.writeLock().unlock();
}
}
/**
* Return a standard red-blue-green rainbow colour map
*/
public static ColorMap getRBGRainbowMap()
{
if (RBG_RAINBOW_MAP == null)
{
Map<Double, Color> entries = new HashMap<Double, Color>();
entries.put(0.0, Color.RED);
entries.put(0.5, Color.BLUE);
entries.put(1.0, Color.GREEN);
RBG_RAINBOW_MAP =
new ColorMap(Messages.ColorMaps_RBGName, Messages.ColorMaps_RBGDescription,
entries, null, InterpolationMode.INTERPOLATE_HUE, true);
}
return RBG_RAINBOW_MAP;
}
/**
* Return a standard red-green-blue rainbow colour map
*/
public static ColorMap getRGBRainbowMap()
{
if (RGB_RAINBOW_MAP == null)
{
Map<Double, Color> entries = new HashMap<Double, Color>();
entries.put(0.0, Color.RED);
entries.put(0.5, Color.GREEN);
entries.put(1.0, Color.BLUE);
RGB_RAINBOW_MAP =
new ColorMap(Messages.ColorMaps_RGBName, Messages.ColorMaps_RGBDescription,
entries, null, InterpolationMode.INTERPOLATE_HUE, true);
}
return RGB_RAINBOW_MAP;
}
@Inject
public static void loadFromExtensions(IEclipseContext context)
{
logger.debug("Registering color map readers"); //$NON-NLS-1$
try
{
ExtensionRegistryUtil.createFromExtension(READERS_EXTENSION_POINT_ID,
CLASS_ATTRIBUTE, IColorMapReader.class, context,
new Callback<IColorMapReader>()
{
@Override
public void run(IColorMapReader reader,
IConfigurationElement element,
IEclipseContext context)
{
registerColorMapReader(reader);
}
});
}
catch (CoreException e)
{
logger.error("Exception occurred while loading reader from extension", e); //$NON-NLS-1$
}
}
@Inject
public static void loadGOCADColorMaps()
{
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/africa.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/bgr.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/classic.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/cyan_red.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/flag.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/gray.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/grn_yel.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/high_res.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/rainbow.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/rainbow1.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/rainbow2.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/red_blue.cmap"))); //$NON-NLS-1$
add(readFrom(ColorMaps.class.getResource("/colormaps/gocad/whi_blue.cmap"))); //$NON-NLS-1$
}
/**
* Register the provided {@link IColorMapReader} on this class
*
* @param reader
* The reader to register
*/
public static void registerColorMapReader(IColorMapReader reader)
{
if (reader == null)
{
return;
}
readersLock.writeLock().lock();
try
{
logger.debug("Registering color map reader: {}", reader.getClass()); //$NON-NLS-1$
readers.add(reader);
}
finally
{
readersLock.writeLock().unlock();
}
}
/**
* Read a ColorMap from the given source, using registered
* {@link IColorMapReader} implementations.
*
* @param source
* The source object to read from
*
* @return The loaded colour map, or <code>null</code> if a colour map could
* not be read from the provided source.
*/
public static ColorMap readFrom(Object source)
{
if (source == null)
{
return null;
}
readersLock.readLock().lock();
try
{
for (IColorMapReader reader : readers)
{
if (reader.supports(source))
{
return reader.read(source);
}
}
logger.debug("No color map reader found that supports source {}", source); //$NON-NLS-1$
return null;
}
catch (Exception e)
{
logger.debug("An exception occurred while reading color map from source " + source, e); //$NON-NLS-1$
return null;
}
finally
{
readersLock.readLock().unlock();
}
}
}