-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Simple force-directed layout
--   
--   Simulation engine for doing simple force-based layout, <i>e.g.</i> for
--   trees or graphs. See the diagrams-contrib package for usage examples.
@package force-layout
@version 0.4.0.6


-- | A simple, Haskell-native simulator for doing force-directed layout,
--   <i>e.g.</i> of trees or graphs.
--   
--   To use, just create an <a>Ensemble</a> like so:
--   
--   <pre>
--   import           Control.Lens        ((&amp;), (.~))
--   import           Data.Default.Class  (def)
--   import qualified Data.Map            as M
--   import           Linear.Affine
--   import           Linear.V2
--   import           Physics.ForceLayout
--   
--   e :: Ensemble V2 Double
--   e = Ensemble [ (edges,    hookeForce 0.05 4)
--                , (allPairs, coulombForce 1)
--                ]
--                particleMap
--     where edges       = [(1,2), (2,3), (2,5), (3,5), (3,4), (4,5)]
--           allPairs    = [(x,y) | x &lt;- [1..4], y &lt;- [x+1..5]]
--           particleMap = M.fromList . zip [1..]
--                       . map (initParticle . P . uncurry V2)
--                       $ [ (2.0, 3.1), (6.3, 7.2)
--                         , (0.3, 4.2), (1.6, -1.1)
--                         , (4.8, 2.9)
--                         ]
--   </pre>
--   
--   Then run a simulation using either <a>simulate</a> (to get the list of
--   all intermediate states) or <a>forceLayout</a> (to get only the ending
--   state):
--   
--   <pre>
--   e' :: Ensemble V2 Double
--   e' = forceLayout (def &amp; damping     .~ 0.8
--                         &amp; energyLimit .~ Just 0.001
--                         &amp; stepLimit   .~ Nothing
--                    )
--                    e
--   </pre>
--   
--   See the diagrams-contrib package
--   (<a>http://github.com/diagrams/diagrams-contrib/</a>) for more
--   examples.
module Physics.ForceLayout

-- | A particle has a current position, current velocity, and current force
--   acting on it.
data Particle v n
Particle :: Point v n -> v n -> v n -> Particle v n
[_pos] :: Particle v n -> Point v n
[_vel] :: Particle v n -> v n
[_force] :: Particle v n -> v n
pos :: forall v_a9eB n_a9eC. Lens' (Particle v_a9eB n_a9eC) (Point v_a9eB n_a9eC)
vel :: forall v_a9eB n_a9eC. Lens' (Particle v_a9eB n_a9eC) (v_a9eB n_a9eC)
force :: forall v_a9eB n_a9eC. Lens' (Particle v_a9eB n_a9eC) (v_a9eB n_a9eC)

-- | Create an initial particle at rest at a particular location.
initParticle :: (Additive v, Num n) => Point v n -> Particle v n

-- | Used to uniquely identify particles.
type PID = Int

-- | An edge is a pair of particle identifiers.
type Edge = (PID, PID)

-- | An <tt>Ensemble</tt> is a physical configuration of particles. It
--   consists of a mapping from particle IDs (unique integers) to
--   particles, and a list of forces that are operative. Each force has a
--   list of edges to which it applies, and is represented by a function
--   giving the force between any two points.
data Ensemble v n
Ensemble :: [([Edge], Point v n -> Point v n -> v n)] -> Map PID (Particle v n) -> Ensemble v n
[_forces] :: Ensemble v n -> [([Edge], Point v n -> Point v n -> v n)]
[_particles] :: Ensemble v n -> Map PID (Particle v n)
forces :: forall v_ae6F n_ae6G. Lens' (Ensemble v_ae6F n_ae6G) [([Edge], Point v_ae6F n_ae6G -> Point v_ae6F n_ae6G -> v_ae6F n_ae6G)]
particles :: forall v_ae6F n_ae6G. Lens' (Ensemble v_ae6F n_ae6G) (Map PID (Particle v_ae6F n_ae6G))

-- | <tt>hookeForce k l p1 p2</tt> computes the force on <tt>p1</tt>,
--   assuming that <tt>p1</tt> and <tt>p2</tt> are connected by a spring
--   with equilibrium length <tt>l</tt> and spring constant <tt>k</tt>.
hookeForce :: (Metric v, Floating n) => n -> n -> Point v n -> Point v n -> v n

-- | <tt>coulombForce k</tt> computes the electrostatic repulsive force
--   between two charged particles, with constant of proportionality
--   <tt>k</tt>.
coulombForce :: (Metric v, Floating n) => n -> Point v n -> Point v n -> v n

-- | <tt>distForce f p1 p2</tt> computes the force between two points as a
--   multiple of the unit vector in the direction from <tt>p1</tt> to
--   <tt>p2</tt>, given a function <tt>f</tt> which computes the force's
--   magnitude as a function of the distance between the points.
distForce :: (Metric v, Floating n) => (n -> n) -> Point v n -> Point v n -> v n

-- | Options for customizing a simulation.
data ForceLayoutOpts n
FLOpts :: n -> Maybe n -> Maybe Int -> ForceLayoutOpts n

-- | Damping factor to be applied at each step. Should be between 0 and 1.
--   The default is 0.8.
[_damping] :: ForceLayoutOpts n -> n

-- | Kinetic energy below which simulation should stop. If
--   <tt>Nothing</tt>, pay no attention to kinetic energy. The default is
--   <tt>Just 0.001</tt>.
[_energyLimit] :: ForceLayoutOpts n -> Maybe n

-- | Maximum number of simulation steps. If <tt>Nothing</tt>, pay no
--   attention to the number of steps. The default is <tt>Just 1000</tt>.
[_stepLimit] :: ForceLayoutOpts n -> Maybe Int
damping :: forall n_aeEk. Lens' (ForceLayoutOpts n_aeEk) n_aeEk
energyLimit :: forall n_aeEk. Lens' (ForceLayoutOpts n_aeEk) (Maybe n_aeEk)
stepLimit :: forall n_aeEk. Lens' (ForceLayoutOpts n_aeEk) (Maybe Int)

-- | Simulate a starting ensemble according to the given options, producing
--   a list of all the intermediate ensembles. Useful for, <i>e.g.</i>,
--   making an animation. Note that the resulting list could be infinite,
--   if a <a>stepLimit</a> is not specified and either the kinetic energy
--   never falls below the specified threshold, or no energy threshold is
--   specified.
simulate :: (Metric v, Num n, Ord n) => ForceLayoutOpts n -> Ensemble v n -> [Ensemble v n]

-- | Run a simluation from a starting ensemble, yielding either the first
--   ensemble to have kinetic energy below the <a>energyLimit</a> (if
--   given), or the ensemble that results after a number of steps equal to
--   the <a>stepLimit</a> (if given), whichever comes first. Otherwise
--   <tt>forceLayout</tt> will not terminate.
forceLayout :: (Metric v, Num n, Ord n) => ForceLayoutOpts n -> Ensemble v n -> Ensemble v n

-- | Simulate one time step for an entire ensemble, with the given damping
--   factor.
ensembleStep :: (Additive v, Num n) => n -> Ensemble v n -> Ensemble v n

-- | Simulate one time step for a particle (assuming the force acting on it
--   has already been computed), with the given damping factor.
particleStep :: (Additive v, Num n) => n -> Particle v n -> Particle v n

-- | Recalculate all the forces acting in the next time step of an
--   ensemble.
recalcForces :: (Additive v, Num n) => Ensemble v n -> Ensemble v n

-- | Compute the total kinetic energy of an ensemble.
kineticEnergy :: (Metric v, Num n) => Ensemble v n -> n
instance GHC.Real.Fractional n => Data.Default.Class.Default (Physics.ForceLayout.ForceLayoutOpts n)
instance GHC.Classes.Eq (v n) => GHC.Classes.Eq (Physics.ForceLayout.Particle v n)
