如何解决这个轮换问题?

时间:2009-11-22 13:47:01

标签: iphone cocoa-touch math rotation

对于你们中的一些人来说,这对你来说非常简单。

但是:当我旋转视图时,让我们说从0度开始并向前旋转0.1,1,10,100,150,160,170,179,179,999,并继续向同一方向旋转,这种情况发生,说得清清楚楚:BANG !!!! BAAAAAAAAANNNNNGGGG !!!! -179,9999,-170,-150,-50,0,50,100,170,179,99,再次:BBBBAAAANNNGGG !!! -179,999,-170,-100等等......肯定你知道我的意思; - )

想象一下,你在一条道路上行驶,突然你的英里距离跳得如此。你会惊慌失措,对吗?

你知道吗?这对我的算法来说非常糟糕。我有没有想法如何解决这个问题,而不是检查if-else-blocks,如果我的值突然交换掉了。有些东西告诉我,我必须看一些数学函数,如窦波和其他东西。但是我的数学知识很有吸引力。

我该如何解决这个问题?我尝试计算角度之间的距离,即我有两个视图,其中一个位于另一个,两个都旋转。我想计算两个视图的整体轮换。一旦价值突然从-179,99999转换到179,99999,这个小但疯狂的东西会破坏我的计算。如果你知道我的意思,我也不知道是否存在180或者如果事情在fabsf(179,999999999999999999999)交换。

例如:什么是-170度减去50度?好吧,我认为-220度。但是当我旋转-170 - 50时,我最终得到这个值:40度。

如果没有任何不安全的交换if-else逻辑,我怎样才能收到我期望的-220而不是40?有时我的自制交换器可以正常工作,但有时它不会因为数学方面的困难。

编辑:我根据视图图层的transform.rotation.z属性计算角度。

3 个答案:

答案 0 :(得分:5)

视图不是数据的规范表示,查询会告诉您系统的可视状态,仅此而已。如果您关心角度的特定表示,那么您不应该从变换中读取它,您应该根据需要将其存储在模型或控制器中,并根据它设置视图的状态。

@interface MyViewController: UIViewController {
  CGFloat rotation;
}

@property (nonatomic) CGFloat rotation;

@end

@implementation MyViewController
@synthesize rotation;

- (void)setRotation:(CGFloat)rotation_ {
  rotation = rotation_;
  // Do whatever math you want and set the transform of the view based on that;
}
@end

答案 1 :(得分:1)

你在这里看到的是角度数学就像时钟一样模块化。在时钟上11 + 2 == 1而不是13.同样,您可以将所有角度表示为负旋转或正旋转。所以,+ 180 ==( - 180)。所以,179 + 2 =( - 179)。变换正在计算从原始零旋转开始的最短距离旋转。显然,181度的最短旋转实际上是-179度的负旋转。

除非您将相同的变换提供给变换计算,否则变换不会累积。这意味着如果您创建一个转换以将视图旋转45度然后将其应用两次,则只能获得45度旋转。要获得累积旋转,您需要使用像CGAffineTransformRotate这样的函数,并继续为它提供前一轮的变换。

只要喂食角度<180°,这将在相同方向上产生平滑旋转。

答案 2 :(得分:1)

对于你的UIView的CALayer,transform属性是一个CATransform3D结构。该结构没有旋转成员,但Apple提供了一个便利键路径来设置和读取该结构的旋转。从正度到负度的变化是用于确定结构旋转的计算的人为因素。这个数学是在Quartz 2D Programming Guide部分"The Math Behind the Matrices"中针对CATransform3D,CGAffineTransform的2-D等价物描述的。

为了解决这个问题,您可以使用我在this answer中提供的代码自行进行计算:

CATransform3D rotationTransform = [(CALayer *)[self.layer presentationLayer] transform];
float angle;
if (rotationTransform.m11 < 0.0f)
        angle = 180.0f - (asin(rotationTransform.m12) * 180.0f / M_PI);
else
        angle = asin(rotationTransform.m12) * 180.0f / M_PI;

这应该产生从0到360的角度值。由于旋转的周期特性,一旦你越过0或360,这将会翻转。