{-# LANGUAGE TypeFamilies #-}{-# LANGUAGE MultiParamTypeClasses #-}{-# LANGUAGE FlexibleContexts #-}{-# OPTIONS -Wall #-}-------------------------------------------------------------------------------- |-- Module : Wumpus.Core.AffineTrans-- Copyright : (c) Stephen Tetley 2009-2010-- License : BSD3---- Maintainer : stephen.tetley@gmail.com-- Stability : unstable-- Portability : GHC---- Affine transformations.-- -- The common affine transformations represented as type classes --- scaling, rotation, translation.---- Unlike other functional graphics systems (e.g. Clastic), Wumpus-- performs the affine transformations as matrix operations. This -- simplifies the implementation of pictures -- ("Wumpus.Core.PictureInternal"). When a picture is composed and -- transformed, transformations will be performed only on the -- bounding box in Wumpus but the transformation of the -- picture content (paths or text labels) will be communicated to -- PostScript or SVG to render. This is because Wumpus has no -- access to the paths that make fonts so cannot transform them -- directly.-- -- To generate efficient PostScript, Wumpus relies on the matrix-- representations of the affine transformations being invertible.-- Do not scale elements by zero!----------------------------------------------------------------------------------moduleWumpus.Core.AffineTrans(-- * Type classesTransform(..),Rotate(..),RotateAbout(..),Scale(..),Translate(..)-- * Common rotations,rotate30,rotate30About,rotate45,rotate45About,rotate60,rotate60About,rotate90,rotate90About,rotate120,rotate120About-- * Common scalings,uniformScale,reflectX,reflectY-- * Translate by a vector,translateBy-- * Reflections in supplied plane rather than about the origin,reflectXPlane,reflectYPlane)whereimportWumpus.Core.Geometry---------------------------------------------------------------------------------- Affine transformations -- | Apply a matrix transformation directly.--classTransformtwheretransform::u~DUnitt=>Matrix3'3u->t->t-- | Type class for rotation.-- classRotatetwhererotate::Radian->t->tinstanceNumu=>Transform(Point2u)wheretransformctm=(ctm*#)instanceNumu=>Transform(Vec2u)wheretransformctm=(ctm*#)instance(Floatingu,Realu)=>Rotate(Point2u)whererotatea=((rotationMatrixa)*#)instance(Floatingu,Realu)=>Rotate(Vec2u)whererotatea=((rotationMatrixa)*#)-- | Type class for rotation about a point.--classRotateAbouttwhererotateAbout::u~DUnitt=>Radian->Point2u->t->tinstance(Floatingu,Realu)=>RotateAbout(Point2u)whererotateAboutapt=((originatedRotationMatrixapt)*#)instance(Floatingu,Realu)=>RotateAbout(Vec2u)whererotateAboutapt=((originatedRotationMatrixapt)*#)---------------------------------------------------------------------------------- Scale-- | Type class for scaling.--classScaletwherescale::u~DUnitt=>u->u->t->tinstanceNumu=>Scale(Point2u)wherescalesxsy=((scalingMatrixsxsy)*#)instanceNumu=>Scale(Vec2u)wherescalesxsy=((scalingMatrixsxsy)*#)---------------------------------------------------------------------------------- Translate-- | Type class for translation.--classTranslatetwheretranslate::DUnitt->DUnitt->t->tinstanceNumu=>Translate(Point2u)wheretranslatedxdy(P2xy)=P2(x+dx)(y+dy)instanceNumu=>Translate(Vec2u)wheretranslatedxdy(V2xy)=V2(x+dx)(y+dy)-------------------------------------------------------------------------------- -- Common rotations-- | Rotate by 30 degrees about the origin. --rotate30::Rotatet=>t->trotate30=rotate(pi/6)-- | Rotate by 30 degrees about the supplied point.--rotate30About::(RotateAboutt,DUnitt~u)=>Point2u->t->trotate30About=rotateAbout(pi/6)-- | Rotate by 45 degrees about the origin. --rotate45::Rotatet=>t->trotate45=rotate(pi/4)-- | Rotate by 45 degrees about the supplied point.--rotate45About::(RotateAboutt,DUnitt~u)=>Point2u->t->trotate45About=rotateAbout(pi/4)-- | Rotate by 60 degrees about the origin. --rotate60::Rotatet=>t->trotate60=rotate(2*pi/3)-- | Rotate by 60 degrees about the supplied point.--rotate60About::(RotateAboutt,DUnitt~u)=>Point2u->t->trotate60About=rotateAbout(2*pi/3)-- | Rotate by 90 degrees about the origin. --rotate90::Rotatet=>t->trotate90=rotate(pi/2)-- | Rotate by 90 degrees about the supplied point.--rotate90About::(RotateAboutt,DUnitt~u)=>Point2u->t->trotate90About=rotateAbout(pi/2)-- | Rotate by 120 degrees about the origin. --rotate120::Rotatet=>t->trotate120=rotate(4*pi/3)-- | Rotate by 120 degrees about the supplied point.--rotate120About::(RotateAboutt,DUnitt~u)=>Point2u->t->trotate120About=rotateAbout(4*pi/3)---------------------------------------------------------------------------------- Common scalings-- | Scale both x and y dimensions by the same amount.--uniformScale::(Scalet,DUnitt~u)=>u->t->tuniformScalea=scaleaa-- | Reflect in the X-plane about the origin.--reflectX::(Numu,Scalet,DUnitt~u)=>t->treflectX=scale(-1)1-- | Reflect in the Y-plane about the origin.--reflectY::(Numu,Scalet,DUnitt~u)=>t->treflectY=scale1(-1)---------------------------------------------------------------------------------- Translations-- | Translate by the x and y components of a vector.--translateBy::(Translatet,DUnitt~u)=>Vec2u->t->ttranslateBy(V2xy)=translatexy---------------------------------------------------------------------------------- Translation and scaling-- | Reflect in the X plane that intersects the supplied point. --reflectXPlane::(Numu,Scalet,Translatet,u~DUnitt)=>Point2u->t->treflectXPlane(P2xy)=translatexy.scale(-1)1.translate(-x)(-y)-- | Reflect in the Y plane that intersects the supplied point.--reflectYPlane::(Numu,Scalet,Translatet,u~DUnitt)=>Point2u->t->treflectYPlane(P2xy)=translatexy.scale1(-1).translate(-x)(-y)