/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>, Mathieu Jacomy, Julian Bilcke, Eduardo Ramos
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.desktop.datalab.utils;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* <p>Class to draw time intervals as graphics, being able to indicate the colors to use (or default colors).
* The result graphics are like:</p>
*
* <p>|{background color}|time-interval{fill color}|{background color}|</p>
*
* @author Eduardo Ramos <eduramiba@gmail.com>
*/
public class TimeIntervalGraphics {
private static final Color DEFAULT_FILL = new Color(153, 255, 255);
private static final Color DEFAULT_BORDER = new Color(2, 104, 255);
private double min;
private double max;
private BigDecimal range;
/**
* Create a new TimeIntervalGraphics with the given minimum and maximum times to render intervals later.
* @param min Minimum time of all intervals
* @param max Maximum time of all intervals
*/
public TimeIntervalGraphics(double min, double max) {
min = normalize(min);
max = normalize(max);
if (min > max) {
throw new IllegalArgumentException("min should be less or equal than max");
}
this.min = min;
this.max = max;
calculateRange();
}
private void calculateRange() {
range = new BigDecimal(max);
range = range.subtract(new BigDecimal(min));
}
/**
* Creates a time interval graphic representation with default colors.
* If start or end are infinite, they will be assigned min or max values.
* @param start Start of the interval (must be greater or equal than minimum time)
* @param end End of the interval (must be lesser or equal than maximum time)
* @param width Image width
* @param height Image height
* @return Generated image for the interval
*/
public BufferedImage createTimeIntervalImage(double start, double end, int width, int height) {
return createTimeIntervalImage(start, end, width, height, null, null, null);
}
/**
* Creates a time interval graphic representation with the indicated fill and border colors (or null to use default colors).
* If start or end are infinite, they will be assigned min or max values.
* @param start Start of the interval (must be greater or equal than minimum time)
* @param end End of the interval (must be lesser or equal than maximum time)
* @param width Image width
* @param height Image height
* @param fill Fill color for the interval
* @param border Border color for the interval
* @return Generated image for the interval
*/
public BufferedImage createTimeIntervalImage(double start, double end, int width, int height, Color fill, Color border) {
return createTimeIntervalImage(start, end, width, height, fill, border, null);
}
/**
* Creates a time interval graphic representation with the indicated fill, border and background colors (or null to use default colors).
* If start or end are infinite, they will be assigned min or max values.
* @param start Start of the interval (must be greater or equal than minimum time)
* @param end End of the interval (must be lesser or equal than maximum time)
* @param width Image width
* @param height Image height
* @param fill Fill color for the interval
* @param border Border color for the interval
* @param background Background color
* @return Generated image for the interval
*/
public BufferedImage createTimeIntervalImage(double start, double end, int width, int height, Color fill, Color border, Color background) {
start = normalizeToRange(start);
end = normalizeToRange(end);
if (start > end) {
throw new IllegalArgumentException("start should be less or equal than end");
}
// if (start < min) {
// throw new IllegalArgumentException("start should be greater or equal than the minimum time set, " + start + "<" + min);
// }
// if (end > max) {
// throw new IllegalArgumentException("end should be lesser or equal than the maximum time set, " + end + ">" + max);
// }
/*** Previous code commented and values normalized to range because DynamicIndex min and max values are sometimes wrong***/
if (fill == null) {
fill = DEFAULT_FILL;
}
if (border == null) {
border = DEFAULT_BORDER;
}
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final int startPixel, endPixel;
if (range.compareTo(new BigDecimal(0)) == 0) {//No range, Min=Max
//Fill all drawing area:
startPixel = 0;
endPixel = width;
} else {
startPixel = (int) (width * new BigDecimal(start).subtract(new BigDecimal(min)).divide(range, 5, RoundingMode.HALF_EVEN).doubleValue());
endPixel = (int) (width * new BigDecimal(end).subtract(new BigDecimal(min)).divide(range, 5, RoundingMode.HALF_EVEN).doubleValue());
}
//Draw brackground if any:
if (background != null) {
g.setColor(background);
g.fillRect(0, 0, startPixel, height);
g.fillRect(endPixel + 1, 0, width - endPixel - 1, height);
}
//Draw time interval fill:
g.setColor(fill);
g.fillRect(startPixel + 1, 0, endPixel - startPixel - 2, height);
//Draw borders:
g.setColor(border);
g.drawLine(startPixel, 0, startPixel, height);
g.drawLine(endPixel - 1, 0, endPixel - 1, height);
return image;
}
public double getMax() {
return max;
}
public void setMax(double max) {
max = normalize(max);
if (max < min) {
throw new IllegalArgumentException("min should be less or equal than max");
}
this.max = max;
calculateRange();
}
public double getMin() {
return min;
}
public void setMin(double min) {
min = normalize(min);
if (max < min) {
throw new IllegalArgumentException("min should be less or equal than max");
}
this.min = min;
calculateRange();
}
private double normalize(double d) {
if (d == Double.NEGATIVE_INFINITY) {
return -Double.MAX_VALUE;
}
if (d == Double.POSITIVE_INFINITY) {
return Double.MAX_VALUE;
}
return d;
}
private double normalizeToRange(double d) {
if (d == Double.NEGATIVE_INFINITY || d < min) {
return min;
}
if (d == Double.POSITIVE_INFINITY || d > max) {
return max;
}
return d;
}
}