2009-07-17 13 views
9

Scenario:Come posso verificare se un utente ha toccato vicino a CGPath?

Ho un set di CGPath s. Sono per lo più solo linee (cioè forme non chiuse). Sono disegnati sullo schermo con il metodo di disegno di UIView.

Come posso verificare se l'utente ha toccato vicino a uno dei percorsi?

Ecco quello che avevo a lavorare:

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

Quindi quello che sto facendo è la creazione di un contesto di immagini, perché ha le funzioni di cui ho bisogno. Quindi aggiungo il percorso al contesto e imposta la larghezza della linea su 15. Tracciando il percorso a questo punto creerei l'area di clic che posso controllare all'interno per trovare i clic. Quindi ottengo quel percorso tracciato dicendo al contesto di trasformare il percorso in un percorso tracciato, quindi copiare quel percorso di nuovo in un altro CGPath. Più tardi, posso controllare:

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

Tutto funzionava bene, ma il CGContextCopyPath, essendo privi di documenti, sembrava una cattiva idea di utilizzare per ovvie ragioni. C'è anche un certo imbarazzo nel fare un CGContext solo per questo scopo.

Quindi, qualcuno ha qualche idea? Come faccio a verificare se un utente ha toccato vicino (in questo caso, entro 15 pixel) di qualsiasi area su un CGPath?

risposta

18

In iOS 5.0 e versioni successive, questo può essere fatto più semplicemente utilizzando CGPathCreateCopyByStrokingPath:

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

if (pointIsNearPath) ... 
+2

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

2

Bene, ho trovato una risposta. Esso utilizza 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; 
    } 
} 

in fondo è solo il mio metodo per ReplacePathWithStrokedPath, ma funziona solo con linee per adesso.

+0

Grazie mille per la pubblicazione di questo! io stesso non ne avrei la minima idea. Sebbene la risposta accettata funzioni bene, ma questa funzione fondamentalmente mi ha salvato in quanto offre flessibilità - posso trattare gli elementi del percorso in modo diverso: esattamente ciò di cui avevo bisogno. Grazie ancora! – user1244109

Problemi correlati