Project Tango: Determine whether an IntersectionPointPlaneModelPair is aligned with Gravity - java

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;
}

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;
}
}

How to solve sine mathematic equation in java?

How to solve following mathematic equation in java?
Equation:
x + sin(x) = constant, where x is variable. I encountered this equation after 18 years. I forgot this basic concept. Please help me on this basic high school question.
I tried to code above equation x + sin(x) = constant as following, however, it is giving wrong answer. Please let me know where i am wrong.
public double balanceLength(double total_weight) {
// 5.00 assume inical value of x
return newtonRaphson( 5.00, total_weight);
}
private static double derivFunc(double x)
{
return sin(x) + x;
}
private static double func(double x, double weight)
{
return sin(x) + x - weight;
}
static double newtonRaphson(double x, double weight)
{
double h = func(x, weight) / derivFunc(x);
while (abs(h) >= EPSILON)
{
h = func(x, weight) / derivFunc(x);
x = x - h;
}
return round(x * 100.0) / 100.0 ;
}
This is a very basic implementation, only partially tested. It reruns x in radians, which satisfies y=six(x) +x for a given y :
//returned value in radians
static double evaluateSinxPlusx(double y){
double delta = y>0 ? 0.01 : -0.01 ;//change constants
double epsilon = 0.01; //to change
int iterations = 100; //accuracy
double x = 0;
double sum = 1;
while(Math.abs(y - sum) > epsilon) {
x+=delta;
//based Taylor series approximation
double term = 1.0;
sum = x;
double d = 1;
for (int i = 1; i< iterations; i++) {
term = Math.pow(x, i);
d*=i;
if (i % 4 == 1) {
sum += term/d;
}
if (i % 4 == 3) {
sum -= term/d;
}
}
}
return x;
}
//test it
public static void main(String[] args) throws Exception{
double y = 0.979;
//expected x = 0.5 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
y = -0.979;
//expected x = - 0.5 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
y = 0.33256;
//expected x = 0.16666 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
}
This is not a robust implementation and should be used as demo only.

No convergence with batch gradient descent

