在iOS中旋转一条简单的线

在iOS中旋转一条简单的线,ios,core-graphics,ios7.1,bezier,Ios,Core Graphics,Ios7.1,Bezier,我用贝塞尔路径画了两条线,它们看起来如下: ________________ ________________ 我想完成的是旋转第二行。但我似乎不能把它弄对。 这是我到目前为止所做的 - (void)drawRect:(CGRect)rect { //Path #1 UIBezierPath *p1 = [UIBezierPath bezierPath]; [p1 moveToPoint:CGPointMake(100.0, 100.0)]; [p1 addLineToPoint:CGPo

我用贝塞尔路径画了两条线,它们看起来如下:

________________

________________
我想完成的是旋转第二行。但我似乎不能把它弄对。 这是我到目前为止所做的

- (void)drawRect:(CGRect)rect
{
//Path #1
UIBezierPath *p1 = [UIBezierPath bezierPath];

[p1 moveToPoint:CGPointMake(100.0, 100.0)];
[p1 addLineToPoint:CGPointMake(250.0, 100.0)];
[p1 closePath];
p1.lineWidth = 15;
[[UIColor greenColor]setStroke];
[[UIColor redColor]setFill];
//draw the path
[p1 fill];
[p1 stroke];

//Path #2
UIBezierPath *p2 = [UIBezierPath bezierPath];

CGContextRef context = UIGraphicsGetCurrentContext();

[p2 moveToPoint:CGPointMake(100.0, 200.0)];
[p2 addLineToPoint:CGPointMake(250.0, 200.0)];
[p2 closePath];
p2.lineWidth = 15;
[[UIColor blueColor]setStroke];
[[UIColor yellowColor]setFill];
[p2 fill];
[p2 stroke];
CGContextRotateCTM(context, M_PI);

}
它绘制线,但不旋转第二条线


谢谢。

要了解你在做什么,试试这个。在模拟器上剪下一张与视图大小相同的纸。注释掉你的旋转线,运行应用程序,并跟踪它在未旋转位置显示的线。现在,取消对该行的注释(但进行旋转M_PI/4.0)并再次运行该应用程序——您应该可以看到该行部分偏离屏幕左侧,并以45度角指向下方。现在,将纸张的左上角固定在模拟器视图的左上角,将纸张顺时针旋转45度——描出的线条现在应该与屏幕上的线条重叠。这就是你做旋转时要做的(顺便说一句,如果你想要90度的旋转而不是M_-PI,你想使用M_-PI/2.0)

要使直线从其左边缘旋转,需要平移视图,但不平移其x和y坐标,然后进行旋转,然后再平移回

//Path #2
UIBezierPath *p2 = [UIBezierPath bezierPath];

CGContextRef context = UIGraphicsGetCurrentContext();

[p2 moveToPoint:CGPointMake(100.0, 200.0)];
[p2 addLineToPoint:CGPointMake(250.0, 200.0)];
[p2 closePath];
p2.lineWidth = 15;
[[UIColor blueColor]setStroke];
[[UIColor yellowColor]setFill];
[p2 fill];

CGContextTranslateCTM(context, 100, 200);
CGContextRotateCTM(context, M_PI/2.0);
CGContextTranslateCTM(context, -100, -200);
[p2 stroke];
正如马特在他的回答中所说,你可以直接将转移应用到贝塞尔路径,而不是坐标空间。我认为,这可能是一种更好的方法,而且在概念上更容易理解。在我上面给出的示例中,您会注意到旋转时唯一不改变其位置的点是{0,0}。因此,如果要旋转贝塞尔路径,请平移它,使要保持固定的点位于{0,0},旋转它,然后向后平移。从功能上讲,这只是意味着你首先要用x和y坐标的负数来翻译(而不是用我原来的答案的正数)。那么,以你为例,那就是

//Path #2
    UIBezierPath *p2 = [UIBezierPath bezierPath];
    [p2 moveToPoint:CGPointMake(100, 200)];
    [p2 addLineToPoint:CGPointMake(250.0, 200)];
    p2.lineWidth = 8;
    [[UIColor blueColor]setStroke];

    [p2 applyTransform:CGAffineTransformMakeTranslation(-100, -200)];
    [p2 applyTransform:CGAffineTransformMakeRotation(M_PI/2)];
    [p2 applyTransform:CGAffineTransformMakeTranslation(100, 200)];

    [p2 stroke];

还要注意,填充不起作用,因为直线(作为一个数学概念)没有内部,所以没有什么可填充的——笔划的宽度不会影响它。如果需要填充,那么应该绘制一个矩形而不是一条线(也不需要closePath调用,因为没有任何东西可以用线来结束)。

要了解您在做什么,请尝试以下操作。在模拟器上剪下一张与视图大小相同的纸。注释掉你的旋转线,运行应用程序,并跟踪它在未旋转位置显示的线。现在,取消对该行的注释(但进行旋转M_PI/4.0)并再次运行该应用程序——您应该可以看到该行部分偏离屏幕左侧,并以45度角指向下方。现在,将纸张的左上角固定在模拟器视图的左上角,将纸张顺时针旋转45度——描出的线条现在应该与屏幕上的线条重叠。这就是你做旋转时要做的(顺便说一句,如果你想要90度的旋转而不是M_-PI,你想使用M_-PI/2.0)

要使直线从其左边缘旋转,需要平移视图,但不平移其x和y坐标,然后进行旋转,然后再平移回

//Path #2
UIBezierPath *p2 = [UIBezierPath bezierPath];

CGContextRef context = UIGraphicsGetCurrentContext();

[p2 moveToPoint:CGPointMake(100.0, 200.0)];
[p2 addLineToPoint:CGPointMake(250.0, 200.0)];
[p2 closePath];
p2.lineWidth = 15;
[[UIColor blueColor]setStroke];
[[UIColor yellowColor]setFill];
[p2 fill];

CGContextTranslateCTM(context, 100, 200);
CGContextRotateCTM(context, M_PI/2.0);
CGContextTranslateCTM(context, -100, -200);
[p2 stroke];
正如马特在他的回答中所说,你可以直接将转移应用到贝塞尔路径,而不是坐标空间。我认为,这可能是一种更好的方法,而且在概念上更容易理解。在我上面给出的示例中,您会注意到旋转时唯一不改变其位置的点是{0,0}。因此,如果要旋转贝塞尔路径,请平移它,使要保持固定的点位于{0,0},旋转它,然后向后平移。从功能上讲,这只是意味着你首先要用x和y坐标的负数来翻译(而不是用我原来的答案的正数)。那么,以你为例,那就是

//Path #2
    UIBezierPath *p2 = [UIBezierPath bezierPath];
    [p2 moveToPoint:CGPointMake(100, 200)];
    [p2 addLineToPoint:CGPointMake(250.0, 200)];
    p2.lineWidth = 8;
    [[UIColor blueColor]setStroke];

    [p2 applyTransform:CGAffineTransformMakeTranslation(-100, -200)];
    [p2 applyTransform:CGAffineTransformMakeRotation(M_PI/2)];
    [p2 applyTransform:CGAffineTransformMakeTranslation(100, 200)];

    [p2 stroke];

还要注意,填充不起作用,因为直线(作为一个数学概念)没有内部,所以没有什么可填充的——笔划的宽度不会影响它。如果需要填充,那么应该绘制一个矩形而不是一条线(也不需要closePath调用,因为没有任何东西可以用线来关闭)。

将变换应用于贝塞尔路径的方法是使用
applyTransform:
。可以在构建路径之前或之后执行此操作,但应在笔划/填充路径之前执行此操作,因为此时路径已复制到当前图形上下文中。您应该放弃获取当前上下文并将转换应用于该上下文的整个业务;你只是把自己弄糊涂了。

将变换应用到贝塞尔路径的方法是使用
applyTransform:
。可以在构建路径之前或之后执行此操作,但应在笔划/填充路径之前执行此操作,因为此时路径已复制到当前图形上下文中。您应该放弃获取当前上下文并将转换应用于该上下文的整个业务;你只是把自己弄糊涂了。

你知道你对
CGContextRotateCTM
的调用是在你对
笔划的调用之后进行的。如果我在
[p2 fill]
之前或在填充和笔划之间移动它,我会尝试移动它;然后线路就不显示了。那是因为线路现在不在屏幕上了。您正在旋转视图的框架,而不仅仅是线条。你想要什么结果?我想要第二行显示垂直而不是水平旋转什么?它的中心?它的左边?为什么不先把它垂直画出来呢?你知道你对
CGContextRotateCTM
的调用是在你对
stroke
的调用之后进行的吗?如果我在
[p2 fill]
之前或在fill和stroke之间移动它,我会尝试移动它;然后线路就不显示了。那是因为线路现在不在屏幕上了。您正在旋转视图的框架,而不仅仅是线条。你想要什么结果?我想要第二行显示垂直而不是水平旋转什么?它的中心?它的左边?为什么不把它画成垂直的呢?这个代码真的适合你吗?应用
cgcontexttranslatecm
等af