Как обнаружить пересечение UIBezierPath и стереть его - PullRequest
1 голос
/ 29 мая 2019

Я создаю iOS приложение для рисования и хотел бы добавить функциональность, при которой стирание UIBezierPath удалит весь путь, а не просто наложит сегмент белым цветом.

У меня есть массивUIBezierPaths сохранено, но я не уверен, насколько эффективно будет проходить через весь массив для каждой точки касания, определять, пересекается ли он с текущей точкой касания, и удалять его из массива.

Есть предложения?

1 Ответ

2 голосов
/ 29 мая 2019

Если я правильно понимаю, вам нужно как минимум пройти по пути.В конце концов, они независимы.

У UIBezierPaths есть метод contains, который сообщает вам, находится ли точка внутри пути.Если это пригодно для использования, то вам нужно просто

paths = paths.filter { !$0.contains(touchPoint) }

Но поскольку это приложение для рисования, можно с уверенностью предположить, что вы используете штрих, а не заливку, которая, скорее всего, не будет работать с containsтак, как вы хотите.

Вы можете сделать пересечение вручную, и оно будет иметь относительно хорошую производительность, пока у вас не будет слишком много точек.Но когда у вас слишком много очков, я думаю, что производительность рисования будет больше беспокоить вас.Тем не менее, пересечение может быть немного проблематичным с включением некоторой ширины линии обводки;пользователю необходимо пересечь центр вашей линии, чтобы обнаружить попадание.

Существует способ преобразования обведенного пути в заполненный путь.После этого вы сможете использовать метод contains.Этот метод называется replacePathWithStrokedPath, но дело в том, что он существует только на CGContext (по крайней мере, мне никогда не удавалось найти эквивалент на UIBezierPath).Таким образом, процедура для этого включает в себя создание контекста.Например, что-то вроде этого будет работать:

static func convertStrokePathToFillPath(_ path: UIBezierPath) throws -> UIBezierPath {
    UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), true, 1.0)
    guard let context = UIGraphicsGetCurrentContext() else { throw NSError(domain: "convertStrokePathToFillPath", code: 500, userInfo: ["dev_message":"Could not generate image context"]) }

    context.addPath(path.cgPath)
    context.setLineWidth(path.lineWidth)
    // TODO: apply all possible settings from path to context
    context.replacePathWithStrokedPath()

    guard let returnedPath = context.path else { throw NSError(domain: "convertStrokePathToFillPath", code: 500, userInfo: ["dev_message":"Could not get path from context"]) }
    UIGraphicsEndImageContext()

    return UIBezierPath(cgPath: returnedPath)
}

Таким образом, результат должен выглядеть примерно так:

static func filterPaths(_ paths: [UIBezierPath], containingPoint point: CGPoint) -> [UIBezierPath] {
    return paths.filter { !(try! convertStrokePathToFillPath($0).contains(point)) }
}
...