/*******************************************************************************
* Copyright (c) 2010-2015 Henshin developers. All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* TU Berlin, University of Luxembourg, SES S.A.
*******************************************************************************/
package de.tub.tfs.henshin.editor.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import de.tub.tfs.muvitor.ui.utils.SWTResourceManager;
/**
* The Class ColorUtil.
*/
public class ColorUtil {
/** The mapping colors. */
private static Map<Integer, Integer> mappingColors = new HashMap<Integer, Integer>();
/**
* Stores all used colors in the exist rules in transformation system. <li>
* Map-key: integer value of the color <li>Map-value: the rules which use
* the color.
*/
private static Map<Integer, Set<Rule>> usedColors = new HashMap<Integer, Set<Rule>>();
private static Map<Integer, Integer> mappingNumbers = new HashMap<Integer, Integer>();
/**
* Gets the color.
*
* @param index
* the index
* @return the color
*/
public static Color getColor(Integer index) {
if (index == -1) {
return null;
}
// The number of colors stored in mappingColors are less than the given
// index
if (index >= mappingColors.size()) {
for (int i = mappingColors.size(); i < index + 1; i++) {
Color color = getDistinctColor(mappingColors.values());
mappingColors.put(i, color2Int(color));
}
}
int colorInt = mappingColors.get(index);
return int2Color(colorInt);
}
/**
* Int2 color.
*
* @param iColor
* the i color
* @return the color
*/
public static Color int2Color(int iColor) {
if (iColor == 0) {
return SWTResourceManager.getColor(220, 220, 220);
}
return SWTResourceManager.getColor((iColor & 0x00FF0000) >> 16,
(iColor & 0x0000FF00) >> 8, iColor & 0x000000FF);
}
/**
* Color2 int.
*
* @param color
* the color
* @return the int
*/
public static int color2Int(Color color) {
int iColor = 0;
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
r = r << 16;
g = g << 8;
iColor = iColor | r | g | b;
return iColor;
}
/**
* Remove the the given mapping color and a rule from the global variable
* {@link ColorUtil#usedColors} that stores all used mapping color.
*
* @param colorInt
* The color to remove.
* @param rule
* The rule to remove from {@link ColorUtil#usedColors} with the
* given color as a map key.
*/
public static void removeMappingColor(final int colorInt, final Rule rule) {
Set<Rule> rules = usedColors.get(colorInt);
if (rules != null) {
rules.remove(rule);
if (rules.isEmpty()) {
usedColors.remove(colorInt);
int numberToRemove = -1;
for (Integer mappingNumber : mappingNumbers.keySet()) {
if (mappingNumbers.get(mappingNumber).equals(colorInt)) {
numberToRemove = mappingNumber;
break;
}
}
if (numberToRemove != -1) {
mappingNumbers.remove(numberToRemove);
}
}
}
}
/**
* Add the the given mapping color and a rule to the global variable
* {@link ColorUtil#usedColors} that stores all used mapping color.
*
* @param colorInt
* The color to add.
* @param rule
* The rule to add to {@link ColorUtil#usedColors} with the given
* color as a map key.
*/
public static void addMappingColor(final int colorInt, final Rule rule) {
if (colorInt != 0) {
actualizeUsedColors(colorInt, rule);
}
}
/**
* Returns the next mapping color for the given {@code rule}.
*
* @param rule
* For this rule the next mapping color has to be found.
* @return The next mapping color-int for the given {@code rule}.
*/
public static int getNextMappingColor(final Rule rule) {
Integer nextColorInt = null;
for (Integer colorInt : usedColors.keySet()) {
if (!usedColors.get(colorInt).contains(rule)) {
nextColorInt = colorInt;
break;
}
}
if (nextColorInt == null) {
nextColorInt = color2Int(getDistinctColor(usedColors.keySet()));
}
actualizeUsedColors(nextColorInt, rule);
return nextColorInt;
}
/**
* @param colorInt
* The color whose mapping number is returned.
* @return The mapping number for the given color.
*/
public static int getMappingNumber(final Integer colorInt) {
int mappingNumber = -1;
if (mappingNumbers.containsValue(colorInt)) {
for (Integer key : mappingNumbers.keySet()) {
if (mappingNumbers.get(key).equals(colorInt)) {
mappingNumber = key;
break;
}
}
} else if (usedColors.containsKey(colorInt)) {
final List<Integer> keyList = new ArrayList<Integer>(
usedColors.keySet());
mappingNumber = keyList.indexOf(colorInt);
if (mappingNumbers.containsKey(mappingNumber)) {
mappingNumber = usedColors.size();
}
mappingNumbers.put(mappingNumber, colorInt);
}
return mappingNumber;
}
/**
* Add the given {@code rule} to the map value with the given key
* {@code colorInt}.
*
* @param rule
* A part of map value.
* @param colorInt
* Map key.
*/
private static void actualizeUsedColors(final int colorInt, final Rule rule) {
Set<Rule> rules;
if (usedColors.containsKey(colorInt)) {
rules = usedColors.get(colorInt);
} else {
rules = new HashSet<Rule>();
}
// Add only the given rule
rules.add(rule);
usedColors.put(colorInt, rules);
}
/**
* Gets the distinct color.
*
* @param forbiddenColors
* the forbidden colors
* @return the distinct color
*/
public static Color getDistinctColor(Collection<Integer> forbiddenColors) {
int c = 1;
Color color = null;
do {
final float f = (float) Math.ceil(c / 360.0f);
color = getColorFromHSB(c % 360, 0.7f / f, 0.8f);
/*
* we may try one of these nice prime-numbers too 2, 3, 5, 7, 11,
* 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
* 79, 83, 89, 97, 101, 103, 107, 109, 113
*/
c += 61.0f; // step in hue direction
} while (forbiddenColors.contains(Integer.valueOf(color2Int(color))));
return color;
}
/**
* Gets the color from hsb.
*
* @param hue
* the hue
* @param saturation
* the saturation
* @param brightness
* the brightness
* @return the color from hsb
*/
private static Color getColorFromHSB(float hue, final float saturation,
final float brightness) {
if (hue < 0 || hue > 360 || saturation < 0 || saturation > 1
|| brightness < 0 || brightness > 1) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
float r, g, b;
if (saturation == 0) {
r = g = b = brightness;
} else {
if (hue == 360) {
hue = 0;
}
hue /= 60;
final int i = (int) hue;
final float f = hue - i;
final float p = brightness * (1 - saturation);
final float q = brightness * (1 - saturation * f);
final float t = brightness * (1 - saturation * (1 - f));
switch (i) {
case 0:
r = brightness;
g = t;
b = p;
break;
case 1:
r = q;
g = brightness;
b = p;
break;
case 2:
r = p;
g = brightness;
b = t;
break;
case 3:
r = p;
g = q;
b = brightness;
break;
case 4:
r = t;
g = p;
b = brightness;
break;
case 5:
default:
r = brightness;
g = p;
b = q;
break;
}
}
return SWTResourceManager.getColor((int) (r * 255 + 0.5),
(int) (g * 255 + 0.5), (int) (b * 255 + 0.5));
}
}