{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Basic.Kernel.Objects.Displacement -- Copyright : (c) Stephen Tetley 2010-2011 -- License : BSD3 -- -- Maintainer : stephen.tetley@gmail.com -- Stability : highly unstable -- Portability : GHC -- -- Displacing points - often start points. -- -------------------------------------------------------------------------------- module Wumpus.Basic.Kernel.Objects.Displacement ( -- * Displacement PointDisplace , ThetaPointDisplace , displace , dispParallel , dispPerpendicular , dispOrtho , dispDirectionTheta , dispCardinalTheta -- * Named vectors , go_up , go_down , go_left , go_right , go_north , go_south , go_east , go_west , go_north_east , go_north_west , go_south_east , go_south_west , go_up_left , go_up_right , go_down_left , go_down_right ) where import Wumpus.Basic.Kernel.Base.BaseDefs import Wumpus.Core -- package: wumpus-core import Data.AffineSpace -- package: vector-space -- | 'PointDisplace' is a type representing functions -- @from Point to Point@. -- -- It is especially useful for building composite graphics where -- one part of the graphic is drawn from a different start point -- to the other part. -- type PointDisplace u = Point2 u -> Point2 u -- | 'ThetaPointDisplace' is a type representing functions -- @from Radian * Point to Point@. -- -- It is useful for building arrowheads which are constructed -- with an implicit angle representing the direction of the line -- at the arrow tip. -- type ThetaPointDisplace u = Radian -> Point2 u -> Point2 u -- | 'displace' : @ Vec2 -> PointDisplace @ -- -- Alias for @.+^@ from @Data.AffineSpace@. -- displace :: Num u => Vec2 u -> PointDisplace u displace (V2 dx dy) (P2 x y) = P2 (x+dx) (y+dy) -------------------------------------------------------------------------------- -- ThetaPointDisplace functions -- | 'dispParallel' : @ dist -> ThetaPointDisplace @ -- -- Build a combinator to move @Points@ in parallel to the -- direction of the implicit angle by the supplied distance -- @dist@. -- dispParallel :: Floating u => u -> ThetaPointDisplace u dispParallel d = \theta pt -> pt .+^ avec (circularModulo theta) d -- | 'dispParallel' : @ dist -> ThetaPointDisplace @ -- -- Build a combinator to move @Points@ perpendicular to the -- inclnation of the implicit angle by the supplied distance -- @dist@. -- dispPerpendicular :: Floating u => u -> ThetaPointDisplace u dispPerpendicular d = \theta pt -> pt .+^ avec (circularModulo $ theta + (0.5*pi)) d -- | 'dispOrtho' : @ vec -> ThetaPointDisplace @ -- -- This is a combination of @displaceParallel@ and -- @displacePerpendicular@, with the x component of the vector -- displaced in parallel and the y component displaced -- perpendicular. -- dispOrtho :: Floating u => Vec2 u -> ThetaPointDisplace u dispOrtho (V2 x y) = \theta -> dispParallel x theta . dispPerpendicular y theta -- | /Angular/ version of 'dispDirection'. -- -- The displacement direction is with respect to implicit angle -- of inclination, so: -- -- > up == perpendicular -- > down == perdendicular . negate -- > left == parallel . negate -- > right == parallel -- dispDirectionTheta :: Floating u => Direction -> u -> ThetaPointDisplace u dispDirectionTheta UP = dispPerpendicular dispDirectionTheta DOWN = dispPerpendicular . negate dispDirectionTheta LEFT = dispParallel . negate dispDirectionTheta RIGHT = dispParallel -- | /Angular/ version of 'dispCardinal'. -- -- The displacement direction is with respect to implicit angle -- of inclination, so: -- -- > north == perpendicular -- > east == parallel -- > south == perdendicular . negate -- > etc. -- dispCardinalTheta :: Floating u => Cardinal -> u -> ThetaPointDisplace u dispCardinalTheta NORTH = dispPerpendicular dispCardinalTheta NORTH_EAST = \d ang -> displace (avec (ang + (0.25*pi)) d) dispCardinalTheta EAST = dispParallel dispCardinalTheta SOUTH_EAST = \d ang -> displace (avec (ang + (1.75*pi)) d) dispCardinalTheta SOUTH = dispPerpendicular . negate dispCardinalTheta SOUTH_WEST = \d ang -> displace (avec (ang + (1.25*pi)) d) dispCardinalTheta WEST = dispParallel . negate dispCardinalTheta NORTH_WEST = \d ang -> displace (avec (ang + (0.75*pi)) d) -------------------------------------------------------------------------------- -- Named vectors go_up :: Num u => u -> Vec2 u go_up d = V2 0 d go_down :: Num u => u -> Vec2 u go_down d = V2 0 (-d) go_left :: Num u => u -> Vec2 u go_left d = V2 (-d) 0 go_right :: Num u => u -> Vec2 u go_right d = V2 d 0 go_north :: Num u => u -> Vec2 u go_north = go_up go_south :: Num u => u -> Vec2 u go_south = go_down go_east :: Num u => u -> Vec2 u go_east = go_right go_west :: Num u => u -> Vec2 u go_west = go_left go_north_east :: Floating u => u -> Vec2 u go_north_east = avec (0.25*pi) go_north_west :: Floating u => u -> Vec2 u go_north_west = avec (0.75*pi) go_south_east :: Floating u => u -> Vec2 u go_south_east = avec (1.75*pi) go_south_west :: Floating u => u -> Vec2 u go_south_west = avec (1.25*pi) go_up_left :: Num u => u -> Vec2 u go_up_left d = V2 (-d) d go_up_right :: Num u => u -> Vec2 u go_up_right d = V2 d d go_down_left :: Num u => u -> Vec2 u go_down_left d = V2 (-d) (-d) go_down_right :: Num u => u -> Vec2 u go_down_right d = V2 d (-d) -------------------------------------------------------------------------------- {- -- ORPHANS - need a new home... -- | Absolute units. -- centerRelative :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => (Int,Int) -> a -> Query (Anchor u) centerRelative coord a = snapmove coord >>= \v -> return $ center a .+^ v -- TODO - These are really for Anchors. -- -- Should the have a separate module or be rolled into the same -- module as the classes? -- -- | Value is 1 snap unit right. -- -- This function should be considered obsolete, pending a -- re-think. -- right_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) right_of = centerRelative (1,0) -- | Value is 1 snap move left. -- -- This function should be considered obsolete, pending a -- re-think. -- left_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) left_of = centerRelative ((-1),0) -- | Value is 1 snap move up, 1 snap move right. -- -- This function should be considered obsolete, pending a -- re-think. -- above_right_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) above_right_of = centerRelative (1,1) -- | Value is 1 snap move below, 1 snap move right. -- -- This function should be considered obsolete, pending a -- re-think. -- below_right_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) below_right_of = centerRelative (1, (-1)) -- | Value is 1 snap move up, 1 snap move left. -- -- This function should be considered obsolete, pending a -- re-think. -- above_left_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) above_left_of = centerRelative ((-1),1) -- | Value is 1 snap move down, 1 snap move left. -- -- This function should be considered obsolete, pending a -- re-think. -- below_left_of :: (CenterAnchor a, Fractional u, InterpretUnit u, u ~ DUnit a) => a -> Query (Anchor u) below_left_of = centerRelative ((-1),(-1)) -}