I wrote a function which takes two parameters:
JPG image as 3D array
rotation degrees given by alpha
My approach was:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha);
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
for(int i = 0; i < height; i++) {
for(int j = height - i - 1; j < width; j++) {
if(j < height && i < width) {
double i_new = Math.floor(cos * (img[i].length - i) - sin * (img[j].length - j)) + i;
double j_new = Math.floor(sin * (img[i].length - i) + cos * (img[j].length - j)) + j;
rotate[i][j] = img[(int)j_new][(int)i_new];
}
}
}
return rotate;
}
While fixing the index range, the output is a black image. What am I missing?
After a while I got to a solution.
Caution: Its not using any special pre-defined libraries.
The global function which run`s over the matrice:
public static int[][] rotate(int[][] img, double alpha) {
double rad = Math.toRadians(alpha); //construct of the relevant angles
double sin = Math.sin(rad);
double cos = Math.cos(rad);
int height = img.length;
int width = img[0].length;
int[][] rotate = new int[height][width];
int a = height / 2; //we will use the area of a and b to compare coordinates by the formula given
int b = width / 2;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
double i_new = Math.floor(cos * (i - a) - sin * (j - b)) + a; // following the conversion function
double j_new = Math.floor(sin * (i - a) + cos * (j - b)) + b;
if (i_new >= rotate.length || i_new < 0 || j_new >= rotate[0].length || j_new < rotate[0][0]) { // if out of scope of the conversion --> print none
System.out.print(""); //mainly cause 'continue' statements are not necessary in java and JS
} else {
rotate[(int) i_new][(int) j_new] = img[i][j]; //convert
}
}
}
return rotate;
}
The global function which rotates each 2D matrice:
public static int[][][] rotate_alpha(int[][][] img, double alpha) {
int height = img[0].length;
int width = img[0][0].length;
int[][][] rotated = new int[3][height][width];
for (int k = 0; k < 3; k++) {
rotated[k] = rotate(img[k], alpha);
}
return rotated;
}
Hope this topic is solved by now, and stands by all the standards of the clean code.
Related
I've been given a 2D array of pixels and I am suppose to rotate this image based off of the pixel array about it's centermost point. I've tried to implement code which rotates the image based off of the rotation matrix, but I haven't been successful so far.
Current 2D Array Rotation Code:
int width = originalImage.length;
int height = originalImage[0].length;
final double angle = 90;
int[][] array = new int[width][height];
double c = Math.cos(Math.toRadians(angle));
double s = Math.sin(Math.toRadians(angle));
int x = width / 2;
int y = height / 2;
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
int xp = xx - x;
int yp = yy - y;
int xa = (int)((float)((float)xp * c - (float)yp * s));
int ya = (int)((float)((float)xp * s + (float)yp * c));
xa += x;
ya += y;
xp += x;
yp += y;
if(xa < width && ya < height) array[xa][ya] = originalImage[xp][yp];
//System.out.print("\n"+xa+" "+ya);
}
}
I've also tried this:
int[][] array = new int[originalImage.length][originalImage[0].length];
int xx = 0, yy = 0;
for (int x = originalImage.length - 1; x >= 0; x--) {
xx = 0;
for (int y = 0; y < originalImage[x].length; y++) {
//System.out.println(array[yy][xx]);
//System.out.println(originalImage[y][x]);
if (y < originalImage.length && x < originalImage[x].length) {
array[yy][xx] = originalImage[y][x];
//System.out.print(array[yy][xx]);
}
xx++;
}
yy++;
}
Are there any suggestion to how I can improve my code, or how this should be done?
since you are rotating by 90 degrees you can skip a bit
// origin to center point
int xp = xx - x;
int yp = yy - y;
// rotation and origin back to (0,0)
int x_rotated = -yp + y;
int y_rotated = xp + x;
//
array[x_rotated][y_rotated] = originalImage[xx][yy];
If you want to rotate in a different direction change
int x_rotated = yp + y;
int y_rotated = -xp + x;
I am new to Perlin noise and I have hit a roadblock. The perlin noise function I have translated from C++ seems to work correctly for one octave, however I have found that the lower octaves of noise aren't added to the original Perlin Noise. Here is my code:
public class Perlin {
float[][] generateWhiteNoise(int width, int height) {
Random random = new Random(0);
float[][] noise = new float[width][height];
for (int i = 0; i < noise.length; i++) {
for (int j = 0; j < noise[i].length; j++){
noise[i][j] = (float)random.nextDouble();
}
}
return noise;
}
float[][] generateSmoothNoise(float[][] baseNoise, int octave){
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][] smoothNoise = baseNoise;
int samplePeriod = (int) Math.pow(2,octave); // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++) {
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++){
//calculate the vertical sampling indices
int sample_j0 = (j / samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float interpolate(float x0, float x1, float alpha){
return (float) ((float)(x0) * (float)(1 - alpha) + (float)(alpha * x1));
}
float[][] generatePerlinNoise(float[][] baseNoise, int octaveCount) {
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = .5f;
//generate smooth noise
for (int i = 0; i<octaveCount; i++) {
System.out.println("Generating Smooth Noise: " + i);
smoothNoise[i] = generateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[width][height];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--) {
amplitude *= persistance;
totalAmplitude += amplitude;
System.out.println("Adding smooth noise for octave: " + octave + " at amplitude: " + amplitude);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalization
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
public float[][] printVals(float[][] baseNoise){
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
for(int i = 0; i<baseNoise.length; i++){
String row = "";
for(int j = 0; j<baseNoise[i].length;j++){
row+= (int)(baseNoise[i][j]*255) + " ";
}
System.out.println(row);
}
return baseNoise;
}
}
Here is the code in that I use to get values:
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
Here are the outputs at octaves 1,2,3, and 4
Any help would be appreciated!
Edit:
Through trial and error, I have found that the most likely area for there to be problems is in the generatePerlinNoise() function. If I change the octaves, I get the desired noise level, which is what I want. That also means that the generateWhiteNoise() and generateSmoothNoise() works. So, somewhere within the generatePerlinNoise() blending there is a problem, but it seems like it should work.
I have found an answer. I had thought that the generateSmoothNoise() command was going to give me multi-octave perlin noise. However, I realized that I needed to build another command similar to what happens with the blending of the smooth noise to blend my different octaves of perlin noise.
public float[][] generateMultiOctavePerlinNoise(int octaves, double persistence, double dropoff, int width, int height){
float[][][]noise = new float[octaves][width][height];
for(int i = octaves - 1; i > 0;i--){
noise[i] = generatePerlinNoise(generateWhiteNoise(width,height),octaves - i);
}
float[][] multiOctave = new float[width][height];
for(int a= 0; a<noise.length; a++){
persistence*= dropoff;
for(int i = 0; i<multiOctave.length; i++){
for(int j = 0; j<multiOctave[i].length; j++){
multiOctave[i][j] += noise[a][i][j]*persistence;
}
}
}
return multiOctave;
}
Recently I have been using the Polygon class to create asteroids as well as bullets and a spaceship. I am currently trying to create the collision detection for the program however it appears that the collision detection only works around 1/5 of the time (no pattern appears as to why it works).
Here's the code..
Creating the Polygon:
void renderPoly() {
int j;
int s = sides;
double r, angle;
int x, y;
for (j = 0; j < s; j++) {
angle = 2 * Math.PI / s * j;
r = MIN_ROCK_SIZE + (int) (Math.random() * (MAX_ROCK_SIZE - MIN_ROCK_SIZE));
x = (int) (r * Math.cos(angle));
y = (int) (r * -Math.sin(angle));
cOM[0] += x;
cOM[1] += y;
pointData[j][0] = x;
pointData[j][1] = y;
}
cOM[0] /= asteroidShape.npoints;
cOM[1] /= asteroidShape.npoints;
for (int i = 0; i < asteroidShape.npoints; i++) {
pointData[i][0] += cOM[0];
pointData[i][1] += cOM[1];
}
}
rotating and moving the polygon:
void move() {
int x, y, i;
//change rotation
theta += rotVel;
//change x
asteroidData[0] += deltaX;
//change y
asteroidData[1] += deltaY;
for (i = 0; i < asteroidShape.npoints; i++) {
x = (int) (pointData[i][0] * Math.cos(theta) - pointData[i][1] * Math.sin(theta) );
y = (int) (pointData[i][0] * Math.sin(theta) + pointData[i][1] * Math.cos(theta) );
asteroidShape.xpoints[i] = x + asteroidData[0];
asteroidShape.ypoints[i] = y + asteroidData[1];
asteroidShape.invalidate();
}
}
check if touching bullet:
boolean hitBullet(Bullet b) {
this.asteroidShape.invalidate();
for (int i = 0; i < b.bulletShape.npoints; i++)
if (this.asteroidShape.contains(b.bulletShape.xpoints[i], b.bulletShape.ypoints[i]) )
return true;
for (int j = 0; j < this.asteroidShape.npoints; j++)
if (b.bulletShape.contains(this.asteroidShape.xpoints[j], this.asteroidShape.ypoints[j]) )
return true;
return false;
}
(the ship method is the same except the constructor requires a ship object)
as well as the loop that calls it in the 'game' class:
for (int i = 0; i < aArray.length-1; i++) {
if (aArray[i] != null) {
for (int j = 0; j < bArray.length-1; j++) {
if (bArray[j] != null) {
if (aArray[i].hitBullet(bArray[j])) {
aArray[i] = null;
bArray[j] = null;
i = aArray.length-1;
j = bArray.length-1;
}
}
else {
i = aArray.length-1;
j = bArray.length-1;
}
}
}
else {
i = aArray.length-1;
}
}
I have been looking around at alternative solutions such as the Separating Axis Theorem however I do have convex polygons at times and since this method (.contains()) already exists I would like to use it.
Any help would be appreciated, thanks!
The easy way to solve this that I've found is to convert Shapes (in your case Polygon(2D?)) into Areas. You can use Area.intersect(Area) to see if two Areas have collided
I have been working with perlin noise recently and when implementing it into a tile engine I am using, I have noticed that the perlin noise function produced "blocks" as seen in the picture below. Each pixel is another different location in a 500 by 500 array that is returned from the perlin noise function.
in this example the persistence is 0.5 with an octave count of 5
When playing with it further, the more octaves I have, the larger the block chunks.
Here is the Code that I am using to call the perlin noise function:
PerlinNoise p = new PerlinNoise();
//returns a float[][] array of 500 by 500
p.GeneratePerlinNoise(p.genWhiteNoise(500, 500), 5, (float) 0.1);
PerlinNoise class
import java.util.Random;
public class PerlinNoise {
Random r;
public PerlinNoise() {
r = new Random();
}
public void setSeed(long seed) {
r.setSeed(seed);
}
public void printOutArray(float[][] arr) {
for(int i = 0; i < arr.length; i++) {
for(int n = 0; n < arr[0].length; n++) {
System.out.print(arr[i][n] + ", ");
}
System.out.print("\n");
}
}
public void printOutTerrain(float[][] arr) {
for(int i = 0; i < arr.length; i++) {
for(int n = 0; n < arr[0].length; n++) {
float a = arr[i][n];
if(a < 0.4) {
System.out.print("W");
} else {
System.out.print("L");
}
}
System.out.print("\n");
}
}
//-------------------------------------------------------------//
float[][] genWhiteNoise(int width, int height) {
float[][] noise = new float[height][width];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
noise[y][x] = r.nextFloat();
}
}
return noise;
}
float[][] genSmoothNoise(float[][] baseNoise, int octave) {
int height = baseNoise.length;
int width = baseNoise[0].length;
float[][] smoothNoise = new float[height][width];
int samplePeriod = 1 << octave; //calculates 2^k
float sampleFrequency = (float) (1.0/samplePeriod);
for(int i = 0; i < height; i++) {
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % height; //wrap around
float vertical_blend = (i - sample_i0) * sampleFrequency;
for(int n = 0; n < width; n++) {
int sample_n0 = (n / samplePeriod) * samplePeriod;
int sample_n1 = (sample_n0 + samplePeriod) % width; //wrap around
float horizontal_blend = (n - sample_n0) * sampleFrequency;
//blend the top two corners
float top = Interpolate(baseNoise[sample_i0][sample_n0],
baseNoise[sample_i1][sample_n0], horizontal_blend);
//blend the bottom two corners
float bottom = Interpolate(baseNoise[sample_i0][sample_n1],
baseNoise[sample_i1][sample_n1], horizontal_blend);
//final blend
smoothNoise[i][n] = Interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount, float persistance)
{
int height = baseNoise.length;
int width = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = genSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[height][width];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalisation
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
//linear average between two points
float Interpolate(float x0, float x1, float alpha)
{
return Cosine_Interpolate(x0, x1, alpha);
}
//Linear Interpolation
float Linear_Interpolate(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
//Cosine interpolation (much smoother)
float Cosine_Interpolate(float x0, float x1, float alpha)
{
float ft = (float) (alpha * 3.141592653589);
float f = (float) ((1 - Math.cos(ft)) * 0.5);
return x0*(1-f) + x1*f;
}
}
So to reiterate my question: Why is my perlin noise function behaving the way it does, as in only generating space in chunks?
So to fix this, all I had to do is swap the vertical_blend and horizontal_blend variables in the genSmoothNoise() method. It's amazing what you notice after a break
I'm trying to rotate a Bitmap where the pixels are stored in an Array int pixels[]. I got the following method:
public void rotate(double angle) {
double radians = Math.toRadians(angle);
double cos, sin;
cos = Math.cos(radians);
sin = Math.sin(radians);
int[] pixels2 = pixels;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++) {
int centerx = this.width / 2, centery = this.height / 2;
int m = x - centerx;
int n = y - centery;
int j = (int) (m * cos + n * sin);
int k = (int) (n * cos - m * sin);
j += centerx;
k += centery;
if (!((j < 0) || (j > this.width - 1) || (k < 0) || (k > this.height - 1)))
try {
pixels2[(x * this.width + y)] = pixels[(k * this.width + j)];
} catch (Exception e) {
e.printStackTrace();
}
}
pixels = pixels2;
}
But it just gives me crazy results. Does anyone know where the error is?
The line
int[] pixels2 = pixels;
is supposed to copy the array, but you are just copying the reference to it. Use pixels.clone(). In fact, you just need a new, empty array, so new int[pixels.lenght] is enough. In the end you need System.arraycopy to copy the new content into the old array.
There are other problems in your code -- you are mixing up rows and columns. Some expressions are written as though the image is stored row by row, others as if column by column. If row-by-row (my assumption), then this doesn't make sense: x*width + y. It should read y*width + x -- you are skipping y rows down and then moving x columns to the right. All in all, I have this code that works OK:
import static java.lang.System.arraycopy;
public class Test
{
private final int width = 5, height = 5;
private int[] pixels = {0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0};
public Test rotate(double angle) {
final double radians = Math.toRadians(angle),
cos = Math.cos(radians), sin = Math.sin(radians);
final int[] pixels2 = new int[pixels.length];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++) {
final int
centerx = this.width / 2, centery = this.height / 2,
m = x - centerx,
n = y - centery,
j = ((int) (m * cos + n * sin)) + centerx,
k = ((int) (n * cos - m * sin)) + centery;
if (j >= 0 && j < width && k >= 0 && k < this.height)
pixels2[(y * width + x)] = pixels[(k * width + j)];
}
arraycopy(pixels2, 0, pixels, 0, pixels.length);
return this;
}
public Test print() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
System.out.print(pixels[width*y + x]);
System.out.println();
}
System.out.println();
return this;
}
public static void main(String[] args) {
new Test().print().rotate(-45).print();
}
}
public void render(float nx, float ny, float nz, float size, float rotate) {
int wid = (int) ((width - nz) * size);
int hgt = (int) ((height - nz) * size);
if (wid < 0 || hgt < 0) {
wid = 0;
hgt = 0;
}
for (int x = 0; x < wid; x++) {
for (int y = 0; y < hgt; y++) {
double simple = Math.PI;
int xp = (int) (nx +
Math.cos(rotate) * ((x / simple) - (wid / simple) / 2) + Math
.cos(rotate + Math.PI / 2)
* ((y / simple) - (hgt / simple) / 2));
int yp = (int) (ny + Math.sin(rotate)
* ((x / simple) - (wid / simple) / 2) + Math.sin(rotate
+ Math.PI / 2)
* ((y / simple) - (hgt / simple) / 2));
if (xp + width < 0 || yp + height < 0 || xp >= Main.width
|| yp >= Main.height) {
break;
}
if (xp < 0
|| yp < 0
|| pixels[(width / wid) * x + ((height / hgt) * y)
* width] == 0xFFFF00DC) {
continue;
}
Main.pixels[xp + yp * Main.width] = pixels[(width / wid) * x
+ ((height / hgt) * y) * width];
}
}
}
This is only a new to rotating for me, but the process of this is that of a normal rotation. It still needs much fixing -- it's inefficient and slow. But in a small program, this code works. I'm posting this so you can take it, and make it better. :)