math-grads-0.1.5.1: src/Math/Grads/Drawing/Internal/Utils.hs
-- | Module that provides utility functions for whole Drawing module.
--
module Math.Grads.Drawing.Internal.Utils
( Coord
, CoordList
, randomVectors
, findIncidentCoords
, reflectCycle
, reflectBond
, centroid
, tupleToList
, compareCoords
, cleanListOfCoordLists
, cleanCoordList
, coordElem
, pairToV2
, uV2
) where
import Control.Arrow ((***))
import Data.List (unfoldr)
import Linear.V2 (V2 (..))
import Math.Grads.Algo.Interaction (isIncident)
import Math.Grads.Angem (reflectPoint)
import Math.Grads.Graph (GraphEdge)
import System.Random (StdGen, randomR)
-- | Alias for list of 'Coord's.
--
type CoordList e = [Coord e]
-- | 'Coord' is pair that containts graph's edge and coordinates of vertices that
-- are incident to it.
--
type Coord e = (GraphEdge e, (V2 Float, V2 Float))
-- | Generates vector of random 'Int's of given length.
--
randomVector :: Int -> StdGen -> ([Int], StdGen)
randomVector len gen = helper 0 ([], gen)
where
helper :: Int -> ([Int], StdGen) -> ([Int], StdGen)
helper currentLength (a, g) | currentLength < len = helper (currentLength + 1) (headA : a, newGen)
| otherwise = (a, g)
where
(headA, newGen) = randomR (0, 1) g
-- | Generates list of random vectors of length numberOfVectors.
-- Each vector has length lengthOfVector.
--
randomVectors :: StdGen -> Int -> Int -> [[Int]]
randomVectors gen lengthOfVector numberOfVectors = helper gen
where
helper = take numberOfVectors . unfoldr (Just . randomVector lengthOfVector)
-- | Find all 'Coord's in 'CoordList' that are incident to vertex with given index.
--
findIncidentCoords :: Int -> CoordList e -> CoordList e
findIncidentCoords ind = filter (flip isIncident ind . fst)
-- | Reflect given cycle in form of 'CoordList' over given axis.
--
reflectCycle :: CoordList e -> (V2 Float, V2 Float) -> CoordList e
reflectCycle thisCycle = (<$> thisCycle) . flip reflectBond
-- | Reflect given 'Coord' over given axis.
--
reflectBond :: Coord e -> (V2 Float, V2 Float) -> Coord e
reflectBond coord ends = fmap (reflectPoint ends *** reflectPoint ends) coord
-- | Calculates centroid of vertices in given 'CoordList'.
--
centroid :: CoordList e -> V2 Float
centroid coords' = sum coords / fromIntegral (length coords)
where
coords = snd <$> foldl (\x ((a, b, _), (coordA, coordB)) -> helper x (a, coordA) (b, coordB)) [] coords'
helper list (a, coordA') (b, coordB') | a `elem` fmap fst list && b `elem` fmap fst list = list
| a `elem` fmap fst list = (b, coordB') : list
| b `elem` fmap fst list = (a, coordA') : list
| otherwise = (a, coordA') : ((b, coordB') : list)
-- | Converts tuple to lis.
--
tupleToList :: (a, a) -> [a]
tupleToList (x, y) = [x, y]
-- | Converts 'V2' to pair.
--
uV2 :: V2 Float -> (Float, Float)
uV2 (V2 a b) = (a, b)
-- | Converts pair to 'V2'.
--
pairToV2 :: (Float, Float) -> V2 Float
pairToV2 (a, b) = V2 a b
-- | Given 'CoordList' of conjugated cycles leaves only cycles that don't intersect
-- with each other excluding first cycle in list that is taken by default.
--
cleanListOfCoordLists :: Eq e => [CoordList e] -> [CoordList e] -> [CoordList e]
cleanListOfCoordLists [] final = final
cleanListOfCoordLists (x : xs) [] = cleanListOfCoordLists xs [x]
cleanListOfCoordLists (x : xs) final = if any (\thisCycle -> any (`coordElem` thisCycle) x) xs then cleanListOfCoordLists xs final
else cleanListOfCoordLists xs (x : final)
-- | Leaves only unique 'Coord's in given 'CoordList'.
--
cleanCoordList :: Eq e => CoordList e -> CoordList e -> CoordList e
cleanCoordList [] coords = coords
cleanCoordList (x : xs) coords = if not (x `coordElem` coords) then cleanCoordList xs (x : coords)
else cleanCoordList xs coords
-- | Checks that 'Coord' is present in 'CoordList'.
--
coordElem :: Eq e => Coord e -> CoordList e -> Bool
coordElem coord = any (compareCoords coord)
-- | Comparator for 'Coord's.
--
compareCoords :: Eq e => Coord e -> Coord e -> Bool
compareCoords (a, _) (b, _) = a == b