这种使用CGAffineTransform的方式有什么问题?

时间:2014-03-29 21:55:44

标签: objective-c uikit core-graphics cgaffinetransform

我想在显示数值数据的UIView中制作图表。所以我需要绘制轴,一些坐标线,一些刻度线,然后将数据绘制为连​​接的直线。数据通常可以包括-500范围内的几百个x值。到+1000。相应的y值在300到350之间。

所以我认为一个好的方法是转换UIView的坐标(对于给出的示例值),视图的左侧是-500,右侧是1000,顶部是400,底部是300. y向上增加。然后在drawRect:我可以使用我自己的坐标系编写一堆CGContextMoveToPoint()和CGContextAddLineToPoint()语句,而不必在心理上将每个调用转换为UIView坐标。

我编写了以下函数来生成我自己的CGContextRef,但它没有达到我的预期。我已经尝试了几天的变化,浪费了这么多时间。有人可以说如何解决它?我意识到我无法清楚地知道变换是否应该根据我的坐标指定UIView坐标,反之亦然,或完全不同。

static inline CGContextRef myCTX(CGRect rect, CGFloat xLeft, CGFloat xRight, CGFloat yBottom, CGFloat yTop) {
    CGAffineTransform ctxTranslate = CGAffineTransformMakeTranslation(xLeft, rect.size.height - yTop);
    CGAffineTransform ctxScale = CGAffineTransformMakeScale( rect.size.width / (xRight - xLeft), -rect.size.height / (yTop - yBottom) );  //minus so y increases toward top
    CGAffineTransform combinedTransform = CGAffineTransformConcat(ctxTranslate, ctxScale);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextConcatCTM(c, combinedTransform);
    return c;
}

我使用它的方式是在drawRect中我只有:

CGContextRef ctx = myCTX(rect, self.xLeft, self.xRight, self.yBottom, self.yTop);

然后是一系列陈述,如:

CGContextAddLineToPoint(ctx, [x[i] floatValue], [y[i] floatValue]);

1 个答案:

答案 0 :(得分:1)

我通过实验来解决这个问题。转换需要3个步骤而不是2步(或者,如果不需要,至少它以这种方式工作):

static inline CGContextRef myCTX(CGRect rect, CGFloat xLeft, CGFloat xRight, CGFloat yBottom, CGFloat yTop) {
    CGAffineTransform translate1 =  CGAffineTransformMakeTranslation(-xLeft, -yBottom);
    CGAffineTransform scale =       CGAffineTransformMakeScale( rect.size.width / (xRight - xLeft), -rect.size.height / (yTop - yBottom) );
    CGAffineTransform transform =   CGAffineTransformConcat(translate1, scale);
    CGAffineTransform translate2 =  CGAffineTransformMakeTranslation(1, rect.size.height);
    transform =                     CGAffineTransformConcat(transform, translate2);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextConcatCTM(c, transform);
    return c;
}

您在drawRect中使用此功能。在我的例子中,xLeft,xRight等值是UIView子类的属性,由viewController设置。所以视图的drawRect看起来像这样:

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSaveGState(c);
    CGContextRef ctx = myCTX(rect, self.xLeft, self.xRight, self.yBottom, self.yTop);
    …    
    all of the CGContextMoveToPoint(), CGContextAddLineToPoint(), calls to 
    draw your desired lines, rectangles, curves, etc. but not stroke or fill them
    …

    CGContextRestoreGState(c);
    CGContextSetLineWidth(c, 1);
    CGContextStrokePath(c);
}

如果您希望线宽为1,则不需要CGContextSetLineWidth调用。如果您不在strokePath之前恢复图形状态,则路径宽度会受到缩放的影响。

现在我必须弄清楚如何在视图上绘制文字。