Функции вращения iPhone и математические вращения вручную несовместимы - PullRequest
0 голосов
/ 23 июня 2010

В настоящее время я вращаю UIImageView, касаясь, перетаскивая и отпуская. Я вращаю объект по функции:

-(void)rotateForTime:(CGFloat)time distance:(CGFloat)distance
{
    CABasicAnimation* rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = [NSNumber numberWithFloat:distance];
    rotationAnimation.removedOnCompletion = NO;
    rotationAnimation.fillMode = kCAFillModeForwards;
    rotationAnimation.duration = time;
    rotationAnimation.repeatCount = 1.0;
    rotationAnimation.timingFunction = [CAMediaTimingFunctionfunctionWithName:
                                                kCAMediaTimingFunctionEaseOut];
    rotationAnimation.delegate = self;
    [bottle.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

Поскольку после поворота границы прямоугольного изображения меняются, чтобы определить, касается ли пользователь внутреннего изображения или нет, я отслеживаю углы изображения, поворачивая их на то же расстояние, на которое я поворачиваю изображение и затем используйте методы определения вектора-> пересечения ребер, чтобы проверить, коснулся ли пользователь границ прямоугольника, сделанного углами. Я использую эту функцию для поворота углов:

-(void) rotateImageBounds:(CGFloat) angle
{
    // Translate the center and the corners of the image to the origin and their respective positions.
    corner1.x = corner1.x - bottle.center.x;
    corner1.y = corner1.y - bottle.center.y;
    corner2.x = corner2.x - bottle.center.x;
    corner2.y = corner2.y - bottle.center.y;
    corner3.x = corner3.x - bottle.center.x;
    corner3.y = corner3.y - bottle.center.y;
    corner4.x = corner4.x - bottle.center.x;
    corner4.y = corner4.y - bottle.center.y;

    // Rotates the point around the origin/center.
    // x = x1cos(angle) - x1sin(angle)
    // y = x1sin(angle) + y1cos(angle)
    CGFloat tempX;
    tempX = (corner1.x*cos(angle)) - (corner1.y*sin(angle));
    corner1.y = (corner1.x*sin(angle)) + (corner1.y*cos(angle));
    corner1.x = tempX;
    tempX = (corner2.x*cos(angle)) - (corner2.y*sin(angle));
    corner2.y = (corner2.x*sin(angle)) + (corner2.y*cos(angle));
    corner2.x = tempX;
    tempX = (corner3.x*cos(angle)) - (corner3.y*sin(angle));
    corner3.y = (corner3.x*sin(angle)) + (corner3.y*cos(angle));
    corner3.x = tempX;
    tempX = (corner4.x*cos(angle)) - (corner4.y*sin(angle));
    corner4.y = (corner4.x*sin(angle)) + (corner4.y*cos(angle));
    corner4.x = tempX;

    // Translates the points back to the original center of the image.
    corner1.x = corner1.x + bottle.center.x;
    corner1.y = corner1.y + bottle.center.y;
    corner2.x = corner2.x + bottle.center.x;
    corner2.y = corner2.y + bottle.center.y;
    corner3.x = corner3.x + bottle.center.x;
    corner3.y = corner3.y + bottle.center.y;
    corner4.x = corner4.x + bottle.center.x;
    corner4.y = corner4.y + bottle.center.y;
}

Это прекрасно работает после первого поворота, углы выглядят так, как будто все еще находятся в углах изображения. Однако после дополнительных поворотов изображение и углы больше не совпадают. Насколько я знаю, метод вращения точен, и математика для углов правильна. Я пытался разобраться с этой проблемой уже несколько дней. Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ * Проблема решена: В итоге я позволил анимации удалить себя, когда она была сделана, и просто повернул изображение в правильное положение, когда я закончил (это было проще, потому что мне также нужно поворачивать изображение во время движения мыши). Для функции поворота: (угол - это угол, под которым в данный момент находилась мышь (или касание), полученный с помощью atan2 (dy, dx), где dy - высота между касанием и центром, а dx - ширина. нужно вращать.

-(void)rotateForTime:(CGFloat)time distance:(CGFloat)distance
{

animating = TRUE;
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.fromValue = [NSNumber numberWithFloat:angle];
rotationAnimation.toValue = [NSNumber numberWithFloat:distance + angle];
rotationAnimation.removedOnCompletion = YES;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.duration = time;
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = [CAMediaTimingFunction
                                      functionWithName:kCAMediaTimingFunctionEaseOut];
rotationAnimation.delegate = self;

[bottle.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

А затем в конце анимации:

-(void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{

animating = FALSE;
    // Rotates the image to the last spot that the animation rotated to.
[bottle.layer setValue:[NSNumber numberWithFloat:angle + distance]
                                    forKeyPath:@"transform.rotation.z"];

    // Gives the corners of the image after rotation (Thanks to mustISignUp) check to make sure 
    // that the touch is within these bounds (I use a ray line intersection algorithm in another part of my code)
ptInLayerCoords1 = [[bottle.layer presentationLayer] convertPoint:corner1 toLayer:self.view.layer];
ptInLayerCoords2 = [[bottle.layer presentationLayer] convertPoint:corner2 toLayer:self.view.layer];
ptInLayerCoords3 = [[bottle.layer presentationLayer] convertPoint:corner3 toLayer:self.view.layer];
ptInLayerCoords4 = [[bottle.layer presentationLayer] convertPoint:corner4 toLayer:self.view.layer];
}

Ответы [ 2 ]

0 голосов
/ 23 июня 2010

Как говорит BlueRaja, математика не точна - она ​​изначально приблизительная, и вы накапливаете ошибки. Вам необходимо каждый раз пересчитывать положение углов по абсолютным размерам и повороту слоя, а не пытаться отслеживать его.

К счастью, CALayer может сделать это для вас без особых хлопот

ptInLayerCoords = [bottle.layer convertPoint:pt fromLayer:self.layer];
didHit = [layer containsPoint:ptInLayerCoords];
0 голосов
/ 23 июня 2010

Я не знаком с IPhone, но это обычно происходит из-за накопления ошибок округления (которые особенно очевидны, если corner.x / corner.y являются целыми числами).

Чтобы исправить, вместо того, чтобы иметь повернутый прямоугольник, который вы поворачиваете снова каждый кадр (или каждый раз, когда пользователь касается экрана, или что-то еще), вы сохраняете только угловое смещение от исходной ориентации прямоугольника и пересчитываетеновые координаты каждый кадр.

...