Find Two Points In A Three-Dimensional Space Nearest To Each Other - java

As the title suggests, I'm working on a homework assignment where we are limited to using multi-dimensional arrays in order to create a program that finds two points nearest to each other in a three dimensional space. So far my code looks like this (hybridized from examples in my textbook and my own code):
package exercise7_7;
public class Exercise7_7 {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.println("Enter the number of points:");
int numberOfPoints = input.nextInt();
double[][] points = new double[numberOfPoints][3];
System.out.println("Enter " + numberOfPoints + " points:");
for (int i = 0; i < points.length; i++) {
points[i][0] = input.nextDouble();
points[i][1] = input.nextDouble();
points[i][2] = input.nextDouble();
}
int p1 = 0, p2 = 1, p3 = 2;
double shortestDistance = distance(points[p1][0] , points[p1][1] , points[p1][2] ,
points[p2][0] , points[p2][1] , points[p2][2]);
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
double distance = distance(points[i][0] , points[j][0] , points[j][1] , points[j][2] , points[i][2] , points[j][2]);
if (shortestDistance > distance) {
p1 = i;
p2 = j;
shortestDistance = distance;
}
}
}
System.out.println("The closest two points are " + "(" + points[p1][0] + "," + points[p1][1] +
and (" + points[p2][0] + "," );
}
public static double distance(
double x1, double y1, double z1, double x2, double y2, double z2) {
return Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)) + ((z2 - z1) * (z2 - z1)));
}
}
What I mostly need help with is figuring out just how to get these points compared. I don't think the way I tackled this problem was the best way to do it.
Thanks for the help guys. I'm running on 2 hours of sleep for 2 days now so please excuse any stupid questions or sloppy code.
******
I think I've got it:
package exercise7_7;
public class Exercise7_7 {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.println("Enter the number of points:");
int numberOfPoints = input.nextInt();
double[][] points = new double[numberOfPoints][3];
System.out.println("Enter " + numberOfPoints + " points:");
for (int i = 0; i < points.length; i++) {
points[i][0] = input.nextDouble();
points[i][1] = input.nextDouble();
points[i][2] = input.nextDouble();
}
int p1 = 0, p2 = 1;
double shortestDistance = distance(points[p1][0] , points[p1][1] , points[p1][2] ,
points[p2][0] , points[p2][1] , points[p2][2]);
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
double distance = distance(points[i][0] , points[j][0] , points[j][1] , points[j][2] , points[i][2] , points[j][2]);
if (shortestDistance > distance) {
p1 = i;
p2 = j;
shortestDistance = distance;
}
}
}
System.out.println("The closest two points are " + "(" + points[p1][0] + "," + points[p1][1] + "," + points[p1][2] +
") and (" + points[p2][0] + "," + points[p2][1] + "," + points[p2][2] + ")");
}
public static double distance(
double x1, double y1, double z1, double x2, double y2, double z2) {
return Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)) + ((z2 - z1) * (z2 - z1)));
}
}
Input is taken in, processed, and then outputs the two closest points. Just as a reference, when:
(-1,0,3),(-1,-1,-1),(4,1,1),(2,0.5,9),(3.5,1.5,3),(-1.5,4,2),(5.5,4,-0.5) are inputted, the outcome
seems to be (-1,0,3) and (4,1,1). Could someone confirm that for me.
If this isn't the way to follow up on my own question, I apologize. First day on these slopes and I'm still
learning the ropes.

