This is an alternative to the java.awt.geom.Area class, focusing on performance.
As of this writing (Feb 2022) this project accomplishes 3 things:
- It improves performance when combining (adding) several shapes (see profile results).
- It improves performance when clipping shapes to a rectangle (see profile results).
- It offers an alternative to the Area class (see the RectangleMask2D).
So far most of my changes still rely on the Area
class - we're just using it more carefully. Eventually I also want to fork the Area class and provide a new replacement with additional internal optimizations.
This project is still under development. I'll update everything (including this doc) when I have an official v1.0 release. This is an unpaid free-time project, so there is no release schedule planned.
This project introduces the Outline
class as a replacement for the Area
class. Internally an Outline is a simple wrapper object that contains three things:
- A base shape
- A series of operations (add/subtract/clip/xor) to perform on the base shape
- An
OutlineEngine
responsible for executing operations as needed
The queued operations are only performed when it becomes necessary. That is: you may add 100 shapes, but no geometric analysis happens until you actually ask to render the Outline
object. Sometimes looking at several shapes in bulk can help us spot performance optimizations.
There are currently three OutlineEngines
:
- The
AreaOutlineEngine
simply usesArea
objects to execute all operations. There may be a few very small/subtle optimizations, but performance-wise this should be mostly identical to using anArea
object directly. - The
OptimizedOutlineEngine
uses simple optimizations to increase performance. It always delegates to another underlying engine (typically theAreaOutlineEngine
) when it can't optimize away an operation. - The
ScaledMaskOutlineEngine
uses aRectangleMask2D
(see below) instead of anArea
.
This is a java.awt.Shape
composed of java.awt.geom.Rectangle2Ds
. (And it has a related cousin: the RectangleMask
is composed of java.awt.Rectangles
)
You can think of this as a "pixelated shape". You can designate a resolution and add an arbitrary java.awt.Shape
, and it will convert that shape to a series of small rectangles. If you set the resolution to 2 (so each "pixel" can be divided into a 2x2 grid), then your resulting shape still appears antialiased on a normal (100% resolution) monitor. If you set the resolution to 3 or 4 then the results look antialiased on a high resolution (4K) monitor, too.
Performance-wise this is hard to compare to the AreaEngine
. In some tests it was faster, and in others it was slower.
Most of the code in this project is intended to supplement the existing Area
class, but this is class's selling point is its an alternative. In rare cases the Area
class can throw OutOfMemoryErrors
. Or - if you avoid the errors - sometimes an Area can take seconds or minutes to finish a geometric operation. If you're OK with the trade-off of losing your Bézier curvature: this might be a good fit for you if you want to avoid the Area
class's occasional problems.
You can write your project using Outline
objects, and then switch between the ScaledMaskOutlineEngine
and the AreaOutlineEngine
if you want to compare the two.
This class clips an arbitrary shape to a Rectangle2D
. This project's new DefaultRectangularClipper
significantly outperforms the AreaRectangularClipper
.
This PathIterator
breaks up another PathIterator
into monotonic segments.
This is a java.awt.Shape
composed of several member shapes. This offers some performance benefits at no overhead to the caller.
For example: suppose you want to create a glyph for an equals sign. A CompoundShape
will store both rectangles. As long as no member shapes overlap you can add indefinitely many shapes to a CompoundShape
without triggering any complex geometric analysis. If you try to add a diagonal slash to the equals sign, though, then a CompoundShape
will use an OutlineEngine
(usually an AreaOutlineEngine
) to flatten all the members into one layer.
The OptimizedOutlineEngine
uses a CompoundShape
to achieve some of its performance benefits. In general I don't recommend instantiating a CompoundShape
directly: you're probably better off just using an Outline
with the default OptimizedOutlineEngine
.