Search code examples
androidcollision-detection

Android, How to check collision between two rotated views


I am trying to randomize the position of a few textviews inside a frameview. The textviews will also have a randomized rotation between 0 and 360 degrees. The textViews is not allowed to be on top of eachother which means I need to check for collisions (or at least know which points that are valid/not valid). I do not know how to check for collision between two textviews when they are rotated. I have tried to use Rect intersects but this does not really work because this function only works if there is no rotation to the view.

Here is an example on what i want:

enter image description here

TEXT1 is placed first. When TEXT2 is placed the green border around the TEXT1 and TEXT2 is colliding which means that TEXT2 should not be allowed to be placed there. TEXT3 does however not collide with anything and should be allowed to be placed. So I want to check the collision for the green border and not the blue rectangle. How do I do this?

Edit

To rotate the view I am using View.setRotation(float)

To position the textview I am using setX(float) and setY(float).


Solution

  • I ended up with the following solution where I create 4 points, one for each corner of the textView, which I then rotate at the same angle as the textView. With these points I then create a Path which I am using to create a region.

    private Region createRotatedRegion(TextView textView){
        Matrix matrix = new Matrix();
        matrix.setRotate(textView.getRotation(), textView.getX() + textView.getMeasuredWidth() / 2, textView.getY() + textView.getMeasuredHeight() / 2);
    
        Path path = new Path();
        Point LT = rotatePoint(matrix, textView.getX(), textView.getY());
        Point RT = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY());
        Point RB = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY() + textView.getMeasuredHeight());
        Point LB = rotatePoint(matrix, textView.getX(), textView.getY() + textView.getMeasuredHeight());
    
        path.moveTo(LT.x, LT.y);
        path.lineTo(RT.x, RT.y);
        path.lineTo(RB.x, RB.y);
        path.lineTo(LB.x, LB.y);
    
        Region region = new Region();
        region.setPath(path,  new Region(0, 0, textViewParent.getWidth(), textViewParent.getHeight()));
        return region;
    }
    
    private Point rotatePoint(Matrix matrix, float x, float y){
        float[] pts = new float[2];
        pts[0] = x;
        pts[1] = y;
        matrix.mapPoints(pts);
        return new Point((int)pts[0], (int)pts[1]);
    }
    

    When I have two regions which now have the same position and rotation as two textViews I can then use the following code to check for collision:

    if (!region1.quickReject(region2) && region1.op(region2, Region.Op.INTERSECT)) {
        return true; //There is a collision
    }
    

    Probably not the best solution but it gets the job done.