我有一组构成多边形的 CGPoints,如何检测一个单独的 CGPoint 是否在多边形内或外?
比如,假设该多边形是一个三角形,而这个 CGPoint 是在水平移动,我该如何检测它何时穿过三角形的边界线?
当形状为常规的四边形时,我可以使用 CGRectContainsPoint
进行判断,但对于奇异形状,我不知道应该如何实现。
我有一组构成多边形的 CGPoints,如何检测一个单独的 CGPoint 是否在多边形内或外?
比如,假设该多边形是一个三角形,而这个 CGPoint 是在水平移动,我该如何检测它何时穿过三角形的边界线?
当形状为常规的四边形时,我可以使用 CGRectContainsPoint
进行判断,但对于奇异形状,我不知道应该如何实现。
CG(Mutable)PathRef
(或包装了CGPathRef
的UIBezierPath
),并使用CGPathContainsPoint
函数检查一个点是否在该路径内。如果使用UIBezierPath
,还可以使用containsPoint:
方法。以下是用Swift编写的实现:
extension CGPoint {
func isInsidePolygon(vertices: [CGPoint]) -> Bool {
guard vertices.count > 0 else { return false }
var i = 0, j = vertices.count - 1, c = false, vi: CGPoint, vj: CGPoint
while true {
guard i < vertices.count else { break }
vi = vertices[i]
vj = vertices[j]
if (vi.y > y) != (vj.y > y) &&
x < (vj.x - vi.x) * (y - vi.y) / (vj.y - vi.y) + vi.x {
c = !c
}
j = i
i += 1
}
return c
}
}
Swift 3
使用 Swift 3 更简单的方法是使用 UIBezierPath
的 contains
方法。
创建 CAShapeLayer
实例时,请确保设置 accessibilityPath
。
shapeLayer.path = bazierPath.cgPath
shapeLayer.accessibilityPath = bazierPath
检查路径是否包含触摸位置。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
for shape in layer.sublayers ?? [] where shape is CAShapeLayer {
guard let layer = shape as? CAShapeLayer,
let bazier = layer.accessibilityPath else { continue }
// Handle touch
print(bazier.contains(point))
}
}