I'm currently trying to create a method which can make a multilinear interpolation for an unknown number of points (the number is equal to 2^n) in n-dimensional space.
The cases for n = 1 (no interpolation) and n = 2 (linear interpolation) are already implemented and seem to work. But now I'm already struggling to make the bilinear interpolation (for the case n = 4) dimension agnostic and I have no idea how I should progress from that point on (n = 8, ..., 2^n).
Is there a general approach for this problem or should I hardcode some of the cases and throw an UnsupportedOperationException otherwise?
Below I added an SSCCE which should hopefully clarify my problem. It consists of a point class which stores the coordinates and a value and also contains some functionality like calculating the distance to another point and the interpolation method which already contains my implementation of the cases for n = 1 and n = 2.
Code
import java.util.ArrayList;
import java.util.List;
public class Interpolator {
public static void main(String[] args) {
Interpolator ip = new Interpolator();
Point currentPoint = new Point(new long[]{5, 5}, 0);
List<Point> neighbors = new ArrayList<Point>() {{
add(new Point(new long[]{3, 3}, 7));
add(new Point(new long[]{10, 10}, 4));
}};
System.out.println(ip.interpolate(currentPoint, neighbors));
}
public float interpolate(Point currentPoint, List<Point> neighbors) {
if (neighbors.size() == 1) {
// no interpolation necessary with only one neighbor
return neighbors.get(0).getValue();
} else if (neighbors.size() == 2) {
// distance between point and the two neighbors
float distanceOne = currentPoint.distance(neighbors.get(0));
float distanceTwo = currentPoint.distance(neighbors.get(1));
float completeDistance = distanceOne + distanceTwo;
// calculate weights
float weightOne = 1 - distanceOne / completeDistance;
float weightTwo = 1 - distanceTwo / completeDistance;
// linear interpolation
return neighbors.get(0).getValue() * weightOne
+ neighbors.get(1).getValue() * weightTwo;
} else if (neighbors.size() == 4) {
//TODO: bilinear interpolation
} else if(neighbors.size() == 8){
//TODO: trilinear interpolation
}
//TODO: quadlinear interpolation or higher?
return -1;
}
public static class Point {
private long[] m_coordinates;
private float m_value;
public Point(final long[] coordinates, float value) {
this.m_coordinates = coordinates;
this.m_value = value;
}
public long[] getCoordinates() {
return this.m_coordinates;
}
public int numDim() {
return m_coordinates.length;
}
public long dim(final int i) {
return this.m_coordinates[i];
}
public float distance(final Point otherPoint) {
if (this.numDim() != otherPoint.numDim()) {
throw new IllegalArgumentException(
"Can't measure distance between points with different dimensionality");
}
float sum = 0;
for (int i = 0; i < this.numDim(); i++) {
sum += Math.pow(this.dim(i) - otherPoint.dim(i), 2);
}
return (float) Math.sqrt(sum);
}
public float getValue() {
return m_value;
}
}
}
This seems to do what your algorithm does but is dimension agnostic. I am not saying your calculation is correct - I am just saying that I think this is the same calculation but for n dimensions:
public float interpolate(Point currentPoint, List<Point> neighbors) {
int dimensions = neighbors.size();
float[] distance = new float[dimensions];
float sumDistances = 0;
for (int i = 0; i < dimensions; i++) {
distance[i] = currentPoint.distance(neighbors.get(i));
sumDistances += distance[i];
}
float[] weight = new float[dimensions];
for (int i = 0; i < dimensions; i++) {
weight[i] = 1 - distance[i] / sumDistances;
}
float interpolatedDistance = 0;
for (int i = 0; i < dimensions; i++) {
interpolatedDistance += neighbors.get(i).getValue() * weight[i];
}
return interpolatedDistance;
}
Related
I have made a simple perceptron model with java. For visualization I use processing to see results.
Basically, the perceptron gives either negative or positive 1, depending on the location of the given position (float array with 2 values x and y). It is supposed to learn, if a given position is above or below a line.
My code worked fine with a formula of y=x, but has troubles when getting a formula like y=height-x
I tried tweaking the learningStrength, the number of dots it has to guess, changing the bias and line formula.
I can't figure out why it works with the formula y=x, but not with any other...
Class node (Perceptron):
public class Node {
float[] weights;
PApplet pApplet;
float trainingStrength = 0.01f;
public Node(int inputs, PApplet pApplet){
this.weights = new float[inputs + 1];
this.pApplet = pApplet;
for (int i = 0; i < inputs; i++){
this.weights[i] = pApplet.random(1);
}
}
private float activation(float sum){
return Math.signum(sum);
}
public float guess(float[] inputs){
float[] inputsB = addBias(inputs);
if (inputsB.length != weights.length){
return 0;
}
float sum = 0;
for (int i = 0; i < inputsB.length; i++){
sum += inputsB[i] * weights[i];
}
return activation(sum);
}
public void tweak(float[] inputs, int error){
float[] inputsB = addBias(inputs);
for(int i = 0; i < weights.length; i++){
weights[i] += error * inputsB[i] * trainingStrength;
}
}
public float guessY(int x){
float w0 = weights[0];
float w1 = weights[1];
float w2 = weights[2];
return -(w2/w1) - (w0/w1) * x;
}
private float[] addBias(float[] inputs){
float[] inputsB = new float[inputs.length + 1];
for (int i = 0; i < inputs.length; i++) {
inputsB[i] = inputs[i];
if (i + 1 >= inputs.length){
// bias = 1
inputsB[i + 1] = 1;
}
}
return inputsB;
}
}
Class Dot:
public class Dot {
PVector position;
PApplet pApplet;
int answer;
boolean correct;
public Dot(PVector position, PApplet pApplet){
this.position = position;
this.pApplet = pApplet;
}
public void setAnswer(int answer) {
this.answer = answer;
}
public int getAnswer() {
return answer;
}
public PVector getPosition() {
return position;
}
public void guessed(boolean correct) {
this.correct = correct;
}
public void show(){
pApplet.push();
if (!correct) {
pApplet.fill(255, 0, 0);
} else {
pApplet.fill(0,255,0);
}
pApplet.ellipse(position.x,position.y,20,20);
if (answer >= 0){
pApplet.fill(255);
} else {
pApplet.fill(0);
}
pApplet.ellipse(position.x,position.y,10,10);
pApplet.pop();
}
}
Main with processing sketch:
public class NeuralNetworkLibrary extends PApplet{
Node brain;
List<Dot> dots;
int nDots = 1000;
public void settings() {
size(1200,1200);
brain = new Node(2, this);
dots = new ArrayList<>();
for (int i = 0; i < nDots; i++){
dots.add(new Dot(new PVector(random(width), random(height)), this));
dots.get(i).setAnswer((int) Math.signum(formula((int) dots.get(i).getPosition().x) - dots.get(i).getPosition().y));
}
}
public void draw() {
frameRate(1);
background(120);
strokeWeight(1);
for (Dot dot : dots){
int guess = (int) brain.guess(new float[]{dot.getPosition().x,dot.getPosition().y});
int error = dot.getAnswer() - guess;
boolean correct = false;
if (error == 0){
correct = true;
} else {
brain.tweak(new float[]{dot.getPosition().x,dot.getPosition().y}, error);
}
dot.guessed(correct);
dot.show();
}
strokeWeight(5);
line(0, formula(0), width, formula(width));
line(0,brain.guessY(0),width,brain.guessY(width));
}
public int formula(int x){
return x + height / 2;
}
public static void main(String[] args) {
PApplet.main(NeuralNetworkLibrary.class);
}
}
This is the code I have done so far. It creates the ArrayList and adds the circles. The volume is stored and is printed in the console. The last thing I have to do is print out the smallest volume using a for-each loop. This is where I'm having difficulties. I could really use some help/advice
public static void main(String[] args)
{
Random rand = new Random();
final int RADIUS_MAX = 100;
int NUM_SPHERES = 4;
List<Sphere> spheres = new ArrayList<Sphere>();
for(int add = 1; add <= NUM_SPHERES; add++) {
spheres.add(new Sphere(rand.nextInt(RADIUS_MAX)));
}
for (Sphere s : spheres) {
System.out.println(s);
}
//TODO: Convert to a for-each loop to find the volume of the smallest sphere
for (Sphere s : spheres) {
}
}
You do not need an additional loop. The sphere with the smallest radius will have the smallest volume. You could store the smallest volume so far (initialized to a very large volume) and update it in either of your existing loops. I believe the formula for volume is (4. / 3) * Math.PI * Math.pow(radius, 3).
The volume formula of the sphere depends from radius like V <=> R, so no need to calculate volume each time, because minimal voule will be with minimal radius.
public class Foo {
public static void main(String... args) {
Random rand = new Random();
final int maxRadius = 100;
final int totalSphere = 4;
List<Sphere> spheres = new ArrayList<>();
for (int i = 0; i < totalSphere; i++)
spheres.add(new Sphere(rand.nextInt(maxRadius)));
for (Sphere sphere : spheres)
System.out.println(sphere);
Sphere smallestSphere = spheres.get(0);
for (Sphere sphere : spheres)
if (smallestSphere == null || sphere.compareTo(smallestSphere) < 0)
smallestSphere = sphere;
System.out.println("smallest volume: " + smallestSphere.getVolume());
}
public static class Sphere implements Comparable<Sphere> {
private final int radius;
public Sphere(int radius) {
this.radius = radius;
}
public double getVolume() {
return (4. / 3) * Math.PI * Math.pow(radius, 3);
}
#Override
public String toString() {
return "radius: " + radius;
}
#Override
public int compareTo(Sphere sphere) {
return Integer.compare(radius, sphere.radius);
}
}
}
My perceptron doesn't find the right y-intercept even though I added a bias. The slope is correct. This is my second try coding a perceptron from scratch and I got the same error twice.
The perceptron evaluates if a point on a canvas is higher or lower than the interception line. The inputs are the x-coordinate, y-coordinate and 1 for the bias.
Perceptron class:
class Perceptron
{
float[] weights;
Perceptron(int layerSize)
{
weights = new float[layerSize];
for (int i = 0; i < layerSize; i++)
{
weights[i] = random(-1.0,1.0);
}
}
float Evaluate(float[] input)
{
float sum = 0;
for (int i = 0; i < weights.length; i++)
{
sum += weights[i] * input[i];
}
return sum;
}
float Learn(float[] input, int expected)
{
float guess = Evaluate(input);
float error = expected - guess;
for (int i = 0; i < weights.length; i++)
{
weights[i] += error * input[i] * 0.01;
}
return guess;
}
}
This is the testing code:
PVector[] points;
float m = 1; // y = mx+q (in canvas space)
float q = 0; //
Perceptron brain;
void setup()
{
size(600,600);
points = new PVector[100];
for (int i = 0; i < points.length; i++)
{
points[i] = new PVector(random(0,width),random(0,height));
}
brain = new Perceptron(3);
}
void draw()
{
background(255);
DrawGraph();
DrawPoints();
//noLoop();
}
void DrawPoints()
{
for (int i = 0; i < points.length; i++)
{
float[] input = new float[] {points[i].x / width, points[i].y / height, 1};
int expected = ((m * points[i].x + q) < points[i].y) ? 1 : 0; // is point above line
float output = brain.Learn(input, expected);
fill(sign(output) * 255);
stroke(expected*255,100,100);
strokeWeight(3);
ellipse(points[i].x, points[i].y, 20, 20);
}
}
int sign(float x)
{
return x >= 0 ? 1 : 0;
}
void DrawGraph()
{
float y1 = 0 * m + q;
float y2 = width * m + q;
stroke(255,100,100);
strokeWeight(3);
line(0,y1,width,y2);
}
I found the problem
float guess = Evaluate(input);
float error = expected - guess;
should be
float guess = sign(Evaluate(input));
float error = expected - guess;
The output was never exactly one ore zero even if the answer would be correct. Because of this even the correct points gave a small error that stopped the perceptron from finding the right answer. By calculating the sign of the answer first the error is 0 if the answer is correct.
This "Given n points on a 2D plane, find the maximum number of points that lie on the same straight line."
question from leetcode.com I am trying to solve it but I am not able to pass all test
cases.
What I am trying to do is:- I am using a hashmap whose key is the angle b/w the points which I am getting through tan inverse of the slope and I am storing the values for each slope initially the value of the no of occurrance of that point and then incrementing it.
I am using another hashmap for counting the occurance of points.
I am not getting the correct answer for points like (0,0),(1,0) which should return 2 but it's returning 1.
What am I missing?
My code is:
public class MaxPointsINLine {
int max = 0;
int same;
public int maxPoints(Point[] points) {
int max = 0;
Map<Double, Integer> map = new HashMap<Double, Integer>();
Map<Point, Integer> pointmap = new HashMap<Point, Integer>();
for(Point point: points)
{
if(!pointmap.containsKey(point))
{
pointmap.put(point, 1);
}
else
{
pointmap.put(point, pointmap.get(point)+1);
}
}
if (points.length >= 2) {
for (int i = 0; i < points.length; i++) {
for (int j = i ; j < points.length; j++) {
double dx = points[j].x - points[i].x;
double dy = points[j].y - points[i].y;
double slope = Math.atan(dy / dx);
if (!map.containsKey(slope)) {
map.put(slope, pointmap.get(points[j]));
} else
map.put(slope, map.get(slope) + 1);
}
}
for (Double key : map.keySet()) {
if (map.get(key) > max) {
max = map.get(key);
}
}
return max;
} else if (points.length != 0) {
return 1;
} else {
return 0;
}
}
public static void main(String[] args) {
Point point1 = new Point(0,0);
Point point2 = new Point(0,0);
//Point point3 = new Point(2,2);
MaxPointsINLine maxpoint = new MaxPointsINLine();
Point[] points = { point1, point2};
System.out.println(maxpoint.maxPoints(points));
}
}
class Point {
int x;
int y;
Point() {
x = 0;
y = 0;
}
Point(int a, int b) {
x = a;
y = b;
}
#Override
public boolean equals(Object obj) {
Point that = (Point)obj;
if (that.x == this.x && that.y == this.y)
return true;
else
return false;
}
#Override
public int hashCode() {
// TODO Auto-generated method stub
return 1;
}
}
The general strategy doesn't seem like it can work. Let's suppose that we've successfully populated map with key-value pairs (a, N) where a is an angle and N is the number of pairs of points that are joined by the angle a. Consider the following arrangement of 6 points:
**
**
**
Explicitly, there are points at (0,0), (1,0), (2,1), (3,1), (0,2), and (1,2). You can check that the maximum number of points that lie on any line is 2. However, there are 3 pairs of points that are joined by the same angle: ((0,0), (1,0)), ((2,1), (3,1)), and ((0,2), (1,2)). So map will contain a key-value pair with N = 3, but that isn't the answer to the original question.
Because of arrangements like the above, it's not enough to count slopes. A successful algorithm will have to represent lines in such a way that you can distinguish between parallel lines.
This one worked for me:
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
public class Solution {
public int maxPoints(Point[] points) {
int result = 0;
for(int i = 0; i<points.length; i++){
Map<Double, Integer> line = new HashMap<Double, Integer>();
Point a = points[i];
int same = 1;
//System.out.println(a);
for(int j = i+1; j<points.length; j++){
Point b = points[j];
//System.out.println(" point " + b.toString());
if(a.x == b.x && a.y == b.y){
same++;
} else {
double dy = b.y - a.y;
double dx = b.x - a.x;
Double slope;
if(dy == 0){ // horizontal
slope = 0.0;
} else if(dx == 0){//eartical
slope = Math.PI/2;
} else {
slope = Math.atan(dy/dx);
}
Integer slopeVal = line.get(slope);
//System.out.println(" slope " + slope + " slope value " + slopeVal);
if(slopeVal == null){
slopeVal = 1;
} else {
slopeVal += 1;
}
line.put(slope, slopeVal);
}
}
for (Double key : line.keySet()) {
Integer val = line.get(key);
result = Math.max(result, val + same);
}
// for all points are same
result = Math.max(result, same);
}
return result;
}
}
The most straightforward solution here seems to be the following: One can consider each pair of points. For each pair, one computes the distance of each other point to the line connecting the two points. If this distance is nearly zero, then the point lies on the line.
When this is done for all pairs, one can pick the pair for which the highest number of points lies on the connecting line.
Of course, this is not very elegant, as it is in O(n^3) and performs some computations twice. But it is very simple and rather reliable. I just implemented this as a MCVE here:
One can set points with left-clicking the mouse. Right-clicks clear the screen. The maximum number of points in one line is displayed, and the corresponding points are highlighted.
(EDIT: Updated to handle points that have a distance of 0, based on the comment)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PointsOnStraightLineTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(new PointsPanel());
f.setSize(600, 600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class PointsOnStraightLine
{
// Large epsilon to make it easier to place
// some points on one line with the mouse...
private static final double EPSILON = 5.0;
List<Point> maxPointsOnLine = new ArrayList<Point>();
void compute(List<Point> points)
{
maxPointsOnLine = new ArrayList<Point>();
for (int i=0; i<points.size(); i++)
{
for (int j=i+1; j<points.size(); j++)
{
Point p0 = points.get(i);
Point p1 = points.get(j);
List<Point> resultPoints = null;
if (p0.distanceSq(p1) < EPSILON)
{
resultPoints = computePointsNearby(p0, points);
}
else
{
resultPoints = computePointsOnLine(p0, p1, points);
}
if (resultPoints.size() > maxPointsOnLine.size())
{
maxPointsOnLine = resultPoints;
}
}
}
}
private List<Point> computePointsOnLine(
Point p0, Point p1, List<Point> points)
{
List<Point> result = new ArrayList<Point>();
for (int k=0; k<points.size(); k++)
{
Point p = points.get(k);
double d = Line2D.ptLineDistSq(p0.x, p0.y, p1.x, p1.y, p.x, p.y);
if (d < EPSILON)
{
result.add(p);
}
}
return result;
}
private List<Point> computePointsNearby(
Point p0, List<Point> points)
{
List<Point> result = new ArrayList<Point>();
for (int k=0; k<points.size(); k++)
{
Point p = points.get(k);
double d = p.distanceSq(p0);
if (d < EPSILON)
{
result.add(p);
}
}
return result;
}
}
class PointsPanel extends JPanel implements MouseListener
{
private final List<Point> points;
private final PointsOnStraightLine pointsOnStraightLine;
PointsPanel()
{
addMouseListener(this);
points = new ArrayList<Point>();
pointsOnStraightLine = new PointsOnStraightLine();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.BLACK);
for (Point p : points)
{
g.fillOval(p.x-2, p.y-2, 4, 4);
}
pointsOnStraightLine.compute(points);
int n = pointsOnStraightLine.maxPointsOnLine.size();
g.drawString("maxPoints: "+n, 10, 20);
g.setColor(Color.RED);
for (Point p : pointsOnStraightLine.maxPointsOnLine)
{
g.drawOval(p.x-3, p.y-3, 6, 6);
}
}
#Override
public void mouseClicked(MouseEvent e)
{
if (SwingUtilities.isRightMouseButton(e))
{
points.clear();
}
else
{
points.add(e.getPoint());
}
repaint();
}
#Override
public void mousePressed(MouseEvent e)
{
}
#Override
public void mouseReleased(MouseEvent e)
{
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
}
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);
}