Andres' algorithm - Draw a circular chromatic gradiation - java

I wrote a program which draws a circle colored thanks to a chromatic gradation, using the Andres' algorithm. Here is an execution's result :
Now I would want to shift this gradation. For example, I would want the red to begin at the right of the circle. Or at 70°. Etc.
So I have a shift, in radians. And I must use it in my Andres' algorithm.
But I don't understand how. However, I see two ways to do that :
Either I change the Andres' algorithm, I mean I change the coordinates of each pixel of each octant (= I change the circle's drawing) ;
Or I really shift the gradation and not the drawing.
I would prefer the solution number one. And I know it will make use of trigonometry. But my skills are too bad and I really need your help please...
Here is the source of my Andres' implementation. If you need it, I can also show you the code of my gradation-function. Thank you in advance.
NB : the most important part is just below the line while (y >= x) (id est : the octants' coordinates).
case "Andres' algorithm":
w = 2 * Math.PI;
for(double current_thickness = 0; current_thickness < this.thickness; current_thickness++) {
x = 0;
y = (int) (radius + current_thickness);
double d = radius + current_thickness - 1;
while (y >= x) {
double octant_1_x = x0 + x, octant_1_y = y0 + y;
double octant_2_x = x0 + y, octant_2_y = y0 + x;
double octant_3_x = x0 - x, octant_3_y = y0 + y;
double octant_4_x = x0 - y, octant_4_y = y0 + x;
double octant_5_x = x0 + x, octant_5_y = y0 - y;
double octant_6_x = x0 + y, octant_6_y = y0 - x;
double octant_7_x = x0 - x, octant_7_y = y0 - y;
double octant_8_x = x0 - y, octant_8_y = y0 - x;
max_counter++;
double[] rgb_gradation_octant_1 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_1_y - y0, octant_1_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_1_x, octant_1_y, Color.color(rgb_gradation_octant_1[0], rgb_gradation_octant_1[1], rgb_gradation_octant_1[2]))); // octant n°1
double[] rgb_gradation_octant_2 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_2_y - y0, octant_2_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_2_x, octant_2_y, Color.color(rgb_gradation_octant_2[0], rgb_gradation_octant_2[1], rgb_gradation_octant_2[2])));
double[] rgb_gradation_octant_3 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_3_y - y0, octant_3_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_3_x, octant_3_y, Color.color(rgb_gradation_octant_3[0], rgb_gradation_octant_3[1], rgb_gradation_octant_3[2])));
double[] rgb_gradation_octant_4 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_4_y - y0, octant_4_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_4_x, octant_4_y, Color.color(rgb_gradation_octant_4[0], rgb_gradation_octant_4[1], rgb_gradation_octant_4[2]))); // octant n°4
double[] rgb_gradation_octant_5 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_5_y-y0, octant_5_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_5_x, octant_5_y, Color.color(rgb_gradation_octant_5[0], rgb_gradation_octant_5[1], rgb_gradation_octant_5[2]))); // octant n°5
double[] rgb_gradation_octant_6 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_6_y-y0, octant_6_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_6_x, octant_6_y, Color.color(rgb_gradation_octant_6[0], rgb_gradation_octant_6[1], rgb_gradation_octant_6[2])));
double[] rgb_gradation_octant_7 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_7_y-y0, octant_7_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_7_x, octant_7_y, Color.color(rgb_gradation_octant_7[0], rgb_gradation_octant_7[1], rgb_gradation_octant_7[2])));
double[] rgb_gradation_octant_8 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_8_y-y0, octant_8_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_8_x, octant_8_y, Color.color(rgb_gradation_octant_8[0], rgb_gradation_octant_8[1], rgb_gradation_octant_8[2]))); // octant n°8
if (d >= 2 * x) {
d -= 2 * x + 1;
x++;
} else if (d < 2 * (radius + thickness - y)) {
d += 2 * y - 1;
y--;
} else {
d += 2 * (y - x - 1);
y--;
x++;
}
}
}
gui.getImageAnimation().setMax(max_counter*8);
break;

