2011-02-11 7 views
6

Tengo esta función en Haskell (estoy usando la biblioteca de Haskell-SDL):equivalente funcional a la iteración en una matriz 2D

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

pixel screen x y color

quiero usar esto para tomar una Arreglo 2D (u otro tipo de estructura de datos) y dibujarlo en la pantalla, un píxel a la vez. Intenté hacerlo con forM_ pero no puedo encontrar la manera de hacerlo funcionar con los argumentos xey.

Soy bastante nuevo para Haskell y la programación funcional en general. Estoy trabajando en el tutorial de Yet Another Haskell, pero este problema me tiene perplejo.

En caso de que sea relevante para la solución, estoy tratando de escribir un raytracer. Tiene que realizar un cálculo para cada píxel y luego escribir ese píxel en la pantalla.

+0

¿Ya has descubierto cómo representar una matriz 2D en Haskell? – Gabe

+0

Creo que se podría hacer con listas anidadas, como por ejemplo: [[1,2,3], [4,5,6], [7,8,9]] –

+0

Haskell tiene arreglos adecuados de varios tipos, utilizando un lista anidada de píxeles no es una buena idea. Verifique mi respuesta a continuación. –

Respuesta

1

Tienes que dividir dos problemas aquí. Primero necesita calcular el valor de píxel. Esta debe ser una función pura de la escena y la coordenada del rayo que está disparando en ella. Entonces necesita escribir ese valor de píxel en la pantalla.

Así que primero quieren una función:

type Coord = (Int, Int) 

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

entonces usted quiere llamar a esa función para cada píxel de la superficie, para obtener una lista de pares de coordenadas de color:

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) 

Y finalmente coloque la lista de píxeles en la superficie de la pantalla con la función "píxel".

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 

Lo único es que su función "pixel" devuelve un "IO Bool". No sé por qué, así que lo ignoré usando "mapM_" en lugar de "mapM".

Esto parece que construye una lista terriblemente ineficiente de pares de coordenadas y color y luego lo itera para dibujar la imagen. Pero, de hecho, gracias a la naturaleza perezosa de Haskell, en realidad se compila en un ciclo que genera cada color y luego llama "pixel" al resultado.

3

Si está utilizando listas anidadas, hacer:

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

Haskell tiene matrices reales de diversos tipos. Para mí, parece que estás haciendo algo bastante ineficiente, ¿quieres crear un búfer de píxeles y ajustarlo a otro búfer? Sería mucho más eficiente crear una nueva superficie SDL (para lo cual puedes obtener/establecer píxeles) y combinarla con otra superficie/pantalla o crear una matriz real de píxeles y crear una superficie SDL con eso luego usar las rutinas blit de SDL. Si explica lo que está tratando de hacer, creo que podemos mostrarle una mejor manera.

+0

Estoy tratando de escribir un raytracer. Tiene que realizar un cálculo para cada píxel y luego escribir ese píxel en la pantalla. –

+1

@chuzzum Sugiero que lea/escriba en el búfer de la pantalla o que cree una superficie SDL vacía que es solo un búfer de píxeles (para el que puede manipular píxeles) y blit (blitSurface) esa superficie en el búfer posterior o crear un mutable unboxed array para el que tiene varias opciones como IOUArray, STUArray, StorableArray, Unboxed.MVector (http://hackage.haskell.org/package/vector) y luego copie los píxeles en el búfer posterior. SDL tiene una función que puede crear una superficie SDL a partir de una matriz y los enlaces de haskell exponen esto también. Usar una lista 2D de píxeles es una mala idea en realidad. –

+0

¿Hay una gran ventaja en el rendimiento al hacerlo? Dado que lo único que voy a hacer es iterar sobre él, no veo por qué una lista es peor o mejor que una matriz. ¿Cuál es la ventaja de usar una matriz mutable sobre listas inmutables, por ejemplo? Pero creo que escribir directamente en la pantalla es probablemente la mejor solución. –

Cuestiones relacionadas