The core library of primitives forming the basis of an embedded
domain-specific language for describing and rendering diagrams.
Normal users of the diagrams library should almost never need to
import anything from this package directly; instead, import modules
(especially Diagrams.Prelude) from the diagrams-lib package,
which re-exports most things of value to users.

For most library code needing access to core internals, it should
be sufficient to import this module, which simply re-exports useful
functionality from other modules in the core library. Library
writers needing finer-grained access or functionality may
occasionally find it useful to directly import one of the
constituent core modules.

Associated vector spaces

Points

Point is a newtype wrapper around vectors that we wish to treat
as points, so we don't get them mixed up. The distinction is
important: translations affect points, but leave vectors
unchanged. Points are instances of the AffineSpace class from
Data.AffineSpace.

Names

A (qualified) name is a (possibly empty) sequence of atomic names.
Atomic names can be either numbers or arbitrary strings. Numeric
names are provided for convenience in naming lists of things,
such as a row of ten squares, or the vertices of a path.

NameMaps form a monoid with the empty map as the identity, and
map union as the binary operation. No information is ever lost:
if two maps have the same name in their domain, the resulting map
will associate that name to the union of the two sets of points
associated with that name.

Look for the given name in a name map, returning a list of points
associated with that name. If no names match the given name
exactly, return all the points associated with names of which the
given name is a suffix.

Unwrap an unknown Attribute type, performing a dynamic (but
safe) check on the type of the result. If the required type
matches the type of the attribute, the attribute value is
returned wrapped in Just; if the types do not match, Nothing
is returned.

Bounding regions

Every diagram comes equipped with a bounding function.
Intuitively, the bounding function for a diagram tells us the
minimum distance we have to go in a given direction to get to a
(hyper)plane entirely containing the diagram on one side of
it. Formally, given a vector v, it returns a scalar s such
that

for every vector u with its endpoint inside the diagram,
if the projection of u onto v is s' *^ v, then s' <= s.

s is the smallest such scalar.

This could probably be expressed in terms of a Galois connection;
this is left as an exercise for the reader.

Bounding functions form a monoid, with the constantly zero
function (i.e. the empty region) as the identity, and pointwise
maximum as composition. Hence, if b1 is the bounding function
for diagram d1, and b2 is the bounding function for d2,
then b1 `mappend` b2 is the bounding function for d1
`atop` d2.

Given a boundable object, compute a functional bounding region
for it. For types with an intrinsic notion of "local
origin", the bounding function will be based there. Other
types (e.g. Trail) may have some other default reference
point at which the bounding function will be based; their
instances should document what it is.

Note that this function is in some sense dual to translate
(for types which are also Transformable); moving the origin
itself while leaving the object "fixed" is dual to fixing the
origin and translating the diagram.

Diagrams form a monoid since each of their components do:
the empty diagram has no primitives, a constantly zero bounding
function, no named points, and a constantly empty query function.

Diagrams compose by aligning their respective local origins. The
new diagram has all the primitives and all the names from the two
diagrams combined, and query functions are combined pointwise.
The first diagram goes on top of the second. "On top of"
probably only makes sense in vector spaces of dimension lower
than 3, but in theory it could make sense for, say, 3-dimensional
diagrams when viewed by 4-dimensional beings.

The default sort of diagram is one where sampling at a point
simply tells you whether that point is occupied or not.
Transforming a default diagram into one with more interesting
annotations can be done via the Functor instance of
AnnDiagram b.

Given a name and a diagram transformation indexed by a point,
perform the transformation using the first point associated with
the name, or perform the identity transformation if the name does
not exist.

By default, diagram attributes are not affected by
transformations. This means, for example, that lw 0.01 circle
and scale 2 (lw 0.01 circle) will be drawn with lines of the
same width, and scaleY 3 circle will be an ellipse drawn with
a uniform line. Once a diagram is frozen, however,
transformations do affect attributes, so, for example, scale 2
(freeze (lw 0.01 circle)) will be drawn with a line twice as
thick as lw 0.01 circle, and scaleY 3 (freeze circle) will be
drawn with a "stretched", variable-width line.

Another way of thinking about it is that pre-freeze, we are
transforming the "abstract idea" of a diagram, and the
transformed version is then drawn; when doing a freeze, we
produce a concrete drawing of the diagram, and it is this visual
representation itself which is acted upon by subsequent
transformations.

Backends

Abstract diagrams are rendered to particular formats by
backends. Each backend/vector space combination must be an
instance of the Backend class. A minimal complete definition
consists of the three associated types and implementations for
withStyle and doRender.

The type of rendering operations used by this backend, which
must be a monoid. For example, if Render b v = M () for some
monad M, a monoid instance can be made with mempty = return
() and mappend = (>>).

adjustDia allows the backend to make adjustments to the final
diagram (e.g. to adjust the size based on the options) before
rendering it. A default implementation is provided which makes
no adjustments.

When dealing with bounding regions we often want scalars to be an
ordered field (i.e. support all four arithmetic operations and be
totally ordered) so we introduce this class as a convenient
shorthand.