Subversion Repositories AndroidProjects

Rev

Rev 1150 | Rev 1153 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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==================================================================================

}