2013-03-29 26 views
9

我不知道從哪裏開始。顯然CGRectIntersectsRect在這種情況下不起作用,你會看到爲什麼。Objective-C檢查旋轉UIViews的子視圖是否相交?

我的UIView的子類,在其內部具有一個UIImageView被放置在了UIView的確切中心:

UIView before rotation

我然後旋轉自定義的UIView到保持內的UIImageView的幀同時仍然能夠執行CGAffineRotation。最後生成的框架看起來是這樣的:

UIView after rotation

我需要防止用戶這些UIImageViews的相交,但我不知道如何檢查兩個的UIImageViews之間的交集,因爲不僅做好自己的幀不適用到父UIView,而且,它們在沒有影響其幀的情況下被旋轉。

我的嘗試的唯一結果是不成功。

任何想法?

回答

8

下面的算法可用於檢查兩個(旋轉或以其它方式轉化的)視圖重疊:

  • 使用[view convertPoint:point toView:nil]到的兩個視圖 4個邊界點轉換到公共座標系(在窗口座標)。
  • 轉換的點形成兩個凸四邊形。
  • 使用SAT (Separating Axis Theorem)檢查四邊形是否相交。

這是:http://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf是包含僞代碼的算法的另一種描述,更多可以通過谷歌搜索「分離軸定理」找到。


更新:我試圖創造了「分離軸定理」一個Objective-C的方法,這是我得到了什麼。到目前爲止,我只做了一些測試,所以我希望沒有太多的錯誤。

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

測試如果2個凸多邊形相交。兩個多邊形均以頂點數組形式給出。

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

測試(如上所述)如果兩個任意視圖相交。

實現:

- (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]; 
} 
+1

的算法的另一個描述:http://stackoverflow.com/a/115520/1187415。 –

+0

太棒了!非常感謝! – David

+0

@MartinR我問了一個新的問題[這裏](http://stackoverflow.com/questions/26821725/determine-if-crop-rect-is-entirely-contained-within-rotated-uiview)基於這個問題/回答。想知道你是否可以看一看? – brandonscript