Как я могу проверить, нажал ли пользователь рядом с CGPath? - PullRequest
10 голосов
/ 17 июля 2009

Сценарий:

У меня есть набор CGPath с. В основном это просто линии (то есть не замкнутые формы). Они нарисованы на экране методом рисования UIView.

Как я могу проверить, нажал ли пользователь рядом с одним из путей?

Вот что у меня было:

UIGraphincsBeginImageContext(CGPathGetBoundingBox(path));
CGContextRef g = UIGraphicsGetCurrentContext();
CGContextAddPath(g,path);
CGContextSetLineWidth(g,15);
CGContextReplacePathWithStrokedPath(g);
CGPath clickArea = CGContextCopyPath(g);  //Not documented
UIGraphicsEndImageContext();

Итак, я делаю создание контекста изображения, потому что в нем есть нужные мне функции. Затем я добавляю путь к контексту и устанавливаю ширину линии равной 15. Нажатие на путь в этой точке создаст область щелчка, внутри которой я могу проверить, чтобы найти щелчки. Таким образом, я получаю этот штриховой путь, сообщая контексту, чтобы он превращался в штриховой путь, а затем копируя этот путь обратно в другой CGPath. Позже я могу проверить:

if (CGPathContainsPoint(clickArea,NULL,point,NO)) { ...

Все это работало хорошо и хорошо, но CGContextCopyPath, будучи недокументированным, показалось плохой идеей для использования по понятным причинам. Существует также определенная хитрость в создании CGContext только для этой цели.

Итак, у кого-нибудь есть идеи? Как проверить, коснулся ли пользователь (в данном случае, в пределах 15 пикселей) какой-либо области на CGPath?

Ответы [ 3 ]

20 голосов
/ 19 октября 2012

В iOS 5.0 и более поздних версиях это можно сделать проще, используя CGPathCreateCopyByStrokingPath:

CGPathRef strokedPath = CGPathCreateCopyByStrokingPath(path, NULL, 15,
    kCGLineCapRound, kCGLineJoinRound, 1);
BOOL pointIsNearPath = CGPathContainsPoint(strokedPath, NULL, point, NO);
CGPathRelease(strokedPath);

if (pointIsNearPath) ...
2 голосов
/ 18 июля 2009

Ну, я разобрался с ответом. Он использует CGPathApply:

clickArea = CGPathCreateMutable();
CGPathApply(path,clickArea,&createClickArea);

void createClickArea (void *info, const CGPathElement *elem) {
  CGPathElementType type = elem->type;
  CGMutablePathRef path = (CGMutablePathRef)info;
  static CGPoint last;
  static CGPoint subpathStart;
  switch (type) {
    case kCGPathElementAddCurveToPoint:
    case kCGPathElementAddQuadCurveToPoint:
      break;
    case kCGPathElmentCloseSubpath:
    case kCGPathElementMoveToPoint: {
      CGPoint p = type == kCGPathElementAddLineToPoint ? elem->points[0] : subpathStart;
      if (CGPointEqualToPoint(p,last)) {
        return;
      }
      CGFloat rad = atan2(p.y - last.y, p.x - last.x);
      CGFloat xOff = CLICK_DIST * cos(rad);
      CGFloat yOff = CLICK_DIST * sin(rad);
      CGPoint a = CGPointMake(last.x - xOff, last.y - yOff);
      CGPoint b = CGPointMake(p.x + xOff, p.y + yOff);
      rad += M_PI_2;
      xOff = CLICK_DIST * cos(rad);
      yOff = CLICK_DIST * sin(rad);
      CGPathMoveToPoint(path, NULL, a.x - xOff, a.y - yOff);
      CGPathAddLineToPoint(path, NULL, a.x + xOff, a.y + yOff);
      CGPathAddLineToPoint(path, NULL, b.x + xOff, b.y + yOff);
      CGPathAddLineToPoint(path, NULL, b.x - xOff, b.y - yOff);
      CGPathCloseSubpath(path);
      last = p;
      break; }
    case kCGPathElementMoveToPoint:
      subpathStart = last = elem->points[0];
      break;
  }
}

По сути, это просто мой собственный метод для ReplacePathWithStrokedPath, но сейчас он работает только со строками.

0 голосов
/ 29 ноября 2018

In Swift

let area = stroke.copy(strokingWithWidth: 15, lineCap: .round, lineJoin: .round, miterLimit: 1)
if (area.contains(point)) { ... }
...