gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Graphics Rounding (was Re: Pixel-aligned autoresizing)


From: Eric Wasylishen
Subject: Re: Graphics Rounding (was Re: Pixel-aligned autoresizing)
Date: Sun, 10 Jul 2011 16:14:33 -0600

On 2011-07-10, at 1:51 PM, Fred Kiefer wrote:

> On 09.07.2011 21:04, Eric Wasylishen wrote:
>> Hi Philippe,
>> 
>> The jumping is caused by our use of rint() in NSButtonCell - in fact, I 
>> think we should avoid rint() entirely for graphics, because it uses a "round 
>> halfway cases to the nearest even integer" algorithm; so 1.5 rounds to 2, 
>> but 2.5 also rounds to 2.
>> 
>> The annoying thing is that none of the C standard library functions 
>> implement a good rounding algorithm for graphics. c99's round() rounds 
>> halfway cases away from zero. This is probably OK in practice but not ideal, 
>> since it means the location of the coordinate system origin affects the 
>> rounding. I think the best algorithm for graphics is round-towards-infinity, 
>> so just floor(x+0.5). I wonder if we should just introduce this as a 
>> function for internal use, like GSRoundTowardsInfinity().
>> 
>> Eric
> 
> Hi Eric,
> 
> could you please explain why you think that one of these rounding methods is 
> better suited for graphics than the others? For me they are all equally 
> problematic :-(

Sure. We have this code in NSButtonCell drawImage:withFrame:inView:

position.x = MAX(NSMidX(cellFrame) - (size.width / 2.), 0.);
position.y = MAX(NSMidY(cellFrame) - (size.height / 2.), 0.);

Suppose position.x is 16.5, then rint() would round that to 16, so the image 
will be drawn half a pixel to the left of where it should be.

The problem is if we move the button one point to the right, position.x will be 
17.5, and rint() rounds that to 18, so suddenly the image is drawn right of 
where it should be.  You wouldn't expect moving the button frame to affect the 
position of the image inside, but it does. i.e. whether something is at an even 
or odd coordinate should be unimportant for graphics, but rint() decides which 
way to round based on that. 

round() suffers from a similar problem; but only when the cell rect is 
translated such that position.x changes from positive to negative or 
vice-versa, the image position will move by 1 pt inside the cell.

floor(x+0.5) doesn't have these problems; as it always rounds halfway cases 
towards infinity.

> If we ever change to another function we will have to make sure it is 
> available equally on all supported systems. That way why I wanted to stick 
> with rint() for all cases as we already try to support that everywhere.

I think introducing our own is the way to go. All that's needed should be:

CGFloat GSRoundTowardsInfinity(CGFloat x) { return floor(x+0.5); }

There would be no compatibility concerns because floor is from c89 or earlier.

> PS: I also don't see how pure horizontal resizing may affect the vertical 
> position of a subview. Is this the case that mentioned earlier, but couldn't 
> come up with a real test case for?

This made me think of a case we should add to the NSView autoresizing test: if 
a view starts with a non-pixel aligned frame, and is subsequently autoresized, 
should it be "corrected" to be pixel aligned?

Other than that, I can't think of any way purely horizontal resizing could 
affect vertical positions of views.

-Eric


reply via email to

[Prev in Thread] Current Thread [Next in Thread]