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.

Upvotes: 7

Views: 1854

Answers (3)

Sam
Sam

Reputation: 500

I have found overlaps.js by yckart.

I have made a fiddle with the rotated divs here: http://jsfiddle.net/n3M5e/

You can change the rotation of the divs in the CSS yourself, and the detection still works well.

overlaps.js:

(function ($) {
    $.fn.overlaps = function (obj) {
        var elems = {
            targets: [],
            hits: []
        };
        this.each(function () {
            var bounds = $(this).offset();
            bounds.right = bounds.left + $(this).outerWidth();
            bounds.bottom = bounds.top + $(this).outerHeight();

            var compare = $(obj).offset();
            compare.right = compare.left + $(obj).outerWidth();
            compare.bottom = compare.top + $(obj).outerHeight();

            if (!(compare.right < bounds.left || compare.left > bounds.right || compare.bottom < bounds.top || compare.top > bounds.bottom)) {
                elems.targets.push(this);
                elems.hits.push(obj);
            }
        });

        return elems;
    };
}(jQuery));

Hope I have helped.

EDIT:

Thanks to @jbrosi, overlaps.js doesn't really work very well with rotated divs.

Upvotes: -1

Alex
Alex

Reputation: 10216

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.

Upvotes: 5

Mazzu
Mazzu

Reputation: 2839

You're looking for div collision detection.

If you want to raise an event, you have to repeatedly test, but it would be be better just to run the function over all your divs.

The sample demo is at http://jsfiddle.net/nGRwt/7/

Here is the function you need to use

function collision($div1, $div2) {
      var x1 = $div1.offset().left;
      var y1 = $div1.offset().top;
      var h1 = $div1.outerHeight(true);
      var w1 = $div1.outerWidth(true);
      var b1 = y1 + h1;
      var r1 = x1 + w1;
      var x2 = $div2.offset().left;
      var y2 = $div2.offset().top;
      var h2 = $div2.outerHeight(true);
      var w2 = $div2.outerWidth(true);
      var b2 = y2 + h2;
      var r2 = x2 + w2;

      if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
      return true;
    }

Another Demo

You can also refer to http://jsfiddle.net/98sAG/ for collison detection.

For this use below code :

var overlaps = (function () {
    function getPositions( elem ) {
        var pos, width, height;
        pos = $( elem ).position();
        width = $( elem ).width();
        height = $( elem ).height();
        return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
    }

    function comparePositions( p1, p2 ) {
        var r1, r2;
        r1 = p1[0] < p2[0] ? p1 : p2;
        r2 = p1[0] < p2[0] ? p2 : p1;
        return r1[1] > r2[0] || r1[0] === r2[0];
    }

    return function ( a, b ) {
        var pos1 = getPositions( a ),
            pos2 = getPositions( b );
        return comparePositions( pos1[0], pos2[0] ) && comparePositions( pos1[1], pos2[1] );
    };
})();

Hope this will help you :)

Upvotes: -1

Related Questions