Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
General
GeneralPortable MacsHardwareNetworking
Applications
Mac ApplicationsEudoraFirefox / MozillaInternet ExplorerOutlook ExpressMS OfficeEntourageExcelPowerPointWordVirtual PCMedia PlayerOther MS Products
Programming
Mac ProgrammingCodeWarriorPerl
Country Specific
Australian Mac GroupUK Mac Group

Mac Forum / Programming / Mac Programming / December 2006



Tip: Looking for answers? Try searching our database.

Line width

Thread view: 
Enable EMail Alerts  Start New Thread
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

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.