/* moonCanvas.java Paul Carlisle An extension of Canvas, which displays an image of the Moon in a particular phase. Uses a double buffering technique to provide smooth transitions. */ import java.awt.*; import java.applet.*; import java.net.*; import java.util.*; public class moonCanvas extends Canvas { private int Width; private int Height; private double phase; private double pAng; private int imageWidth; private int imageHeight; private int offsetx; private int offsety; private Image masterImage; private Image buffer; private Graphics bufferGraphics; // Moved these out of the polygon routine to avoid having to call // new() on them evertime the routine was called. private int x[]; private int y[]; private Polygon mask; public moonCanvas(int width, int height, Image image) { Width = width; Height = height; masterImage = image; imageWidth = masterImage.getWidth(this); imageHeight = masterImage.getHeight(this); offsetx = (Width - imageWidth) / 2; offsety = (Height - imageHeight) / 2; x = new int[imageWidth * 2]; y = new int[imageWidth * 2]; mask = new Polygon(); redraw(0, 0); resize(Width, Height); setBackground(Color.black); } // Calculate the points forming the polygon which delimits the shadowed // portion of the Moon's disk. This routine could be made more efficient // by using a differencing algorithm, similar to Bressenham's circle // algorithm. But in the interest of meeting out deadline, we use // the analytic formulas. // Surprisingly fast, considering the number of square roots involved. private Polygon calculatePolygon(double phase, double pAng) { int a = imageWidth / 2; int a2 = a*a; double b = a * Math.cos(phase); int b2 = (int)(b*b); int iw2 = a; int iw32 = 3 * a; double t = Math.abs(pAng) - Math.PI/2; if (pAng >= 0) t = -t; double sint = Math.sin(t); double cost = Math.cos(t); double tx, ty; double a1 = imageWidth / 2; double aa = a1*a1; double b1 = a1 * Math.cos(phase); double bb = b1 * b1; // First quadrant for (int yindex = 0; yindex < iw2; yindex++) { // Eliptical arc. ty = -(iw2 - yindex - 1); tx = Math.sqrt(bb - (bb * ty * ty)/aa); if ( (phase >= Math.PI/2) && (phase < Math.PI) || (phase >= 3 * Math.PI/2) && (phase < 2*Math.PI) ) tx = - tx; x[yindex] = (int)Math.round(a1 + (tx * cost - ty * sint)); y[yindex] = (int)Math.round(a1 + (tx * sint + ty * cost)); // Circular arc. ty = -yindex; tx = Math.sqrt(aa - ty * ty); if ( (phase >= 0) && (phase < Math.PI) ) tx = -tx; x[iw32 + yindex] = (int)Math.round(a1 + (tx * cost - ty * sint)); y[iw32 + yindex] = (int)Math.round(a1 + (tx * sint + ty * cost)); } // Second quadrant. for (int yindex = iw2; yindex < imageWidth; yindex++) { // Eliptical arc. ty = (yindex - iw2); tx = Math.sqrt(bb - (bb * ty * ty)/aa); if ( (phase >= Math.PI/2) && (phase < Math.PI) || (phase >= 3 * Math.PI/2) && (phase < 2*Math.PI) ) tx = - tx; x[yindex] = (int)Math.round(a1 + (tx * cost - ty * sint)); y[yindex] = (int)Math.round(a1 + (tx * sint + ty * cost)); // Circular arc. ty = imageWidth - yindex - 1; tx = Math.sqrt(aa - ty * ty); if ( (phase >= 0) && (phase < Math.PI) ) tx = -tx; x[iw2 + yindex] = (int)Math.round(a1 + (tx * cost - ty * sint)); y[iw2 + yindex] = (int)Math.round(a1 + (tx * sint + ty * cost)); } mask.npoints = imageWidth * 2; mask.xpoints = x; mask.ypoints = y; return mask; } public void paint(Graphics g) { Polygon tempPolygon; tempPolygon = calculatePolygon(phase, pAng); // Might consider making buffer global, and only creating it once. buffer = createImage(imageWidth, imageHeight); bufferGraphics = buffer.getGraphics(); bufferGraphics.drawImage(masterImage, 0, 0, this); bufferGraphics.setColor(Color.black); bufferGraphics.fillPolygon(tempPolygon); g.drawImage(buffer, offsetx, offsety, this); // Attempts to cure evil memory leak in IE3.0. // Not effective, but helps with NC4.0. bufferGraphics.dispose(); g.dispose(); buffer.flush(); System.gc(); } public void redraw(double Phase, double PAng) { phase = Phase; pAng = PAng; repaint(); } public void update(Graphics g) { paint(g); } }