|








|
|
 |
|
 |
/*
Lemniscate.java
Any portion of this code may be used without permission from BrainyPage.
www.BrainyPage.com | Created by Raul Aguilar | Last Modified 200205032153
Enjoy!
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.math.*;
import java.applet.*;
import com.borland.jbcl.layout.*;
import java.util.*;
public class Lemniscate extends JApplet{
private aJFrame f;
public void init() {
// Set the arguments.
String[] args = { "2.0" };
f = new aJFrame(args, getContentPane());
}
public void paint(Graphics g) {
super.paint(g);
f.redraw();
}
public static void main(String[] args) {
aJFrame frame = new aJFrame(args);
frame.setTitle("Lemniscate");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
class aJFrame extends JFrame {
public static final int SQUARE = 400;
public static final int WIDTH = SQUARE;
public static final int HEIGHT = SQUARE;
public aJFrame(String[] args) {
buildPanels(args, getContentPane());
}
public aJFrame(String[] args, Container cp) {
buildPanels(args, cp);
}
public void buildPanels(String[] args, Container cp) {
panelSimulate = new Simulate(args);
Control panelControl = new Control(args, panelSimulate);
setSize(WIDTH,HEIGHT);
JPanel p = new JPanel();
p.setLayout(new XYLayout());
p.add(panelSimulate, new XYConstraints(5, 5, WIDTH - 20, HEIGHT - 65));
p.add(panelControl, new XYConstraints(5, WIDTH - 55, HEIGHT - 20, 90));
cp.add(p,BorderLayout.CENTER);
}
public void redraw() {
panelSimulate.repaint();
}
Simulate panelSimulate;
}
class Simulate extends JPanel {
private double r;
private String[] args;
int w;
int h;
double w2;
double h2;
double cx;
double cy;
double positiveUnitsX;
double positiveUnitsY;
double degreeToRadian;
double transMathToDeviceX;
double transMathToDeviceY;
public Simulate(String[] args) {
setParameters(args);
//Initialize drawing colors
setBackground(Color.white);
setForeground(Color.black);
}
public void setParameters(String controlValues) {
StringTokenizer st = new StringTokenizer(controlValues);
ArrayList al = new ArrayList();
while (st.hasMoreTokens()) {
al.add((String) st.nextToken());
}
String[] s = (String[]) al.toArray(new String[0]);
setParameters(s);
}
public void setParameters(String[] args) {
r = Double.parseDouble(args[0]);
System.out.println("parameter values:");
System.out.println();
System.out.println("r = " + r);
}
public void fixDimensions() {
// Find the width and height of the JPanel.
Dimension d = getSize();
w = d.width;
h = d.height;
// Calculate the half height.
w2 = w / 2.0;
h2 = h / 2.0;
// Set the graph center at center of graph.
cx = w / 2.0;
cy = h / 2.0;
// Set size of positive x-axis.
positiveUnitsX = 3.5;
// Find size of positive y-axis.
positiveUnitsY = positiveUnitsX * h2 / w2;
// Use to convert degree to radian.
degreeToRadian = Math.PI /180.0;
// In this code version,
// transMathToDeviceX is same value as transMathToDeviceY.
transMathToDeviceX = w2 / positiveUnitsX;
transMathToDeviceY = h2 / positiveUnitsY;
}
public void paint(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
fixDimensions();
drawGrid(g2);
// Set the pen width.
int penWidth = 2;
g2.setStroke(new BasicStroke(penWidth));
drawLemniscate(g2);
drawCircle(g2, r * Math.sqrt(2.0), 0, r);
drawOrginToCircle(g2, 30, r * Math.sqrt(2.0), 0, r);
drawPoint(g2, 0, 0);
drawPoint(g2, r * Math.sqrt(2.0), 0);
}
private void drawGrid(Graphics2D g2) {
// Use physical xy points.
double px;
double py;
double nx;
double ny;
double unitsPerGridLine = .2;
double gridLines = positiveUnitsX/unitsPerGridLine;
for (int i=0; i < 2*gridLines ; ++i) {
px = cx + (i * unitsPerGridLine) * transMathToDeviceX;
py = cy - (i * unitsPerGridLine) * transMathToDeviceY;
// Find the minus x values for grid lines
// on the negative side of the graph.
nx = cx - (i * unitsPerGridLine) * transMathToDeviceX;
ny = cy + (i * unitsPerGridLine) * transMathToDeviceY;
if (i == 0) {
// Draw the xy axis.
g2.setPaint(new Color(255, 0, 255));
}
else {
g2.setPaint(new Color(0, 255, 255));
g2.draw(new Line2D.Double( nx, 0, nx, h));
g2.draw(new Line2D.Double( 0, ny, w, ny));
}
g2.draw(new Line2D.Double( px, 0, px, h));
g2.draw(new Line2D.Double( 0, py, w, py));
}
}
private void drawLemniscate(Graphics2D g2) {
RenderingHints hint = new RenderingHints(null);
hint.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hint);
g2.setStroke(new BasicStroke(1));
// Set pen color.
g2.setPaint(new Color(0, 0, 255));
// Angular change in degree.
double delta = 1.0;
// Previous x and y device values.
int x_prev = 0;
int y_prev = 0;
// Span one quadrant 0 to 90 degree.
// Account for the square root only producing a positive radius.
for (double degree = 0.0; degree < 360.0; degree += delta) {
// Convert to radian.
double radian = degree * degreeToRadian;
// Find the cosine.
double cos = Math.cos(2.0 * radian);
// To avoid the complex plane, use only the positive return values.
if (0.0 <=cos) {
// Find the polar value.
double radius = Math.sqrt(2 * r * r * cos);
// Polar to cartesian transform of the positive square root.
double dx = radius * Math.cos(radian);
double dy = radius * Math.sin(radian);
// Quadrant 1.
int x = userToDeviceX(dx);
int y = userToDeviceY(dy);
if ((delta / 2.0) < degree) {
// Render the normal distribution line.
Point2D startP = new Point2D.Double(x_prev, y_prev);
Point2D endP = new Point2D.Double(x, y);
g2.draw(new Line2D.Double(startP, endP));
}
x_prev = x;
y_prev = y;
}
}
}
private void drawOrginToCircle(
Graphics2D g2,
double angle,
double cx,
double cy,
double r) {
RenderingHints hint = new RenderingHints(null);
hint.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hint);
g2.setStroke(new BasicStroke(1));
/*
In solving for the line to circle points of intersection,
we can easily call,
drawPoint(g2, x, y);
but the challenge remains in computing the other intersect
point.
Instead consider equations,
y = mx + b and
x^2 + y^2 = r2
Since m = tan(angle) and b = 0 substitution leaves,
x = +- r^2 / sqrt(1 + tan(angle))
wherein we can solve for the positive values of y
y = sqrt(r^2 - x^2)
*/
double theta = Math.toRadians(angle);
double m = Math.tan(theta);
double a = 1 + m * m;
double b = -2.0 * Math.sqrt(2) * r;
double c = r * r;
double xLeft = quadratic(-1.0, a, b, c);
double xRight = quadratic(1.0, a, b, c);
// Account for translation.
double xL = xLeft - (Math.sqrt(2) * r);
double xR = xRight - (Math.sqrt(2) * r);
double yLeft = Math.sqrt(r * r - xL * xL);
double yRight = Math.sqrt(r * r - xR * xR);
// Set pen color.
g2.setPaint(new Color(255, 0, 0));
g2.drawLine(
userToDeviceX(r * Math.sqrt(2)),
userToDeviceY(0),
userToDeviceX(xRight),
userToDeviceY(yRight));
g2.drawLine(
userToDeviceX(0),
userToDeviceY(0),
userToDeviceX(xRight),
userToDeviceY(yRight));
drawPoint(g2, xLeft, yLeft);
drawPoint(g2, xRight, yRight);
double rP = r * Math.sqrt(2.0) * Math.sqrt(Math.cos(2.0 * theta));
double xP = rP * Math.cos(theta);
double yP = rP * Math.sin(theta);
drawPoint(g2, xP, yP);
}
private double quadratic(double multi, double a, double b, double c) {
double operand = b * b - 4.0 * a * c;
if (0 < operand) { return (-1.0 * b + multi * Math.sqrt(operand)) / (2.0 * a); }
else { return 0; }
}
private void drawCircle(
Graphics2D g2,
double cx,
double cy,
double r) {
RenderingHints hint = new RenderingHints(null);
hint.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hint);
g2.setStroke(new BasicStroke(1));
// Set pen color.
g2.setPaint(new Color(0, 255, 255));
Ellipse2D circle =
new Ellipse2D.Double(
userToDeviceX(cx - r),
userToDeviceY(cy + r),
2 * r * transMathToDeviceX,
2 * r * transMathToDeviceY);
g2.draw(circle);
}
private void drawPoint(
Graphics2D g2,
double x,
double y) {
// Set pen color.
g2.setPaint(new Color(0, 0, 0));
// Radius in device units (pixels).
double d = 2;
/*
Rectangle2D rect = new Rectangle2D.Double();
rect.setFrameFromDiagonal(
new Point2D.Double(userToDeviceX(x) - d, userToDeviceY(y) - d),
new Point2D.Double(userToDeviceX(x) + d, userToDeviceY(y) + d));
*/
Ellipse2D rect = new Ellipse2D.Double();
rect.setFrameFromDiagonal(
new Point2D.Double(userToDeviceX(x) - d, userToDeviceY(y) - d),
new Point2D.Double(userToDeviceX(x) + d, userToDeviceY(y) + d));
g2.fill(rect);
g2.draw(rect);
}
private int userToDeviceX(double x) {
return (int) (cx + x * transMathToDeviceX);
}
private int userToDeviceY(double y) {
return (int) (cy - y * transMathToDeviceY);
}
}
class Control extends JPanel {
private String[] args;
private JTextField tf;
private Simulate s;
public Control(String[] args, Simulate sp) {
this.args = args;
this.setLayout(new XYLayout());
s = sp;
JButton b = new JButton("Go");
ActionListener bl = new ActionListener() {
public void actionPerformed(ActionEvent event) {
s.setParameters(tf.getText().trim());
s.repaint();
}
};
b.addActionListener(bl);
add(b, new XYConstraints(0, 3, 50, 20));
tf = new JTextField("2.0",5);
add(tf, new XYConstraints(60, 3, 50, 20));
}
}
|