-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Simple force-directed layout -- -- Simulation engine for doing simple force-based layout, e.g. for -- trees or graphs. See the diagrams-contrib package for usage examples. @package force-layout @version 0.2 -- | A simple, Haskell-native simulator for doing force-directed layout, -- e.g. of trees or graphs. -- -- To use, just create an Ensemble like so: -- --
-- import Physics.ForceLayout -- import qualified Data.Map as M -- import Data.AffineSpace.Point -- -- e :: Ensemble (Double, 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 <- [1..4], y <- [x+1..5]] -- particleMap = M.fromList . zip [1..] -- . map (initParticle . P) -- $ [ (2.0, 3.1), (6.3, 7.2) -- , (0.3, 4.2), (1.6, -1.1) -- , (4.8, 2.9) -- ] ---- -- Then run a simulation using either simulate (to get the list of -- all intermediate states) or forceLayout (to get only the ending -- state): -- --
-- e' :: Ensemble (Double, Double)
-- e' = forceLayout (FLOpts { damping = 0.8
-- , energyLimit = Just 0.001
-- , stepLimit = Nothing
-- }
-- )
-- e
--
--
-- See the diagrams-contrib package
-- (http://github.com/diagrams/diagrams-contrib/) for more
-- examples.
module Physics.ForceLayout
-- | A particle has a current position, current velocity, and current force
-- acting on it.
data Particle v
Particle :: Point v -> v -> v -> Particle v
_pos :: Particle v -> Point v
_vel :: Particle v -> v
_force :: Particle v -> v
pos :: Lens (Particle v_a4gP) (Particle v_a4gP) (Point v_a4gP) (Point v_a4gP)
vel :: Lens (Particle v_a4gP) (Particle v_a4gP) v_a4gP v_a4gP
force :: Lens (Particle v_a4gP) (Particle v_a4gP) v_a4gP v_a4gP
-- | Create an initial particle at rest at a particular location.
initParticle :: AdditiveGroup v => Point v -> Particle v
-- | Used to uniquely identify particles.
type PID = Int
-- | An edge is a pair of particle identifiers.
type Edge = (PID, PID)
-- | An Ensemble 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
Ensemble :: [([Edge], Point v -> Point v -> v)] -> Map PID (Particle v) -> Ensemble v
_forces :: Ensemble v -> [([Edge], Point v -> Point v -> v)]
_particles :: Ensemble v -> Map PID (Particle v)
forces :: Lens (Ensemble v_a5c9) (Ensemble v_a5c9) [([Edge], Point v_a5c9 -> Point v_a5c9 -> v_a5c9)] [([Edge], Point v_a5c9 -> Point v_a5c9 -> v_a5c9)]
particles :: Lens (Ensemble v_a5c9) (Ensemble v_a5c9) (Map PID (Particle v_a5c9)) (Map PID (Particle v_a5c9))
-- | hookeForce k l p1 p2 computes the force on p1,
-- assuming that p1 and p2 are connected by a spring
-- with equilibrium length l and spring constant k.
hookeForce :: (InnerSpace v, Floating (Scalar v)) => Scalar v -> Scalar v -> Point v -> Point v -> v
-- | coulombForce k computes the electrostatic repulsive force
-- between two charged particles, with constant of proportionality
-- k.
coulombForce :: (InnerSpace v, Floating (Scalar v)) => Scalar v -> Point v -> Point v -> v
-- | distForce f p1 p2 computes the force between two points as a
-- multiple of the unit vector in the direction from p1 to
-- p2, given a function f which computes the force's
-- magnitude as a function of the distance between the points.
distForce :: (InnerSpace v, Floating (Scalar v)) => (Scalar v -> Scalar v) -> Point v -> Point v -> v
-- | Options for customizing a simulation.
data ForceLayoutOpts v
FLOpts :: Scalar v -> Maybe (Scalar v) -> Maybe Int -> ForceLayoutOpts v
-- | Damping factor to be applied at each step. Should be between 0 and 1.
damping :: ForceLayoutOpts v -> Scalar v
-- | Kinetic energy below which simulation should stop. If
-- Nothing, pay no attention to kinetic energy.
energyLimit :: ForceLayoutOpts v -> Maybe (Scalar v)
-- | Maximum number of simulation steps. If Nothing, pay no
-- attention to the number of steps.
stepLimit :: ForceLayoutOpts v -> Maybe Int
-- | Simulate a starting ensemble according to the given options, producing
-- a list of all the intermediate ensembles. Useful for, e.g.,
-- making an animation. Note that the resulting list could be infinite,
-- if a stepLimit is not specified and either the kinetic energy
-- never falls below the specified threshold, or no energy threshold is
-- specified.
simulate :: (InnerSpace v, Ord (Scalar v), Num (Scalar v)) => ForceLayoutOpts v -> Ensemble v -> [Ensemble v]
-- | Run a simluation from a starting ensemble, yielding either the first
-- ensemble to have kinetic energy below the energyLimit (if
-- given), or the ensemble that results after a number of steps equal to
-- the stepLimit (if given), whichever comes first. Otherwise
-- forceLayout will not terminate.
forceLayout :: (InnerSpace v, Ord (Scalar v), Num (Scalar v)) => ForceLayoutOpts v -> Ensemble v -> Ensemble v
-- | Simulate one time step for an entire ensemble, with the given damping
-- factor.
ensembleStep :: VectorSpace v => Scalar v -> Ensemble v -> Ensemble v
-- | Simulate one time step for a particle (assuming the force acting on it
-- has already been computed), with the given damping factor.
particleStep :: VectorSpace v => Scalar v -> Particle v -> Particle v
-- | Recalculate all the forces acting in the next time step of an
-- ensemble.
recalcForces :: AdditiveGroup v => Ensemble v -> Ensemble v
-- | Compute the total kinetic energy of an ensemble.
kineticEnergy :: (InnerSpace v, Num (Scalar v)) => Ensemble v -> Scalar v
instance Eq v => Eq (Particle v)
instance Show v => Show (Particle v)