Copyright  (c) 20122013 diagramslib team (see LICENSE) 

License  BSDstyle (see LICENSE) 
Maintainer  diagramsdiscuss@googlegroups.com 
Safe Haskell  None 
Language  Haskell2010 
Wrapper for creating scaleinvariant objects in two dimensions.
 data ScaleInv t = ScaleInv {
 _scaleInvObj :: t
 _scaleInvDir :: Vn t
 _scaleInvLoc :: Point (V t) (N t)
 scaleInvObj :: forall t. Lens' (ScaleInv t) t
 scaleInvDir :: forall t. Lens' (ScaleInv t) (Vn t)
 scaleInvLoc :: forall t. Lens' (ScaleInv t) (Point (V t) (N t))
 scaleInv :: (V t ~ v, N t ~ n, Additive v, Num n) => t > v n > ScaleInv t
 scaleInvPrim :: (V t ~ V2, N t ~ n, RealFloat n, Typeable t, Renderable t b, Monoid m) => t > V2 n > QDiagram b (V t) (N t) m
Documentation
The ScaleInv
wrapper creates twodimensional scaleinvariant
objects. Intuitively, a scaleinvariant object is affected by
transformations like translations and rotations, but not by scales.
However, this is problematic when it comes to nonuniform
scales (e.g. scaleX 2 . scaleY 3
) since they can introduce a
perceived rotational component. The prototypical example is an
arrowhead on the end of a path, which should be scaleinvariant.
However, applying a nonuniform scale to the path but not the
arrowhead would leave the arrowhead pointing in the wrong
direction.
Moreover, for objects whose local origin is not at the local origin of the parent diagram, any scale can result in a translational component as well.
The solution is to also store a point (indicating the location, i.e. the local origin) and a unit vector (indicating the direction) along with a scaleinvariant object. A transformation to be applied is decomposed into rotational and translational components as follows:
 The transformation is applied to the direction vector, and the difference in angle between the original direction vector and its image under the transformation determines the rotational component. The rotation is applied with respect to the stored location, rather than the global origin.
 The vector from the location to the image of the location under the transformation determines the translational component.
ScaleInv  

(Show t, Show (Vn t)) => Show (ScaleInv t) #  
((~) (* > *) (V t) V2, (~) * (N t) n, RealFloat n, Transformable t) => Transformable (ScaleInv t) #  
((~) (* > *) (V t) v, (~) * (N t) n, Additive v, Num n, HasOrigin t) => HasOrigin (ScaleInv t) #  
((~) (* > *) (V t) V2, (~) * (N t) n, RealFloat n, Renderable t b) => Renderable (ScaleInv t) b #  
type V (ScaleInv t) #  
type N (ScaleInv t) #  
scaleInvObj :: forall t. Lens' (ScaleInv t) t #
scaleInvDir :: forall t. Lens' (ScaleInv t) (Vn t) #
scaleInv :: (V t ~ v, N t ~ n, Additive v, Num n) => t > v n > ScaleInv t #
Create a scaleinvariant object pointing in the given direction, located at the origin.
scaleInvPrim :: (V t ~ V2, N t ~ n, RealFloat n, Typeable t, Renderable t b, Monoid m) => t > V2 n > QDiagram b (V t) (N t) m #
Create a diagram from a single scaleinvariant primitive. The vector argument specifies the direction in which the primitive is "pointing" (for the purpose of keeping it rotated correctly under nonuniform scaling). The primitive is assumed to be "located" at the origin (for the purpose of translating it correctly under scaling).
Note that the resulting diagram will have an empty envelope, trace, and query. The reason is that the envelope, trace, and query cannot be cachedapplying a transformation would cause the cached envelope, etc. to get "out of sync" with the scaleinvariant object. The intention, at any rate, is that scaleinvariant things will be used only as "decorations" (e.g. arrowheads) which should not affect the envelope, trace, and query.