So I finished up a program that recursively draws lines which takes an argument "n" to define the depth of the recursion. I have 2 functions, one which draws the relatively left line and another which draws the relatively right one. I tested it ant it seems to work for the first 4 levels, but then either the lines become too small to accurately represent or there's something wrong with my code because the breaks between the lines seem to become arbitrary. Was hoping somebody could test my code and see if they could find what the problem is.
The following image is of depth 10.
EDIT: fixed a part of code, still need help though
public class Art
{
//draws the relatively left line
public static void drawLeftLine(double x0, double y0, double x1, double y1)
{
//define new x coordinate for line
//double x2 = (1/3.0)*(x1 - x0);
//color of line
StdDraw.setPenColor(StdDraw.BLUE);
//draw line by adding new x coord to original
StdDraw.line(x0, y0, x1, y1);
}
//draw relatively right line
public static void drawRightLine(double x0, double y0, double x1, double y1)
{
//define new x coord for line
//double x2 = (2/3.0)*(x1 - x0);
//color of line
StdDraw.setPenColor(StdDraw.BLUE);
//draw line by adding new x coord to original
StdDraw.line(x0, y0, x1, y1);
}
public static void cantor(int n, double x0, double y0, double x1, double y1)
{
if (n == 0)
return;
drawLeftLine(x0, y0, x1, y1);
drawRightLine(x0, y0, x1, y1);
y0 = y0 - 0.1;
y1 = y1 - 0.1;
cantor(n-1, x0, y0, x0 + ((x1 - x0))/3.0, y1); //left
cantor(n-1, (2.0/ 3) * (x1 - x0) + x0, y0, x1, y1); //right
}
public static void main(String[] args)
{
//change n into integer (depth)
int n = Integer.parseInt(args[0]);
//specify inital values for line
double x0 = 0;
double y0 = 0.9;
double x1 = 0.9;
double y1 = 0.9;
//recursive function cantor
cantor(n, x0, y0, x1, y1);
}
}
I think that the drawing looks incorrect because the of the fact that all of the nice double values are being approximated with discrete pixels causing unwanted overlap between the line segments (see EDIT at the bottom). Some comments about your code however :
1) You don't need the drawLeftLine
and drawRightLine
methods since currently they are drawing exactly the same thing. Since at each step you are calling cantor
twice (once for each side of the deleted inner third), you have one call to cantor
for each line segment that has to be drawn. As such I would put all of the drawing directly into the cantor
method.
2) Since y0
and y1
are both always the same, I would reduce them to just a single y
variable.
3) I would simplify the math for computing the new x0
and x1
values down to
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
4) Instead of decrementing the y
value by 0.1
every time, you should have a global variable that decides the amount by which this should be decremented (otherwise if you try n > 10
things will break). This value can just be set to 1.0 / n
.
5) You don't need to set the color of the pen every time you paint. You can set it just once in the main method.
6) StdDraw
already sets a border around the picture you are drawing so there is no need to start your coordinates from 0.9
- you can use 1
instead.
Following these suggestions the code would look like this :
private static double yIncrement;
public static void cantor(int n, double x0, double x1, double y) {
if (n == 0)
return;
StdDraw.line(x0, y, x1, y);
y = y - yIncrement;
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
}
public static void main(String[] args) {
//change n into integer (depth)
int n = Integer.parseInt(args[0]);
// specify inital values for line
double x0 = 0;
double x1 = 1;
double y = 1;
yIncrement = 1.0 / n;
StdDraw.setPenColor(Color.BLUE);
// recursive function cantor
cantor(n, x0, x1, y);
}
EDIT : Playing around with the StdDraw
canvas size, canvas scaling settings, and line segment endpoint rounding mode you can get a slightly better picture (the code below produces a picture that looks mostly correct down to the 8th level)
private static double yIncrement;
public static void cantor(int n, double x0, double x1, double y) {
if (n == 0)
return;
x0 = Math.ceil(x0);
x1 = Math.floor(x1);
StdDraw.line(x0, y, x1, y);
y = y - yIncrement;
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
}
public static void main(String[] args) {
// change n into integer (depth)
int n = Integer.parseInt(args[0]);
int width = 1920;
int height = 1080;
StdDraw.setCanvasSize(width, height);
// specify inital values for line
double x0 = 0;
double x1 = width;
double y = 1;
yIncrement = 1.0 / n;
StdDraw.setPenColor(Color.BLUE);
StdDraw.setXscale(0, width);
// recursive function cantor
cantor(n, x0, x1, y);
}
To display everything down to the tenth level with absolute correctness you would need a width of 3^9 pixels (19K pixels). For level 9 that's 3^8 = 6K. For level 8 that's 3^7 = 2k, which is why it looks almost correct with 1.9K pixel width and integer rounding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With