Maintainer | diagrams-discuss@googlegroups.com |
---|---|
Safe Haskell | None |
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.
- type family V a :: *
- data Point v
- origin :: AdditiveGroup v => Point v
- (*.) :: VectorSpace v => Scalar v -> Point v -> Point v
- data u :-: v
- (<->) :: (HasLinearMap u, HasLinearMap v) => (u -> v) -> (v -> u) -> u :-: v
- linv :: (u :-: v) -> v :-: u
- lapp :: (VectorSpace v, Scalar u ~ Scalar v, HasLinearMap u) => (u :-: v) -> u -> v
- data Transformation v
- inv :: HasLinearMap v => Transformation v -> Transformation v
- transp :: Transformation v -> v :-: v
- transl :: Transformation v -> v
- apply :: HasLinearMap v => Transformation v -> v -> v
- papply :: HasLinearMap v => Transformation v -> Point v -> Point v
- fromLinear :: AdditiveGroup v => (v :-: v) -> (v :-: v) -> Transformation v
- translation :: HasLinearMap v => v -> Transformation v
- translate :: (Transformable t, HasLinearMap (V t)) => V t -> t -> t
- moveTo :: HasOrigin t => Point (V t) -> t -> t
- place :: HasOrigin t => t -> Point (V t) -> t
- scaling :: (HasLinearMap v, Fractional (Scalar v)) => Scalar v -> Transformation v
- scale :: (Transformable t, Fractional (Scalar (V t)), Eq (Scalar (V t))) => Scalar (V t) -> t -> t
- class HasLinearMap (V t) => Transformable t where
- transform :: Transformation (V t) -> t -> t
- newtype TransInv t = TransInv {
- unTransInv :: t
- data AName
- data Name
- class (Typeable a, Ord a, Show a) => IsName a where
- class Qualifiable q where
- (.>) :: (IsName a1, IsName a2) => a1 -> a2 -> Name
- newtype SubMap b v m = SubMap (Map Name [Subdiagram b v m])
- fromNames :: IsName a => [(a, Subdiagram b v m)] -> SubMap b v m
- rememberAs :: IsName a => a -> QDiagram b v m -> SubMap b v m -> SubMap b v m
- lookupSub :: IsName n => n -> SubMap b v m -> Maybe [Subdiagram b v m]
- class (Typeable a, Semigroup a) => AttributeClass a
- data Attribute v
- mkAttr :: AttributeClass a => a -> Attribute v
- mkTAttr :: (AttributeClass a, Transformable a, V a ~ v) => a -> Attribute v
- unwrapAttr :: AttributeClass a => Attribute v -> Maybe a
- data Style v
- class HasStyle a where
- applyStyle :: Style (V a) -> a -> a
- getAttr :: forall a v. AttributeClass a => Style v -> Maybe a
- combineAttr :: AttributeClass a => a -> Style v -> Style v
- applyAttr :: (AttributeClass a, HasStyle d) => a -> d -> d
- applyTAttr :: (AttributeClass a, Transformable a, V a ~ V d, HasStyle d) => a -> d -> d
- data Envelope v
- inEnvelope :: (Option (v -> Max (Scalar v)) -> Option (v -> Max (Scalar v))) -> Envelope v -> Envelope v
- appEnvelope :: Envelope v -> Maybe (v -> Scalar v)
- onEnvelope :: ((v -> Scalar v) -> v -> Scalar v) -> Envelope v -> Envelope v
- mkEnvelope :: (v -> Scalar v) -> Envelope v
- class (InnerSpace (V a), OrderedField (Scalar (V a))) => Enveloped a where
- getEnvelope :: a -> Envelope (V a)
- envelopeVMay :: Enveloped a => V a -> a -> Maybe (V a)
- envelopeV :: Enveloped a => V a -> a -> V a
- envelopePMay :: Enveloped a => V a -> a -> Maybe (Point (V a))
- envelopeP :: Enveloped a => V a -> a -> Point (V a)
- diameter :: Enveloped a => V a -> a -> Scalar (V a)
- radius :: Enveloped a => V a -> a -> Scalar (V a)
- newtype Trace v = Trace {}
- inTrace :: ((Point v -> v -> PosInf (Scalar v)) -> Point v -> v -> PosInf (Scalar v)) -> Trace v -> Trace v
- mkTrace :: (Point v -> v -> PosInf (Scalar v)) -> Trace v
- class (Ord (Scalar (V a)), VectorSpace (V a)) => Traced a where
- traceV :: Traced a => Point (V a) -> V a -> a -> Maybe (V a)
- traceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))
- maxTraceV :: Traced a => Point (V a) -> V a -> a -> Maybe (V a)
- maxTraceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))
- class VectorSpace (V t) => HasOrigin t where
- moveOriginTo :: Point (V t) -> t -> t
- moveOriginBy :: HasOrigin t => V t -> t -> t
- class Juxtaposable a where
- juxtaposeDefault :: (Enveloped a, HasOrigin a) => V a -> a -> a -> a
- newtype Query v m = Query {}
- data Prim b v where
- Prim :: Renderable p b => p -> Prim b (V p)
- nullPrim :: (HasLinearMap v, Monoid (Render b v)) => Prim b v
- data QDiagram b v m
- mkQD :: Prim b v -> Envelope v -> Trace v -> SubMap b v m -> Query v m -> QDiagram b v m
- type Diagram b v = QDiagram b v Any
- prims :: HasLinearMap v => QDiagram b v m -> [(Prim b v, (Split (Transformation v), Style v))]
- envelope :: Ord (Scalar v) => QDiagram b v m -> Envelope v
- trace :: (Ord (Scalar v), VectorSpace v, HasLinearMap v) => QDiagram b v m -> Trace v
- subMap :: QDiagram b v m -> SubMap b v m
- names :: HasLinearMap v => QDiagram b v m -> [(Name, [Point v])]
- query :: Monoid m => QDiagram b v m -> Query v m
- sample :: Monoid m => QDiagram b v m -> Point v -> m
- value :: Monoid m => m -> QDiagram b v Any -> QDiagram b v m
- resetValue :: (Eq m, Monoid m) => QDiagram b v m -> QDiagram b v Any
- clearValue :: QDiagram b v m -> QDiagram b v Any
- named :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => n -> QDiagram b v m -> QDiagram b v m
- nameSub :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => (QDiagram b v m -> Subdiagram b v m) -> n -> QDiagram b v m -> QDiagram b v m
- namePoint :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => (QDiagram b v m -> Point v) -> n -> QDiagram b v m -> QDiagram b v m
- withName :: IsName n => n -> (Subdiagram b v m -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v m
- withNameAll :: IsName n => n -> ([Subdiagram b v m] -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v m
- withNames :: IsName n => [n] -> ([Subdiagram b v m] -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v m
- freeze :: forall v b m. (HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => QDiagram b v m -> QDiagram b v m
- setEnvelope :: forall b v m. (OrderedField (Scalar v), InnerSpace v, HasLinearMap v, Monoid' m) => Envelope v -> QDiagram b v m -> QDiagram b v m
- setTrace :: forall b v m. (OrderedField (Scalar v), InnerSpace v, HasLinearMap v, Semigroup m) => Trace v -> QDiagram b v m -> QDiagram b v m
- atop :: (HasLinearMap v, OrderedField (Scalar v), InnerSpace v, Semigroup m) => QDiagram b v m -> QDiagram b v m -> QDiagram b v m
- data Subdiagram b v m = Subdiagram (QDiagram b v m) (DownAnnots v)
- mkSubdiagram :: QDiagram b v m -> Subdiagram b v m
- getSub :: (HasLinearMap v, InnerSpace v, Floating (Scalar v), Ord (Scalar v), Semigroup m) => Subdiagram b v m -> QDiagram b v m
- rawSub :: Subdiagram b v m -> QDiagram b v m
- location :: HasLinearMap v => Subdiagram b v m -> Point v
- subPoint :: (HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Point v -> Subdiagram b v m
- class (HasLinearMap v, Monoid (Render b v)) => Backend b v where
- data Render b v :: *
- type Result b v :: *
- data Options b v :: *
- withStyle :: b -> Style v -> Transformation v -> Render b v -> Render b v
- doRender :: b -> Options b v -> Render b v -> Result b v
- adjustDia :: Monoid' m => b -> Options b v -> QDiagram b v m -> (Options b v, QDiagram b v m)
- renderDia :: (InnerSpace v, OrderedField (Scalar v), Monoid' m) => b -> Options b v -> QDiagram b v m -> Result b v
- class Backend b v => MultiBackend b v where
- renderDias :: (InnerSpace v, OrderedField (Scalar v), Monoid' m) => b -> Options b v -> [QDiagram b v m] -> Result b v
- class Transformable t => Renderable t b where
- data NullBackend
- type D v = Diagram NullBackend v
- class (HasBasis v, HasTrie (Basis v), VectorSpace v) => HasLinearMap v
- class (Fractional s, Floating s, Ord s, AdditiveGroup s) => OrderedField s
- class (Semigroup m, Monoid m) => Monoid' m
Associated vector spaces
Many sorts of objects have an associated vector space in which
they "live". The type function V
maps from object types to
the associated vector space.
Points
data Point v
Point
is a newtype wrapper around vectors used to represent
points, so we don't get them mixed up. The distinction between
vectors and points is important: translations affect points, but
leave vectors unchanged. Points are instances of the
AffineSpace
class from Data.AffineSpace.
Functor Point | |
Typeable1 Point | |
Eq v => Eq (Point v) | |
Data v => Data (Point v) | |
Ord v => Ord (Point v) | |
Read v => Read (Point v) | |
Show v => Show (Point v) | |
AdditiveGroup v => AffineSpace (Point v) | |
VectorSpace v => HasOrigin (Point v) | |
HasLinearMap v => Transformable (Point v) | |
(Ord (Scalar v), VectorSpace v) => Traced (Point v) | The trace of a single point is the empty trace, i.e. the one which returns positive infinity for every query. Arguably it should return a finite distance for vectors aimed directly at the given point and infinity for everything else, but due to floating-point inaccuracy this is problematic. Note that the envelope for a single point is *not* the empty envelope (see Diagrams.Core.Envelope). |
(OrderedField (Scalar v), InnerSpace v) => Enveloped (Point v) | |
Newtype (Point v) v |
origin :: AdditiveGroup v => Point v
The origin of the vector space v
.
(*.) :: VectorSpace v => Scalar v -> Point v -> Point v
Scale a point by a scalar.
Transformations
Invertible linear transformations
(v1 :-: v2)
is a linear map paired with its inverse.
HasLinearMap v => Monoid (:-: v v) | Invertible linear maps from a vector space to itself form a monoid under composition. |
HasLinearMap v => Semigroup (:-: v v) |
(<->) :: (HasLinearMap u, HasLinearMap v) => (u -> v) -> (v -> u) -> u :-: vSource
Create an invertible linear map from two functions which are assumed to be linear inverses.
lapp :: (VectorSpace v, Scalar u ~ Scalar v, HasLinearMap u) => (u :-: v) -> u -> vSource
Apply a linear map to a vector.
General transformations
data Transformation v Source
General (affine) transformations, represented by an invertible linear map, its transpose, and a vector representing a translation component.
By the transpose of a linear map we mean simply the linear map corresponding to the transpose of the map's matrix representation. For example, any scale is its own transpose, since scales are represented by matrices with zeros everywhere except the diagonal. The transpose of a rotation is the same as its inverse.
The reason we need to keep track of transposes is because it turns out that when transforming a shape according to some linear map L, the shape's normal vectors transform according to L's inverse transpose. This is exactly what we need when transforming bounding functions, which are defined in terms of perpendicular (i.e. normal) hyperplanes.
HasLinearMap v => Monoid (Transformation v) | |
HasLinearMap v => Semigroup (Transformation v) | Transformations are closed under composition; |
HasLinearMap v => HasOrigin (Transformation v) | |
HasLinearMap v => Transformable (Transformation v) | |
(HasLinearMap v, ~ * v (V a), Transformable a) => Action (Transformation v) a | Transformations can act on transformable things. |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
inv :: HasLinearMap v => Transformation v -> Transformation vSource
Invert a transformation.
transp :: Transformation v -> v :-: vSource
Get the transpose of a transformation (ignoring the translation component).
transl :: Transformation v -> vSource
Get the translational component of a transformation.
apply :: HasLinearMap v => Transformation v -> v -> vSource
Apply a transformation to a vector. Note that any translational component of the transformation will not affect the vector, since vectors are invariant under translation.
papply :: HasLinearMap v => Transformation v -> Point v -> Point vSource
Apply a transformation to a point.
fromLinear :: AdditiveGroup v => (v :-: v) -> (v :-: v) -> Transformation vSource
Create a general affine transformation from an invertible linear transformation and its transpose. The translational component is assumed to be zero.
Some specific transformations
translation :: HasLinearMap v => v -> Transformation vSource
Create a translation.
translate :: (Transformable t, HasLinearMap (V t)) => V t -> t -> tSource
Translate by a vector.
moveTo :: HasOrigin t => Point (V t) -> t -> tSource
Translate the object by the translation that sends the origin to
the given point. Note that this is dual to moveOriginTo
, i.e. we
should have
moveTo (origin .^+ v) === moveOriginTo (origin .^- v)
For types which are also Transformable
, this is essentially the
same as translate
, i.e.
moveTo (origin .^+ v) === translate v
place :: HasOrigin t => t -> Point (V t) -> tSource
A flipped variant of moveTo
, provided for convenience. Useful
when writing a function which takes a point as an argument, such
as when using withName
and friends.
scaling :: (HasLinearMap v, Fractional (Scalar v)) => Scalar v -> Transformation vSource
Create a uniform scaling transformation.
scale :: (Transformable t, Fractional (Scalar (V t)), Eq (Scalar (V t))) => Scalar (V t) -> t -> tSource
Scale uniformly in every dimension by the given scalar.
The Transformable class
class HasLinearMap (V t) => Transformable t whereSource
Type class for things t
which can be transformed.
transform :: Transformation (V t) -> t -> tSource
Apply a transformation to an object.
Translational invariance
TransInv
is a wrapper which makes a transformable type
translationally invariant; the translational component of
transformations will no longer affect things wrapped in
TransInv
.
TransInv | |
|
Names
A (qualified) name is a (possibly empty) sequence of atomic names.
Eq Name | |
Ord Name | |
Show Name | |
Typeable Name | |
Monoid Name | |
Semigroup Name | |
Qualifiable Name | Of course, names can be qualified using |
IsName Name | |
Action Name a | Names don't act on anything else. |
Action Name (SubMap b v m) | A name acts on a name map by qualifying every name in it. |
Newtype (SubMap b v m) (Map Name [Subdiagram b v m]) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
class Qualifiable q whereSource
Instances of Qualifiable
are things which can be qualified by
prefixing them with a name.
Qualifiable Name | Of course, names can be qualified using |
Qualifiable (SubMap b v m) |
|
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Qualifiable (QDiagram b v m) | Diagrams can be qualified so that all their named points can now be referred to using the qualification prefix. |
(.>) :: (IsName a1, IsName a2) => a1 -> a2 -> NameSource
Convenient operator for writing qualified names with atomic
components of different types. Instead of writing toName a1 <>
toName a2 <> toName a3
you can just write a1 .> a2 .> a3
.
Subdiagram maps
A SubMap
is a map associating names to subdiagrams. There can
be multiple associations for any given name.
SubMap (Map Name [Subdiagram b v m]) |
Action Name (SubMap b v m) | A name acts on a name map by qualifying every name in it. |
Functor (SubMap b v) | |
Monoid (SubMap b v m) |
|
Semigroup (SubMap b v m) | |
Qualifiable (SubMap b v m) |
|
(OrderedField (Scalar v), InnerSpace v, HasLinearMap v) => HasOrigin (SubMap b v m) | |
(InnerSpace v, Floating (Scalar v), HasLinearMap v) => Transformable (SubMap b v m) | |
Newtype (SubMap b v m) (Map Name [Subdiagram b v m]) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
fromNames :: IsName a => [(a, Subdiagram b v m)] -> SubMap b v mSource
Construct a SubMap
from a list of associations between names
and subdiagrams.
rememberAs :: IsName a => a -> QDiagram b v m -> SubMap b v m -> SubMap b v mSource
Add a name/diagram association to a submap.
lookupSub :: IsName n => n -> SubMap b v m -> Maybe [Subdiagram b v m]Source
Look for the given name in a name map, returning a list of subdiagrams associated with that name. If no names match the given name exactly, return all the subdiagrams associated with names of which the given name is a suffix.
Attributes and styles
class (Typeable a, Semigroup a) => AttributeClass a Source
An existential wrapper type to hold attributes. Some attributes are affected by transformations and some are not.
Semigroup (Attribute v) | Attributes form a semigroup, where the semigroup operation simply returns the right-hand attribute when the types do not match, and otherwise uses the semigroup operation specific to the (matching) types. |
HasLinearMap v => Transformable (Attribute v) |
mkAttr :: AttributeClass a => a -> Attribute vSource
Wrap up an attribute.
mkTAttr :: (AttributeClass a, Transformable a, V a ~ v) => a -> Attribute vSource
Wrap up a transformable attribute.
unwrapAttr :: AttributeClass a => Attribute v -> Maybe aSource
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.
A Style
is a heterogeneous collection of attributes, containing
at most one attribute of any given type.
Monoid (Style v) | The empty style contains no attributes; composition of styles is a union of attributes; if the two styles have attributes of the same type they are combined according to their semigroup structure. |
Semigroup (Style v) | |
HasLinearMap v => Transformable (Style v) | |
HasStyle (Style v) | |
Action (Style v) m | Styles have no action on other monoids. |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
Type class for things which have a style.
applyStyle :: Style (V a) -> a -> aSource
Apply a style by combining it (on the left) with the existing style.
HasStyle a => HasStyle [a] | |
(HasStyle a, Ord a) => HasStyle (Set a) | |
HasStyle (Style v) | |
HasStyle b => HasStyle (a -> b) | |
(HasStyle a, HasStyle b, ~ * (V a) (V b)) => HasStyle (a, b) | |
HasStyle a => HasStyle (Map k a) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => HasStyle (QDiagram b v m) |
getAttr :: forall a v. AttributeClass a => Style v -> Maybe aSource
Extract an attribute from a style of a particular type. If the
style contains an attribute of the requested type, it will be
returned wrapped in Just
; otherwise, Nothing
is returned.
combineAttr :: AttributeClass a => a -> Style v -> Style vSource
Add a new attribute to a style that does not already contain an attribute of this type, or combine it on the left with an existing attribute.
applyAttr :: (AttributeClass a, HasStyle d) => a -> d -> dSource
Apply an attribute to an instance of HasStyle
(such as a
diagram or a style). If the object already has an attribute of
the same type, the new attribute is combined on the left with the
existing attribute, according to their semigroup structure.
applyTAttr :: (AttributeClass a, Transformable a, V a ~ V d, HasStyle d) => a -> d -> dSource
Apply a transformable attribute to an instance of HasStyle
(such as a diagram or a style). If the object already has an
attribute of the same type, the new attribute is combined on the
left with the existing attribute, according to their semigroup
structure.
Envelopes
Every diagram comes equipped with an envelope. What is an envelope?
Consider first the idea of a bounding box. A bounding box expresses the distance to a bounding plane in every direction parallel to an axis. That is, a bounding box can be thought of as the intersection of a collection of half-planes, two perpendicular to each axis.
More generally, the intersection of half-planes in every direction would give a tight "bounding region", or convex hull. However, representing such a thing intensionally would be impossible; hence bounding boxes are often used as an approximation.
An envelope is an extensional representation of such a "bounding region". Instead of storing some sort of direct representation, we store a function which takes a direction as input and gives a distance to a bounding half-plane as output. The important point is that envelopes can be composed, and transformed by any affine transformation.
Formally, given a vector v
, the envelope computes a scalar s
such
that
- for every point
u
inside the diagram, if the projection of(u - origin)
ontov
iss' *^ v
, thens' <= s
. -
s
is the smallest such scalar.
There is also a special "empty envelope".
The idea for envelopes came from Sebastian Setzer; see http://byorgey.wordpress.com/2009/10/28/collecting-attributes/#comment-2030. See also Brent Yorgey, Monoids: Theme and Variations, published in the 2012 Haskell Symposium: http://www.cis.upenn.edu/~byorgey/pub/monoid-pearl.pdf; video: http://www.youtube.com/watch?v=X-8NCkD2vOw.
Show (Envelope v) | |
Ord (Scalar v) => Monoid (Envelope v) | |
Ord (Scalar v) => Semigroup (Envelope v) | |
(InnerSpace v, Fractional (Scalar v)) => HasOrigin (Envelope v) | The local origin of an envelope is the point with respect to which bounding queries are made, i.e. the point from which the input vectors are taken to originate. |
(HasLinearMap v, InnerSpace v, Floating (Scalar v)) => Transformable (Envelope v) | |
(InnerSpace v, OrderedField (Scalar v)) => Enveloped (Envelope v) | |
(InnerSpace v, OrderedField (Scalar v)) => Juxtaposable (Envelope v) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
inEnvelope :: (Option (v -> Max (Scalar v)) -> Option (v -> Max (Scalar v))) -> Envelope v -> Envelope vSource
appEnvelope :: Envelope v -> Maybe (v -> Scalar v)Source
mkEnvelope :: (v -> Scalar v) -> Envelope vSource
class (InnerSpace (V a), OrderedField (Scalar (V a))) => Enveloped a whereSource
Enveloped
abstracts over things which have an envelope.
getEnvelope :: a -> Envelope (V a)Source
Compute the envelope of an object. For types with an intrinsic
notion of "local origin", the envelope will be based there.
Other types (e.g. Trail
) may have some other default
reference point at which the envelope will be based; their
instances should document what it is.
Enveloped b => Enveloped [b] | |
Enveloped b => Enveloped (Set b) | |
(OrderedField (Scalar v), InnerSpace v) => Enveloped (Point v) | |
(InnerSpace v, OrderedField (Scalar v)) => Enveloped (Envelope v) | |
(Enveloped a, Enveloped b, ~ * (V a) (V b)) => Enveloped (a, b) | |
Enveloped b => Enveloped (Map k b) | |
(OrderedField (Scalar v), InnerSpace v, HasLinearMap v) => Enveloped (Subdiagram b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v)) => Enveloped (QDiagram b v m) |
envelopeVMay :: Enveloped a => V a -> a -> Maybe (V a)Source
Compute the vector from the local origin to a separating
hyperplane in the given direction, or Nothing
for the empty
envelope.
envelopeV :: Enveloped a => V a -> a -> V aSource
Compute the vector from the local origin to a separating hyperplane in the given direction. Returns the zero vector for the empty envelope.
envelopePMay :: Enveloped a => V a -> a -> Maybe (Point (V a))Source
Compute the point on a separating hyperplane in the given
direction, or Nothing
for the empty envelope.
envelopeP :: Enveloped a => V a -> a -> Point (V a)Source
Compute the point on a separating hyperplane in the given direction. Returns the origin for the empty envelope.
diameter :: Enveloped a => V a -> a -> Scalar (V a)Source
Compute the diameter of a enveloped object along a particular vector. Returns zero for the empty envelope.
radius :: Enveloped a => V a -> a -> Scalar (V a)Source
Compute the "radius" (1/2 the diameter) of an enveloped object along a particular vector.
Traces
Every diagram comes equipped with a *trace*. Intuitively, the trace for a diagram is like a raytracer: given a line (represented as a base point + direction), the trace computes the distance from the base point along the line to the first intersection with the diagram. The distance can be negative if the intersection is in the opposite direction from the base point, or infinite if the ray never intersects the diagram. Note: to obtain the distance to the *furthest* intersection instead of the *closest*, just negate the direction vector and then negate the result.
Note that the output should actually be interpreted not as an
absolute distance, but as a multiplier relative to the input
vector. That is, if the input vector is v
and the returned
scalar is s
, the distance from the base point to the
intersection is given by s *^ magnitude v
.
Show (Trace v) | |
Ord (Scalar v) => Monoid (Trace v) | |
Ord (Scalar v) => Semigroup (Trace v) | |
VectorSpace v => HasOrigin (Trace v) | |
HasLinearMap v => Transformable (Trace v) | |
(Ord (Scalar v), VectorSpace v) => Traced (Trace v) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
inTrace :: ((Point v -> v -> PosInf (Scalar v)) -> Point v -> v -> PosInf (Scalar v)) -> Trace v -> Trace vSource
class (Ord (Scalar (V a)), VectorSpace (V a)) => Traced a whereSource
Traced
abstracts over things which have a trace.
Traced b => Traced [b] | |
Traced b => Traced (Set b) | |
(Ord (Scalar v), VectorSpace v) => Traced (Point v) | The trace of a single point is the empty trace, i.e. the one which returns positive infinity for every query. Arguably it should return a finite distance for vectors aimed directly at the given point and infinity for everything else, but due to floating-point inaccuracy this is problematic. Note that the envelope for a single point is *not* the empty envelope (see Diagrams.Core.Envelope). |
(Ord (Scalar v), VectorSpace v) => Traced (Trace v) | |
(Traced a, Traced b, ~ * (V a) (V b)) => Traced (a, b) | |
Traced b => Traced (Map k b) | |
(Ord (Scalar v), VectorSpace v, HasLinearMap v) => Traced (Subdiagram b v m) | |
(HasLinearMap v, VectorSpace v, Ord (Scalar v)) => Traced (QDiagram b v m) |
traceV :: Traced a => Point (V a) -> V a -> a -> Maybe (V a)Source
Compute the vector from the given point to the boundary of the
given object in the given direction, or Nothing
if there is no
intersection.
traceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))Source
Given a base point and direction, compute the closest point on
the boundary of the given object, or Nothing
if there is no
intersection in the given direction.
maxTraceV :: Traced a => Point (V a) -> V a -> a -> Maybe (V a)Source
Like traceV
, but computes a vector to the *furthest* point on
the boundary instead of the closest.
maxTraceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))Source
Like traceP
, but computes the *furthest* point on the boundary
instead of the closest.
Things with local origins
class VectorSpace (V t) => HasOrigin t whereSource
Class of types which have an intrinsic notion of a "local origin", i.e. things which are not invariant under translation, and which allow the origin to be moved.
One might wonder why not just use Transformable
instead of
having a separate class for HasOrigin
; indeed, for types which
are instances of both we should have the identity
moveOriginTo (origin .^+ v) === translate (negateV v)
The reason is that some things (e.g. vectors, Trail
s) are
transformable but are translationally invariant, i.e. have no
origin.
moveOriginTo :: Point (V t) -> t -> tSource
Move the local origin to another point.
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.
HasOrigin a => HasOrigin [a] | |
(HasOrigin a, Ord a) => HasOrigin (Set a) | |
VectorSpace v => HasOrigin (Point v) | |
VectorSpace (V t) => HasOrigin (TransInv t) | |
HasLinearMap v => HasOrigin (Transformation v) | |
VectorSpace v => HasOrigin (Trace v) | |
(InnerSpace v, Fractional (Scalar v)) => HasOrigin (Envelope v) | The local origin of an envelope is the point with respect to which bounding queries are made, i.e. the point from which the input vectors are taken to originate. |
(HasOrigin a, HasOrigin b, ~ * (V a) (V b)) => HasOrigin (a, b) | |
HasOrigin a => HasOrigin (Map k a) | |
VectorSpace v => HasOrigin (Query v m) | |
(OrderedField (Scalar v), InnerSpace v, HasLinearMap v) => HasOrigin (SubMap b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v)) => HasOrigin (Subdiagram b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => HasOrigin (QDiagram b v m) | Every diagram has an intrinsic "local origin" which is the basis for all combining operations. |
moveOriginBy :: HasOrigin t => V t -> t -> tSource
Move the local origin by a relative vector.
Juxtaposable things
class Juxtaposable a whereSource
Class of things which can be placed "next to" other things, for some appropriate notion of "next to".
juxtapose :: V a -> a -> a -> aSource
juxtapose v a1 a2
positions a2
next to a1
in the
direction of v
. In particular, place a2
so that v
points
from the local origin of a1
towards the old local origin of
a2
; a1
's local origin becomes a2
's new local origin. The
result is just a translated version of a2
. (In particular,
this operation does not combine a1
and a2
in any way.)
(Enveloped b, HasOrigin b) => Juxtaposable [b] | |
(Enveloped b, HasOrigin b, Ord b) => Juxtaposable (Set b) | |
(InnerSpace v, OrderedField (Scalar v)) => Juxtaposable (Envelope v) | |
(Enveloped a, HasOrigin a, Enveloped b, HasOrigin b, ~ * (V a) (V b)) => Juxtaposable (a, b) | |
(Enveloped b, HasOrigin b) => Juxtaposable (Map k b) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Juxtaposable (QDiagram b v m) |
juxtaposeDefault :: (Enveloped a, HasOrigin a) => V a -> a -> a -> aSource
Queries
A query is a function that maps points in a vector space to values in some monoid. Queries naturally form a monoid, with two queries being combined pointwise.
The idea for annotating diagrams with monoidal queries came from the graphics-drawingcombinators package, http://hackage.haskell.org/package/graphics-drawingcombinators.
Functor (Query v) | |
Applicative (Query v) | |
Monoid m => Monoid (Query v m) | |
Semigroup m => Semigroup (Query v m) | |
VectorSpace v => HasOrigin (Query v m) | |
HasLinearMap v => Transformable (Query v m) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
Primtives
A value of type Prim b v
is an opaque (existentially quantified)
primitive which backend b
knows how to render in vector space v
.
Prim :: Renderable p b => p -> Prim b (V p) |
HasLinearMap v => Transformable (Prim b v) | The |
HasLinearMap v => Renderable (Prim b v) b | The |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
nullPrim :: (HasLinearMap v, Monoid (Render b v)) => Prim b vSource
The null primitive, which every backend can render by doing nothing.
Diagrams
The fundamental diagram type is represented by trees of
primitives with various monoidal annotations. The Q
in
QDiagram
stands for "Queriable", as distinguished from
Diagram
, a synonym for QDiagram
with the query type
specialized to Any
.
Typeable3 QDiagram | |
Functor (QDiagram b v) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Monoid (QDiagram b v m) | Diagrams form a monoid since each of their components do: the empty diagram has no primitives, an empty envelope, an empty trace, no named subdiagrams, 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. |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Semigroup (QDiagram b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Qualifiable (QDiagram b v m) | Diagrams can be qualified so that all their named points can now be referred to using the qualification prefix. |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => HasOrigin (QDiagram b v m) | Every diagram has an intrinsic "local origin" which is the basis for all combining operations. |
(HasLinearMap v, OrderedField (Scalar v), InnerSpace v, Semigroup m) => Transformable (QDiagram b v m) | Diagrams can be transformed by transforming each of their components appropriately. |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => HasStyle (QDiagram b v m) | |
(HasLinearMap v, VectorSpace v, Ord (Scalar v)) => Traced (QDiagram b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v)) => Enveloped (QDiagram b v m) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Juxtaposable (QDiagram b v m) | |
Newtype (QDiagram b v m) (DUALTree (DownAnnots v) (UpAnnots b v m) () (Prim b v)) |
mkQD :: Prim b v -> Envelope v -> Trace v -> SubMap b v m -> Query v m -> QDiagram b v mSource
Create a diagram from a single primitive, along with an envelope, trace, subdiagram map, and query function.
prims :: HasLinearMap v => QDiagram b v m -> [(Prim b v, (Split (Transformation v), Style v))]Source
Extract a list of primitives from a diagram, together with their associated transformations and styles.
trace :: (Ord (Scalar v), VectorSpace v, HasLinearMap v) => QDiagram b v m -> Trace vSource
Get the trace of a diagram.
subMap :: QDiagram b v m -> SubMap b v mSource
Get the subdiagram map (i.e. an association from names to subdiagrams) of a diagram.
names :: HasLinearMap v => QDiagram b v m -> [(Name, [Point v])]Source
Get a list of names of subdiagrams and their locations.
query :: Monoid m => QDiagram b v m -> Query v mSource
Get the query function associated with a diagram.
sample :: Monoid m => QDiagram b v m -> Point v -> mSource
Sample a diagram's query function at a given point.
clearValue :: QDiagram b v m -> QDiagram b v AnySource
Set all the query values of a diagram to False
.
named :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => n -> QDiagram b v m -> QDiagram b v mSource
Attach an atomic name to a diagram.
nameSub :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => (QDiagram b v m -> Subdiagram b v m) -> n -> QDiagram b v m -> QDiagram b v mSource
Attach an atomic name to a certain subdiagram, computed from the given diagram.
namePoint :: (IsName n, HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => (QDiagram b v m -> Point v) -> n -> QDiagram b v m -> QDiagram b v mSource
Attach an atomic name to a certain point (which may be computed from the given diagram), treated as a subdiagram with no content and a point envelope.
withName :: IsName n => n -> (Subdiagram b v m -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v mSource
Given a name and a diagram transformation indexed by a subdiagram, perform the transformation using the most recent subdiagram associated with (some qualification of) the name, or perform the identity transformation if the name does not exist.
withNameAll :: IsName n => n -> ([Subdiagram b v m] -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v mSource
Given a name and a diagram transformation indexed by a list of subdiagrams, perform the transformation using the collection of all such subdiagrams associated with (some qualification of) the given name.
withNames :: IsName n => [n] -> ([Subdiagram b v m] -> QDiagram b v m -> QDiagram b v m) -> QDiagram b v m -> QDiagram b v mSource
Given a list of names and a diagram transformation indexed by a list of subdiagrams, perform the transformation using the list of most recent subdiagrams associated with (some qualification of) each name. Do nothing (the identity transformation) if any of the names do not exist.
freeze :: forall v b m. (HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => QDiagram b v m -> QDiagram b v mSource
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.
setEnvelope :: forall b v m. (OrderedField (Scalar v), InnerSpace v, HasLinearMap v, Monoid' m) => Envelope v -> QDiagram b v m -> QDiagram b v mSource
Replace the envelope of a diagram.
setTrace :: forall b v m. (OrderedField (Scalar v), InnerSpace v, HasLinearMap v, Semigroup m) => Trace v -> QDiagram b v m -> QDiagram b v mSource
Replace the trace of a diagram.
atop :: (HasLinearMap v, OrderedField (Scalar v), InnerSpace v, Semigroup m) => QDiagram b v m -> QDiagram b v m -> QDiagram b v mSource
A convenient synonym for mappend
on diagrams, designed to be
used infix (to help remember which diagram goes on top of which
when combining them, namely, the first on top of the second).
Subdiagrams
data Subdiagram b v m Source
A Subdiagram
represents a diagram embedded within the context
of a larger diagram. Essentially, it consists of a diagram
paired with any accumulated information from the larger context
(transformations, attributes, etc.).
Subdiagram (QDiagram b v m) (DownAnnots v) |
Functor (Subdiagram b v) | |
(HasLinearMap v, InnerSpace v, OrderedField (Scalar v)) => HasOrigin (Subdiagram b v m) | |
(HasLinearMap v, InnerSpace v, Floating (Scalar v)) => Transformable (Subdiagram b v m) | |
(Ord (Scalar v), VectorSpace v, HasLinearMap v) => Traced (Subdiagram b v m) | |
(OrderedField (Scalar v), InnerSpace v, HasLinearMap v) => Enveloped (Subdiagram b v m) | |
Newtype (SubMap b v m) (Map Name [Subdiagram b v m]) |
mkSubdiagram :: QDiagram b v m -> Subdiagram b v mSource
Turn a diagram into a subdiagram with no accumulated context.
getSub :: (HasLinearMap v, InnerSpace v, Floating (Scalar v), Ord (Scalar v), Semigroup m) => Subdiagram b v m -> QDiagram b v mSource
Turn a subdiagram into a normal diagram, including the enclosing
context. Concretely, a subdiagram is a pair of (1) a diagram and
(2) a "context" consisting of an extra transformation and
attributes. getSub
simply applies the transformation and
attributes to the diagram to get the corresponding "top-level"
diagram.
rawSub :: Subdiagram b v m -> QDiagram b v mSource
Extract the "raw" content of a subdiagram, by throwing away the context.
location :: HasLinearMap v => Subdiagram b v m -> Point vSource
Get the location of a subdiagram; that is, the location of its local origin with respect to the vector space of its parent diagram. In other words, the point where its local origin "ended up".
subPoint :: (HasLinearMap v, InnerSpace v, OrderedField (Scalar v), Semigroup m) => Point v -> Subdiagram b v mSource
Create a "point subdiagram", that is, a pointDiagram
(with no
content and a point envelope) treated as a subdiagram with local
origin at the given point. Note this is not the same as
mkSubdiagram . pointDiagram
, which would result in a subdiagram
with local origin at the parent origin, rather than at the given
point.
Backends
class (HasLinearMap v, Monoid (Render b v)) => Backend b v whereSource
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 = (>>)
.
The result of running/interpreting a rendering operation.
Backend-specific rendering options.
:: b | Backend token (needed only for type inference) |
-> Style v | Style to use |
-> Transformation v | Transformation to be applied to the style |
-> Render b v | Rendering operation to run |
-> Render b v | Rendering operation using the style locally |
Perform a rendering operation with a local style.
:: b | Backend token (needed only for type inference) |
-> Options b v | Backend-specific collection of rendering options |
-> Render b v | Rendering operation to perform |
-> Result b v | Output of the rendering operation |
doRender
is used to interpret rendering operations.
adjustDia :: Monoid' m => b -> Options b v -> QDiagram b v m -> (Options b v, QDiagram b v m)Source
adjustDia
allows the backend to make adjustments to the final
diagram (e.g. to adjust the size based on the options) before
rendering it. It can also make adjustments to the options
record, usually to fill in incompletely specified size
information. A default implementation is provided which makes
no adjustments. See the diagrams-lib package for other useful
implementations.
renderDia :: (InnerSpace v, OrderedField (Scalar v), Monoid' m) => b -> Options b v -> QDiagram b v m -> Result b vSource
Render a diagram. This has a default implementation in terms
of adjustDia
, withStyle
, doRender
, and the render
operation from the Renderable
class (first adjustDia
is
used, then withStyle
and render
are used to render each
primitive, the resulting operations are combined with
mconcat
, and the final operation run with doRender
) but
backends may override it if desired.
HasLinearMap v => Backend NullBackend v |
class Backend b v => MultiBackend b v whereSource
A class for backends which support rendering multiple diagrams, e.g. to a multi-page pdf or something similar.
renderDias :: (InnerSpace v, OrderedField (Scalar v), Monoid' m) => b -> Options b v -> [QDiagram b v m] -> Result b vSource
Render multiple diagrams at once.
class Transformable t => Renderable t b whereSource
The Renderable type class connects backends to primitives which they know how to render.
render :: b -> t -> Render b (V t)Source
Given a token representing the backend and a transformable object, render it in the appropriate rendering context.
HasLinearMap v => Renderable (Prim b v) b | The |
The null backend
data NullBackend Source
A null backend which does no actual rendering. It is provided
mainly for convenience in situations where you must give a
diagram a concrete, monomorphic type, but don't actually care
which one. See D
for more explanation and examples.
It is courteous, when defining a new primitive P
, to make an instance
instance Renderable P NullBackend where render _ _ = mempty
This ensures that the trick with D
annotations can be used for
diagrams containing your primitive.
HasLinearMap v => Backend NullBackend v | |
Monoid (Render NullBackend v) |
type D v = Diagram NullBackend vSource
The D
type is provided for convenience in situations where you
must give a diagram a concrete, monomorphic type, but don't care
which one. Such situations arise when you pass a diagram to a
function which is polymorphic in its input but monomorphic in its
output, such as width
, height
, phantom
, or names
. Such
functions compute some property of the diagram, or use it to
accomplish some other purpose, but do not result in the diagram
being rendered. If the diagram does not have a monomorphic type,
GHC complains that it cannot determine the diagram's type.
For example, here is the error we get if we try to compute the
width of an image (this example requires diagrams-lib
):
ghci> width (image "foo.png" 200 200) <interactive>:8:8: No instance for (Renderable Diagrams.TwoD.Image.Image b0) arising from a use of `image' Possible fix: add an instance declaration for (Renderable Diagrams.TwoD.Image.Image b0) In the first argument of `width', namely `(image "foo.png" 200 200)' In the expression: width (image "foo.png" 200 200) In an equation for `it': it = width (image "foo.png" 200 200)
GHC complains that there is no instance for Renderable Image
b0
; what is really going on is that it does not have enough
information to decide what backend to use (hence the
uninstantiated b0
). This is annoying because we know that the
choice of backend cannot possibly affect the width of the image
(it's 200! it's right there in the code!); but there is no way
for GHC to know that.
The solution is to annotate the call to image
with the type
, like so:
D
R2
ghci> width (image "foo.png" 200 200 :: D R2) 200.00000000000006
(It turns out the width wasn't 200 after all...)
As another example, here is the error we get if we try to compute the width of a radius-1 circle:
ghci> width (circle 1) <interactive>:4:1: Couldn't match type `V a0' with `R2' In the expression: width (circle 1) In an equation for `it': it = width (circle 1)
There's even more ambiguity here. Whereas image
always returns
a Diagram
, the circle
function can produce any PathLike
type, and the width
function can consume any Enveloped
type,
so GHC has no idea what type to pick to go in the middle.
However, the solution is the same:
ghci> width (circle 1 :: D R2) 1.9999999999999998
Convenience classes
class (HasBasis v, HasTrie (Basis v), VectorSpace v) => HasLinearMap v Source
HasLinearMap
is a poor man's class constraint synonym, just to
help shorten some of the ridiculously long constraint sets.
(HasBasis v, HasTrie (Basis v), VectorSpace v) => HasLinearMap v |
class (Fractional s, Floating s, Ord s, AdditiveGroup s) => OrderedField s Source
When dealing with envelopes 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.
(Fractional s, Floating s, Ord s, AdditiveGroup s) => OrderedField s |