2009-07-17 2 views
9

Сценарий:Как проверить, что пользователь подключен к CGPath?

У меня есть набор CGPath s. Они в основном просто линии (т. Е. Не закрытые формы). Они рисуются на экране в методе рисования 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?

ответ

18

В прошивкой 5.0 и выше, это можно сделать более просто с помощью CGPathCreateCopyByStrokingPath:

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

if (pointIsNearPath) ... 
+2

В Swift 3.0: 'path.copy (strokingWithWidth: CGFloat ...)' – buildsucceeded

2

Ну, я понял ответ. Он использует 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

Большое спасибо за размещение этого! Я сам не знал бы об этом. Хотя принятый ответ работает отлично, но эта функция в основном спасла меня, поскольку она дает вам гибкость - я могу обрабатывать элементы пути по-разному: именно то, что мне нужно. Еще раз спасибо! – user1244109

Смежные вопросы