Haskell & Gtk : how to draw points as soon as they

2019-07-19 17:12发布

问题:

I created a working program displaying the Mandelbrot set, but the whole set is displayed after all is computed; I wonder which changes of the code I must do in order to have a points displayed as soon as it's known if it belongs to the set or not.

Here is my program; the beginning is not very important, it's more or less common to all programs using Gtk:

module Main where

import           Control.Monad            (when)
import           Graphics.Rendering.Cairo as C
import           Graphics.UI.Gtk
import           Graphics.UI.Gtk.Builder  ()


main :: IO()
main = do
    _ <- initGUI

    window <- windowNew
    windowSetPosition window WinPosCenter
    windowSetDefaultSize window 500 350
    set window [windowTitle := "Ensemble de Mandelbrot"]
    on window objectDestroy mainQuit

    canvas <- drawingAreaNew
    canvas `on` sizeRequest $ return (Requisition 450 300)
    window `containerAdd` canvas

    _ <- onExpose canvas $ const (updateCanvas canvas)

    widgetShowAll window
    mainGUI


updateCanvas :: DrawingArea -> IO Bool
updateCanvas canvas = do
  win <- widgetGetDrawWindow canvas
  (width, height) <- widgetGetSize canvas
  _ <- mapM_ (affiche win)  (points (fromIntegral width) (fromIntegral height))

  return True

k :: Int
k=100 -- 100 : after launching, u must wait less than 10s

mandelbrot :: Double -> Double -> Bool
mandelbrot a b =
  let
    mandelrec :: Double -> Double -> Int -> Bool
    mandelrec x y i
      | (x * x + y * y > 4) = False
      | (i==k) && (x * x + y * y <= 4) = True
      | otherwise = mandelrec x' y' (i+1)
            where x' = x * x - y * y + a
                  y' = 2 * x * y + b
  in mandelrec 0 0 0

affiche2 :: DrawWindow -> Double -> Double -> IO()
affiche2 win a b = renderWithDrawable win $ do
    setSourceRGB 0 0 0
    setLineWidth 1
    C.rectangle a b 1 1 
    stroke


affiche :: DrawWindow -> ((Double,Double), (Double,Double)) -> IO ()
affiche win ((a0,a), (b0,b)) = when (mandelbrot a b) $ postGUIAsync (affiche2 win a0 b0)

colonnes :: Double -> [(Double, Double)]
colonnes w = [ (t,t/w*4-2) | t<-[0..(w-1)] ]

lignes :: Double -> [(Double, Double)]
lignes h = [ (t,t/h*4-2) | t<-[0..(h-1)] ]

points :: Double -> Double -> [((Double, Double), (Double, Double))]
points w h = [ (colonne,ligne)| colonne <- colonnes w,ligne <- lignes h]