Perlin noise glitch - java

I have an infinite map generator. It works well with positive coordinates.
Positive coordinates generation 1
But on negative coordinates I have this trash:
Negative coordinates broken generation
2
void generateChunk(int x0, int y0) {
Chunk chunk = new Chunk(x0, y0);
for(int yTile = 0; yTile < Chunk.CHUNK_SIZE; yTile++) {
for(int xTile = 0; xTile < Chunk.CHUNK_SIZE; xTile++) {
int pX = chunk.x0 + xTile;
int pY = chunk.y0 + yTile;
double perlinNoiseHeight = floorPerlinNoise.getHeight(pX, pY);;
if(perlinNoiseHeight > BEACH_AREA) {
chunk.setFloor(GrassTile.ID, xTile, yTile);
} else if(perlinNoiseHeight > 0) {
chunk.setFloor(SandTile.ID, xTile, yTile);
} else {
chunk.setFloor(WaterTile.ID, xTile, yTile);
}
}
}
saveChunk(chunk);
}
Perlin noise class:
package org.ixnomad.game.level.generation;
public class PerlinNoise {
private double persistence, frequency, amplitude;
private int octaves;
private long seed;
public PerlinNoise(double persistence, double frequency, double amplitude, int octaves, long seed) {
this.persistence = persistence;
this.amplitude = amplitude;
this.frequency = frequency;
this.octaves = octaves;
this.seed = seed;
}
public double getHeight(double x, double y) {
return amplitude * total(x, y) + 0.4;
}
private double total(double i, double j) {
double total = 0.0d;
double _ampl = 1;
double _freq = frequency;
for(int k = 0; k < octaves; k++) {
total += getValue(j * _freq + seed, i * _freq + seed) * _ampl;
_ampl *= persistence;
_freq *= 2;
}
return total;
}
private double getValue(double x, double y) {
int xInt = (int) x;
int yInt = (int) y;
double xFrac = x - xInt;
double yFrac = y - yInt;
double n01 = noise(xInt-1, yInt-1);
double n02 = noise(xInt+1, yInt-1);
double n03 = noise(xInt-1, yInt+1);
double n04 = noise(xInt+1, yInt+1);
double n05 = noise(xInt-1, yInt );
double n06 = noise(xInt+1, yInt );
double n07 = noise(xInt , yInt-1);
double n08 = noise(xInt , yInt+1);
double n09 = noise(xInt , yInt );
double n12 = noise(xInt+2, yInt-1);
double n14 = noise(xInt+2, yInt+1);
double n16 = noise(xInt+2, yInt );
double n23 = noise(xInt-1, yInt+2);
double n24 = noise(xInt+1, yInt+2);
double n28 = noise(xInt , yInt+2);
double n34 = noise(xInt+2, yInt+2);
double x0y0 = 0.0625*(n01+n02+n03+n04) + 0.125*(n05+n06+n07+n08) + 0.25*(n09);
double x1y0 = 0.0625*(n07+n12+n08+n14) + 0.125*(n09+n16+n02+n04) + 0.25*(n06);
double x0y1 = 0.0625*(n05+n06+n23+n24) + 0.125*(n03+n04+n09+n28) + 0.25*(n08);
double x1y1 = 0.0625*(n09+n16+n28+n34) + 0.125*(n08+n14+n06+n24) + 0.25*(n04);
double v1 = interpolate(x0y0, x1y0, xFrac);
double v2 = interpolate(x0y1, x1y1, xFrac);
return interpolate(v1, v2, yFrac);
}
private double interpolate(double x, double y, double frac) {
double negFrac = 1.0 - frac;
double negFraqSqr = negFrac * negFrac;
double fac1 = 3.0 * negFraqSqr - 2.0 * negFraqSqr * negFrac;
double fracSqr = frac * frac;
double fac2 = 3.0 * fracSqr - 2.0 * fracSqr * frac;
return x * fac1 + y * fac2;
}
private double noise(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
int t = (n * (n * n * 15713 + 789221) + 1376312589) & 0x7fffffff;
return 1.0d - (double) (t * 0.931322574615478515625e-9);
}
}
I have tried to solve this problem for a whole day, but I don't know, what I'm doing wrong. I thought that the problem is in bit shift (private double noise(double x, double y)), but the problem doesn't depend on it.
I tried to use this Perlin's algoryth: https://mrl.nyu.edu/~perlin/noise/
But effect is the same.

Good morning, I probably have solved the problem :D Jush should sleep and reload brains)
Just use the max value the integer can bring and move generate coordinates to half :D
int maxint = 0x07fffffff;
double perlinNoiseHeight = floorPerlinNoise.getHeight(pX + (maxint >> 1), pY + (maxint >> 1));
That is a simple solution, but it works)
Negative coordinates

Related

Java, 3D prospective projection

