Line width
|
|
Thread rating:  |
C Lund - 16 Dec 2006 23:28 GMT I think I asked about something like this a few years ago, but I can't find the thread, so...
I'm trying to draw a grid that has differing line widths - depending on where in the grid the line is. (think sudoku)
This bit here draws the vertical lines:
NSBezierPath *lineToDraw; NSPoint theMarker;
for (i=0;i<2;i++) for (j=0;j<3;j++) for (k=0;k<10;k++) { if ((k==0)||(k==10)) [lineToDraw setLineWidth:3.0]; else if ((k==3)||(k==6)) [lineToDraw setLineWidth:2.0]; else [lineToDraw setLineWidth:1.0]; theMarker.x = 320*i+30*k+20; theMarker.y = 320*j+30; [lineToDraw moveToPoint:theMarker]; theMarker.x = 320*i+30*k+20; theMarker.y = 320*(j+1)-20; [lineToDraw lineToPoint:theMarker];
[lineToDraw stroke]; } } }
The full app draws six grids. However, the lines all end up being drawn with the thickest width - except in the last grid, where the line width just peters out.
What am I doing wrong here? Any ideas?
 Signature C Lund, www.notam02.no/~clund
Patrick Machielse - 17 Dec 2006 00:43 GMT > The full app draws six grids. However, the lines all end up being > drawn with the thickest width - except in the last grid, where the > line width just peters out. It's late, but let me give it a try:
- could it be that your lines overlap, so the wide lines obscure the narrow ones?
- remember to draw on the pixel boundaries.
patrick
C Lund - 17 Dec 2006 11:10 GMT > > The full app draws six grids. However, the lines all end up being > > drawn with the thickest width - except in the last grid, where the > > line width just peters out. > It's late, but let me give it a try:
> - could it be that your lines overlap, so the wide lines obscure the > narrow ones? Well, there is a possibility, but I don't think so. I'll look at the indexes just to be on the safe side.
> - remember to draw on the pixel boundaries. I'm not sure I get what you mean by that...?
> patrick
 Signature C Lund, www.notam02.no/~clund
Patrick Machielse - 17 Dec 2006 20:37 GMT > > - remember to draw on the pixel boundaries. > > I'm not sure I get what you mean by that...? That must be the problem then! ;-)
Because of anti-aliassing, it matters whether you draw exactly on a pixel boundary or not...
This article seems quite good:
<http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingG uide/Transforms/chapter_4_section_2.html>
This code illustrates the behavior:
@implementation MyView - (void)drawRect:(NSRect)rect { [[NSColor whiteColor] set]; NSRectFill(rect); NSRect myrect = NSMakeRect(20, 20, 100, 100); [[NSColor blackColor] set]; // on pixel boundaries, sharp '1 px' wide line NSFrameRect(myrect);
// not on pixel boundaries, fuzzy '2 px' wide line NSFrameRect(NSOffsetRect(myrect, 120.5, 0.5)); } @end
patrick
C Lund - 17 Dec 2006 20:50 GMT > > > - remember to draw on the pixel boundaries. > > I'm not sure I get what you mean by that...? > That must be the problem then! ;-)
> Because of anti-aliassing, it matters whether you draw exactly on a > pixel boundary or not...
> This article seems quite good:
> <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingG > uide/Transforms/chapter_4_section_2.html>
> This code illustrates the behavior: > [quoted text clipped - 14 lines] > } > @end Well, at least I understand what you were saying. That's not the problem, though. If you look at the code I included in the OP, you'll see that I'm using integer values only - and only straight lines.
Thanks anyway. B)
> patrick
 Signature C Lund, www.notam02.no/~clund