I make my first steps in implementation of batch and stochastic gradient descent.
Here is my implementation:
package ch.learning;
import java.util.*;
import org.jzy3d.analysis.AbstractAnalysis;
import org.jzy3d.analysis.AnalysisLauncher;
import org.jzy3d.chart.factories.AWTChartComponentFactory;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.*;
import org.jzy3d.plot3d.builder.concrete.*;
import org.jzy3d.plot3d.primitives.Scatter;
import org.jzy3d.plot3d.primitives.Shape;
import org.jzy3d.plot3d.rendering.canvas.Quality;
import org.apache.commons.math3.analysis.function.Sigmoid;
public class LogisticReg_GradientDescent {
private List<double[]> trainingExamples = new LinkedList<double[]>();
private static final int sizeTrainingset = 1000;
private volatile double[] theta = {10, 10, 10, 10 };
// Configurable compoenent of step size during theata update
private final double alpha = 0.01;
// Amount of iteration in Batch Gradient Descent
private static final int iterations = 10000;
private static final int printsAtStartAndEnd = 5;
private void buildTrainingExample(int amount) {
// Area of the house
double areaMin = 80;
double areaMax = 1000;
double areaRange = areaMax - areaMin;
// Distance to center
double distanceMin = 10;
double distanceMax = 10000;
double distanceRange = distanceMax - distanceMin;
// Generate training examples with prices
for (int i = 0; i < amount; i++) {
double[] example = new double[5];
example[0] = 1.0;
example[1] = areaMin + Math.random() * areaRange;
example[2] = distanceMin + Math.random() * distanceRange;
// Price is a feature as well in this logistic regression example
double price = 0;
price += _priceComponent(example[1], areaRange);
price += _priceComponent(example[2], distanceRange);
// price += _priceComponent(example[3], yocRange);
example[3] = price;
example[4] = (price>200000)?0:1;
trainingExamples.add(example);
}
}
// Random price according with some range constraints
private double _priceComponent(double value, double range) {
if (value <= range / 3)
return 50000 + 50000 * Math.random() * 0.1;
if (value <= (range / 3 * 2))
return 100000 + 100000 * Math.random() * 0.1;
return 150000 + 150000 * Math.random() * 0.1;
}
private double classificationByHypothesis(double[] features) {
// Scaling
double scalingF0 = features[0];
double scalingF1 = (features[1] - 80) / (920);
double scalingF2 = (features[2] - 10) / (9990);
double scalingF3 = (features[3] - 50000) / (400000);
double z = this.theta[0] * scalingF0 + this.theta[1] * scalingF1 + this.theta[2] * scalingF2
+ this.theta[3] * scalingF3;
double ret = 1 / (1 + Math.pow(Math.E, -z));
return ret;
}
// Costfunction: Mean squared error function
private double gradientBatch_costs() {
double costs = this.trainingExamples.stream().mapToDouble(l -> {
double costsint;
if (l[4] == 0) {
costsint = -Math.log(1 - classificationByHypothesis(l));
} else {
costsint = -Math.log(classificationByHypothesis(l));
}
return costsint;
}).sum();
return costs / this.trainingExamples.size();
}
// Theta Update with Batch Gradient Descent
private void gradientBatch_thetaUpdate(int amount) {
for (int i = 0; i < amount; i++) {
double partialDerivative0 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[0]).sum();
double tmpTheta0 = this.theta[0] - (this.alpha * partialDerivative0 / this.trainingExamples.size());
double partialDerivative1 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[1]).sum();
double tmpTheta1 = this.theta[1] - (this.alpha * partialDerivative1 / this.trainingExamples.size());
double partialDerivative2 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[2]).sum();
double tmpTheta2 = this.theta[2] - (this.alpha * partialDerivative2 / this.trainingExamples.size());
double partialDerivative3 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[3]).sum();
double tmpTheta3 = this.theta[3] - (this.alpha * partialDerivative3 / this.trainingExamples.size());
this.theta = new double[] { tmpTheta0, tmpTheta1, tmpTheta2, tmpTheta3 };
}
}
// Theta update with Stochastic Gradient Descent
private void gradientStochastic_thetaUpdate(double[] feature) {
double tmpTheta0 = this.theta[0] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[0];
double tmpTheta1 = this.theta[1] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[1];
double tmpTheta2 = this.theta[2] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[2];
double tmpTheta3 = this.theta[3] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[3];
this.theta = new double[] { tmpTheta0, tmpTheta1, tmpTheta2, tmpTheta3 };
}
private void resetTheta() {
this.theta = new double[] {0.00001, 0.00001, 0.00001, 0.00001};
}
private void printSummary(int iteration) {
System.out.println(String.format("%s \t\t Theta: %f \t %f \t %f \t %f \t Costs: %f", iteration, this.theta[0],
this.theta[1], this.theta[2], this.theta[3], this.gradientBatch_costs()));
}
public static void main(String[] args) {
LogisticReg_GradientDescent d = new LogisticReg_GradientDescent();
// Batch and Stochastic Gradient Descent use the same training example
d.buildTrainingExample(sizeTrainingset);
System.out.println("Batch Gradient Descent");
d.printSummary(0);
System.out.println(String.format("First %s iterations", printsAtStartAndEnd));
for (int i = 1; i <= iterations; i++) {
d.gradientBatch_thetaUpdate(1);
d.printSummary(i);
}
System.out.println("Some examples are:");
System.out.println(String.format("The 1:%s, Area:%s, Distance:%s, Price:%s, Classification:%s", d.trainingExamples.get(0)[0],d.trainingExamples.get(0)[1],d.trainingExamples.get(0)[2],d.trainingExamples.get(0)[3],d.trainingExamples.get(0)[4]));
System.out.println(String.format("The 1:%s, Area:%s, Distance:%s, Price:%s, Classification:%s", d.trainingExamples.get(500)[0],d.trainingExamples.get(500)[1],d.trainingExamples.get(500)[2],d.trainingExamples.get(500)[3],d.trainingExamples.get(500)[4]));
try {
AnalysisLauncher.open(d.new SurfaceDemo());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class SurfaceDemo extends AbstractAnalysis{
#Override
public void init(){
double x;
double y;
double z;
float a;
Coord3d[] points = new Coord3d[trainingExamples.size()];
Color[] colors = new Color[trainingExamples.size()];
for(int i=0; i<trainingExamples.size(); i++){
x = trainingExamples.get(i)[1]; // Area
y = trainingExamples.get(i)[2]; // Distance to center
z = trainingExamples.get(i)[3]; // price
points[i] = new Coord3d(x, y, z);
a = 1f;
if(trainingExamples.get(i)[4]==1){
colors[i] =new Color(0,0,0,a);
}else{
colors[i]= new Color(250,0,0,a);
}
}
Scatter scatter = new Scatter(points, colors);
scatter.setWidth(4);
Mapper mapper = new Mapper() {
#Override
public double f(double x, double y) {
return (-theta[0]-theta[1]*x-theta[2]*y)/theta[3];
}
};
// Create the object to represent the function over the given range.
Range rangeX = new Range(0, 1000);
Range rangeY = new Range(0, 10000);
int steps = 10;
final Shape surface = Builder.buildOrthonormal(new OrthonormalGrid(rangeX, steps, rangeY, steps), mapper);
surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1, 1, 1, .5f)));
surface.setFaceDisplayed(true);
surface.setWireframeDisplayed(false);
chart = AWTChartComponentFactory.chart(Quality.Advanced, getCanvasType());
chart.getScene().add(scatter);
chart.getScene().add(surface);
}
}
}
A graphical representation looks like
So i plot the generated training instances with org.jzy3d.plot3d.
We see x(the area of the house), y(distance to town center) and z(price).
The classification makes red (negative class -> not sold) and black (positive class -> sold).
In the generated trainings instances the classification depends just at the price, you see it here:
example[4] = (price>200000)?0:1;
The problem, the thing I don't understand is
I would like to plot the decision boundary of my classificator.
The decision bounday depends on the optimized components from Theta. (Using batch gradient descent).
So i try to plot the decision boundary plane with this code:
Mapper mapper = new Mapper() {
#Override
public double f(double x, double y) {
return (-theta[0]-theta[1]*x-theta[2]*y)/theta[3];
}
};
Because
theta[0]*1 + theta[1 ]*x + theta[2]*y + theta[3]*z = 0
so
z = -(theta[0]*1 + theta[1 ]*x + theta[2]*y)/theta[3]
I would expect my decision boundary plane between the red- and blackarea.
Instead it hangs around by z=0.
I didn't know, either I'm not able to plot this decision boundary plane in a proper way, or my optimized parameters are shit.
Further I don't know how to choose a good initial theta vector.
Right now i use
private volatile double[] theta = {1, 1, 1, 1 };
I set alpha to 0.0001
private final double alpha = 0.0001;
It was the biggest possible Alpha, where my cost function doesn't jump around and the sigmoid implementation doesn't return infinity.
I already make feature scaling at
private double classificationByHypothesis(double[] features) {
// Scaling
double scalingF0 = features[0];
double scalingF1 = (features[1] - 80) / (920);
double scalingF2 = (features[2] - 10) / (9990);
double scalingF3 = (features[3] - 50000) / (400000);
double z = this.theta[0] * scalingF0 + this.theta[1] * scalingF1 + this.theta[2] * scalingF2
+ this.theta[3] * scalingF3;
double ret = 1 / (1 + Math.pow(Math.E, -z));
return ret;
}
The last five iteration with given initial theta and alpha equals 0.0001 are
9996,Theta: 1.057554,-6.340981,-6.242139,8.145087,Costs: 0.359108
9997,Theta: 1.057560,-6.341234,-6.242345,8.145576,Costs: 0.359109
9998,Theta: 1.057565,-6.341487,-6.242552,8.146065,Costs: 0.359110
9999,Theta: 1.057571,-6.341740,-6.242758,8.146553,Costs: 0.359112
10000,Theta: 1.057576,-6.341993,-6.242965,8.147042,Costs: 0.359113
Some example of the generated training instances are
Area: 431.50139030510206, Distance: 8591.341686012887,
Price: 255049.1280388437, Classification:0.0
Area: 727.4042972310916, Distance: 4364.710136408952,
Price: 258385.59452489938, Classification:0.0
Thanks for any hint!

