Please help me how to color the triangle with the three colors. I have it as a problem for school,
Use Java programming language
Hello this is the code:
I am trying to fill the triangle with the three colors, but is hard to mix colors to get it. Please if you are to solve it(approximate it) as much as you can send it to me, i have it as a homework and 5-6 days deadline
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
public class NotFullVersion2 extends JApplet {
public static void main(String s[]) {
JFrame frame = new JFrame();
frame.setTitle("Colors");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new NotFullVersion2();
applet.init();
applet.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e) {
System.out.println(e.getX() + " " + e.getY());
}});
frame.getContentPane().add(applet);
frame.pack();
frame.setVisible(true);
}
ColorPanel panel;
public void init() {
panel = new ColorPanel();
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(panel, BorderLayout.CENTER);
JPanel p = new JPanel();
cp.add(p,BorderLayout.EAST);
}
}
class ColorPanel extends JPanel {
//int red = 100,green = 100, blue = 100;
public ColorPanel() {
setPreferredSize(new Dimension(500, 500));
setBackground(Color.black);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for(int i = 0; i < 256; i++) {
int start = 399;
g2.setColor(new Color(0,i,255-i));
for(int j = 0; j < 200; j ++) {
Rectangle rec = new Rectangle(150+j,start - i,1,1);
g2.fill(rec);
}
}
for(int j = 0; j < 100; j++) {
int start = 100;
for(int i = 0; i < 300; i++) {
if(i < 22) {
g2.setColor(new Color(255,0,0));
Rectangle rec = new Rectangle(100 + i,start + j,1,1);
g2.fill(rec);
} else if(i > 21 && i < 278) {
g2.setColor(new Color(255-(i-22),(i-22),0));
Rectangle rec = new Rectangle(100 + i,start + j,1,1);
g2.fill(rec);
} else if(i < 300) {
g2.setColor(new Color(0,255,0));
Rectangle rec = new Rectangle(100 + i,start + j,1,1);
g2.fill(rec);
}
}
}
GeneralPath closePath1a = new GeneralPath();
g2.setColor(new Color(0,0,0));
closePath1a.moveTo(100,100);
closePath1a.lineTo(100,400);
closePath1a.lineTo(250,400);
closePath1a.closePath();
g2.fill(closePath1a);
GeneralPath closePath2a = new GeneralPath();
g2.setColor(new Color(0,0,0));
closePath2a.moveTo(400,100);
closePath2a.lineTo(400,400);
closePath2a.lineTo(250,400);
closePath2a.closePath();
g2.fill(closePath2a);
GeneralPath closePath3a = new GeneralPath();
g2.setColor(new Color(0,0,0));
closePath3a.moveTo(100,100);
closePath3a.lineTo(100,50);
closePath3a.lineTo(400,50);
closePath3a.lineTo(400,100);
closePath3a.closePath();
g2.fill(closePath3a);
}
}
Coloring a triangle like this is equivalent to calculating the barycentric coordinates of each pixel within the triangle. The following untested code calculates the barycentric coordinates for each pixel within the triangle ABC, and then uses it to color that pixel:
private float area(float Ax, float Ay, float Bx, float By, float Cx, float Cy) {
return 0.5*((Ax - Cx)*(By - Ay) - (Ax - Bx)*(Cy - Ay));
}
private void paintTriangle(Graphics g, float Ax, float Ay, float Bx, float By, float Cx, float Cy) {
// calculate the bounding box of the triangle:
int minX = Math.round(Math.min(Ax, Math.min(Bx, Cx)));
int minY = Math.round(Math.min(Ay, Math.min(By, Cy)));
int maxX = Math.round(Math.max(Ax, Math.max(Bx, Cx)));
int maxY = Math.round(Math.max(Ay, Math.max(By, Cy)));
// loop for each pixel in the bounding box of the triangle
for(int y = minY; y < maxY; ++y) {
for(int x = minX; x < maxX; ++x) {
// center of the pixel (x,y)
float Px = x + 0.5, Py = y + 0.5;
// barycentric coordinates of P
float denom = area(Ax, Ay, Bx, By, Cx, Cy);
float b0 = area(Px, Py, Bx, By, Cx, Cy)/denom;
float b1 = area(Ax, Ay, Px, Py, Cx, Cy)/denom;
float b2 = area(Ax, Ay, Bx, By, Px, Py)/denom;
// discard pixels outside the triangle
if(b0 < 0 || b1 < 0 || b2 < 0)
continue;
// paint a pixel of color (b0,b1,b2) at (x,y)
g.setColor(new Color(b0,b1,b2));
g.fillRect(x,y,1,1));
}
}
}
I'll leave it to you to test and integrate this code.
You can read more about barycentric coordinates on wikipedia;
Related
I'm working on a java programming exercise where we have to draw a circular spiral using the drawArc method so that the result looks similar to this:
I've been working on this for a while and this is what I have so far:
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int x = 100;
int y = 120;
int width = 40;
int height = 60;
int startAngle = 20;
int arcAngle = 80;
for (int i = 0; i < 5; i++) {
g.drawArc(x, y, width, height, startAngle, arcAngle);
g.drawArc(x + 10, y + 10, width, height, startAngle + 10, arcAngle);
x = x + 5;
y = y + 5;
startAngle = startAngle - 10;
arcAngle = arcAngle + 10;
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
My code gives me this result:
I know the problem lies in my arguments for the drawArc method because the numbers aren't right, but I don't know how to go about making the numbers go in a circular manner. Any help is appreciated. Thank you!
Your idea is almost right. I did some modifications. You need to inverse the angle to draw the other side of the spiral and use fixed point to startAngle.
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int x = getSize().width / 2 - 10;
int y = getSize().height/ 2 - 10;
int width = 20;
int height = 20;
int startAngle = 0;
int arcAngle = 180;
int depth = 10;
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
// g.drawArc(x + 10, y + 10, width, height, startAngle + 10, -arcAngle);
// x = x - 5;
y = y - depth;
width = width + 2 * depth;
height = height + 2 * depth;
g.drawArc(x, y, width, height, startAngle, -arcAngle);
} else {
// g.drawArc(x + 10, y + 10, width, height, startAngle + 10, arcAngle);
x = x - 2 * depth;
y = y - depth;
width = width + 2 * depth;
height = height + 2 * depth;
g.drawArc(x, y, width, height, startAngle, arcAngle);
}
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
If this were my project, yes I'd draw my arcs in a loop, but within the loop, I'd try to make the arc's bounding box bigger but still centered over the same location. To do this I'd decrement x and y by some small constant, say DELTA (which I'd set to == 1), and I'd increment width and height by 2 * DELTA. I'd also leave my arcAngle unchanged but rather would change my startAngle in the loop like so: startAngle = startAngle - arcAngle;.
For example, this:
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class CircSpiral extends JPanel {
private static final int DELTA = 1;
private static final int ARC_ANGLE = 20;
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W;
private static final int LOOP_MAX = 400;
public void paintComponent(Graphics g) {
int x = PREF_W / 2;
int y = PREF_H / 2;
int width = 1;
int height = 1;
int startAngle = 0;
int arcAngle = ARC_ANGLE;
for (int i = 0; i < LOOP_MAX; i++) {
g.drawArc(x, y, width, height, startAngle, arcAngle);
x = x - DELTA;
y = y - DELTA;
width += 2 * DELTA;
height += 2 * DELTA;
startAngle = startAngle - arcAngle;
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.pack();
application.setLocationRelativeTo(null);
application.setVisible(true);
}
}
Would result in this:
The following code will output this image:
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int numIterations = 5;
int arcWidth = 10;
int arcGrowDelta = 30;
for (int i = 0; i < numIterations; i++) {
g.drawArc(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 0, 180);
arcWidth += arcGrowDelta;
g.drawArc(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 180, 180);
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
The idea is very simple, just draw the upper half of a circle, like this:
Then increment the arc size by a constant factor and draw the bottom half of the circle but making the end point of this circle and the upper circle match, for it, just substrate the arcGrowDelta from the bottom circle width:
And repeat.
This is my solution:
package mainpack;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JPanel;
public class SpiralPanel extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
int width = 10;
int height = 10;
int startAngle = 0;
int arcAngle = 180;
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
int i = 0;
int t = 0;
while (i < 36) {
g2d.drawArc(x + t, y, width, height, startAngle, arcAngle);
if (i % 2 == 0) {
t -= 10;
}
y -= 5;
width += 10;
height += 10;
startAngle += 180;
i++;
}
}
}
I am a beginner to java and finally managed how to create the spiral.
Here is my code:
int lineLength = 20; //starting line length
int x = getWidth() / 2; //start drawing from center of JPanel
int y = getHeight() / 2; //start drawing from center of JPanel
for( int counter = 0; counter < 10; counter++ )
{
g.drawArc( x, y, lineLength, lineLength, 0, 180 ); //draws top semicircle of equal width and height
lineLength += 20; //increases arc diameter
x -= 20; //moves x coordinate left
g.drawArc( x, y - 10, lineLength, lineLength, 0, -180 ); //draws bottom semicircle; 'y - 10' joins the 2 semicircles
lineLength += 20; //increases arc diameter
y -= 20; //moves y coordinate up
}
If you're willing to let some good old trigonometry do the work, you could use this:
import java.awt. *;
import javax.swing. *;
import java.math.*;
public class Spiral extends JFrame {
public Spiral()
{
// Set Window
setTitle("Spirale");
setSize(1500, 1500);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g);
for(double i = 1; i < 50000; i++)
{
int locY = 600 - (int) (Math.cos((Math.PI*i)/1800)*i/50);
int locX = 600 - (int) (Math.sin((Math.PI*i)/1800)*i/50);
g.drawLine(locX, locY, locX, locY);
}
}
public static void main(String[] args) {
new Spiral();
}
}
Could anyone help me figure out why my circle is not printing out on top of the square all the way to the top? The square seems to print out onto the frame perfectly fine but I've been unable to figure out why the loop stops after the 2nd row but never completing up to the 6th row. thank guys!
This is my main ExampleGUI.java class
import javax.swing.*;
public class ExampleGUI {
public static void main(String args[]) {
JFrame frame = new JFrame("Example Graphics");
ExamplePanel panel = new ExamplePanel();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(3);
frame.pack();
frame.setVisible(true);
}
}
This is my method/constructor class ExamplePanel.java
import java.awt.*;
import javax.swing.*;
public class ExamplePanel extends JPanel {
public ExamplePanel() {
setPreferredSize(new Dimension(600, 600));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0;
int x2 = 5;
int y = 500;
int y2 = 505;
int w = 100;
int w2 = 90;
int h = 100;
int h2 = 90;
int i, j;
for (j = 1; j < 7; j++) {
x = 0;
x2 = x + 5;
System.out.println(x + " " + y);
for (i = 1; i < 7; i++) {
g.setColor(Color.red);
g.fillRect(x, y, w, h);
g.setColor(Color.black);
g.drawRect(x, y, w, h);
g.setColor(Color.green);
g.fillOval(x2, y2, w2, h2);
g.setColor(Color.black);
g.drawOval(x2, y2, w2, h2);
x = x + w;
x2 = x2 + w2 + 10;
}
x = x + w;
y2 = 505;
y = y - h;
y2 = (y2 - h2) - 10;
}
}
}
You have to remove your y2= 505;
You have mistakenly set your y2 to the same value each iteration :)
I am making a circle to circle collision detection program. I can get the balls to move around but when the collision is detected, the balls are quite far overlapped. Any suggestions? Thanks in advance!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.lang.Math;
public class ShapePanel extends JPanel{
private JButton button, startButton, stopButton;
private JTextField textField;
private JLabel label;
private Timer timer;
private final int DELAY = 10;
ArrayList<Shape> obj = new ArrayList<Shape>();
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ShapePanel());
frame.pack();
frame.setVisible(true);
}
public ShapePanel(){
JPanel controlPanel = new JPanel();
DrawingPanel dpanel = new DrawingPanel();
controlPanel.setPreferredSize(new Dimension(100,400));
button = new JButton("Add Shape");
startButton = new JButton("Start");
stopButton = new JButton("Stop");
textField = new JTextField(2);
label = new JLabel("Count:");
controlPanel.add(button);
controlPanel.add(label);
controlPanel.add(textField);
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(controlPanel);
add(dpanel);
ButtonListener bListen = new ButtonListener();
button.addActionListener(bListen);
startButton.addActionListener(bListen);
stopButton.addActionListener(bListen);
timer = new Timer(DELAY, bListen);
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == button){
obj.add(new Shape());
if (obj.get(obj.size()-1).y > 200){
obj.get(obj.size()-1).moveY = -obj.get(obj.size()-1).moveY;
}
}else if (e.getSource() == timer){
for (int i = 0; i < obj.size(); i++){
obj.get(i).move();
}
for (int i = 0; i < obj.size(); i++){
for (int j = i + 1; j < obj.size(); j++){
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius){
timer.stop();
}
}
}
}else if (e.getSource() == startButton){
timer.start();
}else if (e.getSource() == stopButton){
timer.stop();
}
repaint();
}
}
private class DrawingPanel extends JPanel{
DrawingPanel(){
setPreferredSize(new Dimension(400,400));
setBackground(Color.pink);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i = 0; i < obj.size(); i++){
obj.get(i).display(g);
}
}
}
}
import java.awt.*;
import java.util.*;
public class Shape{
public int x, y, width, height, moveX = 1, moveY = 1, centerCoordX, centerCoordY, radius;
private Color colour;
public boolean reverse = false, sameDirection = true;
Random generator = new Random();
public int randomRange(int lo, int hi){
return generator.nextInt(hi-lo)+lo;
}
Shape(){
width = randomRange(30, 50);
if (width % 2 != 0){
width = randomRange(30, 50);
}
height = width;
radius = width/2;
x = randomRange(0, 400-width);
y = randomRange(0, 400-height);
colour = new Color(generator.nextInt(256),generator.nextInt(256),generator.nextInt(256));
}
public void display(Graphics g){
g.setColor(colour);
g.fillOval(x, y, width, height);
}
void move(){
x += moveX;
y += moveY;
centerCoordX = x + width/2;
centerCoordY = y + height/2;
if(x >= 400-width){
moveX = -moveX;
}if(x <= 0){
moveX = -moveX;
}if(y >= 400-height){
moveY = -moveY;
}if (y <= 0){
moveY = -moveY;
}
}
}
So much uncommented code!
The balls are just colliding if their centres are within the sum of the radii. Let r1 and r2 be the ball radii, and x1, y1 the position of the centre of ball1; similarly x2, y2 for ball2.
Measure the square of the distance between the centres as (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1). (Pythagoras).
They have collided if this is less than or equal to (r1 + r2) * (r1 + r2).
The key thing here is that there is no need to compute the square roots which is an expensive computational task.
I'd say it probably due to your circles moving too fast or your time step is too high. Reduce your time step. A better approach is use a physics library like Box2D. Have a look at libgdx, that a java library that has it included.
its discussed a bit in this link
You should check the colision after each move.
for (int i = 0; i < obj.size(); i++)
{
obj.get(i).move();
for (int j = 0; j < obj.size(); j++)
{
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius && i!=j)
{
timer.stop();
}
}
}
You need something like this.
public boolean overlaps (Circle c1, Circle c2) {
float dx = c1.x - c2.x;
float dy = c1.y - c2.y;
float distance = dx * dx + dy * dy;
float radiusSum = c1.radius + c2.radius;
return distance < radiusSum * radiusSum;
}
I am trying to draw lines using JPanel and I have hit somewhat of a wall. I can get two sides down but once it comes to subtracting from the x cord it all goes wrong.
package GUIstuff;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel{
public void paintComponent (Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int drawCounter = 0; // counters for all the while statements
int drawCounter2 = 0;
int drawCounter3 = 0;
int drawCounter4 = 0;
int x1 = 0; // cords change with the while statemetns
int x2 = 0;
int y1 = 0;
int y2 = 0;
while (drawCounter <= 15){ // counter
y2 = 250;
g.drawLine(x1, y1, x2, y2);
x2 = x2 + 15;
y1 = y1 + 15;
drawCounter++; }
int u1 = 0;
int u2 = 0;
int v1 = 0;
int v2 = 0;
while (drawCounter2 <= 15){
u2 = 250;
g.drawLine(u1, v1, u2, v2);
u1 = u1 + 15;
v2 = v2 + 15;
drawCounter2++;
}
int a1 = 0;
int a2 = 0;
int b1 = 0;
int b2 = 0;
while (drawCounter3 <= 15){
a2 = 250;
g.drawLine(a1, b1, a2, b2);
b1 = b1 + 15;
a2 = a2 - 15;
drawCounter3++;
}
}
}
Here is my runner class
package GUIstuff;
import javax.swing.JFrame;
public class DrawPanelTest {
public static void main (String args[]){
DrawPanel panel = new DrawPanel();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize (250, 250);
application.setVisible(true);
}
}
I have a the lines in the bottom left and the upper right but when I try to subtract from x I just get lines going a crossed the whole box.
When doing custom painting you should override the getPreferredSize() method so the panel can be displayed at its preferred size.
When you draw the lines two variable are the same and two variables differ. Use the width/height variable when appropriate instead of hardcoding a number. In the example below I did the left and bottom sides. The bottom side shows how to subtract. I'll let you figure out the pattern for the other two side.
Also, I made the panel a little more dynamic so it will be easy to configure the number of lines you want painted and the gap between the lines.
import java.awt.*;
import javax.swing.*;
public class DrawSSCCE extends JPanel
{
private int lines;
private int lineGap;
public DrawSSCCE(int lines, int lineGap)
{
this.lines = lines;
this.lineGap = lineGap;
}
#Override
public Dimension getPreferredSize()
{
int size = lines * lineGap;
return new Dimension(size, size);
}
#Override
public void paintComponent(Graphics g)
{
int width = getWidth();
int height = getHeight();
// Draw lines starting from left to bottom
int x = lineGap;
int y = 0;
for (int i = 0; i < lines; i++)
{
g.drawLine(0, y, x, height);
x += lineGap;
y += lineGap;
}
// Draw lines starting from bottom to right
x = 0;
y = height - lineGap;
for (int i = 0; i < lines; i++)
{
g.drawLine(x, height, width, y);
x += lineGap;
y -= lineGap;
}
// Draw lines starting from right to top
// Draw lines starting from top to left
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("DrawSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new DrawSSCCE(15, 15) );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
One way to draw this type of graphic would be to divide the drawing into quadrants. Here's a GUI I came up with.
This drawing is created by drawing lines all around the rectangle.
I created a JFrame and a drawing JPanel. I created the drawing JPanel by dividing the horizontal width and vertical height into the same number of increments. Since the width is greater than the height, the width increment is greater than the height increment.
I divided the drawing into quarters, and worked on the code for each quarter separately, using fewer and larger increments. Once I had all four quarters working, I quadrupled the number of increments and divided the width increment and the height increment by four.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawOvalRectangle implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawOvalRectangle());
}
#Override
public void run() {
JFrame frame = new JFrame("Curved Lines 2021");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int width, height, margin, increments, xIncrement, yIncrement;
public DrawingPanel() {
this.margin = 10;
this.increments = 80;
this.xIncrement = 8;
this.yIncrement = 6;
this.width = increments * xIncrement;
this.height = increments * yIncrement;
this.setPreferredSize(new Dimension(
width + margin + margin, height + margin + margin));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
drawNorthwestQuadrant(g);
drawNortheastQuadrant(g);
drawSouthwestQuadrant(g);
drawSoutheastQuadrant(g);
}
private void drawNorthwestQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x2 += xIncrement;
y1 -= yIncrement;
}
}
private void drawNortheastQuadrant(Graphics g) {
int x1 = margin;
int y1 = margin;
int x2 = width + margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 += yIncrement;
}
}
private void drawSouthwestQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 += yIncrement;
}
}
private void drawSoutheastQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = width + margin;
int y2 = height + margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 -= yIncrement;
}
}
}
}
I have an assignment that requires us to paint a tree of Pythagoras using recursion. The tree is started with the square ABCD and the points A and B are defined by mouse clicks. Everything seems to work until I get to the recursion where I can get either the left or right part of the tree to paint, but not both. I placed a comment where I believe I am running into problems.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class PythagorasTree extends JFrame
{
public static void main(String[] args)
{
new PythagorasTree();
}
PythagorasTree()
{
super("Pythagoras Tree");
setSize(800,800);
add("Center", new DrawingPanel());
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class DrawingPanel extends JPanel
{
Random random = new Random();
int centerX;
int centerY;
int clickCount = 0;
float pixelSize;
float rWidth = 10.0F;
float rHeight = 7.5F;
float red, green, blue;
Point a = new Point();
Point b = new Point();
Point c = new Point();
Point d = new Point();
Point e = new Point();
Point u = new Point();
DrawingPanel()
{
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent click)
{
clickCount++;
if (clickCount == 1)
{
a.x = fx(click.getX());
a.y = fy(click.getY());
repaint();
}
if (clickCount == 2)
{
b.x = fx(click.getX());
b.y = fy(click.getY());
repaint();
}
}
});
}
void initgr()
{
Dimension d = getSize();
int maxX = d.width - 1;
int maxY = d.height - 1;
pixelSize = Math.max(rWidth/maxX, rHeight/maxY);
centerX = maxX/2;
centerY = maxY/2;
}
int iX(float x){return Math.round(centerX + x/pixelSize);}
int iY(float y){return Math.round(centerY - y/pixelSize);}
float fx(int x){return (x - centerX) * pixelSize;}
float fy(int y){return (centerY - y) * pixelSize;}
public void paintComponent(Graphics g)
{
initgr();
super.paintComponent(g);
setBackground(Color.white);
g.setColor(Color.red);
if (clickCount == 1)
g.drawLine(iX(a.x), iY(a.y), iX(a.x), iY(a.y));
if (clickCount > 1)
drawTree(g,a,b);
}
public void drawTree(Graphics g, Point first, Point second)
{
float xSquared = (float) Math.pow((second.x-first.x),2);
float ySquared = (float) Math.pow((second.y-first.y),2);
float length = (float) Math.sqrt(xSquared + ySquared);
if ( length > .001)
{
u.x = second.x - first.x;
u.y = second.y - first.y;
a.x = first.x;
a.y = first.y;
b.x = second.x;
b.y = second.y;
d.x = first.x + (u.y * -1);
d.y = first.y + u.x;
c.x = d.x + u.x;
c.y = d.y + u.y;
e.x = d.x + .5F * (u.x + (u.y*-1));
e.y = d.y + .5F * (u.y + u.x);
Polygon square = new Polygon();
Polygon triangle = new Polygon();
square.addPoint(iX(a.x), iY(a.y));
square.addPoint(iX(b.x), iY(b.y));
square.addPoint(iX(c.x), iY(c.y));
square.addPoint(iX(d.x), iY(d.y));
red = random.nextFloat();
green = random.nextFloat();
blue = random.nextFloat();
g.setColor(new Color(red, green, blue));
g.fillPolygon(square);
triangle.addPoint(iX(c.x), iY(c.y));
triangle.addPoint(iX(d.x), iY(d.y));
triangle.addPoint(iX(e.x), iY(e.y));
red = random.nextFloat();
green = random.nextFloat();
blue = random.nextFloat();
g.setColor(new Color(red, green, blue));
g.fillPolygon(triangle);
/* Problem code is here, tree will draw Left or Right depending on which recursive call
* is first in the code, but will never reach the 2nd call.
*/
drawTree(g,d,e); //Draw tree left
drawTree(g,e,c); //Draw tree right
}
}
}
class Point
{
public float x;
public float y;
public Point()
{
}
}
It's time this question had an answer. The problem is with these member variable declarations:
Point c = new Point();
Point e = new Point();
And this code in drawTree():
drawTree(g,d,e); //Draw tree left
drawTree(g,e,c); //Draw tree right
Since c and e are a member variables, not local, they get modified by the first recursive call to drawTree(g, d, e) so by the time we make the second call to drawTree(g, e, c), it's no longer the same c and e we thought we had. The following rework of the code makes these local (clearly not as efficient GC-wise, but also not as buggy) as well as several other small modifications:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
class Point
{
public float x;
public float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public Point() {
}
}
class DrawingPanel extends JPanel
{
Random random = new Random();
int clickCount = 0;
float pixelSize;
float rWidth = 10.0F;
float rHeight = 7.5F;
float red, green, blue;
Point a = new Point();
Point b = new Point();
Point center = new Point();
DrawingPanel()
{
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent click)
{
clickCount++;
if (clickCount == 1)
{
a.x = fx(click.getX());
a.y = fy(click.getY());
repaint();
}
else if (clickCount == 2)
{
b.x = fx(click.getX());
b.y = fy(click.getY());
repaint();
}
}
});
}
void initgr()
{
Dimension d = getSize();
int maxX = d.width - 1;
int maxY = d.height - 1;
pixelSize = Math.max(rWidth / maxX, rHeight / maxY);
center.x = maxX / 2;
center.y = maxY / 2;
}
int iX(float x){ return Math.round(center.x + x / pixelSize); }
int iY(float y){ return Math.round(center.y - y / pixelSize); }
float fx(int x){ return (x - center.x) * pixelSize; }
float fy(int y){ return (center.y - y) * pixelSize; }
public void paintComponent(Graphics g)
{
super.paintComponent(g);
initgr();
setBackground(Color.white);
if (clickCount == 1)
{
g.setColor(Color.red);
g.drawLine(iX(a.x), iY(a.y), iX(a.x), iY(a.y));
}
else if (clickCount > 1) {
drawTree(g, a, b);
}
}
public void drawTree(Graphics g, Point first, Point second)
{
double xSquared = Math.pow(second.x - first.x, 2);
double ySquared = Math.pow(second.y - first.y, 2);
if (Math.sqrt(xSquared + ySquared) < 0.01) {
return;
}
Point u = new Point(second.x - first.x, second.y - first.y);
Point d = new Point(first.x - u.y, first.y + u.x);
Point c = new Point(d.x + u.x, d.y + u.y);
Point e = new Point(d.x + 0.5F * (u.x - u.y), d.y + 0.5F * (u.y + u.x));
Polygon square = new Polygon();
square.addPoint(iX(first.x), iY(first.y));
square.addPoint(iX(second.x), iY(second.y));
square.addPoint(iX(c.x), iY(c.y));
square.addPoint(iX(d.x), iY(d.y));
red = random.nextFloat();
green = random.nextFloat();
blue = random.nextFloat();
g.setColor(new Color(red, green, blue));
g.fillPolygon(square);
Polygon triangle = new Polygon();
triangle.addPoint(iX(c.x), iY(c.y));
triangle.addPoint(iX(d.x), iY(d.y));
triangle.addPoint(iX(e.x), iY(e.y));
red = random.nextFloat();
green = random.nextFloat();
blue = random.nextFloat();
g.setColor(new Color(red, green, blue));
g.fillPolygon(triangle);
drawTree(g, d, e); // Draw tree left
drawTree(g, e, c); // Draw tree right
}
}
public class PythagorasTree extends JFrame
{
PythagorasTree()
{
super("Pythagoras Tree");
setSize(800, 800);
add("Center", new DrawingPanel());
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new PythagorasTree();
}
}
OUTPUT