Use a class to represent your points. This way to you have a distanceTo method that calculates and returns distance. Also you can have a toString method that prints out the point for display to the user. Taking your code rearranging yields this class:
public class ThreeDPoint {
final double x;
final double y;
final double z;
public ThreeDPoint(final double x, final double y, final double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double distanceto(final ThreeDPoint other) {
final double dx = other.x - x;
final double dy = other.y - y;
final double dz = other.z - z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
#Override
public String toString() {
return "{X=" + x + ",Y=" + y + ",Z=" + z + "}";
}
}
Now putting that together gives this, which is much more readable. I have removed the bit where you read points and used random numbers:
public static void main(String args[]) {
final ThreeDPoint[] points = new ThreeDPoint[5];
final Random random = new Random();
for (int i = 0; i < points.length; ++i) {
points[i] = new ThreeDPoint(random.nextInt(100), random.nextInt(100), random.nextInt(100));
}
//store min
double min = Double.POSITIVE_INFINITY;
int first = -1;
int last = -1;
for (int i = 0; i < points.length; ++i) {
for (int j = i + 1; j < points.length; ++j) {
final double d = points[i].distanceto(points[j]);
if (d < min) {
min = d;
first = i;
last = j;
}
}
}
System.out.println("The minimum distance is between point " + first + " and " + last + "(" + points[first] + " and " + points[last] + "). This distance is " + min + ".");
}
private static final class ThreeDPoint {
final double x;
final double y;
final double z;
public ThreeDPoint(final double x, final double y, final double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double distanceto(final ThreeDPoint other) {
final double dx = other.x - x;
final double dy = other.y - y;
final double dz = other.z - z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
#Override
public String toString() {
return "{X=" + x + ",Y=" + y + ",Z=" + z + "}";
}
}

Related

Saving a sequence of numbers to an array

There is a code for solving the Lorentz system, I need to save all the solutions x, y, z at each iteration in the corresponding array solutions, that is, 5000 solutions x, y, z put in an array, how is this best done? How to translate arrays to a string then?
public class Butterfly {
public static double dx(double x, double y, double z) {
return -10*(x - y);
}
public static double dy(double x, double y, double z) {
return -x*z + 28*x - y;
}
public static double dz(double x, double y, double z) {
return x*y - 8*z/3;
}
public static void main(String[] args) {
double x = 0.0, y = 20.0, z = 25.0; //
double dt = 0.001;
// uses Euler method
for (int i = 0; i < 5000; i++) {
//
double xnew = x + dx(x, y, z) * dt;
double ynew = y + dy(x, y, z) * dt;
double znew = z + dz(x, y, z) * dt;
x = xnew;
y = ynew;
z = znew;
double[][] xyzArray = new double[5000][3];
for (i = 0; i < xyzArray.length; i++) {
for (int j = 0; i < xyzArray.length; j++) {
xyzArray[i][j] = x;
}
}
for (i = 0; i < xyzArray.length; i++) {
for (int j = 0; i < xyzArray.length; j++) {
System.out.println(xyzArray[i][j]);
}
System.out.println();
}
}
}
}
Аfter editing the code the program displays 5000 times one value x, y, z, not all the values. I think that in this way lost the other solutions. After all, I have 5000 decisions of each variable, I need to save each...
// uses Euler method
double[][] xyzArray = new double[5000][3];
for (int i = 0; i < xyzArray.length; i++) {
for (i = 0; i < 5000; i++) {
double xnew = x + dx(x, y, z) * dt;
double ynew = y + dy(x, y, z) * dt;
double znew = z + dz(x, y, z) * dt;
xyzArray[i][0] = xnew;
xyzArray[i][1] = ynew;
xyzArray[i][2] = znew;
}
}
for (int i = 0; i < xyzArray.length; i++) {
System.out.println(xyzArray[i][0] + ", " + xyzArray[i][1] + ", " + xyzArray[i][2]);
}
}
after editing the following code is produced. 5,000 solutions of the first iteration are still output: it does not work in IDEAS or in jshell. I understand that the code is correct, but I can not understand why I get the wrong result
public class Butterfly {
public static double dx(double x, double y, double z) {
return -10 * (x - y);
}
public static double dy(double x, double y, double z) {
return -x * z + 28 * x - y;
}
public static double dz(double x, double y, double z) {
return x * y - 8 * z / 3;
}
public static void main(String[] args) {
double x = 0.0, y = 20.0, z = 25.0;
double dt = 0.001;
double[][] xyzArray = new double[5000][3];
for (int i = 0; i < xyzArray.length; i++) {
double xnew = x + dx(x, y, z) * dt;
double ynew = y + dy(x, y, z) * dt;
double znew = z + dz(x, y, z) * dt;
xyzArray[i][0] = xnew;
xyzArray[i][1] = ynew;
xyzArray[i][2] = znew;
}
for (int i = 0; i < xyzArray.length; i++) {
System.out.println(xyzArray[i][0] + ", " + xyzArray[i][1] + ", " + xyzArray[i][2]);
}
}
}
You've declared your array inside the loop. You don't want to create 5000 copies of your array of 5000 data points! You want only 1 array of 5000 data points, so you need to declare and create the array outside the loop.
double[][] xyzArray = new double[5000][3];
// uses Euler method
for (int i = 0; i < xyzArray.length; i++) {
// ... compute xnew, ynew, znew ... etc ...
Once you've got your new values for the current step, you want to save them in the [i]-th entry of your array. You'll store x in the [i][0] sub-entry, y in the [i][1] sub-entry, and z in the [i][2] sub-entry.
xyzArray[i][0] = xnew;
xyzArray[i][1] = ynew;
xyzArray[i][2] = znew;
To print the values out after all values have been computed:
} // end of Euler method loop
for (int i = 0; i < xyzArray.length; i++) {
System.out.println(xyzArray[i][0] + ", " + xyzArray[i][1] +", " + xyzArray[i][2]);
}
Your revision 3 code works.
View your revision 3 code
Copy the program text
Paste it in a jshell
Execute it with Butterfly.main(new String[] {})
And you will see your 5000 x,y,z values -- all different.
C:\>"\Program Files\Java\jdk-10\bin\jshell.exe"
| Welcome to JShell -- Version 10
| For an introduction type: /help intro
jshell> public class Butterfly {
...>
...> public static double dx(double x, double y, double z) {
...> return -10*(x - y);
[... many lines omitted for brevity ...]
...> }
...> }
...> }
| created class Butterfly
jshell> Butterfly.main(new String[] {})
0.2, 19.98, 24.933333333333334
0.39780000000000004, 19.960633333333334, 24.870840444444443
0.5934283333333333, 19.9419174796712, 24.81245854319926
0.786913224796712, 19.92386713960567, 24.758126085937494
[... many lines omitted for brevity ...]
0.381817425662861, 0.5879585365342771, 12.654916756967012
0.38387883677157514, 0.59322959817818, 12.621394805096582
0.3859723443856412, 0.5985398896533907, 12.587965480571079
0.3880980198383187, 0.6038899688589537, 12.554628592467306
jshell>

Get all nearest points in array

I'v two dimensional array, am storing some points in it in order to get the nearest two points e.g :
"(-1, 3), (-1, -1), (1, 1), (2, 0.5) , (2, -1) , (3, 3) ,(4, 2) ,(4, 0.5)"
The result is : "(1.0, 1.0) and (2.0, 0.5)"
And that worked very-well:
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number of points");
int numberOfPoints = scanner.nextInt();
//setting number of rows, number of column is unable to change
double[][] points = new double[numberOfPoints][2];
for (int i = 0; i < points.length; i++) {
points[i][0] = scanner.nextDouble();
points[i][1] = scanner.nextDouble();
}
int point1 = 0, point2 = 1;
double shortestDistance = distance(points[point1][0], points[point1][1],
points[point2][0], points[point2][1]);
//get shortest distance
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
double distance = distance(points[i][0], points[i][1],
points[j][0], points[j][1]);
if (shortestDistance > distance) {
point1 = i;
point2 = j;
shortestDistance = distance;
}
}
}
System.out.println("The closest two points is" +
"(" + points[point1][0] + ", " + points[point1][1] + ") and (" +
points[point2][0] + ", " + points[point2][1] + ")");
}
public static double distance(double x1, double y1, double x2, double y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
Am trying to get all nearest points not only two points.
I'v tried to get it by this way, but it doesn't cover all cases and doesn't display all points:
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points.length; j++) {
if (distance(points[i][0], points[i][1],
points[j][0], points[j][1]) == shortestDistance)
System.out.println("The closest two points are " +
"(" + points[i][0] + ", " + points[i][1] + ") and (" +
points[j][0] + ", " + points[j][1] + ")");
}
}
Also I'v tried to initialize new array and store distance into it then sort it, but it's fail.
How i can display all nearest points?
Note:
I didn't find this question useful for me.
The following comment clarifies the actual goal of the question:
So you mean that when you've found the 2 points that are closest to each other ((1.0, 1.0) - (2.0, 0.5)), you want to eliminate those then find the next "pair" that are now closest to each other ((3.0, 3.0) - (4.0, 2.0)), then repeat ((2.0, -1.0) - (4.0, 0.5)), and finally get last remaining pair ((-1.0, 3.0) - (-1.0, -1.0))?
To do that, you should first create a Point class, so you can easily keep track of points that have already been used. You could use java.awt.geom.Point2D.Double if you don't want to write your own.
You should also create a class for tracking pairs of points, so you can easily sort the pairs by distance. It can be named anything, but I named it Distance below.
Now the logic is that you create a list of all the possible Distance objects, i.e. pairs of points. You then sort it by distance.
The first list element is now the pair that is nearest to each other. You then iterate the list to find the next pair of points that are nearest, skipping any that use points already used.
If more than one pair are equally "nearest", the logic below will just pick one of them. You can change that behavior once you define what should actually happen in that scenario.
public static void main(String[] args) {
double[][] pointValues = { {-1, 3}, {-1, -1}, {1, 1}, {2, 0.5}, {2, -1}, {3, 3}, {4, 2}, {4, 0.5} };
Point[] points = new Point[pointValues.length];
for (int i = 0; i < points.length; i++)
points[i] = new Point(pointValues[i][0], pointValues[i][1]);
List<Distance> distances = new ArrayList<>();
for (int i = 0; i < points.length; i++)
for (int j = i + 1; j < points.length; j++)
distances.add(new Distance(points[i], points[j]));
Collections.sort(distances);
Set<Point> used = new HashSet<>();
for (Distance distance : distances) {
if (! used.contains(distance.getPoint1()) && ! used.contains(distance.getPoint2())) {
System.out.println(distance);
used.add(distance.getPoint1());
used.add(distance.getPoint2());
}
}
}
public final class Point {
private final double x;
private final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
#Override
public String toString() {
return "(" + this.x + ", " + this.y + ")";
}
#Override
public int hashCode() {
return Double.hashCode(this.x) * 31 + Double.hashCode(this.y);
}
#Override
public boolean equals(Object obj) {
if (! (obj instanceof Point))
return false;
Point that = (Point) obj;
return (Double.doubleToLongBits(this.x) == Double.doubleToLongBits(that.x)
&& Double.doubleToLongBits(this.y) == Double.doubleToLongBits(that.y));
}
}
public final class Distance implements Comparable<Distance> {
private final Point p1;
private final Point p2;
private final double distance;
public Distance(Point p1, Point p2) {
this.p1 = p1;
this.p2 = p2;
this.distance = Math.hypot(p2.getX() - p1.getX(), p2.getY() - p1.getY());
}
public Point getPoint1() {
return this.p1;
}
public Point getPoint2() {
return this.p2;
}
public double getDistance() {
return this.distance;
}
#Override
public String toString() {
return String.format("%-12s - %-12s: %s", this.p1, this.p2, this.distance);
}
#Override
public int compareTo(Distance that) {
return Double.compare(this.distance, that.distance);
}
}
Output
(1.0, 1.0) - (2.0, 0.5) : 1.118033988749895
(3.0, 3.0) - (4.0, 2.0) : 1.4142135623730951
(2.0, -1.0) - (4.0, 0.5) : 2.5
(-1.0, 3.0) - (-1.0, -1.0): 4.0
First a optimizing trick: instead of distance, use its square (dropping taking the root).
public static double distance2(double x1, double y1, double x2, double y2) {
return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
}
Taking all nearest points one needs to maintain a list of (i, j).
List<int[]> nearestPointIndices = new ArrayList<>();
double shortestDistance2 = Double.MAX_VALUE;
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
double distance2 = distance2(points[i][0], points[i][1],
points[j][0], points[j][1]);
if (shortestDistance2 >= distance2) {
if (shortestDistance2 > distance2) {
nearestPointIndices.clear();
shortestDistance2 = distance2;
}
nearestPointIndices.add(new int[] { i, j });
}
}
}
That is one collects a list of nearest points upto (i, j) and
either clears that list on a more near point, or on the same near point add to the list.
Also worth mentioning is another the function of the Math class like sqrt:
public static double distance(double x1, double y1, double x2, double y2) {
return Math.hypot((x2 - x1), (y2 - y1)); // Hypotenuse sqrt(a² + b²).
}

