// ITU F2005 JMA - Mandatory assignment #1 // Plot.java // 2005-03-01 Kenn A. Thisted /* I choose to do transformations directly on data values rather than on * display values, because the basis of this assignment specified to maximize * the visible graph area/values according to display size - thus specifically * (intentionally?) corrupting any x,y aspect ratio. * * In the event of data values being represented as points (x,y pairs) rather * than merely a series of y values, one would want to preserve the aspect ratio * even when transforming the visible area. * (using classic 2D transformation window/viewport, normalized device coordi- * nates and all that jazz...) */ import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class Plot { private Graphics g; // available outside draw() private Canvas c; private int w; // Canvas width private int h; // Canvas height private String title; private int[] y; // Dataset private int xMin; // Data boundaries private int xMax; private int yMin; private int yMax; private int xLow; // Visible data range private int xHigh; private int yLow; private int yHigh; public Plot(String title, int[] y, Canvas c) { this.c = c; this.title = title; this.y = y; w = c.getWidth(); // Get canvas size h = c.getHeight(); //System.out.println("w: " + w); //System.out.println("h: " + h); xMin = 0; // Get x span xMax = y.length-1; yMin = (int)Integer.MAX_VALUE; // Get y span yMax = (int)Integer.MIN_VALUE; for (int i = xMin; i <=xMax; i++) { // - min and max yMin = (y[i] < yMin ? y[i] : yMin); yMax = (y[i] > yMax ? y[i] : yMax); } //System.out.println("xMin: " + xMin); //System.out.println("xMax: " + xMax); //System.out.println("yMin: " + yMin); //System.out.println("yMax: " + yMax); xLow = xMin; // Show all data xHigh = xMax; // by default } /* Some issues from before this mandatory assignment still persist: * - problems handling large numbers (large.txt) * - most likely due to scaling and offset not working properly * - moving left and right affects only leftmost y-values? */ public void draw(Graphics g) { this.g = g; g.setColor( 255, 255, 255 ); // background and headlines g.fillRect( 0, 0, w, h ); g.setColor( 0, 0, 255 ); g.drawString( "ITU F2005 JMA", w/2, 0, g.TOP | g.HCENTER ); g.drawString( title, w/2, g.getFont().getHeight(), g.TOP | g.HCENTER ); g.drawString( "Kenn A. Thisted", w/2, g.getFont().getHeight() * 2, g.TOP | g.HCENTER ); yLow = (int)Integer.MAX_VALUE; // Get visible y span yHigh = (int)Integer.MIN_VALUE; for (int i = xLow; i <= xHigh; i++) { // - min and max yLow = (y[i] < yLow ? y[i] : yLow ); yHigh = (y[i] > yHigh ? y[i] : yHigh); } //System.out.println("xLow: " + xLow); //System.out.println("xHigh: " + xHigh); //System.out.println("yLow: " + yLow); //System.out.println("yHigh: " + yHigh); int wL = w << 16; // bitshift blows up values int hL = h << 16; // to avoid using floats int xD = wL / (xHigh - xLow); // x displacement int yD = hL / (yHigh - yLow); // y displacement int yOffset = (yD * (yHigh - yLow) / 2 - hL / 2 ); // vertical offset int x1 = 0 * xD; // initial point x,y int y1 = hL - yOffset - (y[xLow] * yD); for (int i = xLow; i <= xHigh; i++) { // loop through x,y int x2 = i * xD; int y2 = hL - yOffset - (y[i] * yD); g.setColor( 0, 0, 0 ); g.drawLine( x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16); //g.drawString("x", x1 >> 16, (y1 >> 16) + g.getFont().getHeight()/2, g.BOTTOM | g.HCENTER ); x1 = x2; y1 = y2; } g.setColor( 0, 0, 255 ); g.drawString( "y["+xLow+"]="+y[xLow]+" .. y["+xHigh+"]="+y[xHigh], w/2, h-g.getFont().getHeight(), g.TOP | g.HCENTER ); } // draw() /* Navigation methods have "collision detection" to avoid illegal values * being caught by java.lang.ArrayIndexOutOfBoundsException. * * When moving left and right I purposely did not allow "automatic" zooming * of "inner" values when corresponding "outer" values collide. */ public void zoomIn() { // When zooming in... if ( (xHigh - xLow) >= 2 ) // left and right cannot "meet" { xLow++; xHigh--; } draw(g); c.repaint(); } public void zoomOut() { // When zooming out... if ( (xLow > xMin) & (xHigh < xMax) ) // detect outer boundaries { xLow--; xHigh++; } draw(g); c.repaint(); } public void left() { // When moving left... if ( xLow > xMin ) { // detect lower boundary xLow--; xHigh--; } draw(g); c.repaint(); } public void right() { // When moving right... if ( xHigh < xMax ) { // detect upper boundary xLow++; xHigh++; } draw(g); c.repaint(); } public void center() { // When lost... xLow = xMin; // go to "start" xHigh = xMax; draw(g); c.repaint(); } }