如何编写函数将画布上的点映射到实际平面上的点

1 投票
3 回答
1287 浏览
提问于 2025-04-17 09:17

我正在用Python写一个简单的Mandelbrot可视化程序,显示在pygame的屏幕上。对于600乘600的屏幕上的每一个像素,我都在判断这个像素(x, y)作为一个复数,是否属于Mandelbrot集合。

问题是,我从(0, 0)开始,遍历到(600, 600),而大部分区域其实都不在这个集合里。所以我加了一个缩放因子来放大,但我现在只是在绘制右上角的部分。我想找到一种方法,让我的绘图总是围绕0+0i这个点居中。

我想做的是找到一种方法,把这个600平方像素的画布映射到实际的坐标平面上,x轴的范围是[-2, 2],y轴的范围是[2, -2]。这样的话,比如复数0+0i就会映射到屏幕上的(300, 300)这个位置。这样,我的绘图就总是能保持居中。

3 个回答

1

其实我会采取一种更灵活的方法,写代码时让它支持比较随意的映射。不过如果你想要严格按照你的要求来做,可以试试下面的代码:

x = (float(pix_x) + 0.5 - 300.0) / 150.0

然后对 y 也做同样的处理。这段代码把每个像素看作是屏幕上那对点的中心,但把像素的角落映射到 (+-2, +-2) 的位置。这是把整个视口映射到复平面上一个正方形的最“正确”的方法。不过这样做的一个缺点是,你可能会错过一些重要的数字,比如0、实数线或者虚数线。

1
class Mapper:
    def __init__(self, old_ul, old_lr, new_ul, new_lr):
        self.old_ul = old_ul
        self.old_lr = old_lr
        self.new_ul = new_ul
        self.new_lr = new_lr
        self.old_diff = Point(old_lr.x - old_ul.x,
                              old_ul.y - old_lr.y)
        self.new_diff = Point(new_lr.x - new_ul.x,
                              new_ul.y - new_lr.y)

    def map(self, pt):
        nx = (self.old_lr.x+pt.x) * (self.new_diff.x / self.old_diff.x) + self.new_ul.x
        ny = (self.old_ul.y+pt.y) * (self.new_diff.y / self.old_diff.y) + self.new_lr.y
        return Point(nx, ny)
def main(args):
    pixelToReal = Mapper(Point(0, 0), Point(600, 600), Point(-2, 2), Point(2, -2))
    realToPixel = Mapper(Point(-2, 2), Point(2, -2), Point(0, 0), Point(600, 600))
    print(pixelToReal.map(Point(300,300))) # prints 0.0,0.0
    print(realToPixel.map(pixelToReal.map(Point(300,300)))) # prints 300,300
    for x in range(0,630, 30):
        for y in range(0,630, 30):
            print(pixelToReal.map(Point(x,y)))

Mapper的构造函数需要四个参数:原始的左上角和右下角坐标,以及新的左上角和右下角坐标。Mapper.map()这个方法的作用是把一个点从原来的空间转换到新的空间里。

2

你想为你的数据创建一个窗口。这个窗口的宽度是600像素,高度也是600像素。像素坐标的范围是(0, 0)到(600, 600)。你可以这样做:

Point coordFromPixelLocation (pixelX, pixelY, pixelWidth, pixelHeight, minCoordX, maxCoordX, minCoordY, maxCoordY)
{
    xPercent = pixelX / pixelWidth;
    yPercent = pixelY / pixelHeight;

    newX = minCoordX + (maxCoordX - minCoordX) * xPercent;
    newY = minCoordY + (maxCoordY - minCoordY) * yPercent;

    return Point (newX, newY);
}

这里的pixelX和pixelY是你想要转换到更小范围的像素坐标。pixelWidth和pixelHeight分别是你窗口的宽度和高度。minCoordX/Y和maxCoordX/Y是从(-2,-2)到(2,2)的值。

撰写回答