diagrams-lib-0.7: src/Diagrams/Align.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Diagrams.Align
-- Copyright : (c) 2011-2013 diagrams-lib team (see LICENSE)
-- License : BSD-style (see LICENSE)
-- Maintainer : diagrams-discuss@googlegroups.com
--
-- The /alignment/ of an object refers to the position of its local
-- origin with respect to its envelope. This module defines the
-- 'Alignable' class for things which can be aligned, as well as a
-- default implementation in terms of 'HasOrigin' and 'Enveloped',
-- along with several utility methods for alignment.
--
-----------------------------------------------------------------------------
module Diagrams.Align
( -- * Alignable class
Alignable(..)
, alignByDefault
-- * General alignment functions
, align
, center
) where
import Diagrams.Core
import Data.AffineSpace (alerp)
import Data.VectorSpace
import qualified Data.Map as M
import qualified Data.Set as S
-- | Class of things which can be aligned.
class Alignable a where
-- | @alignBy v d a@ moves the origin of @a@ along the vector
-- @v@. If @d = 1@, the origin is moved to the edge of the
-- envelope in the direction of @v@; if @d = -1@, it moves to the
-- edge of the envelope in the direction of the negation of @v@.
-- Other values of @d@ interpolate linearly (so for example, @d =
-- 0@ centers the origin along the direction of @v@).
alignBy :: V a -> Scalar (V a) -> a -> a
-- | Default implementation of 'alignBy' for types with 'HasOrigin'
-- and 'Enveloped' instances.
alignByDefault :: (HasOrigin a, Enveloped a, Num (Scalar (V a)))
=> V a -> Scalar (V a) -> a -> a
alignByDefault v d a = moveOriginTo (alerp (envelopeP (negateV v) a)
(envelopeP v a)
((d + 1) / 2))
a
instance (InnerSpace v, OrderedField (Scalar v)) => Alignable (Envelope v) where
alignBy = alignByDefault
instance (Enveloped b, HasOrigin b) => Alignable [b] where
alignBy = alignByDefault
instance (Enveloped b, HasOrigin b, Ord b) => Alignable (S.Set b) where
alignBy = alignByDefault
instance (Enveloped b, HasOrigin b) => Alignable (M.Map k b) where
alignBy = alignByDefault
instance ( HasLinearMap v, InnerSpace v, OrderedField (Scalar v)
, Monoid' m
) => Alignable (QDiagram b v m) where
alignBy = alignByDefault
-- | @align v@ aligns an enveloped object along the edge in the
-- direction of @v@. That is, it moves the local origin in the
-- direction of @v@ until it is on the edge of the envelope. (Note
-- that if the local origin is outside the envelope to begin with,
-- it may have to move \"backwards\".)
align :: (Alignable a, Num (Scalar (V a))) => V a -> a -> a
align v = alignBy v 1
-- | @center v@ centers an enveloped object along the direction of
-- @v@.
center :: (Alignable a, Num (Scalar (V a))) => V a -> a -> a
center v = alignBy v 0