How can all those tiny polygons generated by RegionPlot be joined into a single FilledCurve?

RegionPlot will usually generate a large number of tiny polygons for filling the region:

RegionPlot[-1 < x < 1 && -1 < y < 1 && x^2 + y^2 > 4/5, {x, -1.2,
1.2}, {y, -1.2, 1.2}, Mesh -> All]


When exported to PDF, these are often not very fast to render.

It is clear that theoretically these polygons could be joined into a single FilledCurve, defined by the outlines only. This should be much faster to render.

How can we do this in a robust way?

Note: the reason we need a FilledCurve and that a plain Polygon will not work is that a FilledCurve can have a hole in it (it may be multiply connected), like in the image above. Alternatively I will accept a solution which uses more than one Polygon, but still reduces the number of Polygonss as much as possible (in the example above two polygons will suffice).

Here's a complex RegionPlot to test on:

a = 36;
g = RegionPlot[
Mod[Sqrt[x^2 + y^2] - 7/2 ArcTan[x, y] + Sin[x] +
Cos[y], π] < π/2, {x, -a, a}, {y, -a, a},
PlotPoints -> 100]


The equation is from here.

-
Wow, that last code gives beautiful graphics. Was it made up or does it have a story? – Vitaliy Kaurov Jan 25 '12 at 0:45
@Vitaliy It's a GrafEq demo. See the very last link in my question. – Szabolcs Jan 25 '12 at 9:41

You could start by extracting the Line primitives from the normalized GraphicsComplex:

a=36;

g=RegionPlot[Mod[Sqrt[x^2+y^2]-7/2 ArcTan[x,y]+Sin[x]+Cos[y],Pi]<Pi/2,
{x,-a,a},{y,-a,a},PlotPoints->100];

lines=Cases[Normal[g], _Line, Infinity];


The lines can then be directly included in a FilledCurve:

Graphics[{
EdgeForm@Directive[Black, Thickness[Medium]],
FaceForm@Directive[Opacity[1/2], Orange],
FilledCurve[List /@ lines]
}]


This renders noticeably faster even within Mathematica (for example during resizing).

The structure of the FilledCurve must follow the FilledCurve[{{Line[...]}, {Line[...]}, ...}] pattern in order for the holes to show correctly. Each line must be included in a separate sublist.

If each Line is included in a separate FilledCurve, then the holes will be missing:

Graphics[FilledCurve/@lines]


If we use the FilledCurve[{Line[...], Line[...], ...}] structure, the lines will be effectively concatenated into one continuous line, causing artefacts:

Graphics[FilledCurve[lines]]


-
I used this directly on @Szabolcs plot, and all I got was a blank image. – rcollyer Jan 25 '12 at 3:43
@rcollyer - Was that with the Mesh->All setting? Because there are no Line primitives with that setting. – Arnoud Buzing Jan 25 '12 at 3:56
Removed Mesh -> All got a black rectangle. – rcollyer Jan 25 '12 at 3:58
@rcollyer - In the simpler case this seems to work (but it breaks the more complicated case): Graphics[FilledCurve[lines]] – Arnoud Buzing Jan 25 '12 at 4:05
I got it, the solution is FilledCurve[List /@ lines]. Since you're probably sleeping now, I'll edit your answer. Please review the edit, proofread it, and I'll accept afterwards! – Szabolcs Jan 25 '12 at 10:07