In 2 dimensions, you can achieve rotation with the following formulas:
x' = x cos f - y sin f
y' = y cos f + x sin f
Instead of repeating the transformation in every Pixel instantiation, you could write a helper that creates a rotated pixel and returns it. I meant something like:
Pixel rotated_pixel (double x, double y, Pixel rotation_center, Color color, double angle) {
double x0 = rotation_center.x,
y0 = rotation_center.y, // Oh god I hope I'm not also wrong about the field names now
sinw = Math.sin(angle), cosw = Math.cos(angle),
x_rot = x0 + (x-x0)*cosw - (y-y0)*sinw,
y_rot = y0 + (y-y0)*cosw + (x-x0)*sinw;
return new Pixel(x_rot, y_rot, color); // or smth
}
Then you can use it like updates.add(rotated_pixel(x,y,whatever));
I'm sorry that I cannot check the validity of this code; I don't currently have access to a computer with Java.

Thanks to #kubuzetto , the code below allows me to draw a circle taking account of a shift, expressed in radians. I mean its drawing begins at a certain angle (which is the shift). I still use Andres.
The only new problem with this solution is that gaps appear when the circle is rotated (ie. : when there is a shift).
Indeed :
http://imgur.com/BcAsP9n
I thought it was because of a cast which would have decreased the precision of the coordinates, but it's not the case.
If someone see why there is this problem, it would be fine !
/**
* Constructs a Pixel taking account of a shift and near the position (x0 ; y0)
* #param x
* #param y
* #param color
* #param angle
* #param x0
* #param y0
*/
Pixel(double x, double y, Color color, double angle, double x0, double y0) {
this.x = (int) (x0 + (x-x0) * Math.cos(angle) - (y-y0) * Math.sin(angle));
this.y = (int) (y0 + (y-y0) * Math.cos(angle) + (x-x0) * Math.sin(angle));
this.color = color;
}
And the Andres' algorithm :
case "Andres' algorithm":
w = 2 * Math.PI;
for(double current_thickness = 0; current_thickness < this.thickness; current_thickness++) {
x = 0;
y = (int) (radius + current_thickness);
double d = radius + current_thickness - 1;
while (y >= x) {
double octant_1_x = x0 + x, octant_1_y = y0 + y;
double octant_2_x = x0 + y, octant_2_y = y0 + x;
double octant_3_x = x0 - x, octant_3_y = y0 + y;
double octant_4_x = x0 - y, octant_4_y = y0 + x;
double octant_5_x = x0 + x, octant_5_y = y0 - y;
double octant_6_x = x0 + y, octant_6_y = y0 - x;
double octant_7_x = x0 - x, octant_7_y = y0 - y;
double octant_8_x = x0 - y, octant_8_y = y0 - x;
max_counter++;
double[] rgb_gradation_octant_1 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_1_y - y0, octant_1_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_1_x, octant_1_y,
Color.color(rgb_gradation_octant_1[0], rgb_gradation_octant_1[1], rgb_gradation_octant_1[2]),
circle_gradation_beginning, x0, y0)); // octant n°1
double[] rgb_gradation_octant_2 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_2_y - y0, octant_2_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_2_x, octant_2_y,
Color.color(rgb_gradation_octant_2[0], rgb_gradation_octant_2[1], rgb_gradation_octant_2[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_3 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_3_y - y0, octant_3_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_3_x, octant_3_y,
Color.color(rgb_gradation_octant_3[0], rgb_gradation_octant_3[1], rgb_gradation_octant_3[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_4 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_4_y - y0, octant_4_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_4_x, octant_4_y,
Color.color(rgb_gradation_octant_4[0], rgb_gradation_octant_4[1], rgb_gradation_octant_4[2]),
circle_gradation_beginning, x0, y0)); // octant n°4
double[] rgb_gradation_octant_5 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_5_y-y0, octant_5_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_5_x, octant_5_y,
Color.color(rgb_gradation_octant_5[0], rgb_gradation_octant_5[1], rgb_gradation_octant_5[2]),
circle_gradation_beginning, x0, y0)); // octant n°5
double[] rgb_gradation_octant_6 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_6_y-y0, octant_6_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_6_x, octant_6_y,
Color.color(rgb_gradation_octant_6[0], rgb_gradation_octant_6[1], rgb_gradation_octant_6[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_7 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_7_y-y0, octant_7_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_7_x, octant_7_y,
Color.color(rgb_gradation_octant_7[0], rgb_gradation_octant_7[1], rgb_gradation_octant_7[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_8 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_8_y-y0, octant_8_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_8_x, octant_8_y,
Color.color(rgb_gradation_octant_8[0], rgb_gradation_octant_8[1], rgb_gradation_octant_8[2]),
circle_gradation_beginning, x0, y0)); // octant n°8
if (d >= 2 * x) {
d -= 2 * x + 1;
x++;
} else if (d < 2 * (radius + thickness - y)) {
d += 2 * y - 1;
y--;
} else {
d += 2 * (y - x - 1);
y--;
x++;
}
}
}
gui.getImageAnimation().setMax(max_counter*8);
break;

