packages feed

gloss-algorithms (empty) → 1.9.2.1

raw patch · 7 files changed

+541/−0 lines, 7 filesdep +basedep +containersdep +ghc-primsetup-changed

Dependencies added: base, containers, ghc-prim, gloss

Files

+ Graphics/Gloss/Algorithms/RayCast.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE PatternGuards, RankNTypes #-}++-- | Various ray casting algorithms.+module Graphics.Gloss.Algorithms.RayCast+	( castSegIntoCellularQuadTree+	, traceSegIntoCellularQuadTree)+where+import Graphics.Gloss.Data.Picture+import Graphics.Gloss.Data.Quad+import Graphics.Gloss.Data.Extent+import Graphics.Gloss.Data.QuadTree+import Data.List+import Data.Function+++-- | The quadtree contains cells of unit extent (NetHack style).+--   Given a line segement (P1-P2) through the tree, get the cell +--   closest to P1 that intersects the segment, if any.+--   +--   TODO: This currently uses a naive algorithm. It just calls +--         `traceSegIntoCellularQuadTree` and sorts the results+--         to get the one closest to P1. It'd be better to do a +--         proper walk over the tree in the direction of the ray.+--         +castSegIntoCellularQuadTree +	:: forall a+	.  Point 			-- ^ (P1) Starting point of seg.+	-> Point 			-- ^ (P2) Final point of seg.+	-> Extent 			-- ^ Extent convering the whole tree.+	-> QuadTree a 			-- ^ The tree.+	-> Maybe (Point, Extent, a)	-- ^ Intersection point, extent of cell, value of cell (if any).++castSegIntoCellularQuadTree p1 p2 extent tree+	| cells@(_:_)	<- traceSegIntoCellularQuadTree p1 p2 extent tree+	, c : _		<- sortBy ((compareDistanceTo p1) `on` (\(a, _, _) -> a) ) cells+	= Just c+	+	| otherwise+	= Nothing+	+compareDistanceTo :: Point -> Point -> Point -> Ordering+compareDistanceTo p0 p1 p2+ = let	d1	= distance p0 p1+	d2	= distance p0 p2+   in	compare d1 d2++distance :: Point -> Point -> Float+distance (x1, y1) (x2, y2)	+ = let	xd	= x2 - x1+	yd	= y2 - y1+   in	sqrt (xd * xd + yd * yd)+++-- | The quadtree contains cells of unit extent (NetHack style).+--   Given a line segment (P1-P2) through the tree, return the list of cells +--   that intersect the segment.+--  +traceSegIntoCellularQuadTree 	+	:: forall a+	.  Point 			-- ^ (P1) Starting point of seg.+	-> Point 			-- ^ (P2) Final point of seg.+	-> Extent 			-- ^ Extent covering the whole tree.+	-> QuadTree a 			-- ^ The tree.+	-> [(Point, Extent, a)]		-- ^ Intersection point, extent of cell, value of cell.+	+traceSegIntoCellularQuadTree p1 p2 extent tree + = case tree of+	TNil	-> []+	TLeaf a+	 -> case intersectSegExtent p1 p2 extent of+		Just pos	-> [(pos, extent, a)]+		Nothing		-> []+					+	TNode nw ne sw se+	 | touchesSegExtent p1 p2 extent +	 -> concat+             [ traceSegIntoCellularQuadTree p1 p2 (cutQuadOfExtent NW extent) nw+             , traceSegIntoCellularQuadTree p1 p2 (cutQuadOfExtent NE extent) ne+             , traceSegIntoCellularQuadTree p1 p2 (cutQuadOfExtent SW extent) sw+             , traceSegIntoCellularQuadTree p1 p2 (cutQuadOfExtent SE extent) se ]+	+	_ -> []
+ Graphics/Gloss/Data/Extent.hs view
@@ -0,0 +1,195 @@+{-# LANGUAGE PatternGuards #-}++-- | Represents an integral rectangular area of the 2D plane.+--   Using `Int`s (instead of `Float`s) for the bounds means we can safely+--   compare extents for equality.+module Graphics.Gloss.Data.Extent+	( Extent+	, Coord+	, makeExtent+	, takeExtent+	, squareExtent+	, sizeOfExtent+	, isUnitExtent+	, coordInExtent+	, pointInExtent+	, centerCoordOfExtent+	, cutQuadOfExtent+	, quadOfCoord+	, pathToCoord+	, intersectSegExtent+	, touchesSegExtent)+where+import Graphics.Gloss.Data.Point+import Graphics.Gloss.Data.Quad+import Graphics.Gloss.Geometry.Line+import Data.Maybe+++-- | A rectangular area of the 2D plane.+--   We keep the type abstract to ensure that invalid extents cannot be+--   constructed.+data Extent+	= Extent Int Int Int Int+	deriving (Eq, Show)+++-- | An integral coordinate.+type Coord+	= (Int, Int)+++-- | Construct an extent.+--	The north value must be > south, and east > west, else `error`.+makeExtent +	:: Int 	-- ^ y max (north)+	-> Int 	-- ^ y min (south)+	-> Int 	-- ^ x max (east)+	-> Int 	-- ^ x min (west)+	-> Extent++makeExtent n s e w+	| n >= s, e >= w+	= Extent n s e w+	+	| otherwise+	= error "Graphics.Gloss.Geometry.Extent.makeExtent: invalid extent"+++-- | Take the NSEW components of an extent.+takeExtent :: Extent -> (Int, Int, Int, Int)+takeExtent (Extent n s e w)+	= (n, s, e, w)+++-- | A square extent of a given size.+squareExtent :: Int -> Extent+squareExtent i+	= Extent i 0 i 0+++-- | Get the width and height of an extent.+sizeOfExtent :: Extent -> (Int, Int)+sizeOfExtent (Extent n s e w)+	= (e - w, n - s)+++-- | Check if an extent is a square with a width and height of 1.+isUnitExtent :: Extent -> Bool+isUnitExtent extent+	= sizeOfExtent extent == (1, 1)+++-- | Check whether a coordinate lies inside an extent.+coordInExtent :: Extent -> Coord -> Bool+coordInExtent (Extent n s e w) (x, y)+	=  x >= w && x < e+	&& y >= s && y < n+++-- | Check whether a point lies inside an extent.+pointInExtent :: Extent -> Point -> Bool+pointInExtent (Extent n s e w) (x, y)+ = let	n'	= fromIntegral n+	s'	= fromIntegral s+	e'	= fromIntegral e+	w'	= fromIntegral w+	+   in	x >= w' && x <= e'+     && y >= s' && y <= n'+++-- | Get the coordinate that lies at the center of an extent.+centerCoordOfExtent :: Extent -> (Int, Int)+centerCoordOfExtent (Extent n s e w)+ = 	( w + (e - w) `div` 2+	, s + (n - s) `div` 2)+++-- | Cut one quadrant out of an extent.+cutQuadOfExtent :: Quad -> Extent -> Extent+cutQuadOfExtent quad (Extent n s e w)  + = let	hheight	= (n - s) `div` 2+	hwidth	= (e - w) `div` 2+   in	case quad of+	  	NW -> Extent n (s + hheight)  (e - hwidth) w+		NE -> Extent n (s + hheight)  e (w + hwidth)+		SW -> Extent (n - hheight) s  (e - hwidth) w+		SE -> Extent (n - hheight) s  e (w + hwidth)+	+	+-- | Get the quadrant that this coordinate lies in, if any.+quadOfCoord :: Extent -> Coord -> Maybe Quad+quadOfCoord extent coord+ 	= listToMaybe +	$ filter (\q -> coordInExtent (cutQuadOfExtent q extent) coord)+	$ allQuads++	+-- | Constuct a path to a particular coordinate in an extent.+pathToCoord :: Extent -> Coord -> Maybe [Quad]+pathToCoord extent coord+	| isUnitExtent extent	+	= Just []+	+	| otherwise+	= do	quad	<- quadOfCoord extent coord+		rest	<- pathToCoord (cutQuadOfExtent quad extent) coord+		return	$ quad : rest+++-- | If a line segment (P1-P2) intersects the outer edge of an extent then+--   return the intersection point, that is closest to P1, if any.+--   If P1 is inside the extent then `Nothing`.+--+--   @+--                   P2+--                  /+--            ----/-+--            | /  |+--            +    |+--           /------+--         / +--        P1+--   @+-- +intersectSegExtent :: Point -> Point -> Extent -> Maybe Point+intersectSegExtent p1@(x1, y1) p2 (Extent n' s' e' w')+	-- starts below extent+	| y1 < s+	, Just pos	<- intersectSegHorzSeg p1 p2 s w e+	= Just pos+	+	-- starts above extent+	| y1 > n+	, Just pos	<- intersectSegHorzSeg p1 p2 n w e+	= Just pos++	-- starts left of extent+	| x1 < w+	, Just pos	<- intersectSegVertSeg p1 p2 w s n+	= Just pos+	+	-- starts right of extent+	| x1 > e+	, Just pos	<- intersectSegVertSeg p1 p2 e s n+	= Just pos++	-- must be starting inside extent.+	| otherwise+	= Nothing+	+	where	n	= fromIntegral n'+		s	= fromIntegral s'+		e	= fromIntegral e'+		w	= fromIntegral w'+++-- | Check whether a line segment's endpoints are inside an extent, or if it+--   intersects with the boundary.+touchesSegExtent :: Point -> Point -> Extent -> Bool+touchesSegExtent p1 p2 extent+	=   pointInExtent extent p1+       	 || pointInExtent extent p2+	 || isJust (intersectSegExtent p1 p2 extent)+
+ Graphics/Gloss/Data/Quad.hs view
@@ -0,0 +1,17 @@++module Graphics.Gloss.Data.Quad+	( Quad(..)+	, allQuads)+where+	+-- | Represents a Quadrant in the 2D plane.+data Quad+	= NW 	-- ^ North West+	| NE 	-- ^ North East+	| SW 	-- ^ South West+	| SE	-- ^ South East+	deriving (Show, Eq, Enum)++-- | A list of all quadrants. Same as @[NW .. SE]@.+allQuads :: [Quad]+allQuads = [NW .. SE]
+ Graphics/Gloss/Data/QuadTree.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE RankNTypes #-}++-- | A QuadTree can be used to recursively divide up 2D space into quadrants.+--   The smallest division corresponds to an unit `Extent`, so the total depth +--   of the tree will depend on what sized `Extent` you start with.+module Graphics.Gloss.Data.QuadTree+	( QuadTree (..)+	, emptyTree+	, emptyNode+	, takeQuadOfTree+	, liftToQuad+	, insertByPath+	, insertByCoord+	, lookupNodeByPath+	, lookupByPath+	, lookupByCoord+	, flattenQuadTree+	, flattenQuadTreeWithExtents)+where+import Graphics.Gloss.Data.Quad+import Graphics.Gloss.Data.Extent++-- | The quad tree structure.+data QuadTree a+	-- | An empty node.+	= TNil++	-- | A leaf containint some value.+	| TLeaf a+	+	-- | A node with four children.+	| TNode (QuadTree a) (QuadTree a) 	-- NW NE+		(QuadTree a) (QuadTree a)	-- SW SE+	deriving Show+++-- | A `TNil` tree.+emptyTree :: QuadTree a+emptyTree = TNil+++-- | A node with `TNil`. for all its branches.+emptyNode :: QuadTree a+emptyNode = TNode TNil TNil TNil TNil+++-- | Get a quadrant from a node.+--   If the tree does not have an outer node then `Nothing`.+takeQuadOfTree+	:: Quad+	-> QuadTree a+	-> Maybe (QuadTree a)++takeQuadOfTree quad tree+ = case tree of+	TNil		-> Nothing+	TLeaf{}		-> Nothing+	TNode nw ne sw se+	 -> case quad of+		NW	-> Just nw+		NE	-> Just ne+		SW	-> Just sw+		SE	-> Just se+++-- | Apply a function to a quadrant of a node.+--   If the tree does not have an outer node then return the original tree.+liftToQuad+	:: Quad+	-> (QuadTree a -> QuadTree a) +	-> QuadTree a  -> QuadTree a++liftToQuad quad f tree+ = case tree of+	TNil		-> tree+	TLeaf{}		-> tree+	TNode nw ne sw se+	 -> case quad of+		NW	-> TNode (f nw) ne sw se+		NE	-> TNode nw (f ne) sw se+		SW	-> TNode nw ne (f sw) se+		SE	-> TNode nw ne sw (f se)+		 +		+-- | Insert a value into the tree at the position given by a path.+--   If the path intersects an existing `TLeaf` then return the original tree.+insertByPath :: [Quad] -> a -> QuadTree a -> QuadTree a+	+insertByPath [] x _+	= TLeaf x+	+insertByPath (q:qs) x tree+ = case tree of+	TNil	-> liftToQuad q (insertByPath qs x) emptyNode+	TLeaf{}	-> tree+	TNode{}	-> liftToQuad q (insertByPath qs x) tree+++-- | Insert a value into the node containing this coordinate.+--   The node is created at maximum depth, corresponding to an unit `Extent`.+insertByCoord :: Extent -> Coord -> a -> QuadTree a -> Maybe (QuadTree a)+insertByCoord extent coord x tree+ = do	path	<- pathToCoord extent coord+	return	$  insertByPath path x tree+++-- | Lookup a node based on a path to it.+lookupNodeByPath+	:: [Quad]+	-> QuadTree a+	-> Maybe (QuadTree a)++lookupNodeByPath [] tree+	= Just tree+	+lookupNodeByPath (q:qs) tree+ = case tree of+	TNil	-> Nothing+	TLeaf{}	-> Nothing+	TNode{}+	 -> let Just quad	= takeQuadOfTree q tree+	    in  lookupNodeByPath qs quad+++-- | Lookup an element based given a path to it.+lookupByPath :: [Quad] -> QuadTree a -> Maybe a+lookupByPath path tree+ = case lookupNodeByPath path tree of+	Just (TLeaf x)	-> Just x+	_		-> Nothing+++-- | Lookup a node if a tree given a coordinate which it contains.+lookupByCoord +	:: forall a+	.  Extent 	-- ^ Extent that covers the whole tree.+	-> Coord 	-- ^ Coordinate of the value of interest.+	-> QuadTree a +	-> Maybe a+lookupByCoord extent coord tree+ = do	path	<- pathToCoord extent coord+	lookupByPath path tree+	+	+-- | Flatten a QuadTree into a list of its contained values, with coordinates.+flattenQuadTree +	:: forall a+	.  Extent 	-- ^ Extent that covers the whole tree.+	-> QuadTree a +	-> [(Coord, a)]+	+flattenQuadTree extentInit treeInit+ = flatten' extentInit treeInit+ where	flatten' extent tree+ 	 = case tree of+		TNil	-> []+		TLeaf x	+		 -> let (_, s, _, w) = takeExtent extent+		    in  [((w, s), x)]++		TNode{}	-> concat $ map (flattenQuad extent tree) allQuads+			+	flattenQuad extent tree quad+ 	 = let	extent'		= cutQuadOfExtent quad extent+		Just tree'	= takeQuadOfTree quad tree+   	   in	flatten' extent' tree'+++-- | Flatten a QuadTree into a list of its contained values, with coordinates.+flattenQuadTreeWithExtents+	:: forall a+	.  Extent 	-- ^ Extent that covers the whole tree.+	-> QuadTree a +	-> [(Extent, a)]+	+flattenQuadTreeWithExtents extentInit treeInit+ = flatten' extentInit treeInit+ where	flatten' extent tree+ 	 = case tree of+		TNil	-> []+		TLeaf x	+		 -> [(extent, x)]++		TNode{}	-> concat $ map (flattenQuad extent tree) allQuads+			+	flattenQuad extent tree quad+ 	 = let	extent'		= cutQuadOfExtent quad extent+		Just tree'	= takeQuadOfTree quad tree+   	   in	flatten' extent' tree'++
+ LICENSE view
@@ -0,0 +1,13 @@+Copyright (c) 2010-2014 Benjamin Lippmeier ++ Permission is hereby granted, free of charge, to any person+ obtaining a copy of this software and associated documentation+ files (the "Software"), to deal in the Software without+ restriction, including without limitation the rights to use,+ copy, modify, merge, publish, distribute, sublicense, and/or sell+ copies of the Software, and to permit persons to whom the+ Software is furnished to do so, subject to the following+ condition:++ The above copyright notice and this permission notice shall be+ included in all copies or substantial portions of the Software.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ gloss-algorithms.cabal view
@@ -0,0 +1,41 @@+Name:                gloss-algorithms+Version:             1.9.2.1+License:             MIT+License-file:        LICENSE+Author:              Ben Lippmeier+Maintainer:          benl@ouroborus.net+Build-Type:          Simple+Cabal-Version:       >=1.6+Stability:           stable+Category:            Graphics+Homepage:            http://gloss.ouroborus.net+Bug-reports:         gloss@ouroborus.net+Description:+        Data structures and algorithms for working with 2D graphics.++Synopsis:+        Data structures and algorithms for working with 2D graphics.++source-repository head+        type:           git+        location:       https://github.com/benl23x5/gloss++Library+  Build-Depends: +        base       == 4.7.*,+        ghc-prim   == 0.3.*,+        containers == 0.5.*,+        gloss      == 1.9.2.*++  ghc-options:+        -O2 -Wall++  Exposed-modules:+        Graphics.Gloss.Algorithms.RayCast+        Graphics.Gloss.Data.Extent+        Graphics.Gloss.Data.Quad+        Graphics.Gloss.Data.QuadTree++  Extensions:+        DeriveDataTypeable+        PatternGuards