Calculating Area in Java; Order of Operations - java

I'm trying to find the area of a Polygon using the following formula:
Area = r^2 n sin( 2 π / n) / 2
where n is the number of sides and r is the radius. I do not think my code is producing the correct result. If n= 6 and r = 4, i'm getting an area of 24. My code is as follows:
import java.math.*;
public class RegularPolygon {
private int n; // number of vertices
private double r; //radius of the polygon
/**
* This is the full constructor
* #param n is the number of vertices
* #param r is the radius
*/
public RegularPolygon(int n, double r) {
super();
this.n = n;
this.r = r;
}
/**
* default constructor. Sets number of sides and radius to zero
*/
public RegularPolygon() {
super();
this.n = 0;
this.r = 0;
}
//getters and setters for Number of vertices "n" and radius "r".
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
#Override
public String toString() {
return "RegularPolygon [n=" + n + ", r=" + r + "]";
}
public double area(){
float area;
//this method returns the area of the polygon
//Use Math.PI and Math.sin as needed
return area = (float) (Math.pow(r, 2)* n * ( Math.sin(Math.PI / n)/2));
It is unclear to me where my order of operations is messed up.

You're not translating the formula correctly. You need return Math.pow(r, 2) * n * Math.sin(2 * Math.PI / n) / 2; As forpas pointed out in the comments, you're missing a 2 and saying Math.sin(Math.PI / n) This has nothing to do with order of operations, since it's all just multiplication and division.

You should not type cast to float as you have declared the return type of the method as double
return Math.pow(r,2) * n * Math.sin(2 * Math.PI/n) / 2;
I think the above code will satisfy your need.

Related

Java Perlin Noise height map generation lacks desired randomness

I am trying to generate a height map using Perlin Noise, but am having trouble with generating truly unique maps. That is, each one is a minor variation of all the others. Two examples are below:
And here is my code (most was just copied and pasted from Ken Perlin's implementation, though adapted for 2D):
public class HeightMap {
private ArrayList<Point> map = new ArrayList<>();
private double elevationMax, elevationMin;
private final int[] P = new int[512], PERMUTATION = { 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
public HeightMap() {
this.map = null;
this.elevationMax = 0.0;
this.elevationMin = 0.0;
}
public HeightMap(HeightMap map) {
this.map = map.getPoints();
this.elevationMax = map.getElevationMax();
this.elevationMin = map.getElevationMin();
}
/**
* Generates a Height Map that is, along an imaginary z-axis, centered around the median elevation, given the following parameters:
* #param mapWidth the width [x] of the map
* #param mapHeight the height [y] of the map
* #param tileWidth the width [x] of each tile, or Point
* #param tileHeight the height [y] of each tile, or Point
* #param elevationMax the maximum elevation [z] of the map
* #param elevationMin the minimum elevation [z] of the map
*/
public HeightMap(int mapWidth, int mapHeight, int tileWidth, int tileHeight, double elevationMax, double elevationMin) {
this.elevationMax = elevationMax;
this.elevationMin = elevationMin;
for (int i=0; i < 256 ; i++) {
P[256+i] = P[i] = PERMUTATION[i];
}
int numTilesX = mapWidth / tileWidth;
int numTilesY = mapHeight / tileHeight;
Random r = new Random();
for (int t = 0; t < numTilesX * numTilesY; t++) {
double x = t % numTilesX;
double y = (t - x) / numTilesX;
r = new Random();
x += r.nextDouble();
y += r.nextDouble();
this.map.add(new Point(x, y, lerp(noise(x, y, 13), (elevationMin + elevationMax) / 2, elevationMax), tileWidth, tileHeight));
}
}
/**
* Ken Perlin's Improved Noise Java Implementation (https://mrl.cs.nyu.edu/~perlin/noise/)
* Adapted for 2D
* #param x the x-coordinate on the map
* #param y the y-coordinate on the map
* #param stretch the factor by which adjacent points are smoothed
* #return a value between -1.0 and 1.0 to represent the height of the terrain at (x, y)
*/
private double noise(double x, double y, double stretch) {
x /= stretch;
y /= stretch;
int X = (int)Math.floor(x) & 255, Y = (int)Math.floor(y) & 255;
x -= Math.floor(x);
y -= Math.floor(y);
double u = fade(x),
v = fade(y);
int AA = P[P[X ] + Y ],
AB = P[P[X ] + Y + 1],
BA = P[P[X + 1] + Y ],
BB = P[P[X + 1] + Y + 1];
return lerp(v, lerp(u, grad(P[AA], x, y), grad(P[BA], x - 1, y)), lerp(u, grad(P[AB], x, y - 1), grad(P[BB], x - 1, y - 1)));
}
private double fade(double t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
private double lerp(double t, double a, double b) {
return a + t * (b - a);
}
//Riven's Optimization (http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html)
private double grad(int hash, double x, double y) {
switch(hash & 0xF)
{
case 0x0:
case 0x8:
return x + y;
case 0x1:
case 0x9:
return -x + y;
case 0x2:
case 0xA:
return x - y;
case 0x3:
case 0xB:
return -x - y;
case 0x4:
case 0xC:
return y + x;
case 0x5:
case 0xD:
return -y + x;
case 0x6:
case 0xE:
return y - x;
case 0x7:
case 0xF:
return -y - x;
default: return 0; // never happens
}
}
}
Is this problem inherent in Perlin Noise because the 'height' is calculated from nearly the same (x, y) coordinate each time? Is there a way to implement the noise function so that it doesn't depend on the (x, y) coordinate of each point but still looks like terrain? Any help is greatly appreciated.
With some help from a friend of mine, I resolved the problem. Because I was using the same PERMUTATION array each generation cycle, the noise calculation was using the same base values each time. To fix this, I made a method permute() that filled PERMUTATION with the numbers 0 to 255 in a random, non-repeating order. I changed the instantiation of PERMUTATION to just be a new int[].
private final int[] P = new int[512], PERMUTATION = new int[256];
...
public void permute() {
for (int i = 0; i < PERMUTATION.length; i++) {
PERMUTATION[i] = i;
}
Random r = new Random();
int rIndex, rIndexVal;
for (int i = 0; i < PERMUTATION.length; i++) {
rIndex = r.nextInt(PERMUTATION.length);
rIndexVal = PERMUTATION[rIndex];
PERMUTATION[rIndex] = PERMUTATION[i];
PERMUTATION[i] = rIndexVal;
}
}

Given a set of points in 3d space, find all sets of points within a distance of eachother

I have a set of 3d points S.
I need to find the set X of all sets of points in S which are within manhattan distance d of each other.
i.e. for each set Y in X there exists atleast one point in 3d space that is within distance d of all points in Y
The length of set S will never be >20 but I will have to run this analysis on a stream of sets which are being produced at ~10 new sets per second, so whatever solution I use will have to be fairly efficient.
an example to help visualize the problem, given the following:
the output would be ((A,B), (B,C,E), (B,D,E))
we only care about the largest possible sets so the sets (B,C), (B,D), (B,E), (C,E) and (D,E), while within the given parameters, are not in the output given they are subsets of other sets in X
also this I'm doing this in java but any pointers in terms of algorithms or pseudo code would be greatly appreciated, thanks in advance.
A solution in pseudocode would be:
calculate_intersections(areas):
intersections = calculate every two intersecting areas
combinations = combine_intersections(intersections)
reduced = remove all sets in combinations that are included in bigger sets
combine_intersections(intersections):
do:
combinations = new HashSet
for s1 in intersections:
for s2 in intersections:
diff_1_2 = s1 \ s2
diff_2_1 = s2 \ s1
if diff_1_2.len == 1 && diff_2_1.len == 1:
union = diff_1_2 + diff_2_1
if union in intersections:
union2 = s1 + s2
if !union2 in intersections:
combinations.add(union)
while (combinations not empty)
An implementation in Java could look like this:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.collections4.SetUtils;
public class IntersectionSetCalculation {
private static class ManhattanDistanceArea {
private String id;
private Vector3D center;
private double distance;
public ManhattanDistanceArea(Vector3D center, double distance, String id) {
this.center = center;
this.distance = distance;
this.id = id;
}
#Override
public String toString() {
return id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((center == null) ? 0 : center.hashCode());
long temp;
temp = Double.doubleToLongBits(distance);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ManhattanDistanceArea other = (ManhattanDistanceArea) obj;
if (center == null) {
if (other.center != null)
return false;
}
else if (!center.equals(other.center))
return false;
if (Double.doubleToLongBits(distance) != Double.doubleToLongBits(other.distance))
return false;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}
public boolean intersects(ManhattanDistanceArea other) {
double maxDist = distance + other.distance;
return center.distance(other.center, 1) < maxDist;
}
}
/**
* Calculate the intersection of all areas (maximum of 2 areas in an intersection)
*/
public static Set<Set<ManhattanDistanceArea>> getIntersectingAreas(Set<ManhattanDistanceArea> areas) {
Set<Set<ManhattanDistanceArea>> intersections = new HashSet<Set<ManhattanDistanceArea>>();
for (ManhattanDistanceArea area : areas) {
for (ManhattanDistanceArea area2 : areas) {
if (!area.equals(area2) && area.intersects(area2)) {
HashSet<ManhattanDistanceArea> intersection = new HashSet<ManhattanDistanceArea>();
intersection.add(area);
intersection.add(area2);
intersections.add(intersection);
}
}
}
Set<Set<ManhattanDistanceArea>> combined = combineIntersections(intersections);
Set<Set<ManhattanDistanceArea>> reduced = reduceIntersections(combined);
return reduced;
}
/**
* Combine the small intersections (with a maximum of 2 areas in an intersection) to bigger intersections
*/
public static Set<Set<ManhattanDistanceArea>> combineIntersections(Set<Set<ManhattanDistanceArea>> inters) {
Set<Set<ManhattanDistanceArea>> intersections = new HashSet<Set<ManhattanDistanceArea>>(inters);
Set<Set<ManhattanDistanceArea>> combinations;
do {
combinations = new HashSet<Set<ManhattanDistanceArea>>();
for (Set<ManhattanDistanceArea> intersecting1 : intersections) {
for (Set<ManhattanDistanceArea> intersecting2 : intersections) {
Set<ManhattanDistanceArea> diff_1_2 = SetUtils.difference(intersecting1, intersecting2);
Set<ManhattanDistanceArea> diff_2_1 = SetUtils.difference(intersecting2, intersecting1);
if (diff_1_2.size() == 1 && diff_2_1.size() == 1) {
Set<ManhattanDistanceArea> union_1_2 = SetUtils.union(diff_1_2, diff_2_1);
if (intersections.contains(union_1_2)) {
Set<ManhattanDistanceArea> union = SetUtils.union(intersecting1, intersecting2);
if (!intersections.contains(union)) {
combinations.add(union);
}
}
}
}
}
intersections.addAll(combinations);
} while (!combinations.isEmpty());
return intersections;
}
/**
* Remove the small intersections that are completely covered by bigger intersections
*/
public static Set<Set<ManhattanDistanceArea>> reduceIntersections(Set<Set<ManhattanDistanceArea>> inters) {
Set<Set<ManhattanDistanceArea>> intersections = new HashSet<Set<ManhattanDistanceArea>>(inters);
Iterator<Set<ManhattanDistanceArea>> iter = intersections.iterator();
while (iter.hasNext()) {
Set<ManhattanDistanceArea> intersection = iter.next();
for (Set<ManhattanDistanceArea> intersection2 : inters) {
if (intersection2.size() > intersection.size() && intersection2.containsAll(intersection)) {
iter.remove();
break;
}
}
}
return intersections;
}
public static void main(String[] args) {
final double dist = 2d;//the manhattan distance d
ManhattanDistanceArea A = new ManhattanDistanceArea(new Vector3D(0, -3, 0), dist, "A");
ManhattanDistanceArea B = new ManhattanDistanceArea(new Vector3D(0, 0, 0), dist, "B");
ManhattanDistanceArea C = new ManhattanDistanceArea(new Vector3D(3.5, 0, 0), dist, "C");
ManhattanDistanceArea D = new ManhattanDistanceArea(new Vector3D(0, 3.5, 0), dist, "D");
ManhattanDistanceArea E = new ManhattanDistanceArea(new Vector3D(1, 1, 0), dist, "E");
ManhattanDistanceArea F = new ManhattanDistanceArea(new Vector3D(-1, 1, 0), dist, "F");
//test the example you provided
Set<ManhattanDistanceArea> abcde = new HashSet<ManhattanDistanceArea>();
abcde.addAll(Arrays.asList(new ManhattanDistanceArea[] {A, B, C, D, E}));
//test another example
Set<ManhattanDistanceArea> abcdef = new HashSet<ManhattanDistanceArea>();
abcdef.addAll(abcde);
abcdef.add(F);
Set<Set<ManhattanDistanceArea>> intersectionsABCDE = getIntersectingAreas(abcde);
Set<Set<ManhattanDistanceArea>> intersectionsABCDEF = getIntersectingAreas(abcdef);
System.out.println(intersectionsABCDE);
System.out.println(intersectionsABCDEF);
//test the runntime for 1000 calculation
double startTime = System.currentTimeMillis();
final int calculations = 1000;
for (int i = 0; i < calculations; i++) {
Set<ManhattanDistanceArea> areas = new HashSet<ManhattanDistanceArea>();
for (int j = 0; j < 20; j++) {
areas.add(new ManhattanDistanceArea(new Vector3D(Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 10 - 5), dist,
"A" + j));
}
getIntersectingAreas(areas);
}
System.out.println("\nTime used for " + calculations + " intersection calculations (with sets of size 20): "
+ (System.currentTimeMillis() - startTime) + "ms");
}
}
For the implementation I used this class Vector3D:
public class Vector3D {
public double x;
public double y;
public double z;
public static final Vector3D NAN_VEC = new Vector3D(Double.NaN, Double.NaN, Double.NaN);
public static final Vector3D NULL_VEC = new Vector3D(0, 0, 0);
public enum Axis {
X, Y, Z;
}
public Vector3D() {
}
/**
* Crate a new Vector2D with x and y components.
*/
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3D(double... val) {
x = val[0];
y = val[1];
z = val[2];
}
/**
* Create a Vector3D by two angles (in degree).
*
* The first angle is in XY direction. The second angle is the Z direction.
*
* An angle (XY) of 0° results in (x, y) = (1, 0); 90° in (x, y) = (0, 1); ... An angle (Z) of 0° results in (x, y, z) = (x, y, 0); 90° in (x, y,
* z) = (x, y, 1); -90° in (x, y, z) = (x, y, -1)
*
* The resulting vector has a length of 1.
*
* #param angleXY
* The angle of the new vector (in degree) for the XY direction (from 0 to 360).
*
* #param angleZ
* The angle of the new vector (in degree) for the Z direction (from -90 to 90).
*/
public Vector3D(double angleXY, double angleZ) {
x = Math.cos(angleXY * Math.PI / 180) * Math.cos(angleZ * Math.PI / 180);
y = Math.sin(angleXY * Math.PI / 180) * Math.cos(angleZ * Math.PI / 180);
z = Math.sin(angleZ * Math.PI / 180);
double len = length();
x /= len;
y /= len;
z /= len;
}
private Vector3D(Vector3D clone) {
this.x = clone.x;
this.y = clone.y;
}
#Override
public Vector3D clone() {
return new Vector3D(this);
}
#Override
public String toString() {
return "Vector3D[x: " + x + " y: " + y + " z:" + z + "]";
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Vector3D) {
Vector3D v = (Vector3D) obj;
return Math.abs(x - v.x) < 1e-8 && Math.abs(y - v.y) < 1e-8 && Math.abs(z - v.z) < 1e-8;
}
return false;
}
/**
* Get this vector as 3D-Array.
*/
public double[] asArray() {
return new double[] {x, y, z};
}
/**
* The (euclidean) length of the Vector.
*/
public double length() {
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
}
/**
* The length of this vector in a given norm.
*
* #param norm
* The norm of the vector length.
*
* #return The length of this vector in the given norm.
*/
public double length(int norm) {
if (norm == Integer.MAX_VALUE) {
return Math.max(Math.max(x, y), z);
}
return Math.pow(Math.pow(x, norm) + Math.pow(y, norm) + Math.pow(z, norm), 1.0 / norm);
}
/**
* Rotate this vector an angle (in degrees) around an axis resulting in a new Vector that is returned.
*
* #param degrees
* The angle to return the vector.
*
* #param axis
* The axis around which the vector is rotated.
*
* #return The new created vector.
*/
public Vector3D rotate(double degrees, Axis axis) {
double cos = Math.cos(degrees * Math.PI / 180);
double sin = Math.sin(degrees * Math.PI / 180);
switch (axis) {
case X:
return new Vector3D(x, cos * y - sin * z, sin * y + cos * z);
case Y:
return new Vector3D(cos * x + sin * z, y, -sin * x + cos * z);
case Z:
return new Vector3D(cos * x - sin * y, sin * x + cos * y, z);
default:
return null;
}
}
/**
* Project the vector given as parameter on this vector.
*
* #param vec
* The vector that is to be projected on this vector.
*
* #return The projected vector.
*/
public Vector3D project(Vector3D vec) {
return mult(scalar(vec) / Math.pow(length(), 2));
}
/**
* Add another Vector3D to this vector resulting in a new Vector that is returned.
*
* #param vec
* The vector added to this vector.
*
* #return The new created vector.
*/
public Vector3D add(Vector3D vec) {
return new Vector3D(x + vec.x, y + vec.y, z + vec.z);
}
/**
* Subtract another Vector3D from this vector resulting in a new Vector that is returned.
*
* #param vec
* The vector subtracted from this vector.
*
* #return The new created vector.
*/
public Vector3D sub(Vector3D vec) {
return new Vector3D(x - vec.x, y - vec.y, z - vec.z);
}
/**
* Multiply this vector with a scalar resulting in a new Vector that is returned.
*
* #param scalar
* The scalar to multiply this vector with.
*
* #return The new created vector.
*/
public Vector3D mult(double scalar) {
return new Vector3D(x * scalar, y * scalar, z * scalar);
}
/**
* Check whether this vector is linearly dependent to the parameter vector.
*
* #param vec
* The checked vector.
*
* #return True if the vectors are linearly dependent. False otherwise.
*/
public boolean isLinearlyDependent(Vector3D vec) {
double t1 = (x == 0 ? 0 : vec.x / x);
double t2 = (y == 0 ? 0 : vec.y / y);
double t3 = (z == 0 ? 0 : vec.z / z);
return Math.abs(t1 - t2) < 1e-5 && Math.abs(t1 - t3) < 1e-5 && t1 != 0;//all parameters t are equal and != 0
}
/**
* Calculate the scalar product of this vector and the parameter vector.
*
* #param vec
* The vector to calculate the scalar with this vector.
*
* #return The scalar of the vectors.
*/
public double scalar(Vector3D vec) {
return this.x * vec.x + this.y * vec.y + this.z * vec.z;
}
/**
* Calculate the cross product of this vector with another vector (resulting vector = this X parameter vector)
*
* #param vec
* The second vector for the cross product calculation.
*
* #return The cross product vector of the two vectors.
*/
public Vector3D cross(Vector3D vec) {
return new Vector3D(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x);
}
/**
* Create a new vector with the same direction but a different length as this vector.
*
* #param length
* The length of the new vector.
*
* #return The new vector with a new length.
*/
public Vector3D setLength(double length) {
double len = length();
return new Vector3D(x * length / len, y * length / len, z * length / len);
}
/**
* Get the distance of this point's position vector to another point's position vector.
*
* #param p
* The second point's position vector.
*
* #return The distance between the points.
*/
public double distance(Vector3D p) {
return Math.sqrt((this.x - p.x) * (this.x - p.x) + (this.y - p.y) * (this.y - p.y) + (this.z - p.z) * (this.z - p.z));
}
/**
* Get the distance of this point's position vector to another point's position vector in a given norm.
*
* #param p
* The second point's position vector.
*
* #param norm
* The norm in which the distance is calculated (1 -> manhattan, 2 -> euclide, ...)
*
* #return The distance between the points in the given norm.
*/
public double distance(Vector3D p, int norm) {
return Math.pow((Math.pow(Math.abs(this.x - p.x), norm) + Math.pow(Math.abs(this.y - p.y), norm) + Math.pow(Math.abs(this.z - p.z), norm)),
1d / norm);
}
/**
* Change this vector to the new coordinates.
*/
public void move(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Move a point's position vector in a direction (by a vector) and a distance.
*
* #param p
* The direction vector.
*
* #param distance
* The distance to move the new vector
*
* #return The new created vector.
*/
public Vector3D moveTo(Vector3D p, double distance) {
double d = distance(p);
double dx = p.x - x;
double dy = p.y - y;
double dz = p.z - z;
double coef = distance / d;
return new Vector3D(x + dx * coef, y + dy * coef, z + dz * coef);
}
/**
* Get the angle difference of this vector to another vector.
*
* #param vec
* The other vector.
*
* #return The angle difference of the two vectors (from 0° to 180°).
*/
public double getAngleTo(Vector3D vec) {
double angle = Math.acos(scalar(vec) / (length() * vec.length())) * 180 / Math.PI;
if (angle > 180) {
angle = 360 - angle;
}
return angle;
}
/**
* Get the vector from this point to another.
*
* #param vec
* The point to which the vector is calculated.
*
* #return The vector from this points position vector to the other point.
*/
public Vector3D vectorTo(Vector3D vec) {
return new Vector3D(vec.x - x, vec.y - y, vec.z - z);
}
/**
* Checks whether a point (by its position vector) is in a given range of this point.
*
* #param p
* The point that is checked.
*
* #param range
* The range used for the check.
*
* #return True if the point is in the range of this point (distance <= range).
*/
public boolean isInRange(Vector3D p, double range) {
return p != this && distance(p) <= range;
}
}
and the class SetUtils from the apache commons lib.
I also added some tests:
the test from your question
another test with a bigger intersection set
a test for the runtime
The results are:
[[A, B], [B, E, C], [B, E, D]]
[[A, B], [B, E, C], [D, E, F, B]]
Time used for 1000 intersection calculations (with sets of size 20):
791.0ms
So the results seem to be correct and you can calculate more than 1000 intersections in a second.
Exhaustive distance computation between 20 points, i.e. 190 distances is nothing for a PC. Time will measure in microseconds. You can draw the desired information from the "close to" relation encoded in a matrix.

Project Tango: Determine whether an IntersectionPointPlaneModelPair is aligned with Gravity

Spoiler Alert: I am not sure whether or not I am using Quaternions in the correct way.
I have an IntersectionPointPlaneModelPair pair from using the TangoSupport.fitPlaneModelNearClick(...) method. I would now like to find out whether or not this plane is aligned with Gravity (more or less). My approach was to create a Quaternion (Rajawali) from the pair.planeModel and another from ScenePoseCalculator.TANGO_WORLD_UP and a rotation of 0.0, multiply them and determine the angle between the original and the product:
IntersectionPointPlaneModelPair pair= TangoSupport.fitPlaneModelNearClick(...);
double x = 0.05; // subject to change
double[] p = pair.planeModel;
Quaternion plane = new Quaternion(p[0], p[1], p[2], p[3]);
plane.normalize();
Quaternion gravity = Quaternion(ScenePoseCalculator.TANGO_WORLD_UP.clone(), 0.0);
Quaternion product = plane.multiply(gravity);
if (plane.angleBetween(product) > x){
...
}
However, this does not work, because the product turned out to be identical to the plane. Thanks in advance!
I found out, that I was having a wrong understanding of Quaternions. I also found this formula for angle calculation of planes. Therefore I changed my implementation to be the following:
Edit: New Answer (old answer below)
private boolean isAlignedWithGravity(IntersectionPointPlaneModelPair candidate,
TangoPoseData devicePose, double maxDeviation) {
Matrix4 adfTdevice = ScenePoseCalculator.tangoPoseToMatrix(devicePose);
Vector3 gravityVector = ScenePoseCalculator.TANGO_WORLD_UP.clone();
adfTdevice.clone().multiply(mExtrinsics.getDeviceTDepthCamera()).inverse().
rotateVector(gravityVector);
double[] gravity = new double[]{gravityVector.x, gravityVector.y, gravityVector.z};
double angle = VectorUtilities.getAngleBetweenVectors(candidate.planeModel, gravity);
// vectors should be perpendicular => 90° => PI / 2 in radians
double target = Math.PI / 2;
return (Math.abs(target - angle) <= maxDeviation);
}
And in a class VectorUtilities:
/**
* Calculates the angle between two planes according to http://www.wolframalpha
* .com/input/?i=dihedral+angle
*/
public static double getAngleBetweenVectors(double[] a, double[] b) {
double numerator = 0;
for (int i = 0; i < Math.min(a.length, b.length); i++){
numerator += a[i] * b[i];
}
double denominator = getLength(a) * getLength(b);
return Math.acos(numerator / denominator);
}
public static double getLength(double[] vector) {
double sum = 0.0;
for (double dimension : vector) {
sum += (dimension * dimension);
}
return Math.sqrt(sum);
}
Old Answer
private boolean isAlignedWithGravity(IntersectionPointPlaneModelPair pair,
TangoPoseData devicePose) {
Matrix4 adfTdevice = ScenePoseCalculator.tangoPoseToMatrix(devicePose);
Vector3 gravityVector = ScenePoseCalculator.TANGO_WORLD_UP.clone();
adfTdevice.clone().multiply(mExtrinsics.getDeviceTDepthCamera()).inverse().
rotateVector(gravityVector);
double[] gravity = new double[]{gravityVector.x, gravityVector.y, gravityVector.z};
double angle = getAngleBetweenPlanes(pair.planeModel, gravity);
Log.d(TAG, "angle: " + angle);
if (angle < 0.1) {
return false;
}
return true;
}
/**
* Calculates the angle between two planes according to http://mathworld.wolfram
* .com/DihedralAngle.html
*/
private double getAngleBetweenPlanes(double[] a, double[] b) {
double numerator = Math.abs(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
double aFactor = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
double bFactor = Math.sqrt(b[0] * b[0] + b[1] * b[1] + b[2] * b[2]);
double denumerator = aFactor * bFactor;
double result = Math.acos(numerator / denumerator);
return result;
}

Actual and formal argument lists differs in length but I can't see why

In my Java Course, there's an exercise for making a class called Area with 4 overloaded constructors to calculate the area of a circle, a triangle, a rectangle or a cillinder.
After solving 6 errors, I still have 3 left.
This is the code I used:
import java.lang.Math;
class Area {
public double pi = Math.PI;
private int b, l, w, area;
private double r, h;
public Area(){
}
public Area(double radio){
r = radio;
area = pi * r * r;
}
public Area(int base, double alt){
b = base;
h = alt;
double o5 = 0.5;
double db = (double) b;
area = o5 * db * h;
}
public Area(int lar, int anc){
l = lar;
w = anc;
area = l * w;
}
public Area(double radio, double alt){
r = radio;
h = alt;
area = pi * r * r * h;
}
}
public class JavaCLab2P144 {
/**
* #param args
*/
public static void main(String[] args){
Area circ = new Area(4.0);
Area tria = new Area(6,3.0);
Area rect = new Area(2,4);
Area cili = new Area(4.0,10.0);
System.out.println("Area de un circulo:\t" + circ);
System.out.println("Area de un triangulo:\t" + tria);
System.out.println("Area de un rectangulo:\t" + rect);
System.out.println("Area de un cilindro:\t" + cili);
}
}
This is the error I get:
java/JavaCLab2P144/JavaCLab2P144.java:14: error: possible loss of precision
area = pi * r * r;
^
required: int
found: double
java/JavaCLab2P144/JavaCLab2P144.java:22: error: possible loss of precision
area = o5 * db * h;
^
required: int
found: double
java/JavaCLab2P144/JavaCLab2P144.java:34: error: possible loss of precision
area = pi * r * r * h;
^
required: int
found: double
3 errors
You cannot implicitly convert from double to it since you will possibly lose precision as errors indicate. You need an explicit cast to it using cast operator : (int) after assignment operator and becaude of order of ops you should put parens around multiplications like so
Area= (int)(pi * r * r);
There are many other issues to consider in your class such as choice of it for area instead of double since result is a double. As other poster stated you should use double instead for area field. You also don't need to declare variable for pi since it'd already a static cost on math or at least make it private static final
Problem is that double can have values like 1.5 which in case you want to change into int could be 1 or 2 (or is just you're mistake in coding). So java tells you that you have to do something about it.
To solve it you can cast double to int, which cuts to full number
double x = 1.2;
double y = 1.7;
int a = (int) x; // a == 1
int b = (int) y; // b == 1
Other option (in you're case better) is using Math#round(double) function
double x = 1.2;
double y = 1.7;
// Math.round(double) return long, so you also have to cast it into int
int a = (int) Math.round(x); // a == 1
int b = (int) Math.round(y); // b == 2

coneVolume Method returning zero

I can't seem to figure out why my coneVolume method is returning zero when all of my other methods are working properly.
import java.util.Scanner;
public class P56old{
public static double sphereVolume(double r){
double sphereVolume = (4/3)*(Math.PI)*(Math.pow(r, 3));
return sphereVolume;
}
public static double sphereSurface(double r){
double sphereSurface = 4 * (Math.PI) * Math.pow(r, 2);
return sphereSurface;
}
public static double cylinderVolume(double r, double h){
double cylinderVolume = (Math.PI) * (Math.pow(r, 2)) * h;
return cylinderVolume;
}
public static double cylinderSurface(double r, double h){
double cylinderSurface = 2 * (Math.PI) * (Math.pow(r, 2)) + 2 * Math.PI * r * h;
return cylinderSurface;
}
public static double coneVolume(double r, double h){
double coneVolume = (1/3) * Math.PI * (Math.pow(r,2)) * h;
return coneVolume;
}
public static double coneSurface(double r, double h){
double s = Math.sqrt(Math.pow(r,2) + Math.pow(h, 2));
double coneSurface = Math.PI * Math.pow(r,2) + Math.PI * r * s;
return coneSurface;
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.print("Please give the radius: ");
double r = in.nextDouble();
System.out.print("Please give the height: ");
double h = in.nextDouble();
double coneVolume = coneVolume(r,h);
double sphereVolume = sphereVolume(r);
double sphereSurface = sphereSurface(r);
double cylinderVolume = cylinderVolume(r,h);
double cylinderSurface = cylinderSurface(r,h);
double coneSurface = coneSurface(r,h);
System.out.println("The Sphere Volume is " + sphereVolume);
System.out.println("The Sphere Surface is " + sphereSurface);
System.out.println("The Cylinder volume is " + cylinderVolume);
System.out.println("The Cylinder Surface is " + cylinderSurface);
System.out.println("The Cone Volume is " + coneVolume);
System.out.println("The Cone Surface is " + coneSurface);
}
}
I'd appreciate any insight on the matter, and any critique is appreciated. I think it may have to do with all the public classes and maybe another method is affecting the coneVolume method but I just don't know enough about methods at the moment to fix the issue at hand.
When you do 1/3, it does integer division, resulting in 0 (the remainder is 1). Multiplying by 0 gives 0. Do 1.0/3.0 instead, and it will correctly compute an approximation to one third.

Categories

Resources