paintComponent() output error - java

i'm trying to make a program that will connect two points that i click in my JPanel. i'm trying to connect the two points with a line. i displayed the values of my (x1, y1) and (x2,y2) coordinates whenever i click using the mouse and there is no error in the values. but when the line is displayed, it the line doesn't seem to follow the coordinates i specify but instead outputs in a different location and is distorted. most of the lines will appear to be cut by something, i think it's the rectangle created by the line because i used setBounds(). also, i add a System.out.println("") inside my paintComponent function and i noticed that it printed multiple times (increasing by 1 after every click) even though it should only print once. can anyone help me with this? thanks!
here are two of the classes which contribute to the error:
CLASS # 1:
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Arch. Don Saborrido
*/
public class twixtBoard extends JPanel implements java.awt.event.MouseListener{
int x1 = 0, x2, y1 = 0, y2;
DrawLine line;
//DrawLine line;
public twixtBoard(){
//requestFocus();
setLayout(null);
setVisible(false);
setBounds(0,0,600,450);
setOpaque(false);
setFocusable(false);
addListener();
}
public void addListener(){
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
if (x1 == 0 || y1 == 0){
x1 = e.getX();
y1 = e.getY();
System.out.println(x1 + " " + y1);
}
else{
x2 = e.getX();
y2 = e.getY();
//System.out.println(x2 + " " + y2);
line = new DrawLine(x1, y1, x2, y2);
line.setBounds(x1, y1, x2, y2);
System.out.println("" + line.getLocation());
//line.setOpaque(false);
add(line);
x1 = x2;
y1 = y2;
repaint();
}
}
public void mousePressed(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseReleased(MouseEvent e) {
///throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseEntered(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseExited(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
}
CLASS # 2 (Paint Class):
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Arch. Don Saborrido
*/
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.GeneralPath;
//import java.awt.geom.Line2D;
import javax.swing.JPanel;
public class DrawLine extends JPanel{
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
//Line2D line;
Stroke[] s = new Stroke[] {new BasicStroke(10.0f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)};
//new BasicStroke(25.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL),
//new BasicStroke(25.0f, BasicStroke.CAP_SQUARE,BasicStroke.JOIN_MITER)
GeneralPath path = new GeneralPath();
public DrawLine(int start_x, int start_y, int end_x, int end_y){
x1 = start_x;
y1 = start_y;
x2 = end_x;
y2 = end_y;
System.out.println(x1+ " " + y1+ " " + x2+ " " + y2+ " ");
}
#Override
protected void paintComponent(Graphics g) {
System.out.println("entered paint");
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.setStroke(s[0]);
path.moveTo(x1,y1);
System.out.println("x1 = " + x1 + " y1 = " + y1);
path.lineTo(x2,y2);
System.out.println("x2 = " + x2 + " y2 = " + y2);
System.out.println("" + path.getBounds2D());
g2.draw(path);
//line = new Line2D.Float(x1, y1, x2, y2);
//if(x1 != x2 && y1 != y2)
//g2.draw(line);
}
}

This is a very complicated approach.
Try the following:
make a class (e.g. LineClass) with four variables: x1, x2, y1 and y2.
keep a ArrayList of your generated lines
draw each line in the ArrayList on your JPanel using g.drawline(line.x1, line.y1, line.x2, line.y2) where line is the element of the ArrayList
class MainClass extends JPanel implements MouseListener {
boolean clickedOnce = false;
ArrayList<Line> lines = new ArrayList<Line>();
int x, y;
MainClass () {
// init...
addMouseListener(this);
}
// more MouseEvent methods
public void mouseClicked(MouseEvent e) {
if (!clickedOnce){
x=e.getX();
y = e.getY();
clickedOnce = true;
}
else{
lines.add(new Line(x,y,e.getX(), e.getY());
clickedOnce = false;
repaint();
}
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
for (Line l: lines)
g.drawLine(l.x1, l.y2, l.x2, l.y2);
}
private class Line {
public int x1, y1, x2, y2;
Line (int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
}
}

line = new DrawLine(x1, y1, x2, y2);
ine.setBounds(x1, y1, x2, y2);
add(line);
The basic logic looks wrong to me. You can't just use the 4 values fo the size and location.
The location would be the minimum of the x1/x2 and y1/y2.
The size (width, height) would then be the absolute value of (x1 - x2) and (y1 - y2).
Then when you draw the line you would draw the line from (0, 0) to (width, height).
Maybe the code examples from Custom Painting Approaches will help with a slightly different solution.

One of the problems is that you are calculating the width and height wrong. They would be the difference between x1 and x2 and y1 and y2.
You could also probably do this easier using java's Graphics class. That has methods like drawLine(), which would probably make your life easier.

Related

Applet AWT Canvas not updating graphics

I am trying to program a basic plotter using Applets. I need to use Applets specifically.
For the polt I have created a separate Canvas, but I have encountered a problem I cannot solve. When I draw any graph for the first time, it is drawn nicely. However, the canvas is not being repainted properly afterwards - I see in the debugging screen that the repaint() method was called and the paint() is invoked, but no graphics are updated.
Here is the code:
public class MyCanvas extends Canvas{
int w,h; //width and height
int samples;
ArrayList<Double> eqValues = new ArrayList<>();
MyCanvas(int wi, int he) //constructor
{ w=wi; h=he;
setSize(w,h); //determine size of canvas
samples=wi-20;
}
public void paint(Graphics g)
{
int y0=0, y1; //previous and new function value
g.setColor(Color.yellow);
g.fillRect(0,0,w,h); //clear canvas
g.setColor(Color.black);
if (eqValues.size()>0) { // draw new graph
for (int t = 1; t <= samples; t = t + 1) {
y1 = eqValues.get(t).intValue();
g.drawLine(10 + t - 1, h - y0, 10 + t, h - y1);
y0 = y1;
}
}
System.out.println("Repainted");
/*g.drawLine(10,10,10,h-10); //y-axis
g.drawLine(10,h/2,w-10,h/2); //x-axis
g.drawString("P",w-12,h/2+15);
g.drawString("P/2",w/2-13,h/2+15);
g.drawLine(w-10,h/2-2,w-10,h/2+2); //horizontal marks
g.drawLine(w/2, h/2-2,w/2, h/2+2);*/
}
public void drawSine(double amp, double xCoef, double phase){
for (int j=0;j<=samples;j++){
eqValues.add(amp*Math.sin(xCoef*Math.PI*j/samples + Math.PI*phase/180)+0.5+h/2);
}
repaint();
System.out.println("Got sine vals");
}
public void drawFOeq(double sc, double fc){
for (int j=0;j<=samples;j++){
eqValues.add(sc*j+fc);
}
repaint();
System.out.println("Got FO eq vals");
}
}
Thanks in advance!
The problem is when you add values to the ArrayList: you are putting them after the ones already in the ArrayList (with the add(Double) method). If you just want to clear the plot and draw a new function use the clear() method in the ArrayList of values before adding the new ones:
public void drawSine(double amp, double xCoef, double phase) {
eqValues.clear(); //this clear the ArrayList
......
repaint();
......
}
public void drawFOeq(double sc, double fc){
eqValues.clear(); //this clear the ArrayList
......
repaint();
......
}
If you want to plot multiple functions you have to create different ArrayList or, even better, store in the ArrayList all points (for example with java.awt.Point):
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
public class MyCanvas extends Canvas {
int w, h; // width and height
int samples;
ArrayList<Point> eqValues = new ArrayList<>(); //Point constructor receives 2 int arguments: x and y; however, his methods getX() and getY() return double values
// constructor
MyCanvas(int wi, int he) {
w = wi;
h = he;
setSize(w, h); // determine size of canvas
samples = wi - 20;
}
public void paint(Graphics g) {
int x1, y0, y1; // previous and new function value
g.setColor(Color.yellow);
g.fillRect(0, 0, w, h); // clear canvas
g.setColor(Color.black);
if (eqValues.size() > 0) { // draw new graph
y0 = (int) Math.round(eqValues.get(0).getY()); // first line must start at the first point, not at 0,h
for (Point p : eqValues) { // iterates over the ArrayList
x1 = (int) Math.round(p.getX());
y1 = (int) Math.round(p.getY());
g.drawLine(10 + x1 - 1, h - y0, 10 + x1, h - y1);
y0 = y1;
}
}
System.out.println("Repainted");
}
public void drawSine(double amp, double xCoef, double phase) {
for (int j = 0; j <= samples; j++) {
eqValues.add(new Point(j, (int) Math
.round(amp * Math.sin(xCoef * Math.PI * j / samples + Math.PI * phase / 180) + 0.5 + h / 2)));
}
repaint();
System.out.println("Got sine vals");
}
public void drawFOeq(double sc, double fc) {
for (int j = 0; j <= samples; j++) {
eqValues.add(new Point(j, (int) Math.round(sc * j + fc)));
}
repaint();
System.out.println("Got FO eq vals");
}
}

How to move an object using radians?

I've got a problem couse I need to move my ball and it just stand still. I've succed moving it with a simple function (x=x+1) but when it comes to radians it just doesnt work. I've read some posts here and I thought I'm making it in the right way, but its obvious I've missed something :)
Here is my Ball class:
public class Ball {
int x = 0;
int y = 0;
int rightleft = 1;
int updown = 1;
private static final int sizeBall = 30;
float angle = 120;
float angleInRadians = (float) (angle*Math.PI/180);
private Main main;
public Ball(Main main){
this.main=main;
}
// That function should move my ball
void move() {
x = (int) (x + Math.cos(angleInRadians));
y= (int) (x+Math.sin(angleInRadians));
}
void paint(Graphics2D g) {
g.setColor(Color.red);
g.fillOval(x, y, sizeBall, sizeBall);
}
public Rectangle getSize(){
return new Rectangle(x,y,sizeBall,sizeBall);
}
}
And here is my Main class:
public class Main extends JPanel {
Ball ball = new Ball(this);
private void moveBall() throws InterruptedException{
ball.move();
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
}
public static void main(String[] args) throws InterruptedException {
// TODO code application logic here
JFrame okno = new JFrame("TEST");
Main main = new Main();
okno.add(main);
okno.setSize(500,500);
okno.setVisible(true);
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while(true){
main.moveBall();
main.repaint();
Thread.sleep(10);
}
}
}
Do you know where is my mistake?
x and y will always = 0. Understand that they are 0 to begin with, and then you add a sine or cose to them which is guaranteed to be < 1.
x = (int) (x + Math.cos(angleInRadians));
y = (int) (x+Math.sin(angleInRadians));
So 0 + a number < 1 will be < 1.
Then when you cast to int the number < 1 will become 0.
Also
use a Swing Timer not a while (true) loop.
override JPanel's paintComponent method, not its paint method for smoother animation.
I would use double numbers to represent my x and y values, and only cast or round when using them to draw.
I'm not sure what trajectory that you're aiming for, but your current code (if it worked) does not move in a polar way, but rather always at 45% angle from the current point.
For example, this GUI is created by the code below:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyPolar extends JPanel {
private static final int BI_W = 400;
private static final int BI_H = BI_W;
private static final int CTR_X = BI_W / 2;
private static final int CTR_Y = BI_H / 2;
private static final Color AXIS_COLOR = Color.black;
private static final Color GRID_LINE_COLOR = Color.LIGHT_GRAY;
private static final Color DRAWING_COLOR = Color.RED;
private static final float AXIS_LINE_WIDTH = 4f;
private static final double SCALE = BI_W / (2 * 1.25);
private static final float GRID_LINE_WIDTH = 2f;
private static final float DRAWING_WIDTH = 2f;
private static final double DELTA_THETA = Math.PI / (2 * 360);
private static final int TIMER_DELAY = 20;
private BufferedImage axiImg;
private List<Point> ptList = new ArrayList<>();
private double theta = 0;
public MyPolar() {
axiImg = createAxiImg();
int x = xEquation(theta);
int y = yEquation(theta);
ptList.add(new Point(x, y));
new Timer(TIMER_DELAY, new TimerListener()).start();
}
private int xEquation(double theta) {
double r = 2 * Math.sin(4 * theta);
return (int) (SCALE * 0.5 * r * Math.cos(theta)) + CTR_X;
}
private int yEquation(double theta) {
double r = 2 * Math.sin(4 * theta);
return (int) (SCALE * 0.5 * r * Math.sin(theta)) + CTR_Y;
}
private BufferedImage createAxiImg() {
BufferedImage img = new BufferedImage(BI_W, BI_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(AXIS_COLOR);
g2.setStroke(new BasicStroke(AXIS_LINE_WIDTH));
int x1 = 0;
int y1 = CTR_Y;
int x2 = BI_W;
int y2 = y1;
g2.drawLine(x1, y1, x2, y2);
x1 = CTR_X;
y1 = 0;
x2 = x1;
y2 = BI_H;
g2.drawLine(x1, y1, x2, y2);
g2.setColor(GRID_LINE_COLOR);
g2.setStroke(new BasicStroke(GRID_LINE_WIDTH));
x1 = (int) (CTR_X - BI_H * 0.5 * Math.tan(Math.PI / 6));
y1 = BI_H;
x2 = (int) (CTR_X + BI_H * 0.5 * Math.tan(Math.PI / 6));
y2 = 0;
g2.drawLine(x1, y1, x2, y2);
x1 = BI_W - x1;
x2 = BI_W - x2;
g2.drawLine(x1, y1, x2, y2);
x1 = (int) (CTR_X - BI_H * 0.5 * Math.tan(Math.PI / 3));
y1 = BI_H;
x2 = (int) (CTR_X + BI_H * 0.5 * Math.tan(Math.PI / 3));
y2 = 0;
g2.drawLine(x1, y1, x2, y2);
x1 = BI_W - x1;
x2 = BI_W - x2;
g2.drawLine(x1, y1, x2, y2);
for (int i = 1; i < 4; i++) {
int x = (int) (CTR_X - i * SCALE / 2.0);
int y = x;
int width = (int) (i * SCALE);
int height = width;
g2.drawOval(x, y, width, height);
}
g2.dispose();
return img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (axiImg != null) {
g2.drawImage(axiImg, 0, 0, null);
}
g2.setColor(DRAWING_COLOR);
g2.setStroke(new BasicStroke(DRAWING_WIDTH));
Point prev = null;
for (Point point : ptList) {
if (prev != null) {
int x1 = prev.x;
int y1 = prev.y;
int x2 = point.x;
int y2 = point.y;
g2.drawLine(x1, y1, x2, y2);
}
prev = point;
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(BI_W, BI_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
theta += DELTA_THETA;
if (theta > 2 * Math.PI) {
((Timer) e.getSource()).stop();
} else {
int x = xEquation(theta);
int y = yEquation(theta);
ptList.add(new Point(x, y));
}
repaint();
}
}
private static void createAndShowGui() {
MyPolar mainPanel = new MyPolar();
JFrame frame = new JFrame("MyPolar");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

making a double/int out of Point.getX() and .getY()

i'm trying to calculate the distance between 2 points with Java Point, it works fine till i say for example: double point1x = point1.getX();. cause when i do, i receive a error.
can somebody help me find the problem in my code?
public class ClickAndCalc extends JFrame implements MouseListener {
public ClickAndCalc() throws IOException{
addMouseListener(this);
}
public static void Window() throws IOException {
String path = "kaakfoto.jpg"; //imported image
File file = new File(path);
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
JLabel label = new JLabel(new ImageIcon(image)); //add the image to the JLabel
System.out.println("height: " + height); //print out the height and width of the image
System.out.println("width: " + width);
ClickAndCalc frame = new ClickAndCalc(); //make a new frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(label);
frame.setSize(width+3, height+26); //set the size of the frame the same as the size of the image
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
int i=0;
Point p1, p2, p3;
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) { //when clicked add point for 3 times
if(i==0) {
p1 = e.getPoint();
System.out.println("coordinates Point1: X=" + p1.getX() + ". Y=" + p1.getY());
}
else if(i==1) {
p2 = e.getPoint();
System.out.println("coordinates Point2: X=" + p2.getX() + ". Y=" + p2.getY());
}
else if(i==2) {
p3 = e.getPoint();
System.out.println("coordinates Point3: X=" + p3.getX() + ". Y=" + p3.getY());
}
i++;
}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
//down here is some mistake i can't find
double distanceAB(double x1, double y1, double x2, double y2) {
return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}
double x1 = p1.getX(), //convert getX and getY to doubles
y1 = p1.getY(),
x2 = p2.getX(),
y2 = p2.getY(),
distanceAB;{
distanceAB = distanceAB(x1, y1, x2, y2); //calculate the distance between point A and B
System.out.println("the distance between the points AB is " + distanceAB + ".");
}
public static void main(String[] args) throws IOException {
Window(); //add the window (frame, label, image)
}
}
The problem is here:
double x1 = p1.getX(), //convert getX and getY to doubles
y1 = p1.getY(),
x2 = p2.getX(),
y2 = p2.getY(),
distanceAB;
You are defining member variable of the class ClickAndCalc. These member variables are initialized when a new instance of the class is created, and that is the moment p1.getX(), p1.getY(), p2.getX() and p2.getY() are called. At this point, however, p1 and p2 are null, so you get a NullPointerException.
You can call calculate the distance between p1 and p2 only when you've determined the coordinates, that is, after you've clicked twice on the frame. The easiest solution is to move the code to the mousePressed method:
public void mousePressed(MouseEvent e) { //when clicked add point for 3 times
if (i==0) {
...
}
else if (i==1) {
p2 = e.getPoint();
System.out.println("coordinates Point2: X=" + p2.getX() + ". Y=" + p2.getY());
double x1 = p1.getX();
double y1 = p1.getY();
double x2 = p2.getX();
double y2 = p2.getY();
double distanceAB = distanceAB(x1, y1, x2, y2);
System.out.println("the distance between the points AB is " + distanceAB + ".");
}
...
}

Recursive Sierpinski's Triangle Java

I'm trying to draw Sierpinski's Triangle recursively in Java, but it doesn't work, though to me the logic seems fine. The base case is when the triangles are within 2 pixels of each other, hence the use of the Distance Formula.
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Font;
import java.awt.Canvas;
public class Triangle extends Canvas implements Runnable
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public Triangle()
{
setBackground(Color.WHITE);
}
public void paint( Graphics window )
{
window.setColor(Color.BLUE);
window.setFont(new Font("ARIAL",Font.BOLD,24));
window.drawString("Serpinski's Gasket", 25, 50);
triangle(window, (WIDTH-10)/2, 20, WIDTH-40, HEIGHT-20, 40, HEIGHT-20, 4);
}
public void triangle(Graphics window, int x1, int y1, int x2, int y2, int x3, int y3, int r)
{
//if statement base case
//midpoint = (x1 + x2 / 2), (y1 + y2/ 2)
if(Math.sqrt((double)(Math.pow(x2-x1, 2)) + (double)(Math.pow(y2-y1, 2))) > 2)
//if(r==0)
{
window.drawLine(x1, y1, x2, y2);
window.drawLine(x2, y2, x3, y3);
window.drawLine(x3, y3, x1, y1);
}
int xa, ya, xb, yb, xc, yc; // make 3 new triangles by connecting the midpoints of
xa = (x1 + x2) / 2; //. the previous triangle
ya = (y1 + y2) / 2;
xb = (x1 + x3) / 2;
yb = (y1 + y3) / 2;
xc = (x2 + x3) / 2;
yc = (y2 + y3) / 2;
triangle(window, x1, y1, xa, ya, xb, yb, r-1); // recursively call the function using the 3 triangles
triangle(window, xa, ya, x2, y2, xc, yc, r-1);
triangle(window, xb, yb, xc, yc, x3, y3, r-1);
}
public void run()
{
try{
Thread.currentThread().sleep(3);
}
catch(Exception e)
{
}
}
}
The Runner is
import javax.swing.JFrame;
public class FractalRunner extends JFrame
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public FractalRunner()
{
super("Fractal Runner");
setSize(WIDTH+40,HEIGHT+40);
getContentPane().add(new Triangle());
setVisible(true);
}
public static void main( String args[] )
{
FractalRunner run = new FractalRunner();
}
}
To me this should work but it causes a runtime/StackOverFlow error that I don't know how to correct. Any help?
You need to move the recursive calls to triangle, and the associated math, inside the conditional check on the separation. Right now, it will always call it and therefore you get the stack overflow.
Chances are your base case might not be working properly- what if the distance between two triangles is never two pixels? say we star with y1 and x1 being 0 and 200. their midpoint would be 100, then 50, 25, 12, 6, 3, 1<--- never hits the 2 pixel base case...
"StdDraw" was taken from here:
public class Sierpinski {
public static void sierpinski(int n) {
sierpinski(n, 0, 0, 1);
}
public static void sierpinski(int n, double x, double y, double size) {
if (n == 0) return;
//compute triangle points
double x0 = x;
double y0 = y;
double x1 = x0 + size;
double y1 = y0;
double x2 = x0 + size / 2;
double y2 = y0 + (Math.sqrt(3)) * size / 2;
// draw the triangle
StdDraw.line(x0, y0, x1, y1);
StdDraw.line(x0, y0, x2, y2);
StdDraw.line(x1, y1, x2, y2);
StdDraw.show(100);
//recursive calls
sierpinski(n-1, x0, y0, size / 2);
sierpinski(n-1, (x0 + x1) / 2, (y0 + y1) / 2, size / 2);
sierpinski(n-1, (x0 + x2) / 2, (y0 + y2) / 2, size / 2);
}
// read in a command-line argument n and plot an order Sierpinski Triangle
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
StdDraw.setPenRadius(0.005);
sierpinski(n);
}
}
Guy

Pythagoras tree with g2d

I'm trying to build my first fractal (Pythagoras Tree):
alt text http://img13.imageshack.us/img13/926/lab6e.jpg
in Java using Graphics2D. Here's what I have now :
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int i=0;
Scanner scanner = new Scanner(System.in);
System.out.println("Give amount of steps: ");
i = scanner.nextInt();
new Pitagoras(i);
}
}
class Pitagoras extends JFrame {
private int powt, counter;
public Pitagoras(int i) {
super("Pythagoras Tree.");
setSize(1000, 1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
powt = i;
}
private void paintIt(Graphics2D g) {
double p1=450, p2=800, size=200;
for (int i = 0; i < powt; i++) {
if (i == 0) {
g.drawRect((int)p1, (int)p2, (int)size, (int)size);
counter++;
}
else{
if( i%2 == 0){
//here I must draw two squares
}
else{
//here I must draw right triangle
}
}
}
}
#Override
public void paint(Graphics graph) {
Graphics2D g = (Graphics2D)graph;
paintIt(g);
}
So basically I set number of steps, and then draw first square (p1, p2 and size). Then if step is odd I need to build right triangle on the top of square. If step is even I need to build two squares on free sides of the triangle. What method should I choose now for drawing both triangle and squares ? I was thinking about drawing triangle with simple lines transforming them with AffineTransform but I'm not sure if it's doable and it doesn't solve drawing squares.
You do not have to draw triangles, only squares (the edges of the squares are the triangle) in this tree.
You can make things a lot easier looking into recursion (these types of fractals are standard examples for recursion):
In Pseudo-Code
drawSquare(coordinates) {
// Check break condition (e.g. if square is very small)
// Calculate coordinates{1|2} of squares on top of this square -> Pythagoras
drawSquare(coordinates1)
drawSquare(coordinates2)
}
And since I often programmed fractals, a hint: Draw the fractal itself in a BufferedImage and only paint the image in the paint-method. The paint-Method gets called possibly several times per second, so it must be faaaaast.
Also do not directly draw in a JFrame but use a Canvas (if you want to use awt) or a JPanel (if you use swing).
My final solution :
import java.awt.*;
import java.util.Scanner;
import javax.swing.*;
public class Main extends JFrame {;
public Main(int n) {
setSize(900, 900);
setTitle("Pythagoras tree");
add(new Draw(n));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Give amount of steps: ");
new Main(sc.nextInt());
}
}
class Draw extends JComponent {
private int height = 800;
private int width = 800;
private int steps;
public Draw(int n) {
steps = n;
Dimension d = new Dimension(width, height);
setMinimumSize(d);
setPreferredSize(d);
setMaximumSize(d);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
int x1, x2, x3, y1, y2, y3;
int base = width/7;
x1 = (width/2)-(base/2);
x2 = (width/2)+(base/2);
x3 = width/2;
y1 = (height-(height/15))-base;
y2 = height-(height/15);
y3 = (height-(height/15))-(base+(base/2));
g.drawPolygon(new int[]{x1, x1, x2, x2, x1}, new int[]{y1, y2, y2, y1, y1}, 5);
int n1 = steps;
if(--n1 > 0){
g.drawPolygon(new int[] {x1, x3, x2}, new int[] {y1, y3, y1}, 3);
paintMore(n1, g, x1, x3, x2, y1, y3, y1);
paintMore(n1, g, x2, x3, x1, y1, y3, y1);
}
}
public void paintMore(int n1, Graphics g, double x1_1, double x2_1, double x3_1, double y1_1, double y2_1, double y3_1){
int x1, x2, x3, y1, y2, y3;
x1 = (int)(x1_1 + (x2_1-x3_1));
x2 = (int)(x2_1 + (x2_1-x3_1));
x3 = (int)(((x2_1 + (x2_1-x3_1)) + ((x2_1-x3_1)/2)) + ((x1_1-x2_1)/2));
y1 = (int)(y1_1 + (y2_1-y3_1));
y2 = (int)(y2_1 + (y2_1-y3_1));
y3 = (int)(((y1_1 + (y2_1-y3_1)) + ((y2_1-y1_1)/2)) + ((y2_1-y3_1)/2));
g.setColor(Color.green);
g.drawPolygon(new int[] {x1, x2, (int)x2_1, x1}, new int[] {y1, y2, (int)y2_1, y1}, 4);
g.drawLine((int)x1, (int)y1, (int)x1_1, (int)y1_1);
g.drawLine((int)x2_1, (int)y2_1, (int)x2, (int)y2);
g.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
if(--n1 > 0){
g.drawLine((int)x1, (int)y1, (int)x3, (int)y3);
g.drawLine((int)x2, (int)y2, (int)x3, (int)y3);
paintMore(n1, g, x1, x3, x2, y1, y3, y2);
paintMore(n1, g, x2, x3, x1, y2, y3, y1);
}
}
}

Categories

Resources