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);
	}

}