如何旋转包含UIBezierPath的CAShapeLayer?

Chr*_*her 3 rotation calayer ios

可能重复:
旋转CGPath而不更改其位置

我搜索并测试了几个小时的代码,我无法让它工作.

我在随机位置添加一个任意UIBezierPath到CAShapeLayer,它被添加到视图中.我需要旋转路径,以便我可以处理设备旋转.我可以旋转图层而不是路径.我只需要旋转结果.

我已经有了通过缩放和转换来处理bezier路径转换的方法.它工作得很好,但现在我需要简单地向左或向右旋转90度.

有关如何做到这一点的任何建议?

基本代码:

UIBezierPath *path = <create arbitrary path>
CAShapeLayer *layer = [CAShapeLayer layer];
[self addPathToLayer:layer
             fromPath:path];

// I could get the center of the box but where is the box center for the view it is in?
// CGRect box = CGPathGetPathBoundingBox(path.CGPath);

// layer.anchorPoint = ? How to find the center of the box for the anchor point?

// Rotating here appears to rotate around 0,0 of the view
layer.transform = CATransform3DMakeRotation(DegreesToRadians(-90), 0.0, 0.0, 1.0);
Run Code Online (Sandbox Code Playgroud)

我看到以下帖子: UIView中的BezierPath旋转

我想我可以按原样旋转,然后将路径转换回原位.我只需要弄清楚翻译的价值是什么.

我还应该声明,在我尝试旋转之后,我看到的是图像在某处移动到屏幕外.我试着旋转25度来观察运动,它围绕视图的原点0 0旋转,这样如果我旋转90度,图像就会离屏.我正在运行这些测试而不旋转设备 - 只是为了看旋转是如何工作的.

更新#1 - 12/4/2012:出于一些奇怪的原因,如果我将位置设置为一个值,我根据经验发现它会在旋转后将旋转的贝塞尔曲线路径移动到正确的位置:

layer.position = CGPointMake(280, 60);
Run Code Online (Sandbox Code Playgroud)

此值是从启动/停止应用程序并进行调整的猜测.我不知道为什么我需要调整旋转位置.锚点应位于图层的中心.但是,我确实发现即使设置了路径,CAShapeLayer的帧和位置都是ZERO,并且路径在视图中的位置也是正确的.当旋转+90时,280,60位置将路径移动到路径边界框的中心.如果我改变旋转值,我需要调整位置.我不应该这样做手动调整.

我认为最后的办法是以某种方式将bezier路径转换为图像,然后添加它.我发现如果我将图层内容设置为图像,然后旋转,它会围绕其中心点旋转而不需要进行位置调整.设置路径不是这样.

更新#12 12/4/2012 - 我尝试设置框架并且摆弄我将其设置为如下:

CGRect box = CGPathGetPathBoundingBox(path.CGPath);
CGRect rect = CGRectMake(0, 0, box.origin.x + (3.5 * box.size.width), box.origin.y + (3.5 * box.size.height));
layer.frame = rect;
layer.transform = CATransform3DMakeRotation(DegreesToRadians(90), 0.0, 0.0, 1.0);
Run Code Online (Sandbox Code Playgroud)

为什么乘以3.5?我没有线索.我发现添加盒子大小约为盒子大小3.5倍的盒子原点会将旋转的CAShapeLayer路径移动到它应该的位置.

必须有更好的方法来做到这一点.这是比我之前的帖子更好的解决方案,因为帧大小不依赖于旋转角度.我只是不知道为什么框架需要设置为我设置的值.我认为它应该是CGRectMake(0,0,box.origin.x +(box.size.width/2),box.origin.y +(box.size.height/2));

但是,它将图像向左移动太多.

我找到的另一个线索是,如果我设置[自我视图] .frame的帧(整个父视图的帧,即iPhone的屏幕),然后旋转,旋转点是屏幕的中心,路径/图像围绕该中心点运行.这就是为什么我尝试将框架移动到路径中心的位置,以便它围绕盒子中心进行轨道运动.

