IOS中二维坐标变换

1.坐标变换的数学基础

      1.1 坐标系

          数学中我们使用的是笛卡儿坐标系,如下图所示:                    

                 

            X轴正方向向右,Y轴正方向向上,原点O,坐标点A(x,y)

         1.2 仿射变换

             已知坐标点A,变换后新坐标系中坐标为B ,则有:

                                               B = AM

                  A1*3的矩阵[x,y,1]

                  B 1* 3的矩阵[x’,y’,1]

                  M3*3仿射矩阵

                             

                  所以AMB可以写成:

                            

                 展开后得到:   

                                  

                 以下是常用的变换矩阵:

                     单位矩阵:

                               

                      展开后得:

                              

                      平移矩阵:          

                              

                     展开后得: 

                              

                     缩放矩阵:

                             

                    展开后得:

                             

                            旋转矩阵:

                            

                   展开后得:       

                                                                                                                                                                    

      1.3 坐标变换类型

           模型变换: 坐标系固定不动,变换坐标系中的模型

           坐标轴变换:坐标系中模型固定不动, 变换坐标系,相对于新坐标系构造的变换矩阵和模型变换矩阵是一样的          

          

          如上图所示,A为原坐标系C中坐标,A'为新坐标系中C'坐标,在模型变换中新坐标系和原坐标系重叠在一起    

          二种变换方式A->A'变换矩阵都是相同的.     

2. IOS中坐标系

       2.1 IOS中包含UIKit坐标系(X正方向向右,Y正方向向)和标准的Quartz 2D绘图坐标系(X正方向向右,Y正方向向)

            使用相关API时要仔细阅读文档,弄清坐标系类型,原点位置等.

      2.2 例子分析

            2.2.1把中心点为A(50,50)长为20,宽为10的矩形以X轴逆时针旋转45

  - (void)drawRect:(CGRect)rect{
      /**
       * UIKit坐标系,原点在UIView左上角
       */
      CGContextRef context =  UIGraphicsGetCurrentContext();
      CGContextSaveGState(context);
      CGAffineTransform transform;

      /**
       * 变换后 transform = CBA,显然不是想要的结果.
       * 这是由于CGAffineTransform变换函数构造的矩阵在左边,如:
       * t' = CGAffineTransformTranslate(t,tx,ty)
       * 结果为:t' = [ 1 0 0 1 tx ty ] * t
       * 累积变换就会得到上面的结果
       */
      transform = CGAffineTransformIdentity;
      transform = CGAffineTransformTranslate(transform, -50, -50); //A
      transform = CGAffineTransformRotate(transform, M_PI_4);      //B
      transform = CGAffineTransformTranslate(transform, 50, 50);   //C


      /**
       * 为了得到正确结果,调整顺序如下:
       */
      transform = CGAffineTransformIdentity;
      transform = CGAffineTransformTranslate(transform, 50, 50);    //C
      transform = CGAffineTransformRotate(transform, M_PI_4);       //B
      transform = CGAffineTransformTranslate(transform, -50, -50);  //A

   
      /**
       * context函数变换
       */
      //CGContextTranslateCTM(context, 50, 50);    //C
      //CGContextRotateCTM(context, M_PI_4);       //B
      //CGContextTranslateCTM(context, -50, -50);  //A

      CGContextConcatCTM(context, transform);

      /**
       * 绘制矩形
       */
      CGContextFillRect(context, CGRectMake(40, 45, 20, 10));

      CGContextRestoreGState(context);
  }

              

   2.2.2 绘制图片,下面函数在工作线程里面很有用

  void drawImage(CGContextRef context, CGImageRef image , CGRect rect){
      /**
       * 注意变换顺序A->B->C->D
       */
      CGContextSaveGState(context);

      /**
       * 矩形回到起始位置
       */
      CGContextTranslateCTM(context, rect.origin.x, rect.origin.y);  //D

      /**
       * 矩形Y轴正方向平移rect.size.height
       */
      CGContextTranslateCTM(context, 0, rect.size.height);           //C

      /**
       * 垂直反转矩形
       */
      CGContextScaleCTM(context, 1.0, -1.0);                         //B

      /**
       * 矩形平移到原点
       */
      CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);//A

      /**
       * 绘制图片
       */
      CGContextDrawImage(context, rect, image);

      CGContextRestoreGState(context);
  }

       2.2.3 坐标轴变换

/**
 * 原坐标系为Quartz 2D,目标坐标系为UKit,用原坐标系中坐标绘图
 */
- (void)drawRect:(CGRect)rect
{
    //UKit坐标系
    CGContextRef context =  UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGRect bounds = self.bounds;
    
    /**
     * 坐标轴变换A->B
     */
    
    /**
     * 平移坐标轴
     */
    CGContextTranslateCTM(context, 0, bounds.size.height); // B
    
    /**
     * 翻转Y坐标轴
     */
    CGContextScaleCTM(context, 1, -1);                     //A
    
    /**
     * 绘制矩形
     */
    CGContextFillRect(context, CGRectMake(10, 10, 20, 20));
    
    CGContextRestoreGState(context);
}

  

 

posted @ 2011-08-03 20:14  Delon  阅读(11703)  评论(4编辑  收藏  举报