Some print functions do not run in this calculation class. Why? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Alongside with my main class, i want to output the table with the points of the airfoil to the command line, but right now some of the system print functions aren't working. here is my calc class:
package airfoil;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class airfoil
{
private static final int numOfCoord = 250;
double dx = 1.0 / numOfCoord;
private double m; // maximum camber in % of chord
private double p; // chordwise position of max ord., 10th of chord
private double t; // thickness in % of the cord
private String nacaNum; // NACA number - 4 digits
private double[][] coordinates; // Coordinates of the upper half
// or lower half of the airfoil
private double[][] meanLine; // mean line coordinates
public airfoil(String number) {
nacaNum = number;
m = Double.parseDouble(nacaNum.substring(0,1)) / 100.0;
p = Double.parseDouble(nacaNum.substring(1,2)) / 10.0;
t = Double.parseDouble(nacaNum.substring(2,4)) / 100.0;
meanLine = new double[2][numOfCoord]; // x values row 0, y values row 1
// x upper = row 0,
// y upper = row 1,
// x lower = row 2,
// y lower = row 3
coordinates = new double [4][numOfCoord];
System.out.println("NACA: " + nacaNum);
System.out.println("Number of coordinates: " + numOfCoord);
calcMeanLine();
calcAirfoil();
}
/*
* Calculates the values for the mean line forward of the maximum
* ordinate and aft of the maximum ordinate.
*/
private void calcMeanLine() {
double x = dx;
int j = 0;
// fwd of max ordinate
while (x <= p) {
meanLine[0][j] = x;
meanLine[1][j] = (m / (p * p))*(2*p*x - (x*x));
x += dx;
j++;
}
// aft of max ordinate
while (x <= 1.0 + dx) {
meanLine[0][j] = x;
meanLine[1][j] = (m / ((1 - p) * (1 - p))) *
((1 - 2*p) + 2*p*x - x * x);
x += dx;
j++;
}
} // end calcMeanLine
/*
* Calculate the upper and lower coordinates of the airfoil surface.
*/
private void calcAirfoil() {
double theta; // arctan(dy_dx)
double dy; // derivative of mean line equation
double yt, ml; // thickness and meanline values, respectively
double x = dx; // x-value w.r.t. chord
int j = 0; // counter for array
// calculate upper/lower surface coordinates fwd of max ordinate
while (x <= p) {
dy = (m / (p*p)) * (2*p - 2*x);
theta = Math.atan(dy);
yt = thicknessEQ(x);
ml = meanLine[1][j];
// upper surface coordinates;
coordinates[0][j] = x - yt * Math.sin(theta);
coordinates[1][j] = ml + yt * Math.cos(theta);
// lower surface coordinates
coordinates[2][j] = x + yt*Math.sin(theta);
coordinates[3][j] = ml - yt * Math.cos(theta);
x += dx;
j++;
}
// calculate the coordinates aft of max ordinate
while (x <= 1.0 + dx) {
dy = (m / ((1 - p) * (1 - p))) * ((2 * p) - (2 * x));
theta = Math.atan(dy);
yt = thicknessEQ(x);
ml = meanLine[1][j];
// upper surface coordinates;
coordinates[0][j] = x - yt * Math.sin(theta);
coordinates[1][j] = ml + yt * Math.cos(theta);
// lower surface coordinates
coordinates[2][j] = x + yt * Math.sin(theta);
coordinates[3][j] = ml - yt * Math.cos(theta);
x += dx;
j++;
}
System.out.println("j = " + j);
} // end calcAirfoil
/*
* Thickness equation
*/
private double thicknessEQ(double x) {
return ((t / 0.2) * (0.2969 * Math.sqrt(x) - (0.126 * x) -
(0.3526 * x * x) + (0.28430 * x * x * x) -
(0.1015 * x * x * x * x)));
}
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
/*
* Return the coordinates array
*/
public double[][] getCoordinates() { return coordinates; }
public int getSize() { return numOfCoord; }
} // end Airfoil class
This part of the class is supposed to print a table, but it isnt doing anything:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
So what can I do to make these things print correctly?
Your System.out.println("Xu\tYu\tXl\tYl"); code prints the following: Xu Yu Xl Yl because you did not add any variables to it. You could change it to:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
System.out.println(str);
return str;
}
Anyway, don't print in toString() function. toString() shouldn't print anything, it should just return the String so that you can print it or do whatever you want with it.
Airfoil airfoil = new Airfoil(); // Yes, first letter uppercase recommended
// do stuff
System.out.println(airfoil.toString());
EDIT: It works for me (I think). I used the input 1000 (by the way, you should use try/catch for numbers with 3 characters or less or it will crash), and this is the output I got (only the beginning and ending), as it's long.
NACA: 1000
Number of coordinates: 250
j = 250
0.0040 0.0100 0.0040 0.0100
0.0080 0.0100 0.0080 0.0100
0.0120 0.0100 0.0120 0.0100
[...]
0.9920 0.0002 0.9920 0.0002
0.9960 0.0001 0.9960 0.0001
1.0000 -0.0000 1.0000 -0.0000
This is the toString() code used to make it work:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
// System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
And the main I used:
public static void main (String args[]){
Airfoil air = new Airfoil("1000");
System.out.println(air.toString());
}