Related

How to rework acceleration formula for double pendulum with mouse interaction

I need to make the mousePressed() function move the entire pendulum within the bounds of its length (r1 and r2 = 200). Lines 32-44 need to change based on the mousePressed function
I have code for a single pendulum that uses PGraphics with a function that works the way i want it to. It uses the length of the pendulum as the maximum displacement for the ball at the end. I need to translate this into a double pendulum that accounts for two lengths instead of one.After running the program for a while the line traced is bound in a circle with a radius being the sum of the r variable (400)
void drag() {
// If we are draging the ball, we calculate the angle between the
// pendulum origin and mouse position
// we assign that angle to the pendulum
if (dragging) {
PVector diff = PVector.sub(origin, new PVector(mouseX, mouseY)); // Difference between 2 points
angle = atan2(-1*diff.y, diff.x) - radians(90); // Angle relative to vertical axis
}
}
}
float r1 = 200;
float r2 = 200;
float m1 = 40;
float m2 = 40;
float a1 = PI/2;
float a2 = PI/2;
float a1_v = 0;
float a2_v = 0;
float g = 1;
float px2 = -1;
float py2 = -1;
float cx, cy;
PGraphics canvas;
void setup() {
size(1024, 768);
cx = width/2;
cy = 200;
canvas = createGraphics(width, height);
canvas.beginDraw();
canvas.background(255);
canvas.endDraw();
}
void draw() {
background(255);
imageMode(CORNER);
image(canvas, 0, 0, width, height);
float num1 = -g * (2 * m1 + m2) * sin(a1);
float num2 = -m2 * g * sin(a1-2*a2);
float num3 = -2*sin(a1-a2)*m2;
float num4 = a2_v*a2_v*r2+a1_v*a1_v*r1*cos(a1-a2);
float den = r1 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a1_a = (num1 + num2 + num3*num4) / den;
num1 = 2 * sin(a1-a2);
num2 = (a1_v*a1_v*r1*(m1+m2));
num3 = g * (m1 + m2) * cos(a1);
num4 = a2_v*a2_v*r2*m2*cos(a1-a2);
den = r2 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a2_a = (num1*(num2+num3+num4)) / den;
translate(cx, cy);
stroke(0);
strokeWeight(2);
float x1 = r1 * sin(a1);
float y1 = r1 * cos(a1);
float x2 = 0;
float y2 = 0;
if(mousePressed){
x2 = mouseX - cx;
y2 = mouseY - cy;
}else{
x2 = x1 + r2 * sin(a2);
y2 = y1 + r2 * cos(a2);
}
line(0, 0, x1, y1);
fill(0);
ellipse(x1, y1, m1, m1);
line(x1, y1, x2, y2);
fill(0);
ellipse(x2, y2, m2, m2);
a1_v += a1_a;
a2_v += a2_a;
a1 += a1_v;
a2 += a2_v;
// a1_v *= 0.99;
// a2_v *= 0.99;
canvas.beginDraw();
//canvas.background(0, 1);
canvas.translate(cx, cy);
canvas.stroke(0);
if (frameCount > 1) {
canvas.line(px2, py2, x2, y2);
}
canvas.endDraw();
px2 = x2;
py2 = y2;
}

How to add mouse drag function to double pendulum

I have code for a double pendulum that traces the second pendulums centre with a line by using the previous position of the pendulum. I need to add a function that when the mouse is clicked (on or not on the pendulum, it doesnt matter), the pendulum can be dragged around the screen within the boundaries of the pendulum, im not sure if mouse dragged() would work or if i should use a class for the pendulum to make it easier
float r1 = 200;
float r2 = 200;
float m1 = 40;
float m2 = 40;
float a1 = PI/2;
float a2 = PI/2;
float a1_v = 0;
float a2_v = 0;
float g = 1;
float px2 = -1;
float py2 = -1;
float cx, cy;
PGraphics canvas;
void setup() {
size(900, 600);
cx = width/2;
cy = 200;
canvas = createGraphics(width, height);
canvas.beginDraw();
canvas.background(255);
canvas.endDraw();
}
void draw() {
background(255);
imageMode(CORNER);
image(canvas, 0, 0, width, height);
float num1 = -g * (2 * m1 + m2) * sin(a1);
float num2 = -m2 * g * sin(a1-2*a2);
float num3 = -2*sin(a1-a2)*m2;
float num4 = a2_v*a2_v*r2+a1_v*a1_v*r1*cos(a1-a2);
float den = r1 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a1_a = (num1 + num2 + num3*num4) / den;
num1 = 2 * sin(a1-a2);
num2 = (a1_v*a1_v*r1*(m1+m2));
num3 = g * (m1 + m2) * cos(a1);
num4 = a2_v*a2_v*r2*m2*cos(a1-a2);
den = r2 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a2_a = (num1*(num2+num3+num4)) / den;
translate(cx, cy);
stroke(0);
strokeWeight(2);
float x1 = r1 * sin(a1);
float y1 = r1 * cos(a1);
float x2 = x1 + r2 * sin(a2);
float y2 = y1 + r2 * cos(a2);
line(0, 0, x1, y1);
fill(0);
ellipse(x1, y1, m1, m1);
line(x1, y1, x2, y2);
fill(0);
ellipse(x2, y2, m2, m2);
a1_v += a1_a;
a2_v += a2_a;
a1 += a1_v;
a2 += a2_v;
// a1_v *= 0.99;
// a2_v *= 0.99;
canvas.beginDraw();
//canvas.background(0, 1);
canvas.translate(cx, cy);
canvas.stroke(0);
if (frameCount > 1) {
canvas.line(px2, py2, x2, y2);
}
canvas.endDraw();
px2 = x2;
py2 = y2;
}
You're on the right track: cx and cy are the coordinates of the system's origin.
Simply update those to the mouse coordinates in the mouseDragged() callback:
void mouseDragged(){
cx = mouseX;
cy = mouseY;
}
To address your question as clarified in the comments, one quick and dirty option is to simply override x2,y2 with mouse coordinates (offsetting by the cx,cy system origin position):
float x2 = 0;
float y2 = 0;
if(mousePressed){
x2 = mouseX - cx;
y2 = mouseY - cy;
}else{
x2 = x1 + r2 * sin(a2);
y2 = y1 + r2 * cos(a2);
}
here's a full code listing with the above applied:
float r1 = 200;
float r2 = 200;
float m1 = 40;
float m2 = 40;
float a1 = PI/2;
float a2 = PI/2;
float a1_v = 0;
float a2_v = 0;
float g = 1;
float px2 = -1;
float py2 = -1;
float cx, cy;
PGraphics canvas;
void setup() {
size(900, 600);
cx = width/2;
cy = 200;
canvas = createGraphics(width, height);
canvas.beginDraw();
canvas.background(255);
canvas.endDraw();
}
void draw() {
background(255);
imageMode(CORNER);
image(canvas, 0, 0, width, height);
float num1 = -g * (2 * m1 + m2) * sin(a1);
float num2 = -m2 * g * sin(a1-2*a2);
float num3 = -2*sin(a1-a2)*m2;
float num4 = a2_v*a2_v*r2+a1_v*a1_v*r1*cos(a1-a2);
float den = r1 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a1_a = (num1 + num2 + num3*num4) / den;
num1 = 2 * sin(a1-a2);
num2 = (a1_v*a1_v*r1*(m1+m2));
num3 = g * (m1 + m2) * cos(a1);
num4 = a2_v*a2_v*r2*m2*cos(a1-a2);
den = r2 * (2*m1+m2-m2*cos(2*a1-2*a2));
float a2_a = (num1*(num2+num3+num4)) / den;
translate(cx, cy);
stroke(0);
strokeWeight(2);
float x1 = r1 * sin(a1);
float y1 = r1 * cos(a1);
float x2 = 0;
float y2 = 0;
if(mousePressed){
x2 = mouseX - cx;
y2 = mouseY - cy;
}else{
x2 = x1 + r2 * sin(a2);
y2 = y1 + r2 * cos(a2);
}
line(0, 0, x1, y1);
fill(0);
ellipse(x1, y1, m1, m1);
line(x1, y1, x2, y2);
fill(0);
ellipse(x2, y2, m2, m2);
a1_v += a1_a;
a2_v += a2_a;
a1 += a1_v;
a2 += a2_v;
// a1_v *= 0.99;
// a2_v *= 0.99;
canvas.beginDraw();
//canvas.background(0, 1);
canvas.translate(cx, cy);
canvas.stroke(0);
if (frameCount > 1) {
canvas.line(px2, py2, x2, y2);
}
canvas.endDraw();
px2 = x2;
py2 = y2;
}
Bare in mind this will simply allow you to drag the second ball visually, completely ignoring the simulation. When you release the mouse the simulation will resume. If you do want to affect the simulation from bottom to top you will need to workout the math (lines 32-44 in your case).

