{-# 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.moduleGraphics.Gloss.Data.QuadTree(QuadTree(..),emptyTree,emptyNode,takeQuadOfTree,liftToQuad,insertByPath,insertByCoord,lookupNodeByPath,lookupByPath,lookupByCoord,flattenQuadTree,flattenQuadTreeWithExtents)whereimportGraphics.Gloss.Data.QuadimportGraphics.Gloss.Data.Extent-- | The quad tree structure.dataQuadTreea-- | An empty node.=TNil-- | A leaf containint some value.|TLeafa-- | A node with four children.|TNode(QuadTreea)(QuadTreea)-- NW NE(QuadTreea)(QuadTreea)-- SW SEderivingShow-- | A `TNil` tree.emptyTree::QuadTreeaemptyTree=TNil-- | A node with `TNil`. for all its branches.emptyNode::QuadTreeaemptyNode=TNodeTNilTNilTNilTNil-- | Get a quadrant from a node.-- If the tree does not have an outer node then `Nothing`.takeQuadOfTree::Quad->QuadTreea->Maybe(QuadTreea)takeQuadOfTreequadtree=casetreeofTNil->NothingTLeaf{}->NothingTNodenwneswse->casequadofNW->JustnwNE->JustneSW->JustswSE->Justse-- | 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->(QuadTreea->QuadTreea)->QuadTreea->QuadTreealiftToQuadquadftree=casetreeofTNil->treeTLeaf{}->treeTNodenwneswse->casequadofNW->TNode(fnw)neswseNE->TNodenw(fne)swseSW->TNodenwne(fsw)seSE->TNodenwnesw(fse)-- | 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->QuadTreea->QuadTreeainsertByPath[]x_=TLeafxinsertByPath(q:qs)xtree=casetreeofTNil->liftToQuadq(insertByPathqsx)emptyNodeTLeaf{}->treeTNode{}->liftToQuadq(insertByPathqsx)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->QuadTreea->Maybe(QuadTreea)insertByCoordextentcoordxtree=dopath<-pathToCoordextentcoordreturn$insertByPathpathxtree-- | Lookup a node based on a path to it.lookupNodeByPath::[Quad]->QuadTreea->Maybe(QuadTreea)lookupNodeByPath[]tree=JusttreelookupNodeByPath(q:qs)tree=casetreeofTNil->NothingTLeaf{}->NothingTNode{}->letJustquad=takeQuadOfTreeqtreeinlookupNodeByPathqsquad-- | Lookup an element based given a path to it.lookupByPath::[Quad]->QuadTreea->MaybealookupByPathpathtree=caselookupNodeByPathpathtreeofJust(TLeafx)->Justx_->Nothing-- | Lookup a node if a tree given a coordinate which it contains.lookupByCoord::foralla.Extent-- ^ Extent that covers the whole tree.->Coord-- ^ Coordinate of the value of interest.->QuadTreea->MaybealookupByCoordextentcoordtree=dopath<-pathToCoordextentcoordlookupByPathpathtree-- | Flatten a QuadTree into a list of its contained values, with coordinates.flattenQuadTree::foralla.Extent-- ^ Extent that covers the whole tree.->QuadTreea->[(Coord,a)]flattenQuadTreeextentInittreeInit=flatten'extentInittreeInitwhereflatten'extenttree=casetreeofTNil->[]TLeafx->let(_,s,_,w)=takeExtentextentin[((w,s),x)]TNode{}->concat$map(flattenQuadextenttree)allQuadsflattenQuadextenttreequad=letextent'=cutQuadOfExtentquadextentJusttree'=takeQuadOfTreequadtreeinflatten'extent'tree'-- | Flatten a QuadTree into a list of its contained values, with coordinates.flattenQuadTreeWithExtents::foralla.Extent-- ^ Extent that covers the whole tree.->QuadTreea->[(Extent,a)]flattenQuadTreeWithExtentsextentInittreeInit=flatten'extentInittreeInitwhereflatten'extenttree=casetreeofTNil->[]TLeafx->[(extent,x)]TNode{}->concat$map(flattenQuadextenttree)allQuadsflattenQuadextenttreequad=letextent'=cutQuadOfExtentquadextentJusttree'=takeQuadOfTreequadtreeinflatten'extent'tree'