Java Perlin Noise Implementation Problems

Hey stackoverflow community! I have been reading about perlin noise for the past 2 weeks and tried implementing it on my own in the most basic way. Even so, my program does not work. It outputs near similar looking results all the time and the persistence does not seem to change anything. Here is my code:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Noise extends JPanel{
public static int octaves = 4;
public static int size = 128;
public static float[][][] noise = new float[size][size][octaves];
public static float[][] perlinnoise = new float[size][size];
public static float p = (float) 1/4;
public static Random gen = new Random();
public static float GenerateNoise() {
return gen.nextFloat();
}
public static float SmoothNoise(int x, int y, int z) {
try{
float corners = (noise[x - 1][y - 1][z] + noise[x + 1][y - 1][z] + noise[x - 1][y + 1][z] + noise[x + 1][y + 1][z]) / 16;
float sides = (noise[x - 1][y][z] + noise[x + 1][y][z] + noise[x][y - 1][z] + noise[x][y + 1][z]) / 8;
float center = noise[x][y][z] / 4;
return corners + sides + center;
}catch(Exception e) {
return 0;
}
}
public static float InterpolatedNoise(float x, float y, int pX, int pY, int pZ) {
int intX = (int) x;
int intY = (int) y;
float fracX = x - intX;
float fracY = y - intY;
float v1 = SmoothNoise(pX, pY, pZ);
float v2 = SmoothNoise(pX + 1, pY, pZ);
float v3 = SmoothNoise(pX, pY + 1, pZ);
float v4 = SmoothNoise(pX + 1, pY + 1, pZ);
float i1 = Interpolate(v1, v2, fracX);
float i2 = Interpolate(v3, v4, fracX);
return Interpolate(i1, i2, fracY);
}
public static float Interpolate(float a, float b, float x) {
float ft = (float) (x * 3.1415927);
float f = (float) ((1 - Math.cos(ft)) * 0.5);
return (float) (a * (1 - f) + b * f);
}
public static float Perlin2D(float x, float y, int posX, int posY, int posZ) {
float total = 0;
for(int i = 0; i < octaves; i++) {
double f = Math.pow(2, i);
double a = Math.pow(p, i);
total = (float) (total + InterpolatedNoise((float)(x * f), (float)(y * f), posX, posY, posZ) * a);
}
return total;
}
public static void main(String [] args) {
for(int z = 0; z < octaves; z++) {
for(int y = 0; y < size; y++) {
for(int x = 0; x < size; x++) {
noise[x][y][z] = GenerateNoise();
}
}
}
for(int z = 0; z < octaves; z++) {
for(int y = 0; y < size; y++) {
for(int x = 0; x < size; x++) {
perlinnoise[x][y] = Perlin2D(x / (size - 1), y / (size - 1), x, y, z) / octaves;
}
}
}
JFrame f = new JFrame("Perlin Noise");
f.setSize(400, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new Noise());
f.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int y = 0; y < size; y++) {
for(int x = 0; x < size; x++) {
g.setColor(new Color(perlinnoise[x][y], perlinnoise[x][y], perlinnoise[x][y]));
g.fillRect(x * 2, y * 2, 2, 2);
}
}
repaint();
}
}
I do not understand why it is not working because it is exactly as the pseudo code in this article said to do it. Can anyone assist me in figuring this out? Thanks.
EDIT: Ok please can someone just explain the process required to do this PLEASE I am going crazy trying to figure this out. I have been trying to figure it out for the past 2 weeks and no one is giving me any help with it. Please if you know how to do this, please just explain it to me I would greatly appreciate it. Thanks.

