Here is a quite fast and clean solution.
It also works to test multiple paths vs one, which is fine, isn't it?
It works on CGBezier ( iOS and MacOS compatible )
• 1 - Create the necessaries contexts
Create a 16 bits, one component (no alpha) graphics port with the same size than the view.
- Don't recreate this context at each test, it's time consuming.
Recreate it only when view is resized.
- Let's call this context computeContext
Create a 16 bits, one component (no alpha) graphics port of 1 pixel width and height.
- Let's call this context testContext
• 2 - When you need to test the paths intersection:
We work in computeContext for the following operations:
- Clear the context ( It will be full black )
- Clip the context to the path you want to test
- Fill all the paths versus which you want to test
with white color
- ( From now, you don't need to be in the computeContext. ) Get the image and draw it in the testContext with something like :
CGImageRef clippedPathsImage = CGBitmapContextCreateImage(computeContext);
CGRect onePixSquare = CGRectMake(0,0,1,1);
CGContextDrawImage(testContext, onePixSquare, clippedPathsImage);
( Don't worry, image creation function is fast. It does not malloc any memory since the bits are allocated in the bitmapContext )
We're done!
long* data = CGBitmapContextGetData(testContext);
BOOL intersects = (*data!=0);
This is much faster than doing some composition drawing with alpha values
This is much faster than testing all the pixels in a big image
The image scaling is made internally, hardware accelerated. So it is not a big deal.
If however you want to speed up even more and can afford less precision,
you can create a smaller computeContext, for exemple 25% of view size, and render all the paths with a scale transform matrix.
The transfer in the 1 pixel context will then be faster, but you are not sure to detect intersections smaller than 4 pixels in size ( with a 25% scale, Logic ).
Don't use 8 bits gray. I don't think it speeds the process up, and you lose a lot of precision when reducing to 1 pixel. Enough to fail.
Don't forget that the first test to do before using the hard way is to test bounding boxes intersection !
That's all
Opened a GitHub with the library ;)
https://github.com/moosefactory
Hope this helps, cheers ! ;)
Here is the code to create a 16bits gray context.
It can be more concise, but I declare variables to make it clear. You don't need any bitmapInfo ( last parameter ), since there is no alphaValue, and we don't use float format.
-(CGContextRef)createComputeContext
{
size_t w = (size_t)self.bounds.size.width;
size_t h = (size_t)self.bounds.size.height;
size_t nComps = 1;
size_t bits = 16;
size_t bitsPerPix = bits*nComps;
size_t bytesPerRow = bitsPerPix*w;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bmContext = CGBitmapContextCreate(NULL, w, h, bits, bytesPerRow, cs, 0);
return bmContext;
}