-- | 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