Patrick Machielse - 17 Dec 2006 21:03 GMT > Well, at least I understand what you were saying. That's not the > problem, though. If you look at the code I included in the OP, you'll > see that I'm using integer values only - and only straight lines. Must be solution 1 then...
patrick
Paul - 17 Dec 2006 22:49 GMT Hi,
There's a "NSMakeRect"!!
How the hell do you find these things?
Paul
> > > - remember to draw on the pixel boundaries. > > [quoted text clipped - 30 lines] > > patrick Patrick Machielse - 18 Dec 2006 00:16 GMT > There's a "NSMakeRect"!! Useful thread, isn't it :-)
> How the hell do you find these things? They're listed in Foundation -> Functions:
<http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Mis cellaneous/Foundation_Functions/index.html#//apple_ref/doc/uid/TP4000377 4>
patrick
Patrick Machielse - 17 Dec 2006 21:01 GMT > for (i=0;i<2;i++) > for (j=0;j<3;j++) [quoted text clipped - 15 lines] > } > } Use:
if ((k==0)||(k==10)) { [[NSColor yellowColor] set]; [lineToDraw setLineWidth:3.0]; } else if ((k==3)||(k==6)) { [[NSColor redColor] set]; [lineToDraw setLineWidth:2.0]; } else { [[NSColor blackColor] set]; [lineToDraw setLineWidth:1.0]; }
And you'll see the where the problem lies. (really your loop code is to difficult to understand...)
patrick
C Lund - 18 Dec 2006 11:01 GMT > > for (i=0;i<2;i++) > > for (j=0;j<3;j++) [quoted text clipped - 26 lines] > [lineToDraw setLineWidth:1.0]; > }
> And you'll see the where the problem lies. (really your loop code is to > difficult to understand...) Eh? This just makes all the lines yellow.
Just to test things, I added this sequence to the end of the procedure:
[[NSColor blackColor] set];
[lineToDraw setLineWidth:1.0]; theMarker.x = 25; theMarker.y = 25; [lineToDraw moveToPoint:theMarker]; theMarker.x = 215; theMarker.y = 25; [lineToDraw lineToPoint:theMarker]; [lineToDraw stroke]; [lineToDraw setLineWidth:2.0]; theMarker.x = 215; theMarker.y = 25; [lineToDraw moveToPoint:theMarker]; theMarker.x = 215; theMarker.y = 215; [lineToDraw lineToPoint:theMarker]; [lineToDraw stroke]; [lineToDraw setLineWidth:3.0]; theMarker.x = 215; theMarker.y = 215; [lineToDraw moveToPoint:theMarker]; theMarker.x = 25; theMarker.y = 215; [lineToDraw lineToPoint:theMarker]; [lineToDraw stroke]; [lineToDraw setLineWidth:4.0]; theMarker.x = 25; theMarker.y = 215; [lineToDraw moveToPoint:theMarker]; theMarker.x = 25; theMarker.y = 25; [lineToDraw lineToPoint:theMarker]; [lineToDraw stroke];
This should draw a black rectangle with sides of differing thicknesses. However, all four lines are equally thick.
Maybe the line-drawing procedures don't work the way I think they do...
> patrick
 Signature C Lund, www.notam02.no/~clund
Don Sample - 18 Dec 2006 14:00 GMT > > > for (i=0;i<2;i++) > > > for (j=0;j<3;j++) [quoted text clipped - 86 lines] > > > patrick You just keep adding more points to lineToDraw, without removing the old ones, so you are drawing 1 side of the rectangle with a width of 1, then 2 sides with a width of 2, then 3 sides with a width of 3, and finally all 4 sides, with a width of 4, with each subsequent stroke overdrawing the previous ones. Something similar is happening with your grid.
 Signature Quando omni flunkus moritati Visit the Buffy Body Count at <http://homepage.mac.com/dsample/>
Gregory Weston - 17 Dec 2006 21:56 GMT > I think I asked about something like this a few years ago, but I can't > find the thread, so... [quoted text clipped - 32 lines] > > What am I doing wrong here? Any ideas? First, better variable names would help. Partly when you're asking for help and partly when you're coming back to the code 2 years from now.
Second, I don't see you allocating lineToDraw. If you're really not doing that, rather than having just omitted it from the posted code, I think that's the major problem.
Third, if you're just drawing straight lines, NSBezierPath has a class method that strokes a line from one point to another. There's also a class method to impose a line width for subsequent drawing commands.
Fourth, k loops from 0 to 9, but you've got a line of code looking for it to be 10. You probably want that to be a 9 so that last line will have a width of 3 instead of 1.
 Signature The best intentions in the world don't make a flawed argument magically valid.
C Lund - 18 Dec 2006 10:48 GMT > > NSBezierPath *lineToDraw; > > NSPoint theMarker; [quoted text clipped - 18 lines] > > } > > }
> First, better variable names would help. Partly when you're asking for > help and partly when you're coming back to the code 2 years from now. This particular procedure is so simple that i,j,k,l is sufficient - imo. B)
In case you wonder: What the procedure does is draw six sudoku grids. i is the number of grids in the horizontal direction (2), and j in the vertical (3). k and l are the grid lines within the grids themselves.
> Second, I don't see you allocating lineToDraw. If you're really not > doing that, rather than having just omitted it from the posted code, I > think that's the major problem. I didn't quote it. I think omitting it from the code would have crashed the app.
> Third, if you're just drawing straight lines, NSBezierPath has a class > method that strokes a line from one point to another. There's also a > class method to impose a line width for subsequent drawing commands. Yes; "lineToPoint:" But I am using it. That's why need the "lineToDraw" variable.
> Fourth, k loops from 0 to 9, but you've got a line of code looking for > it to be 10. You probably want that to be a 9 so that last line will > have a width of 3 instead of 1. Oops. Thanks for spotting that one.
 Signature C Lund, www.notam02.no/~clund
