I was following the guidelines as described here, but when my android app examines a picture taken in a well-lit room and tries to match every color to the closest basic color (black, red, blue, green, etc.), most of the colors are associated with black. I have no idea why this happens and I have spent 3 hours examining my code to find out where the flaw was. Can anyone suggest where my error is?
Here is my code:
public double getMinEValue(int color1, int color2) {
double result_value = 0;
double[] color1_values = getColorValues(color1);
double[] color2_values = getColorValues(color2);
double delta_L = color1_values[0] - color2_values[0];
double delta_C = Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2))-Math.sqrt(Math.pow(color2_values[1], 2)+Math.pow(color2_values[2], 2));
double delta_a = color1_values[1]-color2_values[1];
double delta_b = color1_values[2]-color2_values[2];
double delta_H = Math.sqrt(Math.pow(delta_a, 2)+Math.pow(delta_b, 2)+Math.pow(delta_C, 2));
double k_1 = 0.045; double k_2 = 0.015;
double s_c = 1+k_1*Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2));
double s_h = 1+k_2*Math.sqrt(Math.pow(color1_values[1], 2)+Math.pow(color1_values[2], 2));
result_value = Math.sqrt(Math.pow(delta_L, 2)+Math.pow((delta_C/s_c), 2)+Math.pow((delta_H/s_h), 2));
return result_value;
}
public double[] getColorValues(int color1) {
double[] return_value = new double[3];
double r = Color.red(color1)/255;
double g = Color.green(color1)/255;
double b = Color.blue(color1)/255;
double r_linear = makeLinear(r) * 100;
double g_linear = makeLinear(g) * 100;
double b_linear = makeLinear(b) * 100;
double[][] matrix = {{0.4124, 0.3576, 0.1805}, {0.2126, 0.7152, 0.0722}, {0.0193, 0.1192, 0.9508}};
double[] linear_matrix = {r_linear, g_linear, b_linear};
double[] result_matrix = new double[3];
result_matrix = multiplyMatrices(matrix, linear_matrix);
//double X_n = 109.85; double Y_n = 100.00; double Z_n = 35.58; // Illuminant A
double X_n = 95.047; double Y_n = 100.00; double Z_n = 108.883; // D65
double L_star = 116*f(result_matrix[1]/Y_n)-16;
double a_star = 500*(f(result_matrix[0]/X_n)-f(result_matrix[1]/Y_n));
double b_star = 200*(f(result_matrix[1]/Y_n)-f(result_matrix[2]/Z_n));
return_value[0] = L_star; return_value[1] = a_star; return_value[2] = b_star;
return return_value;
}
private double f(double t) {
double return_value;
if (Double.compare(t, Math.pow((6/29), 3)) > 0) {
return_value = Math.pow(t, (1/3));
} else {
return_value = (1/3)*Math.pow((29/6), 2)*t+(4/29);
}
return return_value;
}
private double makeLinear(double c) {
double return_value = 0;
if (Double.compare(0.04045, c)<=0) {
return_value = c/12.92;
} else {
double a = 0.055;
return_value = Math.pow(((c + a) / (1 + a)), 2.4);
}
return return_value;
}
private double[] multiplyMatrices(double[][] matrix, double[] other_matrix) {
double[] return_matrix = new double[3];
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
return_matrix[i] += matrix[i][j]*other_matrix[j];
}
}
return return_matrix;
}
You've got a whole lot of integer divisions that need to be floating point divisions. You need to cast one of the operands of each division to double, or include a decimal point, to get these to work. For example, you have
Color.red(color1)/255
which should be
Color.red(color1)/255.0
and you also have expressions like
(1/3)*Math.pow((29/6), 2)*t+(4/29);
which needs to be
(1.0/3)*Math.pow((29.0/6), 2)*t+(4.0/29);
and many others. You have made this same mistake several times.
Related
This method takes in an array of planets and calculates their net x force component on the planet called upon. I get symbol not found error on compile for a1
public double calcForceExertedByX(Planet[] a1){
double forceX;
for (int i = 0; i < a1.length(); i++){
forceX = forceX + 6.667e-11 *(mass*a1[i].mass)/( xxPos - a1[i].xxPos)*(xxPos - a1[i].xxPos);
}
return forceX;
}
below is the complete code, as requested.
public class Planet {
public double xxPos;
public double yyPos;
public double xxVel;
public double yyVel;
public double mass;
public String imgFileName;
public Planet(double xPs, double yPs, double xVl, double
yVl, double m, String imge){
xxPos = xPs;
yyPos = yPs;
xxVel = xVl;
yyVel = yVl;
mass = m;
imgFileName = imge;
}
public Planet(Planet p){
xxPos = p.xxPos;
yyPos = p.yyPos;
xxVel = p.xxVel;
yyVel = p.yyVel;
mass = p.mass;
imgFileName = p.imgFileName;
}
public double calcDistance(Planet p1){
double distx = xxPos - p1.xxPos;
double disty = yyPos - p1.yyPos;
double dist = Math.sqrt(distx*distx + disty*disty);
return dist;
}
public double calcForceExertedBy(Planet p1){
double force = 6.667e-11 *(mass*p1.mass)/(this.calcDistance(p1)*this.calcDistance(p1));
return force;
}
public double calcForceExertedByX(Planet[] a1){
double forceX;
for (int i = 0; i < a1.length(); i++){
forceX = forceX + 6.667e-11 *(mass*a1[i].mass)/( xxPos - a1[i].xxPos)*(xxPos - a1[i].xxPos);
}
return forceX;
}
public double calcForceExertedByY(Planet[] a1){
double forceY;
for (int i = 0; i <a1.length(); i++){
forceY = forceY + 6.667e-11 *(mass*a1[i].mass)/( yyPos - a1[i].yyPos)*(yyPos - a1[i].yyPos);
}
return forceY;
}
}
Windows 7 JAVAc 11.01
I am guessing the error that is trying to be referenced is that Planet[] a1 does not have method length(). Arrays use .length rather than a method call.
Also forceX is not initialised.
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!
I am trying to pass aF variable. But when debugging, it shows to have a value of 0. Any idea? below is the code I am using (Update: I included the whole code).
import java.util.ArrayList;
import java.util.List;
public class EOS {
//defining constants, input variables
public static final double GAS_CONSTANT = 8.3144598; //J K-1 mol-1
double criticalTemperature;
double criticalPressure;
double temperature;
double pressure;
double molecularWeight;
public EOS(double criticalTemperature, double criticalPressure, double temperature, double pressure, double molecularWeight) {
this.criticalTemperature = criticalTemperature;
this.criticalPressure = criticalPressure;
this.temperature = temperature;
this.pressure = pressure;
this.molecularWeight = molecularWeight;
}
// calculation of A* and B* (values of "a" and "b" will be provided by subclasses)
public double aStar(double a) {
return a * pressure / (Math.pow(GAS_CONSTANT, 2) * Math.pow(temperature, 2));
}
public double bStar(double b) {
return b * pressure / (GAS_CONSTANT * temperature);
}
//calculation of Z Value. The idea is to form the cubic function of Z as follow:
public List<Double> calculateZ(double aStar, double bStar, double uValue, double wValue) {
List<Double> solution = new ArrayList<>();
double a, b, c, q, r, d;
a = -1 - bStar + uValue * bStar;
b = aStar + wValue * Math.pow(bStar, 2) - uValue * bStar - uValue * Math.pow(bStar, 2);
c = - bStar * aStar - wValue * Math.pow(bStar, 2) - wValue * Math.pow(bStar, 3);
q = (3*b-Math.pow(a, 2))/3;
r = (2*Math.pow(a, 3)-9*a*b+27*c)/27;
d = (Math.pow(q, 3)/27) + (Math.pow(r, 2)/4);
if (d == 0) {
double x1 = 2*Math.pow(-r/2, 1/3) -(a/3);
double x2 = -2*Math.pow(-r/2, 1/3) -(a/3);
double x3 = x2;
double[] temp = {x1, x2, x3};
for (int i = 0; i < temp.length; i++) {
if (temp[i] > 0) {
solution.add(temp[i]);
}
}
} else if (d > 0) {
double x1 = Math.pow((-r/2)+Math.pow(d, 0.5),1/3)+Math.pow((-r/2)+Math.pow(d, 0.5),1/3)-(a/3);
solution.add(x1);
} else {
double theta = Math.acos((3*r/(2*q))*Math.sqrt(-3/q));
double x1 = 2*Math.sqrt(-q/3)*Math.cos(theta/3)-(a/3);
double x2 = 2*Math.sqrt(-q/3)*Math.cos((theta+2*Math.PI)/3)-(a/3);
double x3 = 2*Math.sqrt(-q/3)*Math.cos((theta+4*Math.PI)/3)-(a/3);
double[] temp = {x1, x2, x3};
for (int i = 0; i < temp.length; i++) {
if (temp[i] > 0) {
solution.add(temp[i]);
}
}
}
return solution;
}
}
Here the subclass
import java.util.Collections;
public class Soave extends EOS {
public Soave (double aFactor, double criticalTemperature, double criticalPressure, double temperature, double pressure, double molecularWeight) {
super(criticalTemperature, criticalPressure, temperature, pressure, molecularWeight);
this.aF = aFactor;
this.fW = 0.48+1.574*aFactor-0.176*Math.pow(aFactor, 2);
}
double aF;
double uValue = 1;
double wValue = 0;
double fW;
public double reducedTemperature = temperature / criticalTemperature;
public double bValue = 0.08664*GAS_CONSTANT*criticalTemperature/criticalPressure;
public double aValue() {
double term1 = 1 - Math.sqrt(reducedTemperature);
double term2 = 1+fW*term1;
double term3 = Math.pow(term2, 2.0);
double term4 = Math.pow(GAS_CONSTANT, 2)*Math.pow(criticalTemperature, 2.0);
return 0.42748*term3*term4/criticalPressure;
}
public double aStarValue = aStar(aValue());
public double bStarValue = bStar(bValue);
public double gasZValue = Collections.max(calculateZ(aStarValue, bStarValue, uValue, wValue));
public double liquidZValue = Collections.min(calculateZ(aStarValue, bStarValue, uValue, wValue));
public double gasDensity = pressure * molecularWeight / (1000 * gasZValue * GAS_CONSTANT * temperature);
public double liquidDensity = pressure * molecularWeight / (1000 * liquidZValue * GAS_CONSTANT * temperature);
}
So now when we create an instance of Soave for the following inputs, we should get for liquidDensity a value of 568.77
double p = 500000;
double t = 318.15;
double pC = 3019900;
double tC = 507.9;
double aF = 0.299;
double mW = 86;
Soave soave = new Soave(aF, tC, pC, t, p, mW);
System.out.println(soave.liquidDensity);
You set your fW variable prior to actually setting the value of aF so it is using the default value of the primitive double which is 0.
Either create a getter for fW where you do the calculations or more the calculation for fW inside the constructor block.
So Either you do like this:
public class Soave extends EOS {
public double aF;
double uValue = 1;
double wValue = 0;
public double fW;
public Soave (double aFactor, double criticalTemperature, double criticalPressure, double temperature, double pressure, double molecularWeight) {
super(criticalTemperature, criticalPressure, temperature, pressure, molecularWeight);
this.aF = aFactor;
fW = 0.48+1.574*aF-0.176*Math.pow(aF, 2); //This will give you the proper number.
}
Alternatively add a getter and do the calculation directly(No need for the fW-variable in the class then).
public double getfWValue() {
return 0.48+1.574*aF-0.176*Math.pow(aF, 2);
}
If so then use that directly in your print-statement instead.
System.out.println(soave.getfWValue());
It is surely the matter of passing the argument or reading it. Look at the piece of code where you pass the value(Most likely you pass 0, it's quite "hard" to make it 0 while reading). If you still can't find your mistake, post the proper code here.
In this link, the process of trilateration is given.
And this is my java code for the localization process:
public static double[] localize(final double[] p1, final double[] p2, final double[] p3, final double[] p4, final double r1, final double r2, final double r3, final double r4)
{
double[] ex = normalize(difference(p2,p1));
double i = dot(ex, difference(p3, p1));
double[] ey = normalize(difference(difference(p3,p1), scalar(i,ex)));
double[] ez = cross(ex, ey);
double d = distance(p2, p1);
if(d - r1 >= r2 || r2 >= d + r1 )
return null;
double j = dot(ey, difference(p3, p1));
double x = ((r1*r1) - (r2*r2) + (d*d)) / (2*d);
double y = (((r1*r1) - (r3*r3) + (i*i) + (j*j)) / (2*j)) - ((i*x) / j);
double z = r1*r1- x*x - y*y;
if(z < 0)
return null;
double z1 = Math.sqrt(z);
double z2 = z1*-1;
double[] result1 = new double[]{p1[0], p1[1], p1[2]};
result1 = add(result1, scalar(x,ex));
result1 = add(result1, scalar(y,ey));
result1 = add(result1, scalar(z1,ez));
double[] result2 = new double[]{p1[0], p1[1], p1[2]};
result2 = add(result2, scalar(x,ex));
result2 = add(result2, scalar(y,ey));
result2 = add(result2, scalar(z2,ez));
double d1 = Math.abs(distance(result1, p4) - r4);
double d2 = Math.abs(distance(result2, p4) - r4);
if(d1<=d2)
return result1;
else
return result2;
}
But now, as shown in this paper, I want to instroduce some errors to distance measurements.
For an error alpha, There will be six spheres intersecting: three inner spheres and three outer spheres.
Their thickness will be amount of alpha(the measurement error).
I will get two areas instead of two points. But how do I estimate the position of a point given two areas?
In order to write such code, I tried this approach:
public static boolean inside(final double[] p, double[] c, final double r, final double error)
{
if(Math.pow(p[0]-c[0],2) + Math.pow(p[1]-c[1],2) + Math.pow(p[2]-c[2],2) >= r-error)
if(Math.pow(p[0]-c[0],2) + Math.pow(p[1]-c[1],2) + Math.pow(p[2]-c[2],2) <= r+error)
return true;
return false;
}
public static double[] localize(final double[] p1, final double[] p2, final double[] p3, final double[] p4, final double r1, final double r2, final double r3, final double r4, final double error)
{
double[][][] result = new double[8][3][3];
result[0] = intersection(p1,p2,p3,r1-error,r2-error,r3-error);
result[1] = intersection(p1,p2,p3,r1-error,r2-error,r3+error);
result[2] = intersection(p1,p2,p3,r1-error,r2+error,r3-error);
result[3] = intersection(p1,p2,p3,r1-error,r2+error,r3+error);
result[4] = intersection(p1,p2,p3,r1+error,r2-error,r3-error);
result[5] = intersection(p1,p2,p3,r1+error,r2-error,r3+error);
result[6] = intersection(p1,p2,p3,r1+error,r2+error,r3-error);
result[7] = intersection(p1,p2,p3,r1+error,r2+error,r3+error);
for(int i=0; i<8; i++)
if(result[i] != null)
for(int j=0; j<2; j++)
if(inside(result[i][j], p4, r4, error))
return result[i][j];
return null;
}
Which gives me null all the times.
Could you help me to get through this?
Edit: The function intersection() is same as localize(). It does not pick any point, but returns both.
Brief summary of the paper:
The paper investigates the 3-D localization by using pairwise distances and the effect of distance measurement errors. The interesting part is, in the paper, the quadratic equations were used to build linear matrices and therefore, the localization was done by using more than four beacons(references). Here, you can search for the keyword error and see how the error was modelled and how the linear equatios were built.
Moreover, I'll refer to this paper for the 2-D version of the problem.
I am currently developing a 2D Mario-Like Platformer Game. I ran into a collision problem i've been trying to solve for a while now, but nothing seems to work :/
Basicly, i have a CenterLayer, which stores at which Position what kind of Tile is.
Then i have some Sprites and a Player, which should collide with these Tiles.
Because these Tiles can be triangular shaped (or any other kind of convex polygon), i decided to handle collision via SAT (Seperating Axis Theorem). This works great, but when it comes to collision with the floor where many tiles are adjacent to eachother and the sprite is moving left, it pickes the wrong edge and moves the Sprite to the right, but expected result would be moving it up. This causes the sprite to get stuck.
This is the code im currently using:
package level;
import java.awt.Polygon;
import tiles.Tile;
import sprites.*;
public class Collider {
/** Collide Sprite (or Player) with CenterLayer **/
public static void collide(Sprite s, CenterLayer c){
CollisionPolygon ps = s.getPolygon();
//Get blocks to collide with
int startXTile = (int) (s.getX() / CenterLayer.TILE_WIDTH) - 1;
int endXTile = (int) Math.ceil((s.getX() + s.getWidth()) / CenterLayer.TILE_WIDTH) + 1;
int startYTile = (int) (s.getY() / CenterLayer.TILE_HEIGHT) - 1;
int endYTile = (int) Math.ceil((s.getY() + s.getHeight()) / CenterLayer.TILE_HEIGHT) +1;
//limit to level boundaries
if(startXTile < 0) startXTile = 0;
if(endXTile > c.LEVEL_WIDTH) endXTile = c.LEVEL_WIDTH;
if(startYTile < 0) startYTile = 0;
if(endYTile > c.LEVEL_HEIGHT) endYTile = c.LEVEL_HEIGHT;
int sizeX = endXTile - startXTile;
int sizeY = endYTile - startYTile;
//loop through tiles and collide
for(int xc = 0; xc < sizeX; xc++)
for(int yc = 0; yc < sizeY; yc++){
int xblock = xc + startXTile;
int yblock = yc + startYTile;
Tile t = c.getTile(xblock, yblock);
if(t!=null){ //if tile == null --> tile is air
CollisionPolygon pt = t.getPolygon(xblock, yblock);
double[] projection = PolygonCollision(ps, pt);
//if collision has happened
if(projection[0] != 0 || projection[1] != 0){
//collide
s.moveBy(projection[0], projection[1]);
//update sprites polygon to new position
ps = s.getPolygon();
}
}
}
}
public static double dotProduct(double x, double y, double dx, double dy) {
return x * dx + y * dy;
}
// Calculate the projection of a polygon on an axis (ax, ay)
// and returns it as a [min, max] interval
public static double[] ProjectPolygon(double ax, double ay, Polygon p) {
double dotProduct = dotProduct(ax, ay, p.xpoints[0], p.ypoints[0]);
double min = dotProduct;
double max = dotProduct;
for (int i = 0; i < p.npoints; i++) {
dotProduct = dotProduct(p.xpoints[i], p.ypoints[i], ax, ay);
if (dotProduct < min) {
min = dotProduct;
} else if (dotProduct > max) {
max = dotProduct;
}
}
return new double[] { min, max };
}
// Calculate the distance between [minA, maxA](p1[0], p1[1]) and [minB, maxB](p2[0], p2[1])
// The distance will be negative if the intervals overlap
public static double IntervalDistance(double[] p1, double[] p2) {
if (p1[0] < p2[0]) {
return p2[0] - p1[1];
} else {
return p1[0] - p2[1];
}
}
public static double[] PolygonCollision(CollisionPolygon p1, CollisionPolygon p2){
boolean intersection = true;
int edgeCount1 = p1.npoints;
int edgeCount2 = p2.npoints;
double projectionX = 0;
double projectionY = 0;
double projectionDist = Double.POSITIVE_INFINITY;
//loop through all the edges
for(int edgeIndex = 0; edgeIndex < edgeCount1 + edgeCount2; edgeIndex++){
//find edges
double[] axis;
if(edgeIndex < edgeCount1){
axis = p1.getAxis(edgeIndex);
} else {
axis = p2.getAxis(edgeIndex - edgeCount1);
}
double axisX = axis[0];
double axisY = axis[1];
//System.out.println("edge: " +axisX + ", "+ axisY);
//find the projection of both polygons on current axis
final double[] proj1 = ProjectPolygon(axisX, axisY, p1);
final double[] proj2 = ProjectPolygon(axisX, axisY, p2);
//Check if polygons are intersecting, if not end loop
double id = IntervalDistance(proj1, proj2);
if(id > 0){
intersection = false;
break;
}
//Check if projection would be shorter than previous one
id = Math.abs(id);
if(id < projectionDist){
projectionDist = id;
projectionX = axisX;
projectionY = axisY;
//check if hit from "false" side
double d1x = p1.getCenterX();
double d1y = p1.getCenterY();
double d2x = p2.getCenterX();
double d2y = p2.getCenterY();
double midx = d1x - d2x;
double midy = d1y - d2y;
double dot = dotProduct(midx, midy, projectionX, projectionY);
if(dot < 0){
projectionX = -projectionX;
projectionY = -projectionY;
}
}
}
double[] result = new double[]{0, 0};
if(intersection){
//System.out.println("colliison: " + projectionX +"; "+ projectionY + ", " + projectionDist);
result[0] = projectionX * projectionDist;
result[1] = projectionY * projectionDist;
}
return result;
}
}
Any Ideas?
Tom
I had this bug too , it happens when there are parallel edges on a poly.The easy way to fix this is to project the difference between the polygon centers on the found axis.If the result is negative you would just multiply the axis by -1.
Vector aMidPoint = new Vector();
Vector bMidPoint = new Vector();
for ( Vector v : aVerts) {
aMidPoint = aMidPoint.add(v);
}
for ( Vector v : bVerts) {
bMidPoint = bMidPoint.add(v);
}
aMidPoint = aMidPoint.scalarDivision(aVerts.size());
bMidPoint = bMidPoint.scalarDivision(bVerts.size());
Vector ba = aMidPoint.subtract(bMidPoint);
if (ba.dotProduct(minOverlapVector) < 0) {
minOverlapVector = minOverlapVector.scalarMultiplication(-1);
}