6 votes

Équivalent fonctionnel de l'itération sur un tableau 2D

J'ai cette fonction en Haskell (j'utilise la bibliothèque Haskell-SDL) :

pixel :: Surface -> Int16 -> Int16 -> Pixel -> IO Bool

pixel screen x y color

Je veux l'utiliser pour prendre un tableau 2D (ou un autre type de structure de données) et le dessiner à l'écran, un pixel à la fois. J'ai cherché à le faire avec forM_ mais je n'arrive pas à trouver comment le faire fonctionner sur les arguments x et y.

Je suis assez novice en Haskell et en programmation fonctionnelle en général. Je suis en train de parcourir Yet Another Haskell Tutorial mais ce problème me laisse perplexe.

Au cas où cela serait pertinent pour la solution, j'essaie d'écrire un raytracer. Il doit effectuer un calcul pour chaque pixel, puis écrire ce pixel sur l'écran.

3voto

Jeremiah Willcock Points 14674

Si vous utilisez des listes imbriquées, faites-le :

import Control.Monad
plot :: Surface -> [[Pixel]] -> IO ()
plot surf = zipWithM_ (\ y -> zipWithM_ (\ x c -> pixel surf x y c) [0..]) [0..]

2voto

snk_kid Points 2234

Haskell dispose de tableaux réels de différents types. Il me semble que vous faites quelque chose d'assez inefficace, vous voulez créer un tampon de pixels et le fusionner avec un autre tampon ? Il serait beaucoup plus efficace de créer une nouvelle surface SDL (pour laquelle vous pouvez obtenir/régler des pixels) et de la fusionner avec une autre surface/écran ou de créer un vrai tableau de pixels et de créer une surface SDL avec celui-ci puis d'utiliser les routines de fusion de SDL. Si vous expliquez ce que vous essayez de faire, je pense que nous pouvons vous montrer une meilleure solution.

2voto

Paul Johnson Points 8604

Vous devez séparer deux problèmes ici. D'abord, vous devez calculer la valeur du pixel. Il doit s'agir d'une fonction pure de la scène et de la coordonnée du rayon que vous envoyez dans la scène. Ensuite, vous devez écrire cette valeur de pixel à l'écran.

Donc d'abord vous voulez une fonction :

type Coord = (Int, Int)

raytrace :: Scene -> Coord -> (Coord, Colour)  
    -- You will see why it returns this pair in a few lines

Vous voulez ensuite appeler cette fonction pour chaque pixel de votre surface, afin d'obtenir une liste de paires coordonnées-couleurs :

allCoords :: Int -> Int -> [Coord]
allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]]

allPixels :: Scene -> Int -> Int -> [(Coord, Colour)]
allPixels scene w h = map (raytrace scene) (allCoords w h)

Et enfin, mettez la liste des pixels sur la surface d'affichage en utilisant votre fonction "pixel".

writeScene :: Surface -> Scene -> Int -> Int -> IO ()
writeScene surface scene w h = mapM_ writePixel (allPixels scene w h)
    where writePixel ((x,y),c) = pixel surface x y c

Le seul problème est que votre fonction "pixel" renvoie un "IO Bool". Je ne sais pas pourquoi, alors je l'ai ignoré en utilisant "mapM_" plutôt que "mapM".

On a l'impression qu'il s'agit de construire une liste terriblement inefficace de paires coordonnées-couleurs, puis de la parcourir pour dessiner l'image. Mais en fait, grâce à la nature paresseuse de Haskell, elle se compile en une boucle qui génère chaque couleur et appelle ensuite "pixel" sur le résultat.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X