18

My Question is something similar to this.

I have 2 CGPathRef and 1 will be moved by finger touch. I want to find that whether the 2 CGPathRef are intersected? That question was asked almost 2 years ago and I want to know whether something has been found in the mean time.

Community
  • 1
  • 1
Ilanchezhian
  • 17,426
  • 1
  • 53
  • 55
  • Relevant discussion: http://www.cocoabuilder.com/archive/cocoa/65568-determing-the-intersection-of-two-nsbezierpath.html – Chuck Jul 20 '11 at 05:57
  • Are there any further constraints on your data? For example, have you restricted yourself to Beziers, or possibly even only one type of Bezier? – Tommy Jul 20 '11 at 05:59
  • No, As of now I m considering CGPath. If i require Bezier path, I would use that. But I guess, if we had for CGPaths, then it wud not be difficult for bezier paths. – Ilanchezhian Jul 20 '11 at 10:33
  • Do you need to know the actual intersection point or just whether or not they intersect? – RPeck Nov 21 '11 at 20:56
  • Just wanted to know whether they are intersected or not.. It would be great if we get the intersection point too... – Ilanchezhian Nov 22 '11 at 05:22
  • It would be easy enough to use bitmap data for such collision detection. – Alex Nichol Nov 23 '11 at 22:30
  • @AlexNichol, thanks for suggestion.. since it is moved with finger touch, it should be smooth such that the intersection find logic could not struck the main thread. – Ilanchezhian Nov 24 '11 at 05:09
  • I have posted a small sample project of how this might be done to github: https://github.com/unixpickle/PathIntersection. Download the Xcode project, run it, and see if it is what you're looking for. I will probably add more to the README tomorrow. – Alex Nichol Nov 24 '11 at 05:26
  • @AlexNichol, Thanks. I will check and give you my feedback. – Ilanchezhian Nov 24 '11 at 07:08

4 Answers4

9

This is fairly old, but I found it looking for a similar solution, in my problem I wanted to find when a circle overlapped with a path (a special case of your question).

I solved this by using CGPathCreateCopyByStrokingPath to create a stroked version of the original path using the radius of the circle as the stroke width. If the center point of the circle overlaps the stroked path then the original path overlaps the circle.

BOOL CGPathIntersectsCircle(CGPathRef path, CGPoint center, CGFloat radius)
{
    CGPathRef fuzzyPath;
    fuzzyPath = CGPathCreateCopyByStrokingPath(path, NULL, radius,
                                               kCGLineCapRound,
                                               kCGLineJoinRound, 0.0);
    if (CGPathContainsPoint(fuzzyPath, NULL, center, NO))
    {
        CGPathRelease(fuzzyPath);
        return YES;
    }
    CGPathRelease(fuzzyPath);
    return NO;
}

Edit: A minor bug where the fuzzyPath was not released.

Andrew
  • 396
  • 3
  • 5
6

I have written a small pixel based path collision detection API for CGPathRefs. It requires that you add a few source directories to your project, and it only works with ARC, but it should at least show you how one might do something like this. It basically draws the two paths on two separate contexts, and then does pixel-by-pixel checks to see if any pixels are on both paths. Obviously this would be slow to run every time the user drags their finger, but it certainly could be done once every half second or so, maybe not even on the main thread.

This is the easiest way I've found of doing something like this, and it may easily be that there's no better way, besides using lots of math.

Alex Nichol
  • 7,512
  • 4
  • 32
  • 30
  • Thanks Alex, but still, as I have already mentioned in the question, the intersection needs to be found as it happens while moving the path along with finger touch. – Ilanchezhian Nov 29 '11 at 09:16
2

Generally speaking, finding the intersection of two arbitrary CGPaths is going to be very complex.

There are ways to do approximations. Checking the intersections of the bounding boxes is a good first step. You can also subdivide the curve and repeat the process to get better approximations. Another option is to flatten the paths and see if any of the line segments of the flattened paths intersect.

For the general case, however, things get very nasty very fast. Consider, for example, the fact that two cubic bezier segments (never mind an entire path... just one segment) can intersect with another segment at up to 6 points. The more segments in your path, the more potential intersections. There is also the problem of degenerate bezier curves where a segment has a cusp that just touches one point of another segment. Does that count as an intersection? (sometimes yes, sometimes no)

It's not clear from your question, but you might also want to consider the intersections of the strokes that are applied to the curves, and correctly account for line joins and miters. That that gets even harder. Macromedia FreeHand (a drawing program similar to Adobe Illustrator) had a very large, complex, intensely mathematical library for discovering arbitrary bezier curve intersections. The problem is not easily solved.

Scott Thompson
  • 22,629
  • 4
  • 32
  • 34
1

To find the intersection of two CAShapeLayers, we can use below method, CAShapeLayer won't return frame. But we can get the refPath frame using CGPathGetBoundingBox. But this one will give the frame in rectangle.I thing you may understand.

if (CGRectIntersectsRect(CGPathGetBoundingBox(layer.path), CGPathGetBoundingBox(layer.path)))    
Krish
  • 31
  • 3