CGAffineTranformRotate atan2 不准确
我正在转换视图,总是发生一些奇怪的事情,我的意思是我使用以下代码计算角度:angle = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint) .y - center.y, previousTouchPoint.x - center.x);
并且视图旋转但不正确。我的意思是它以正确的方向旋转,但角度始终不准确,约为 +/- 0.05 弧度。当我再次点击时,视图会旋转到正确的位置。有什么建议吗?对我来说,将角度精确到逗号后的 5 位非常重要。
Some NSLog to show you the problem:
First rotation first tap and second tap
2012-01-07 01:01:26.283 Wheel[9080:707] Angle: 0.598412
2012-01-07 01:01:29.281 Wheel[9080:707] Angle: -0.070008
Second rotation first tap and second tap
2012-01-07 01:01:31.103 Wheel[9080:707] Angle: -0.679809
2012-01-07 01:01:32.450 Wheel[9080:707] Angle: 0.092595
Third rotation first tap and second tap
2012-01-07 01:01:35.745 Wheel[9080:707] Angle: 0.607844
2012-01-07 01:01:36.945 Wheel[9080:707] Angle: -0.064927
Fourth rotation first tap and second tap
2012-01-07 01:01:41.073 Wheel[9080:707] Angle: -0.635756
2012-01-07 01:01:41.920 Wheel[9080:707] Angle: 0.052361
而且我忘了告诉你,条件是,点之间的差异越远,不准确度就越大。
编辑:
Circle *view = (Circle *) [self view];
for (CircleThumb *thumb in view.subviews) {
CGPoint point = [thumb convertPoint:thumb.centerPoint toView:nil];
CircleThumb *shadow = [[view.overlayView subviews] lastObject];
CGPoint centralPoint = [shadow convertPoint:shadow.centerPoint toView:nil];
CGRect shadowRect = [shadow.superview convertRect:shadow.frame toView:nil];
if (CGRectContainsPoint(shadowRect, point) == YES) {
CGPoint pointInShadowRect = [thumb convertPoint:thumb.centerPoint toView:shadow];
if (CGPathContainsPoint(shadow.arc.CGPath, NULL, pointInShadowRect, NULL)) {
CGAffineTransform current = view.transform;
CGPoint center = view.window.center;
CGPoint currentTouchPoint =centralPoint;
CGPoint previousTouchPoint = point;
long double angle = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);
[UIView animateWithDuration:0.3f animations:^{
[view setTransform:CGAffineTransformRotate(current, angle)];
}];
[view.delegate circle:view didMoveToSegment:thumb.tag thumb:thumb];
NSLog(@"Angle: %Lf ", angle);
break;
}
}
}
这是“-touchesEnded:withEvent:”实现的一部分的代码,
我正在制作类似于Convert bot中的控制。我的应用程序和 Convertbot 中的“轮子”看起来很相似,但我的应用程序使用自定义绘图。
所以 Circle 是一个我们旋转的 UIView。 Circle 有子视图 - CircleThumbs。拇指代表圆的单段。分数是正确计算的,但我不会解释为什么,因为没有必要。
I'm making transition of my view and always happens something weird, I mean I calculate angle using this code: angle = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);
And the view rotates but not properly. I mean it rotates in proper direction but the angle is always inaccurate about +/- 0.05 radians. And when I tap again, view rotates into proper position. Any adivices? It's important to me to get angle accurate to 5 places after comma.
Some NSLog to show you the problem:
First rotation first tap and second tap
2012-01-07 01:01:26.283 Wheel[9080:707] Angle: 0.598412
2012-01-07 01:01:29.281 Wheel[9080:707] Angle: -0.070008
Second rotation first tap and second tap
2012-01-07 01:01:31.103 Wheel[9080:707] Angle: -0.679809
2012-01-07 01:01:32.450 Wheel[9080:707] Angle: 0.092595
Third rotation first tap and second tap
2012-01-07 01:01:35.745 Wheel[9080:707] Angle: 0.607844
2012-01-07 01:01:36.945 Wheel[9080:707] Angle: -0.064927
Fourth rotation first tap and second tap
2012-01-07 01:01:41.073 Wheel[9080:707] Angle: -0.635756
2012-01-07 01:01:41.920 Wheel[9080:707] Angle: 0.052361
And I forget to tell you, condition, the difference between points is farther the inaccuration is bigger.
EDIT:
Circle *view = (Circle *) [self view];
for (CircleThumb *thumb in view.subviews) {
CGPoint point = [thumb convertPoint:thumb.centerPoint toView:nil];
CircleThumb *shadow = [[view.overlayView subviews] lastObject];
CGPoint centralPoint = [shadow convertPoint:shadow.centerPoint toView:nil];
CGRect shadowRect = [shadow.superview convertRect:shadow.frame toView:nil];
if (CGRectContainsPoint(shadowRect, point) == YES) {
CGPoint pointInShadowRect = [thumb convertPoint:thumb.centerPoint toView:shadow];
if (CGPathContainsPoint(shadow.arc.CGPath, NULL, pointInShadowRect, NULL)) {
CGAffineTransform current = view.transform;
CGPoint center = view.window.center;
CGPoint currentTouchPoint =centralPoint;
CGPoint previousTouchPoint = point;
long double angle = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);
[UIView animateWithDuration:0.3f animations:^{
[view setTransform:CGAffineTransformRotate(current, angle)];
}];
[view.delegate circle:view didMoveToSegment:thumb.tag thumb:thumb];
NSLog(@"Angle: %Lf ", angle);
break;
}
}
}
This is code which is part of '- touchesEnded: withEvent:' implementation
I'm making control similar to the one in Convert bot. the "wheels" from my app and from convertbot look similar but mine uses custom drawing.
So Circle is a UIView which we rotate. Circle has got subviews - CircleThumbs. thumb represents single segment of the circle. Points are calculated properly but I won't explain why, because there's no need.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
阿坦计算永远不会完全正确。然后你让 iOS 再次计算角度之外的 cos 和 sin(cgaffinetransformRotate 就是这样做的)。所以你正在堆积三角函数的不准确性。由于您仅计算与前一个角度的差异,因此我想您还会累积多个触摸事件的不准确性。
如果是旋转某物,那么就没有理由使用三角学或角度。您可以使用线性代数完全实现这一点。像这样的东西:
这个伪代码计算当前点的归一化向量(还存储了前一个点的向量)。然后我们定义一个矩阵,将先前的向量旋转为新的向量。该矩阵与现有的转换连接起来。
如果旋转不总是根据先前的状态计算,而是根据初始状态计算,那就更好了。诀窍是仅计算达阵的“前一个”。
An atan calculation is never entirely correct. And you let iOS calculate cos and sin out of the angle again (cgaffinetransformRotate does that). So you're stacking up trigonometric inaccuracies. And since you calculate only the difference wi the previous angle, I imagine that you are also stacking up inaccuracies over the multiple touch events.
If it is to rotate something, then there is no reason to use trigonometry or angles. You can implement this completely using linear algebra. Something like this:
This pseudo code calculates a normalized vector for current point (the one for the previous point was also stored). Then we define a matrix that rotates the previous vector into the new vector. That matrix is concatenated with the existing transformation.
It would be better if the rotation wasn't always calculated from the previous state, but rather from an initial state. The trick is to calculate 'previous' only for the touchdown.