Обнаружить, если CGPoint в полигоне
У меня есть набор CGPoints, которые составляют форму многоугольника, как я могу определить, находится ли один CGPoint внутри или вне многоугольника?
Скажем, форма была треугольником, а CGPoint двигался горизонтально, как я мог обнаружить, когда она пересекла линию треугольника?
Я могу использовать CGRectContainsPoint
, когда форма является обычной 4-сторонней формой, но я не вижу, как бы я сделал это с нечетной формой.
Ответы
Ответ 1
Вы можете создать CG(Mutable)PathRef
(или UIBezierPath
, который обертывает CGPathRef
) из ваших точек, и использовать CGPathContainsPoint
, чтобы проверить, находится ли точка внутри этого пути. Если вы используете UIBezierPath
, вы также можете использовать метод containsPoint:
.
Ответ 2
Для этого вам нужно написать один метод, реализующий точку внутри алгоритма многоугольника.
Этот метод будет принимать массив с N точками (полигон) в качестве аргумента и одной конкретной точки. Он должен возвращать true, если точка находится внутри полигона, а false, если нет.
Посмотрите на этот отличный ответ на S.O.
Ответ 3
Вот реализация в Swift:
extension CGPoint {
func isInsidePolygon(vertices:[CGPoint]) -> Bool {
var i = 0, j = 0, c = false, vi:CGPoint, vj:CGPoint
for (i = 0, j = vertices.count-1; i < vertices.count; j = i++) {
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;
}
}
return c
}
}
Ответ 4
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))
}
}