Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if two rotated divs collide using JQuery

I would like to detect if two rotated divs are colliding. I know how to do it if they're not rotated, but I don't know how to do it when they actually are.

I have tried some collision plugins such as jQuery Collision (http://sourceforge.net/projects/jquerycollision/), but they have not worked when the div is rotated.

I have made the rotation of the divs using CSS's transform property.

like image 922
Imanol Pérez Arribas Avatar asked Jul 26 '14 11:07

Imanol Pérez Arribas


1 Answers

It is not 100% accurate but it does work for most cases, I used the algorythm from here:

function isUndefined(a) {
    return a === undefined;
}

/**
 * Helper function to determine whether there is an intersection between the two polygons described
 * by the lists of vertices. Uses the Separating Axis Theorem
 *
 * @param a an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
 * @param b an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
 * @return true if there is any intersection between the 2 polygons, false otherwise
 */
function doPolygonsIntersect (a, b) {
    var polygons = [a, b];
    var minA, maxA, projected, i, i1, j, minB, maxB;

    for (i = 0; i < polygons.length; i++) {

        // for each polygon, look at each edge of the polygon, and determine if it separates
        // the two shapes
        var polygon = polygons[i];
        for (i1 = 0; i1 < polygon.length; i1++) {

            // grab 2 vertices to create an edge
            var i2 = (i1 + 1) % polygon.length;
            var p1 = polygon[i1];
            var p2 = polygon[i2];

            // find the line perpendicular to this edge
            var normal = { x: p2.y - p1.y, y: p1.x - p2.x };

            minA = maxA = undefined;
            // for each vertex in the first shape, project it onto the line perpendicular to the edge
            // and keep track of the min and max of these values
            for (j = 0; j < a.length; j++) {
                projected = normal.x * a[j].x + normal.y * a[j].y;
                if (isUndefined(minA) || projected < minA) {
                    minA = projected;
                }
                if (isUndefined(maxA) || projected > maxA) {
                    maxA = projected;
                }
            }

            // for each vertex in the second shape, project it onto the line perpendicular to the edge
            // and keep track of the min and max of these values
            minB = maxB = undefined;
            for (j = 0; j < b.length; j++) {
                projected = normal.x * b[j].x + normal.y * b[j].y;
                if (isUndefined(minB) || projected < minB) {
                    minB = projected;
                }
                if (isUndefined(maxB) || projected > maxB) {
                    maxB = projected;
                }
            }

            // if there is no overlap between the projects, the edge we are looking at separates the two
            // polygons, and we know there is no overlap
            if (maxA < minB || maxB < minA) {
                console.log("polygons don't intersect!");
                return false;
            }
        }
    }
    return true;
};

$('#r').click(function() {
    var rota = Math.floor( Math.random() * 100 ),
        rotb = Math.floor( Math.random() * 100 ),
        pointsa = new Array(4),
        pointsb = new Array(4);

    $('#a').css('transform', 'rotateZ(' + rota + 'deg)');
    $('#b').css('transform', 'rotateZ(' + rotb + 'deg)');

    $('#a div').each(function(i) {
        pointsa[i] = {x: parseInt($(this).offset().left), y: parseInt($(this).offset().top)};
    });

    $('#b div').each(function(i) {
        pointsb[i] = {x: parseInt($(this).offset().left), y: parseInt($(this).offset().top)};
    });


    $('#s').val("intersection: " + doPolygonsIntersect(pointsb, pointsa).toString());
});

working fiddle

It's not the best way of doing it I guess, what my script does is basically give a random rotation between 0 and 100 degrees, get the x and y positions of each corner (using divs, you can do that with math, also (i cant :D)) and run the algorythm using those coordinates.

like image 150
Alex Avatar answered Oct 12 '22 23:10

Alex