I'm learning 3D rendering with java and I encountered a weird issue.
I'm able to rotate and display 3D objects to the screen. but when I tried to use prospective projection to show depth, the program freaks out. No errors or anything, but the depth seems to stretch incurability long. I narrowed the problem down to the perspective divide in the projection function.
Can anyone help?
public class Renderer extends JPanel{
public Renderer() {
}
double angle = 0;
double a;
double f;
double l;
double offSet;
public void update() {
angle += 0.03;
repaint();
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
for(Triangle element: MidService.mesh)
{
Vertex v1 = rotateY(element.v1);
Vertex v2 = rotateY(element.v2);
Vertex v3 = rotateY(element.v3);
v1 = projection(v1);
v2 = projection(v2);
v3 = projection(v3);
int offSet = (int) (MidService.displayX/2);
g2d.drawLine(offSet + v1.x, offSet + v1.y, offSet + v2.x, offSet + v2.y);
g2d.drawLine(offSet + v2.x, offSet + v2.y, offSet + v3.x, offSet + v3.y);
g2d.drawLine(offSet + v3.x, offSet + v3.y, offSet + v1.x, offSet + v1.y);
}
}
public Vertex projection(Vertex v)
{
a = MidService.displayY / MidService.displayX;
f = 1 / (Math.tan(MidService.fieldOfView/2));
l = MidService.Zfar / (MidService.Zfar - MidService.Znear);
offSet = MidService.Zfar / (MidService.Zfar - MidService.Znear) * MidService.Znear;
double x = (v.x * a * f);
double y = (v.y * f);
double z = (v.z * l - offSet);
double w = v.z;
//the if function below caused the issue
if(w != 0.0) {
x /= w;
y /= w;
z /= w;
}
return new Vertex((int)x, (int)y, (int)z);
}
public Vertex rotateY(Vertex v)
{
double x = v.x * Math.cos(angle) + v.z * Math.sin(angle);
double y = v.y;
double z = v.x * (-Math.sin(angle)) + v.z * Math.cos(angle);
return new Vertex((int)x, (int)y, (int)z);
}
//-------------------------------------------------------
public class MidService {
public static double displayX = 1000;
public static double displayY = 1000;
public static double fieldOfView = 180;
public static double Zfar = 10;
public static double Znear = 1;
public static ArrayList<Triangle> mesh = new ArrayList<>();
}
//---------------------------------------------
public class Driver {
public static void main(String[] args) {
Display display = new Display();
MidService.mesh.add(new Triangle(new Vertex(-100, 100, 100),
new Vertex(-100, -100, 100),
new Vertex(100, -100, 100)));
MidService.mesh.add(new Triangle(new Vertex(-100, 100, 100),
new Vertex(100, -100, 100),
new Vertex(100, 100, 100)));
Here's a video of it:[https://youtu.be/bFJLU5c3JE0]
A follow up to the perspective division issue. It turns out to be the inverse of the difference between camera distance and z coordinate. So instead of division by z, its 1/(distance - z)
Below is modification for Gaba Miau's matrix multiply function
Vertex Mult(float[][] mat,Vertex v){
float ver[] = {v.x,v.y,v.z,v.w};
float ans[] = {0,0,0,0};
for (int i=0;i<mat.length;i++){
for(int j=0;j<mat[0].length;j++){
ans[i] += mat[i][j] * ver[j];
}
}
float temp = 100/(500 - v.z);
if(temp != 0)
{
ans[0] *= temp;
ans[1] *= temp;
ans[2] *= temp;
}
Vertex vans = new Vertex((int)ans[0],(int)ans[1],(int)ans[2]);
vans.w =(int) ans[3];
return vans;
}
P.S. it's ans[i] += mat[i][j] * ver[j]; in the forloop
Firstly you should be using a graphics API like OpenGL or DirectX, secondly you should be using a math library like GLM that contains all the projection matrix formulas and other stuff. Thirdly, you shouldn't be using int as a datatype to store vertex data.
I made a few changes to your code so it doesn't freak out anymore.
The fov should be in the range(0.001,179.999), never 180, it is recommanded using 90 deg. Also the math function tan takes in radians not deg.
package Render;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.sound.midi.MidiDevice;
import javax.swing.JPanel;
import Beans.Triangle;
import Beans.Vertex;
import Utilities.MidService;
public class Renderer extends JPanel{
public Renderer() {
}
double angle = 0;
double a;
double f;
double l;
double offSet;
public void update() {
//angle += 0.03;
repaint();
}
float projMat[][]= {
{1f / ((float)Math.tan(MidService.fieldOfView/2f)),0,0,0},
{0,1f / ((float)Math.tan(MidService.fieldOfView/2f)),0,0},
{0,0,MidService.Zfar / (MidService.Zfar - MidService.Znear),1},
{0,0,-MidService.Zfar* MidService.Znear / (MidService.Zfar - MidService.Znear),0},
};
Vertex Mult(float[][] mat,Vertex v){
float ver[] = {v.x,v.y,v.z,v.w};
float ans[] = {0,0,0,0};
for (int i=0;i<mat.length;i++){
for(int j=0;j<mat[0].length;j++){
ans[i] += mat[i][j] * ver[i];
}
}
Vertex vans = new Vertex((int)ans[0],(int)ans[1],(int)ans[2]);
vans.w =(int) ans[3];
return vans;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
for(Triangle element: MidService.mesh)
{
Vertex v1 = rotateZ(element.v1);
Vertex v2 = rotateZ(element.v2);
Vertex v3 = rotateZ(element.v3);
v1 = rotateY(v1);
v2 = rotateY(v2);
v3 = rotateY(v3);
v1 = Mult(projMat,v1);
v2 = Mult(projMat,v2);
v3 = Mult(projMat,v3);
int offSet = (int) (MidService.displayX/2);
g2d.drawLine(offSet + (int)v1.x, offSet + (int)v1.y, offSet + (int)v2.x, offSet + (int)v2.y);
g2d.drawLine(offSet + (int)v2.x, offSet + (int)v2.y, offSet + (int)v3.x, offSet + (int)v3.y);
g2d.drawLine(offSet + (int)v3.x, offSet + (int)v3.y, offSet + (int)v1.x, offSet + (int)v1.y);
}
}
public Vertex projection(Vertex v)
{
a = MidService.displayY / MidService.displayX;
f = 1 / (Math.tan(MidService.fieldOfView/2));
l = MidService.Zfar / (MidService.Zfar - MidService.Znear);
offSet = MidService.Zfar / (MidService.Zfar - MidService.Znear) * MidService.Znear;
double x = (v.x * a * f);
double y = (v.y * f);
double z = (v.z * l - offSet);
double w = v.z;
if(w != 0.0) {
x /= w;
y /= w;
z /= w;
}
return new Vertex((int)x, (int)y, (int)z);
}
public Vertex rotateY(Vertex v)
{
double x = v.x * Math.cos(angle) + v.z * Math.sin(angle);
double y = v.y;
double z = v.x * (-Math.sin(angle)) + v.z * Math.cos(angle);
return new Vertex((int)x, (int)y, (int)z);
}
public Vertex rotateZ(Vertex v)
{
double x = v.x * Math.cos(angle) + v.y * (-Math.sin(angle));
double y = v.x * Math.sin(angle) + v.y * Math.cos(angle);
double z = v.z;
return new Vertex((int)x, (int)y, (int)z);
}
}
Here is the MidService class
package Utilities;
import java.util.ArrayList;
import Beans.Triangle;
public class MidService {
public static float displayX = 1000;
public static float displayY = 1000f;
public static float fieldOfView = 3.14f/2f;
public static float Zfar = 100f;
public static float Znear = 0.1f;
public static ArrayList<Triangle> mesh = new ArrayList<>();
}
And Vertex
package Beans;
public class Vertex {
public float x;
public float y;
public float z;
public float w = 1;
public Vertex(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}

Procedurally Generated Voronoi Roads

i'm using a noise function inspired by libnoiseforjava to try and generate roads. (See below)
public class VoronoiNoise {
private static final double SQRT_2 = 1.4142135623730950488;
private static final double SQRT_3 = 1.7320508075688772935;
private long seed;
private short distanceMethod;
private final double frequency;
public VoronoiNoise(long seed, double frequency, short distanceMethod) {
this.seed = seed;
this.distanceMethod = distanceMethod;
this.frequency = frequency;
}
private double getDistance(double xDist, double zDist) {
switch(distanceMethod) {
case 0: //EUCLIDIAN - Length
return Math.sqrt(xDist * xDist + zDist * zDist) / SQRT_2;
case 1: //???
return xDist + zDist;
case 2: //???
return Math.pow(Math.E, Math.sqrt(xDist * xDist + zDist * zDist) / SQRT_2)/Math.E;
case 3: //MANHATTAN
return Math.abs(xDist) + Math.abs(zDist);
case 4: //CHEBYCHEV
return Math.max(Math.abs(xDist), Math.abs(zDist));
case 5: //MINKOVSKI
return Math.pow(Math.pow(Math.abs(xDist), Math.PI) + Math.pow(Math.abs(zDist), Math.PI), (1 / Math.PI));
case 6: //MINKOVSKI4
return Math.pow(xDist*xDist*xDist*xDist+zDist*zDist*zDist*zDist,0.25);
default:
return 1.0;
}
}
private double getDistance(double xDist, double yDist, double zDist) {
switch(distanceMethod) {
case 0:
return Math.sqrt(xDist * xDist + yDist * yDist + zDist * zDist) / SQRT_3;
case 1:
return xDist + yDist + zDist;
default:
return 1.0;
}
}
public short getDistanceMethod() {
return distanceMethod;
}
public long getSeed() {
return seed;
}
public double noise(double x, double z) {
x *= frequency;
z *= frequency;
int xInt = (x > .0? (int)x: (int)x - 1);
int zInt = (z > .0? (int)z: (int)z - 1);
double minDist = 32000000.0;
double xCandidate = 0;
double zCandidate = 0;
double xCandidate2 = 0;
double zCandidate2 = 0;
Random random = new Random(seed);
long xSeed = random.nextLong();
long zSeed = random.nextLong();
for(int zCur = zInt - 2; zCur <= zInt + 2; zCur++) {
for(int xCur = xInt - 2; xCur <= xInt + 2; xCur++) {
double xPos = xCur + valueNoise2D(xCur, zCur, xSeed);
double zPos = zCur + valueNoise2D(xCur, zCur, zSeed);
double xDist = xPos - x;
double zDist = zPos - z;
double dist = xDist * xDist + zDist * zDist;
if(dist < minDist) {
xCandidate2 = xCandidate;
zCandidate2 = zCandidate;
xCandidate = xPos;
zCandidate = zPos;
minDist = dist;
}
}
}
double xDist = xCandidate - x;
double zDist = zCandidate - z;
//return getDistance(xDist, zDist);
return getDistance(xCandidate2 - x, zCandidate2 - z) - getDistance(xCandidate - x, zCandidate - z);
}
public double noise(double x, double y, double z) {
x *= frequency;
y *= frequency;
z *= frequency;
int xInt = (x > .0? (int)x: (int)x - 1);
int yInt = (y > .0? (int)y: (int)y - 1);
int zInt = (z > .0? (int)z: (int)z - 1);
double minDist = 32000000.0;
double xCandidate = 0;
double yCandidate = 0;
double zCandidate = 0;
Random rand = new Random(seed);
for(int zCur = zInt - 2; zCur <= zInt + 2; zCur++) {
for(int yCur = yInt - 2; yCur <= yInt + 2; yCur++) {
for(int xCur = xInt - 2; xCur <= xInt + 2; xCur++) {
double xPos = xCur + valueNoise3D (xCur, yCur, zCur, seed);
double yPos = yCur + valueNoise3D (xCur, yCur, zCur, rand.nextLong());
double zPos = zCur + valueNoise3D (xCur, yCur, zCur, rand.nextLong());
double xDist = xPos - x;
double yDist = yPos - y;
double zDist = zPos - z;
double dist = xDist * xDist + yDist * yDist + zDist * zDist;
if(dist < minDist) {
minDist = dist;
xCandidate = xPos;
yCandidate = yPos;
zCandidate = zPos;
}
}
}
}
double xDist = xCandidate - x;
double yDist = yCandidate - y;
double zDist = zCandidate - z;
return getDistance(xDist, yDist, zDist);
}
public void setDistanceMethod(short distanceMethod) {
this.distanceMethod = distanceMethod;
}
public void setSeed(long seed) {
this.seed = seed;
}
public static double valueNoise2D (int x, int z, long seed) {
long n = (1619 * x + 6971 * z + 1013 * seed) & 0x7fffffff;
n = (n >> 13) ^ n;
return 1.0 - ((double)((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
public static double valueNoise3D (int x, int y, int z, long seed) {
long n = (1619 * x + 31337 * y + 6971 * z + 1013 * seed) & 0x7fffffff;
n = (n >> 13) ^ n;
return 1.0 - ((double)((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
}
As you can see i've been calculating the Distance21 - the distance of the 1st minus the 2nd closest point. I've been using this along with Euclidian distance calculation to generate a noise map. Here is what I get:
I've then been checking whether the noise is below a certain value (black colours) and using that to place roads. One problem is that some of the cells are black, some blacker than the roads causing a mass of roads. Also, the roads are more than 1 unit in width which is unacceptable for my purposes.
Here is a chart of the different types of voronoi noise.
I was wondering if there is an algorithm for procedurally generating noise like this
Except that given a seed, a frequency and a point (x,y) it would return true or false whether or not the vertices pass through that point or not.
Creating lines
As a last resort I will use a repeating, static, image.
EDIT: I managed to do what i set out to do by checking if the 4 points around the point have a different closest point
I would still like to know if this is possible some other less intensive way.

Result of Quaternion Multiplication not yielding expected Rotation of local coordinate system

I'm getting unexpected results when multiplying two quaternions and applying the resulting rotation to my local right-handed coordinate system. (X pointing forward, Y to the right and Z downward).
(See my Java SCCE below)
So I am trying to first apply a Z rotation by 90 degrees (yaw) and then a rotation of 90 degrees around the local X axis (roll).
I am trying to accomplish this by multiplying two quaternions representing these two rotations, creating a rotation Matrix from the result and applying it to the 3 unit vectors of my coordinate system but the results I am getting do not make sense. (i.e. they do not represent the coordinate system you should get from these two rotations.)
I have tried changing the quaternion multiplication order which did not help (see code lines that were commented out in the main method of the SCCE).
I have also tried creating the quaternion for the second rotation from global Y to simulate that it was created from the resulting local coordinate system after the first rotation.
For reference I am also calculating the result by applying the two individual rotation matrices (which works as expected).
What am I doing wrong?
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class Quaternion {
public static final double NORMALIZATION_LOWER_TOLERANCE = 1 - 1e-4;
public static final double NORMALIZATION_UPPER_TOLERANCE = 1 + 1e-4;
private double w = 1.0;
private double x = 0.0;
private double y = 0.0;
private double z = 0.0;
public static void main(String[] args) {
Vector3D xVect = new Vector3D(1,0,0);
Vector3D yVect = new Vector3D(0,1,0);
Vector3D zVect = new Vector3D(0,0,1);
System.out.println("Initial Local Coordinate System: X:"+xVect+" / Y:"+yVect+ " / Z:"+zVect);
Quaternion rotZ = new Quaternion(Math.PI/2, zVect); // Yaw +90 deg
Quaternion rotY = new Quaternion(Math.PI/2, yVect); // Yaw +90 deg
Quaternion rotX = new Quaternion(Math.PI/2, xVect); // Then roll +90 deg
Matrix rotationMatrixZ = new Matrix(rotZ);
Vector3D localX = xVect.rotate(rotationMatrixZ);
Vector3D localY = yVect.rotate(rotationMatrixZ);
Vector3D localZ = zVect.rotate(rotationMatrixZ);
System.out.println("New Local Coordinate System after Yaw: X:"+localX+" / Y:"+localY+ " / Z:"+localZ); // Gives expected result
Quaternion localRotX = new Quaternion(Math.PI/2, localX);
Matrix localRotXMatrix = new Matrix(localRotX);
Vector3D rotatedX = localX.rotate(localRotXMatrix);
Vector3D rotatedY = localY.rotate(localRotXMatrix);
Vector3D rotatedZ = localZ.rotate(localRotXMatrix);
System.out.println("New Local Coordinate System two local rotations: X:"+rotatedX+" / Y:"+rotatedY+ " / Z:"+rotatedZ); // Gives expected result
Quaternion rotZX = rotZ.multiply(rotX);
// Quaternion rotZX = rotX.multiply(rotZ); // Tried both orders
// Quaternion rotZX = rotZ.multiply(rotY); // rotY is in fact the local rotX
// Quaternion rotZX = rotZ.multiply(rotY); // rotY is in fact the local rotX, tried both orders
rotZX.normalizeIfNeeded();
Matrix rotationXMatrixZX = new Matrix(rotZX);
rotatedX = xVect.rotate(rotationXMatrixZX);
rotatedY = localY.rotate(rotationXMatrixZX);
rotatedZ = localZ.rotate(rotationXMatrixZX);
System.out.println("New Local Coordinate System Quaternion Multiplication: X:"+rotatedX+" / Y:"+rotatedY+ " / Z:"+rotatedZ); // Expect same as above
}
public Quaternion() {
}
public Quaternion(double w, double x, double y, double z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
public Quaternion(double angle, Vector3D vector){
double halfAngle = angle / 2;
double sin = Math.sin(halfAngle);
this.w = Math.cos(halfAngle);
this.x = vector.getX()*sin;
this.y = vector.getY()*sin;
this.z = vector.getZ()*sin;
}
public boolean normalizeIfNeeded() {
double sum = w * w + x * x + y * y + z * z;
if (NORMALIZATION_LOWER_TOLERANCE < sum && sum < NORMALIZATION_UPPER_TOLERANCE) {
return false;
}
double magnitude = Math.sqrt(sum);
w /= magnitude;
x /= magnitude;
y /= magnitude;
z /= magnitude;
return true;
}
public Quaternion multiply(Quaternion q2) {
Quaternion result = new Quaternion();
result.w = w * q2.w - x * q2.x - y * q2.y - z * q2.z;
result.x = w * q2.x + x * q2.w + y * q2.z - z * q2.y;
result.y = w * q2.y - x * q2.z + y * q2.w + z * q2.x;
result.z = w * q2.z + x * q2.y - y * q2.x + z * q2.w;
return result;
}
public Quaternion conjugate() {
return new Quaternion(w, -x, -y, -z);
}
public double getW() {
return w;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
#Override
public String toString() {
return "Quaternion [w=" + w + ", x=" + x + ", y=" + y + ", z=" + z + "]";
}
static class Vector3D {
double x=0;
double y=0;
double z=0;
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3D rotate(Matrix rotationMatrix){
return rotationMatrix.multiply(this);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
#Override
public String toString() {
NumberFormat df = DecimalFormat.getNumberInstance();
return "[x=" + df.format(x) + ", y=" + df.format(y) + ", z=" + df.format(z) + "]";
}
}
static class Matrix {
private double[][] values;
public Matrix(int rowCount, int colCount) {
values = new double[rowCount][colCount];
}
public Matrix(Quaternion quaternionForRotationMatrix) {
this(3,3);
double w = quaternionForRotationMatrix.getW();
double x = quaternionForRotationMatrix.getX();
double y = quaternionForRotationMatrix.getY();
double z = quaternionForRotationMatrix.getZ();
double ww = w*w;
double wx = w*x;
double xx = x*x;
double xy = x*y;
double xz = x*z;
double wy = w*y;
double yy = y*y;
double yz = y*z;
double wz = w*z;
double zz = z*z;
values[0][0] = ww + xx - yy - zz;
values[0][1] = 2 * xy - 2 * wz;
values[0][2] = 2 * xz + 2 * wy;
values[1][0] = 2 * xy + 2 * wz;
values[1][1] = ww - xx + yy - zz;
values[1][2] = 2 * yz + 2 * wx;
values[2][0] = 2 * xz - 2 * wy;
values[2][1] = 2 * yz - 2 * wx;
values[2][2] = ww - xx - yy + zz;
}
public Vector3D multiply(Vector3D vector){
double [][] vect = new double [3][1];
vect[0][0] = vector.getX();
vect[1][0] = vector.getY();
vect[2][0] = vector.getZ();
double [][] result = multiplyMatrices(values, vect);
return new Vector3D(result[0][0], result[1][0], result[2][0]);
}
private double[][] multiplyMatrices(double[][] m1, double[][] m2) {
double[][] result = null;
if (m1[0].length == m2.length) {
int rowCount1 = m1.length;
int colCount1 = m1[0].length;
int rowCount2 = m2[0].length;
result = new double[rowCount1][rowCount2];
for (int i = 0; i < rowCount1; i++) {
for (int j = 0; j < rowCount2; j++) {
result[i][j] = 0;
for (int k = 0; k < colCount1; k++) {
result[i][j] += m1[i][k] * m2[k][j];
}
}
}
} else {
int rowCount = m1.length;
int colCount = m1[0].length;
result = new double[rowCount][colCount];
for (int i = 0; i < m1.length; i++) {
for (int j = 0; j < m1[0].length; j++) {
result[i][j] = 0;
}
}
}
return result;
}
#Override
public String toString() {
StringBuffer sb = new StringBuffer("Matrix = ");
for(int row = 0 ; row<values.length; row++){
sb.append ("[ ");
for(int col = 0 ; col<values[0].length; col++){
sb.append(Double.toString(values[row][col]));
if(col<values.length-1){
sb.append(" | ");
}
}
sb.append("] ");
}
return sb.toString();
}
}
}
Nevermind. Found it. I had an error in the formulas to build the rotation matrix. It now works as expected.
I am making a mental note to use formulas from Wikipedia in the future and not some random other site.
The respective part should be
values[0][0] = ww + xx - yy - zz;
values[0][1] = 2 * xy - 2 * wz;
values[0][2] = 2 * xz + 2 * wy;
values[1][0] = 2 * xy + 2 * wz;
values[1][1] = ww - xx + yy - zz;
values[1][2] = 2 * yz - 2 * wx; //CORRECTED SIGN
values[2][0] = 2 * xz - 2 * wy;
values[2][1] = 2 * yz + 2 * wx; //CORRECTED SIGN
values[2][2] = ww - xx - yy + zz;
At the end of the main method I was also using the wrong vectors for y and z:
Matrix rotationXMatrixZX = new Matrix(rotZX);
rotatedX = xVect.rotate(rotationXMatrixZX);
rotatedY = yVect.rotate(rotationXMatrixZX); // Corrected used y-vector
rotatedZ = zVect.rotate(rotationXMatrixZX); // Corrected used z-vector

Estimating Area Between Shapes

In my class, we are given the task as follows:
For this assignment you will attempt to make a program for computing the overlapping area of a set of shapes, implementing Monte Carlo integration, as discussed in class.
Make AreaEstimator.java, a program that estimates the area of overlap of an arbitrary number of circles and triangles using randomized estimation. The program's arguments will be the number of randomly-generated points to be used in this trial, followed by the coordinates of the points that define the shapes. For example,
java AreaEstimator 1000000 circle 2.0 2.0 1.0 triangle 1.0 1.0 2.5 3.0 2.0 -3.0 circle 2.5 1.0 3.0
would generate one million random points to estimate the overlap of a triangle whose vertices are ( 1.0, 1.0 ), ( 2.5, 3.0 ), ( 2.0, -3.0 ), with two circles whose centers are at ( 2.0, 2.0 ) and ( 2.5, 1.0 ), and whose radii are 1.0 and 3.0, respectively.
Here is my code for the Circle class:
public class Circle {
private double xcenter;
private double ycenter;
private double radius;
private double xcmax;
private double xcmin;
private double ycmax;
private double ycmin;
public Circle ( double xcenter, double ycenter, double radius){
if(radius <= 0){
throw new IllegalArgumentException();
}
this.xcenter = xcenter;
this.ycenter = ycenter;
this.radius = radius;
}
public void maxAndMinCircle (){ //find the minimun and maximum for the plane according to this circle
xcmax = (this.xcenter + this.radius);
ycmax = (this.ycenter + this.radius);
xcmin = (this.xcenter - this.radius);
ycmin = (this.ycenter - this.radius);
}
public double getXCMax (){
return xcmax;
}
public double getYCMax () {
return ycmax;
}
public double getXCMin() {
return xcmin;
}
public double getYCMin(){
return ycmin;
}
public boolean outsideCircle(double randX, double randY){ // find if the random point passed thru is in this circle
double distance = Math.sqrt((randX-this.xcenter)*(randX-this.xcenter) + (randY-this.ycenter) * (randY - this.ycenter));
return distance >= radius;
}}
The Triangle Class:
public class Triangle {
private double cornerx1;
private double cornery1;
private double cornerx2;
private double cornery2;
private double cornerx3;
private double cornery3;
private double xtmax;
private double xtmin;
private double ytmax;
private double ytmin;
private Double[] corners;
public Triangle (double cornerx1, double cornery1, double cornerx2, double cornery2, double cornerx3, double cornery3){
corners = new Double [6];
corners[0] = cornerx1;
corners[1] = cornery1;
corners[2] = cornerx2;
corners[3] = cornery2;
corners[4] = cornerx3;
corners[5] = cornery3;
}
public void maxAndMinTriangle (){ // find the minimum and maximum of the plane according to this triangle
xtmax = corners[0];
for(int i=1;i < corners.length;i += 2){
if(corners[i] > xtmax){
xtmax = corners[i];
}
}
xtmin = corners[0];
for(int i=1;i < corners.length;i += 2){
if(corners[i] < xtmin){
xtmin = corners[i];
}
}
ytmax = corners[1];
for(int i=1;i < corners.length;i += 2){
if(corners[i] > ytmax){
ytmax = corners[i];
}
}
ytmin = corners[1];
for(int i=1;i < corners.length;i += 2){
if(corners[i] < ytmin){
ytmin = corners[i];
}
}
}
public double getXTMax (){
return xtmax;
}
public double getYTMax () {
return ytmax;
}
public double getXTMin() {
return xtmin;
}
public double getYTMin(){
return ytmin;
}
//public static boolean isLeft (double x1, double y1, double x2, double y2, double x3, double y3){
//return ( 0 <= ( ( x2 - x1 ) * ( y - y1) )- (( y2 - y1) * ( x - x1)));
//}
public boolean isLeft1 (double randX, double randY){ // find if this point is to the left of the first line
return ( 0 <= ( ( corners[2] - corners[0] ) * ( randY - corners[1]) )- (( corners[3] - corners[1]) * ( randX - corners[0])));
}
public boolean isLeft2 (double randX, double randY){ // find if this point is to the left of the second line
return ( 0 <= ( ( corners[4] - corners[0]) * ( randY - corners[1]) )- (( corners[5] - corners[1]) * ( randX - corners[0])));
}
public boolean isLeft3 (double randX, double randY){ // find if this point is to the left of the third line
return ( 0 <= ( ( corners[4] - corners[2] ) * ( randY - corners[3]) )- (( corners[5] - corners[3]) * ( randX - corners[2])));
}
public boolean outsideTriangle ( double randX, double randY ){ // find if this point is inside of the triangle
int counter = 0;
if (isLeft1(randX,randY)){
counter++;
}
if (isLeft2(randX,randY)){
counter++;
}
if (isLeft3(randX,randY)){
counter++;
}
return counter == 2; // must be to the left of exactly 2 of the lines
}}
And then the AreaEstimator class:
public class AreaEstimator{
public static double[] maxAndMinValues (Circle[] circles,Triangle[] triangles){
// find maximum and minimum values according to all of the triangles and circles
double xmax = -100;
double ymax = -100;
double xmin = 100;
double ymin = 100;
for (int l=0; l < circles.length; l++){
if (xmax < circles[l].getXCMax()){
xmax = circles[l].getXCMax();
}
if (ymax < circles[l].getYCMax()){
ymax = circles[l].getYCMax();
}
if (xmin > circles[l].getXCMin()){
xmin = circles[l].getXCMin();
}
if (ymin > circles[l].getYCMin()){
ymin = circles[l].getYCMin();
}
}
for ( int m = 0; m < triangles.length; m++){
if(xmax < triangles[m].getXTMax()){
xmax = triangles[m].getXTMax();
}
if(ymax < triangles[m].getYTMax()){
ymax = triangles[m].getYTMax();
}
if(xmin > triangles[m].getXTMin()){
xmin = triangles[m].getXTMin();
}
if(ymin > triangles[m].getYTMin()){
ymin = triangles[m].getYTMin();
}
}
double[] result = new double [4];
result[0] = xmax;
result[1] = ymax;
result[2] = xmin;
result[3] = ymin;
return result;
}
public static void main (String[] args) {
double numThrows = Integer.parseInt(args[0]); // initialize amount of throws
if (numThrows <= 0){
throw new IllegalArgumentException();
}
int countCircles = 0; // find the amount of circles given
for ( int i = 1; i<args.length; i++){
if(args[i].equals("circle")){
countCircles++;
}
}
Circle[] circles = new Circle [countCircles];
for ( int i = 1; i<args.length; i++){
if (args[i].equals("circle")){
for ( int k = 0; k< countCircles; k++){
double xcenter = Double.parseDouble(args[i+1]);
double ycenter = Double.parseDouble(args[i+2]);
double radius = Double.parseDouble(args[i+3]);
circles[k] = new Circle (xcenter, ycenter, radius); //values associated with this circle
circles[k].maxAndMinCircle();//max and min value of the circle itself
}
}
}
int countTriangles = 0; // find the amount of the triangles given
for ( int i = 1; i < args.length; i++){
if(args[i].equals("triangle")){
countTriangles++;
}
}
Triangle[] triangles = new Triangle [countTriangles];
for ( int i = 1; i<args.length; i++){
if (args[i].equals("triangle")){
for ( int p = 0; p< countTriangles; p++){
double cornerx1 = Double.parseDouble(args[i+1]);
double cornery1 = Double.parseDouble(args[i+2]);
double cornerx2 = Double.parseDouble(args[i+3]);
double cornery2 = Double.parseDouble(args[i+4]);
double cornerx3 = Double.parseDouble(args[i+5]);
double cornery3 = Double.parseDouble(args[i+6]);
triangles[p] = new Triangle (cornerx1, cornery1, cornerx2, cornery2, cornerx3, cornery3);
//values associated with this triangle
triangles[p].maxAndMinTriangle(); //max and min value of the triangle itself
}
}
}
boolean dartsInOverlap = true;
double countInOverlap = 0; // initialize amount of darts in the overlapping shape
double[]result = maxAndMinValues(circles,triangles);
for(int i= 0;i < numThrows;i++){
double randX= (Math.random() * (result[0]-result[2]) + result[2]) ; // generate a random x value
double randY= (Math.random() * (result[1]-result[3])+ result[3]); // generate a random y value
for ( int h = 0; h < circles.length && dartsInOverlap; h++){
if (circles[h].outsideCircle(randX, randY)){
dartsInOverlap = false; // if the point is outside of the circle, it returns false
}
}
for ( int q = 0; q < triangles.length && dartsInOverlap; q++){
if (triangles[q].outsideTriangle(randX, randY)){
dartsInOverlap = false; // if the point is outside of the triangle, it returns false
}
}
if (dartsInOverlap){
countInOverlap++; // counts up the amount of points in the overlapping shape
}
dartsInOverlap = true;
}
System.out.println("This many darts were in the overlap between the shapes:" + countInOverlap);
// counts up the amount of points in the overlapping shape
System.out.println("The estimated overlapped areas is" + (result[0]-result[2])*(result[1]-result[3]) *(countInOverlap/numThrows));
//finds estimated area
}}
My code has worked for a few test cases, if in the command line there is only a circle and triangle entered, or only a sole circle. A triangle by itself or any other combination will give me answers far from the desired area estimation. I have looked and reviewed my code, and it all seems logical. So, where in my code could the problem persist? Any help would be appreciated.
There is at least a typo in maxAndMinTriangle. You wrote a 1 where you need a 0
xtmax = corners[0];
for(int i=1;i < corners.length;i += 2){
...
xtmin = corners[0];
for(int i=1;i < corners.length;i += 2){
it should be
xtmax = corners[0];
for(int i=0;i < corners.length;i += 2){
...
xtmin = corners[0];
for(int i=0;i < corners.length;i += 2){

Convert for loop into a recursive function

this is a homework problem. I'm having trouble converting the following into a recursive function:
public class Integrate {
public static double integrate(int a, int b, int steps)
{
double sum=0;
double delta = 1.0 * (b - a)/steps;
double x = a;
double f = 0.5*x*x + 3*x + 5;
for (int i = 0; i< steps; i++)
{
x = x + delta;
double fr = 0.5*x*x + 3*x + 5;
double area = f * delta + 0.5*(fr - f)*delta;
sum += area;
f = fr;
}
return sum;
}
public static void main(String [] args)
{
int a, b, step;
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]);
step = Integer.parseInt(args[2]);
System.out.format("Integral is %f\n", integrate(a,b,step));
}
}
This is what I have so far but the output is not the same as the original code. I can't figure out what is wrong
public class Integrate {
public static double integrate(int a, int b, int steps) {
double sum=0;
int i=0;
sum = rintegrate(a, b, steps, i, sum);
return sum;
}
public static double rintegrate(int a, int b, int steps,
int i, double sum) {
double delta = 1.0 * (b - a)/steps;
double x = a;
double f = 0.5*x*x + 3*x + 5;
if (i<steps) {
x = x + delta;
double fr = 0.5*x*x + 3*x + 5;
double area = f * delta + 0.5*(fr - f)*delta;
sum += area;
f = fr;
i++;
rintegrate(a, b, steps, i, sum);
}
return sum;
}
public static void main(String[] args) {
int a, b, step;
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]);
step = Integer.parseInt(args[2]);
System.out.format("Integral is %f\n", integrate(a,b,step));
}
}
I'm not going to fully analyze the problem, but here are some observations that I have
if (i<steps) {
x = x + delta;
double fr = 0.5*x*x + 3*x + 5;
double area = f * delta + 0.5*(fr - f)*delta;
sum += area;
f = fr;
i++;
rintegrate(a, b, steps, i, sum);
}
return sum;
everything between sum += area; and return sum; is superfluous.
you're setting f to fr, but you never even use f after that. if you want f to be different next time, maybe you can pass it as a parameter to your recursive function
you're recursively calling rintegrate(...), but you're not doing anything with the value it returns. you might want to use that value.
You should think about recursion as using a smaller version of a problem to solve itself.
Here's some code for your problem assuming that you have a function: segment that just calculates the size of the first segment given a, and delta
rintegrate(a, b, steps)
{
if(steps <= 1)
{
delta = b-a;
return segment(a, delta)
}
else
{
delta = (b-a)/steps
return segment(a, delta) + rintegrate(a+delta, b, steps-1)
}
}
Working version
Just copy paste and you will get the same output as your original method.
public static void main(String[] args) {
int a = 1, b = 10, step = 1000;
double delta = 1.0 * (b - a) / step;
double sum = integrate(a, b, step, 0, 0, 0, delta);
double test = working(a, b, step);
System.out.println("Integral is " + sum);
System.out.println("Integral is " + test);
}
The working recursive version:
public static double integrate(double x, int b, int steps, int i,
double sum, double f, double delta) {
f = 0.5 * x * x + 3 * x + 5;
if (i < steps) {
x = x + delta;
double fr = 0.5 * x * x + 3 * x + 5;
double area = f * delta + 0.5 * (fr - f) * delta;
return integrate(x, b, steps, i + 1, sum + area, fr, delta);
}
return sum;
}
Your original iterative method;
public static double working(int a, int b, int steps) {
double sum = 0;
double delta = 1.0 * (b - a) / steps;
double x = a;
double f = 0.5 * x * x + 3 * x + 5;
for (int i = 0; i < steps; i++) {
x = x + delta;
double fr = 0.5 * x * x + 3 * x + 5;
double area = f * delta + 0.5 * (fr - f) * delta;
sum += area;
f = fr;
}
return sum;
}
This is what you want ;)
public class Integrate{
/**
* #param args
*/
public static void main(String[] args) {
int a, b, step;
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]);
step = Integer.parseInt(args[2]);
System.out.format("Integral is %f\n",
adaptiveSimpsons(a, b, step));
}
private static double f(double i) {
return (0.5 * i * i + 3 * i + 5);
}
static double adaptiveSimpsons(double a, double b, // interval [a,b]
int maxRecursionDepth) { // recursion cap
double c = (a + b) / 2, h = b - a;
double fa = f(a), fb = f(b), fc = f(c);
double S = (h / 6) * (fa + 4 * fc + fb);
return adaptiveSimpsonsAux(a, b, S, fa, fb, fc, maxRecursionDepth);
}
private static double adaptiveSimpsonsAux(double a, double b, double S, double fa,
double fb, double fc, int bottom) {
double c = (a + b) / 2, h = b - a;
double d = (a + c) / 2, e = (c + b) / 2;
double fd = f(d), fe = f(e);
double Sleft = (h / 12) * (fa + 4 * fd + fc);
double Sright = (h / 12) * (fc + 4 * fe + fb);
double S2 = Sleft + Sright;
if (bottom <= 0)
return S2 + (S2 - S) / 15;
return adaptiveSimpsonsAux(a, c, Sleft, fa, fc, fd, bottom - 1)
+ adaptiveSimpsonsAux(c, b, Sright, fc, fb, fe, bottom - 1);
}
}
Tested and Working
Translated C code given here

Categories