All Downloads are FREE. Search and download functionalities are using the official Maven repository.

JSci.awt.Graph2D.vm Maven / Gradle / Ivy

package ${package};

import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
#if(!($api == "AWT"))import JSci.awt.*;#end
import JSci.maths.ExtraMath;

/**
* The ${className} superclass provides an abstract encapsulation of 2D graphs.
* There is some support for the handling of NaN values.
* @version 1.8
* @author Mark Hale
*/
public abstract class ${className} extends ${extendsClassName} implements GraphDataListener {
        public final static int LINEAR_SCALE = 0;
        public final static int LOG_SCALE = 1;
        /**
        * Data model.
        */
        protected Graph2DModel model;
        /**
        * Origin.
        */
        protected Point origin = new Point();
        protected Graph2D.DataMarker dataMarker = Graph2D.DataMarker.NONE;
        /**
        * Series colors.
        */
        protected Color seriesColor[]={Color.black,Color.blue,Color.green,Color.red,Color.yellow,Color.cyan,Color.lightGray,Color.magenta,Color.orange,Color.pink};
        /**
        * Axis numbering.
        */
        protected boolean xNumbering = true, yNumbering = true;
        protected NumberFormat xNumberFormat = new DecimalFormat("${numberFormat}");
        protected NumberFormat yNumberFormat = new DecimalFormat("${numberFormat}");
	protected boolean xAxisLine = true, yAxisLine = true;
        protected boolean gridLines = false;
        private final Color gridLineColor = Color.lightGray;
        /**
        * Axis scaling.
        */
        private float xScale,yScale;
        /**
        * Axis scaling type.
        */
        private int xScaleType, yScaleType;
        /**
        * Axis extrema.
        */
        private float minX, minY, maxX, maxY;
        private float scaledMinX, scaledMinY, scaledMaxX, scaledMaxY;
        private boolean autoXExtrema=true, autoYExtrema=true;
        private float xGrowth, yGrowth;
        /**
        * Axis numbering increment.
        */
        private final float xIncPixels = 40.0f;
        private final float yIncPixels = 40.0f;
        private float xInc,yInc;
        private boolean autoXInc=true,autoYInc=true;
        /**
        * Padding.
        */
        protected final int scalePad=5;
        protected final int axisPad=25;
        protected int leftAxisPad;
        /**
        * Constructs a 2D graph.
        */
        public ${className}(Graph2DModel gm) {
                model=gm;
                model.addGraphDataListener(this);
                dataChanged(new GraphDataEvent(model));
        }
        /**
        * Sets the data plotted by this graph to the specified data.
        */
        public final void setModel(Graph2DModel gm) {
                model.removeGraphDataListener(this);
                model=gm;
                model.addGraphDataListener(this);
                dataChanged(new GraphDataEvent(model));
        }
        /**
        * Returns the model used by this graph.
        */
        public final Graph2DModel getModel() {
                return model;
        }
        /**
        * Implementation of GraphDataListener.
	* Supports {@link JSci.awt.GraphDataEvent#isIncremental() incremental} updates.
        * Application code will not use this method explicitly, it is used internally.
        */
        public void dataChanged(GraphDataEvent e) {
                if(e.isIncremental()) {
                        Graphics g = getOffscreenGraphics();
                        if(g == null)
                                return;
                        final int series = e.getSeries();
                        if(series == GraphDataEvent.ALL_SERIES) {
                                model.firstSeries();
                                int n = 0;
                                do {
                                        final int i = model.seriesLength() - 1;
                                        incrementalRescale(model.getXCoord(i), model.getYCoord(i));
                                        g.setColor(seriesColor[n]);
                                        drawDataPoint(g, i);
                                        n++;
                                } while(model.nextSeries());
                        } else {
                                model.firstSeries();
                                int n=0;
                                for(; nseriesColor.length) {
                                Color tmp[]=seriesColor;
                                seriesColor=new Color[n];
                                System.arraycopy(tmp,0,seriesColor,0,tmp.length);
                                for(int i=tmp.length; i maxX)
                        max = autoXExtrema ? Math.max(x, maxX+xGrowth) : maxX+xGrowth;
                else
                        max = maxX;
                rescaleX(min, max);

                if(y < minY)
                        min = autoYExtrema ? Math.min(y, minY-yGrowth) : minY-yGrowth;
                else
                        min = minY;
                if(y > maxY)
                        max = autoYExtrema ? Math.max(y, maxY+yGrowth) : maxY+yGrowth;
                else
                        max = maxY;
                rescaleY(min, max);
        }
        /**
        * Turns axis numbering on/off.
        * Default is on.
        */
        public final void setNumbering(boolean flag) {
		setNumbering(flag, flag);
	}
        public final void setNumbering(boolean xFlag, boolean yFlag) {
                xNumbering = xFlag;
		yNumbering = yFlag;
                leftAxisPad = axisPad;
                if(yNumbering && getFont() != null) {
                        // adjust leftAxisPad to accomodate y-axis numbering
                        final FontMetrics metrics = getFontMetrics(getFont());
                        final int maxYNumLen = metrics.stringWidth(yNumberFormat.format(maxY));
                        final int minYNumLen = metrics.stringWidth(yNumberFormat.format(minY));
                        int yNumPad = Math.max(minYNumLen, maxYNumLen);
                        if(scaledMinX<0.0f) {
                                final int negXLen = (int)((Math.max(getSize().width,getMinimumSize().width)-2*(axisPad+scalePad))*scaledMinX/(scaledMinX-scaledMaxX));
                                yNumPad = Math.max(yNumPad-negXLen, 0);
                        }
                        leftAxisPad += yNumPad;
                }
                rescale();
        }
        public void addNotify() {
                super.addNotify();
                // getFont() is now not null
                // recalculate padding
                setNumbering(xNumbering, yNumbering);
        }
        /**
        * Sets the display format used for axis numbering.
        * Convenience method.
        * @see #setXNumberFormat(NumberFormat)
        * @see #setYNumberFormat(NumberFormat)
        */
        public final void setNumberFormat(NumberFormat format) {
                xNumberFormat = format;
                yNumberFormat = format;
                setNumbering(xNumbering, yNumbering);
        }
        /**
        * Sets the display format used for x-axis numbering.
        */
        public final void setXNumberFormat(NumberFormat format) {
                xNumberFormat = format;
                setNumbering(xNumbering, yNumbering);
        }
        /**
        * Sets the display format used for y-axis numbering.
        */
        public final void setYNumberFormat(NumberFormat format) {
                yNumberFormat = format;
                setNumbering(xNumbering, yNumbering);
        }
	/**
	* Turns the axis lines on/off.
	*/
	public final void setAxisLines(boolean xFlag, boolean yFlag) {
		xAxisLine = xFlag;
		yAxisLine = yFlag;
		redraw();
	}
        /**
        * Turns grid lines on/off.
        * Default is off.
        */
        public final void setGridLines(boolean flag) {
                gridLines = flag;
                redraw();
        }
        /**
        * Sets the x-axis scale type.
        * @param t a _SCALE constant.
        */
        public final void setXScale(int t) {
                if(xScaleType != t) {
                        xScaleType = t;
                        dataChanged(new GraphDataEvent(model));
                }
        }
        /**
        * Sets the y-axis scale type.
        * @param t a _SCALE constant.
        */
        public final void setYScale(int t) {
                if(yScaleType != t) {
                        yScaleType = t;
                        dataChanged(new GraphDataEvent(model));
                }
        }
        /**
        * Sets the x-axis numbering increment.
        * @param dx use 0.0f for auto-adjusting (default).
        */
        public final void setXIncrement(float dx) {
                if(dx < 0.0f) {
                        throw new IllegalArgumentException("Increment should be positive.");
                } else if(dx == 0.0f) {
                        if(!autoXInc) {
                                autoXInc = true;
                                rescale();
                        }
                } else {
                        autoXInc = false;
                        if(dx != xInc) {
                                xInc = dx;
                                rescale();
                        }
                }
        }
        /**
        * Returns the x-axis numbering increment.
        */
        public final float getXIncrement() {
                return xInc;
        }
        /**
        * Sets the y-axis numbering increment.
        * @param dy use 0.0f for auto-adjusting (default).
        */
        public final void setYIncrement(float dy) {
                if(dy < 0.0f) {
                        throw new IllegalArgumentException("Increment should be positive.");
                } else if(dy == 0.0f) {
                        if(!autoYInc) {
                                autoYInc = true;
                                rescale();
                        }
                } else {
                        autoYInc = false;
                        if(dy != yInc) {
                                yInc = dy;
                                rescale();
                        }
                }
        }
        /**
        * Returns the y-axis numbering increment.
        */
        public final float getYIncrement() {
                return yInc;
        }
        /**
        * Sets the minimum/maximum values on the x-axis.
        * Set both min and max to 0.0f for auto-adjusting (default).
        */
        public final void setXExtrema(float min, float max) {
                if(min==0.0f && max==0.0f) {
                        autoXExtrema=true;
                        // determine min and max from model
                        min=Float.POSITIVE_INFINITY;
                        max=Float.NEGATIVE_INFINITY;
                        float tmp;
                        model.firstSeries();
                        do {
                                for(int i=0;i 0.0f;
                if(autoYInc) {
                        yInc = (float) ExtraMath.round((double)yIncPixels/(double)yScale, 1);
                        if(yInc == 0.0f)
                                yInc = Float.MIN_VALUE;
                }
                //assert yInc > 0.0f;
                origin.x=leftAxisPad-Math.round(scaledMinX*xScale);
                origin.y=thisHeight-axisPad+Math.round(scaledMinY*yScale);
                redraw();
        }
        /**
        * Converts a data point to screen coordinates.
        */
        protected final Point dataToScreen(float x,float y) {
                if(xScaleType == LOG_SCALE)
                        x = (float) Math.log(x);
                if(yScaleType == LOG_SCALE)
                        y = (float) Math.log(y);
                return scaledDataToScreen(x, y);
        }
        /**
        * Converts a scaled data point to screen coordinates.
        */
        protected final Point scaledDataToScreen(float x, float y) {
                return new Point(origin.x+Math.round(xScale*x), origin.y-Math.round(yScale*y));
        }
        /**
        * Converts a screen point to data coordinates.
        */
        protected final Point2D.Float screenToData(Point p) {
                double x = (double)(p.x-origin.x) / (double)xScale;
                double y = (double)(origin.y-p.y) / (double)yScale;
                if(xScaleType == LOG_SCALE)
                        x = Math.exp(x);
                if(yScaleType == LOG_SCALE)
                        y = Math.exp(y);
                return new Point2D.Float((float)x, (float)y);
        }
        /**
        * Draws the graph axes.
        */
        protected final void drawAxes(Graphics g) {
#if($api == "Swing")
                // Swing optimised
                final int width = getWidth();
                final int height = getHeight();
#else
                final Dimension size = getSize();
                final int width = size.width;
                final int height = size.height;
#end
                g.setColor(getForeground());
// grid lines and numbering
                if(gridLines || xNumbering) {
// x-axis numbering and vertical grid lines
                        float xAxisY;
                        if(scaledMinY > 0.0f)
                                xAxisY = scaledMinY;
                        else if(scaledMaxY < 0.0f)
                                xAxisY = scaledMaxY;
                        else
                                xAxisY = 0.0f;
                        for(double x=(scaledMinX>0.0f)?scaledMinX:xInc; x<=scaledMaxX; x+=xInc) {
                                Point p=scaledDataToScreen((float)x, xAxisY);
                                if(gridLines) {
                                        g.setColor(gridLineColor);
                                        g.drawLine(p.x, axisPad-scalePad, p.x, height-(axisPad-scalePad));
                                        g.setColor(getForeground());
                                }
                                if(xNumbering) {
					drawXLabel(g, x, p);
                                }
                        }
                        for(double x=-xInc; x>=scaledMinX; x-=xInc) {
                                Point p=scaledDataToScreen((float)x, xAxisY);
                                if(gridLines) {
                                        g.setColor(gridLineColor);
                                        g.drawLine(p.x, axisPad-scalePad, p.x, height-(axisPad-scalePad));
                                        g.setColor(getForeground());
                                }
                                if(xNumbering) {
					drawXLabel(g, x, p);
                                }
                        }
		}
		if(gridLines || yNumbering) {
// y-axis numbering and horizontal grid lines
                        float yAxisX;
                        if(scaledMinX > 0.0f)
                                yAxisX = scaledMinX;
                        else if(scaledMaxX < 0.0f)
                                yAxisX = scaledMaxX;
                        else
                                yAxisX = 0.0f;
                        for(double y=(scaledMinY>0.0f)?scaledMinY:yInc; y<=scaledMaxY; y+=yInc) {
                                Point p=scaledDataToScreen(yAxisX, (float)y);
                                if(gridLines) {
                                        g.setColor(gridLineColor);
                                        g.drawLine(leftAxisPad-scalePad, p.y, width-(axisPad-scalePad), p.y);
                                        g.setColor(getForeground());
                                }
                                if(yNumbering) {
					drawYLabel(g, y, p);
                                }
                        }
                        for(double y=-yInc; y>=scaledMinY; y-=yInc) {
                                Point p=scaledDataToScreen(yAxisX, (float)y);
                                if(gridLines) {
                                        g.setColor(gridLineColor);
                                        g.drawLine(leftAxisPad-scalePad, p.y, width-(axisPad-scalePad), p.y);
                                        g.setColor(getForeground());
                                }
                                if(yNumbering) {
					drawYLabel(g, y, p);
                                }
                        }
                }

// axis lines
	if(xAxisLine) {
                // horizontal axis
                if(scaledMinY > 0.0f) {
                        // draw at bottom
                        g.drawLine(leftAxisPad-scalePad, height-axisPad, width-(axisPad-scalePad), height-axisPad);
                } else if(scaledMaxY < 0.0f) {
                        // draw at top
                        g.drawLine(leftAxisPad-scalePad, axisPad, width-(axisPad-scalePad), axisPad);
                } else {
                        // draw through y origin
                        g.drawLine(leftAxisPad-scalePad, origin.y, width-(axisPad-scalePad), origin.y);
                }
	}
	if(yAxisLine) {
                // vertical axis
                if(scaledMinX > 0.0f) {
                        // draw at left
                        g.drawLine(leftAxisPad, axisPad-scalePad, leftAxisPad, height-(axisPad-scalePad));
                } else if(scaledMaxX < 0.0f) {
                        // draw at right
                        g.drawLine(width-axisPad, axisPad-scalePad, width-axisPad, height-(axisPad-scalePad));
                } else {
                        // draw through x origin
                        g.drawLine(origin.x, axisPad-scalePad, origin.x, height-(axisPad-scalePad));
                }
	}
        }
	protected void drawXLabel(Graphics g, double x, Point p) {
		double scaledX;
		if(xScaleType == LOG_SCALE)
			scaledX = Math.exp(x);
		else
			scaledX = x;
		String str = xNumberFormat.format(scaledX);
		FontMetrics metrics=g.getFontMetrics();
		int strWidth=metrics.stringWidth(str);
		int strHeight=metrics.getHeight();
		g.drawLine(p.x,p.y,p.x,p.y+5);
		g.drawString(str,p.x-strWidth/2,p.y+5+strHeight);
	}
	protected void drawYLabel(Graphics g, double y, Point p) {
		double scaledY;
		if(yScaleType == LOG_SCALE)
			scaledY = Math.exp(y);
		else
			scaledY = y;
		String str = yNumberFormat.format(scaledY);
		FontMetrics metrics=g.getFontMetrics();
		int strWidth=metrics.stringWidth(str);
		int strHeight=metrics.getHeight();
		g.drawLine(p.x,p.y,p.x-5,p.y);
		g.drawString(str,p.x-8-strWidth,p.y+strHeight/3);
	}
        /**
        * Draws the graph data.
        * Override this method to change how the graph data is plotted.
        */
        protected void drawData(Graphics g) {
// points
                model.firstSeries();
                g.setColor(seriesColor[0]);
                int i;
                for(i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy