[Drawkit] Fix for aliasing of drawing edges
Graham Cox
graham.cox at bigpond.com
Mon May 19 23:14:16 PDT 2008
This gives somewhat more consistent results:
if([NSGraphicsContext currentContextDrawingToScreen])
{
float factor = 0.5/[aView scale];
NSAffineTransform* pixelShiftToAdjustForQuartzCoordinates =
[NSAffineTransform transform];
[pixelShiftToAdjustForQuartzCoordinates translateXBy:factor
yBy:factor];
[pixelShiftToAdjustForQuartzCoordinates concat];
[[self paperColour] set];
NSRectFill( rect );
}
There are still some occasional pixels left unpainted when scrolling
at high zooms, but far less, because here the actual zoom is used to
compute the necessary shift, which at high zooms is a much smaller
factor (it's still 0.5 of a pixel on screen, but now represents some
much smaller factor in the drawing).
I had a look at the grid.
The grid would need to employ a similar trick to avoid the squares
becoming highly uneven at large zoom factors - just flooring and
adding 0.5 causes a big shift in some of the lines which is very
obvious when you zoom in. The visual alignment of objects is thus
substantially impaired.
At present, the grid is not recomputed for every redraw of the screen,
but is calculated once and cached. Without this caching drawing the
grid is a big performance hit (as it stands it barely makes an
impact). Thus the cache would have to be invalidated when the view
scale changes or else the cache removed and the grid recalculated on
every draw (bear in mind there could be multiple views with differing
scales rendering the same drawing). To my mind this is just not
worthwhile. By ignoring screen alignment issues, DrawKit is accurate
to the full floating-point resolution (the only reason that turning
off the grid crisps up the edges with the offset applied is because
the mouse itself only resolves to integer coordinates). One benefit of
Quartz is that this compromise is no longer needed, with the small
drawback that you get softer edges on the screen because it's
rendering floating-point objects into a coarse grid of pixels.
I guess if your focus is on-screen presentation, the offset trick is
worth using, but if it's printed output and geometric fidelity, it
isn't.
Not sure how to resolve this - making it a switchable flag is one
option, but addressing it for the grid case is going to a) be
complicated and b) hit performance badly.
cheers, Graham
On 20 May 2008, at 2:01 pm, Graham Cox wrote:
> I'm aware of the 0.5 pixel "problem", but I chose not to attempt to
> compensate for it, instead deciding to go for accuracy over crispness.
>
> That said, It definitely does look a lot sharper. One problem with
> the code below is that it causes a big problem when the view is
> scrolled when it's zoomed in to large scale. Not sure why at the
> moment, but it's so bad I can't recommend including this at present.
> I think the update area marking needs to be similarly offset
> otherwise there is a small amount of overlap that doesn't get
> repainted when scrolling.
>
> Regarding offsetting the grid alignment, I'll look into it, but one
> thing I do want to avoid is the appearance of uneven spacing between
> grid lines by forcing them to integer co-ordinates, and any
> misalignment of objects visually between the grid "real" position
> and the apparent position of the lines. This might not turn out to
> be a problem, just thinking aloud at this stage.
>
>
> cheers, Graham
>
>
>
> On 20 May 2008, at 9:03 am, Brad Larson wrote:
>
>> I noticed that the borders of the drawing, along with the edges of
>> objects, were being aliased (one-pixel-wide black lines were drawn
>> as two-pixel-wide grey lines). The Quartz drawing model is a
>> little odd in that integer coordinates are considered to be between
>> pixels, so you need to shift your drawing space by a half pixel in
>> X and Y to get things to line up correctly.
>>
>> By changing
>>
>> if([NSGraphicsContext currentContextDrawingToScreen])
>> {
>> [[self paperColour] set];
>> NSRectFill( rect );
>> }
>>
>> to be
>>
>> if([NSGraphicsContext currentContextDrawingToScreen])
>> {
>> NSAffineTransform* pixelShiftToAdjustForQuartzCoordinates =
>> [NSAffineTransform transform];
>> [pixelShiftToAdjustForQuartzCoordinates translateXBy:0.5 yBy:0.5];
>> [pixelShiftToAdjustForQuartzCoordinates concat];
>>
>> [[self paperColour] set];
>> NSRectFill( rect );
>> }
>>
>> in - (void) drawRect:inView: within DKDrawing.m, you can remove
>> this aliasing. There is still some aliasing with the background
>> grids and objects drawn on them, due to their drawing coordinates
>> not mapping to integer values. In DrawDemo, you'll need to turn
>> off grid snapping to see how much sharper rectangles and the like
>> are with this setting, because otherwise they'll snap to the non-
>> integer grid locations.
>>
>> A go-between function, template, or method might be needed to
>> floor() or ceil() the x and y values of grids and drawable objects
>> for display to the screen. Apple has some tips on this at http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/chapter_4_section_6.html
>> .
>>
>>
>> ______________________
>> Brad Larson
>> SonoPlot, Inc.
>> 3030 Laura Lane, Suite 120
>> Middleton, WI 53562
>>
>>
>>
>> _______________________________________________
>> Drawkit mailing list
>> Drawkit at lists.apptree.net
>> http://lists.apptree.net/listinfo.cgi/drawkit-apptree.net
>
> _______________________________________________
> Drawkit mailing list
> Drawkit at lists.apptree.net
> http://lists.apptree.net/listinfo.cgi/drawkit-apptree.net
More information about the Drawkit
mailing list