packages feed

wraparound (empty) → 0.0.1

raw patch · 5 files changed

+323/−0 lines, 5 filesdep +basesetup-changed

Dependencies added: base

Files

+ Data/WrapAround.hs view
@@ -0,0 +1,194 @@+{-|+  WrapAround is a convenience module which helps you perform calculations with+  points that are supposed to exist on a 2-dimensional, finite, unbounded plane.+  (Or infinite, bounded plane, depending on who you ask.) On such a plane, space+  wraps around so that an object travelling vertically or horizontally eventually+  comes back to the place where it started. This allows you to move objects+  around on a seamless map. For example, in some video games when an object+  crosses the bottom of the screen it reappears at the top.++  WrapAround represents the points and handles the common calculations properly+  so you don't have to bother with the messy math and edge cases. This is done+  with two data structures: a 'WrapMap', which stores information about the size+  of the plane, and a 'WrapPoint', which stores information about the location of+  the point.++  A WrapPoint is represented internally as a pair of angles, like in a torus.+  The WrapMap and WrapPoint structures are kept separate because some WrapPoint+  calculations can be performed without a WrapMap context. Functions typically+  only need a WrapMap when a WrapPoint must be converted to actual x, y+  coordinates or vice versa. You can perform calculations mixing WrapPoints that+  were generated with different WrapMaps, but this generally yields meaningless+  results.++  When you need the actual x, y coordinates, use the 'toCoords' conversion+  function.++  If you are grateful for this software, I gladly accept donations!++  <https://frigidcode.com/donate/>+-}+module Data.WrapAround ( WrapMap()+                       , wrapmap+                       , WrapPoint()+                       , wrappoint+                       , addPoints+                       , addPoints'+                       , distance+                       , subtractPoints+                       , toCoords+                       , vectorRelation+                       -- , windowView+                       -- , WrapWindow(..)+                       ) where++-- |Contains the contextual information necessary to convert a WrapPoint to+-- coordinates and vice versa.+data WrapMap = WrapMap { radiusr :: Double -- radius from tube center+                       , radiusR :: Double -- radius from torus center+                       }+  deriving (Show)++-- |Generates a 'WrapMap'.+wrapmap :: Double   -- ^ Width+        -> Double   -- ^ Height+        -> WrapMap+wrapmap width height = WrapMap { radiusR = height / (2 * pi)+                               , radiusr = width / (2 * pi)+                               }++-- |A representation of a point location that allows for wrapping in the+-- vertical or horizontal direction.+data WrapPoint = WrapPoint { angler :: Double -- radians around tube center+                           , angleR :: Double -- radians around torus center+                           }+  deriving (Show)++-- |Generates a 'WrapPoint'.+wrappoint :: WrapMap           -- ^ Corresponding WrapMap structure+          -> (Double, Double)  -- ^ x, y coordinates+          -> WrapPoint+wrappoint wmap (x, y)+  = let angleR' = fixAngle (y / radiusR wmap) in +    let angler' = fixAngle (x / radiusr wmap) in+    WrapPoint { angleR = angleR', angler = angler' }++-- |Converts a WrapPoint to x, y coordinates. Generally you will only will only+-- want to use this function for informational purposes, for example, to print+-- out the x, y coordinates or to feed the coordinates to a graphics display+-- function. If you convert a WrapPoint to x, y coordinates so that you can+-- perform calculations with the coordinates, you must handle the wrapping math+-- yourself and you are doing the work the module is supposed to do for you.+toCoords :: WrapMap          -- ^ Corresponding WrapMap structure+         -> WrapPoint        -- ^ WrapPoint to be converted+         -> (Double, Double)+toCoords WrapMap { radiusR = mRadiusR, radiusr = mRadiusr }+         WrapPoint { angleR = pAngleR, angler = pAngler }+  = (pAngler * mRadiusr, pAngleR * mRadiusR)++-- |Adds two WrapPoints together (vector style).+addPoints :: WrapPoint  -- ^ The first WrapPoint in the operation+          -> WrapPoint  -- ^ The WrapPoint to be added to the first WrapPoint+          -> WrapPoint+addPoints wp1 wp2+  = let angleR' = fixAngle (angleR wp1 + angleR wp2) in+    let angler' = fixAngle (angler wp1 + angler wp2) in+    WrapPoint { angleR = angleR', angler = angler' }++-- |Adds a WrapPoint and a pair of x, y coordinates (vector style).+addPoints' :: WrapMap           -- ^ The corresponding WrapMap structure+           -> WrapPoint         -- ^ The WrapPoint in the operation+           -> (Double, Double)  -- ^ The x, y coordinates to be added to the WrapPoint+           -> WrapPoint+addPoints' wmap wp1 (x, y)+  = let wp2 = wrappoint wmap (x, y) in+    let angleR' = fixAngle (angleR wp1 + angleR wp2) in+    let angler' = fixAngle (angler wp1 + angler wp2) in+    WrapPoint { angleR = angleR', angler = angler' }++-- |Subtracts a WrapPoint from a WrapPoint (vector style).+subtractPoints :: WrapPoint  -- ^ The first WrapPoint in the operation+               -> WrapPoint  -- ^ The WrapPoint to be subtracted from the first WrapPoint+               -> WrapPoint+subtractPoints wp1 wp2+  = let angleR' = fixAngle (angleR wp1 - angleR wp2) in+    let angler' = fixAngle (angler wp1 - angler wp2) in+    WrapPoint { angleR = angleR', angler = angler' }++-- distance :: WrapMap -> WrapPoint -> WrapPoint -> Double+-- distance WrapMap { radiusR = mRadiusR, radiusr = mRadiusr }+--          WrapPoint { angleR = p1angleR, angler = p1angler }+--          WrapPoint { angleR = p2angleR, angler = p2angler }+--   = let dXa = abs (p2angler - p1angler) in+--     let dYa = abs (p2angleR - p1angleR) in+--     let dXb = if p1angler < p2angler+--                 then abs ((p1angler + 2 * pi) - p2angler)+--                 else abs ((p1angler - 2 * pi) - p2angler) in+--     let dYb = if p1angleR < p2angleR+--                 then abs ((p1angleR + 2 * pi) - p2angleR)+--                 else abs ((p1angleR - 2 * pi) - p2angleR) in+--     let dX = min dXa dXb in+--     let dY = min dYa dYb in+--     let dX' = dX * mRadiusr in+--     let dY' = dY * mRadiusR in+--     sqrt (dX'**2 + dY'**2)+++-- |Finds the distance between two WrapPoints.+distance :: WrapMap    -- ^ The corresponding WrapMap structure+         -> WrapPoint  -- ^ The first WrapPoint+         -> WrapPoint  -- ^ The second WrapPoint+         -> Double+distance wmap wp1 wp2+  = let (dX, dY) = vectorRelation wmap wp1 wp2 in+     sqrt (dX**2 + dY**2)++fixAngle :: Double -> Double+fixAngle radians+  = let q = radians / (2 * pi) in+    let angle = radians - fromIntegral (truncate q) * (2 * pi) in+    if angle < 0 then 2 * pi + angle+                 else angle++-- |Returns the relationship between two WrapPoints as a pair of x, y+-- coordinates (a vector).+vectorRelation :: WrapMap          -- ^ The corresponding WrapMap structure+               -> WrapPoint        -- ^ The first WrapPoint+               -> WrapPoint        -- ^ The second WrapPoint+               -> (Double, Double)+vectorRelation WrapMap { radiusR = mRadiusR, radiusr = mRadiusr }+               WrapPoint { angleR = p1angleR, angler = p1angler }+               WrapPoint { angleR = p2angleR, angler = p2angler }+  = let dXa = abs (p2angler - p1angler) in+    let dYa = abs (p2angleR - p1angleR) in+    let dXb = if p1angler < p2angler+                then abs ((p1angler + 2 * pi) - p2angler)+                else abs ((p1angler - 2 * pi) - p2angler) in+    let dYb = if p1angleR < p2angleR+                then abs ((p1angleR + 2 * pi) - p2angleR)+                else abs ((p1angleR - 2 * pi) - p2angleR) in+    let dX = min dXa dXb in+    let dY = min dYa dYb in+    let dX' = dX * mRadiusr in+    let dY' = dY * mRadiusR in+    (dX', dY')++-- Maybe add these someday after I find them useful++-- data WrapWindow = WrapWindow { tlCorner :: (Double, Double)+--                              , width :: Double+--                              , height :: Double+--                              , wrapMap :: WrapMap+--                              }++-- windowView :: WrapWindow -> WrapPoint -> WrapPoint -> (Double, Double)+-- windowView window centerpoint point+--   = let cornerPoint = addPoints'+--                         (wrapMap window)+--                         centerpoint+--                         ((-width window) / 2.0, height window / 2.0) in+--     let (vx, vy) = vectorRelation (wrapMap window) cornerPoint point in+--     let vx' = vx in+--     let vy' = (-vy) in+--     (vx' + fst (tlCorner window), vy' + snd (tlCorner window))+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2012, Christopher Howard++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Christopher Howard nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ wrap-around-example.hs view
@@ -0,0 +1,35 @@+import Graphics.Gloss.Interface.Pure.Simulate+import GHC.Float+import Data.WrapAround++dispmode = InWindow "WrapAround module test" (1024, 768) (0, 0)++main = simulate dispmode (dim green) 10 model dispmodel stepfunc++data Model = Model { particles :: [(WrapPoint, (Double, Double))]+                   , wrapMap :: WrapMap }+  deriving (Show)++wmap = wrapmap 200 300++model = Model { particles = [ (wrappoint wmap (10, 10), (10, 0))+                            , (wrappoint wmap (30, 30), ((-5), (-5)))+                            ]+              , Main.wrapMap = wmap+              }++dispmodel m = let ps = do (wp, _) <- particles m+                          let (px, py) = toCoords (Main.wrapMap m) wp in+                            [ Polygon [ (double2Float px, double2Float py)+                                      , (double2Float px + 10, double2Float py)+                                      , (double2Float px + 10, double2Float py + 10)+                                      , (double2Float px, double2Float py + 10)+                                      ] ] in+              Translate (-100.0) (-150.0) (Color green (Pictures ps))++stepfunc _ _ m = let map = Main.wrapMap m in+                 let nparticles = do (wp, (x, y)) <- particles m+                                     [ (addPoints' map wp (x, y), (x, y)) ] in+                 m { particles = nparticles }++
+ wraparound.cabal view
@@ -0,0 +1,62 @@+Name:                wraparound++-- The package version. See the Haskell package versioning policy+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for+-- standards guiding when and how versions should be incremented.+Version:             0.0.1++-- A short (one-line) description of the package.+Synopsis:            Convenient handling of points on a seamless 2-dimensional plane++-- A longer description of the package.+Description:+        WrapAround helps you perform calculations involving points on a finite,+	unbounded plane, in which objects that move across one edge of the map+	appear on the other. Add points, calculate distance, and so forth+	without worrying about the edge cases and frustrating math mistakes.++-- URL for the project homepage or repository.+Homepage:            http://frigidcode.com++-- The license under which the package is released.+License:             BSD3++-- The file containing the license text.+License-file:        LICENSE++-- The package author(s).+Author:              Christopher Howard++-- An email address to which users can send suggestions, bug reports,+-- and patches.+Maintainer:          christopher.howard@frigidcode.com++-- A copyright notice.+-- Copyright:           ++Category:            Data++Build-type:          Simple++-- Extra files to be distributed with the package, such as examples or+-- a README.+Extra-source-files:  wrap-around-example.hs++-- Constraint on the version of Cabal needed to build this package.+Cabal-version:       >=1.10++Library+  -- Modules exported by the library.+  Exposed-modules:     Data.WrapAround+  +  -- Packages needed in order to build this package.+  Build-depends:       base >= 4 && < 5+  +  Default-language:    Haskell2010++  -- Modules not exported by this package.+  -- Other-modules:       +  +  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.+  -- Build-tools:         +