How to check intersection between 2 rotated rectangles?

前端 未结 11 1721
囚心锁ツ
囚心锁ツ 2020-11-27 04:18

Can someone explain how to check if one rotated rectangle intersect other rectangle?

相关标签:
11条回答
  • 2020-11-27 04:20

    Took Sri's JavaScript and made it work with Phaser 3 Polygons.

        /// Checks if the two Phaser 3 polygons are intersecting.
        gameScene.doPolygonsIntersect=function(a, b) {
            // https://stackoverflow.com/questions/10962379/how-to-check-intersection-between-2-rotated-rectangles#10965077
            /**
             * 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
             */
    
            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.points.length; i1++) {
    
                    // grab 2 vertices to create an edge
                    var i2 = (i1 + 1) % polygon.points.length;
                    var p1 = polygon.points[i1];
                    var p2 = polygon.points[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.points.length; j++) {
                        projected = normal.x * a.points[j].x + normal.y * a.points[j].y;
                        if (!isDef(minA) || projected < minA) {
                            minA = projected;
                        }
                        if (!isDef(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.points.length; j++) {
                        projected = normal.x * b.points[j].x + normal.y * b.points[j].y;
                        if (!isDef(minB) || projected < minB) {
                            minB = projected;
                        }
                        if (!isDef(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;
        };
    
    0 讨论(0)
  • 2020-11-27 04:30

    Here's the same algorithm in Java if anybody is interested.

    boolean isPolygonsIntersecting(Polygon a, Polygon b)
    {
        for (int x=0; x<2; x++)
        {
            Polygon polygon = (x==0) ? a : b;
    
            for (int i1=0; i1<polygon.getPoints().length; i1++)
            {
                int   i2 = (i1 + 1) % polygon.getPoints().length;
                Point p1 = polygon.getPoints()[i1];
                Point p2 = polygon.getPoints()[i2];
    
                Point normal = new Point(p2.y - p1.y, p1.x - p2.x);
    
                double minA = Double.POSITIVE_INFINITY;
                double maxA = Double.NEGATIVE_INFINITY;
    
                for (Point p : a.getPoints())
                {
                    double projected = normal.x * p.x + normal.y * p.y;
    
                    if (projected < minA)
                        minA = projected;
                    if (projected > maxA)
                        maxA = projected;
                }
    
                double minB = Double.POSITIVE_INFINITY;
                double maxB = Double.NEGATIVE_INFINITY;
    
                for (Point p : b.getPoints())
                {
                    double projected = normal.x * p.x + normal.y * p.y;
    
                    if (projected < minB)
                        minB = projected;
                    if (projected > maxB)
                        maxB = projected;
                }
    
                if (maxA < minB || maxB < minA)
                    return false;
            }
        }
    
        return true;
    }
    
    0 讨论(0)
  • 2020-11-27 04:31

    You can also use Rect.IntersectsWith().

    For example, in WPF if you have two UIElements, with RenderTransform and placed on a Canvas, and you want to find out if they intersect you can use something similar:

    bool IsIntersecting(UIElement element1, UIElement element2)
    {
        Rect area1 = new Rect(
            (double)element1.GetValue(Canvas.TopProperty),
            (double)element1.GetValue(Canvas.LeftProperty),
            (double)element1.GetValue(Canvas.WidthProperty),
            (double)element1.GetValue(Canvas.HeightProperty));
    
        Rect area2 = new Rect(
            (double)element2.GetValue(Canvas.TopProperty),
            (double)element2.GetValue(Canvas.LeftProperty),
            (double)element2.GetValue(Canvas.WidthProperty),
            (double)element2.GetValue(Canvas.HeightProperty));
    
        Transform transform1 = element1.RenderTransform as Transform;
        Transform transform2 = element2.RenderTransform as Transform;
    
        if (transform1 != null)
        {
            area1.Transform(transform1.Value);
        }
    
        if (transform2 != null)
        {
            area2.Transform(transform2.Value);
        }
    
        return area1.IntersectsWith(area2);
    }
    
    0 讨论(0)
  • 2020-11-27 04:33

    A Type(Java)Script implementation with a toggle to (ex)include "Touch" situations:

    class Position {
        private _x: number;
        private _y: number;
    
        public constructor(x: number = null, y: number = null) {
            this._x = x;
            this._y = y;
        }
    
        public get x() { return this._x; }
        public set x(value: number) { this._x = value; }
    
        public get y() { return this._y; }
        public set y(value: number) { this._y = value; }
    }
    
    class Polygon {
        private _positions: Array<Position>;
    
        public constructor(positions: Array<Position> = null) {
            this._positions = positions;
        }
    
        public addPosition(position: Position) {
            if (!position) {
                return;
            }
    
            if (!this._positions) {
                this._positions = new Array<Position>();
            }
    
            this._positions.push(position);
        }
    
        public get positions(): ReadonlyArray<Position> { return this._positions; }
    
    /**
     * https://stackoverflow.com/a/12414951/468910
     * 
     * 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 polygonToCompare a polygon to compare with
     * @param allowTouch consider it an intersection when polygons only "touch"
     * @return true if there is any intersection between the 2 polygons, false otherwise
     */
      public isIntersecting(polygonToCompare: Polygon, allowTouch: boolean = true): boolean {
        const polygons: Array<ReadonlyArray<Position>> = [this.positions, polygonToCompare.positions]
    
        const firstPolygonPositions: ReadonlyArray<Position> = polygons[0];
        const secondPolygonPositions: ReadonlyArray<Position> = polygons[1];
    
        let 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
            const polygon = polygons[i];
            for (i1 = 0; i1 < polygon.length; i1++) {
    
                // grab 2 vertices to create an edge
                const i2 = (i1 + 1) % polygon.length;
                const p1 = polygon[i1];
                const p2 = polygon[i2];
    
                // find the line perpendicular to this edge
                const 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 < firstPolygonPositions.length; j++) {
                    projected = normal.x * firstPolygonPositions[j].x + normal.y * firstPolygonPositions[j].y;
    
                    if (!minA || projected < minA || (!allowTouch && projected === minA)) {
                        minA = projected;
                    }
    
                    if (!maxA || projected > maxA || (!allowTouch && 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 < secondPolygonPositions.length; j++) {
                    projected = normal.x * secondPolygonPositions[j].x + normal.y * secondPolygonPositions[j].y;
    
                    if (!minB || projected < minB || (!allowTouch && projected === minB)) {
                        minB = projected;
                    }
    
                    if (!maxB || projected > maxB || (!allowTouch && 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 || (!allowTouch && maxA === minB) || maxB < minA || (!allowTouch && maxB === minA)) {
                    return false;
                }
            }
        }
    
        return true;
    }
    
    0 讨论(0)
  • 2020-11-27 04:33

    Here it is in LUA, hope it will help somebody when they need it:

    function doPolygonsIntersect(a, b)
        local polygons = { a, b };
        local minA, maxA, projected, i, i1, j, minB, maxB;
    
        for i = 1, #polygons do
            --// for each polygon, look at each edge of the polygon, and determine if it separates
            --// the two shapes
            local polygon = polygons[i];
            for i1 = 0, (#polygon-1) do
                --// grab 2 vertices to create an edge
                local i2 = (i1 + 1) % (#polygon);
                local p1 = polygon[i1+1];
                local p2 = polygon[i2+1];
    
                --// find the line perpendicular to this edge
                local normal = { x = p2.y - p1.y, y = p1.x - p2.x };
                minA = nil;
                maxA = nil;
    
                --// 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 = 1, #a do
                    projected = normal.x * a[j].x + normal.y * a[j].y;
                    if (minA == nil or projected < minA) then
                        minA = projected;
                    end
                    if (maxA == nil or projected > maxA) then
                        maxA = projected;
                    end
                end
    
                --// 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 = nil;
                maxB = nil;
                for j = 1, #b do
                    projected = normal.x * b[j].x + normal.y * b[j].y;
                    if (minB == nil or projected < minB) then
                        minB = projected;
                    end
                    if (maxB == nil or projected > maxB) then
                        maxB = projected;
                    end
                end
    
                if (maxA < minB or maxB < minA) then
                    return false;
                end
            end
        end
    
        return true;
    end
    
    0 讨论(0)
  • 2020-11-27 04:34

    In javascript, the exact same algorithm is (for convenience):

    /**
     * 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("polygons don't intersect!");
                    return false;
                }
            }
        }
        return true;
    };
    

    Hope this helps someone.

    0 讨论(0)
提交回复
热议问题