更新#3 12/4/2012 - 我试图将图层渲染为图像.但是,看起来只是设置图层的路径并不会使其成为图层中的"图像",因为它是空的

    CGRect box = CGPathGetPathBoundingBox(path.CGPath);
    layer.frame = box;

    UIImage *image = [ImageHelper imageFromLayer:layer]; // ImageHelper library I created  

    CAShapeLayer *newLayer = [CAShapeLayer layer];
    newLayer.frame = CGRectMake(box.origin.x, box.origin.y, image.size.width, image.size.height);
    newLayer.contents = (id) image.CGImage;
Run Code Online (Sandbox Code Playgroud)

似乎用它的路径设置旋转层与简单地旋转贝塞尔路径本身没有什么不同.我将回到旋转bezier路径,看看我是否可以摆弄位置元素或其他东西.必须有一个解决方案.

目标:围绕其最初创建的视图中的中心点旋转UIBezierPath.

更新#4 12/4/2012 - 我进行了一系列测试,测量翻译所需的值,以便将UIBezierPath放置在其先前的中心位置.

CGAffineTransform rotate = CGAffineTransformMakeRotation(DegreesToRadians(-15));
[path applyTransform:rotate];

// CGAffineTransform translate = CGAffineTransformMakeTranslation(-110, 70); // -45
CGAffineTransform translate = CGAffineTransformMakeTranslation(-52, -58); // -15
[path applyTransform:translate];
Run Code Online (Sandbox Code Playgroud)

但是,x/y平移的比率不对应,因此我无法根据角度推断出所需的平移.似乎'CGAffineTransformMakeRotation'使用一些任意的锚来进行旋转,此刻看起来可能是(viewWidth/2,0).我做得比实际需要的要困难得多.我缺少一些简单的旋转,以保持中心点.我只需要向左或向右"旋转"90度.

更新#5 12/4/2012 - 运行其他测试后,似乎旋转UIBezierPath的锚点是绘制所有点的原点.在这种情况下,原点是0,0并且所有点都相对于该点.因此,它应用了一个旋转,旋转发生在原点周围,这就是为什么路径在-90和-25左右向上移动的原因.我需要以某种方式将旋转的锚点设置为中心所以它在中心周围"旋转",而不是原始的原点.在这一个问题上花了12个小时.

Chr*_*her 5

经过一些详细的分析和绘制纸上的边界框后,我发现我断言0,0的起源是正确的.

此问题的解决方案是将路径(基础矩阵)转换为原点,边界框的中心位于原点,旋转,然后将路径转换回其原始位置.

以下是如何将UIBezierPath旋转90度:

CGAffineTransform translate = CGAffineTransformMakeTranslation(-1 * (box.origin.x + (box.size.width / 2)), -1 * (box.origin.y + (box.size.height / 2)));
[path applyTransform:translate];

CGAffineTransform rotate = CGAffineTransformMakeRotation(DegreesToRadians(90));
[path applyTransform:rotate];

translate = CGAffineTransformMakeTranslation((box.origin.x + (box.size.width / 2)), (box.origin.y + (box.size.height / 2)));
[path applyTransform:translate];
Run Code Online (Sandbox Code Playgroud)

插入-90度以向另一个方向旋转.

将设备从纵向旋转到横向时,可以使用此公式,反之亦然.

我仍然认为这不是理想的解决方案,但结果是我现在所需要的.

如果有人有更好的解决方案请发布.

更新12/7/2012 - 我发现了我认为最好的解决方案,并且非常简单,因为我会这样.我不是在贝塞尔曲线路径上使用旋转,平移和缩放方法,而是将点数组提取为CGPoint对象,并根据视图大小和方向根据需要缩放/平移它们.然后,我创建一个新的贝塞尔曲线路径并将图层设置为此路径.

结果是完美的缩放,平移,旋转.