//Conics.java //ellipses etc import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import java.text.*; public class Conics extends JApplet implements ActionListener, ItemListener { JLabel aLabel, bLabel, hLabel, kLabel, alphaLabel, cLabel, eLabel; JTextField aTextField, bTextField, hTextField, kTextField, alphaTextField, cTextField, eTextField; JPanel controlPanel; JButton zoomInButton, zoomOutButton; JRadioButton ellipseRadioButton, parabolaRadioButton, hyperbolaRadioButton; ButtonGroup conicButtonGroup; int conicChoice; //1=ellipse, 2=parabola, 3=hyperbola double a, b, h, k, alpha, c, e, scale; DecimalFormat d2; public void init() { d2 = new DecimalFormat ("0.00"); Container container = getContentPane(); container.setLayout( new BorderLayout() ); controlPanel = new JPanel(); controlPanel.setLayout(new FlowLayout()); controlPanel.setBackground(Color.LIGHT_GRAY); controlPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); container.add(controlPanel,BorderLayout.NORTH); conicChoice = 1; //start with ellipse ellipseRadioButton = new JRadioButton( "Ellipse" , true); ellipseRadioButton.setBackground(Color.RED); controlPanel.add( ellipseRadioButton ); ellipseRadioButton.addItemListener( this ); parabolaRadioButton = new JRadioButton( "Parabola" ); controlPanel.add( parabolaRadioButton ); parabolaRadioButton.addItemListener( this ); hyperbolaRadioButton = new JRadioButton( "Hyperbola" ); controlPanel.add( hyperbolaRadioButton ); hyperbolaRadioButton.addItemListener( this ); conicButtonGroup = new ButtonGroup(); conicButtonGroup.add(ellipseRadioButton); conicButtonGroup.add(parabolaRadioButton); conicButtonGroup.add(hyperbolaRadioButton); aLabel = new JLabel( "Semi-major a" ); controlPanel.add( aLabel ); aTextField = new JTextField("2",4); a = Double.parseDouble(aTextField.getText()); aTextField.setBackground(Color.CYAN); aTextField.addActionListener( this ); controlPanel.add( aTextField ); bLabel = new JLabel( "\u2265 Semi-minor b" ); controlPanel.add( bLabel ); bTextField = new JTextField("1",4); b = Double.parseDouble(bTextField.getText()); bTextField.setBackground(Color.MAGENTA); bTextField.addActionListener( this ); controlPanel.add( bTextField ); hLabel = new JLabel( " (h" ); controlPanel.add( hLabel ); hTextField = new JTextField("0",3); h = Double.parseDouble(hTextField.getText()); //hTextField.setBackground(Color.MAGENTA); hTextField.addActionListener( this ); controlPanel.add( hTextField ); kLabel = new JLabel( ",k" ); controlPanel.add( kLabel ); kTextField = new JTextField("0",3); k = Double.parseDouble(kTextField.getText()); //kTextField.setBackground(Color.MAGENTA); kTextField.addActionListener( this ); controlPanel.add( kTextField ); alphaLabel = new JLabel( ") \u03B1\u00B0" ); controlPanel.add( alphaLabel ); alphaTextField = new JTextField("0",3); alpha = Math.toRadians(Double.parseDouble(alphaTextField.getText())); alphaTextField.setHorizontalAlignment(JTextField.RIGHT); alphaTextField.addActionListener( this ); controlPanel.add( alphaTextField ); cLabel = new JLabel( " c" ); controlPanel.add( cLabel ); c = Math.sqrt(a*a-b*b); cTextField = new JTextField(""+c,5); cTextField.setEditable(false); cTextField.setBackground(Color.YELLOW); cTextField.addActionListener( this ); controlPanel.add( cTextField ); eLabel = new JLabel( " e" ); controlPanel.add( eLabel ); e = c / a; eTextField = new JTextField(""+e,5); eTextField.setEditable(false); //eTextField.setBackground(Color.GRAY); eTextField.addActionListener( this ); controlPanel.add( eTextField ); zoomInButton = new JButton( "Zoom IN" ); controlPanel.add( zoomInButton ); zoomInButton.addActionListener( this ); zoomOutButton = new JButton( "Zoom OUT" ); controlPanel.add( zoomOutButton ); zoomOutButton.addActionListener( this ); scale = getHeight()/5; //incantation that responds to mouse click events: addMouseListener( //anonymous inner class overrides mouseClicked. //creates a $1 class file which must be uploaded to web site new MouseAdapter() { public void mouseClicked( MouseEvent event) { int mouseX = event.getX(); //gets X coord of mouse click event int mouseY = event.getY(); repaint(); //will invoke paint } } ); } public void paint (Graphics g) { super.paint(g); //clears entire screen g.setFont( new Font( "SansSerif", Font.BOLD, 12 ) ); int width = getWidth(); int height = getHeight(); int xcenter=width/2, ycenter=height/2; int px, py; double x, xCopy, y, angle; //radians double cosAlpha=Math.cos(alpha); double sinAlpha=Math.sin(alpha); //g.setColor(Color.BLACK); //**************************************************** if (conicChoice == 1) { //if (a > c || e<1) { //ELLIPSE //coordinate grid movable g.setColor(Color.GRAY); g.drawLine(0,ycenter+(int)(k*scale), width,ycenter+(int)(k*scale)); //X g.drawLine(xcenter-(int)(h*scale),50, xcenter-(int)(h*scale),height); //Y g.setFont( new Font( "SansSerif", Font.ITALIC|Font.BOLD, 12 ) ); g.drawString("O",xcenter-(int)(h*scale),ycenter+(int)(k*scale)); g.setFont( new Font( "SansSerif", Font.BOLD, 12 ) ); g.setColor(Color.BLACK); for (int i=0; i<720; i++) { //ellipse always in center of screen angle = i * 2 * Math.PI / 720; x = a * Math.cos(angle); xCopy = x; y = b * Math.sin(angle); // x = x*cosAlpha + y*sinAlpha; //rotation about origin // y = -xCopy*sinAlpha + y*cosAlpha; x = rotateX(x,y,alpha); y = rotateY(xCopy,y,alpha); px = (int) (x * scale) + xcenter; py = (int) (y * scale) + ycenter; g.drawLine(px,py, px,py); } /* int aInt, bInt, cInt; aInt = (int)(a * scale); bInt = (int)(b * scale); */ double v1x, v1y, v2x, v2y; double f1x, f1y, f2x, f2y; double d2len, latusRectum=0, directrix=0; /* if (a < b) { //swap a and b ?? double temp = a; a = b; b = temp; } */ // if (a >= b) { //horizontal major axis c = Math.sqrt(a*a-b*b); //cInt = (int)(c * scale); if (a != b) { //not a cirlce latusRectum = 2*b*b / a; g.setColor(Color.GREEN); /*g.drawLine(xcenter-cInt,ycenter-(int)(latusRectum/2*scale), xcenter-cInt,ycenter+(int)(latusRectum/2*scale)); g.drawLine(xcenter+cInt,ycenter-(int)(latusRectum/2*scale), xcenter+cInt,ycenter+(int)(latusRectum/2*scale)); */ g.drawLine((int)(rotateX(-c,-latusRectum/2,alpha)*scale)+xcenter,(int)(rotateY(-c,-latusRectum/2,alpha)*scale)+ycenter, (int)(rotateX(-c,latusRectum/2,alpha)*scale)+xcenter,(int)(rotateY(-c,latusRectum/2,alpha)*scale)+ycenter); g.drawLine((int)(rotateX(c,-latusRectum/2,alpha)*scale)+xcenter,(int)(rotateY(c,-latusRectum/2,alpha)*scale)+ycenter, (int)(rotateX(c,latusRectum/2,alpha)*scale)+xcenter,(int)(rotateY(c,latusRectum/2,alpha)*scale)+ycenter); } g.setColor(Color.CYAN); //xcenter+aInt,ycenter g.drawLine(xcenter,ycenter, (int)(rotateX(a,0,alpha)*scale)+xcenter, (int)(rotateY(a,0,alpha)*scale)+ycenter); //a=semi-major axis g.setColor(Color.MAGENTA); //xcenter,ycenter-bInt g.drawLine(xcenter,ycenter, (int)(rotateX(0,-b,alpha)*scale)+xcenter, (int)(rotateY(0,-b,alpha)*scale)+ycenter); //b=semi-minor axis g.setColor(Color.YELLOW); //xcenter-cInt,ycenter g.drawLine(xcenter,ycenter, (int)(rotateX(-c,0,alpha)*scale)+xcenter, (int)(rotateY(-c,0,alpha)*scale)+ycenter); //c= e = c / a; d2len = 2*a; v1x = a; //assume is flat, and at origin double vlxCopy = v1x; v1y = 0; v1x = rotateXback(v1x,v1y,alpha); //rotate first v1y = rotateYback(vlxCopy,v1y,alpha); v1x += h; //then translate? to new origin v1y += k; v2x = -a; double v2xCopy = v2x; v2y = 0; v2x = rotateXback(v2x,v2y,alpha); v2y = rotateYback(v2xCopy,v2y,alpha); v2x += h; //now translate? v2y += k; f1x = c; double flxCopy = f1x; f1y = 0; f1x = rotateXback(f1x,f1y,alpha); f1y = rotateYback(flxCopy,f1y,alpha); f1x += h; //then translate? to new origin f1y += k; f2x = -c; double f2xCopy = f2x; f2y = 0; f2x = rotateXback(f2x,f2y,alpha); f2y = rotateYback(f2xCopy,f2y,alpha); f2x += h; //then translate? to new origin f2y += k; if (a != b) { //not a circle directrix = a / e; g.setColor(Color.PINK); g.drawLine(xcenter+(int)(rotateX(directrix,-height,alpha)*scale),(int)(rotateY(directrix,-height,alpha)*scale)+ycenter, xcenter+(int)(rotateX(directrix,height,alpha)*scale),(int)(rotateY(directrix,height,alpha)*scale)+ycenter); g.drawLine(xcenter+(int)(rotateX(-directrix,-height,alpha)*scale),(int)(rotateY(-directrix,-height,alpha)*scale)+ycenter, xcenter+(int)(rotateX(-directrix,height,alpha)*scale),(int)(rotateY(-directrix,height,alpha)*scale)+ycenter); } //foci g.setColor(Color.RED); g.fillRect((int)(rotateX(c,0,alpha)*scale)+xcenter, (int)(rotateY(c,0,alpha)*scale)+ycenter, 2,2); g.fillRect((int)(rotateX(-c,0,alpha)*scale)+xcenter, (int)(rotateY(-c,0,alpha)*scale)+ycenter, 2,2); g.setColor(Color.BLUE); //vertexes //g.fillRect(xcenter-(int)(h*scale)+(int)(v1x*scale), ycenter-(int)(k*scale)+(int)(v1y*scale), 2,2); //g.fillRect(xcenter-(int)(h*scale)+(int)(v2x*scale), ycenter-(int)(k*scale)+(int)(v2y*scale), 2,2); g.fillRect(xcenter+(int)(rotateX(a,0,alpha)*scale), ycenter+(int)(rotateY(a,0,alpha)*scale), 2,2); g.fillRect(xcenter+(int)(rotateX(-a,0,alpha)*scale), ycenter+(int)(rotateY(-a,0,alpha)*scale), 2,2); /* } else { //vertical major axis. NEW: rotation subsumes 2 special cases of axis alignment c = Math.sqrt(b*b-a*a); cInt = (int)(c * scale); if (a != b) { //not a cirlce latusRectum = 2*a*a / b; g.setColor(Color.GREEN); g.drawLine(xcenter-(int)(latusRectum/2*scale),ycenter-cInt ,xcenter+(int)(latusRectum/2*scale),ycenter-cInt); g.drawLine(xcenter-(int)(latusRectum/2*scale),ycenter+cInt ,xcenter+(int)(latusRectum/2*scale),ycenter+cInt); } g.setColor(Color.CYAN); g.drawLine(xcenter,ycenter, xcenter+aInt,ycenter); //b=semi-major axis g.setColor(Color.MAGENTA); g.drawLine(xcenter,ycenter, xcenter,ycenter+bInt); //a=semi-minor axis g.setColor(Color.YELLOW); g.drawLine(xcenter,ycenter, xcenter,ycenter-cInt); //c= //g.drawLine(xcenter, ycenter+cInt, xcenter+1, ycenter+cInt); //g.drawLine(xcenter, ycenter-cInt, xcenter+1, ycenter-cInt); e = c / b; d2len = 2*b; v1x = h; v1y = b+k; v2x = h; v2y = -b+k; f1x = h; f1y = c+k; f2x = h; f2y = -c+k; if (a != b) { //not a cirlce directrix = b / e; //distance from center g.setColor(Color.PINK); g.drawLine(0,ycenter-(int)(directrix*scale) ,width,ycenter-(int)(directrix*scale)); g.drawLine(0,ycenter+(int)(directrix*scale) ,width,ycenter+(int)(directrix*scale)); } //foci g.setColor(Color.RED); g.fillRect(xcenter, ycenter+cInt, 2,2); g.fillRect(xcenter, ycenter-cInt, 2,2); } */ /* g.setColor(Color.BLUE); //vertexes g.fillRect(xcenter-(int)(h*scale)+(int)(v1x*scale), ycenter-(int)(k*scale)+(int)(v1y*scale), 2,2); g.fillRect(xcenter-(int)(h*scale)+(int)(v2x*scale), ycenter-(int)(k*scale)+(int)(v2y*scale), 2,2); */ //g.fillRect(xcenter+(int)(v1x*scale), ycenter+(int)(v1y*scale), 2,2); //g.fillRect(xcenter+(int)(v2x*scale), ycenter+(int)(v2y*scale), 2,2); double area = Math.PI*a*b; double perimeter; if (a == b) //circle perimeter = 2 * Math.PI * a; else perimeter = Math.PI * (3*(a+b) - Math.sqrt((3*a+b)*(a+3*b))); //approx. Ramanujan g.setColor(Color.BLACK); g.drawString("area="+d2.format(area), width-200,52); if (a == b) //circle g.drawString("CIRCLE", width-100,52); g.drawString("perimeter\u2248"+d2.format(perimeter), width-200,62); g.setColor(Color.GRAY); if (a >= b) { //horizontal major axis g.drawString("c=\u221A(a\u00B2-b\u00B2) e=c/a", width-200,72); } else { g.drawString("c=\u221A(b\u00B2-a\u00B2) e=c/b", width-200,72); } g.setColor(Color.RED); g.drawString("focus 1: ("+d2.format(f1x)+","+d2.format(f1y)+ ") 2: ("+d2.format(f2x)+","+d2.format(f2y)+")",width-200,82); g.setColor(Color.BLUE); g.drawString("vertex 1:("+d2.format(v1x)+","+d2.format(v1y)+") 2:("+ d2.format(v2x)+","+d2.format(v2y)+")",width-200,92); g.setColor(Color.BLACK); g.drawString("sum of focal radii= "+d2len,width-200,102); if (a != b) { //not a circle g.setColor(Color.GREEN); g.drawString("latus rectum= "+d2.format(latusRectum),width-200,112); g.setColor(Color.GRAY); if (a >= b) g.drawString(" 2b\u00B2/a", width-80,112); else g.drawString(" 2a\u00B2/b", width-80,112); g.setColor(Color.PINK); g.drawString("focus to directrix: "+d2.format(directrix-c),width-200,122); /* if (a >= b) g.drawString("directrix: x="+d2.format(directrix+h)+" x=-"+d2.format(directrix-h),width-200,122); else g.drawString("directrix: y="+d2.format(directrix+k)+" y=-"+d2.format(directrix-k),width-200,122); */ } g.setColor(Color.GRAY); g.drawString("(x-h)\u00B2/a\u00B2 + (y-k)\u00B2/b\u00B2 = 1",width-250,132); g.setColor(Color.BLACK); g.drawString((h==0?"x":((h<0?("(x+"+(-h)):("(x-"+h)))+")") +"\u00B2/"+d2.format(a*a)+ "+ "+ (k==0?"y":((k<0?("(y+"+(-k)):("(y-"+k)))+")") +"\u00B2/"+d2.format(b*b)+" = 1",width-250,142); g.setColor(Color.GRAY); g.drawString("Ax\u00B2 + By\u00B2 + Cx + Dy + E = 0",width-250,162); double A, B, C, D, E; A = b*b; //need to switch ?? B = a*a; C = -2*h*b*b; D = -2*k*a*a; E = b*b*h*h+a*a*k*k-a*a*b*b; g.setColor(Color.BLACK); g.drawString(""+d2.format(A)+"x\u00B2 + "+d2.format(B)+"y\u00B2 "+(h==0?"":" + "+d2.format(C)+"x")+ (k==0?"":" + "+d2.format(D)+"y") +" + "+d2.format(E) +" = 0", width-250,172); } //********************************************************* else if (conicChoice == 2) { //else if (a == c || e==1) { //PARABOLA e = 1; double t; for (int i=-100; i<100; i++) { t = i; px = (int) (a * t*t * scale) + xcenter; py = (int) (2 * a * t * scale) + ycenter; g.drawLine(px,py, px,py); } } cTextField.setText(""+c); cTextField.setCaretPosition(0); eTextField.setText(""+e); eTextField.setCaretPosition(0); } // respond to textfield events public void actionPerformed( ActionEvent event ) { try { double aTry = Double.parseDouble(aTextField.getText()); double bTry = Double.parseDouble(bTextField.getText()); double hTry = Double.parseDouble(hTextField.getText()); double kTry = Double.parseDouble(kTextField.getText()); double alphaTry = Double.parseDouble(alphaTextField.getText()); //double cTry = Double.parseDouble(cTextField.getText()); if (aTry<0 || bTry<0) { JOptionPane.showMessageDialog(null, "a and b must be >= 0", "TriangleApplet: Invalid point input", JOptionPane.ERROR_MESSAGE); return; } if (aTrya) { JOptionPane.showMessageDialog(null, "a, the semimajor axis, must be >= b, the semiminor axis", "TriangleApplet: Invalid point input", JOptionPane.ERROR_MESSAGE); return; } if (alphaTry<0 || alphaTry>180) { JOptionPane.showMessageDialog(null, "angle \u03B1 must be between 0\u00B0 and 180\u00B0", "TriangleApplet: Invalid point input", JOptionPane.ERROR_MESSAGE); return; } } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "all values must be numbers", "Conics: Invalid input", JOptionPane.ERROR_MESSAGE); return; } if ( event.getSource()==aTextField || event.getSource()==bTextField || event.getSource()==hTextField || event.getSource()==kTextField || event.getSource()==alphaTextField) { a = Double.parseDouble(aTextField.getText()); b = Double.parseDouble(bTextField.getText()); h = Double.parseDouble(hTextField.getText()); k = Double.parseDouble(kTextField.getText()); alpha = Math.toRadians(Double.parseDouble(alphaTextField.getText())); repaint(); } /*else if ( event.getSource() == cTextField ) { //c = Double.parseDouble(cTextField.getText()); repaint(); } else if ( event.getSource() == eTextField ) { //e = Double.parseDouble(eTextField.getText()); repaint(); } */ else if ( event.getSource() == zoomInButton ) { scale += scale/10; //grow 10% a = Double.parseDouble(aTextField.getText()); b = Double.parseDouble(bTextField.getText()); repaint(); } else if ( event.getSource() == zoomOutButton ) { scale -= scale/10; //shrink 10% a = Double.parseDouble(aTextField.getText()); b = Double.parseDouble(bTextField.getText()); repaint(); } } public void itemStateChanged( ItemEvent event ) { if ( event.getSource() == ellipseRadioButton ) { if ( ellipseRadioButton.isSelected() ) { conicChoice = 1; //ellipse repaint(); } } else if ( event.getSource() == parabolaRadioButton ) { if ( parabolaRadioButton.isSelected() ) { conicChoice = 2; //parabola repaint(); } } else if ( event.getSource() == hyperbolaRadioButton ) { if ( hyperbolaRadioButton.isSelected() ) { conicChoice = 3; //hyperbola repaint(); } } } public double rotateX(double x, double y, double alpha) { //transform x ccord by alpha radians return x*Math.cos(alpha) + y*Math.sin(alpha); } public double rotateY(double x, double y, double alpha) { //transform y ccord by alpha radians return -x*Math.sin(alpha) + y*Math.cos(alpha); } public double rotateXback(double x, double y, double alpha) { //transform x ccord by alpha radians return x*Math.cos(alpha) - y*Math.sin(alpha); } public double rotateYback(double x, double y, double alpha) { //transform y ccord by alpha radians return x*Math.sin(alpha) + y*Math.cos(alpha); }}