Application not working as expected

I have a standalone Java application below that is:
Generating a random line
Applied to a 2D grid where each cell value is the distance along the line perpindicular to the line
Finds the rise/run and attempts to calculate the original linear equation from the grid
Applies new line to another grid and prints out the greatest difference compared to the first grid
I expected the two grids to have identical values. The gradient lines may be different since the lines can extend outside the area of the grid, but should be similar and in two cases identical.
So is the problem a poor understanding of math, a bug in my code or a misunderstanding of floating point values?
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
import java.util.Iterator;
import java.util.ArrayList;
public final class TestGradientLine {
private static int SIZE = 3;
public TestGradientLine() {
super();
}
//y = mx + b
//b = y - mx
//m is rise / run = gradient
//width and height of bounding box
//for a box 10x10 then width and height are 9,9
public static Line2D getGradientLine(double run, double rise, double width, double height, double x, double y) {
if (run == 0 && rise == 0) {
return new Line2D.Double(x, y, x + width, y + height);
}
//calculate hypotenuse
//check for a vertical line
if (run == 0) {
return new Line2D.Double(x, y, x, y + height);
}
//check for a horizontal line
if (rise == 0) {
return new Line2D.Double(x, y, x + width, y);
}
//calculate gradient
double m = rise / run;
Point2D start;
Point2D opposite;
if (m < 0) {
//lower left
start = new Point2D.Double(x, y + height);
opposite = new Point2D.Double(x + width, y);
} else {
//upper left
start = new Point2D.Double(x, y);
opposite = new Point2D.Double(x + width, y + height);
}
double b = start.getY() - (m * start.getX());
//now calculate another point along the slope
Point2D next = null;
if (m > 0) {
next = new Point2D.Double(start.getX() + Math.abs(run), start.getY() + Math.abs(rise));
} else {
if (rise < 0) {
next = new Point2D.Double(start.getX() + run, start.getY() + rise);
} else {
next = new Point2D.Double(start.getX() - run, start.getY() - rise);
}
}
final double actualWidth = width;
final double actualHeight = height;
final double a = Math.sqrt((actualWidth * actualWidth) + (actualHeight * actualHeight));
extendLine(start, next, a);
Line2D gradientLine = new Line2D.Double(start, next);
return gradientLine;
}
public static void extendLine(Point2D p0, Point2D p1, double toLength) {
final double oldLength = p0.distance(p1);
final double lengthFraction =
oldLength != 0.0 ? toLength / oldLength : 0.0;
p1.setLocation(p0.getX() + (p1.getX() - p0.getX()) * lengthFraction,
p0.getY() + (p1.getY() - p0.getY()) * lengthFraction);
}
public static Line2D generateRandomGradientLine(int width, int height) {
//so true means lower and false means upper
final boolean isLower = Math.random() > .5;
final Point2D start = new Point2D.Float(0, 0);
if (isLower) {
//change origin for lower left corner
start.setLocation(start.getX(), height - 1);
}
//radius of our circle
double radius = Math.sqrt(width * width + height * height);
//now we want a random theta
//x = r * cos(theta)
//y = r * sin(theta)
double theta = 0.0;
if (isLower) {
theta = Math.random() * (Math.PI / 2);
} else {
theta = Math.random() * (Math.PI / 2) + (Math.PI / 2);
}
int endX = (int)Math.round(radius * Math.sin(theta));
int endY = (int)Math.round(radius * Math.cos(theta)) * -1;
if (isLower) {
endY = endY + (height - 1);
}
final Point2D end = new Point2D.Float(endX, endY);
extendLine(start, end, radius);
return new Line2D.Float(start, end);
}
public static Point2D getNearestPointOnLine(Point2D end, Line2D line) {
final Point2D point = line.getP1();
final Point2D start = line.getP2();
double a = (end.getX() - point.getX()) * (start.getX() - point.getX()) + (end.getY() - point.getY()) * (start.getY() - point.getY());
double b = (end.getX() - start.getX()) * (point.getX() - start.getX()) + (end.getY() - start.getY()) * (point.getY() - start.getY());
final double x = point.getX() + ((start.getX() - point.getX()) * a)/(a + b);
final double y = point.getY() + ((start.getY() - point.getY()) * a)/(a + b);
final Point2D result = new Point2D.Double(x, y);
return result;
}
public static double length(double x0, double y0, double x1, double y1) {
final double dx = x1 - x0;
final double dy = y1 - y0;
return Math.sqrt(dx * dx + dy * dy);
}
public static void main(String[] args) {
final Line2D line = generateRandomGradientLine(SIZE, SIZE);
System.out.println("we're starting with line " + line.getP1() + " " + line.getP2());
double[][] region = new double[SIZE][SIZE];
//load up the region with data from our generated line
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
final Point2D point = new Point2D.Double(x, y);
final Point2D nearestPoint = getNearestPointOnLine(point, line);
if (nearestPoint == null) {
System.err.println("uh -oh!");
return;
}
final double distance = length(line.getP1().getX(),
line.getP1().getY(), nearestPoint.getX() + 1,
nearestPoint.getY() + 1);
region[x][y] = distance;
}
}
//now figure out what our line is from the region
double runTotal = 0;
double riseTotal = 0;
double runCount = 0;
double riseCount = 0;
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
if (x < SIZE - 1) {
runTotal += region[x + 1][y] - region[x][y];
runCount++;
}
if (y < SIZE - 1) {
riseTotal += region[x][y + 1] - region[x][y];
riseCount++;
}
}
}
double run = 0;
if (runCount > 0) {
run = runTotal / runCount;
}
double rise = 0;
if (riseCount > 0) {
rise = riseTotal / riseCount;
}
System.out.println("rise is " + rise + " run is " + run);
Line2D newLine = getGradientLine(run, rise, SIZE - 1, SIZE - 1, 0, 0);
System.out.println("ending with line " + newLine.getP1() + " " + newLine.getP2());
double worst = 0.0;
int worstX = 0;
int worstY = 0;
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
final Point2D point = new Point2D.Double(x, y);
final Point2D nearestPoint = getNearestPointOnLine(point, newLine);
if (nearestPoint == null) {
System.err.println("uh -oh!");
return;
}
final double distance = length(line.getP1().getX(),
line.getP1().getY(), nearestPoint.getX() + 1,
nearestPoint.getY() + 1);
final double diff = Math.abs(region[x][y] - distance);
if (diff > worst) {
worst = diff;
worstX = x;
worstY = y;
}
}
}
System.out.println("worst is " + worst + " x: " + worstX + " y: " + worstY);
}
}
I think I have fixed your program.
a) I took out the integer cast.
b) I removed all the 'x + 1' and 'x - 1' fudges you had used.
I think when dealing with floats and doubles, subtracting '1' from the end of a line is a No-No! What is 1 anyway? - it's ok to do this just before you plot it on the screen once it's an integer. But not while calculating! line length is a 'zero-based' quantity.
This version returns approx 4E-16 always.
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
import java.awt.geom.QuadCurve2D;
import java.util.Iterator;
import java.util.ArrayList;
public final class TestGradientLine {
private static int SIZE = 3;
public TestGradientLine() {
super();
}
//y = mx + b
//b = y - mx
//m is rise / run = gradient
//width and height of bounding box
//for a box 10x10 then width and height are 9,9
public static Line2D getGradientLine(double run, double rise, double width, double height, double x, double y) {
if (run == 0 && rise == 0) {
return new Line2D.Double(x, y, x + width, y + height);
}
//calculate hypotenuse
//check for a vertical line
if (run == 0) {
return new Line2D.Double(x, y, x, y + height);
}
//check for a horizontal line
if (rise == 0) {
return new Line2D.Double(x, y, x + width, y);
}
//calculate gradient
double m = rise / run;
Point2D start;
Point2D opposite;
if (m < 0) {
//lower left
start = new Point2D.Double(x, y + height);
opposite = new Point2D.Double(x + width, y);
} else {
//upper left
start = new Point2D.Double(x, y);
opposite = new Point2D.Double(x + width, y + height);
}
double b = start.getY() - (m * start.getX());
//now calculate another point along the slope
Point2D next = null;
if (m > 0) {
next = new Point2D.Double(start.getX() + Math.abs(run), start.getY() + Math.abs(rise));
} else {
if (rise < 0) {
next = new Point2D.Double(start.getX() + run, start.getY() + rise);
} else {
next = new Point2D.Double(start.getX() - run, start.getY() - rise);
}
}
final double actualWidth = width;
final double actualHeight = height;
final double a = Math.sqrt((actualWidth * actualWidth) + (actualHeight * actualHeight));
extendLine(start, next, a);
Line2D gradientLine = new Line2D.Double(start, next);
return gradientLine;
}
public static void extendLine(Point2D p0, Point2D p1, double toLength) {
final double oldLength = p0.distance(p1);
final double lengthFraction =
oldLength != 0.0 ? toLength / oldLength : 0.0;
p1.setLocation(p0.getX() + (p1.getX() - p0.getX()) * lengthFraction,
p0.getY() + (p1.getY() - p0.getY()) * lengthFraction);
}
public static Line2D generateRandomGradientLine(int width, int height) {
//so true means lower and false means upper
final boolean isLower = Math.random() > .5;
final Point2D start = new Point2D.Float(0, 0);
if (isLower) {
//change origin for lower left corner
start.setLocation(start.getX(), height );
}
//radius of our circle
double radius = Math.sqrt(width * width + height * height);
//now we want a random theta
//x = r * cos(theta)
//y = r * sin(theta)
double theta = 0.0;
if (isLower) {
theta = Math.random() * (Math.PI / 2);
} else {
theta = Math.random() * (Math.PI / 2) + (Math.PI / 2);
}
float endX = (float)(radius * Math.sin(theta));
float endY = (float)(radius * Math.cos(theta)) * -1;
if (isLower) {
endY = endY + (height );
}
final Point2D end = new Point2D.Float(endX, endY);
extendLine(start, end, radius);
return new Line2D.Float(start, end);
}
public static Point2D getNearestPointOnLine(Point2D end, Line2D line) {
final Point2D point = line.getP1();
final Point2D start = line.getP2();
double a = (end.getX() - point.getX()) * (start.getX() - point.getX()) + (end.getY() - point.getY()) * (start.getY() - point.getY());
double b = (end.getX() - start.getX()) * (point.getX() - start.getX()) + (end.getY() - start.getY()) * (point.getY() - start.getY());
final double x = point.getX() + ((start.getX() - point.getX()) * a)/(a+b);
final double y = point.getY() + ((start.getY() - point.getY()) * a)/(a+b);
final Point2D result = new Point2D.Double(x, y);
return result;
}
public static double length(double x0, double y0, double x1, double y1) {
final double dx = x1 - x0;
final double dy = y1 - y0;
return Math.sqrt(dx * dx + dy * dy);
}
public static void main(String[] args) {
final Line2D line = generateRandomGradientLine(SIZE, SIZE);
System.out.println("we're starting with line " + line.getP1() + " " + line.getP2());
double[][] region = new double[SIZE][SIZE];
//load up the region with data from our generated line
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
final Point2D point = new Point2D.Double(x, y);
final Point2D nearestPoint = getNearestPointOnLine(point, line);
if (nearestPoint == null) {
System.err.println("uh -oh!");
return;
}
final double distance = length(line.getP1().getX(),
line.getP1().getY(), nearestPoint.getX() ,
nearestPoint.getY() );
region[x][y] = distance;
}
}
//now figure out what our line is from the region
double runTotal = 0;
double riseTotal = 0;
double runCount = 0;
double riseCount = 0;
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
if (x < SIZE - 1) {
runTotal += region[x + 1][y] - region[x][y];
runCount++;
}
if (y < SIZE - 1) {
riseTotal += region[x][y + 1] - region[x][y];
riseCount++;
}
}
}
double run = 0;
if (runCount > 0) {
run = runTotal / runCount;
}
double rise = 0;
if (riseCount > 0) {
rise = riseTotal / riseCount;
}
System.out.println("rise is " + rise + " run is " + run);
Line2D newLine = getGradientLine(run, rise, SIZE, SIZE , 0, 0);
System.out.println("ending with line " + newLine.getP1() + " " + newLine.getP2());
double worst = 0.0;
int worstX = 0;
int worstY = 0;
for (int x = 0; x < SIZE; x++) {
for (int y = 0; y < SIZE; y++) {
final Point2D point = new Point2D.Double(x, y);
final Point2D nearestPoint = getNearestPointOnLine(point, newLine);
if (nearestPoint == null) {
System.err.println("uh -oh!");
return;
}
final double distance = length(line.getP1().getX(),
line.getP1().getY(), nearestPoint.getX() ,
nearestPoint.getY() );
final double diff = Math.abs(region[x][y] - distance);
if (diff > worst) {
worst = diff;
worstX = x;
worstY = y;
}
}
}
System.out.println("worst is " + worst + " x: " + worstX + " y: " + worstY);
}
}
why do you multiply by -1 at the end of this line?
int endY = (int)Math.round(radius * Math.cos(theta)) * -1;
this means that endY is always negative except radius is below 0. (cosinus always returns positive value)
is this intended or am i getting something wrong?
regards
You probably misunderstand float and/or double. This is a common problem with any language that implements the ieee spec for floats and doubles, which Java, C, C++ and just about every other language does.
Essentially
double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
System.out.println(val);
}
results in
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
And sometimes even worse. Either use BigDecimal, which alleviates a lot of the problem, or use integers.

Categories

Resources