Mandelbrot very slow to refresh, any way to make it faster? - java

I've been working recently on a fractal generator, and have been specifically working on the Mandelbrot set. Unfortunately, zooming and moving seems to be very inneficient and takes quite a while to refresh. I am generating it every time I zoom, and I know this is probably not the most efficient way of doing this, and I can't seem to find code that uses another method that I understand.
These are the following methods I use, the first being an intial generation, the second being a refresh method.
private void genMandelbrot(Dimension size) {
for(int x=0;x<size.width;x++) {
for(int y=0;y<size.height;y++) {
double moveX=globalx;
double moveY=globalx;
//zoom and x/y offset.
double real = 1.5 * (x - size.width / 2) / (0.5 * zoom * size.width) + moveX;
double imaginary=(y - size.height / 2) / (0.5 * zoom * size.height) + moveY;
double newRe=0,newIm=0,oldRe=0,oldIm=0;
int i;
for(i=0;i<8000;i++) {
oldRe = newRe;
oldIm = newIm;
newRe = oldRe * oldRe - oldIm * oldIm + real;
newIm = 2 * oldRe * oldIm + imaginary;
if((newRe * newRe + newIm * newIm) > 4) break;
}
Cell c = new Cell(Color.getHSBColor(i % 256, i % 255, 255 * ((i<20)? 1:0)), new Dimension(1,1), new Point(x,y));
cells.add(c);
}
}
}
public void refreshMandelbrot(Dimension size) {
for(Cell c : cells) {
double moveX=globalx;
double moveY=globalx;
int x=c.x;
int y=c.y;
//zoom and x/y offset.
double real = 1.5 * (x - size.width / 2) / (0.5 * zoom * size.width) + moveX;
double imaginary=(y - size.height / 2) / (0.5 * zoom * size.height) + moveY;
double newRe=0,newIm=0,oldRe=0,oldIm=0;
int i;
for(i=0;i<8000;i++) {
oldRe = newRe;
oldIm = newIm;
newRe = oldRe * oldRe - oldIm * oldIm + real;
newIm = 2 * oldRe * oldIm + imaginary;
if((newRe * newRe + newIm * newIm) > 4) break;
}
cells.set(cells.indexOf(c), new Cell(Color.getHSBColor(i % 256, i % 255, 255 * ((i<20)? 1:0)), new Dimension(1,1), new Point(x,y)));
}
System.out.println("Set refreshed.");
}

I suppose that cells is some kind of List implementation?
In that case, the most time of your refresh method is spent in this line:
cells.set(cells.indexOf(c), new Cell(Color.getHSBColor(i % 256, i % 255, 255 * ((i<20)? 1:0)), new Dimension(1,1), new Point(x,y)));
More precisely in cells.indexOf(c), where the entire list is iterated to find the correct index of c.
Since you are just changing the colour of each cell, the easiest fix is to change the colour of the cell you are currently working with. I don't know the actual implementation of your Cell class, but if it had a method setColor(...), you could replace the above line with
c.setColor(Color.getHSBColor(i % 256, i % 255, 255 * ((i<20)? 1:0)));
This reduces the runtime of the refreshMandelbrot method to the same as for the genMandelbrot method.
I don't know the purpose of the Cell class, but if you are only using it as a wrapper for a colour, you might gain some more performance if you store the computed colours for each pixel in a two-dimensional array or write directly to a Graphics or Raster object instead of handling a flat list of cell wrappers.

Most likely you need to subdivide the fractal and compute the less interesting tiles less intense. 8000 repetiton is a lot. You can also simplify the calculation a bit.

Related

Trying to get divisor that produces a quotient within a range

