使用F#绘制f(x)=x³-1牛顿分形仅显示右下1/4的技术求助
问题:F#绘制牛顿分形仅显示右下1/4区域
我最近在用F#实现函数f(x) = x³ - 1的牛顿分形绘制时,碰到了一个头疼的问题——程序跑起来后,窗体上只显示出了分形的右下1/4区域,剩下的左上、左下、右上三块全是空的。我反复核对了设置的复数平面范围,确认是覆盖整个需要展示的区域的,所以怀疑问题出在位图和窗体的坐标映射或者绘制逻辑上。
当前的效果如下:
牛顿分形仅显示右下区域
我目前写的代码片段是这样的:
open System open System.Drawing open System.Windows.Forms open System.Numerics let pi = 3.141592653...
可能的问题原因
这种只显示1/4区域的情况,我之前也碰到过几次,大多和坐标系转换错误脱不了干系:
- Windows窗体的像素坐标系原点在左上角,而我们计算分形的数学坐标系原点在中心,要是没把y轴翻转,或者坐标偏移计算错了,就会导致只有右下象限的点能映射到位图的有效像素范围内
- 计算像素位置时,可能只给x和y加了一半的偏移量,或者没处理负数坐标的转换,导致大部分点都跑到位图的“边界外”了
- 也有可能是创建位图或者绘制的时候,不小心限制了绘制区域,比如只画了右下的矩形块
解决方案思路
给你几个排查和修正的方向:
- 检查坐标映射逻辑:一定要把数学平面的点正确转成窗体像素。比如假设我们的复数平面范围是x∈[-2,2],y∈[-2,2],窗体宽高都是800,那转换应该是这样:
let toPixel (z: Complex) = let scale = float width / 4.0 let pixelX = int((z.Real + 2.0) * scale) // 把x从[-2,2]拉到[0,800] let pixelY = height - int((z.Imaginary + 2.0) * scale) // 翻转y轴,因为Windows像素y向下 (pixelX, pixelY) - 验证位图与绘制范围:确保创建的位图尺寸和窗体完全一致,绘制的时候没有限定区域。比如用
new Bitmap(width, height)创建全尺寸位图,然后用Graphics.DrawImage(bitmap, 0, 0)把整个位图画到窗体上 - 核对循环遍历范围:确认你遍历的x和y是覆盖整个复数平面的,别只遍历了正半轴的x和y,那样自然只会出右下区域
修正后的代码示例
我给你写了一段简化的修正版代码,你可以参考下:
open System open System.Drawing open System.Windows.Forms open System.Numerics let width = 800 let height = 800 let pi = Math.PI // 牛顿迭代:计算下一个迭代值 let newtonStep (z: Complex) = let f z = z * z * z - Complex.One let f' z = 3.0 * z * z z - (f z) / (f' z) // 判断收敛到哪个根 let getRootColor z = let tolerance = 1e-3 // 三个根:1,e^(2πi/3),e^(4πi/3) if Complex.Abs(z - Complex.One) < tolerance then Color.Red elif Complex.Abs(z - Complex.FromPolarCoordinates(1.0, 2.0*pi/3.0)) < tolerance then Color.Green elif Complex.Abs(z - Complex.FromPolarCoordinates(1.0, 4.0*pi/3.0)) < tolerance then Color.Blue else Color.Black [<EntryPoint>] let main _ = let bitmap = new Bitmap(width, height) let scale = float width / 4.0 // 对应x∈[-2,2],y∈[-2,2] // 遍历每个像素,计算对应的分形颜色 for xPixel in 0..width-1 do for yPixel in 0..height-1 do // 像素坐标转复数平面坐标(翻转y轴) let real = (float xPixel) / scale - 2.0 let imag = 2.0 - (float yPixel) / scale let mutable z = Complex(real, imag) // 迭代20次足够收敛 for _ in 1..20 do z <- newtonStep z // 设置像素颜色 bitmap.SetPixel(xPixel, yPixel, getRootColor z) // 创建窗体显示结果 let form = new Form(Width=width, Height=height, Text="牛顿分形") form.Paint.Add(fun e -> e.Graphics.DrawImage(bitmap, Point.Empty)) Application.Run(form) 0
你可以试试这段代码,应该能显示完整的分形图。核心就是把y轴的坐标翻转过来,确保整个复数平面的点都能映射到位图的有效像素范围内。
内容的提问来源于stack exchange,提问作者ComicSans
相关产品推荐
相关产品推荐

