package com.gebauz.bauzoid.math.collision;
import com.badlogic.gdx.Gdx;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.math.Line2;
import com.gebauz.bauzoid.math.Vector2;
public class CollisionUtil
{
// Constants========================================================================================
// Embedded Types===================================================================================
public static class ProjectionResult
{
public float minimum =
Float.
MAX_VALUE;
public float maximum = -
Float.
MAX_VALUE;
/** Returns true if the projection overlaps. */
public boolean isOverlapping
(ProjectionResult other
)
{
return ((maximum
> other.
minimum) && (minimum
< other.
maximum));
/*if ((minimum >= other.minimum) && (minimum <= other.maximum))
return true;
if ((maximum >= other.minimum) && (maximum <= other.maximum))
return true;
return false;*/
}
/** Return the amount of overlap. */
public float getOverlap
(ProjectionResult other
)
{
if (!isOverlapping
(other
))
return 0.0f
;
float maxEdge =
Math.
min(maximum, other.
maximum);
float minEdge =
Math.
max(minimum, other.
minimum);
return (maxEdge - minEdge
);
}
}
// Fields===========================================================================================
// Methods==========================================================================================
/** Calculate collision and minimal penetration vector using the separating axis theorem.
* Returns null if there is no collision, or the penetration vector between the polygons.
*/
/*public static Vector2 calculatePenetration(Line2[] poly1, Line2[] poly2)
{
// select any line segment from poly1
// project both polygons onto it
// see if they collide
// if not -> return null
// if yes, store penetration amount, and go to next poly and start again
// return the smallest penetration vector
return null;
}*/
/** Calculate collision and minimal penetration vector using the separating axis theorem, return penetration vector.
* Returns null if there is no collision, or the penetration vector between the polygons.
*/
public static Vector2 calculatePenetration
(Line2
[] poly1, Line2
[] poly2
)
{
//if ((move == null) || move.isZero())
//return calculatePenetration(poly1, poly2);
// project polygons onto line defined by move
// compare polygons overlapping
// if none -> return null
// if yes -> return amount of penetration
float minimumOverlap =
Float.
MAX_VALUE;
Vector2 overlapAxis =
new Vector2
();
float overlapAxisDistance =
Float.
MAX_VALUE;
/*float min1 = 0.0f;
float min2 = 0.0f;
float max1 = 0.0f;
float max2 = 0.0f;
int overlapIndex = -1;*/
Vector2 polyCenter1 = getCenter
(poly1
);
for (int i =
0; i
< poly2.
length; i++
)
{
// use normals on each of poly2's edges as axis
Vector2 edge = poly2
[i
].
getLineVector();
//Gdx.app.log(Consts.LOG_TAG, "edge" + i + ": " + poly2[i].ax + ", " + poly2[i].ay + " - " + poly2[i].bx + ", " + poly2[i].by);
Vector2 axis =
new Vector2
(edge.
y, -edge.
x);
Vector2 midPoint = poly2
[i
].
getMidPoint();
midPoint.
subtractVector(polyCenter1
);
float distance = midPoint.
length();
//float distance = poly2[i].getClosestDistanceFrom(polyCenter1);
//axis.normalize();
ProjectionResult result1 = projectPoly
(poly1, axis
);
ProjectionResult result2 = projectPoly
(poly2, axis
);
// if not overlapping we can early-break
if (!result1.
isOverlapping(result2
))
{
return null;
}
float overlap = result1.
getOverlap(result2
);
final float OVERLAP_DELTA = 0.01f
;
//Gdx.app.log(Consts.LOG_TAG, "Overlap" + i + ": " + overlap + " (" + axis.x + ", " + axis.y + ") distance: " + distance);
if ((overlap
< (minimumOverlap - OVERLAP_DELTA
)) ||
((Math.
abs(overlap - minimumOverlap
) <= OVERLAP_DELTA
) && (distance
< overlapAxisDistance
)))
{
/*min1 = result1.minimum;
min2 = result2.minimum;
max1 = result1.maximum;
max2 = result2.maximum;
overlapIndex = i;*/
minimumOverlap = overlap
;
overlapAxis = axis.
copy();
overlapAxisDistance = distance
;
}
}
//Gdx.app.log(Consts.LOG_TAG, "OVERLAP: " + minimumOverlap + " (" + overlapAxis.x + ", " + overlapAxis.y + ") overlapIndex: " + overlapIndex);
//Gdx.app.log(Consts.LOG_TAG, "min1: " + min1 + " max1: " + max1 + " min2: " + min2 + " max2: " + max2);
/*
//Gdx.app.log(Consts.LOG_TAG, "-------------------------------");
Vector2 axis = move.copy();
axis.normalize();
//Gdx.app.log(Consts.LOG_TAG, "Axis: " + axis.x + ", " + axis.y);
ProjectionResult result1 = projectPoly(poly1, axis);
//Gdx.app.log(Consts.LOG_TAG, "[1] Min: " + result1.minimum + " Max:" + result1.maximum);
ProjectionResult result2 = projectPoly(poly2, axis);
//Gdx.app.log(Consts.LOG_TAG, "[2] Min: " + result2.minimum + " Max:" + result2.maximum);
if (result1.isOverlapping(result2))
Gdx.app.log(Consts.LOG_TAG, "OVERLAP! OVERLAP! OVERLAP!");*/
float l = overlapAxis.
squaredLength();
return new Vector2
(overlapAxis.
x * (minimumOverlap / l
), overlapAxis.
y * (minimumOverlap / l
));
}
/** Get the center point of a poly. */
public static Vector2 getCenter
(Line2
[] poly
)
{
Vector2 result =
new Vector2
(0,
0);
for (int i =
0; i
< poly.
length; i++
)
{
// need just one point because it should be a closed polygon
result.
x += poly
[i
].
ax;
result.
y += poly
[i
].
ay;
}
result.
x /=
(float)poly.
length;
result.
y /=
(float)poly.
length;
return result
;
}
/** Project the polygon onto an axis. */
public static ProjectionResult projectPoly
(Line2
[] poly, Vector2 axis
)
{
ProjectionResult result =
new ProjectionResult
();
for (int i =
0; i
< poly.
length; i++
)
{
// project the vector from origin to each of the line segment's end points onto b
// the result is the section on the axis
Vector2 a =
new Vector2
(poly
[i
].
ax, poly
[i
].
ay);
Vector2 b =
new Vector2
(poly
[i
].
bx, poly
[i
].
by);
float dpA = Vector2.
dotProduct(a, axis
);
float dpB = Vector2.
dotProduct(b, axis
);
//Gdx.app.log(Consts.LOG_TAG, "a: " + a.x + ", " + a.y + " (" + dpA + ") - b: " + b.x + ", " + b.y + " (" + dpB + ")");
if (dpA
< result.
minimum)
result.
minimum = dpA
;
if (dpB
< result.
minimum)
result.
minimum = dpB
;
if (dpA
> result.
maximum)
result.
maximum = dpA
;
if (dpB
> result.
maximum)
result.
maximum = dpB
;
}
return result
;
}
// Getters/Setters==================================================================================
}