• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: How to get the stroke geometry of a NSBezierPath?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How to get the stroke geometry of a NSBezierPath?


  • Subject: Re: How to get the stroke geometry of a NSBezierPath?
  • From: Jesse Grosjean <email@hidden>
  • Date: Tue, 13 Feb 2007 20:45:30 -0500

Mark,

Thanks so much for your detailed response, and I'm sorry for taking so long to respond. I think you approach makes lots of sense for the standard cases, but it breaks down with non standard strokes. For example consider a dashed stroke, or a the intersection of two lines with a small angle using the NSMiterLineJoinStyle. In those cases the stroke isn't always half stroke width away from the "idea" shape border and so it won't work.

Of course I'm sure there is a way to solve those problems too, but it shouldn't be that hard I think. The system should already be calculating the strokes path somewhere, all I want to do is access it. For example in Java (generally I'm not a fan of the Java apis) they make this easy with their BasicStroke.createStrokedShape() method.

Anyway I've got it mostly working now in Quartz. These methods are in a catagory in NSBezierPath. So you can use [myBezierPath quartzStrokePath] to get a path representing the shapes stroke path. The key line is:

	strokePath = (CGPathRef) CGContextCopyPath(context);

That allows you to copy the stroke path back out of the context. But it also seems to be a private api call (at least I didn't find it documented anywhere) so it's a bit bridle.

Jesse

- (void)loadQuartzPathOf:(NSBezierPath *)bezierPath intoContext: (CGContextRef)context {
CGPathRef path = [bezierPath quartzPath];

CGContextAddPath(context, path);
CGContextSetLineWidth(context, [self lineWidth]);
CGContextSetLineJoin(context, [self lineJoinStyle]);
CGContextSetLineCap(context, [self lineCapStyle]);
CGContextSetMiterLimit(context, [self miterLimit]);

float *myPattern = nil;
float myPhase = nil;
int myCount = -1;
[self getLineDash:nil count:&myCount phase:&myPhase];
if (myCount > 0) {
myPattern = malloc(myCount * sizeof(float)) ;
[self getLineDash:myPattern count:&myCount phase:&myPhase];
CGContextSetLineDash(context,myPhase,myPattern,myCount);
free(myPattern);
}

CFRelease(path);
}


- (CGPathRef)quartzStrokePath {
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGPathRef immutablePath = NULL;
CGPathRef strokePath = NULL;

CGContextSaveGState(context);

[self loadQuartzPathOf:self intoContext:context];

CGContextReplacePathWithStrokedPath(context);

strokePath = (CGPathRef) CGContextCopyPath(context);
immutablePath = CGPathCreateCopy(strokePath);
CFRelease(strokePath);


    CGContextRestoreGState(context);

    return immutablePath;
}


Jesse

On Feb 5, 2007, at 6:50 PM, Mark Onyschuk wrote:

(copied, minus graphic, plus a few more words, for benefit of the list)

On 4-Feb-07, at 5:56 PM, Jesse Grosjean wrote:

I'm trying to find the point where a given line intersects a NSBezierPath, and I'd like to also include the paths current stroke in this calculation. I know how to do it without taking the stroke into consideration by using [NSBezierPath-OAExtensions intersectionWithLine:lineStart:lineEnd:] from the Omni frameworks, but that method ignores the paths current stroke.

I think the easiest way to solve this is to find a way to turn the path's stroke into a path itself, and then just use the same test on that path. (if there's a better way please let me know) And so that lead to my question, how can I get and access the stroke geometry from a NSBezierPath.

You might try a geometric approach to solving the problem:

1. find the calculated intersection as you describe above.

2. calculate a normal for the line at that point. I'm not sure whether Omni's library provides normal calculation along a bezier, but it's pretty straightforward and can be gleaned using the same technique as is used to calculate an intercept: progressively split the bezier into "flatter and flatter" line segment approximations, then locate the intercept by doing a straight-line intercept calculation with the appropriate split segment.

3. given the line width (actually, given 1/2 the line width, since a stroke is applied equidistantly to either side of the conceptual line), step back to the edge from the standard intersection point. To do this: conceptualize a right triangle whose hypotenuse is your own line pointing in towards the calculated intersection point. The adjacent side is the normal from the calculated intercept and has a length of 1/2 line width. SOHCAHTOA (man, that brings back memories of HS math) gives us: cos theta = adjacent / hypotenuse.

so your hypotenuse length is (1/2 line width) / (cos theta)

-Mark


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


References: 
 >How to get the stroke geometry of a NSBezierPath? (From: Jesse Grosjean <email@hidden>)
 >Re: How to get the stroke geometry of a NSBezierPath? (From: Mark Onyschuk <email@hidden>)

  • Prev by Date: NSTokenField not updating collection of Entity
  • Next by Date: Re: Core Data "Integer 32" attribute type <-> NSNumber
  • Previous by thread: Re: How to get the stroke geometry of a NSBezierPath?
  • Next by thread: [Solved] AppleScript support - 10.3/10.4
  • Index(es):
    • Date
    • Thread