packages feed

hevolisa (empty) → 0.0

raw patch · 13 files changed

+672/−0 lines, 13 filesdep +basedep +bytestringdep +cairosetup-changedbinary-added

Dependencies added: base, bytestring, cairo, filepath, haskell98

Files

+ Hevolisa.hs view
@@ -0,0 +1,15 @@+--
+-- Module      : Hevolisa
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Main where
+
+import Hevolisa.Evolution (start)
+
+
+main :: IO ()
+main = start "mona_lisa_crop.png" >> return ()
+ Hevolisa/Evolution.hs view
@@ -0,0 +1,63 @@+--
+-- Module      : Evolution
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Evolution where
+
+import Prelude hiding (error)
+import Hevolisa.Shapes.DnaDrawing
+import Hevolisa.Tools
+import Hevolisa.Renderer ( drawingError,drawingToFile,withImageFromPNG)
+import Debug.Trace
+
+-- |Context contains the current drawing and the source image for comparison
+data EvolutionContext = EvolutionContext {
+      drawing :: DnaDrawing,
+      image   :: [Integer]
+} deriving (Show, Eq)
+
+type Error = Integer
+
+-- |Init the context with image and initial drawing
+initContext :: [Integer]  -> IO EvolutionContext
+initContext image = randomInit >>= \drawing ->
+                    return $ EvolutionContext drawing image
+
+-- |Number of mutations between image writes
+imageInterval = 100
+
+-- |Start the evolution process
+start :: FilePath -> IO (EvolutionContext,Error)
+start fp = do c <- withImageFromPNG fp initContext 
+              e <- error c
+              iter 0 (c,e)
+
+-- |Recursive function combines mutation and writing files
+iter :: Int -> (EvolutionContext,Error) -> IO (EvolutionContext,Error)
+iter n (c1,e1) = do trace (show e1) $ maybeWriteToFile c1
+                    c2 <- mutate c1
+                    e2 <- error c2
+                    iter (n + 1) $ minError (c1,e1)(c2,e2)
+    where maybeWriteToFile
+              | isTimeToWrite = \ec -> drawingToFile (drawing ec) n >> return ec
+              | otherwise     = return
+          isTimeToWrite = n `mod` imageInterval == 0
+          minError (c1,e1)(c2,e2) | e1 < e2   = (c1,e1)
+                                  | otherwise = (c2,e2)
+
+-- |Color error, smaller is better
+error :: EvolutionContext -> IO Integer
+error (EvolutionContext drawing source) = drawingError drawing source
+
+-- |EvolutionContext mutates minimizing the error
+instance Mutable EvolutionContext where
+    mutate = mutateEvolutionContext
+
+-- |Mutate the drawing in the EvolutionContext
+mutateEvolutionContext :: EvolutionContext -> IO EvolutionContext
+mutateEvolutionContext (EvolutionContext d s) = do m <- mutate d
+                                                   return (EvolutionContext m s)
+ Hevolisa/Renderer.hs view
@@ -0,0 +1,96 @@+--+-- Module      : Renderer+-- Copyright   : (c) Daniel Neun 2008+-- License     : BSD-style+-- Maintainer  : daniel.neun@gmx.de+-- Stability   : experimental+-- Portability : portable++module Hevolisa.Renderer (drawingError,+                          withImageFromPNG,+                          drawingToFile) +where++import System.FilePath ((</>),(<.>))+import Control.Monad+import Data.ByteString (unpack)+import Directory+import qualified Graphics.Rendering.Cairo as C+import Hevolisa.Shapes.DnaDrawing+import Hevolisa.Shapes.DnaPolygon+import qualified Hevolisa.Shapes.DnaBrush as B+import Hevolisa.Shapes.DnaPoint+import qualified Hevolisa.Settings as S++-- | Render the shapes with cairo+class Renderable a where+    render :: a -> C.Render ()++instance Renderable DnaPoint where+    render (DnaPoint x y) = C.lineTo x y++instance Renderable DnaPolygon where+    render p = do+      render $ brush p+      render $ points p+      C.fill++instance Renderable B.DnaBrush where+    render br = C.setSourceRGBA r g b a+        where r = normalize $ B.red br+              g = normalize $ B.green br+              b = normalize $ B.blue br+              a = normalize $ B.alpha br+              normalize = (/255) . fromIntegral++instance Renderable DnaDrawing where+    render = render . polygons++instance (Renderable a) => Renderable [a] where+    render = mapM_ render+++-- | 1. Rasterize the drawing+-- 2. Compare the color values of the drawing and the image pixel by pixel+drawingError :: DnaDrawing -- ^ the drawing is rasterized+             -> [Integer]  -- ^ color values of the image+             -> IO Integer -- ^ return the color pixel error+drawingError drawing image = toSurface (render drawing) >>= +                             unpackSurface >>= +                             return . error image+    where+      error :: [Integer] -> [Integer] -> Integer+      error c1 c2 = sum $ zipWith (\x y -> (x - y)^2) c1 c2+                          +      toSurface :: C.Render () -> IO C.Surface+      toSurface r = do surface <- C.createImageSurface C.FormatRGB24 width height+                       C.renderWith surface r+                       return surface++-- | Extract the color values to compute the error+unpackSurface :: C.Surface -> IO [Integer]+unpackSurface s = C.imageSurfaceGetData s >>=+                  return . removeAlpha . map fromIntegral . unpack+    where+      -- remove the alpha channel+      removeAlpha :: [a] -> [a]+      removeAlpha []           = []+      removeAlpha (r:g:b:a:xs) = r:g:b:removeAlpha xs+      removeAlpha _            = Prelude.error "wrong number of color values"++-- | Open an image file and apply the function+withImageFromPNG :: FilePath -> ([Integer] -> IO a) -> IO a+withImageFromPNG fp f = C.withImageSurfaceFromPNG fp unpackSurface >>= f+                 +-- | Rasterize the drawing and save it to a file+drawingToFile :: DnaDrawing -> Int -> IO ()+drawingToFile d n = C.withImageSurface C.FormatRGB24 width height $ \surface -> do+                      C.renderWith surface $ render d+                      dirExists <- doesDirectoryExist subdir+                      unless dirExists $ createDirectory subdir+                      C.surfaceWriteToPNG surface filePath+    where filePath = subdir </> show n <.> "png"+          subdir = "images"++height = truncate S.maxHeight :: Int+width  = truncate S.maxWidth  :: Int
+ Hevolisa/Settings.hs view
@@ -0,0 +1,43 @@+--
+-- Module      : Settings
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Settings where
+
+activeAddPointMutationRate = 1500
+activeAddPolygonMutationRate = 700
+activeAlphaMutationRate = 1500
+activeAlphaRangeMax = 60
+activeAlphaRangeMin = 30
+activeBlueMutationRate = 1500
+activeBlueRangeMax = 255
+activeBlueRangeMin = 0
+activeGreenMutationRate = 1500
+activeGreenRangeMax = 255
+activeGreenRangeMin = 0
+activeMovePointMaxMutationRate = 1500
+activeMovePointMidMutationRate = 1500
+activeMovePointMinMutationRate = 1500
+
+activeMovePointRangeMid = 20.0
+activeMovePointRangeMin = 3.0
+activeMovePolygonMutationRate = 700
+--activePointsMax = 1500
+--activePointsMin = 0
+activePointsPerPolygonMax = 10
+activePointsPerPolygonMin = 3
+activePolygonsMax = 255
+activePolygonsMin = 0
+activeRedMutationRate = 1500
+activeRedRangeMax = 255
+activeRedRangeMin = 0
+activeRemovePointMutationRate = 1500
+activeRemovePolygonMutationRate = 1500
+--addPointMutationRate = 1500
+
+maxWidth = 200.0
+maxHeight = 200.0
+ Hevolisa/Shapes/DnaBrush.hs view
@@ -0,0 +1,57 @@+--
+-- Module      : DnaBrush
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Shapes.DnaBrush (
+                 DnaBrush,
+                         
+                 -- * Accessors
+                 red, green, blue, alpha
+) where
+
+import Hevolisa.Settings
+import Hevolisa.Tools
+
+-- |Brush to color polygons
+data DnaBrush = DnaBrush {
+      red   :: Integer,
+      green :: Integer,
+      blue  :: Integer,
+      alpha :: Integer 
+} deriving (Show,Eq,Read)
+
+-- |Brush is mutable
+instance Mutable DnaBrush where
+    mutate = mutateBrush
+
+-- |Initialize brush with random garbage
+instance RandomInit DnaBrush where
+    randomInit = do r <- getRandomNumber 0 255
+                    g <- getRandomNumber 0 255
+                    b <- getRandomNumber 0 255
+                    a <- getRandomNumber 10 60
+                    return (DnaBrush r g b a)
+
+-- |Change the brush values in a semi random way, rates can be adjusted
+mutateBrush :: DnaBrush -> IO DnaBrush
+mutateBrush (DnaBrush r g b a) = do r <- maybeMutate_ r activeRedMutationRate 
+                                         activeRedRangeMin activeRedRangeMax
+                                    g <- maybeMutate_ g activeGreenMutationRate 
+                                         activeGreenRangeMin activeGreenRangeMax
+                                    b <- maybeMutate_ b activeBlueMutationRate 
+                                         activeBlueRangeMin activeBlueRangeMax
+                                    a <- maybeMutate_ a activeAlphaMutationRate 
+                                         activeAlphaRangeMin activeAlphaRangeMax
+                                    return (DnaBrush r g b a)
+    where
+      -- |Mutate a one-dimensional value
+      maybeMutate_ :: Integer    -- ^ The unchanged value to pass through
+                   -> Integer    -- ^ Mutation rate
+                   -> Integer    -- ^ Minimum for random numbers
+                   -> Integer    -- ^ Maximum for random numbers
+                   -> IO Integer -- ^ Changed value
+      maybeMutate_ unchanged rate min max = maybeMutate rate (getRandomNumber min max) unchanged
+ Hevolisa/Shapes/DnaDrawing.hs view
@@ -0,0 +1,94 @@+--
+-- Module      : DnaDrawing
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Shapes.DnaDrawing ( DnaDrawing,
+                                    -- * Accessors
+                                    polygons
+) where
+
+import Hevolisa.Shapes.DnaPolygon ( DnaPolygon )
+import Hevolisa.Tools
+import Hevolisa.Settings
+
+-- |A drawing contains an ordered set of polygons
+data DnaDrawing = DnaDrawing {
+      polygons :: [DnaPolygon] 
+} deriving (Show,Eq,Read)
+
+
+-- |Count the points in the drawing
+instance Points DnaDrawing where
+    pointCount = sum . map pointCount . polygons
+
+-- |Construct and init a new Drawing
+instance RandomInit DnaDrawing where
+    randomInit = mseq (replicate min addPolygon) >>= return . DnaDrawing
+        where min = fromIntegral activePolygonsMin
+              mseq = foldl (>>=) (return [])
+
+-- |Add a new polygon at a random position
+addPolygon :: [DnaPolygon] -> IO [DnaPolygon]
+addPolygon ps = do random <- getRandomNumber 0 (length ps)
+                   polygon <- randomInit
+                   return (addElem polygon random ps)
+
+-- |Drawing has mutable DNA
+instance Mutable DnaDrawing where
+    mutate old = mutateDrawing old >>= change
+        where change new | old == new = mutate old
+                         | otherwise  = return new
+
+-- |Basic drawing mutation function
+mutateDrawing :: DnaDrawing -> IO DnaDrawing
+mutateDrawing d = maybeAddPolygon d >>= 
+                  maybeRemovePolygon >>= 
+                  maybeMovePolygon >>= 
+                  mutatePolygons
+    where
+      -- |Add a polygon if it`s time to do so and the constraints are met
+      maybeAddPolygon :: DnaDrawing -> IO DnaDrawing
+      maybeAddPolygon d = willMutate  activeAddPolygonMutationRate >>=
+                          when (polygonsCount d < activePolygonsMax)
+                               (applyToPolygons addPolygon) d
+                    
+      -- |Remove a polygon if it`s time to do so and the constraints are met
+      maybeRemovePolygon :: DnaDrawing -> IO DnaDrawing
+      maybeRemovePolygon d = willMutate activeRemovePolygonMutationRate >>=
+                             when (polygonsCount d > activePolygonsMin)
+                                  (applyToPolygons removePolygon) d
+
+      -- |Remove a polygon at a random index
+      removePolygon :: [DnaPolygon] -> IO [DnaPolygon]
+      removePolygon p = do index <- getRandomNumber 0 (length p - 1)
+                           return (removeElem index p)
+
+      -- |Move a polygon if it`s time to do so and the constraints are met
+      maybeMovePolygon :: DnaDrawing -> IO DnaDrawing
+      maybeMovePolygon d = willMutate activeMovePolygonMutationRate >>=
+                           when (polygonsCount d > 0)
+                                (applyToPolygons movePolygon) d
+
+      -- |Move a polygon in the list of polygons
+      movePolygon :: [DnaPolygon] -> IO [DnaPolygon]
+      movePolygon p = do from <- getRandomNumber 0 (length p - 1)
+                         to   <- getRandomNumber 0 (length p - 1)
+                         return (moveElem from to p)
+
+      -- |Mutate polygons if it`s time to do so and the constraints are met
+      mutatePolygons :: DnaDrawing -> IO DnaDrawing
+      mutatePolygons = applyToPolygons (mapM mutate)
+
+      -- |Apply a polygon function to a drawing
+      applyToPolygons :: ([DnaPolygon] -> IO [DnaPolygon])
+                      -> DnaDrawing
+                      -> IO DnaDrawing
+      applyToPolygons f d = f (polygons d) >>= return . DnaDrawing
+
+      -- |Get the number of polygons of a drawing to check constraints
+      polygonsCount :: Integral a => DnaDrawing -> a
+      polygonsCount = fromIntegral . length . polygons
+ Hevolisa/Shapes/DnaPoint.hs view
@@ -0,0 +1,76 @@+--
+-- Module      : DnaPoint
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Shapes.DnaPoint (
+                 DnaPoint (DnaPoint),
+
+                 -- * Accessors
+                 pointX,
+                 pointY,
+
+                 -- * Constructors, mutate
+                 randomPoint
+                ) where
+
+import Hevolisa.Settings
+import Hevolisa.Tools
+
+-- |Mutable Point
+data DnaPoint = DnaPoint {
+      pointX :: Double,
+      pointY :: Double 
+} deriving (Show,Eq,Read)
+
+-- |DnaPoint is mutable
+instance Mutable DnaPoint where
+    mutate = mutatePoint
+
+-- |Initialize point with random garbage
+instance RandomInit DnaPoint where
+    randomInit = do x <- getRandomNumber 0.0 maxWidth
+                    y <- getRandomNumber 0.0 maxHeight
+                    return (DnaPoint x y)
+
+-- |Mutate points dna randomly, rates can be adjusted
+mutatePoint :: DnaPoint -> IO DnaPoint
+mutatePoint p = mutateMax p >>= mutateMid >>= mutateMin
+    where mutateMax   = maybeMutate activeMovePointMaxMutationRate randomInit
+          mutateMid p = maybeMutate activeMovePointMidMutationRate 
+                        (pointFunction midX midY p) p
+          mutateMin p = maybeMutate activeMovePointMinMutationRate 
+                        (pointFunction minX minY p) p
+
+          -- |Change the x and y values of the point with functions
+          pointFunction :: (Double -> IO Double) -- ^ Function to change the x value
+                        -> (Double -> IO Double) -- ^ Function to change the y value
+                        -> DnaPoint              -- ^ Original point
+                        -> IO DnaPoint           -- ^ Changed point (action)
+          pointFunction fx fy p = do x <- fx $ pointX p
+                                     y <- fy $ pointY p
+                                     return (DnaPoint x y)
+
+          -- |Helper functions for different ranges
+          midX, midY, minX, minY :: Double -> IO Double
+          midX = mutateDim activeMovePointRangeMid maxWidth
+          midY = mutateDim activeMovePointRangeMid maxHeight
+          minX = mutateDim activeMovePointRangeMin maxWidth
+          minY = mutateDim activeMovePointRangeMin maxHeight
+
+-- |Mutate a one-dimensional value
+mutateDim :: Double    -- ^ Randomisation range
+          -> Double    -- ^ Maximum
+          -> Double    -- ^ Original value
+          -> IO Double -- ^ New value (action)
+mutateDim range maxn n = getRandomNumber (-range) range >>=
+                         return . min maxn . max 0 . (+ n)
+
+-- |Create a random point using another point
+randomPoint :: DnaPoint -> IO DnaPoint
+randomPoint (DnaPoint x y) = do x <- mutateDim 3 maxWidth x
+                                y <- mutateDim 3 maxHeight y
+                                return (DnaPoint x y)
+ Hevolisa/Shapes/DnaPolygon.hs view
@@ -0,0 +1,97 @@+--+-- Module      : DnaPolygon+-- Copyright   : (c) Daniel Neun 2008+-- License     : BSD-style+-- Maintainer  : daniel.neun@gmx.de+-- Stability   : experimental+-- Portability : portable++module Hevolisa.Shapes.DnaPolygon (+                   DnaPolygon,++                   -- * Accessors+                   brush,+                   points+                  ) where++import Control.Monad ( replicateM )+import Hevolisa.Settings+import Hevolisa.Tools+import Hevolisa.Shapes.DnaBrush ( DnaBrush )+import Hevolisa.Shapes.DnaPoint ( DnaPoint( DnaPoint ), randomPoint, pointX, pointY )++-- |A polygon has a brush for color and a list of points+data DnaPolygon = DnaPolygon {+      brush  :: DnaBrush, +      points :: [DnaPoint] +} deriving (Show,Eq,Read)++-- |Count the points of the polygon+instance Points DnaPolygon where+    pointCount = fromIntegral . length . points++-- |Initialize the polygon with random garbage+instance RandomInit DnaPolygon where+    randomInit = do points <- randomPoints activePointsPerPolygonMin+                    brush <- randomInit+                    return (DnaPolygon brush points)+        where randomPoints :: Integer -> IO [DnaPoint]+              randomPoints n = randomInit >>=+                               replicateM (fromIntegral n) . randomPoint++-- |A polygon has mutable DNA+instance Mutable DnaPolygon where+    mutate = mutatePolygon++-- |Mutate a polygon by adding and removing points and other funny tricks+mutatePolygon :: DnaPolygon -> IO DnaPolygon+mutatePolygon p = maybeAddPoint p >>= +                  maybeRemovePoint >>= +                  mutateBrush >>= +                  mutatePoints+    where+      -- |Add a point if it`s time to do so+      maybeAddPoint :: DnaPolygon -> IO DnaPolygon+      maybeAddPoint p = willMutate activeAddPointMutationRate >>=+                        when (pointCount p < activePointsPerPolygonMax)+                             addPointAtRandomIndex p++      -- |Add a point at a random position between two points+      addPointAtRandomIndex :: DnaPolygon -> IO DnaPolygon+      addPointAtRandomIndex p = do index <- getRandomNumber 1 (pointCount p - 1)+                                   return (p { points = addPoint index (points p) })++      -- |Add a point at the given position+      addPoint :: Int -> [DnaPoint] -> [DnaPoint]+      addPoint index pts = left ++ [DnaPoint newX newY] ++ right+          where left = take index pts+                right = drop index pts+                newX = (pointX prev + pointX next) / 2+                newY = (pointY prev + pointY next) / 2+                prev = last left+                next = head right++      -- |Remove a point if it`s time to do so+      maybeRemovePoint :: DnaPolygon -> IO DnaPolygon+      maybeRemovePoint p = willMutate activeRemovePointMutationRate >>=+                           when (pointCount p > activePointsPerPolygonMin)+                                removePointAtRandomIndex p++      -- |Remove a random point+      removePointAtRandomIndex :: DnaPolygon -> IO DnaPolygon+      removePointAtRandomIndex p@(DnaPolygon b pts) = do +        index <- getRandomNumber 0 (pointCount p)+        return (DnaPolygon b (removePoint index pts))++      -- |Remove a point from the polygon+      removePoint :: Int -> [DnaPoint] -> [DnaPoint]+      removePoint = removeElem++      -- |Mutate the polygon brush+      mutateBrush :: DnaPolygon -> IO DnaPolygon+      mutateBrush (DnaPolygon brush pts) = mutate brush >>= \b -> return (DnaPolygon b pts)++      -- |Mutate the polygon points+      mutatePoints :: DnaPolygon -> IO DnaPolygon+      mutatePoints p = (mapM mutate . points) p >>= +                       return . DnaPolygon (brush p)
+ Hevolisa/Tools.hs view
@@ -0,0 +1,100 @@+--
+-- Module      : Tools
+-- Copyright   : (c) Daniel Neun 2008
+-- License     : BSD-style
+-- Maintainer  : daniel.neun@gmx.de
+-- Stability   : experimental
+-- Portability : portable
+
+module Hevolisa.Tools (
+              -- * Classes
+              Mutable (mutate),
+              Points (pointCount),
+              RandomInit (randomInit),
+
+              -- * Utility functions
+              when,
+              willMutate,
+              maybeMutate,
+              getRandomNumber,
+
+              -- * List index functions
+              addElem,
+              removeElem,
+              moveElem
+) where
+
+import Random
+
+-- |Instances of Mutable can mutate their DNA
+class Mutable a where
+    -- |Perform a genetic mutation in a random way
+    mutate :: a -> IO a
+
+-- |Count the points
+class Points a where
+    -- |Count the points
+    pointCount :: (Integral b) => a -> b
+
+-- |Initialize a shape with random values
+class RandomInit a where
+    -- |Action that returns a shape with random values
+    randomInit :: IO a
+
+-- |Decide whether it`s time for a mutation
+willMutate :: Integer  -- ^ Mutation rate 
+           -> IO Bool  -- ^ True: Mutate
+willMutate mutationRate = do k <- getRandomNumber 0 mutationRate
+                             return (k == 1)
+
+-- |Get a random number between min and max
+getRandomNumber :: Random a => 
+                   a     -- ^ Minimum
+                -> a     -- ^ Maximum
+                -> IO a  -- ^ Random number action
+getRandomNumber x y = getStdRandom (randomR (x,y))
+
+-- |Helper function to get rid of if-then-else
+when :: Bool        -- ^ constraint
+     -> (a -> IO a) -- ^ function
+     -> a           -- ^ unchaged value to pass through
+     -> Bool        -- ^ mutate?
+     -> IO a        -- ^ result action
+when constraint f = flip (awhen constraint f)
+    where awhen :: Bool -> (a -> IO a) -> Bool -> (a -> IO a)
+          awhen constraint f mutate | mutate && constraint = f
+                                    | otherwise            = return
+
+-- |Perform a mutation action when it`s time to do so
+maybeMutate :: Integer  -- ^ Mutation rate
+            -> IO a     -- ^ Mutation action
+            -> a        -- ^ Unchanged value to pass through
+            -> IO a     -- ^ Composed action
+maybeMutate rate action unchanged = do mutate <- willMutate rate
+                                       if mutate then action else return unchanged
+
+-- |Move a list element from index to index
+moveElem :: Int -- ^ from index
+         -> Int -- ^ to index
+         -> [a] -- ^ original list 
+         -> [a] -- ^ result
+moveElem from to lst = addElem elem to $ removeElem from lst
+    where elem = lst !! from
+
+
+-- |Remove an item at index position from list
+removeElem :: Int -- ^ index
+           -> [a] -- ^ original list
+           -> [a] -- ^ result
+removeElem n lst = left ++ right
+    where left = take n lst
+          right = drop (n + 1) lst
+
+-- |Add an item at index position to list
+addElem :: a   -- ^ element
+        -> Int -- ^ index
+        -> [a] -- ^ original list
+        -> [a] -- ^ result
+addElem item index lst = left ++ [item] ++ right
+    where left = take index lst
+          right = drop index lst
+ LICENSE view
+ Setup.hs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell
+
+import Distribution.Simple
+main = defaultMain
+ hevolisa.cabal view
@@ -0,0 +1,27 @@+Name:		hevolisa
+Version:	0.0
+Cabal-Version:	>= 1.2
+License:	BSD3
+License-file:	LICENSE
+Author:		Daniel Neun
+Maintainer:	daniel.neun@gmx.de
+Category:       Graphics
+Synopsis:	Genetic Mona Lisa problem in Haskell
+Description:	Hevolisa is an application that tries to approximate a bitmap image with colored polygons. It draws a set of random polygons which are changed/mutated in small random steps. There is an error function which compares the bitmap created from the polygons with the original image. If the error between the images is smaller than before then the new image replaces the old. This is done over and over again.
+Build-Depends:	base >= 3.0.3.0, haskell98 >= 1.0.1.0, cairo >= 0.9.13, bytestring >= 0.9.1.4, filepath >= 1.1.0.1
+Build-Type:	Simple
+Extra-Source-Files:
+	Hevolisa/Shapes/DnaBrush.hs
+	Hevolisa/Shapes/DnaDrawing.hs
+	Hevolisa/Shapes/DnaPoint.hs
+	Hevolisa/Shapes/DnaPolygon.hs
+	Hevolisa/Evolution.hs
+	Hevolisa/Renderer.hs
+	Hevolisa/Settings.hs
+	Hevolisa/Tools.hs
+Data-Files:
+	mona_lisa_crop.png
+
+Executable:	hevolisa
+Main-is:	Hevolisa.hs
+ghc-options:
+ mona_lisa_crop.png view

binary file changed (absent → 63788 bytes)