// Lenses.java (JDK 1.1) /************************************************************************* * * * Copyright (c) 1998 Northwestern University * * * * This program is free software. You can copy, modify, or redistribute * * this software under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version, provided that both * * the above copyright notice appears in all copies and that this * * permission notice appear in any supporting documentation. * * * * This software is provided "as is" in the hope that it will be useful, * * but WITHOUT any expressed or implied warranty of merchantability or * * fitness for any particular purpose. Your milage may vary. * * See the GNU General Public License for more details. * * * *************************************************************************/ // Modification History // Date Initials Change /* @author Xiaowei Jiang, Greg Anderson * @version 0.1, June 1999 */ import java.awt.*; import java.awt.event.*; import java.applet.*; import Banner; public class Lenses extends Applet{ private LensCanvas canvas; public Lenses(){ canvas = new LensCanvas(); setLayout(new BorderLayout()); add("North", new Banner("Lenses")); add("South", new LensControl(canvas)); add("Center", canvas); } public void init(){ canvas.init(); } public void start(){} public String getAppletInfo(){ return "The Northwestern University Virtual Physics Lab"; } } class LensImage{ public int xx, yy; public int width, height; public double focus; public LensImage(double f, int w, int h){ focus = f; width = w; height = h; xx = 200; yy = 150; } public double getF(){return focus;} public int getW(){return width;} public int getH(){return height;} public int getX(){return xx;} public int getY(){return yy;} public Point getTop(){return new Point(xx, yy+height);} public Point getBottom(){return new Point(xx, yy-height);} public Point getCenter(){return new Point(xx, yy);} public Point getFocus1(){return new Point((int)(xx-focus), yy);} public Point getFocus2(){return new Point((int)(xx+focus), yy);} public void setF(double f){focus = f;} public void setX(int x){xx = x;} public void setY(int y){yy = y;} public void setLocation(int x, int y){xx=x; yy = y;} public boolean inside(int x, int y){return false;} public void paint(Graphics g){}; } class LensSystem{ private LensImage lense; private LensArrow src, img; private int id; //id of the object been activated private boolean showCenterLine = false; private boolean showFirstFocusLine = false; private boolean showSecondFocusLine = false; public LensSystem(LensImage theLens){ lense = theLens; src = new LensArrow(Color.blue, 6, 40); //color, width, height src.setLocation(60, lense.getY()); //(x,y) img = new LensArrow(Color.blue, 6); //color, width, height img.setY(lense.getY()); } public void setView(boolean a, boolean b, boolean c){ showCenterLine = a; showFirstFocusLine = b; showSecondFocusLine = c; } private void setImg(){ double f = lense.getF(); int xLens = lense.getX(); int yLens = lense.getY(); int srcD = xLens - src.getX(); int imgD = (int) (srcD*f/(srcD-f)); img.setX(imgD+xLens); if(srcD!=0) img.setHeight(-src.getHeight()*imgD/srcD); if(img.getX() < lense.getX()) img.setColor(Color.green); else img.setColor(Color.blue); } private int extractY(Point first, Point second, int x){ int x1 = first.x, y1 = first.y; int x2 = second.x, y2= second.y; if(x1!=x2) return (int) (y1 + (x-x1)*(y2-y1)/(x2-x1)); else { int LARGE = 10000; return LARGE; } } private void drawCentralLine(Graphics g){ Point srcTip = src.getTip(); Point imgTip = img.getTip(); if(img.getX()>lense.getX()) {//real image g.setColor(src.getColor()); g.drawLine(srcTip.x, srcTip.y, imgTip.x, imgTip.y); } else{//virtual image g.setColor(img.getColor()); g.drawLine(srcTip.x, srcTip.y, imgTip.x, imgTip.y); int xRight = 520; int yRight = extractY(srcTip, lense.getCenter(), xRight); g.setColor(src.getColor()); g.drawLine(srcTip.x, srcTip.y, xRight, yRight); } } private void drawFocus1Line(Graphics g){ Point srcTip = src.getTip(); Point imgTip = img.getTip(); Point focus = lense.getFocus1(); if(lense.getX() < img.getX()){//real image g.setColor(src.getColor()); int xLens = lense.getX(); int yOnLens = extractY(srcTip, focus, xLens); g.drawLine(srcTip.x, srcTip.y, xLens, yOnLens); g.drawLine(xLens, yOnLens, img.getX(), yOnLens); } else{//virtual image int xRight = 520; int yOnLens = extractY(focus, srcTip, lense.getX()); g.setColor(src.getColor()); g.drawLine(lense.getX(), yOnLens, xRight, yOnLens); g.setColor(img.getColor()); g.drawLine(imgTip.x, imgTip.y, lense.getX(), yOnLens); g.setColor(src.getColor()); g.drawLine(srcTip.x, srcTip.y, lense.getX(), yOnLens); g.setColor(img.getColor()); if(focus.x < srcTip.x){//convex g.drawLine(focus.x, focus.y, srcTip.x, srcTip.y); } else {//concave g.drawLine(focus.x, focus.y, lense.getX(), yOnLens); } } } private void drawFocus2Line(Graphics g){ Point srcTip = src.getTip(); Point imgTip = img.getTip(); g.setColor(src.getColor()); g.drawLine(srcTip.x, srcTip.y, lense.getX(), srcTip.y); if(lense.getX() < img.getX()){//real image g.drawLine(lense.getX(), srcTip.y, imgTip.x, imgTip.y); } else{//virtual image int xRight = 520; int yRight = extractY(new Point(lense.getX(), srcTip.y), lense.getFocus2(), xRight); g.drawLine(lense.getX(), srcTip.y, xRight, yRight); g.setColor(img.getColor()); g.drawLine(lense.getX(), srcTip.y, imgTip.x, imgTip.y); } } public void paint(Graphics g){ setImg(); lense.paint(g); src.paint(g); img.paint(g); if (showCenterLine) drawCentralLine(g); if (showFirstFocusLine) drawFocus1Line(g); if (showSecondFocusLine) drawFocus2Line(g); } public void move(int x, int y){ switch(id){ case 0://drag lense moveLens(x); break; case 1://drag source moveSrc(x); break; case 2://drag image moveImg(x); break; default: break; //do nothing } } private void moveLens(int x){ if(x >= src.getX()) lense.setX(x); else lense.setX(src.getX()); } private void moveSrc(int x){ if(x < lense.getX()) src.setX(x); else src.setX(lense.getX()); } private void moveImg(int x){ //do nothing } MouseListener getFocusAssigner(){ return new FocusAssigner(); } class FocusAssigner extends MouseAdapter{ private int insideId(int x, int y){ if(lense.inside(x,y)) return 0; //case: lense been selected if(src.inside(x,y)) return 1; //case: source been selected if(img.inside(x,y)) return 2; //case: image been selected else return -1; } public void mousePressed(MouseEvent e){ id = insideId(e.getX(), e.getY()); } } } class LensControl extends Panel{ Choice lenseType; Checkbox center, first, second; LensCanvas parent; public LensControl(LensCanvas theCanvas){ parent = theCanvas; setLayout(new GridLayout(1,4,5,5)); lenseType = new Choice(); lenseType.addItem("Convex Lens"); lenseType.addItem("Concave Lens"); add(lenseType); lenseType.addItemListener(new ControlListener()); ItemListener view = new ViewListener(); center = new Checkbox("Center Line"); center.setState(false); add(center); center.addItemListener(view); first = new Checkbox("1st Focus Line"); first.setState(false); add(first); first.addItemListener(view); second = new Checkbox("2nd Focus Line"); second.setState(false); add(second); second.addItemListener(view); } private class ControlListener implements ItemListener{ public void itemStateChanged(ItemEvent e){ parent.item = lenseType.getSelectedIndex(); parent.init(); setView(); parent.repaint(); } } private void setView(){ boolean a = center.getState(); boolean b = first.getState(); boolean c = second.getState(); parent.setView(a,b,c); } private class ViewListener implements ItemListener{ public void itemStateChanged(ItemEvent e){ setView(); parent.repaint(); } } } class LensCanvas extends Canvas{ public int item; //the item to be show, i.e, converge, or diverge private LensSystem lenseSys; LensCanvas(){ item = 0; setBackground(Color.white); } public void init(){ if(item == 0) lenseSys = new LensSystem(new LensConverge()); else lenseSys = new LensSystem(new LensDiverge()); addMouseListener(lenseSys.getFocusAssigner()); addMouseMotionListener(new LensDragListener()); } public void paint(Graphics g){ lenseSys.paint(g); } public void setView(boolean a, boolean b, boolean c){ lenseSys.setView(a,b,c); } class LensDragListener extends MouseMotionAdapter{ public void mouseDragged(MouseEvent e){ int x = e.getX(); int y = e.getY(); lenseSys.move(x, y); repaint(); } } } class LensConverge extends LensImage{ public LensConverge(){ super(80., 10, 80); } public LensConverge(double f, int w, int h){ super(f, w, h); } public boolean inside(int x, int y){ int dis2 = (x-xx)*(x-xx)/(width*width) + (y-yy)*(y-yy)/(height*height); if(dis2 <= 1) return true; else return false; } public void paint(Graphics g){ g.setColor(Color.black); g.drawLine(20, getY(), 520, getY()); g.setColor(Color.gray); g.fillArc(xx-width, yy-height, 2*width, 2*height, 0, 360); g.setColor(Color.black); g.drawLine((int) (xx-focus), yy-5, (int) (xx-focus), yy+5); g.drawLine((int) (xx+focus), yy-5, (int) (xx+focus), yy+5); } } class LensDiverge extends LensImage{ private double alpha; private int radius; public LensDiverge(){ super(-80., 8, 50); setX(160); setParam(); } public LensDiverge(double f, int w, int h){ super(f,w,h); setParam(); } private void setParam(){ alpha = Math.atan2(height, width); radius = (int) (Math.sqrt(width*width/4. + height*height)/(2.*Math.cos(alpha))); } public boolean inside(int x, int y){ int width = getW(); int height = getH(); int dis2 = (x-xx)*(x-xx)/(width*width) + (y-yy)*(y-yy)/(height*height); if(dis2 <= 1) return true; else return false; } public void paint(Graphics g){ g.setColor(Color.black); g.drawLine(20, getY(), 520, getY()); g.drawLine(xx-width-2, yy-height, xx+width+2, yy-height); g.drawLine(xx-width-2, yy+height, xx+width+2, yy+height); int degree = (int) (2*alpha/Math.PI*180); g.drawArc(xx+width/2, yy-radius, 2*radius, 2*radius, degree, 360-2*degree); g.drawArc(xx-width/2-2*radius, yy-radius, 2*radius, 2*radius, degree-180, 360-2*degree); g.setColor(Color.black); g.drawLine((int) (xx-focus), yy-5, (int) (xx-focus), yy+5); g.drawLine((int) (xx+focus), yy-5, (int) (xx+focus), yy+5); } } class LensArrow{ private int xx, yy; private int width, height = 0; Color color; public LensArrow(Color theColor, int w){ color = theColor; width = w; } public LensArrow(Color theColor, int w, int h){ color = theColor; width = w; height = h; } public int getX(){return xx;} public int getY(){return yy;} public int getHeight(){return height;} public Color getColor(){return color;} public Point getTip(){return new Point(xx, yy-height);} public void setX(int x){xx = x;} public void setY(int y){yy = y;} public void setHeight(int h){height=h; if(width*h<0) width = -width;} public void setLocation(int x, int y){ xx = x; yy = y;} public void setColor(Color colo){color = colo;} public boolean inside(int x, int y){ if( Math.abs(x-xx) > (width/2) || (y-yy)*(y-(yy-height-2*width))>0) return false; else return true; } public void paint(Graphics g){ g.setColor(color); int w = (int) (width/2); int h = (int) (height-Math.sqrt(3)*width); if(height>0) g.fillRect(xx-w, yy-h, width+1, h); else g.fillRect(xx+w, yy, -width+1, -h); paintTriangle(g, xx, yy-h); } private void paintTriangle(Graphics g, int x, int y){ int[] xPoints = new int[3]; int[] yPoints = new int[3]; xPoints[0] = x - width; yPoints[0] = y; xPoints[1] = x + width; yPoints[1] = y; xPoints[2] = x; yPoints[2] = (int) (y - Math.sqrt(3)*width); g.fillPolygon(xPoints, yPoints, 3); } }