旋转CGPath而不改变其位置

我想旋转CGPath ,我使用以下代码:

 CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians); CGPathRef rotatedPath = CGPathCreateCopyByTransformingPath(myPath, &transform); 

这段代码工作正常,但它改变了路径的位置! 我希望路径保持与旋转前相同的位置。

路径没有“位置”。 路径是一组点(由线段和曲线段定义)。 每一点都有自己的立场。

也许您想要围绕特定点旋转路径,而不是围绕原点旋转。 诀窍是创建一个组合三个变换的复合变换:

  1. 将原点转换为旋转点。
  2. 旋转。
  3. 反转第1步的翻译。

例如,这是一个获取路径并返回一条新路径的函数,该路径是围绕其边界框中心旋转的原始路径:

 static CGPathRef createPathRotatedAroundBoundingBoxCenter(CGPathRef path, CGFloat radians) { CGRect bounds = CGPathGetBoundingBox(path); // might want to use CGPathGetPathBoundingBox CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformTranslate(transform, center.x, center.y); transform = CGAffineTransformRotate(transform, radians); transform = CGAffineTransformTranslate(transform, -center.x, -center.y); return CGPathCreateCopyByTransformingPath(path, &transform); } 

请注意,此函数返回一个新路径,其中包含+1保留计数,当您完成该计数后,您将负责释放该计数。 例如,如果您尝试旋转形状图层的路径:

 - (IBAction)rotateButtonWasTapped:(id)sender { CGPathRef path = createPathRotatedAroundBoundingBoxCenter(shapeLayer_.path, M_PI / 8); shapeLayer_.path = path; CGPathRelease(path); } 

UPDATE

这是使用Swift游乐场的演示。 我们将从一个帮助函数开始,该函数显示一个路径并用十字准线标记原点:

 import UIKit import XCPlayground func showPath(label: String, path: UIBezierPath) { let graph = UIBezierPath() let r = 40 graph.moveToPoint(CGPoint(x:0,y:r)) graph.addLineToPoint(CGPoint(x:0,y:-r)) graph.moveToPoint(CGPoint(x:-r,y:0)) graph.addLineToPoint(CGPoint(x:r,y:0)) graph.appendPath(path) XCPCaptureValue(label, graph) } 

接下来,这是我们的测试路径:

 var path = UIBezierPath() path.moveToPoint(CGPoint(x:1000,y:1000)) path.addLineToPoint(CGPoint(x:1000,y:1200)) path.addLineToPoint(CGPoint(x:1100,y:1200)) showPath("original", path) 

原始路径

(请记住,十字准线是原点,不是我们正在改造的路径的一部分。)

我们获得中心并转换路径,使其以原点为中心:

 let bounds = CGPathGetBoundingBox(path.CGPath) let center = CGPoint(x:CGRectGetMidX(bounds), y:CGRectGetMidY(bounds)) let toOrigin = CGAffineTransformMakeTranslation(-center.x, -center.y) path.applyTransform(toOrigin) showPath("translated center to origin", path) 

路径翻译为原点

然后我们旋转它。 所有旋转都发生在原点周围:

 let rotation = CGAffineTransformMakeRotation(CGFloat(M_PI / 3.0)) path.applyTransform(rotation) showPath("rotated", path) 

路径旋转

最后,我们将其翻译回来,完全颠倒原始翻译:

 let fromOrigin = CGAffineTransformMakeTranslation(center.x, center.y) path.applyTransform(fromOrigin) showPath("translated back to original center", path) 

从原点翻译的路径

请注意,我们必须反转原始翻译 。 我们不会通过其新边界框的中心进行翻译。 回想一下(在这个例子中),原始中心位于(1050,1100)。 但是在我们将它转​​换为原点并旋转它之后,新的边界框的中心位于(-25,0)。 将路径翻译为(-25,0)不会使其接近原始位置!

Swift 3方法围绕其中心旋转矩形:

 func createRotatedCGRect(rect: CGRect, radians: CGFloat) -> CGPath { let center = CGPoint(x: rect.midX, y: rect.midY) let path = UIBezierPath(rect: rect) path.apply(CGAffineTransform(translationX: center.x, y: center.y).inverted()) path.apply(CGAffineTransform(rotationAngle: radians)) path.apply(CGAffineTransform(translationX: center.x, y: center.y)) return path.cgPath } 

所有rob mayoff用于将其应用于路径及其边界框的代码仍然适用,因此我没有看到重复它们的原因。