// filename: align.java // M.Lampton UCBSSL 2004 // mlampton@SSL.berkeley.edu // // Download and save this file in any directory. // Name the file: align.java // To compile: javac align.java // To run it: java align import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import javax.swing.*; import javax.swing.event.*; import java.io.*; import java.util.*; import java.text.DecimalFormat; public class align { public static void main(String[] args) { CFrame frame = new CFrame(); frame.setSize(800, 650); frame.setLocation(50, 50); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } class CFrame extends JFrame { int[] data = new int[6]; static final int DEFAULT_MICRONS = 100; private JPanel radio; /// class common is a convenience for addRadioButton() private ButtonGroup group; /// class common is a convenience for addRadioButton() static final int NFIELDS = 4; // coordinate with NSTARS in User static JTextField myFields[] = new JTextField[NFIELDS]; // ..for updateField() static JTextField summary; /// class common is a convenience for updateSummary() public CFrame() // constructor for content frame { setTitle(" SNAP TELESCOPE SECONDARY MIRROR HEXAPOD CONTROLLER"); Container contentPane = getContentPane(); contentPane.setLayout(null); // turn off layout managers! ////////////////////// top zone //////////////////////////////// JLabel t1 = new JLabel("Hexapod"); t1.setBounds(50, 100, 100, 15); contentPane.add(t1); JLabel t2 = new JLabel("strut"); t2.setBounds(50, 115, 100, 15); contentPane.add(t2); JLabel t3 = new JLabel("settings"); t3.setBounds(50, 130, 100, 15); contentPane.add(t3); JLabel t4 = new JLabel("microns"); t4.setBounds(50, 145, 100, 15); contentPane.add(t4); for (int i=0; i<6; i++) { final JSlider slider // final for inner class below = new JSlider(JSlider.VERTICAL, -80, 80, 0); slider.setMajorTickSpacing(40); slider.setMinorTickSpacing(20); slider.setPaintTicks(true); slider.setPaintLabels(true); slider.setSize(60,120); slider.setBounds(120+80*i, 40, 50, 200); contentPane.add(slider); final JLabel myLabel // final for inner class below = new JLabel(""+slider.getValue()); data[i] = slider.getValue(); myLabel.setBounds(130+80*i,20, 50, 20); contentPane.add(myLabel); final int ifinal = i; // final for inner class below slider.addChangeListener(new ChangeListener( ) { public void stateChanged(ChangeEvent e) { myLabel.setText(""+slider.getValue( )); data[ifinal] = slider.getValue(); } }); } JButton myButton = new JButton("UPLINK"); myButton.setActionCommand("EXECUTE"); myButton.setSize(myButton.getPreferredSize()); myButton.setBackground(Color.BLUE); myButton.setForeground(Color.WHITE); myButton.setBounds(650, 100, 90, 30); contentPane.add(myButton); JPanel buttonPanel = new JPanel(); buttonPanel.setBounds(640, 90, 110, 50); buttonPanel.setBackground(Color.YELLOW); contentPane.add(buttonPanel); //////////////// mid zone: announcement display ////////// final JTextArea myText // final for inner class below = new JTextArea(4, 36); // 5 rows of 36 columns myText.setEditable(false); JScrollPane sp = new JScrollPane(myText); sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); sp.setBounds(30, 270, 400, 90); contentPane.add(sp); /////////////// graphics displays /////////// radio = new JPanel(); JLabel choose = new JLabel("Choose span of display fields: "); radio.add(choose); group = new ButtonGroup(); addRadioButton("500um", 500); addRadioButton("200um", 200); addRadioButton("100um", 100); addRadioButton("50um", 50); radio.setBounds(50, 365, 600, 25); contentPane.add(radio); PPanel[] mypanels = new PPanel[NFIELDS]; // names only for (int i=0; i X surfs[j][OE12] = cr*sp*st + sr*ct; // x <-> Y surfs[j][OE13] = -cr*sp*ct + sr*st; // x <-> Z surfs[j][OE21] = -sr*cp; // y <-> X surfs[j][OE22] = cr*ct - sr*sp*st; // y <-> Y surfs[j][OE23] = sr*sp*ct + cr*st; // y <-> Z surfs[j][OE31] = sp; // z <-> X surfs[j][OE32] = -cp*st; // z <-> Y surfs[j][OE33] = cp*ct; // z <-> Z } } ///////////// optical utilities ///////////////////////////// static int intercept(double ray[], double surf[]) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 { if (sqr(surf[OCURVE]) < TOL) return planesolve(ray, surf); return quadsolve(ray, surf); } static int redirect(double ray[], double surf[], double tnext) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 { if (surf[OTYPE]==OTIRIS) // iris return iris(ray, surf); boolean groovy = sqr(surf[OGX]) + sqr(surf[OGY]) > TINY; if (surf[OTYPE]==OTMIRROR) // mirror if (groovy) return rgrating(ray, surf); else return mirror(ray, surf); if (groovy) // lens return tgrating(ray, surf, tnext); else return snell(ray, surf, tnext); } static int rgrating(double ray[], double surf[]) { return OFAIL; } static int tgrating(double ray[], double surf[], double t) { return OFAIL; } static int snell(double ray[], double surf[], double t) { return OFAIL; } static int planesolve(double ray[], double surf[]) // if valid plane intercept, ray[] gets updated, return OK // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 // NEEDED: diameter check { double d; if (Math.abs(ray[RZ]) < TOL) return OK; if (Math.abs(ray[RW]) < TOL) return PROPMISS; d = -ray[RZ] / ray[RW]; if (d < 0.0) return PROPBACK; ray[RX] += d * ray[RU]; ray[RY] += d * ray[RV]; ray[RZ] += d * ray[RW]; return OK; } static int quadsolve(double ray[], double surf[]) // if valid quadratic surface intercept, ray[] updated, return OK // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 // NEEDED: diameter testing { double a, b, c, k, s, g; double rx, ry, rz, ru, rv, rw; if (sqr(surf[OCURVE]) < TOL) System.out.println("ERROR: Quadsolve was called for a plane intercept!"); // shorthand variables... k = surf[OCURVE]; // curvature s = surf[OASPHER]+1.0; // shape g = 1.0; // X-stretch is unused rx = ray[RX]; ry = ray[RY]; rz = ray[RZ]; ru = ray[RU]; rv = ray[RV]; rw = ray[RW]; a = k * (sqr(g*ru) + sqr(rv) + s*sqr(rw)); b = 2.0 * k * (g*g*rx*ru + ry*rv + s*rz*rw) - 2.0*rw; c = k * (sqr(g*rx) + sqr(ry) + s*sqr(rz)) - 2.0*rz; double[] d = new double[2]; int nposroots = getposroots(a, b, c, d); if (DEBUG) System.out.println("getposroots() returns nroots = "+fwi(nposroots,3)); switch (nposroots) { case 0: return PROPFAIL; case 1: // here I need to test iris() before agreeing ray[RX] += d[0] * ray[RU]; ray[RY] += d[0] * ray[RV]; ray[RZ] += d[0] * ray[RW]; return OK; case 2: // choose root nearer vertex double azvx0 = Math.abs(ray[RZ] + d[0]*ray[RW]); double azvx1 = Math.abs(ray[RZ] + d[1]*ray[RW]); double dd = (azvx0 < azvx1) ? d[0] : d[1]; ray[RX] += dd * ray[RU]; ray[RY] += dd * ray[RV]; ray[RZ] += dd * ray[RW]; return OK; } return PROPFAIL; } static int iris(double ray[], double surf[]) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 /// ..a better way is to avoid ratios, and always compare differences: /// diff[i] = ray - iris; { boolean square = (surf[OFORM] == OFRECT); // do the inner edge if ((surf[OIDIAX] > TINY) && (surf[OIDIAY] > TINY)) { if (square && (max(sqr((ray[RX])/surf[OIDIAX]), sqr((ray[RY])/surf[OIDIAY])) < 0.25)) return IRISINNER; if ((!square) && (sqr((ray[RX])/surf[OIDIAX]) + sqr((ray[RY])/surf[OIDIAY]) < 0.25)) return IRISINNER; } // do the outer edge if ((surf[OODIAX] > TINY) && (surf[OODIAY] > TINY)) { if (square && (max(sqr((ray[RX])/surf[OODIAX]), sqr((ray[RY])/surf[OODIAY])) > 0.25)) return IRISOUTER; if (!square && (sqr((ray[RX])/surf[OODIAX]) + sqr((ray[RY])/surf[OODIAY]) > 0.25)) return IRISOUTER; } return OK; } static int mirror(double ray[], double surf[]) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 // method: r = i - 2 (i dot n) n // note this is quadratic in n, hence independent of its sign { double[] norm = new double[6]; getnormal(ray, surf, norm); double dotin = ray[RU]*norm[RU] + ray[RV]*norm[RV] + ray[RW]*norm[RW]; ray[RU] -= 2.0 * dotin * norm[RU]; ray[RV] -= 2.0 * dotin * norm[RV]; ray[RW] -= 2.0 * dotin * norm[RW]; normalize(ray); // should be unnecessary! return OK; } static void getnormal(double ray[], double surf[], double normal[]) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 { /// analytic method: Spencer & Murty eq. 18, conics only /// first, verify that func() returns approx zero: double derr = getfunc(ray, surf); if (DEBUG) System.out.println("Getnormal sees fn_val="+fwe(derr)); // now get analytic gradient double r2 = sqr(ray[RX]) + sqr(ray[RY]); double arg = 1.0 - (surf[OASPHER]+1.0)*sqr(surf[OCURVE])*r2; if (arg > 0.0) // valid surface... { double coef = surf[OCURVE]/Math.sqrt(arg); normal[RU] = -ray[RX]*coef; normal[RV] = -ray[RY]*coef; normal[RW] = 1.0; normalize(normal); } else // return flange normal... { normal[RU] = 0.0; normal[RV] = 0.0; normal[RW] = 1.0; }; if (DEBUG) // compare with finite difference method { double delta = DELTA / max(1.0, Math.abs(surf[OCURVE])); double[] fdnorm = new double[6]; double[] rayp = new double[6]; double[] raym = new double[6]; for (int i=0; i<6; i++) rayp[i] = raym[i] = ray[i]; rayp[RX] += delta; raym[RX] -= delta; double fxp = getfunc(rayp, surf); double fxm = getfunc(raym, surf); rayp[RX] = raym[RX] = ray[RX]; rayp[RY] += delta; raym[RY] -= delta; double fyp = getfunc(rayp, surf); double fym = getfunc(raym, surf); rayp[RY] = raym[RY] = ray[RY]; rayp[RZ] += delta; raym[RZ] -= delta; double fzp = getfunc(rayp, surf); double fzm = getfunc(raym, surf); fdnorm[RU] = fxp-fxm; fdnorm[RV] = fyp-fym; fdnorm[RW] = fzp-fzm; normalize(fdnorm); double fderr = Math.sqrt(sqr(normal[RU]-fdnorm[RU]) + sqr(normal[RV]-fdnorm[RV]) + sqr(normal[RW]-fdnorm[RW])); System.out.println("Getnormal gets fd_err="+fwe(fderr)); } } static double getfunc(double ray[], double surf[]) // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 // returns z-zsurf(x,y) for flanged quadratic. // ray[] lies on surface if getfunc()==0. { double r2 = sqr(ray[RX]) + sqr(ray[RY]); double num = surf[OCURVE] * r2; double arg = 1.0 - (surf[OASPHER]+1.0)*sqr(surf[OCURVE])*r2; arg = max(arg, 0.0); double denom = 1.0 + Math.sqrt(arg); double zsurf = num/denom; return ray[RZ] - zsurf; } static void normalize(double norm[]) { double r2 = sqr(norm[RU]) + sqr(norm[RV]) + sqr(norm[RW]); if (r2 > TINY) { double r = Math.sqrt(r2); norm[RU] /= r; norm[RV] /= r; norm[RW] /= r; return; } norm[RU] = 0.0; norm[RV] = 0.0; norm[RW] = 1.0; System.out.println("ERROR: Normalize has substituted default unit vector"); } static void posWnormalize(double ray[]) { double w2 = 1.0 - sqr(ray[RU]) - sqr(ray[RV]); if (w2 >= 0.0) { ray[RW] = Math.sqrt(w2); return; } normalize(ray); System.out.println("ERROR: posWnormalize has had to call normalize"); } static void negWnormalize(double[] ray) { double w2 = 1.0 - sqr(ray[RU]) - sqr(ray[RV]); if (w2 >= 0.0) { ray[RW] = -Math.sqrt(w2); return; } normalize(ray); System.out.println("ERROR: negWnormalize has had to call normalize"); } ///////////////////// math utilities //////////////////// static double sqr(double x) { return x*x; } static double max(double a, double b) { if (a>b) return a; return b; } static double min(double a, double b) { if (a w) { s = ""; for (int i=0; i0.0) return Math.log(arg)/LN10; return -999.9; } static double dex(double arg) { if (arg > 300.0) arg = 300.0; if (arg < -300.0) arg = -300.0; return Math.pow(10.0, arg); } static boolean isodd(int i) { return (i % 2) == 1; } static void beep() { char c = 7; String s = ""+c; System.out.print(s); } static int getposroots(double a, double b, double c, double d[]) // Returns 0, 1,or 2 positive real roots of ax2+bx+c // Method derives from Press et al "Numerical Recipes" 5.5.5 // M.Lampton STELLAR SOFTWARE (C) 1989, 2003 { double discrim, q, r1, r2; d[0] = d[1] = -999.0; // errorcode if (Math.abs(a) < TOL) // LINEAR FUNCTION if (Math.abs(b) > TOL) // one root if (-c/b >= 0.0) // nonnegative? { d[0] = d[1] = -c/b; if (DEBUG) System.out.println("Posroots exit 1,"+nd(1,d)); return 1; // one positive root } else { if (DEBUG) System.out.println("Posroots exit 2, one neg root"); return 0; // one nonpositive root } else { if (DEBUG) System.out.println("Posroots exit 3, no roots"); return 0; // no roots }; if (Math.abs(c) < TOL) // LINEAR FUNCTION if (-b/a >= 0.0) // nonnegative? { d[0] = d[1] = -b/a; if (DEBUG) System.out.println("Posroots exit 4,"+nd(1,d)); return 1; // one positive root } else { if (DEBUG) System.out.println("Posroots exit 5, one neg root"); return 0; // one nonpositive root }; discrim = b*b-4.0*a*c; // QUADRATIC FUNCTION if (discrim < -TOL) // no real roots { if (DEBUG) System.out.println("Posroots exit 6, no real roots"); return 0; } if (discrim < TOL) // degenerate pair at -b/2a if (-0.5*b/a > TOL) { d[0]=d[1]= -0.5*b/a; // return positive pair as one if (DEBUG) System.out.println("Posroots exit 7,"+nd(1,d)); return 1; } else { if (DEBUG) System.out.println("Posroots exit 8, neg pair"); return 0; // nonpositive pair }; if (b > 0.0) // two distinct roots q = -0.5*(b+Math.sqrt(discrim)); else q = -0.5*(b-Math.sqrt(discrim)); r1 = min(c/q, q/a); r2 = max(c/q, q/a); if (r1 >= 0.0) // is the smaller positive? { d[0] = r1; d[1] = r2; if (DEBUG) System.out.println("Posroots exit 9,"+nd(2,d)); return 2; } if (r2 > TOL) // is the larger positive? { d[0] = d[1] = r2; if (DEBUG) System.out.println("Posroots exit 10,"+nd(1,d)); return 1; } if (DEBUG) System.out.println("Posroots exit 11, two neg roots"); return 0; // neither is positive } }