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
Related
i was wondering how can I edit this DDA.
When I have this values: (x1 = 150,y1 = 20,x2 = 100,y2 = 80) it works perfectly fine, because it is in first quadrant.
But if I want to rasterize line from another qudrant
for example with value of (x1 = 10,y1 = 20,x2 = 100,y2 = 80)
this will make just straight line
So I'm having trouble with editing this algorithm to all 4 quadrants.
public void rasterize(int x1, int y1, int x2, int y2, int color) {
int x, y, krok;
float dy, dx;
dx = x2 - x1;
dy = y2 - y1;
if(Math.abs(dx)>Math.abs(dy)){
krok=(int)(Math.abs(dx));
} else {
krok=(int)(Math.abs(dy));
}
dx = dx / (float)krok;
dy = dy/ (float)krok;
x=x1;
y=y1;
for(int i=1;i<=krok;i++){
raster.setPixel(x, y, 0xffff00);
x+=dx;
y+=dy;
}
}
I am writing a recursion code for my triangle drawing. For some reason, it wont do the recursion, but it will do the base drawing. Would like some help in figuring out why my code isn't repeating. Also, if someone could help me figure out how to fill the triangles with a color, that would be much appreciated.
public class Triangle {
public static void draw(int n, double size, double x, double y) {
if (n == 0) return;
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.setPenColor(StdDraw.BLACK);
//StdDraw.line(xy, size/2)
double x1 = x + size/2;
double y1 = y + size/2;
double x2 = x1+ size/2;
// bottom triangle
StdDraw.line(x,y, x1, y1);
StdDraw.line(x1, y1, x2, y );
StdDraw.line(x2, y, x1, y);
//right triangle
StdDraw.line(y, y, x2, x2);
StdDraw.line(x1, x1, x1, y1);
// top triangle and left triangle
StdDraw.line(y1, x1, x, x2);
StdDraw.line(x2, x2, x, y);
draw(n-1, size -3, x, y);
}
public static void main(String[] args) {
double x = 0.0;
double y = 0.0;
double size = 1.0;
int n = 2;
draw(n, size, x, y);
}
}
I am trying to implement DDA algorithm in Java to draw a line. The Line Rasterizer implements an interface. Then I call the rasterizeLine function in class named Canva. The LineRasterizes successfully gets x and y points. No errors are thrown up, however there has to be some logical problem with the algorithm, because the line is not being drawed. Can you help me find the logical mistake?
Interface
package rasterops;
import rasterdata.RasterImage;
public interface LineRasterizer<PixelType> {
RasterImage<PixelType> rasterizeLine(RasterImage<PixelType> img,
double x1, double y1, double x2, double y2,
PixelType value);
}
Line Rasterizer
package rasterops;
import rasterdata.RasterImage;
public class LineRasterizerDDA<PixelType> implements LineRasterizer <PixelType> {
#Override
public RasterImage<PixelType> rasterizeLine(RasterImage<PixelType> img, double x1, double y1, double x2, double y2, PixelType value) {
double dy = y2-y1;
double dx = x2-x1;
double k = dy/dx;
double y = y1;
RasterImage<PixelType> result = img;
for( double x = x1; x <= x2; x++ ){
result = result.withPixel((int)x, (int)Math.round(y), value);
y = y1 + k;
}
return result;
}
}
Canva - calling the function
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
previousX = e.getX();
previousY = e.getY();
}
});
panel.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
final double startX = previousX / (panel.getWidth() - 1.0); //k zamysleni: proc 1.0 a ne 1?
final double startY = 1 - previousY / (panel.getHeight() - 1.0);
final double endX = e.getX() / (panel.getWidth() - 1.0);
final double endY = 1 - e.getY() / (panel.getHeight() - 1.0);
clear(); // zkuste zakomentovat
rasterImage = liner.rasterizeLine(rasterImage,
startX, startY, endX, endY,
0xffff00);
panel.repaint();
}
});
This line:
y = y1 + k;
keeps assigning the same value to y, because y1 and k aren't changing.
Example output, drawing line between (0,0) and (10, 10):
O..........
.OOOOOOOOOO
...........
...........
...........
...........
...........
...........
...........
...........
...........
You may mean:
y = y + k;
or y += k;.
Example output, drawing line between (0,0) and (10, 10):
O..........
.O.........
..O........
...O.......
....O......
.....O.....
......O....
.......O...
........O..
.........O.
..........O
I have an assignment for school where I have to create a program that will calculate the area of a circle given four points, but when I invoke the method areaCircle in main, nothing happens. It doesn't calculate the area.
public static void main(String[] args) {
Scanner reader;
reader = new Scanner(System.in);
System.out.println("Enter the coordinates of a point on the outside of a circle.");
System.out.println("x-coordinate: ");
int x1 = reader.nextInt();
System.out.println("y-coordinate: ");
int y1 = reader.nextInt();
System.out.println("Enter the center point of the circle.");
System.out.println("x-coordinate: ");
int x2 = reader.nextInt();
System.out.println("y-coordinate:");
int y2 = reader.nextInt();
areaCircle(x1, y1, x2, y2);
}
public static double distance(int x1, int y1, int x2, int y2) {
double dx = x2 - x1;
double dy = y2 - y1;
double dsquared = dx * dx + dy * dy;
double result = Math.sqrt(dsquared);
return result;
}
public static double areaCircle(int radius, double area) {
area = Math.PI * (radius * radius);
return area;
}
public static double areaCircle(int x1, int x2, int y1, int y2) {
double radius = distance(x1, y1, x2, y2);
double area = Math.PI * (radius * radius);
return area;
}
You need only to print the result, at the moment you are only calculating it.
Instead of
areaCircle (x1, y1, x2, y2);
write
System.out.println("The area is: " + areaCircle (x1, y1, x2, y2));
I am creating a graph with node pointing to others nodes.
I created my own JComponent to create the arrow :
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import javax.swing.JComponent;
public class GraphicEdge extends JComponent implements MouseListener{
private static final long serialVersionUID = 4474993605950397943L;
private float x1;
private float y1;
private float x2;
private float y2;
private int width;
private int height;
private String identifier;
private Color color = Color.GRAY;
private final int ARR_SIZE = 14;
public GraphicEdge(float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.addMouseListener(this);
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
private void drawArrow(Graphics g1, float x1, float y1, float x2, float y2) {
Graphics2D g = (Graphics2D) g1.create();
g.setColor(color);
// La transformée affine permet d'orienter le dessin par rapport au corps de la flèche
double dx = x2 - x1, dy = y2 - y1;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(angle));
g.transform(at);
// Permet de lisser le dessin
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Dessin de la tête de la flèche
Stroke tempStroke = g.getStroke();
g.setStroke(new BasicStroke(4.0f));
g.drawLine(0, 0, len - ARR_SIZE, 0);
g.setStroke(tempStroke);
g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE, len},
new int[] {0, - Math.round(ARR_SIZE / 2), Math.round(ARR_SIZE / 2), 0}, 4);
// Placement d'un rectangle arrondi pour écrire la charge du lien
at = AffineTransform.getRotateInstance(- angle);
g.transform(at);
g.setColor(Color.BLACK);
if(x1 > x2 && y1 > y2){
g.fillRoundRect(- Math.round((x1 - x2) / 2) - 20, - Math.round((y1 - y2) / 2) - 20, 40, 20, 10, 10);
g.setColor(Color.WHITE);
g.drawString("10.8k", - ((x1 - x2) / 2) - 20 + 5, - ((y1 - y2) / 2) - 10 + 5);
width = Math.round(x1 - x2);
height = Math.round(y1 - y2);
}
else if(x1 > x2 && y1 < y2){
g.fillRoundRect(- Math.round((x1 - x2) / 2) - 20, Math.round((y2 - y1) / 2) + 20, 40, 20, 10, 10);
g.setColor(Color.WHITE);
g.drawString("10.8k", - ((x1 - x2) / 2) - 20 + 5, - ((y1 - y2) / 2) + 10 - 5);
width = Math.round(x1 - x2);
height = Math.round(y2 - y1);
}
else if(x1 < x2 && y1 > y2){
g.fillRoundRect(Math.round((x2 - x1) / 2) - 20, - Math.round((y1 - y2) / 2) + 20, 40, 20, 10, 10);
g.setColor(Color.WHITE);
g.drawString("10.8k", ((x2 - x1) / 2) - 20 + 5, - ((y1 - y2) / 2) + 10 - 5);
width = Math.round(x2 - x1);
height = Math.round(y1 - y2);
}
else if(x1 < x2 && y1 < y2){
g.fillRoundRect(Math.round((x2 - x1) / 2) - 20, Math.round((y2 - y1) / 2) - 20, 40, 20, 10, 10);
g.setColor(Color.WHITE);
g.drawString("10.8k", ((x2 - x1) / 2) - 20 + 5, ((y2 - y1) / 2) - 10 + 5);
width = Math.round(x2 - x1);
height = Math.round(y2 - y1);
}
}
public void setColor(Color color){
this.color = color;
}
public void setLoad(float loadPercentage){
if(loadPercentage > 0.01 && loadPercentage <= 0.1){
setColor(Color.MAGENTA.darker());
}
else if(loadPercentage > 0.1 && loadPercentage <= 0.5){
setColor(Color.BLUE.darker());
}
else if(loadPercentage > 0.5 && loadPercentage <= 1){
setColor(Color.CYAN);
}
else if(loadPercentage > 1 && loadPercentage <= 5){
setColor(Color.GREEN);
}
else if(loadPercentage > 5 && loadPercentage <= 10){
setColor(Color.YELLOW);
}
else if(loadPercentage > 10 && loadPercentage <= 50){
setColor(Color.ORANGE);
}
else if(loadPercentage > 50 && loadPercentage <= 100){
setColor(Color.RED);
}
else{
setColor(Color.GRAY);
}
repaint();
}
public void setCoords(float x1, float y1, float x2, float y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
#Override
public void paintComponent(Graphics g){
drawArrow(g, x1, y1, x2, y2);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(width, height);
}
#Override
public Dimension getMinimumSize() {
return new Dimension(width, height);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(this.getIdentifier());
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mousePressed(MouseEvent e) {};
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
The following code add the arrow in the panel :
String identifier = label.substring(1, label.indexOf("$$$"));
GraphicEdge graphicEdge1 = new GraphicEdge(nodeSourcePos[0], nodeSourcePos[1], posX, posY);
graphicEdge1.setIdentifier(identifier);
graphEdges.add(graphicEdge1);
add(graphicEdge1);
validate();
The problem is that when I click wherever in my container, the mouseClicked event of my GraphicEdge is called.
So, I logged the bounds of my GraphicEdge, I got this :
x:0 y:0 width:940 height:520
Which are the dimensions of my JPanel containing the graph.
So naturally, the only clickable item is the last added on the graph.
How can I fix this problem ?
When doing custom painting you should override the getPreferredSize() method to return the Dimension of your component so layout managers know the size of the component.