Objective-C проверяет, пересекаются ли подпредставления повернутых UIViews?

Я не знаю, с чего начать. очевидно CGRectIntersectsRect не будет работать в этом случае, и вы поймете, почему.

У меня есть подкласс UIView, который имеет UIImageView внутри него, который находится в точном центре UIView:

UIView до вращения

Затем я поворачиваю пользовательский UIView, чтобы сохранить кадр внутреннего UIImageView, при этом все еще будучи в состоянии выполнить CGAffineRotation. Результирующий кадр выглядит примерно так:

UIView после вращения

Мне нужно предотвратить пересечение пользователями этих UIImageView, но я понятия не имею, как проверить пересечение между двумя UIImageView, так как их кадры не только не применяются к родительскому UIView, но также они вращаются так, что это не влияет на их кадры.

Единственные результаты моих попыток оказались безуспешными.

Есть идеи?

1 ответ

Решение

Следующий алгоритм может использоваться, чтобы проверить, перекрываются ли два (повернутые или иным образом преобразованные) представления:

  • использование [view convertPoint:point toView:nil] преобразовать 4 граничные точки обоих видов в общую систему координат (координаты окна).
  • Преобразованные точки образуют два выпуклых четырехугольника.
  • Используйте SAT (Теорема о разделяющей оси), чтобы проверить, пересекаются ли четырехугольники.

Это: http://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf - еще одно описание алгоритма, содержащего псевдокод, более подробную информацию можно найти, прибегнув к поиску "Теорема о разделяющей оси".


Обновление: я попытался создать метод Objective-C для "Теоремы о разделяющей оси", и это то, что я получил. До сих пор я провел всего несколько тестов, поэтому надеюсь, что ошибок будет не слишком много.

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

проверяет, пересекаются ли 2 выпуклых многоугольника. Оба полигона даны как CGPoint массив вершин.

- (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];
}
Другие вопросы по тегам