packages feed

dph-examples-0.6.0.1: examples/real/NBody/Gloss/Draw.hs

{-# LANGUAGE PatternGuards #-}
-- | Drawing the world as a gloss picture.
module Gloss.Draw
	(drawWorld)
where
import Common.World
import Common.Body
import Graphics.Gloss
import qualified Solver.ListBH.Solver		as L
import qualified Data.Vector.Unboxed		as V


-- | Radius of the circle representing each body.
pointSize :: Float
pointSize	= 4


-- | Draw the world, and optionally show the Barnes-Hut tree.
--   NOTE: We always show the list version tree, which might not be the one
--         that's actually being used to calculate the accelerations.
--         To display the other trees we'd have to write draw functions for them,
--         or functions to convert them to the list version.
--
drawWorld :: Bool -> World -> Picture
drawWorld shouldDrawTree world
 = let	picPoints	= Color (makeColor 1 1 1 0.4)
			$ Pictures 
			$ map drawBody
			$ V.toList 
			$ worldBodies world

   	picTree		= drawBHTree
			$ L.buildTree 
			$ map massPointOfBody
			$ V.toList 
			$ worldBodies world

   in	Pictures 
		[ if shouldDrawTree 
			then Color (makeColor 0.5 1.0 0.5 0.2) $ picTree
			else Blank
			
		, picPoints ]


-- | Draw a list version Barnes-Hut tree.
drawBHTree :: L.BHTree -> Picture
drawBHTree bht
 = drawBHTree' 0 bht

drawBHTree' depth bht
 = let	
	-- The bounding box
	L.Box left down right up	= L.bhTreeBox bht
	[left', down', right', up']	= map realToFrac [left, down, right, up]

	picCell		= lineLoop [(left', down'), (left', up'), (right', up'), (right', down')]


	-- Draw a circle with an area equal to the mass of the centroid.
	centroidX	= realToFrac $ L.bhTreeCenterX bht
	centroidY	= realToFrac $ L.bhTreeCenterY bht
	
	centroidMass	= L.bhTreeMass bht
	circleRadius	= realToFrac $ sqrt (centroidMass / pi)

	midX		= (left' + right') / 2
	midY		= (up'   + down')  / 2

	picCentroid	
	 | _:_	<- L.bhTreeBranch bht
	 , depth >= 1
	 = Color (makeColor 0.5 0.5 1.0 0.4)
		$  Pictures
			[ Line [(midX, midY), (centroidX, centroidY)]
			, Translate centroidX centroidY 
			$ ThickCircle
				(circleRadius * 4 / 2) 
				(circleRadius * 4) ]
			
	 | otherwise
	 = Blank

	-- The complete picture for this cell.
	picHere		= Pictures [picCentroid, picCell]
		
	-- Pictures of children.
	picSubs		= map (drawBHTree' (depth + 1))
			$ L.bhTreeBranch bht

   in	Pictures (picHere : picSubs)


-- | Draw a single body.
drawBody :: Body -> Picture
drawBody ((x, y, _), _, _)
	= drawPoint (x, y)


-- | Draw a point using a filled circle.
drawPoint :: (Double, Double) -> Picture
drawPoint (x, y)
	= Translate (realToFrac x) (realToFrac y) 
	$ ThickCircle (pointSize / 2) pointSize