This is for a visualization I am working on. I want to divide a rectangle in N equal parts. I want these parts to have a width of say (min. 1px, max 1.5px), depending on the width of the rectangle and I want this division to end with a remainder of 0 (so I don't have a larger than the rest part).
I have tried implementing Modulo: https://processing.org/reference/modulo.html but I am not sure this is the correct way. Any ideas?
//Generates coordinates within each line.
for (int j = 0; j < line_coordinates.length; j++) {
//Positions start of line draw on random X coordinate.
float xv = component_x1 + (j * (component_length / line_coordinates.length+1));
float yv = line_height;
//Defines available with for each item in a component.
float item_availablewidth = component_length / line_coordinates.length+1;
//Creates vector with X coordinate and Y noise affected coordinate.
line_coordinates[j] = new PVector(xv, y);
rectMode(CENTER);
noStroke();
fill(232, 45, 34);
rect(line_coordinates[j].x,
line_coordinates[j].y - (line_height / 2),
item_availablewidth * item_randomwidthcoefficient,
line_height);
println("line_coordinates[j].x1",
line_coordinates[j].x - ((item_availablewidth * item_randomwidthcoefficient) / 2)); //This is where X starts.
println("line_coordinates[j].x2",
line_coordinates[j].x + ((item_availablewidth * item_randomwidthcoefficient) / 2)); //This is where X is supposed to end.
//This is the first method I tried but I found out this separation needs to be dynamic.
float drawnline_separation = 2;
float drawnline_total = (item_availablewidth * item_randomwidthcoefficient) / drawnline_separation;
println("drawnline_total",
drawnline_total);
//For loop divides each item in vertical -axidrawable- lines separating them by a max
for (int l = 0; l <= drawnline_total; l++) {
float drawnline_x = lerp(line_coordinates[j].x - ((item_availablewidth * item_randomwidthcoefficient) / 2),
line_coordinates[j].x + ((item_availablewidth * item_randomwidthcoefficient) / 2),
l/drawnline_total);
println("drawnline_x", drawnline_x);
stroke(23);
noFill();
//Draws line.
line(drawnline_x,
line_coordinates[j].y,
drawnline_x,
line_coordinates[j].y + 25 );
}
}
//This is the print I am getting.
line_coordinates[j].x1 346.42535
line_coordinates[j].x2 353.44092
drawnline_total 3.5077777
drawnline_x 346.42535
drawnline_x 348.42535
drawnline_x 350.42535
drawnline_x 352.42535
I hope I am being clear! Please let me know if my explanation is very confusing.

Bilinear interpolation anomaly

I wrote a function that takes the subpixels of an image for the purpose of upscaling, and the subpixel is generated by bilinear interpolation, but I am having some weird artifacts.
Here is my code:
public static int getSubPixel(BufferedImage bi, double x, double y) {
float[] topleft = new Color(bi.getRGB((int) Math.floor(x), (int) Math.floor(y))).getColorComponents(null);
float[] topright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), (int) Math.floor(y))).getColorComponents(null);
float[] bottomleft = new Color(bi.getRGB((int) Math.floor(x), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
float[] bottomright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
for (int i = 0; i < 3; i++) {
topleft[i] *= topleft[i];
topright[i] *= topright[i];
bottomleft[i] *= bottomleft[i];
bottomright[i] *= bottomright[i];
}
double decX = x % 1;
double decY = y % 1;
double inv_DecX = 1 - decX;
double inv_DecY = 1 - decY;
float red = (float) Math.sqrt((topleft[0] * inv_DecX + topright[0] * decX) * inv_DecY + (bottomleft[0] * inv_DecX + bottomright[0] * decX) * decY);
float green = (float) Math.sqrt((topleft[1] * inv_DecX + topright[1] * decX) * inv_DecY + (bottomleft[1] * inv_DecX + bottomright[1] * decX) * decY);
float blue = (float) Math.sqrt((topleft[2] * inv_DecX + topright[2] * decX) * inv_DecY + (bottomleft[2] * inv_DecX + bottomright[2] * decX) * decY);
return new Color(red, green, blue).getRGB();
}
This is the result of scaling up a 16x16 image 20 times:
As you can see, there is weird streaking going on. I did go out of my way to square the colors before averaging, then taking the square root of the result, but something does not seem right here. Any insight?
PS: I understand functions already exist to do this. This is an educational exercise. I am trying to understand the process by doing it on my own.
The stripe artifacts that you are seeing are caused by the linear interpolation scheme. Your implementation is correct (except for the squaring, which is unnecessary and causes the stripes to be stronger in darker regions of the image). This is what I'm seeing with a correct linear interpolation (16x instead of 20x as in the OP, I goofed) but without squaring (note less stripes in the dark blue parts):
If you want to get rid of the stripes, use a better interpolation scheme, such as cubic spline interpolation:

Animation making a circle

I need to create an animation which it will make a full circle around another button.
Can i achieve this using classic animations?
Example giving many translates inside an xml file, with specific offset each one? Or i need to create a specific path for this? I'm new in java so i don't know how to start.
Please check image Below:
You need to understand some trigonometric functions.
/**
* #static
* Allows move in circles around given item
* #param r {float|int} radius in px
* #param angle {float|int} current angle between circle center and orbiting element
* #param orbit {object} orbiting el eg. $("#foo")
* #param speed {int} animation's speed
* #param [middle=$('#menubutton')] {object} middle of the circle
*/
static fMenu(r, angle, orbit, speed, middle = Menu.BUTTON) {
const BY = middle.position().top;
const BX = middle.offset().left;
const k = middle.width();
const KY = middle.height();
if (angle === 0) {
angle = 360;
}
const x = Math.cos(angle * Math.PI / 180) * r;
const y = Math.tan(Math.PI * angle / 180) * x;
$(orbit).animate({
top: (BY - y - KY / 2) + "px",
left: (BX + x + k / 2 - orbit.width() / 2) + "px",
opacity: "1"
}, speed);
}
And you shoud do it in loop or setTimeout/setInterval. I've made this code some time ago for jQuery, but you get the idea? - Most important are lines with Math.cos and Math.tan.

Strange wraping when rotating Bitmaps

I started developing a custom Image class for a game which consists of three basic fields, width, height and a unidimensional array of int's which represent the color in the following order ARGB.
About two days ago i started trying to rotate images, and i was able to do that by converting this to a BufferedImage, rotate using Graphics2D and transforming it back to my own Image class, however setRGB and getRGB seem to be too slow and when i have to rotate about 10-20 images of 64*64 pixels the computer starts to struggle to maintain the fps.
So naturally i started developing my own image rotation function and i found a great post on gamedev.stackexchange.
https://gamedev.stackexchange.com/questions/67613/how-can-i-rotate-a-bitmap-without-d3d-or-opengl
The answer explains clearly what i should do to rotate an image even with different rotation points (which i intend to implement later).
However when following a similar formula to the one he explained (I had to change due to using a different coordinate system)
i find myself getting a strange wrapping at the top
Example (55 degrees): http://i.imgur.com/BBq83wV.png (The Black area represents the image size)
So i tried to distanciate the image from the top, and added
yDstPixel += this.height*sin;
Which sorta worked, but now the image gets clipped in half instead of wrapped
Example (35 degrees):http://i.imgur.com/Ap4aqrn.png
I'm almost sure the solution is very simple, but i cant seem to figure it out, a nudge in the right direction would be appreciated.
public Bitmap getRotatedCopy(double radians){
if(radians==0 || radians==(2*Math.PI)) return this;
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
int newWidth = (int) (this.width * cos + this.height * sin);
int newHeight = (int) (this.width * sin + this.height * cos);
Bitmap returnMap = new Bitmap(newWidth,newHeight); //set size of the returned bitmap to the smallest size possible
returnMap.fill(0xFF000000);
for (int y = 0; y < this.height; y++){
for(int x = 0; x < this.width; x++){
int srcPixel = x + (y * this.width);
int color= this.pixels[srcPixel];
if(color>0) continue;
int xDstPixel = (int) Math.abs((x * cos + y * sin));
int yDstPixel = (int) Math.abs((x * sin - y * cos));
//yDstPixel += this.height*sin;
int dstPixel = xDstPixel + (yDstPixel * newWidth);
returnMap.pixels[dstPixel]=color;
}
}
return returnMap;
}
You'll need to implement what you were planning to do later i.e. set the rotation origin and translation after the rotation.
I have modified your code to add them. (I didn't test running it but hope it works.) Please refer to the code below:
int newWidth = (int) (this.width * cos + this.height * sin);
int newHeight = (int) (this.width * sin + this.height * cos);
// After setting the new width and height...
// set rotation origin
double rox = this.width/2;
double roy = this.height/2;
// set translation center
double tcx = newWidth/2;
double tcy = newHeight/2;
Bitmap returnMap = new Bitmap(newWidth,newHeight);
returnMap.fill(0xFF000000);
for (int y = 0; y < this.height; y++){
double yy = y - roy;
for(int x = 0; x < this.width; x++){
double xx = x - rox;
int srcPixel = x + (y * this.width);
int color= this.pixels[srcPixel];
if(color>0) continue;
// following two lines are modified
int xDstPixel = (int) (xx * cos + yy * sin) + tcx;
int yDstPixel = (int) (xx * sin - yy * cos) + tcy;
// prevent negative index : maybe it is not needed at all
if (xDstPixel<0 || yDstPixel<0)
continue;
int dstPixel = xDstPixel + (yDstPixel * newWidth);
returnMap.pixels[dstPixel]=color;
}
}

Minimap causing lag

I make a minimap like this:
public void createMinimap() {
for (int i = 0; i < tilearray.size(); i++) {
float tileX = (200 * tilearray.get(i).getX()) / (getmWidth() * 64);
float tileY = (100 * tilearray.get(i).getY()) / (getmHeight() * 64);
final Rectangle tileRect = new Rectangle(tileX + 590, tileY + 380,
(64 * 200) / (getmWidth() * 64) + (float) 1, (64 * 100)
/ (getmHeight() * 64) + (float) 1, vbom);
tileRect.setColor(Color.WHITE);
tileRect.setAlpha(.7f);
gameHUD.attachChild(tileRect);
mapRectArray.add(tileRect);
}
}
And when I have lots of elements in tilearray, my game lags some. What is the reason for this?
As you are creating more number of tiles and Rectangle objects , it may effect loading.So, i can suggest you to load the resources before the game launches.Load these resources in back ground by placing loading screen.So, after loading all resources you can skip to Game

Categories