Java Swing - Draw an arc using Graphics.DrawArc(...) on Jpanel

I am trying to draw an arc on Jpanel in swing from user input having the center of arc, starting point and end point of arc.
here is my current
int x1 = 300; //start point
int y1 = 300;
int x2 = 350; //center point of arc
int y2 = 350;
int x3 = 300; //end point of arc
int y3 = 400;
int h1 = y1 - y2; //calculate with and height from start-center and center-end
int d1 = x2 - x1;
int h2 = y2 - y3;
int d2 = x3 - x2;
int startangle = (int)(Math.atan(h1 / d1) * 180 / Math.PI);
if (x2 > x1 && y2 > y1) {
startangle = 180 - startangle;
} else if (x2 < x1) {
//change sign
} else if (y1 < y2) {
//change sign
}
System.out.println("x1,y1\n" + x1 + "\n" + y1 + "\n" + d2 / h2 + "\n" + Math.atan(d2 / h2) * 180 / Math.PI);
int endangle = (int)(Math.atan2(x3, y3) * 180 / Math.PI);
System.out.println("args: " + "\n" + x2 + "\n" + y2 + "\n" + startangle + "\n" + endangle + "\n");
g2.drawArc(x1, y1, d1, h1, startangle, startangle);
g2.drawArc(x2, y2, d2, h2, 0, endangle);
However i am not getting the arc on screen, literally nothing related to it (other shapes work but not this one). No errors or exceptions were thrown.
Edit: Thanks to #MadProgrammer's comment, i am getting a shape but not what i expect.
What i get:
What i expect from the same set of coordinates:
Edit 2: managed to make it work by using a bezier curve instead of an arc
It worked by using a bezier curve and drawing quadcurve in two phases (start-middle,middle-end) using the calculated control points instead of the drawArc method.
I think the bounding rectangle of drawarc is the height and width of the ellipse that your arc is part of.

Discontinuous Derivative of Perlin Noise

So I've been trying to implement Perlin noise recently, and have run into some unusual problems. Whenever the edges of the grid in which the random vectors are stored are crossed, the derivative appears to be discontinuous.
Here's a link to a picture of the output (on the right), along with a 1 dimensional slice (on the left).
The Output
class perlin{
private double[][][] grid;
public perlin(int x,int y, int seed){
Random r = new Random(seed);
grid = new double[x+1][y+1][2];
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
grid[i][j][0] = 2*r.nextDouble()-1;
grid[i][j][1] = 2*r.nextDouble()-1;
}
}
}
public static double lerp(double a, double b, double t){
double c = t * t * t * (t * (t * 6 - 15) + 10);
return (b * c) + (a * (1 - c));
}
public double get(double x, double y){
double x2;
double y2;
double x3;
double y3;
x2 = x * (grid.length-1);
y2 = y * (grid[0].length-1);
x3 = down(x2);
y3 = down(y2);
x2 = x2 - x3;
y2 = y2 - y3;
int i = (int) (x3);
int j = (int) (y3);
return lerp(lerp(dot(x2, y2, grid[i][j][0], grid[i][j][1] ), dot(1 - x2, y2, grid[i + 1][j][0], grid[i + 1][j][1]),x2), lerp(dot(x2, 1 - y2, grid[i][j + 1][0], grid[i][j +1][1] ), dot(1 - x2,1 - y2, grid[i + 1][j + 1][0], grid[i + 1][j + 1][1] ), x2),y2 );
// return 0;
}
public static double dot(double x1, double y1, double x2, double y2){
return x1 * x2 + y1 * y2;
}
private static double down(double a){
if (a == 0){
return 0;
}
if(a == Math.floor(a)){
return a - 1;
}else{
return Math.floor(a);
}
}
}
From what I understand about the math behind this, the derivative of the noise should be continuous at all points, but that does not appear to be the case.

