Objective-C check if subviews of rotated UIViews intersect?

前端 未结 1 1498

I don\'t know where to start with this one. Obviously CGRectIntersectsRect will not work in this case, and you\'ll see why.

I have a subclass of UIView

相关标签:
1条回答
  • 2020-12-08 18:12

    The following algorithm can be used to check if two (rotated or otherwise transformed) views overlap:

    • Use [view convertPoint:point toView:nil] to convert the 4 boundary points of both views to a common coordinate system (the window coordinates).
    • The converted points form two convex quadrilaterals.
    • Use the SAT (Separating Axis Theorem) to check if the quadrilaterals intersect.

    This: http://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf is another description of the algorithm containing pseudo-code, more can be found by googling for "Separating Axis Theorem".


    Update: I have tried to create a Objective-C method for the "Separating Axis Theorem", and this is what I got. Up to now, I did only a few tests, so I hope that there are not too many errors.

    - (BOOL)convexPolygon:(CGPoint *)poly1 count:(int)count1 intersectsWith:(CGPoint *)poly2 count:(int)count2;
    

    tests if 2 convex polygons intersect. Both polygons are given as a CGPoint array of the vertices.

    - (BOOL)view:(UIView *)view1 intersectsWith:(UIView *)view2
    

    tests (as described above) if two arbitrary views intersect.

    Implementation:

    - (void)projectionOfPolygon:(CGPoint *)poly count:(int)count onto:(CGPoint)perp min:(CGFloat *)minp max:(CGFloat *)maxp
    {
        CGFloat minproj = MAXFLOAT;
        CGFloat maxproj = -MAXFLOAT;
        for (int j = 0; j < count; j++) {
            CGFloat proj = poly[j].x * perp.x + poly[j].y * perp.y;
            if (proj > maxproj)
                maxproj = proj;
            if (proj < minproj)
                minproj = proj;
        }
        *minp = minproj;
        *maxp = maxproj;
    }
    
    -(BOOL)convexPolygon:(CGPoint *)poly1 count:(int)count1 intersectsWith:(CGPoint *)poly2 count:(int)count2
    {
        for (int i = 0; i < count1; i++) {
            // Perpendicular vector for one edge of poly1:
            CGPoint p1 = poly1[i];
            CGPoint p2 = poly1[(i+1) % count1];
            CGPoint perp = CGPointMake(- (p2.y - p1.y), p2.x - p1.x);
    
            // Projection intervals of poly1, poly2 onto perpendicular vector:
            CGFloat minp1, maxp1, minp2, maxp2;
            [self projectionOfPolygon:poly1 count:count1 onto:perp min:&minp1 max:&maxp1];
            [self projectionOfPolygon:poly2 count:count1 onto:perp min:&minp2 max:&maxp2];
    
            // If projections do not overlap then we have a "separating axis"
            // which means that the polygons do not intersect:
            if (maxp1 < minp2 || maxp2 < minp1)
                return NO;
        }
    
        // And now the other way around with edges from poly2:
        for (int i = 0; i < count2; i++) {
            CGPoint p1 = poly2[i];
            CGPoint p2 = poly2[(i+1) % count2];
            CGPoint perp = CGPointMake(- (p2.y - p1.y), p2.x - p1.x);
    
            CGFloat minp1, maxp1, minp2, maxp2;
            [self projectionOfPolygon:poly1 count:count1 onto:perp min:&minp1 max:&maxp1];
            [self projectionOfPolygon:poly2 count:count1 onto:perp min:&minp2 max:&maxp2];
    
            if (maxp1 < minp2 || maxp2 < minp1)
                return NO;
        }
    
        // No separating axis found, then the polygons must intersect:
        return YES;
    }
    
    - (BOOL)view:(UIView *)view1 intersectsWith:(UIView *)view2
    {
        CGPoint poly1[4];
        CGRect bounds1 = view1.bounds;
        poly1[0] = [view1 convertPoint:bounds1.origin toView:nil];
        poly1[1] = [view1 convertPoint:CGPointMake(bounds1.origin.x + bounds1.size.width, bounds1.origin.y) toView:nil];
        poly1[2] = [view1 convertPoint:CGPointMake(bounds1.origin.x + bounds1.size.width, bounds1.origin.y + bounds1.size.height) toView:nil];
        poly1[3] = [view1 convertPoint:CGPointMake(bounds1.origin.x, bounds1.origin.y + bounds1.size.height) toView:nil];
    
        CGPoint poly2[4];
        CGRect bounds2 = view2.bounds;
        poly2[0] = [view2 convertPoint:bounds2.origin toView:nil];
        poly2[1] = [view2 convertPoint:CGPointMake(bounds2.origin.x + bounds2.size.width, bounds2.origin.y) toView:nil];
        poly2[2] = [view2 convertPoint:CGPointMake(bounds2.origin.x + bounds2.size.width, bounds2.origin.y + bounds2.size.height) toView:nil];
        poly2[3] = [view2 convertPoint:CGPointMake(bounds2.origin.x, bounds2.origin.y + bounds2.size.height) toView:nil];
    
        return [self convexPolygon:poly1 count:4 intersectsWith:poly2 count:4];
    }
    
    0 讨论(0)
提交回复
热议问题