// the original source of ReadFile.java // that reads a text file line by line and outputs to screen is at // // http://www.abbeyworkshop.com/howto/java/readFile/ReadFile.java.html // // I modified it // + to check for proper format of the primitives specification // + to store the information in a vector of vectors // each vector stores one primitive (one line) // My specification is: // + line (x1,y1) (x2,y2) // + rectangle (x1,y1) (x2,y2) // + ellipse (x,y) a,b // + circle (x,y) r // // I use this by habit (I got used to!) -- nothing special in here // // Also, instead of exit whenever there is an error, I skip the line // /* Value Description 0x00000000 Black 0x00FF0000 Bright Red 0x0000FF00 Bright Green 0x000000FF Bright Blue 0x007F7F7F Gray 0x00FFFF00 Bright Yellow 0x00FF7F7F Red Pastel 0x00FFFFFF White */ import java.awt.image.BufferedImage; import java.awt.*; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import java.util.*; import java.io.*; import java.lang.*; import java.util.Arrays; import java.util.Comparator; class myEdgeYminComparator implements Comparator { //... Sort the edges by ymin public int compare(myEdge e1, myEdge e2) { int y1 = e1.getYmin(); int y2 = e2.getYmin(); if (y1 < y2) return -1; if (y1 == y2) return 0; return 1; } } class myEdgeYmaxComparator implements Comparator { public int compare(myEdge e1, myEdge e2) { //... Sort the edges by ymax // because I want it to be in decending order // I multiply it with -1 int y1 = (-1)*e1.getYmax(); int y2 = (-1)*e2.getYmax(); if (y1 < y2) return -1; if (y1 == y2) return 0; return 1; } } class myEdgeXComparator implements Comparator { public int compare(myEdge e1, myEdge e2) { //... Sort the edges by intersection int y1 = e1.getIntersection(); int y2 = e2.getIntersection(); if (y1 < y2) return -1; if (y1 > y2) return 1; return 0; } } public class MyDraw { // set to true for output of intermediate computations final static boolean trace = false; // this constant specifies the size of the buffered image // I set it to 601 since my screen is too small for 800 final static int maxScreen = 601; // print content of a vector public static void printVector(Vector v) { System.out.println(v); } // ellipse public static void EllipsePoints(int x, int y, int xc, int yc, BufferedImage img, int value) { img.setRGB(x + xc, y + yc, value); img.setRGB(-x + xc, y + yc, value); img.setRGB(x + xc, -y + yc, value); img.setRGB(-x + xc, -y + yc, value); } public static void myEllipse(int xc, int yc, int a, int b, BufferedImage img, int value) { double d2; int x = 0; int y = b; double bsq = b*b; double asq = a*a; double d1 = bsq - asq*b + 0.25 * asq; EllipsePoints(x, y, xc, yc, img, value); while (asq*(y-0.5) > bsq*(x+1)) { // region 1 if (d1 < 0) // select E d1 += bsq*(2*x+3); else { // select SE d1 += bsq*(2*x+3) + asq*(-2*y+2) ; y --; } x++; EllipsePoints(x, y, xc, yc, img, value); } // end while region 1 d2 = bsq*(x+0.5)*(x+0.5)+asq*(y-1)*(y-1) - asq*bsq; // copying from the book is not always correct // d2 = b*b*(x+0.5)*(x+0.5)+asq*(y-1)*(y-1) - a*a*b*b; while (y > 0) { // region 2 if (d2 < 0) { // select SE d2 += bsq*(2*x+2) + asq*(-2*y+3) ; // d2 += b*b*(2*x+2) + a*a*(-2*y+3) ; x ++; } else // select S d2 += asq*(-2*y+3); y --; EllipsePoints(x, y, xc, yc, img, value); } // end while region 2 } // circle drawing public static void CirclePoints(int x, int y, int xc, int yc, BufferedImage img, int value) { img.setRGB(x + xc, y + yc, value); img.setRGB(y + yc, x + xc, value); img.setRGB(y + yc, -x + xc, value); img.setRGB(x + xc, -y + yc, value); img.setRGB(-x + xc, -y + yc, value); img.setRGB(-y + yc, -x + xc, value); img.setRGB(-y + yc, x + xc, value); img.setRGB(-x + xc, y + yc, value); } public static void myCircle(int xc, int yc, int radius, BufferedImage img, int value) { int x = 0; int y = radius; double d = 5.0/4.0 - radius; CirclePoints(x, y, xc, yc, img, value); while ((y - yc) > (x - xc)) { if (d < 0) // select E d += 2.0 * x + 3.0; else { // select SE d += 2.0 *(x - y) + 5.0 ; y --; } x ++; CirclePoints(x, y, xc, yc, img, value); } // while } // line drawing public static void myLine(int xmin, int ymin, int xmax, int ymax, BufferedImage img, int value) { int dx = xmax - xmin; int dy = ymax - ymin; int m = dy / dx; // the integer part of slope int d = 2*dy - dx*(2*m +1); // Initial value of d int incrE = 2*dy -2*dx*m; // increment used for move to E int incrNE = 2*(dy-dx*m-dx); // increment used for move to NE int x = xmin; int y = ymin; float slope = (float) dy / (float) dx; System.out.println("xmin "+xmin+" ymin "+ymin+" xmax "+xmax+" ymax "+ymax+" Slope "+slope); // checking slope // if (slope > 1.0 || slope < 0.0) // {System.out.println("Slope greater than 1 or less than 0 -- Stop"); return; } // set color for the first pixel img.setRGB(x, y, value); while (x < xmax) { if (d <= 0) { // choose E d += incrE; x++; } else { // choose NE d+= incrNE; x++; y++; } y += m; img.setRGB(x, y, value); } // while } // end line drawing // Filled Polygon public static void myFilledPolygon(Vector comp, BufferedImage img, int value) { Polygon pl; Point p; Comparator sortByYmin = new myEdgeYminComparator(); Comparator sortByIntersection = new myEdgeXComparator(); Comparator sortByYmax = new myEdgeYmaxComparator(); int sz = (comp.size()+1)/2; int numberOfEdges = 0; int x[] = new int[sz+1]; int y[] = new int[sz+1]; myEdge edge[] = new myEdge[sz+1]; // preparing min and max scanline int ymin = 0; int ymax = 0; int j, i; for (j = 0, i=1; i < comp.size() ; i +=2, j++) { x[j] = new Integer(comp.elementAt(i).toString()); y[j] = new Integer(comp.elementAt(i+1).toString()); if (j == 0) { ymin = y[j]; ymax = y[j]; } else { if (ymin > y[j]) ymin = y[j]; if (ymax < y[j]) ymax = y[j]; } System.out.println("j "+j+" x: "+x[j]+" y: "+y[j]); if (j > 0) { edge[numberOfEdges] = new myEdge(x[j-1], y[j-1], x[j], y[j]); numberOfEdges ++; } } if (trace) System.out.println(" ymin "+ymin+" ymax "+ymax); // if polygon is not closed, close it if (x[0] != x[sz-1] || y[0] != y[sz-1]) { x[sz] = x[0]; y[sz] = y[0]; edge[numberOfEdges] = new myEdge(x[j-1], y[j-1], x[0], y[0]); numberOfEdges ++; } // just checking -- print out the edges for (i = 0; i < numberOfEdges; i++) { System.out.print(i + ": "); edge[i].print(); } // creating edge tables Arrays.sort(edge, 0, numberOfEdges, sortByYmin); // print out the edges tables System.out.println("Edge Table:"); for (i = 0; i < numberOfEdges; i++) { System.out.print(i + ": "); edge[i].print(); } // start the filling process myEdge[] aet = new myEdge[numberOfEdges]; int idxEdge = 0; // recorded the last edge that is not in the active edge table int idxAct = 0; // current length of the active edge table boolean parity; int currentY; for (currentY = ymin; currentY < ymax; currentY++) { // update the scan line // update the intersection with the scan line // which is the x in the structure myEdge for (j = 0; j < idxAct; j ++) { aet[j].update(); } // first get the edges into the active edge table for (j = idxEdge; j < numberOfEdges; j ++) { if (edge[j].getYmin() == currentY) { aet[idxAct] = edge[j]; idxAct ++; } } if (trace) { // for trace System.out.println(currentY + ": ==>"); for (j = 0; j < idxAct; j ++) { System.out.print(j + ": "); aet[j].print(); } } // remove those edges that are no longer // set the colors // do so by sorting the active edge table // by ymax Arrays.sort(aet, 0, idxAct, sortByYmax); for (j = 0; j < idxAct; j ++) { if (currentY >= aet[j].getYmax()) { break; } } idxAct = j; // now fill it // first sort it by intersection Arrays.sort(aet, 0, idxAct, sortByIntersection); if (trace) { // for tracing System.out.println(currentY + ": "); for (j = 0; j < idxAct; j ++) { System.out.print(j + ": "); aet[j].print(); } } parity = false ; for (j = 0; j < idxAct; j ++){ if (!parity) { if (j + 1 < idxAct) { int x1 = aet[j].getIntersection(); int x2 = aet[j+1].getIntersection(); // rounding up x1 and rounding down x2 if (aet[j].getRounding() > 0) x1 ++; if (aet[j+1].getRounding() < 0) x2 --; for (int x3 = x1; x3 < x2 ; x3 ++) { img.setRGB(x3, currentY, value); } } parity = true; } else { parity = false; } } } } // end filled polygon // this is the switch for drawing public static void myDraw(Vector v, BufferedImage image) { System.out.println("Start drawing ... "); try { for (int x = 0; x < maxScreen; x++) for (int y = 0; y < maxScreen; y++) image.setRGB(x, y, 0xFFFFFFFF); Enumeration ecomp = v.elements(); int ptype; for ( ; ecomp.hasMoreElements(); ) { Vector comp = (Vector) ecomp.nextElement(); printVector(comp); ptype = new Integer(comp.firstElement().toString()); switch (ptype) { case 1: // line System.out.println("LINE "); int x[] = new int[4]; for (int i = 0; i < 4 ; i ++) { x[i] = new Integer(comp.elementAt(i+1).toString()); } if (x[0] < x[2]) myLine(x[0], x[1], x[2], x[3], image, 0xFF00FF00); else myLine(x[2], x[3], x[0], x[1], image, 0x00FF7F7F); break; case 2: // rectangle System.out.println("Rectangle "); break; case 12: // filled rectangle System.out.println("filled rectangle "); break; case 3: // ellipse System.out.println("Ellipse "); int xe[] = new int[4]; for (int i = 0; i < 4 ; i ++) { xe[i] = new Integer(comp.elementAt(i+1).toString()); } myEllipse(xe[0], xe[1], xe[2], xe[3], image, 0x00FF0000); break; case 13: // filled ellipse System.out.println("Filled ellipse "); break; case 4: // circle System.out.println("Circle "); int xc[] = new int[4]; for (int i = 0; i < 3 ; i ++) { xc[i] = new Integer(comp.elementAt(i+1).toString()); } myCircle(xc[0], xc[1], xc[2], image, 0x000000FF); break; case 14: // filled circle System.out.println("Filled circle "); break; case 5: // polygon (open) System.out.println("Open polygon "); break; case 6: // polygon (closed) System.out.println("Closed polygon "); break; case 16: // filled polygon System.out.println("Filled polygon "); System.out.println("LINE "); myFilledPolygon(comp, image, 0x000000FF); break; } } } catch (Exception e) {e.printStackTrace();} } // checking for proper format of a line public static boolean typeChecking(Vector v) { // 1 - Line, 2 - Rectangle, 3 - Ellipse, // 4 - Circle, 5 - Polygon (Open), // 6 - Polygon (Closed), 12 - Filled rectangle, // 13 - Filled ellipse, 14 - Filled circle, 16 - Filled Polygon int ptype = new Integer(v.firstElement().toString()); int vsize = v.size(); // size of vector int xy, i; int x, y, a, b; switch (ptype) { case 1: // line if (vsize != 5) { System.out.println("Incorrect line specification"); return false; } break; case 2: // rectangle case 12: // filled rectangle if (vsize != 5) { System.out.println("Incorrect rectangle specification"); return false; } break; case 3: // ellipse case 13: // filled ellipse if (vsize != 5) return false; x = new Integer(v.elementAt(1).toString()); y = new Integer(v.elementAt(2).toString()); a = new Integer(v.elementAt(3).toString()); b = new Integer(v.elementAt(4).toString()); if (x + a >= maxScreen || y+b >= maxScreen || x - a < 0 || y - b < 0) { System.out.println("Incorrect ellipse specification"); return false; } break; case 4: // circle case 14: // filled circle if (vsize != 4) return false; x = new Integer(v.elementAt(1).toString()); y = new Integer(v.elementAt(2).toString()); a = new Integer(v.elementAt(3).toString()); if (x + a >= maxScreen || x - a < 0 || y + a >= maxScreen || y - a < 0) { System.out.println("Incorrect circle specification"); return false; } break; case 5: // polygon (open) case 6: // polygon (closed) case 16: // filled polygon // polygon should have at least three points if (vsize % 2 == 0 || vsize < 7) { System.out.println("Incorrect polygon specification"); return false; } break; default: System.out.println("Unknown specification"); return false; } return true; } // parse the line and put the type and coordinates into a vector public static Vector createToken(String line) { StringTokenizer st = new StringTokenizer(line, " ,"); Vector v = new Vector(); while(st.hasMoreTokens()){ String key = st.nextToken(); Integer ikey; // process the value // should have catch the format error // and out of bound error try { ikey = new Integer(key); } catch (NumberFormatException e) { System.out.println(" NumberFormatException "); return null; } if (ikey >= maxScreen || ikey < 0) { System.out.println(" Out of bound error "); return null; } // add to the vector v.addElement(ikey); } // need to check for properness of each primitive type boolean res = typeChecking(v); if (res == false) return null; return v; } public MyDraw(String filename, BufferedImage image) { Vector fin = new Vector(); try { FileReader input = new FileReader(filename); BufferedReader bufRead = new BufferedReader(input); String line; // String that holds current file line int count = 0; // Line number of count // Read first line line = bufRead.readLine(); count++; // Read through file one line at time. Print line # and line while (line != null){ if (trace) System.out.println(count+": "+line); // create a vector for all the token Vector v = createToken(line); // print the vector if (trace) printVector(v); // add to the two dimention vector if (v == null) { System.out.println("Not acceptable : "+line); // could stop here } else { fin.add(v); } // get the next line line = bufRead.readLine(); count++; } bufRead.close(); // print out the vector of vectors if (trace) System.out.println(fin); // start drawing myDraw(fin, image); } catch (ArrayIndexOutOfBoundsException e){ /* If no file was passed on the command line, this expception is generated. A message indicating how to the class should be called is displayed */ System.out.println("Usage: java ReadFile filename\n"); } catch (IOException e){ // If another exception is generated, print a stack trace e.printStackTrace(); } } public MyDraw (String filename) { JFrame frame = new JFrame("My Primitive Graphics"); BufferedImage image = new BufferedImage(maxScreen, maxScreen, BufferedImage.TYPE_INT_RGB); Vector fin = new Vector(); try { FileReader input = new FileReader(filename); BufferedReader bufRead = new BufferedReader(input); String line; // String that holds current file line int count = 0; // Line number of count // Read first line line = bufRead.readLine(); count++; // Read through file one line at time. Print line # and line while (line != null){ if (trace) System.out.println(count+": "+line); // create a vector for all the token Vector v = createToken(line); // print the vector if (trace) printVector(v); // add to the two dimention vector if (v == null) { System.out.println("Not acceptable : "+line); // could stop here } else { fin.add(v); } // get the next line line = bufRead.readLine(); count++; } bufRead.close(); // print out the vector of vectors if (trace) System.out.println(fin); // start drawing myDraw(fin, image); } catch (ArrayIndexOutOfBoundsException e){ /* If no file was passed on the command line, this expception is generated. A message indicating how to the class should be called is displayed */ System.out.println("Usage: java ReadFile filename\n"); } catch (IOException e){ // If another exception is generated, print a stack trace e.printStackTrace(); } frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JLabel(new ImageIcon(image))); frame.pack(); frame.setVisible(true); } // read the file and process it to create a vector of vectors // it is assumed that the line contains the type of the primitives // and coordinates of its vertices, separated by comma // space can be included public static void main (String args[ ]) { new MyDraw(args[0]); } }