路径没有“位置”。路径是一组点(由线段和曲线段定义)。每个点都有自己的位置。
也许您想围绕特定点而不是原点旋转路径。诀窍是创建一个组合了三个单独变换的复合变换:
- 将原点平移到旋转点。
- 旋转。
- 从第 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);
}
更新
这是一个使用 Swift Playground 的演示。我们将从一个显示路径并用十字准线标记原点的辅助函数开始:
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) 不会使其接近其原始位置!