# [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
>antialiasing.
[...]
>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.

Eric

```