仅在边缘描边 CGPath
Stroke a CGPath on the edges only
我正在使用 Swift 制作游戏并且我有一个任意角度的 CGPath。现在让我们假设它总是一条直线。
我想创建的是这样的:
我已经尝试过非常简单的方法,即以黑色的粗线宽进行描边,复制路径,然后以背景色的稍细的线宽再次描边。这给出了正确的外观,但最终我需要中间是透明的。
我认为这可以通过使用 "parent" 路径(中间)的转换来实现,但我不确定该怎么做。沿单个轴的简单平移将不起作用,因为路径是有角度的。我在想我需要使用它的端点来计算路径的斜率,并使用一些数学来找到一个与父路径有一定垂直距离的点。但我不太确定该怎么做。任何提示,或者有其他方法可以做到这一点吗?
编辑:
我确实尝试使用 CGPathCreateCopyByStrokingPath,但当然这会抚摸整个路径,我真的只需要创建两条边——而不是末端。我不想要这样的东西:
使用 CGPathCreateCopyByStrokingPath
创建一条新路径,以您指定的偏移量(偏移量是 lineWidth
的一半)勾勒出当前路径的轮廓。然后划那条新路径。
更新
这是一个函数,它接受一条线段(作为一对点)和一个偏移量,以及 returns 一条与原始线段平行并偏离原始线段的新线段。
func lineSegment(segment: (CGPoint, CGPoint), offsetBy offset: CGFloat) -> (CGPoint, CGPoint) {
let p0 = segment.0
let p1 = segment.1
// Compute (dx, dy) as a vector in the direction from p0 to p1, with length `offset`.
var dx = p1.x - p0.x
var dy = p1.y - p0.y
let length = hypot(dx, dy)
dx *= offset / length
dy *= offset / length
// Rotate the vector one quarter turn in the direction from the x axis to the y axis, so it's perpendicular to the line segment from p0 to p1.
(dx, dy) = (-dy, dx)
let p0Out = CGPointMake(p0.x + dx, p0.y + dy)
let p1Out = CGPointMake(p1.x + dx, p1.y + dy)
return (p0Out, p1Out)
}
这是它的使用示例:
func stroke(segment: (CGPoint, CGPoint), lineWidth: CGFloat, color: UIColor) {
let path = UIBezierPath()
path.moveToPoint(segment.0)
path.addLineToPoint(segment.1)
path.lineWidth = lineWidth
color.setStroke()
path.stroke()
}
let mainSegment = (CGPointMake(20, 10), CGPointMake(50, 30))
UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 60), true, 2)
UIColor.whiteColor().setFill(); UIRectFill(.infinite)
stroke(mainSegment, lineWidth: 1, color: .blackColor())
stroke(lineSegment(mainSegment, offsetBy: 10), lineWidth: 2, color: .redColor())
stroke(lineSegment(mainSegment, offsetBy: -10), lineWidth: 2, color: .blueColor())
let image = UIGraphicsGetImageFromCurrentImageContext()
XCPlaygroundPage.currentPage.captureValue(image, withIdentifier: "image")
结果:
我正在使用 Swift 制作游戏并且我有一个任意角度的 CGPath。现在让我们假设它总是一条直线。
我想创建的是这样的:
我已经尝试过非常简单的方法,即以黑色的粗线宽进行描边,复制路径,然后以背景色的稍细的线宽再次描边。这给出了正确的外观,但最终我需要中间是透明的。
我认为这可以通过使用 "parent" 路径(中间)的转换来实现,但我不确定该怎么做。沿单个轴的简单平移将不起作用,因为路径是有角度的。我在想我需要使用它的端点来计算路径的斜率,并使用一些数学来找到一个与父路径有一定垂直距离的点。但我不太确定该怎么做。任何提示,或者有其他方法可以做到这一点吗?
编辑: 我确实尝试使用 CGPathCreateCopyByStrokingPath,但当然这会抚摸整个路径,我真的只需要创建两条边——而不是末端。我不想要这样的东西:
使用 CGPathCreateCopyByStrokingPath
创建一条新路径,以您指定的偏移量(偏移量是 lineWidth
的一半)勾勒出当前路径的轮廓。然后划那条新路径。
更新
这是一个函数,它接受一条线段(作为一对点)和一个偏移量,以及 returns 一条与原始线段平行并偏离原始线段的新线段。
func lineSegment(segment: (CGPoint, CGPoint), offsetBy offset: CGFloat) -> (CGPoint, CGPoint) {
let p0 = segment.0
let p1 = segment.1
// Compute (dx, dy) as a vector in the direction from p0 to p1, with length `offset`.
var dx = p1.x - p0.x
var dy = p1.y - p0.y
let length = hypot(dx, dy)
dx *= offset / length
dy *= offset / length
// Rotate the vector one quarter turn in the direction from the x axis to the y axis, so it's perpendicular to the line segment from p0 to p1.
(dx, dy) = (-dy, dx)
let p0Out = CGPointMake(p0.x + dx, p0.y + dy)
let p1Out = CGPointMake(p1.x + dx, p1.y + dy)
return (p0Out, p1Out)
}
这是它的使用示例:
func stroke(segment: (CGPoint, CGPoint), lineWidth: CGFloat, color: UIColor) {
let path = UIBezierPath()
path.moveToPoint(segment.0)
path.addLineToPoint(segment.1)
path.lineWidth = lineWidth
color.setStroke()
path.stroke()
}
let mainSegment = (CGPointMake(20, 10), CGPointMake(50, 30))
UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 60), true, 2)
UIColor.whiteColor().setFill(); UIRectFill(.infinite)
stroke(mainSegment, lineWidth: 1, color: .blackColor())
stroke(lineSegment(mainSegment, offsetBy: 10), lineWidth: 2, color: .redColor())
stroke(lineSegment(mainSegment, offsetBy: -10), lineWidth: 2, color: .blueColor())
let image = UIGraphicsGetImageFromCurrentImageContext()
XCPlaygroundPage.currentPage.captureValue(image, withIdentifier: "image")
结果: