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.
Related
I have modified some code in the Intersector class in libgdx to find the intersection between a line and a polygon. However, I am unsure how to calculate the normal of the point of collision. Below is some code that I have.
public static Vector2 intersectSegmentPolygon (Vector2 p1, Vector2 p2, Polygon polygon) {
float[] vertices = polygon.getTransformedVertices();
float x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
int n = vertices.length;
float x3 = vertices[n - 2], y3 = vertices[n - 1];
for (int i = 0; i < n; i += 2) {
float x4 = vertices[i], y4 = vertices[i + 1];
float d = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
if (d != 0) {
float yd = y1 - y3;
float xd = x1 - x3;
float ua = ((x4 - x3) * yd - (y4 - y3) * xd) / d;
if (ua >= 0 && ua <= 1) {
float ub = ((x2 - x1) * yd - (y2 - y1) * xd) / d;
if (ub >= 0 && ub <= 1) {
return new Vector2(x1 + (x2 - x1) * ua, y1 + (y2 - y1) * ua);
}
}
}
x3 = x4;
y3 = y4;
}
return null;
}
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;
regarding the following code, can I make it better for distance() method?
It feels like it's not completely OOP with this method.. how can I change code to be better OOD for this one ?
Thanks !!
public class Line extends Shape {
private Point lineP1;
private Point lineP2;
public Line(int x1, int x2, int y1, int y2, Color myColor) {
super(x1, x2, y1, y2, myColor);
lineP1 = new Point(this.getX1(),this.getY1());
lineP2 = new Point(this.getX2(),this.getY2());
}
#Override
public void draw(Graphics g) {
g.drawLine(this.getX1(), this.getY1(), this.getX2(), this.getY2());
g.setColor(Color.GREEN);
}
#Override
public boolean contains(Point p) {
if((this.distance(lineP1, p)+this.distance(lineP2, p)) == this.distance(lineP1, lineP2))
return true;
return false;
}
/**#return distance between two given points
* This method return the distance between two given points*/
private double distance(Point p1,Point p2 ){
return Math.sqrt(Math.pow((p1.getX()-p2.getX()), 2) + Math.pow((p1.getY()-p2.getY()), 2));
}
}//class Line
Your distance method seems to be ok (but it would be more performant, if you saved the differences in variables and used the * operator to multiply those values with themselfs instear of using Math.pow).
However, since floating point calculations tend to return inexact results, I don't recomend using the sum of the distances between the end node and the point to test as criterium.
But there's another good way determining, if a point is near a line or not: using the hesse normal form. It works like this:
Let P1 and P2 be vectors corresponing to the end points. * denotes the scalar multiplication and || the length of a vector:
D = (P2 - P1) / |P2 - P1|;
Let N be the vector D with coordinates swaped and the new x coordinate multiplied with -1 (i.e. a vector ortogonal to D).
Then the distance of a point H to the line can be determined like this
| N * H - N * P1 |
Also if H is between P1 and P2 can be checked like this (assuming without loss of generality D * P1 < D * P2):
D * P1 <= D * H <= D * P2
Using scalar products has the additional benefit, that calculating a scalar product only takes 2 multiplication and 1 addition in a 2D space.
This is how you could do this in java code
// components of normal vector
private double normalX;
private double normalY;
// components of direction vector
private double directionX;
private double directionY;
// the value of (N * P) for all points P on the line
private double normalScalarProduct;
// the range allowed for (D * P) for points on the line
private double minDirectionScalarProduct;
private double maxDirectionScalarProduct;
// error ranges; adjust as appropriate
private static final double directionAllowedError = 0.1;
private static final double normalAllowedError = 0.1;
public Line(int x1, int x2, int y1, int y2, Color myColor) {
...
double dx = x2 - x1;
double dy = y2 - y1;
double length = distance(dx, dy);
if (length == 0) {
// choose arbitrary direction, if length == 0
length = 1;
dx = 1;
}
// normalize direction
dx /= length;
dy /= length;
// set D and N values
this.directionX = dx;
this.directionY = dy;
this.normalX = -dy;
this.normalY = dx;
double prod1 = scalarProduct(directionX, directionY, x1, y1);
double prod2 = scalarProduct(directionX, directionY, x2, y2);
if (prod1 < prod2) {
minDirectionScalarProduct = prod1 - directionAllowedError;
maxDirectionScalarProduct = prod2 + directionAllowedError;
} else {
minDirectionScalarProduct = prod2 - directionAllowedError;
maxDirectionScalarProduct = prod1 + directionAllowedError;
}
normalScalarProduct = scalarProduct(x1, y1, normalX, normalY);
}
private static double scalarProduct(double x1, double y1, double x2, double y2) {
return x1*x2 + y1*y2;
}
public boolean contains(Point p) {
if (Math.abs(scalarProduct(p.getX(), p.getX(), normalX, normalY) - normalScalarProduct) <= normalAllowedError) {
// close enough to the line -> check, if between end points
double d = scalarProduct(p.getX(), p.getX(), directionX, directionY);
return minDirectionScalarProduct <= d && d <= maxDirectionScalarProduct;
}
return false;
}
private double distance(double dx, double dy) {
return Math.sqrt(dx*dx + dy*dy);
}
I have to implement a scanline algorithm from our professor but I don't really understand how I get the intersection points from the scanline with a polygon.
Here is the algorithm:
I implemented my own polygon(with methods like paint(), contains() and so on) already and I have all edges from the polygon saved in an array like this:
int[] pointsX;
int[] pointsY;
and I have the min and max values for x and y saved in
int ymin, ymax, xmin, xmax;
So my first thought is that I have to create a scanline starting from 0,ymin and check in a loop if the next point is inside the polygon. I implemented this method like this:
public boolean contains(Point test) {
boolean result = false;
java.awt.Polygon polygon = new java.awt.Polygon(pointsX, pointsY, pointsX.length);
if (polygon.contains(test)) {
result = true;
}
return result;
}
So when the next point is inside the polygon, I have a intersection point and so on. For this i have this loop:
ArrayList<Point> intersectionPoints = new ArrayList<>();
wasInside = false;
for (int yTemp = ymin; yTemp <= ymax; yTemp++) {
for (int xTemp = xmin; xTemp <= xmax; xTemp++) {
if (wasInside != this.contains(new Point(xTemp, yTemp))) {
intersectionPoints.add(new Point(xTemp, yTemp));
wasInside = !wasInside;
}
}
}
But I got a hint that this is no proper solution from my stackoverflow question.
Can someone give me a hint, how I can start implementing the algorithm from my professor? Where do I get the x1,y1,x2,y2,c points? I know that these are the edges but how do I know which edges do I have to take?
EDIT:
OK, now I have all Edges sorted by their y values. Can I calculate the intersection points with the given formula Sx=x1+(x2-x1)/...?
My first try looks like this:
for (int c = ymin; c <= ymax; c++) {
for (int xTemp = xmin; xTemp <= xmax; xTemp++) {
for (int currentEdge = 0; currentEdge < edges.size() - 1; currentEdge++) {
int x1 = edges.get(currentEdge).x;
int x2 = edges.get(currentEdge + 1).x;
int y1 = edges.get(currentEdge).y;
int y2 = edges.get(currentEdge + 1).y;
if ((y1 <= c && y2 > c) || (y2 <= c && y1 > c)) {
intersectionPoints.add(new Point((x1 + (x2 - x1) / (y2 - y1) * (c - y1)),c));
}
}
}
}
But this seems to be wrong, because I get a lot of wrong Points in intersectionPoints.
The problem was that I calculated with int numbers and an int divided by another int results in inaccuracies. So just doing this with double numbers solved it.
This is how I calculate the intersection points:
edges is a ArrayList<Point> containing the edge points.
ymin is the lowest y value and `ymax`` the highest one.
for (int yTemp = ymin; yTemp <= ymax; yTemp++) {
ArrayList<Point> intersectionPoints = new ArrayList<>();
for (int p = 0; p < edges.size() - 1; p++) {
int x1, x2, y1, y2;
double deltax, deltay, x;
x1 = edges.get(p).x;
y1 = edges.get(p).y;
x2 = edges.get(p + 1).x;
y2 = edges.get(p + 1).y;
deltax = x2 - x1;
deltay = y2 - y1;
int roundedX;
x = x1 + deltax / deltay * (yTemp - y1);
roundedX = (int) Math.round(x);
if ((y1 <= yTemp && y2 > yTemp) || (y2 <= yTemp && y1 > yTemp)) {
intersectionPoints.add(new Point(roundedX, yTemp));
}
}
//for the last interval
int x1, x2, y1, y2;
x1 = edges.get(edges.size() - 1).x;
y1 = edges.get(edges.size() - 1).y;
x2 = edges.get(0).x;
y2 = edges.get(0).y;
if ((y1 <= yTemp && y2 > yTemp) || (y2 <= yTemp && y1 > yTemp)) {
intersectionPoints.add(new Point(x1 + (x2 - x1) / (y2 - y1) * yTemp - y1, yTemp));
}
//you have to sort the intersection points of every scanline from the lowest x value to thr highest
Collections.sort(intersectionPoints, new SortXPoints());
pointsOfScanline.add(intersectionPoints);
This will give you an ArrayList containing ArrayLists of scanline points for every Scanline. So you just have to draw them with drawLine(x1, y2, x2, y2).
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: