Таким образом, я просто записал немного отрывка, чтобы генерировать фрактал Mandelbrot и вообразить мое удивление, когда это вышло все ужасные и скошенные (как Вы видите внизу). Я ценил бы точку в направлении того, почему это даже произойдет. Это - полезный опыт, и я не ищу никого, чтобы сделать это для меня, но я отчасти в тупике, отлаживающем его. Незаконный код поколения:
module Mandelbrot where
import Complex
import Image
main = writeFile "mb.ppm" $ imageMB 1000
mandelbrotPixel x y = mb (x:+y) (0:+0) 0
mb c x iter | magnitude x > 2 = iter
| iter >= 255 = 255
| otherwise = mb c (c+q^2) (iter+1)
where q = x -- Mandelbrot
-- q = (abs.realPart $ x) :+ (abs.imagPart $ x) --Burning Ship
argandPlane x0 x1 y0 y1 width height = [ (x,y) |
y <- [y1, y1 - dy .. y0], --traverse from
x <- [x0, x0 + dx .. x1] ] --top-left to bottom-right
where dx = (x1 - x0) / width
dy = (y1 - y0) / height
drawPicture :: (a -> b -> c) -> (c -> Colour) -> [(a, b)] -> Image
drawPicture function colourFunction = map (colourFunction . uncurry function)
imageMB s = createPPM s s
$ drawPicture mandelbrotPixel (replicate 3)
$ argandPlane (-1.8) (-1.7) (0.02) 0.055 s' s'
where s' = fromIntegral s
И код изображения (в котором я довольно уверен):
module Image where
type Colour = [Int]
type Image = [Colour]
createPPM :: Int -> Int -> Image -> String
createPPM w h i = concat ["P3 ", show w, " ", show h, " 255\n",
unlines.map (unwords.map show) $ i]
Ну, изображение перекошено, потому что размеры неправильные, но это очевидно. Вы указываете размер изображения, а затем выплевываете список пикселей, но с неправильным количеством пикселей в строке.
Более конкретно, обратите внимание, что изображение оборачивается почти точно один раз: другими словами, перекос на строку * высота изображения = ширина изображения
. Поскольку изображение квадратное, это означает, что вы генерируете дополнительный пиксель на строку - старая добрая ошибка off-by-one.
Очевидное место, где это может произойти, это когда вы генерируете координаты для итерации. Давайте попробуем небольшой набор и посмотрим, что он нам даст:
> length $ argandPlane (-2.5) (-2) 1.5 2 10 10
121
> 10 ^ 2
100
> 11 ^ 2
121
И так. Я подозреваю, что ошибка связана с тем, что вы рассчитываете приращение как реальное расстояние, деленное на размер пикселя, что дает правильное количество интервалов, но лишнюю точку. Рассмотрим интервал от 0,0 до 1,0. Используя ваш расчет с шириной 4, мы получаем:
> let x0 = 0.0
> let x1 = 1.0
> let width = 4.0
> let dx = (x1 - x0) / width
> dx
0.25
> let xs = [x0, x0 + dx .. x1]
> xs
[0.0, 0.25, 0.5, 0.75, 1.0]
> length xs
5
Итак, чтобы получить правильное количество точек, просто уменьшите размер на 1 при генерации координат.
Это учебный опыт, и я не ищу никого, кто бы сделал это за меня, но я в тупике, отлаживая это
Я знаю, что camccann уже решил вашу проблему, но он как бы "дал вам рыбу", в то время как "научить вас ловить рыбу" могло бы быть более полезным.
Поэтому я поделюсь тем, что, по моему мнению, может быть полезным способом достижения решения.
Итак, ваше изображение Мандельброта перекошено. Некоторые возможные причины:
Вы можете провести эксперимент, чтобы узнать, релевантны ли какие-либо из вышеперечисленных объяснений или нет. Таким экспериментом может быть, например, рисование тривиальных изображений, скажем, горизонтальных и вертикальных линий.
Проделав этот эксперимент, вы увидите, что ваши вертикальные линии не такие уж вертикальные. Возвращаясь к вероятным возможным причинам, ясно, что у вас ошибка в представлении/сохранении изображения, и это все объясняет. Возможно, у вас все еще есть ошибка в формуле Мандельброта, но, скорее всего, нет, и это не имеет отношения к рассматриваемому вопросу.
Теперь вы должны подумать, какая ошибка сохранения изображения может привести к тому, что вертикальные линии будут диагональными. Если никакой идеи не возникнет, вы можете делать ваш простой пример все меньше и меньше, пока результат PPM не станет настолько мал, что вы сможете рассмотреть его вручную. Тогда вы наверняка поймаете ошибку.