Gregory Weston - 18 Dec 2006 12:21 GMT > > > NSBezierPath *lineToDraw; > > > NSPoint theMarker; [quoted text clipped - 34 lines] > > I didn't quote it. I'll suggest that not-quoting is not the best practice when asking why a piece of code doesn't work.
So are you allocating the path in the inner loop, or are you sending removeAllPoints on each pass? If you're doing neither, there's a lot of excess stroking going on.
> I think omitting it from the code would have crashed the app. Not reliably. Depending on the behavior of the compiler it's very likely that you'd just end up with behavior that's not you you expected.
> > Third, if you're just drawing straight lines, NSBezierPath has a class > > method that strokes a line from one point to another. There's also a > > class method to impose a line width for subsequent drawing commands. > > Yes; "lineToPoint:" But I am using it. That's why need the > "lineToDraw" variable. No. _Class_ method. You're invoking an instance method, thus requiring an instance. Try using
+ (void)strokeLineFromPoint:(NSPoint)point1 toPoint:(NSPoint)point2; instead ....
for (i=0;i<2;i++) { for (j=0;j<3;j++) { for (k=0;k<10;k++) { NSPoint a = NSMakePoint(320*i+30*k+20, 320*j+30); NSPoint b = NSMakePoint(320*i+30*k+20, 320*(j+1)-20); float theWidth = 1.0;
if ((k==0)||(k==9)) theWidth = 3.0; else if ((k==3)||(k==6)) theWidth = 2.0;
[NSBezierPath:setDefaultLineWidth:theWidth]; [NSBezierPath:strokeLineFromPoint:a toPoint:b]; } } }
Actually, another (and I think better) alternative. Do use an instance, but accumulate the whole path for a single grid at once at launch time using moveToPoint: and lineToPoint: messages and then use a transform to stamp it where you like when it's time to draw. Since a path only has a single line width associated with it, you'll probably need to generate and store three of them - one for the box, one for the 3x3 grid and one for the 9x9 grid - but I still think it's a win.
G
 Signature The best intentions in the world don't make a flawed argument magically valid.
Patrick Machielse - 18 Dec 2006 16:08 GMT > for (i=0;i<2;i++) > { [quoted text clipped - 14 lines] > } > } Almost exactly what I had come up with ;-)
Note however that this code (like the solution posted earlier) still suffers from not writing on the pixel bounderies; only the lines with width 2.0 appear sharp on the screen. The thin lines even look gray, not black. To remedy this you could add:
NSGraphicsContext *context = [NSGraphicsContext currentContext]; if ( [context isDrawingToScreen] ) { [context setShouldAntialias:NO]; }
before the drawing code. I suspect it is probably also a good idea to end off with:
[NSBezierPath:setDefaultLineWidth:1.0];
patrick
C Lund - 18 Dec 2006 11:22 GMT > I think I asked about something like this a few years ago, but I can't > find the thread, so... [quoted text clipped - 32 lines] > > What am I doing wrong here? Any ideas? What I was doing wrong here was assuming I was drawing the lines one at a time, with whatever characteristics I set most recently.
But what really happens is that the characteristics are set for *all* lines drawn using lineToDraw. In other words, I need a different line object for each line thickness, color, etc.
This code works the way it should:
int i,j,k,l; NSBezierPath *thinLine, *avgLine, *thickLine; NSPoint theMarker;
thinLine = [[NSBezierPath alloc] init]; avgLine = [[NSBezierPath alloc] init]; thickLine = [[NSBezierPath alloc] init];
[[NSColor blackColor] set]; [thinLine setLineWidth:1.0]; [avgLine setLineWidth:2.0]; [thickLine setLineWidth:3.0];
for (i=0;i<2;i++) for (j=0;j<3;j++) { for (k=0;k<10;k++) { if ((k==0)||(k==9)) { theMarker.x = 320*i+30*k+20; theMarker.y = 320*j+30; [thickLine moveToPoint:theMarker]; theMarker.x = 320*i+30*k+20; theMarker.y = 320*(j+1)-20; [thickLine lineToPoint:theMarker]; } else if ((k==3)||(k==6)) { theMarker.x = 320*i+30*k+20; theMarker.y = 320*j+30; [avgLine moveToPoint:theMarker]; theMarker.x = 320*i+30*k+20; theMarker.y = 320*(j+1)-20; [avgLine lineToPoint:theMarker]; } else { theMarker.x = 320*i+30*k+20; theMarker.y = 320*j+30; [thinLine moveToPoint:theMarker]; theMarker.x = 320*i+30*k+20; theMarker.y = 320*(j+1)-20; [thinLine lineToPoint:theMarker]; } } }
[thinLine stroke]; [avgLine stroke]; [thickLine stroke];
 Signature C Lund, www.notam02.no/~clund
|
|
|