[Home] Restricted access for guests. The link to Java source code is disabled
Java source code of 'jhplot.jadraw.JaAxes'
package jhplot.jadraw;
import japlot.Global;
import japlot.JaAxesOptionsPanel;
import japlot.jaxodraw.JaxoColor;
import org.freehep.graphics2d.VectorGraphics;
import java.awt.Color;
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JOptionPane;
import org.apache.commons.math3.util.FastMath;
import jhplot.H2D;
import jplot.Axis;
import jplot.DataArray;
import jplot.LinePars;
import jplot.PlotPoint;
import jplot.Utils;
import jplot.Contour;
/**
* Main class to build a pad with axes, ticks, labels.
*
* @author S.Chekanov (ANL)
*
*/
public class JaAxes extends JaFillObject {
protected final int NAXES = 2;
protected final int X = 0;
protected final int Y = 1;
protected Vector data;
private int[] pad;
private double[] min;
private double[] max;
private double[] diff;
private double[] inv;
protected String[][] ticLabel;
protected double[][] ticNumber;
private int[] numberOfTics;
private int[] numberOfTicsEstimated;
protected int[] maxLabelWidth;
protected int[] maxLabelHight;
private Color backgroundColor;
private Color gridColor;
private boolean[] show;
private boolean[] showMirror;
private boolean[] showGrid;
private Font labelFont;
private Color labelColor;
protected double labelRotation;
protected double[] labelSpace;
private int expForm;
private boolean[] logScale;
private boolean[] rotateTic;
private boolean[] useTicLabels;
private static Rectangle2D.Double rect = new Rectangle2D.Double();
protected int[] AxisExponent;
protected double[] axisLength;
protected double leftMargin;
protected double rightMargin;
protected double bottomMargin;
protected double topMargin;
protected double[] ticLength;
protected double[] subticLength;
private int[] subticNumber;
protected int[] axesArrow;
protected boolean[] autoRange;
protected int plotType;
private String[] statistics;
// for contour plots
protected boolean isContour;
protected int ContourLevels;
protected boolean isContourBar;
protected int ContourBinX;
protected int ContourBinY;
protected boolean isContourGray;
protected Contour contour;
protected H2D h2d;
protected boolean isShowKey;
private boolean isGridFront;
protected static boolean default_AXES;
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructor: sets the width, height, getRelw() and getRelh() to a default
* value of 25.
*/
public JaAxes(int padX, int padY) {
// mess("stage0");
setRelw(INIT_SIZE);
setRelh(INIT_SIZE);
setStroke(2.0f);
default_AXES = true;
isGridFront=false;
isShowKey = true;
autoRange = new boolean[NAXES];
autoRange[X] = true;
autoRange[Y] = true;
data = new Vector();
pad = new int[NAXES];
pad[X] = padX;
pad[Y] = padY;
show = new boolean[NAXES];
show[X] = true;
show[Y] = true;
showMirror = new boolean[NAXES];
showMirror[X] = true;
showMirror[Y] = true;
axesArrow = new int[NAXES];
axesArrow[X] = 0;
axesArrow[Y] = 0;
showGrid = new boolean[NAXES];
showGrid[X] = false;
showGrid[Y] = false;
min = new double[NAXES];
max = new double[NAXES];
rotateTic = new boolean[NAXES];
rotateTic[X] = false;
rotateTic[Y] = false;
min[X] = 0;
min[Y] = 0;
max[X] = 1;
max[Y] = 1;
expForm = 3;
labelColor = Color.black;
labelRotation = 0.0;
labelSpace = new double[NAXES];
labelSpace[X] = 0.01;
labelSpace[Y] = 0.01;
labelFont = new Font("SansSerif", Font.BOLD, 14);
gridColor = Color.GRAY;
logScale = new boolean[NAXES];
logScale[X] = false;
logScale[Y] = false;
ticLabel = new String[NAXES][];
ticNumber = new double[NAXES][];
numberOfTics = new int[NAXES];
numberOfTics[X] = 6;
numberOfTics[Y] = 6;
numberOfTicsEstimated = new int[NAXES];
numberOfTicsEstimated[X] = numberOfTics[X];
numberOfTicsEstimated[Y] = numberOfTics[Y];
maxLabelWidth = new int[NAXES];
maxLabelHight = new int[NAXES];
diff = new double[NAXES];
inv = new double[NAXES];
axisLength = new double[NAXES];
ticLength = new double[NAXES];
ticLength[X] = 0.02;
ticLength[Y] = 0.02;
subticLength = new double[NAXES];
subticLength[X] = 0.01;
subticLength[Y] = 0.01;
subticNumber = new int[NAXES];
subticNumber[X] = 4;
subticNumber[Y] = 4;
useTicLabels = new boolean[NAXES];
useTicLabels[X] = true;
useTicLabels[Y] = true;
// default contour settings
isContour = false;
isContourBar = false;
ContourBinX = 20;
ContourBinY = 20;
ContourLevels = 20;
isContourGray = false;
contour = null;
h2d = null;
AxisExponent = new int[NAXES];
backgroundColor=Color.WHITE; // WHITE;
// prepare axis
prepareAxis(X);
prepareAxis(Y);
buildMargins();
}
/**
* is grid should be shown in front of all drawn objects?
* @return true if grid in front
*/
public boolean isGridFront() {
return isGridFront;
}
/**
* Set grid to be drown in fron of all graphic objects
* @param isGridFront true, if in front
*/
public void setGridFront(boolean isGridFront) {
this.isGridFront = isGridFront;
}
/**
* Set background color
* @param color for background
*/
public void setBackgroundColor(Color bkgColor) {
this.backgroundColor = bkgColor;
}
/**
* Get background color (white is default)
* @return color
*/
public Color getBackgroundColor() {
return backgroundColor;
}
/**
* Rebuild margins
*/
private void buildMargins() {
axisLength[X] = getWidth();
axisLength[Y] = getHeight();
leftMargin = getX();
rightMargin = leftMargin + axisLength[X];
topMargin = getY();
bottomMargin = getY() + axisLength[Y];
}
/**
* Get left margin
* @return left margin size
*/
public double getMarginLeft() {
return leftMargin;
}
/**
* Get right margin
* @return right margin
*/
public double getMarginRight() {
return rightMargin;
}
/**
* Get top margin
* @return top margin size
*/
public double getMarginTop() {
return topMargin;
}
/**
* Get bottom margin
* @return size of bottom margin
*/
public double getMarginBottom() {
return bottomMargin;
}
/**
* Calculate ticks and labels
*
* @param axis
*/
protected void prepareAxis(int axis) {
// find min and max first
setMinMax(axis);
/*
mess("\n\n--> prepareAxis for axis=", axis); mess("set log=" +
Boolean.toString(logScale[axis])); mess("set number of min=",
min[axis]); mess("set number of max=", max[axis]);
mess("set number of Ticks=", numberOfTics[axis]);
*/
int Ntick = 1;
int NtotT = numberOfTics[axis];
// use several attempts to esimate ticks
Ntick = numberOfTics[axis];
Vector tics = Axis.computeTicks(min[axis], max[axis], Ntick,
logScale[axis]);
NtotT = tics.size();
// if not log scale
if (!logScale[axis]) {
if (NtotT < numberOfTics[axis] - 1) {
Ntick = Ntick + 2;
tics = Axis.computeTicks(min[axis], max[axis], Ntick,
logScale[axis]);
NtotT = tics.size();
}
}
if (logScale[axis]) {
max[axis] = FastMath.log10(max[axis]);
min[axis] = FastMath.log10(min[axis]);
}
diff[axis] = FastMath.abs(max[axis] - min[axis]);
// fix tics
if (logScale[axis]) {
/*
if (numberOfTics[axis] > diff[axis]) {
// the following (1.0+1e-10) trick is introduced, again
// to avoid the rounding behaviour ('feature') of java.
// -----------------------------------------------------
NtotT = (int) (diff[axis] * (1.0 + 1e-10)) + 1;
mess("MESS IS CALLED");
}
*/
min[axis] = FastMath.pow(10, min[axis]);
max[axis] = FastMath.pow(10, max[axis]);
}
inv[axis] = (min[axis] < max[axis]) ? 1.0 : -1.0;
int Ntics = NtotT;
ticLabel[axis] = new String[Ntics];
ticNumber[axis] = new double[Ntics];
// double tic = calculateTicSep(axis, min[axis], max[axis]);
// some smart rounding algorithms here! Note the ridiculus
// "/(1.0/tic)" instead of *tic, an experimental trick to
// avoid the java bug (0.1999999999999999 instead of 0.2,
// I known they say it's a feature but it the most useless
// feature I've ever seen in my live ---a bug for me:-().
// --------------------------------------------------------
// double tic = calculateTicSep(min, max);
AxisExponent[axis] = 0;
// determine exponent for labels
if (!logScale[axis]) {
if (FastMath.abs(min[axis]) > FastMath.abs(max[axis]))
AxisExponent[axis] = ((int) FastMath.floor(FastMath.log10(Math
.abs(min[axis])) / 3.0)) * 3;
else
AxisExponent[axis] = ((int) FastMath.floor(FastMath.log10(Math
.abs(max[axis])) / 3.0)) * 3;
// when to use exponential form?
if (FastMath.abs(AxisExponent[axis]) <= expForm)
AxisExponent[axis] = 0;
};
int N = 0;
for (int i = 0; i < Ntics; i++) {
String ticstr = tics.elementAt(i);
double ticval = Double.parseDouble(ticstr);
// extract
double NoExpon = ticval;
if (!logScale[axis]) {
NoExpon = ticval / FastMath.pow(10.0d, AxisExponent[axis]);
ticstr = Utils.FormNum(NoExpon, min[axis], max[axis]);
} else {
ticstr = Utils.FormLog(ticval);
}
// mess("obtained tick="+ticval+" for axis=", axis);
ticNumber[axis][N] = ticval;
ticLabel[axis][N] = ticstr;
N++;
}
numberOfTicsEstimated[axis] = N;
// remove ".0" at the ends
ticLabel[axis] = Utils.skeepZero(ticLabel[axis]);
/*
mess("get log=" + Boolean.toString(logScale[axis]));
mess("calculated number of min=", min[axis]);
mess("calculated number of max=",
max[axis]); mess("calculated number of Ticks=",
numberOfTicsEstimated[axis]);
*/
};
/**
* Set exponential form. By deafult, if the number is
* larger than 1000, it will be shown using exponent.
* @param expForm
*/
public void setExpForm(int expForm) {
this.expForm = expForm;
}
/**
* Get exponential form
* @return
*/
public int getExpForm() {
return expForm;
}
/**
* Set a space between axis and labels for ticks
* @param axis axis (0: for X or 1: for Y)
* @param labelSpace space in NDC (0-1)
*/
public void setLabelSpace(int axis, double labelSpace) {
this.labelSpace[axis] = labelSpace;
}
/**
* Get label space
* @param axis axis (0: for X or 1: for Y)
* @return space
*/
public double getLabelSpace(int axis) {
return labelSpace[axis];
}
/**
* Set grid color
* @param gridColor color used to draw grid
*/
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
}
/**
* Set the number of sub-ticks
* @param axis axis (0: for X or 1: for Y)
* @param maxSubTicks max number of subticks
*/
public void setSubTicksNumber(int axis, int maxSubTicks) {
this.subticNumber[axis] = maxSubTicks;
}
/**
* Set the number of main ticks. Usually, the program tries
* to find the best number, so the actual number of main ticks can be less
* @param axis axis (0: for X or 1: for Y)
* @param maxTicks max number of tics
*/
public void setTicksNumber(int axis, int maxTicks) {
this.numberOfTics[axis] = maxTicks;
}
/**
* Is grid to be shown?
* @param axis axis (0: for X or 1: for Y)
* @param showGrid true if shown.
*/
public void setShowGrid(int axis, boolean showGrid) {
this.showGrid[axis] = showGrid;
}
/**
* Set true if you want to show a particular axis
* @param axis axis (0: for X or 1: for Y) to be shown
* @param show set true if the axis should be drawn
*/
public void setShow(int axis, boolean show) {
this.show[axis] = show;
}
/**
* Set true if a mirror axis to be shown
* @param axis axis (0: for X or 1: for Y)
* @param showMirror true if mirror axis will be shown
*/
public void setShowMirror(int axis, boolean showMirror) {
this.showMirror[axis] = showMirror;
}
/**
* Set the size of the ticks in NDC format.
* @param axis axis (0: for X or 1: for Y)
* @param ticsSize tick size in NDC form
*/
public void setTicksSize(int axis, double ticsSize) {
this.ticLength[axis] = ticsSize;
}
/**
* Set the size of subtics in NDC
* @param axis axis (0: for X or 1: for Y)
* @param subTicsSize subtick size
*/
public void setSubTicksSize(int axis, double subTicsSize) {
this.subticLength[axis] = subTicsSize;
}
/**
* Set the color for labels indicating the ticks
* @param labelColor color
*/
public void setLabelColor(Color labelColor) {
this.labelColor = labelColor;
}
/**
* Get label color
* @return color
*/
public Color getLabelColor() {
return labelColor;
}
/**
* Set label fonts
* @param labelFont font
*/
public void setLabelFont(Font labelFont) {
this.labelFont = labelFont;
}
/**
* Get label font
* @return font
*/
public Font getLabelFont() {
return labelFont;
}
/**
* Set rotation for labels
* @param labelRotation
*/
public void setLabelRotation(double labelRotation) {
this.labelRotation = labelRotation;
}
/**
* Get label rotation
* @return rotation
*/
public double getLabelRotation() {
return labelRotation;
}
/**
* Set pad ID
*
* @param axis
* axis axis (0: for X or 1: for Y)
* @param pad
* pad ID
*/
public void setPad(int axis, int pad) {
this.pad[axis] = pad;
}
/**
* Get ID of the current pad
* @param axis axis (0: for X or 1: for Y)
* @return pad ID
*/
public int getPad(int axis) {
return pad[axis];
}
/**
* Get grid color (gray is default)
* @return color
*/
public Color getGridColor() {
return gridColor;
}
/**
* Set true if ticks should be rotated
* @param axis
* @return
*/
public boolean getRotateTicks(int axis) {
return rotateTic[axis];
}
/**
* Set true if ticks should be rotated
* @param axis axis (0: for X or 1: for Y)
* @param angle angle
*/
public void setRotateTicks(int axis, boolean angle) {
rotateTic[axis] = angle;
}
/**
* Get the number of sub-ticks
* @param axis axis (0: for X or 1: for Y)
* @return number of sub-ticks
*/
public int getSubTicksNumber(int axis) {
return subticNumber[axis];
}
/**
* Get number of main ticks
* @param axis axis (0: for X or 1: for Y)
* @return number of main ticks
*/
public int getTicksNumber(int axis) {
return numberOfTics[axis];
}
/**
* Get number of ticks to be set (after adjustments)
* @param axis
* @return
*/
protected int getTicksNE(int axis) {
return numberOfTicsEstimated[axis];
}
/**
* Get sub-tick size
* @param axis axis (0: for X or 1: for Y)
* @return size
*/
public double getSubTicksSize(int axis) {
return subticLength[axis];
}
/**
* Get subtick size
* @param axis axis (0: for X or 1: for Y)
* @return size
*/
public double getTicksSize(int axis) {
return ticLength[axis];
}
/**
* Is arrow to be shown
* @param axis axis (0: for X or 1: for Y)
* @return error type
*/
public int getAxesArrow(int axis) {
return axesArrow[axis];
}
/**
* Set arrow type
* @param axis axis (0: for X or 1: for Y)
* @param type of arrow
*/
public void setAxesArrow(int axis, int type) {
axesArrow[axis] = type;
}
/**
* Is ticks should be drawn
* @param axis axis (0: for X or 1: for Y)
* @return
*/
public boolean isTicksLabels(int axis) {
return useTicLabels[axis];
}
/**
* Set or not tick labels
* @param axis axis (0: for X or 1: for Y)
* @param draw true if shown
*/
public void setTicksLabels(int axis, boolean draw) {
useTicLabels[axis] = draw;
}
/**
* is key should be shown?
* @return true if shown
*/
public boolean isShowKey() {
return isShowKey;
}
/**
* Set true if keys are shown
* @param show
*/
public void setShowKey(boolean show) {
this.isShowKey = show;
}
/**
* Is a particular axis should be shown?
* @param axis axis (0: for X or 1: for Y)
* @return true if shown
*/
public boolean isShow(int axis) {
return show[axis];
}
/**
* Is grid to be shown?
* @param axis axis (0: for X or 1: for Y)
* @return true if shown
*/
public boolean isShowGrid(int axis) {
return showGrid[axis];
}
/**
* Is axis mirror is shown?
* @param axis axis (0: for X or 1: for Y)
* @return true if shown
*/
public boolean isShowMirror(int axis) {
return showMirror[axis];
}
/**
* Get exponent for the axis
* @param axis axis (0: for X or 1: for Y)
* @return
*/
public String axisExponent(int axis) {
return Integer.toString(AxisExponent[axis]);
}
/**
* Set the contour style and parse the data.
*
* @param isContour
* true if contour style is set.
*/
public void setContour(boolean isContour) {
this.isContour = isContour;
if (this.isContour == false) {
contour = null;
h2d=null;
return;
}
}
/**
* Is contour plot shown?
* @return true if shown
*/
public boolean isContour() {
return this.isContour;
}
/**
* Show or not a bar with color levels
*
* @param bar
* true if the bar is shown
*/
public void setContourBar(boolean bar) {
this.isContourBar = bar;
}
/**
* is a bar showing levels should be shown?
* @return
*/
public boolean isContourBar(){
return this.isContourBar;
}
/**
* Get number of bins in X for contour plot
* @return number of bins in X
*/
public int getContourBinX() {
return ContourBinX;
}
/**
* Get number of bins in Y for contour plot
* @return number of bins in Y
*/
public int getContourBinY() {
return ContourBinY;
}
/**
* Get the number of levels to show contour plot
* @return number of levels
*/
public int getContourLevels() {
return ContourLevels;
}
/**
* Set a strings representing the full statistics
* @param s strings with statistics
*/
public void setStatistics(String[] s) {
this.statistics = s;
}
/**
* Get strings representing the statistics of the object
* @return statistics
*/
public String[] getStatistics() {
return this.statistics;
}
/**
* How many color levels should be shown (10 default)
*
* @param levels
* number of color levels
*/
public void setContourLevels(int levels) {
ContourLevels = levels;
}
/**
* How many bins used to slice the data in X (and Y)
*
* @param binsX
* number of bins in X
* @param binsY
* number of bins in Y
*/
public void setContourBins(int binsX, int binsY) {
ContourBinX = binsX;
ContourBinY = binsY;
}
/**
* Color style to show contour plot. The default is color style.
*
* @param gray
* set to true to show in black-white
*/
public void setContourGray(boolean gray) {
isContourGray = gray;
}
/**
* Set min and max depending on data
*
* @param axis
*/
private void setMinMax(int axis) {
if (data == null)
return;
if (data.size() == 0)
return;
double min = getMin(axis); // chekanov
double max = getMax(axis);
boolean isHisto = false;
if (autoRange[axis]) {
Enumeration e = data.elements();
DataArray da = (DataArray) e.nextElement();
if (da.getType() == LinePars.H1D)
isHisto = true;
double minVal;
if (logScale[axis])
minVal = da.getLowestNonZeroValue(axis);
else
minVal = da.getMinValue(axis);
// System.out.println("minVal = " + minVal);
min = minVal;
max = da.getMaxValue(axis);
while (e.hasMoreElements()) {
da = (DataArray) e.nextElement();
if (logScale[axis])
minVal = da.getLowestNonZeroValue(axis);
else
minVal = da.getMinValue(axis);
if (minVal < min)
min = minVal;
if (da.getMaxValue(axis) > max)
max = da.getMaxValue(axis);
}
// chekanov
// make nice separation
double del = max - min;
del = 0.05 * del;
max = max + del;
min = min - del;
if (min == max) {
min -= 0.1;
max += 0.1;
}
// if histogram, then probably you want to start at Ymin=0
if (isHisto == true && axis == 1) {
min = 0;
if (logScale[axis])
min = da.getLowestNonZeroValue(axis);
}
// fix x-scale
if (axis == 0) {
if (logScale[axis])
min = da.getLowestNonZeroValue(axis);
}
// some special treatment for logarithmic axes:
// ---------------------------------------------
if (logScale[axis]) {
min = getLogBoundary(axis, min) / 10.0;
max = getLogBoundary(axis, max);
}
}
// some smart rounding algorithms here! Note the ridiculus
// "/(1.0/tic)" instead of *tic, an experimental trick to
// avoid the java bug (0.1999999999999999 instead of 0.2,
// I known they say it's a feature but it the most useless
// feature I've ever seen in my live ---a bug for me:-().
// --------------------------------------------------------
double tic = calculateTicSep(axis, min, max);
if (autoRange[axis]) {
if (min < max) {
min = (double) tic * FastMath.floor(min / tic);
max = (double) tic * FastMath.ceil(max / tic);
} else {
min = (double) tic * FastMath.ceil(min / tic);
max = (double) tic * FastMath.floor(max / tic);
}
}
setMin(axis, min);
setMax(axis, max);
};
/**
* Set data in form of vector
* @param data input data
*/
public void setData(Vector data) {
this.data = data;
}
/**
* Convert the user coordinate X to the pixel coordinate
*
* @param x
* user coordinate X for conversion
*/
public int toX(double x) {
double d;
if (logScale[X])
d = FastMath.log10(x / min[X]);
else
d = x - min[X];
return (int) (getX() + inv[X] * d * getWidth() / diff[X]);
}
/**
* Move to User coordinates
*
* @param Xpic
* @return
*/
public double toUserX(int Xpic) {
double mPosX;
double scale = getWidth() / diff[X];
double d = (Xpic - getX()) / (inv[X] * scale);
if (logScale[X]) {
mPosX = FastMath.pow(10, d) * min[X];
} else {
mPosX = d + min[X];
}
return mPosX;
}
/**
* Convert the user coordinate Y to the pixel coordinate
*
* @param y
* user coordinate Y for conversion
*/
public int toY(double y) {
double d;
if (logScale[Y])
d = FastMath.log10(y / min[Y]);
else
d = y - min[Y];
return (int) (getY() + getHeight() * (1.0 - inv[Y] * d / diff[Y]));
}
/**
* Move to User coordinates
*
* @param Ypic
* @return
*/
public double toUserY(int Ypic) {
double scale = getHeight() / diff[Y];
double d = (-1 * Ypic + getY() + getHeight()) / (scale * inv[Y]);
double mPosY;
if (logScale[Y]) {
mPosY = FastMath.pow(10.0, d) * min[Y];
} else {
mPosY = d + min[Y];
}
return mPosY;
}
public void setTicLabel(String[][] ticLabel) {
this.ticLabel = ticLabel;
}
public String[][] getTicLabel() {
return ticLabel;
}
/**
* Sets true or false to plot on a log scale.
*
* @param axis
* defines to which axis this function applies (0 if X, 1 if Y).
* @param b
* toggle, true if the scaling is logarithmic
*/
public void setLogScale(int axis, boolean set) {
this.logScale[axis] = set;
if (set == true && subticNumber[axis] < 10)
subticNumber[axis] = 10;
prepareAxis(axis);
// mess("setLogScale called");
}
public boolean isLogScale(int axis) {
return this.logScale[axis];
}
/**
* Set autorange for a particular axis
* @param axis axis (0: for X and 1: for Y)
* @param autoRange true if autorange
*/
public void setAutoRange(int axis, boolean autoRange) {
this.autoRange[axis] = autoRange;
prepareAxis(axis);
}
/**
* Set auto-range on all axes
*/
public void setAutoRange() {
this.autoRange[X] = true;
this.autoRange[Y] = true;
prepareAxis(X);
prepareAxis(Y);
}
/**
* Is the graph axis were done with the aoutorange option?
* @param axis axis (0: for X and 1: for Y)
* @return true if autorange is set
*/
public boolean isAutoRange(int axis) {
return autoRange[axis];
}
/**
* Set the ranges for the current pad
* @param axis axis (0: for X and 1: for Y)
* @param minValue min value
* @param maxValue max value
*/
public void setRange(int axis, double minValue, double maxValue) {
default_AXES = false;
min[axis] = minValue;
max[axis] = maxValue;
autoRange[axis] = false;
prepareAxis(axis);
// mess("set range for AXIS=", axis);
// mess("Min=", minValue);
// mess("Max=", maxValue);
/*
* mess("Ticks for AXIS=", axis); mess("axis exponent=",
* AxisExponent[axis]); for (int n = 0; n < numberOfTics[axis]; n++)
* mess(" -> labels=" + ticLabel[axis][n]);
*/
}
/**
* Set min values
* @param axis axis (0: for X and 1: for Y)
* @param value min value
*/
public void setMax(int axis, double value) {
default_AXES = false;
max[axis] = value;
}
/**
* Set max value
* @param axis axis (0: for X and 1: for Y)
* @param value max value
*/
public void setMin(int axis, double value) {
default_AXES = false;
min[axis] = value;
}
/**
* Get max value
* @param axis axis (0: for X and 1: for Y)
* @return max value
*/
public double getMax(int axis) {
return max[axis];
}
/**
* Get min value
* @param axis axis (0: for X and 1: for Y)
* @return min value
*/
public double getMin(int axis) {
return min[axis];
}
/**
* Returns an exact copy of this Label.
*
* @return A copy of this Label.
*/
public final JaObject copy() {
JaAxes temp = new JaAxes(0, 0);
temp.setX(getX());
temp.setY(getY());
temp.setX(getX());
temp.setY(getY());
temp.setGridFront(isGridFront);
temp.setGridColor(gridColor);
temp.setLabelColor(labelColor);
temp.setLabelFont(labelFont);
temp.setLabelRotation(labelRotation);
temp.setExpForm(expForm);
temp.setColor(getColor());
temp.setFillColor(getFillColor());
temp.setStroke(getStroke());
temp.setSize(getWidth(), getHeight(), getRelw(), getRelh());
temp.setBoundingBox(getBoundingBox());
for (int i = 0; i < NAXES; i++) {
temp.setPad(i, pad[i]);
temp.setMin(i, min[i]);
temp.setMax(i, max[i]);
temp.setSubTicksSize(i, subticLength[i]);
temp.setAutoRange(i, autoRange[i]);
temp.setTicksSize(i, ticLength[i]);
temp.setSubTicksNumber(i, subticNumber[i]);
temp.setTicksNumber(i, numberOfTics[i]);
temp.setShowGrid(i, showGrid[i]);
temp.setShow(i, show[i]);
temp.setShowMirror(i, showMirror[i]);
temp.setLabelSpace(i, labelSpace[i]);
temp.setRotateTicks(i, rotateTic[i]);
}
return temp;
}
/**
* Returns true if all serializable variables of this JaObject and those of
* the specified one are equal.
*
* @param comp
* A JaObject to compare with.
* @return True if the objects are equal, false otherwise.
*/
public final boolean isCopy(JaObject comp) {
boolean isCopy = false;
if (comp instanceof JaAxes) {
JaAxes temp = (JaAxes) comp;
if ((temp.getX() == getX()) && (temp.getY() == getY())
&& (temp.getColor().equals(getColor()))
&& (temp.getFillColor().equals(getFillColor()))
&& (temp.getStroke() == getStroke())
&& (temp.getMin(X) == getMin(X))
&& (temp.getMin(Y) == getMin(Y))
&& (temp.getMax(X) == getMax(X))
&& (temp.getMax(Y) == getMax(Y))
&& (temp.getRelw() == getRelw())
&& (temp.getRelh() == getRelh())) {
isCopy = true;
}
}
return isCopy;
}
/**
* Determines where on this JaObject a mouse click has ocurred.
*
* @param clickX
* The x position of the point where the mouse click ocurred.
* @param clickY
* The y position of the point where the mouse click ocurred.
* @param editmode
* The current edit mode as defined in JaxoMainPanel.
* @return An integer specifying whether the click ocurred on one of the
* handles and if yes, on which.
*/
public final int getGrabbedHandle(int clickX, int clickY, int editmode) {
if ((editmode == MOVE) || (editmode == COPY)) {
if ((clickX >= (getX() + getWidth()))
&& (clickX <= (getX() + getWidth() + LENGTH))
&& (clickY >= (getY() + getHeight()))
&& (clickY <= (getY() + getHeight() + LENGTH))) {
return SELECT_BODY;
}
if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
&& (clickY >= (getY() + getHeight()))
&& (clickY <= (getY() + getHeight() + LENGTH))) {
return SELECT_BODY;
}
if ((clickX >= (getX() + getWidth()))
&& (clickX <= (getX() + getWidth() + LENGTH))
&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
return SELECT_BODY;
}
if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
return SELECT_BODY;
}
return SELECT_NONE;
}
if (editmode == RESIZE) {
if ((clickX >= (getX() + getWidth()))
&& (clickX <= (getX() + getWidth() + LENGTH))
&& (clickY >= (getY() + getHeight()))
&& (clickY <= (getY() + getHeight() + LENGTH))) {
return SELECT_LR;
}
if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
&& (clickY >= (getY() + getHeight()))
&& (clickY <= (getY() + getHeight() + LENGTH))) {
return SELECT_LL;
}
if ((clickX >= (getX() + getWidth()))
&& (clickX <= (getX() + getWidth() + LENGTH))
&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
return SELECT_UR;
}
if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
return SELECT_UL;
}
return SELECT_NONE;
}
return SELECT_NONE;
}
/**
* Draws the handles of this box object.
*
* @param g2
* The current graphics context.
*/
public final void drawHandles(VectorGraphics g2) {
g2.setColor(JaxoColor.RED);
g2.setStroke(new BasicStroke(1.0f));
int x = getX();
int y = getY();
int width = getWidth();
int height = getHeight();
g2.drawRect(x - LENGTH, y - LENGTH, LENGTH, LENGTH);
g2.drawRect(x - LENGTH, y + height, LENGTH, LENGTH);
g2.drawRect(x + width, y - LENGTH, LENGTH, LENGTH);
g2.drawRect(x + width, y + height, LENGTH, LENGTH);
if (this.isMarked()) {
g2.setColor(JaxoColor.GRAYSCALE150);
g2.fillRect(x - LENGTH + 1, y - LENGTH + 1, LENGTH - 1, LENGTH - 1);
g2.fillRect(x - LENGTH + 1, y + height + 1, LENGTH - 1, LENGTH - 1);
g2.fillRect(x + width + 1, y - LENGTH + 1, LENGTH - 1, LENGTH - 1);
g2.fillRect(x + width + 1, y + height + 1, LENGTH - 1, LENGTH - 1);
}
}
/**
* Get the lastst lavel size
*
*/
public void getLabelDimension(FontMetrics fmX, int axis) {
float wid = 0;
float wLabel = 0;
for (int i = 0; i < numberOfTicsEstimated[axis]; i++) {
if (ticLabel[axis][i] == null) continue;
wid = (float) fmX.stringWidth(ticLabel[axis][i]);
if (wid > wLabel)
wLabel = wid;
}
maxLabelWidth[axis] = (int) wLabel;
maxLabelHight[axis] = (int) fmX.getHeight();
}
/**
* Calculation of the separation length between tics. Some smart rounding
* algorithms are needed to get the scaling properly in case of data going
* to 10.3 or so...
*/
protected double calculateTicSep(int axis, double min, double max) {
double xnorm, tic, posns;
double lrange = FastMath.log10(FastMath.abs(min - max));
double fl = FastMath.floor(lrange);
xnorm = FastMath.pow(10.0, lrange - fl);
posns = numberOfTicsEstimated[axis] / xnorm;
if (posns > 40)
tic = 0.05; // eg 0, .05, .10, ...
else if (posns > 20)
tic = 0.1; // eg 0, .1, .2, ...
else if (posns > 10)
tic = 0.2; // eg 0,0.2,0.4,...
else if (posns > 4)
tic = 0.5; // 0,0.5,1,
else if (posns > 1)
tic = 1; // 0,1,2,....
else if (posns > 0.5)
tic = 2; // 0, 2, 4, 6
else if (posns > 0.2)
tic = 10; // 0, 10, 100, 6
else
tic = FastMath.ceil(xnorm);
tic *= FastMath.pow(10.0, fl);
return tic;
}
/**
* Get the vector which keeps all the data
*
* @return Vector with the data
*/
public Vector getData() {
return data;
}
/**
* Return the number of digits required to display the given number. If more
* than 15 digits are required, 15 is returned).
*/
public int getNumDigits(double num) {
int numDigits = 0;
if (num == 0.0)
return 0;
while (numDigits <= 15 && FastMath.abs(FastMath.floor(num) / num - 1.0) > 1e-10) {
num *= 10.0;
numDigits++;
}
return numDigits;
}
/**
* formats a double precision number such that it is correctly rounded for
* output. Kind of pre-processor for all number for output.
*
* @param num
* number to be formatted
* @param n
* number of digits (accuracy) after the decimal point.
* @return the formatted number in a string.
*/
public String formatNumber(double num, int n) {
int maxFloat = 6;
if (num != 0.0) {
int exp = (int) FastMath.floor(FastMath.log10(num));
int x = FastMath.abs(exp) + n;
BigDecimal bd = new BigDecimal(num);
if (x > maxFloat) {
if (exp > 0)
bd = bd.movePointLeft(exp);
else
bd = bd.movePointRight(FastMath.abs(exp));
} else {
if (exp < 0)
n = x;
else
n = x - FastMath.abs(exp);
}
bd = bd.setScale(n, BigDecimal.ROUND_HALF_EVEN);
int nn = getNumDigits(bd.doubleValue());
if (nn < n)
bd = bd.setScale(nn);
String res = bd.toString();
if (x > maxFloat)
res += "e" + exp;
return res;
} else
return "0";
}
/**
* The method that draws this Jaxo Axes.
*
* @param g2
* The graphics context where the JaAxes has to be drawn.
* @param drawToScreen
* A boolean variable that indicates whether the drawing is done
* on the screen or somewhere else. This is used for
* exporting/printing, where the object handles should not be
* painted, even if they are visible on the screen.
*/
public final void jaxoDraw(VectorGraphics g2, boolean drawToScreen) {
// rebuild margins if changed
buildMargins();
FontMetrics fm = g2.getFontMetrics(labelFont);
GeneralPath gp = getGeneralPath();
if (gp == null) return;
gp.reset();
// draw rectangle
Rectangle2D box = new Rectangle2D.Double();
box.setFrame(getX(), getY(), getWidth(), getHeight());
gp.append(box, false);
g2.setColor(getFillColor());
g2.setStroke(new BasicStroke(1.0f));
g2.fill(gp); // chekanov July 2017
gp.reset();
getLabelDimension(fm, X);
getLabelDimension(fm, Y);
int ylab = Global.fromY((float) labelSpace[X]) + maxLabelHight[X];
int xlab = Global.fromX((float) labelSpace[Y]) + maxLabelWidth[Y];
// find last label in X to find right margin
int last_label = numberOfTicsEstimated[X]-1;
int xlab_right = (int) (0.5*fm.stringWidth(ticLabel[X][last_label]));
// draw axes
DrawAxesTics.drawAxes(this, g2, gp);
// June
if (box != null) g2.draw(box);
// return to normal
g2.setColor(getColor());
g2.setStroke(new BasicStroke(getStroke()));
// draw the rest boxes
g2.draw(gp);
Rectangle2D pad = new Rectangle2D.Float();
// increase box in countor case
int xw = getWidth();
if (isContour == true) {
xw = xw + contour.getFullBarWidth();
// mess("New bar width=");
}
int xshift = xlab + 4;
int yshift = ylab + 2;
pad.setFrame(getX() - xshift, getY() - (int) (0.5 * yshift),
xw+xshift +2+xlab_right, getHeight() + 2 * yshift);
gp.append(pad, false);
Rectangle2D bb = gp.getBounds2D();
double[] bbox = { bb.getMinX(), bb.getMinY(), bb.getMaxX(),
bb.getMaxY() };
setBoundingBox(bbox);
}
/**
* The LaTeX command that is necessary to draw the given JaAxes using the
* axodraw.sty package.
*
* @param scale
* A scale factor to translate Java coordinates to LaTeX
* coordinates.
* @param canvasDim
* The current dimension of the canvas.
* @return The corresponding axodraw LaTeX command.
*/
public final String latexCommand(float scale, Dimension canvasDim) {
int canvasHeight = canvasDim.height;
Point2D lowerCorner = getLaTexLowerCorner(scale, canvasHeight);
Point2D upperCorner = getLaTexUpperCorner(scale, canvasHeight);
String command = "";
if (((int) lowerCorner.getX() == (int) upperCorner.getX())
&& ((int) lowerCorner.getY() == (int) upperCorner.getY())) {
command = "%";
} else {
if (JaxoColor.isGrayScale(getFillColor())) {
String grayScale = JaxoColor.getGreyScale(getFillColor());
command = "\\GAxes" + "(" + D_FORMAT.format(lowerCorner.getX())
+ "," + D_FORMAT.format(lowerCorner.getY()) + ")" + "("
+ D_FORMAT.format(upperCorner.getX()) + ","
+ D_FORMAT.format(upperCorner.getY()) + ")" + "{"
+ grayScale + "}";
} else {
String tlc = JaxoColor.getColorName(getColor());
String tfc = JaxoColor.getColorName(getFillColor());
command = "\\CAxes" + "(" + D_FORMAT.format(lowerCorner.getX())
+ "," + D_FORMAT.format(lowerCorner.getY()) + ")" + "("
+ D_FORMAT.format(upperCorner.getX()) + ","
+ D_FORMAT.format(upperCorner.getY()) + ")" + "{" + tlc
+ "}" + "{" + tfc + "}";
}
}
return command;
}
/*
* Find the boundary values for an X- or Y range in the case of logarithmic
* scaling. @param axis defines the axis we are working on @param v value
* which will be converted to log-scale @return new boundary value, now for
* the log scale.
*/
protected double getLogBoundary(int axis, double v) {
double k = 0.0;
double x = 10.0;
if (v > 1.0) {
while (v >= 1.0 && k < 299) {
v /= 10.0;
k += 1.0;
}
} else {
x = 0.1;
while (v <= 0.1 && k < 299) {
v *= 10.0;
k += 1.0;
}
}
return FastMath.pow(x, k);
}
/**
* Rescales this JaAxes by the scale factor scale, keeping the point (orx,
* ory) fixed.
*
* @param orx
* The x - coordinate of the fixed point
* @param ory
* The y - coordinate of the fixed point
* @param scale
* The scale parameter
*/
public final void rescaleObject(int orx, int ory, float scale) {
// int oldWidth = this.getSize().width;
// int oldHeight = this.getSize().height;
// int newWidth = (int) FastMath.round(oldWidth * scale);
// int newHeight = (int) FastMath.round(oldHeight * scale);
int newRelWidth = (int) FastMath.round(this.getRelSize().width * scale);
int newRelHeight = (int) FastMath.round(this.getRelSize().height * scale);
Point2D newP = this.scalePoint(orx, ory, scale, this.getX(), this
.getY());
this.setX((int) FastMath.round(newP.getX()));
this.setY((int) FastMath.round(newP.getY()));
// this.setWAndH(newWidth, newHeight);
this.setRelWAndH(newRelWidth, newRelHeight);
}
// ///////////////////////////////////////////////////////////////////////
//
// private auxiliary methods //
//
// ///////////////////////////////////////////////////////////////////////
private Point2D getLaTexLowerCorner(float scaleFactor, int canvasHeight) {
Point2D lowerCornerVec = new Point2D.Float();
float x1;
float y1;
x1 = getX();
y1 = getY() + getHeight();
lowerCornerVec.setLocation(x1 / scaleFactor, (canvasHeight - y1)
/ scaleFactor);
return lowerCornerVec;
}
private Point2D getLaTexUpperCorner(float scaleFactor, int canvasHeight) {
Point2D upperCornerVec = new Point2D.Float();
float x1;
float y1;
x1 = getX() + getWidth();
y1 = getY();
upperCornerVec.setLocation(x1 / scaleFactor, (canvasHeight - y1)
/ scaleFactor);
return upperCornerVec;
}
/**
* Add data to this plot.
*
* @param d
* @param plotType
* current plottype
*/
public void addData(DataArray d, int plotType) {
data.add(d);
this.plotType = plotType;
this.h2d = null;
prepareAxis(X);
prepareAxis(Y);
if (isContour == true && this.plotType == LinePars.CONTOUR)
parseContour();
}
/**
* Add h2d data set.
*
* @param h2d
*/
public void addData(H2D h2d, int plotType) {
this.plotType = plotType;
this.h2d = h2d;
if (isContour == true && this.plotType == LinePars.H2D) {
setAutoRange(X, false);
setAutoRange(Y, false);
if (default_AXES == true) {
min[X] = h2d.getMinX();
min[Y] = h2d.getMinY();
max[X] = h2d.getMaxX();
max[Y] = h2d.getMaxY();
}
prepareAxis(X);
prepareAxis(Y);
parseH2D();
}
}
/**
* Prepare a contour plot
*/
public void parseContour() {
for (Enumeration e = data.elements(); e.hasMoreElements();) {
DataArray da = (DataArray) e.nextElement();
if (da.size() == 0)
continue;
contour = new Contour(isContourBar, ContourBinX, ContourBinY,
isContourGray, ContourLevels);
contour.createGrid(da.getData(), min[X], max[X], min[Y], max[Y]);
break;
}
}
/**
* Prepare a contour plot to display H2D histograms
*/
public void parseH2D() {
// mess("call to parseH2D()");
contour = new Contour(isContourBar, ContourBinX, ContourBinY,
isContourGray, ContourLevels);
contour.setHistogram(h2d);
contour.createGrid(min[X], max[X], min[Y], max[Y]);
}
/**
* Clear.
*/
public void clear() {
data.clear();
}
/**
* Fills the graph area with a background color. The area is the area
* between the axes.
*
* @param g2
* graphics canvas
*/
protected void fillGraphArea(VectorGraphics g2) {
rect.setRect(leftMargin, topMargin, axisLength[X], axisLength[Y]);
g2.setColor(getFillColor());
g2.fill(rect);
}
public int getPlotType() {
return plotType;
}
/**
* Draw data points
*/
public void drawData(VectorGraphics g2) {
// draw grid
if (isGridFront == true)DrawGrid.draw(this, g2);
// first draw H2D if needed
if (plotType == LinePars.H2D && h2d != null) {
DrawContour.draw(this, g2, h2d);
// draw grid
if (isGridFront == false)DrawGrid.draw(this, g2);
// redraw axis
DrawAxesTics.redraw(this, g2);
return;
}
if (data == null)
return;
// run over objects
for (Enumeration e = data.elements(); e.hasMoreElements();) {
// get the next data array from the vector:
DataArray da = (DataArray) e.nextElement();
if (da.size() == 0)
continue;
// only one data set is allowed for contour
if (isContour) {
DrawContour.draw(this, g2, da);
} else {
// plot all objects in one go
DrawGraph_2D.draw(this, g2, da);
}
// System.out.println("DrawData");
}
// draw grid
if (isGridFront == false)DrawGrid.draw(this, g2);
// draw top margin
// drawMargins(g2);
// redraw axis
DrawAxesTics.redraw(this, g2);
}
/**
* Checks whether x and y are within the ranges. The ranges are defined by
* the axes system.
*
* @param x
* x-point
* @param y
* y-point
*/
private boolean inRange(double x, double y) {
if (x < leftMargin || x > leftMargin + axisLength[X] || y < topMargin
|| y > topMargin + axisLength[Y])
return false;
return true;
}
/**
* Checks whether x and y are within the frame ranges. The ranges are defined by
* the axes system.
*
* @param x
* x-point
* @param y
* y-point
*/
private boolean inRangeFrame(double x, double y) {
// if (x<0 || x>getWidth() || y>getHeight() || y<0) return false;
if (x<0 || x>getWidth() || y>getHeight()) return false;
return true;
}
/*
* This function rebuilds a polygon of plot points, something like
* data-array does. It ignores plotpoints falling beyond the current domain
* (i.e. outside the axes system).
*/
public Vector getPoints(DataArray da) {
Vector data = da.getData();
double x, y, oldX = 0.0;
double left, right, upper, lower, left_sys, right_sys, upper_sys, lower_sys;
Vector p = new Vector();
int i = 0;
double aXmin = leftMargin;
double aXmax = leftMargin + axisLength[X];
double aYmin = topMargin + axisLength[Y];
double aYmax = topMargin;
for (Enumeration e = data.elements(); e.hasMoreElements(); i++) {
PlotPoint pp = (PlotPoint) e.nextElement();
// pp.print();
x = toX(pp.getX());
y = toY(pp.getY());
left = toX(pp.getX() - pp.getXleft());
right = toX(pp.getX() + pp.getXright());
upper = toY(pp.getY() + pp.getYupper());
lower = toY(pp.getY() - pp.getYlower());
// naow, systematical bars
left_sys = toX(pp.getX() - pp.getXleft() - pp.getXleftSys());
right_sys = toX(pp.getX() + pp.getXright() + pp.getXrightSys());
upper_sys = toY(pp.getY() + pp.getYupper() + pp.getYupperSys());
lower_sys = toY(pp.getY() - pp.getYlower() - pp.getYlowerSys());
// skip some points ouside in case of symbols
if (da.getGraphStyle() != LinePars.HISTO) {
if (right_sys < aXmin - 1)
continue;
if (left_sys > aXmax + 1)
continue;
if (lower_sys < aYmax - 1)
continue;
if (upper_sys > aYmin + 1)
continue;
}
// set to borders if not all are in range
if (da.getGraphStyle() == LinePars.HISTO) {
if (right_sys < aXmin - 1)
continue;
if (left_sys > aXmax + 1)
continue;
}
// this fixes histograms from the top when overflow
if (y< topMargin) y=topMargin;
if (x< leftMargin) x=leftMargin;
if (x> leftMargin + axisLength[X]) x=leftMargin + axisLength[X];
if (y>topMargin + axisLength[Y]) y=topMargin + axisLength[Y];
if (inRange(x, y))
p.add(new PlotPoint(x, y, left, right, upper, lower, left_sys,
right_sys, upper_sys, lower_sys));
}
return p;
}
/*
* This function rebuilds a polygon of plot points, something like
* data-array does. It ignores plotpoints falling beyond the current domain
* (i.e. outside the axes system).
*/
public Vector getPointsNoCuts(DataArray da) {
Vector data = da.getData();
double x, y;
double left, right, upper, lower, left_sys, right_sys, upper_sys, lower_sys;
Vector p = new Vector();
int i = 0;
for (Enumeration e = data.elements(); e.hasMoreElements(); i++) {
PlotPoint pp = (PlotPoint) e.nextElement();
// pp.print();
x = toX(pp.getX());
y = toY(pp.getY());
left = toX(pp.getX() - pp.getXleft());
right = toX(pp.getX() + pp.getXright());
upper = toY(pp.getY() + pp.getYupper());
lower = toY(pp.getY() - pp.getYlower());
// naow, systematical bars
left_sys = toX(pp.getX() - pp.getXleft() - pp.getXleftSys());
right_sys = toX(pp.getX() + pp.getXright() + pp.getXrightSys());
upper_sys = toY(pp.getY() + pp.getYupper() + pp.getYupperSys());
lower_sys = toY(pp.getY() - pp.getYlower() - pp.getYlowerSys());
p.add(new PlotPoint(x, y, left, right, upper, lower, left_sys,
right_sys, upper_sys, lower_sys));
}
return p;
}
/*
* Repaint margins to remove overflows
*/
public void drawMargins(VectorGraphics g2) {
double x = leftMargin + axisLength[X];
double y = topMargin + axisLength[Y];
// fillRect(int x, int y, int width, int height)
int width = getWidth();
int height = getHeight();
g2.setColor(backgroundColor);
//from left vertical
// g2.fillRect(0, 0, leftMargin, height+topMargin+bottomMargin);
// from top horisonal
g2.fillRect(0, 0, width+rightMargin+leftMargin, topMargin);
// right
// g2.fillRect(x, 0, rightMargin, height+topMargin+bottomMargin);
// bottom
// g2.fillRect(0, y, width+rightMargin+leftMargin, bottomMargin);
}
/**
* Brings up the edit panel that allows to change the parameters of this
* object.
*
* @return True if the editing actually changed the object, false if the
* object has not been changed.
*/
public final boolean editPanel() {
JaAxesOptionsPanel boxop = new JaAxesOptionsPanel(this);
return boxop.hasChanged();
}
protected void mess(String s, double d) {
System.out.println("Debug: " + s + Double.toString(d));
}
protected void mess(String s, int d) {
System.out.println("Debug: " + s + Integer.toString(d));
}
protected void mess(String s) {
System.out.println("Debug: " + s);
}
/**
* Generate error message
*
* @param a
* Message
*/
protected void error(String a) {
JOptionPane dialogError = new JOptionPane();
JOptionPane.showMessageDialog(dialogError, a, "Error",
JOptionPane.ERROR_MESSAGE);
}
}