eu.hansolo.steelseries.tools.TickmarkImageFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SteelSeries Show documentation
Show all versions of SteelSeries Show documentation
The SteelSeries is a javabeans component library that contains gauges.
You will find linear and radial gauges. In addition you will also find
digital displays, indicators from cars and some instruments from airplanes and
sailboats.
package eu.hansolo.steelseries.tools;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.Transparency;
import java.util.ArrayList;
import java.util.List;
/**
* @author Gerrit Grunwald
*/
public enum TickmarkImageFactory {
//
INSTANCE;
private final Util UTIL = Util.INSTANCE;
private static final BasicStroke MAJOR_TICKMARK_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
private static final BasicStroke MEDIUM_TICKMARK_STROKE = new BasicStroke(0.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
private static final BasicStroke MINOR_TICKMARK_STROKE = new BasicStroke(0.3f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
private static final int BASE = 10;
private NumberFormat numberFormat = NumberFormat.STANDARD;
// Buffer variables of radial gauges
private BufferedImage imageBufferRad = UTIL.createImage(1, 1, Transparency.TRANSLUCENT);
private int widthBufferRad = 200;
private double minValueBufferRad = 0;
private double maxValueBufferRad = 100;
private int noOfMinorTicksBufferRad = 0;
private int noOfMajorTicksBufferRad = 0;
private double minorTickSpacingBufferRad = 10;
private double majorTickSpacingBufferRad = 10;
private GaugeType gaugeTypeBufferRad = GaugeType.TYPE4;
private TickmarkType minorTickmarkTypeBufferRad = TickmarkType.LINE;
private TickmarkType majorTickmarkTypeBufferRad = TickmarkType.LINE;
private boolean ticksVisibleBufferRad = true;
private boolean ticklabelsVisibleBufferRad = true;
private boolean tickmarkSectionsVisibleBufferRad = false;
private boolean minorTicksVisibleBufferRad = true;
private boolean majorTicksVisibleBufferRad = true;
private NumberFormat numberFormatBufferRad = NumberFormat.AUTO;
private BackgroundColor backgroundColorBufferRad = BackgroundColor.DARK_GRAY;
private Color tickmarkColorBufferRad = backgroundColorBufferRad.LABEL_COLOR;
private boolean tickmarkColorFromThemeBufferRad = true;
private List tickmarkSectionsBufferRad = new ArrayList(10);
private float radiusFactorBufferRad = 0.38f;
private float textDistanceFactorBufferRad = 0.09f;
private Point2D centerBufferRad = new Point2D.Double();
private Point2D offsetBufferRad = new Point2D.Double();
private Orientation orientationBufferRad = Orientation.NORTH;
private TicklabelOrientation ticklabelOrientationBufferRad = TicklabelOrientation.TANGENT;
private boolean niceScaleRad = true;
private boolean logScaleRad = false;
// Buffer variables of linear gauges
private BufferedImage imageBufferLin = UTIL.createImage(1, 1, Transparency.TRANSLUCENT);
private int widthBufferLin = 140;
private int heightBufferLin = 0;
private double minValueBufferLin = 0;
private double maxValueBufferLin = 100;
private int noOfMinorTicksBufferLin = 0;
private int noOfMajorTicksBufferLin = 0;
private double minorTickSpacingBufferLin = 10;
private double majorTickSpacingBufferLin = 10;
private TickmarkType minorTickmarkTypeBufferLin = TickmarkType.LINE;
private TickmarkType majorTickmarkTypeBufferLin = TickmarkType.LINE;
private boolean ticksVisibleBufferLin = true;
private boolean ticklabelsVisibleBufferLin = true;
private boolean minorTicksVisibleBufferLin = true;
private boolean majorTicksVisibleBufferLin = true;
private NumberFormat numberFormatBufferLin = NumberFormat.AUTO;
private boolean tickmarkSectionsVisibleBufferLin = false;
private BackgroundColor backgroundColorBufferLin = BackgroundColor.DARK_GRAY;
private Color tickmarkColorBufferLin = backgroundColorBufferLin.LABEL_COLOR;
private boolean tickmarkColorFromThemeBufferLin = true;
private List tickmarkSectionsBufferLin = new ArrayList(10);
private Point2D offsetBufferLin = new Point2D.Double();
private Orientation orientationBufferLin = Orientation.VERTICAL;
private boolean niceScaleLin = true;
private boolean logScaleLin = false;
//
//
public BufferedImage create_RADIAL_TICKMARKS_Image(final int WIDTH,
final double MIN_VALUE,
final double MAX_VALUE,
final int NO_OF_MINOR_TICKS,
final int NO_OF_MAJOR_TICKS,
final double MINOR_TICK_SPACING,
final double MAJOR_TICK_SPACING,
final GaugeType GAUGE_TYPE,
final TickmarkType MINOR_TICKMARK_TYPE,
final TickmarkType MAJOR_TICKMARK_TYPE,
final boolean TICKS_VISIBLE,
final boolean TICKLABELS_VISIBLE,
final boolean MINOR_TICKS_VISIBLE,
final boolean MAJOR_TICKS_VISIBLE,
final NumberFormat NUMBER_FORMAT,
final boolean TICKMARK_SECTIONS_VISIBLE,
final BackgroundColor BACKGROUND_COLOR,
final Color TICKMARK_COLOR,
final boolean TICKMARK_COLOR_FROM_THEME,
List tickmarkSections,
final float RADIUS_FACTOR,
final float TEXT_DISTANCE_FACTOR,
final Point2D CENTER,
final Point2D OFFSET,
final Orientation ORIENTATION,
final TicklabelOrientation TICKLABEL_ORIENTATION,
final boolean NICE_SCALE,
final boolean LOG_SCALE,
final BufferedImage BACKGROUND_IMAGE) {
if (WIDTH <= 0) {
return UTIL.createImage(1, 1, Transparency.TRANSLUCENT);
}
// Buffer check
if (WIDTH == widthBufferRad
&& Double.compare(MIN_VALUE, minValueBufferRad) == 0
&& Double.compare(MAX_VALUE, maxValueBufferRad) == 0
&& NO_OF_MINOR_TICKS == noOfMinorTicksBufferRad
&& NO_OF_MAJOR_TICKS == noOfMajorTicksBufferRad
&& Double.compare(MINOR_TICK_SPACING, minorTickSpacingBufferRad) == 0
&& Double.compare(MAJOR_TICK_SPACING, majorTickSpacingBufferRad) == 0
&& GAUGE_TYPE == gaugeTypeBufferRad
&& MINOR_TICKMARK_TYPE == minorTickmarkTypeBufferRad
&& MAJOR_TICKMARK_TYPE == majorTickmarkTypeBufferRad
&& TICKS_VISIBLE == ticksVisibleBufferRad
&& TICKLABELS_VISIBLE == ticklabelsVisibleBufferRad
&& MINOR_TICKS_VISIBLE == minorTicksVisibleBufferRad
&& MAJOR_TICKS_VISIBLE == majorTicksVisibleBufferRad
&& TICKMARK_SECTIONS_VISIBLE == tickmarkSectionsVisibleBufferRad
&& NUMBER_FORMAT == numberFormatBufferRad
&& BACKGROUND_COLOR == backgroundColorBufferRad
&& TICKMARK_COLOR.equals(tickmarkColorBufferRad)
&& TICKMARK_COLOR_FROM_THEME == tickmarkColorFromThemeBufferRad
&& tickmarkSections.containsAll(tickmarkSectionsBufferRad)
&& Float.compare(RADIUS_FACTOR, radiusFactorBufferRad) == 0
&& Float.compare(TEXT_DISTANCE_FACTOR, textDistanceFactorBufferRad) == 0
&& CENTER.equals(centerBufferRad)
&& OFFSET.equals(offsetBufferRad)
&& orientationBufferRad == ORIENTATION
&& ticklabelOrientationBufferRad == TICKLABEL_ORIENTATION
&& niceScaleRad == NICE_SCALE
&& logScaleRad == LOG_SCALE) {
if (BACKGROUND_IMAGE != null) {
final Graphics2D G = BACKGROUND_IMAGE.createGraphics();
G.drawImage(imageBufferRad, 0, 0, null);
G.dispose();
return imageBufferRad;
}
}
// Create image if it equals null
if (imageBufferRad != null) {
imageBufferRad.flush();
}
imageBufferRad = UTIL.createImage(WIDTH, WIDTH, Transparency.TRANSLUCENT);
// Adjust the number format of the ticklabels
if (NUMBER_FORMAT == NumberFormat.AUTO) {
if (Math.abs(MAJOR_TICK_SPACING) > 1000) {
numberFormat = NumberFormat.SCIENTIFIC;
} else if (MAJOR_TICK_SPACING % 1.0 != 0) {
numberFormat = NumberFormat.FRACTIONAL;
} else {
numberFormat = NumberFormat.STANDARD;
}
} else {
numberFormat = NUMBER_FORMAT;
}
// Definitions
final Font STD_FONT = new Font("Verdana", 0, (int) (0.04 * WIDTH));
final int TEXT_DISTANCE = (int) (TEXT_DISTANCE_FACTOR * WIDTH);
double ticklabelRotationOffset = 0;
final int MINOR_TICK_LENGTH = (int) (0.0133333333 * WIDTH);
final int MEDIUM_TICK_LENGTH = (int) (0.02 * WIDTH);
final int MAJOR_TICK_LENGTH = (int) (0.03 * WIDTH);
final int MINOR_DIAMETER = (int) (0.0093457944 * WIDTH);
//final int MEDIUM_DIAMETER = (int) (0.0186915888 * WIDTH);
final int MAJOR_DIAMETER = (int) (0.03 * WIDTH);
final Point2D TEXT_POINT = new Point2D.Double(0, 0);
final Point2D INNER_POINT = new Point2D.Double(0, 0);
final Point2D OUTER_POINT = new Point2D.Double(0, 0);
final Point2D OUTER_POINT_LEFT = new Point2D.Double(0, 0);
final Point2D OUTER_POINT_RIGHT = new Point2D.Double(0, 0);
final Line2D TICK_LINE = new Line2D.Double(0, 0, 1, 1);
final Ellipse2D TICK_CIRCLE = new Ellipse2D.Double(0, 0, 1, 1);
final GeneralPath TICK_TRIANGLE = new GeneralPath();
final double ROTATION_OFFSET = GAUGE_TYPE.ROTATION_OFFSET; // Depends on GaugeType
final float RADIUS = WIDTH * RADIUS_FACTOR;
final double ANGLE_STEP = (GAUGE_TYPE.ANGLE_RANGE / ((MAX_VALUE - MIN_VALUE) / MINOR_TICK_SPACING));
double sinValue = 0;
double cosValue = 0;
double valueCounter = MIN_VALUE;
int majorTickCounter = NO_OF_MINOR_TICKS - 1; // Indicator when to draw the major tickmark
// Create the image
final Graphics2D G2 = imageBufferRad.createGraphics();
G2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
G2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
G2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
G2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Set some default parameters for the graphics object
if (OFFSET != null) {
G2.translate(OFFSET.getX(), OFFSET.getY());
}
G2.setFont(STD_FONT);
G2.rotate(ROTATION_OFFSET - Math.PI, CENTER.getX(), CENTER.getY());
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
if (!LOG_SCALE) {
for (double alpha = 0, counter = MIN_VALUE; Double.compare(counter, MAX_VALUE) <= 0; alpha -= ANGLE_STEP, counter += MINOR_TICK_SPACING) {
// Set the color
if (tickmarkSections != null && !tickmarkSections.isEmpty()) {
if (TICKMARK_SECTIONS_VISIBLE) {
for (Section section : tickmarkSections) {
if (Double.compare(valueCounter, section.getStart()) >= 0 && Double.compare(valueCounter, section.getStop()) <= 0) {
G2.setColor(Util.INSTANCE.setAlpha(section.getColor(), 1.0f));
break;
} else if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
}
} else {
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
}
}
sinValue = Math.sin(alpha);
cosValue = Math.cos(alpha);
majorTickCounter++;
// Draw tickmark every major tickmark spacing
if (majorTickCounter == NO_OF_MINOR_TICKS) {
G2.setStroke(MAJOR_TICKMARK_STROKE);
INNER_POINT.setLocation(CENTER.getX() + (RADIUS - MAJOR_TICK_LENGTH) * sinValue, CENTER.getY() + (RADIUS - MAJOR_TICK_LENGTH) * cosValue);
OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
TEXT_POINT.setLocation(CENTER.getX() + (RADIUS - TEXT_DISTANCE) * sinValue, CENTER.getY() + (RADIUS - TEXT_DISTANCE) * cosValue);
// Draw the major tickmarks
if (TICKS_VISIBLE && MAJOR_TICKS_VISIBLE) {
drawRadialTicks(G2, INNER_POINT, OUTER_POINT, CENTER, RADIUS, MAJOR_TICKMARK_TYPE, TICK_LINE, TICK_CIRCLE, TICK_TRIANGLE, MAJOR_TICK_LENGTH, MAJOR_DIAMETER, OUTER_POINT_LEFT, OUTER_POINT_RIGHT, alpha);
}
// Draw the standard tickmark labels
if (TICKLABELS_VISIBLE) {
switch(TICKLABEL_ORIENTATION)
{
case NORMAL:
if (Double.compare(alpha, -GAUGE_TYPE.TICKLABEL_ORIENTATION_CHANGE_ANGLE) > 0) {
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (-Math.PI / 2 - alpha)));
} else {
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (Math.PI / 2 - alpha)));
}
break;
case HORIZONTAL:
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.PI - GAUGE_TYPE.ROTATION_OFFSET));
break;
case TANGENT:
default:
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (Math.PI - alpha + ticklabelRotationOffset)));
break;
}
}
valueCounter += MAJOR_TICK_SPACING;
majorTickCounter = 0;
continue;
}
// Draw tickmark every minor tickmark spacing
{
INNER_POINT.setLocation(CENTER.getX() + (RADIUS - MINOR_TICK_LENGTH) * sinValue, CENTER.getY() + (RADIUS - MINOR_TICK_LENGTH) * cosValue);
OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
G2.setStroke(MINOR_TICKMARK_STROKE);
if (NO_OF_MINOR_TICKS % 2 == 0 && majorTickCounter == (NO_OF_MINOR_TICKS / 2)) {
G2.setStroke(MEDIUM_TICKMARK_STROKE);
INNER_POINT.setLocation(CENTER.getX() + (RADIUS - MEDIUM_TICK_LENGTH) * sinValue,
CENTER.getY() + (RADIUS - MEDIUM_TICK_LENGTH) * cosValue);
OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
}
// Draw the minor tickmarks
if (TICKS_VISIBLE && MINOR_TICKS_VISIBLE) {
drawRadialTicks(G2, INNER_POINT, OUTER_POINT, CENTER, RADIUS, MINOR_TICKMARK_TYPE, TICK_LINE, TICK_CIRCLE, TICK_TRIANGLE, MINOR_TICK_LENGTH, MINOR_DIAMETER, OUTER_POINT_LEFT, OUTER_POINT_RIGHT, alpha);
}
}
}
} else {
// ****************************** LOGARITHMIC SCALING ******************************************************
final double LOG_ANGLE_STEP = Math.abs(GAUGE_TYPE.ANGLE_RANGE / UTIL.logOfBase(BASE, (MAX_VALUE - MIN_VALUE)));
int exponent = 0;
double angle = 0;
double valueStep = 1.0;
for (double value = 1 ; Double.compare(value, MAX_VALUE) <= 0; value += valueStep) {
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
angle = UTIL.logOfBase(BASE, Math.abs(value)) * LOG_ANGLE_STEP;
sinValue = Math.sin(-angle);
cosValue = Math.cos(-angle);
INNER_POINT.setLocation(CENTER.getX() + (RADIUS - MINOR_TICK_LENGTH) * sinValue, CENTER.getY() + (RADIUS - MINOR_TICK_LENGTH) * cosValue);
OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
G2.setStroke(MINOR_TICKMARK_STROKE);
if (Double.compare(value, Math.pow(BASE, exponent + 1)) == 0) {
exponent++;
valueStep = Math.pow(BASE, exponent);
INNER_POINT.setLocation(CENTER.getX() + (RADIUS - MAJOR_TICK_LENGTH) * sinValue, CENTER.getY() + (RADIUS - MAJOR_TICK_LENGTH) * cosValue);
OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
TEXT_POINT.setLocation(CENTER.getX() + (RADIUS - TEXT_DISTANCE) * sinValue, CENTER.getY() + (RADIUS - TEXT_DISTANCE) * cosValue);
if (TICKLABELS_VISIBLE) {
switch(TICKLABEL_ORIENTATION)
{
case NORMAL:
if (Double.compare(value, -GAUGE_TYPE.TICKLABEL_ORIENTATION_CHANGE_ANGLE) > 0) {
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(value), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (-Math.PI / 2 + angle)));
} else {
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(value), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (Math.PI / 2 + angle)));
}
break;
case HORIZONTAL:
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(value), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.PI - GAUGE_TYPE.ROTATION_OFFSET));
break;
case TANGENT:
default:
G2.fill(UTIL.rotateTextAroundCenter(G2, numberFormat.format(value), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), (Math.PI + angle + ticklabelRotationOffset)));
break;
}
}
G2.setStroke(MAJOR_TICKMARK_STROKE);
}
if (TICKS_VISIBLE && MAJOR_TICKS_VISIBLE && MINOR_TICKS_VISIBLE) {
TICK_LINE.setLine(INNER_POINT, OUTER_POINT);
G2.draw(TICK_LINE);
}
}
}
G2.dispose();
if (BACKGROUND_IMAGE != null) {
final Graphics2D G = BACKGROUND_IMAGE.createGraphics();
G.drawImage(imageBufferRad, 0, 0, null);
G.dispose();
}
// Buffer the current parameters
widthBufferRad = WIDTH;
minValueBufferRad = MIN_VALUE;
maxValueBufferRad = MAX_VALUE;
noOfMinorTicksBufferRad = NO_OF_MINOR_TICKS;
noOfMajorTicksBufferRad = NO_OF_MAJOR_TICKS;
minorTickSpacingBufferRad = MINOR_TICK_SPACING;
majorTickSpacingBufferRad = MAJOR_TICK_SPACING;
gaugeTypeBufferRad = GAUGE_TYPE;
minorTickmarkTypeBufferRad = MINOR_TICKMARK_TYPE;
majorTickmarkTypeBufferRad = MAJOR_TICKMARK_TYPE;
ticksVisibleBufferRad = TICKS_VISIBLE;
ticklabelsVisibleBufferRad = TICKLABELS_VISIBLE;
minorTicksVisibleBufferRad = MINOR_TICKS_VISIBLE;
majorTicksVisibleBufferRad = MAJOR_TICKS_VISIBLE;
tickmarkSectionsVisibleBufferRad = TICKMARK_SECTIONS_VISIBLE;
numberFormatBufferRad = NUMBER_FORMAT;
backgroundColorBufferRad = BACKGROUND_COLOR;
tickmarkColorBufferRad = TICKMARK_COLOR;
tickmarkColorFromThemeBufferRad = TICKMARK_COLOR_FROM_THEME;
if (tickmarkSections != null) {
tickmarkSectionsBufferRad.clear();
tickmarkSectionsBufferRad.addAll(tickmarkSections);
}
radiusFactorBufferRad = RADIUS_FACTOR;
textDistanceFactorBufferRad = TEXT_DISTANCE_FACTOR;
centerBufferRad.setLocation(CENTER);
if (OFFSET != null) {
offsetBufferRad.setLocation(OFFSET);
}
orientationBufferRad = ORIENTATION;
ticklabelOrientationBufferRad = TICKLABEL_ORIENTATION;
niceScaleRad = NICE_SCALE;
logScaleRad = LOG_SCALE;
return imageBufferRad;
}
private void drawRadialTicks(final Graphics2D G2,
final Point2D INNER_POINT,
final Point2D OUTER_POINT,
final Point2D CENTER,
final double RADIUS,
final TickmarkType TICKMARK_TYPE,
final Line2D TICK_LINE,
final Ellipse2D TICK_CIRCLE,
final GeneralPath TICK_TRIANGLE,
final double TICK_LENGTH,
final double DIAMETER,
final Point2D OUTER_POINT_LEFT,
final Point2D OUTER_POINT_RIGHT,
final double ALPHA) {
// Draw tickmark every major tickmark spacing
switch (TICKMARK_TYPE) {
case CIRCLE:
TICK_CIRCLE.setFrame(OUTER_POINT.getX() - DIAMETER / 2.0, OUTER_POINT.getY() - DIAMETER / 2.0, DIAMETER, DIAMETER);
G2.fill(TICK_CIRCLE);
break;
case TRIANGLE:
OUTER_POINT_LEFT.setLocation(CENTER.getX() + RADIUS * Math.sin(ALPHA - Math.toRadians(Math.asin(TICK_LENGTH / 16.0))), CENTER.getY() + RADIUS * Math.cos(ALPHA - Math.toRadians(Math.asin(TICK_LENGTH / 16.0))));
OUTER_POINT_RIGHT.setLocation(CENTER.getX() + RADIUS * Math.sin(ALPHA + Math.toRadians(Math.asin(TICK_LENGTH / 16.0))), CENTER.getY() + RADIUS * Math.cos(ALPHA + Math.toRadians(Math.asin(TICK_LENGTH / 16.0))));
TICK_TRIANGLE.reset();
TICK_TRIANGLE.moveTo(INNER_POINT.getX(), INNER_POINT.getY());
TICK_TRIANGLE.lineTo(OUTER_POINT_LEFT.getX(), OUTER_POINT_LEFT.getY());
TICK_TRIANGLE.lineTo(OUTER_POINT_RIGHT.getX(), OUTER_POINT_RIGHT.getY());
TICK_TRIANGLE.closePath();
G2.fill(TICK_TRIANGLE);
break;
case LINE:
default:
TICK_LINE.setLine(INNER_POINT, OUTER_POINT);
G2.draw(TICK_LINE);
break;
}
}
//
//
public BufferedImage create_LINEAR_TICKMARKS_Image(final int WIDTH,
final int HEIGHT,
final double MIN_VALUE,
final double MAX_VALUE,
final int NO_OF_MINOR_TICKS,
final int NO_OF_MAJOR_TICKS,
final double MINOR_TICK_SPACING,
final double MAJOR_TICK_SPACING,
final TickmarkType MINOR_TICKMARK_TYPE,
final TickmarkType MAJOR_TICKMARK_TYPE,
final boolean TICKS_VISIBLE,
final boolean TICKLABELS_VISIBLE,
final boolean MINOR_TICKS_VISIBLE,
final boolean MAJOR_TICKS_VISIBLE,
final NumberFormat NUMBER_FORMAT,
final boolean TICKMARK_SECTIONS_VISIBLE,
final BackgroundColor BACKGROUND_COLOR,
final Color TICKMARK_COLOR,
final boolean TICKMARK_COLOR_FROM_THEME,
List tickmarkSections,
final Point2D OFFSET,
final Orientation ORIENTATION,
final boolean NICE_SCALE,
final boolean LOG_SCALE,
final BufferedImage BACKGROUND_IMAGE) {
if (WIDTH <= 0 || HEIGHT <= 0) {
return UTIL.createImage(1, 1, Transparency.TRANSLUCENT);
}
// Buffer check
if (WIDTH == widthBufferLin
&& HEIGHT == heightBufferLin
&& Double.compare(MIN_VALUE, minValueBufferLin) == 0
&& Double.compare(MAX_VALUE, maxValueBufferLin) == 0
&& NO_OF_MINOR_TICKS == noOfMinorTicksBufferLin
&& NO_OF_MAJOR_TICKS == noOfMajorTicksBufferLin
&& Double.compare(MINOR_TICK_SPACING, minorTickSpacingBufferLin) == 0
&& Double.compare(MAJOR_TICK_SPACING, majorTickSpacingBufferLin) == 0
&& MINOR_TICKMARK_TYPE == minorTickmarkTypeBufferLin
&& MAJOR_TICKMARK_TYPE == majorTickmarkTypeBufferLin
&& TICKS_VISIBLE == ticksVisibleBufferLin
&& MINOR_TICKS_VISIBLE == minorTicksVisibleBufferLin
&& MAJOR_TICKS_VISIBLE == majorTicksVisibleBufferLin
&& TICKLABELS_VISIBLE == ticklabelsVisibleBufferLin
&& NUMBER_FORMAT == numberFormatBufferLin
&& TICKMARK_SECTIONS_VISIBLE == tickmarkSectionsVisibleBufferLin
&& BACKGROUND_COLOR == backgroundColorBufferLin
&& TICKMARK_COLOR.equals(tickmarkColorBufferLin)
&& TICKMARK_COLOR_FROM_THEME == tickmarkColorFromThemeBufferLin
&& tickmarkSections.containsAll(tickmarkSectionsBufferLin)
&& OFFSET.equals(offsetBufferLin)
&& ORIENTATION == orientationBufferLin
&& NICE_SCALE == niceScaleLin
&& LOG_SCALE == logScaleLin) {
if (BACKGROUND_IMAGE != null) {
final Graphics2D G = BACKGROUND_IMAGE.createGraphics();
G.drawImage(imageBufferLin, 0, 0, null);
G.dispose();
return imageBufferLin;
}
}
// Create image if it equals null
if (imageBufferLin != null) {
imageBufferLin.flush();
}
imageBufferLin = UTIL.createImage(WIDTH, HEIGHT, Transparency.TRANSLUCENT);
// Adjust the number format of the ticklabels
if (NUMBER_FORMAT == NumberFormat.AUTO) {
if (Math.abs(MAJOR_TICK_SPACING) > 1000) {
numberFormat = NumberFormat.SCIENTIFIC;
} else if (MAJOR_TICK_SPACING % 1.0 != 0) {
numberFormat = NumberFormat.FRACTIONAL;
}
} else {
numberFormat = NUMBER_FORMAT;
}
// Definitions
final Font STD_FONT;
final Rectangle2D SCALE_BOUNDS;
final int MINOR_DIAMETER;
final int MAJOR_DIAMETER;
final int MINOR_TICK_START;
final int MINOR_TICK_STOP;
final int MEDIUM_TICK_START;
final int MEDIUM_TICK_STOP;
final int MAJOR_TICK_START;
final int MAJOR_TICK_STOP;
double tickSpaceScaling = 1.0;
if (ORIENTATION == Orientation.VERTICAL) {
// Vertical orientation
STD_FONT = new Font("Verdana", 0, (int) (0.062 * WIDTH));
SCALE_BOUNDS = new Rectangle2D.Double(0, HEIGHT * 0.12864077669902912, 0, (HEIGHT * 0.8567961165048543 - HEIGHT * 0.12864077669902912));
MINOR_DIAMETER = (int) (0.0186915888 * WIDTH);
MAJOR_DIAMETER = (int) (0.0280373832 * WIDTH);
MINOR_TICK_START = (int) (0.34 * WIDTH);
MINOR_TICK_STOP = (int) (0.36 * WIDTH);
MEDIUM_TICK_START = (int) (0.33 * WIDTH);
MEDIUM_TICK_STOP = (int) (0.36 * WIDTH);
MAJOR_TICK_START = (int) (0.32 * WIDTH);
MAJOR_TICK_STOP = (int) (0.36 * WIDTH);
tickSpaceScaling = SCALE_BOUNDS.getHeight() / (MAX_VALUE - MIN_VALUE);
} else {
// Horizontal orientation
STD_FONT = new Font("Verdana", 0, (int) (0.062 * HEIGHT));
SCALE_BOUNDS = new Rectangle2D.Double(WIDTH * 0.14285714285714285, 0, (WIDTH * 0.8710124827 - WIDTH * 0.14285714285714285), 0);
MINOR_DIAMETER = (int) (0.0186915888 * HEIGHT);
MAJOR_DIAMETER = (int) (0.0280373832 * HEIGHT);
MINOR_TICK_START = (int) (0.65 * HEIGHT);
MINOR_TICK_STOP = (int) (0.63 * HEIGHT);
MEDIUM_TICK_START = (int) (0.66 * HEIGHT);
MEDIUM_TICK_STOP = (int) (0.63 * HEIGHT);
MAJOR_TICK_START = (int) (0.67 * HEIGHT);
MAJOR_TICK_STOP = (int) (0.63 * HEIGHT);
tickSpaceScaling = SCALE_BOUNDS.getWidth() / (MAX_VALUE - MIN_VALUE);
}
final Graphics2D G2 = imageBufferLin.createGraphics();
G2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
G2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
G2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
G2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Set some default parameters for the graphics object
if (OFFSET != null) {
G2.translate(OFFSET.getX(), OFFSET.getY());
}
G2.setFont(STD_FONT);
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
final FontRenderContext RENDER_CONTEXT = new FontRenderContext(null, true, true);
final TextLayout TEXT_LAYOUT = new TextLayout(numberFormat.format(MAX_VALUE), G2.getFont(), RENDER_CONTEXT);
final Rectangle2D MAX_BOUNDS = TEXT_LAYOUT.getBounds(); // needed to align the numbers on the right (in vertical layout)
final Line2D TICK_LINE = new Line2D.Double(0, 0, 1, 1);
final Ellipse2D TICK_CIRCLE = new Ellipse2D.Double(0, 0, 1, 1);
final GeneralPath TICK_TRIANGLE = new GeneralPath();
TextLayout currentLayout;
Rectangle2D currentBounds;
float textOffset = 0;
double currentPos = 0;
double valueCounter = MIN_VALUE;
int majorTickCounter = NO_OF_MINOR_TICKS - 1; // Indicator when to draw the major tickmark
if (!LOG_SCALE) {
// Non logarithmic scaling
for (double labelCounter = MIN_VALUE, tickCounter = 0; Float.compare((float) labelCounter, (float) MAX_VALUE) <= 0; labelCounter += MINOR_TICK_SPACING, tickCounter += MINOR_TICK_SPACING) {
// Adjust the color for the tickmark and labels
if (tickmarkSections != null && !tickmarkSections.isEmpty()) {
if (TICKMARK_SECTIONS_VISIBLE) {
for (Section section : tickmarkSections) {
if ((Double.compare(tickCounter, section.getStart()) >= 0) && (Double.compare(tickCounter, section.getStop()) <= 0)) {
G2.setColor(section.getColor());
break;
} else if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
}
} else {
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
}
} else {
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
}
// Calculate the bounds of the scaling
if (ORIENTATION == Orientation.VERTICAL) {
currentPos = SCALE_BOUNDS.getMaxY() - tickCounter * tickSpaceScaling;
} else {
currentPos = SCALE_BOUNDS.getX() + tickCounter * tickSpaceScaling;
}
majorTickCounter++;
// Draw tickmark every major tickmark spacing
if (majorTickCounter == NO_OF_MINOR_TICKS) {
G2.setStroke(MAJOR_TICKMARK_STROKE);
// Draw the major tickmarks
if (TICKS_VISIBLE && MAJOR_TICKS_VISIBLE) {
drawLinearTicks(G2, WIDTH, HEIGHT, ORIENTATION, currentPos, MAJOR_TICKMARK_TYPE, TICK_LINE, TICK_CIRCLE, TICK_TRIANGLE, MAJOR_TICK_START, MAJOR_TICK_STOP, MAJOR_DIAMETER);
}
// Draw the standard tickmark labels
if (TICKLABELS_VISIBLE) {
currentLayout = new TextLayout(numberFormat.format(valueCounter), G2.getFont(), RENDER_CONTEXT);
currentBounds = currentLayout.getBounds();
if (ORIENTATION == Orientation.VERTICAL) {
// Vertical orientation
textOffset = (float) (MAX_BOUNDS.getWidth() - currentBounds.getWidth());
G2.drawString(numberFormat.format(valueCounter), 0.18f * WIDTH + textOffset, (float) (currentPos - currentBounds.getHeight() / 2.0 + currentBounds.getHeight()));
} else {
// Horizontal orientation
G2.drawString(numberFormat.format(valueCounter), (float) (tickCounter * tickSpaceScaling - currentBounds.getWidth() / 3.0 + SCALE_BOUNDS.getX()), (float) (HEIGHT * 0.68 + 1.5 * currentBounds.getHeight()));
}
}
valueCounter += MAJOR_TICK_SPACING;
majorTickCounter = 0;
continue;
}
// Draw tickmark every minor tickmark spacing
if (TICKS_VISIBLE && MINOR_TICKS_VISIBLE) {
G2.setStroke(MINOR_TICKMARK_STROKE);
if (NO_OF_MINOR_TICKS % 2 == 0 && majorTickCounter == (NO_OF_MINOR_TICKS / 2)) {
G2.setStroke(MEDIUM_TICKMARK_STROKE);
drawLinearTicks(G2, WIDTH, HEIGHT, ORIENTATION, currentPos, MINOR_TICKMARK_TYPE, TICK_LINE, TICK_CIRCLE, TICK_TRIANGLE, MEDIUM_TICK_START, MEDIUM_TICK_STOP, MINOR_DIAMETER);
} else {
drawLinearTicks(G2, WIDTH, HEIGHT, ORIENTATION, currentPos, MINOR_TICKMARK_TYPE, TICK_LINE, TICK_CIRCLE, TICK_TRIANGLE, MINOR_TICK_START, MINOR_TICK_STOP, MINOR_DIAMETER);
}
}
}
} else {
// Logarithmic scaling
if (TICKS_VISIBLE) {
double offset;
double limit;
if (ORIENTATION == Orientation.VERTICAL) {
offset = SCALE_BOUNDS.getMaxY();
limit = SCALE_BOUNDS.getMinY();
} else {
offset = SCALE_BOUNDS.getMinX();
limit = SCALE_BOUNDS.getMaxX();
}
double stepSize = 1;
int exponent = 0;
double factor = Math.abs(limit - offset) / (UTIL.logOfBase(BASE, MAX_VALUE));
double pos;
Line2D tick = new Line2D.Double();
if (TICKMARK_COLOR_FROM_THEME) {
G2.setColor(BACKGROUND_COLOR.LABEL_COLOR);
} else {
G2.setColor(TICKMARK_COLOR);
}
for (int counter = 0 ; counter <= MAX_VALUE ; counter += stepSize) {
G2.setStroke(MEDIUM_TICKMARK_STROKE);
if (ORIENTATION == Orientation.VERTICAL) {
pos = offset - factor * UTIL.logOfBase(BASE, counter);
tick.setLine(MEDIUM_TICK_START, pos, MEDIUM_TICK_STOP, pos);
} else {
pos = factor * UTIL.logOfBase(BASE, counter) + offset;
tick.setLine(pos, MEDIUM_TICK_START, pos, MEDIUM_TICK_STOP);
}
if (counter == (int)Math.pow(BASE, exponent + 1)) {
exponent++;
stepSize = Math.pow(BASE, exponent);
G2.setStroke(MAJOR_TICKMARK_STROKE);
if (ORIENTATION == Orientation.VERTICAL) {
tick.setLine(MAJOR_TICK_START, pos, MAJOR_TICK_STOP, pos);
} else {
tick.setLine(pos, MAJOR_TICK_START, pos, MAJOR_TICK_STOP);
}
// Ticklabels
if (TICKLABELS_VISIBLE) {
currentLayout = new TextLayout(numberFormat.format(counter), G2.getFont(), RENDER_CONTEXT);
currentBounds = currentLayout.getBounds();
if (ORIENTATION == Orientation.VERTICAL) {
// Vertical orientation
textOffset = (float) (MAX_BOUNDS.getWidth() - currentBounds.getWidth());
G2.drawString(numberFormat.format(counter), 0.18f * WIDTH + textOffset, (float) (pos - currentBounds.getHeight() / 2.0 + currentBounds.getHeight()));
} else {
// Horizontal orientation
G2.drawString(numberFormat.format(counter), (float) (pos - currentBounds.getWidth() / 3.0), (float) (HEIGHT * 0.68 + 1.5 * currentBounds.getHeight()));
}
}
}
G2.draw(tick);
}
}
}
G2.dispose();
if (BACKGROUND_IMAGE != null) {
final Graphics2D G = BACKGROUND_IMAGE.createGraphics();
G.drawImage(imageBufferLin, 0, 0, null);
G.dispose();
}
// Buffer the current parameters
widthBufferLin = WIDTH;
heightBufferLin = HEIGHT;
minValueBufferLin = MIN_VALUE;
maxValueBufferLin = MAX_VALUE;
noOfMinorTicksBufferLin = NO_OF_MINOR_TICKS;
noOfMajorTicksBufferLin = NO_OF_MAJOR_TICKS;
minorTickSpacingBufferLin = MINOR_TICK_SPACING;
majorTickSpacingBufferLin = MAJOR_TICK_SPACING;
minorTickmarkTypeBufferLin = MINOR_TICKMARK_TYPE;
majorTickmarkTypeBufferLin = MAJOR_TICKMARK_TYPE;
ticksVisibleBufferLin = TICKS_VISIBLE;
ticklabelsVisibleBufferLin = TICKLABELS_VISIBLE;
minorTicksVisibleBufferLin = MINOR_TICKS_VISIBLE;
majorTicksVisibleBufferLin = MAJOR_TICKS_VISIBLE;
numberFormatBufferLin = NUMBER_FORMAT;
tickmarkSectionsVisibleBufferLin = TICKMARK_SECTIONS_VISIBLE;
backgroundColorBufferLin = BACKGROUND_COLOR;
tickmarkColorBufferLin = TICKMARK_COLOR;
tickmarkColorFromThemeBufferLin = TICKMARK_COLOR_FROM_THEME;
if (tickmarkSections != null) {
tickmarkSectionsBufferLin.clear();
tickmarkSectionsBufferLin.addAll(tickmarkSections);
}
if (OFFSET != null) {
offsetBufferLin.setLocation(OFFSET);
}
orientationBufferLin = ORIENTATION;
niceScaleLin = NICE_SCALE;
logScaleLin = LOG_SCALE;
return imageBufferLin;
}
private void drawLinearTicks(final Graphics2D G2,
final int WIDTH,
final int HEIGHT,
final Orientation ORIENTATION,
final double CURRENT_POS,
final TickmarkType TICKMARK_TYPE,
final Line2D TICK_LINE,
final Ellipse2D TICK_CIRCLE,
final GeneralPath TICK_TRIANGLE,
final double TICK_START,
final double TICK_STOP,
final double DIAMETER) {
switch (TICKMARK_TYPE) {
case CIRCLE:
if (ORIENTATION == Orientation.VERTICAL) {
TICK_CIRCLE.setFrame(TICK_START, CURRENT_POS - DIAMETER / 2.0, DIAMETER, DIAMETER);
} else {
TICK_CIRCLE.setFrame(CURRENT_POS - DIAMETER / 2.0, TICK_STOP, DIAMETER, DIAMETER);
}
G2.fill(TICK_CIRCLE);
break;
case TRIANGLE:
TICK_TRIANGLE.reset();
if (ORIENTATION == Orientation.VERTICAL) {
// Vertical orientation
TICK_TRIANGLE.moveTo(TICK_START, CURRENT_POS + WIDTH * 0.005);
TICK_TRIANGLE.lineTo(TICK_START, CURRENT_POS - WIDTH * 0.005);
TICK_TRIANGLE.lineTo(TICK_STOP, CURRENT_POS);
TICK_TRIANGLE.closePath();
} else {
// Horizontal orientation
TICK_TRIANGLE.moveTo(CURRENT_POS - HEIGHT * 0.005, TICK_START);
TICK_TRIANGLE.lineTo(CURRENT_POS + HEIGHT * 0.005, TICK_START);
TICK_TRIANGLE.lineTo(CURRENT_POS, TICK_STOP);
TICK_TRIANGLE.closePath();
}
G2.fill(TICK_TRIANGLE);
break;
case LINE:
default:
if (ORIENTATION == Orientation.VERTICAL) {
// Vertical orientation
TICK_LINE.setLine(TICK_START, CURRENT_POS, TICK_STOP, CURRENT_POS);
} else {
// Horizontal orientation
TICK_LINE.setLine(CURRENT_POS, TICK_START, CURRENT_POS, TICK_STOP);
}
G2.draw(TICK_LINE);
break;
}
}
//
}