Generating fractal Swirl [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I need to draw a fractal swirl using the algorithm Iterated Function System.
There are coefficients for this fractal:
0.745455 -0.459091 0.406061 0.887121 1.460279 0.691072 0.912675
-0.424242 -0.065152 -0.175758 -0.218182 3.809567 6.741476 0.087325
And here is my code:
import java.awt.Graphics;
import javax.swing.JPanel;
public class Surface extends JPanel {
double a1 = 0.745455;
double b1 = -0.459091;
double d1 = 0.406061;
double e1 = 0.887121;
double c1 = 1.460279;
double f1 = 0.691072;
double p1 = 0.912675;
double a2 = -0.424242;
double b2 = -0.065152;
double d2 = -0.175758;
double e2 = -0.218182;
double c2 = 3.809567;
double f2 = 6.741476;
double p2 = 0.087325;
double x1(double x, double y) {
return a1 * x + b1 * y + c1;
}
double y1(double x, double y) {
return d1 * x + e1 * y + f1;
}
double x2(double x, double y) {
return a2 * x + b2 * y + c2;
}
double y2(double x, double y) {
return d2 * x + e2 * y + f2;
}
public void paint(Graphics g) {
drawFractal(g);
}
void drawFractal(Graphics g) {
double x1 = 300;
double y1 = 300;
double x2 = 0;
double y2 = 0;
g.fillOval(300 + (int) x1, 300 + (int) y1, 3, 3);
for (int i = 0; i < 10000; i++) {
double p = Math.random();
if (p < 0.91675) {
x2 = x1(x1, y1);
y2 = y1(x1, y1);
g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
x1 = x2;
y1 = y2;
} else {
x2 = x2(x1, y1);
y2 = y2(x1, y1);
g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
x1 = x2;
y1 = y2;
}
}
}
}
Unfortunately, with this code I get a wrong picture:
It would be great if someone could point out my mistake.
Your generation seems correct (i.e. don't do x1 = x2 +300; y1 = y2 +300;), but your problem is you're way off the scale for the purposes of rendering. This means there are very few points that fall outside very center of the image.
Your window is [0..600]x[0..600]. Try multiplying x2 and y2 with 50, so that you're rendering the [-6..6]x[-6..6] region instead of the [-300..300]x[-300..300] region of space.
Note that it should be sufficient to draw single pixels (as lines to itself) instead of 3x3 ovals.
int xp = 300 + (int) (x2 * scale);
int yp = 300 + (int) (y2 * scale);
g.drawLine(xp, yp, xp, yp);
Depending on what gets rendered, you might need to adjust the scale slightly to get the entire image with reasonable bounds. Note the second transformation offsets by -6.7, so a scale of 30 should be about right.
Also note that by using x1 = x2 +300; y1 = y2 +300; you change the transformations and get a different fractal (at a scale at which you expect).
This is great, I was wrong thinking that exponential runtime required! The fractals appeared more dimensional than my imagination!
Thanks #Jan Dvorak!
The following also works (in my coordinates, xcenter=300, ycenter=100 and radius=50 are global drawing parameters) and works faster:
void drawFractal2(Graphics g) {
double x1 = 0;
double y1 = 0;
double x2 = 0;
double y2 = 0;
double p;
g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);
for(int i=0; i<100000; ++i) {
p = Math.random();
if (p < p1) {
x2 = x1(x1, y1);
y2 = y1(x1, y1);
}
else {
x2 = x2(x1, y1);
y2 = y2(x1, y1);
}
g.fillOval(xcenter + (int) (x2 * radius), ycenter + (int) (y2 * radius), 3, 3);
x1 = x2;
y1 = y2;
}
}
and the picture is better
BELOW IS MY INCORRECT ANSWER
But it show how fractals are bigger than the intuition, so I keep it.
I guess your algorithm should be tree-like (recursive) while your one is linear. You are just drawing one chain of points, transforming it one after one. So you get some spiral-like chain. It can't generate any fractal picture in principle.
I GOT YOUR PICTURE
You have 2 mistakes:
1) you pass 300 both into iteration and as drawing shift. This is minor.
2) You algorithm is linear. Linear algorithm can't draw tree-like picture. If you use random values, you should run algorithm multiple times. One chain draws only one random portion of the picture.
I got your picture with following recursive algorithm. It works slow but you are to improve it.
void drawFractal(Graphics g, double x1, double y1, int depth) {
double x2 = 0;
double y2 = 0;
if( depth > 20 ) {
return;
}
g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);
x2 = x1(x1, y1);
y2 = y1(x1, y1);
drawFractal(g, x2, y2, depth+1);
x2 = x2(x1, y1);
y2 = y2(x1, y1);
drawFractal(g, x2, y2, depth+1);
}
to run it I used
public void paint(Graphics g) {
//drawFractal(g);
drawFractal(g, 0, 0, 0);
}
parameters are
int xcenter = 300;
int ycenter = 100;
int radius = 50;
the picture is follows:

Categories

Resources