[cairo] Re: Avoiding seams

Eric Hughes eh-cairo at narthex.us
Mon Dec 12 17:19:47 PST 2005

At 04:49 PM 12/12/2005, mental at rydia.net wrote:
> > Do you have any other ideas ?
>Maybe two-sided fills.  But that's not really any easier to work
>with than the aliased_lineto business, even if it did allow
>I've got a nasty feeling that OSS renderers have been pursuing a
>dead end in this regard.  It's a 90% solution that doesn't seem to
>admit a 10% fix.

I strongly suspect that the API requires changing to get the desired 
result.  My argument is completely indirect, may seem entirely 
aesthetic, and is mathematically oriented.

The beginning is the understanding that there's no truly 1-D object 
can appear in a 2-D rendered image.  In a 2-D metric, the measure of 
a 1-D object is zero.  According to any notion of consistency, such 
an object would have no effect on anything displayed.  (e.g. A region 
of twice the area should have twice the effect on total luminosity; 
extrapolate.)  So here's the question.  What's the precise 
relationship between the 1-D object and the 2-D object that actually 
gets rendered?

Cairo has two such relationships available to it: stroke and 
fill.  These two, as a rule, have different kinds of 
relationships.  Stroke has the 1-D object in the middle; fill has the 
1-D object on its boundary.  If filled edges are treated as strokes, 
with the 1-D object in the middle, then the rendered edges of 
polygons will always overlap.

The problem with the "1-D on the boundary" rule is that in this case, 
each path segment requires an orientation: is the interior on the 
left or the right of the path segment?  It has to be specified.  It 
can be specified once, by the implementer, or with each path, by the 
user.  A closed, orientable path can either be filled with or without 
the point at infinity.  (This is true in all dimensions for 
1-co-dimensional closed and oriented surfaces.)  This is the simplest case.

Cairo also allows the filling of non-orientable paths (such as a 
figure-eight).  Here the problem is that specifying path handedness 
doesn't work.  With the EVEN_ODD rule on, the effectiveness 
handedness can change at a self-intersection point.  So something 
about fill in these cases would have to give.

Generically, only the first handedness would have to be 
specified.  In almost all cases, the orientation of subsequent arcs 
can be derived from the previous one.  The singular case is when the 
subsequent are is the negative of the previous one, that is, it 
retraces it backwards.  In that case the handedness must be deferred 
to when an arc diverges.  Even in this situation there's a singular 
situation: when an arc retraces back to the beginning point.

The urge to move to FSAA to solve this problem seems misguided.  FSAA 
works to disambiguate filled edges that were stroked at 
1-native-pixel width by simply reducing the relative error 
involved.  But it's an expensive way to do it, involving either n or 
n^2 extra effort, where n is the linear pixel oversampling rate.

Anti-aliasing can be done locally with path-as-boundary, with one 
caveat.  You can draw either with luminosity (additive) or occlusion 
(subtractive).  As long as one or the other is specified, you can get 
a linear behavior at edges.  For this to work, however, you have to 
know where zero is.  It's either at black (for luminosity) or white 
(for occlusion), but not both.  I can't tell which one Cairo uses 
without looking at the code.  An alpha channel works with either.


More information about the cairo mailing list