|








|
|
 |
|
 |
/*
GoldenTriangle.java
Any portion of this code may be used without permission from BrainyPage.
www.BrainyPage.com | Created by Raul Aguilar | Last Modified 200205152213
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 GoldenTriangle extends JApplet{
private aJFrame f;
public static final int WIDTH = 400;
public static final int HEIGHT = 400;
public void init() {
// Set the arguments.
String[] args = { "3.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("GoldenTriangle");
frame.setSize(WIDTH,HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
class aJFrame extends JFrame {
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);
JPanel p = new JPanel();
p.setLayout(new XYLayout());
p.add(panelSimulate, new XYConstraints(5, 5, 380, 335));
p.add(panelControl, new XYConstraints(5, 345, 380, 90));
cp.add(p,BorderLayout.CENTER);
}
public void redraw() {
panelSimulate.repaint();
}
Simulate panelSimulate;
}
class Simulate extends JPanel {
private double base;
private double a;
private double b;
private String[] args;
int w;
int h;
double w2;
double h2;
double cx;
double cy;
double positiveUnitsX;
double positiveUnitsY;
double transMathToDeviceX;
double transMathToDeviceY;
Point2D convergedCenterP;
Point2D[] p;
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) {
base = Double.parseDouble(args[0]);
System.out.println("parameter values:");
System.out.println();
System.out.println("base = " + base);
}
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 / 3.0;
cy = 2.0 * h / 3.0;
// Set size of positive x-axis.
positiveUnitsX = 4.0;
// Find size of positive y-axis.
positiveUnitsY = positiveUnitsX * h2 / w2;
// 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));
MakeTriangle();
convergedCenterP = convergedCenter(p);
// Adjust center of made triangle.
p[0] = sub(p[0], convergedCenterP);
p[1] = sub(p[1], convergedCenterP);
p[2] = sub(p[2], convergedCenterP);
drawTriangle(g2, p);
// Find the logarithmic spiral a and b.
Point2D xaxis = new Point2D.Double(1.0, 0.0);
double theta0 = angle(xaxis, p[0]);
double theta1 = -1.0 * angle(xaxis, p[1]);
double thetaDegrees0 = Math.toDegrees(theta0);
double thetaDegrees1 = Math.toDegrees(theta1);
double length0 = length(p[0]);
double length1 = length(p[1]);
b = Math.log(length0/length1)/(theta0-theta1);
a = length0 / Math.exp(b * theta0);
Point2D q;
for (int i=0; i<5; ++i) {
p[0] = findNextPoint(p);
q = p[0];
p[0] = p[1];
p[1] = p[2];
p[2] = q;
drawTriangle(g2, p);
}
drawLogSpiral(g2);
}
private Point2D convergedCenter(Point2D[] p) {
// Make a copy of the p points.
Point2D[] pc = (Point2D[]) p.clone();
Point2D q;
// Use twenty iterations to converge on an approximate center.
for (int i=0; i<20; ++i) {
pc[0] = findNextPoint(pc);
q = pc[0];
pc[0] = pc[1];
pc[1] = pc[2];
pc[2] = q;
}
// Select the last point found p[0] to return.
return pc[0];
}
private void MakeTriangle() {
// Consider an osocillies triangle with
// base length of 2 and angles of 72 degrees.
double b2 = base / 2.0;
double t = b2 * Math.tan(Math.toRadians(72));
p = new Point2D[3];
p[0] = new Point2D.Double(b2, t);
p[1] = new Point2D.Double(base, 0.0);
p[2] = new Point2D.Double(0.0, 0.0);
}
private void drawTriangle(
Graphics2D g2,
Point2D[] p) {
g2.setPaint(new Color(255, 92, 0));
g2.draw(new Line2D.Double(userToDevice(p[0]), userToDevice(p[1])));
g2.draw(new Line2D.Double(userToDevice(p[1]), userToDevice(p[2])));
g2.draw(new Line2D.Double(userToDevice(p[2]), userToDevice(p[0])));
}
private Point2D findNextPoint(Point2D[] p) {
// Create vector from bisecting triangle point.
Point2D v01 = unit(vector(p[1], p[0]));
Point2D v21 = unit(vector(p[1], p[2]));
Point2D v = unit(avg(v01, v21));
Point2D s = p[1];
Point2D u = unit(vector(p[2], p[0]));
Point2D r = p[2];
double srx = s.getX() - r.getX();
double sry = s.getY() - r.getY();
double ux = u.getX();
double uy = u.getY();
double vx = v.getX();
double vy = v.getY();
double nextP =
(srx * (-1.0 * vy) - sry * (-1.0 * vx)) /
(ux * (-1.0 * vy) - uy * (-1.0 * vx));
return new Point2D.Double(
r.getX() + u.getX() * nextP,
r.getY() + u.getY() * nextP);
}
private double angle(Point2D p0, Point2D p1) {
// Convert both vectors to unit.
Point2D up0 = unit(p0);
Point2D up1 = unit(p1);
// Get the arc cosine of the dot product.
return Math.acos(up0.getX() * up1.getX() + up0.getY() * up1.getY());
}
private double length(Point2D p) {
double px = p.getX();
double py = p.getY();
return Math.sqrt(px * px + py * py);
}
private Point2D vector(Point2D pFrom, Point2D pTo) {
return new Point2D.Double(pTo.getX() - pFrom.getX(), pTo.getY() - pFrom.getY());
}
private Point2D unit(Point2D p) {
double len = Math.sqrt(p.getX() * p.getX() + p.getY() * p.getY());
return new Point2D.Double(p.getX() / len, p.getY() / len);
}
private Point2D avg(Point2D a, Point2D b) {
return new Point2D.Double((a.getX() + b.getX()) / 2.0, (a.getY() + b.getY()) / 2.0);
}
private Point2D add(Point2D a, Point2D b) {
return new Point2D.Double(a.getX() + b.getX(), a.getY() + b.getY());
}
private Point2D sub(Point2D a, Point2D b) {
return new Point2D.Double(a.getX() - b.getX(), a.getY() - b.getY());
}
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 drawLogSpiral(Graphics2D g2) {
// 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.
double degreeStart = -720;
for (double degree = degreeStart; degree < 90.0; degree += delta) {
// Convert to radian.
double radian = Math.toRadians(degree);
// Find the cosine.
double radius = a * Math.exp(b * radian);
// Polar to cartesian transform of the positive square root.
double px = radius * Math.cos(radian);
double py = radius * Math.sin(radian);
// Quadrant 1.
int x = userToDeviceX(px);
int y = userToDeviceY(py);
if ((degreeStart + 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 Point2D userToDevice(Point2D p) {
double px = (cx + p.getX() * transMathToDeviceX);
double py = (cy - p.getY() * transMathToDeviceY);
return new Point2D.Double(px, py);
}
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));
}
}
|