How do I wrap a texture around a sphere?

I created a class with a method drawSphere to replace glutDrawSolidSphere. See code below.
But I wonder, how do I wrap a texture around it without tiling? For example, if I want to draw a mouth, eyes and a nose on it, then I want it to have only one mouth, two eyes and one nose, and not 100 tiled all over the sphere.
I'm using Jogl with some libraries.
class Shape {
public void drawSphere(double radius, int slices, int stacks) {
gl.glEnable(GL_TEXTURE_2D);
head.bind(gl); //This method is a shorthand equivalent of gl.glBindTexture(texture.getTarget(), texture.getTextureObject());
gl.glBegin(GL_QUADS);
double stack = (2*PI)/stacks;
double slice = (2*PI)/slices;
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 2 * PI; phi += slice) {
Vector p1 = getPoints(phi, theta, radius);
Vector p2 = getPoints(phi + slice, theta, radius);
Vector p3 = getPoints(phi + slice, theta + stack, radius);
Vector p4 = getPoints(phi, theta + stack, radius);
gl.glTexCoord2d(0, 0);
gl.glVertex3d(p1.x(), p1.y(), p1.z());
gl.glTexCoord2d(1, 0);
gl.glVertex3d(p2.x(), p2.y(), p2.z());
gl.glTexCoord2d(1, 1);
gl.glVertex3d(p3.x(), p3.y(), p3.z());
gl.glTexCoord2d(0, 1);
gl.glVertex3d(p4.x(), p4.y(), p4.z());
}
}
gl.glEnd();
gl.glDisable(GL_TEXTURE_2D);
}
Vector getPoints(double phi, double theta, double radius) {
double x = radius * cos(theta) * sin(phi);
double y = radius * sin(theta) * sin(phi);
double z = radius * cos(phi);
return new Vector(x, y, z);
}
}
You could just map latitude and longitude directly to the texture co-ordinates.
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 2 * PI; phi += slice) {
Just scale theta and phi to be between 0 and 1.
double s0 = theta / (2 * PI);
double s1 = (theta + stack) / (2 * PI);
double t0 = phi / (2 * PI);
double t1 = (phi + slice) / (2 * PI);
And use s0,s1,t0,t1 in place of 0 and 1 in your texCoord() calls.

How to quickly calculate what points are within a given distance of my point

I have a large number of Longitude and Latitudes and I want to quickly find out which ones are within say a 5km radius of a certain Longitude Latitude.
Instead of using a datastructure (Which would be overkill), I should be able to perform n do products very quickly. I've just done something wrong and can't seem to see what.
I have been trying to implement this in Java:
final List<CoOrds> coOrds = Create20x20Grid();
// Determine point X (centre of earth)
final Vector2 X = new Vector2(0,0);
// My CoOrd I want to check
final double srclon = coOrds.get(0).getLongitude();
final double srclat = coOrds.get(0).getLatitude();
final Vector2 A = new Vector2(srclon, srclat, true);
final double brng = 0;
final double d = 5;
final double R = 6371.1;
double dist = 0;
dist = d / R; // convert dist to angular distance in radians
final double lat1 = Math.toRadians(srclat);
final double lon1 = Math.toRadians(srclon);
final double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist)+ Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1),Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2));
// normalise to -180..+180º
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
//Create another point which is the distance is d away from your point
final Vector2 B = new Vector2(Math.toDegrees(lon2),Math.toDegrees(lat2), true);
// Create a vector from X->A
final Vector2 X_A = new Vector2((A.getX() - X.getX()),(A.getY() - X.getY()));
// Create a vector from X->B
final Vector2 X_B = new Vector2((B.getX() - X.getX()),(B.getY() - X.getY()));
// Normalize XA
final Vector2 nX_A = X_A.normalize();
// Normalize XB
final Vector2 nX_B = X_B.normalize();
// Calculate the Dot Product
final Double Alpha = nX_A.dot(nX_B);
int count = 0;
for (final CoOrds c : coOrds) {
final Vector2 P = c.getPosition();
final Vector2 X_P = new Vector2((P.getX() - X.getX()),(P.getY() - X.getY()));
final Vector2 nX_P = X_P.normalize());
final Double Beta = nX_A.dot(nX_P);
if (Beta < Alpha) {
System.out.println(count + " -- " + Beta + " : " + Alpha);
count++;
}
}
System.out.println("Number of CoOrds within Distance : " + count);
The new point P is correct as I've loaded it into Google Maps, but I am not entirely sure if I have the calculations correct.
I have created a custom Vector2 class, which stores the Longitude and Latitude. It also coverts them to Cartesian:
private void convertSphericalToCartesian(final double latitude, final double longitude) {
x = (earthRadius * Math.cos(latitude) * Math.cos(longitude)) ;
y = (earthRadius * Math.cos(latitude) * Math.sin(longitude)) ;
}
The Dot Product:
public double dot(final Vector2 v2) {
return ((getX() * v2.getX()) + (getY() * v2.getY()));
}
The Normalize:
public Vector2 normalize() {
final double num2 = (getX() * getX()) + (getY() * getY());
final double num = 1d / Math.sqrt(num2);
double a = x;
double b = y;
a *= num;
b *= num;
return new Vector2(a, b);
}
Any help with this would be really appreciated
I used this website: http://www.movable-type.co.uk/scripts/latlong.html
To help me calculate point B.
I used this website : http://rbrundritt.wordpress.com/2008/10/14/conversion-between-spherical-and-cartesian-coordinates-systems/
To help me transform Spherical CoOrdinates to Cartesian CoOrdinates.
Thanks
[EDIT]
The test case I am currently running is:
0-0-0
2-2-0
1-2-0
Where the above is a grid of 9 points. The point I am checking is "1". I expect it to return all the points "2". But it is returning all the points in the grid. I have manually checked the distances on Google Maps and it should only be returning the points "2".
Thanks
From the comments above, you're not sure if your formulae are accurate.
The first step is to figure that out.
Select a few well-known points on the globe (North Pole, South Pole, Greenwich UK, etc), and create a test case that invokes convertSphericaltoCartesian() with these coordinates. Check the results and see if they make any sense.

Categories

Resources