0

我正在尝试使用generate_tiles.py创建图块,每次运行脚本时,都会出现以下错误:

线程 Thread-2 中的异常:回溯(最后一次调用):文件“/usr/lib/python2.7/threading.py”,第 552 行,在 __bootstrap_inner self.run() 文件“/usr/lib/python2. 7/threading.py”,第 505 行,运行中 self.__target(*self.__args, **self.__kwargs) 文件“render_tiles.py”,第 114 行,循环中 self.render_tile(tile_uri, x, y, z ) 文件“render_tiles.py”,第 96 行,在 render_tile mapnik.render(self.m, im) MemoryError

这是我的脚本。

#!/usr/bin/python
从数学导入 pi,cos,sin,log,exp,atan
从子流程导入调用
导入系统,操作系统
从队列导入队列
进口地图尼克
导入线程
随机导入
导入参数解析

custom_fonts_dir = '/usr/share/fonts/'
mapnik.register_fonts(custom_fonts_dir)

DEG_TO_RAD = pi/180
RAD_TO_DEG = 180/pi

# 默认生成的渲染线程数,应该大致等于可用的 CPU 内核数
NUM_THREADS = 4

定义最小最大值(a,b,c):
    a = 最大值(a,b)
    a = min(a,c)
    返回一个

类谷歌投影:
    def __init__(self,levels=18):
        自我.Bc = []
        自我抄送 = []
        自我.zc = []
        自我.Ac = []
        c = 256
        对于范围内的 d(0,级别):
            e = c/2;
            self.Bc.append(c/360.0)
            self.Cc.append(c/(2 * pi))
            self.zc.append((e,e))
            self.Ac.append(c)
            c *= 2

    def fromLLtoPixel(self,ll,zoom):
         d = self.zc[int(zoom)]
         e = round(d[0] + float(ll[0]) * self.Bc[zoom])
         f = minmax(sin(DEG_TO_RAD * float(ll[1])),-0.9999,0.9999)
         g = round(d[1] + 0.5*log((1+f)/(1-f))*-self.Cc[zoom])
         返回(例如)

    def fromPixelToLL(self,px,zoom):
         e = self.zc [缩放]
         f = (px[0] - e[0])/self.Bc[缩放]
         g = (px[1] - e[1])/-self.Cc[缩放]
         h = RAD_TO_DEG * ( 2 * atan(exp(g)) - 0.5 * pi)
         返回(f,h)



类渲染线程:
    def __init__(self, tile_dir, mapfile, q, printLock, maxZoom):
        self.tile_dir = tile_dir
        自我.q = q
        self.m = mapnik.Map(256, 256)
        self.printLock = printLock
        # 加载样式 XML
        mapnik.load_map(self.m, mapfile)
        # 获取投影
        self.prj = mapnik.Projection(self.m.srs)
        # 平铺像素坐标和 LatLong 之间的项目 (EPSG:4326)
        self.tileproj = GoogleProjection(maxZoom+1)


    def render_tile(self, tile_uri, x, y, z):
        # 计算左下角和右上角的像素位置
        p0 = (x * 256, (y + 1) * 256)
        p1 = ((x + 1) * 256, y * 256)

        # 转换为经纬度 (EPSG:4326)
        l0 = self.tileproj.fromPixelToLL(p0, z);
        l1 = self.tileproj.fromPixelToLL(p1, z);

        # 转换为地图投影(例如墨卡托坐标 EPSG:900913)
        c0 = self.prj.forward(mapnik.Coord(l0[0],l0[1]))
        c1 = self.prj.forward(mapnik.Coord(l1[0],l1[1]))

        # 瓦片的边界框
        如果 hasattr(mapnik,'mapnik_version') 和 mapnik.mapnik_version() >= 800:
            bbox = mapnik.Box2d(c0.x,c0.y, c1.x,c1.y)
        别的:
            bbox = mapnik.Envelope(c0.x,c0.y, c1.x,c1.y)
        渲染大小 = 256
        self.m.resize(render_size, render_size)
        self.m.zoom_to_box(bbox)
        self.m.buffer_size = 128

        # 使用默认的 Agg 渲染器渲染图像
        im = mapnik.Image(render_size, render_size)
        mapnik.render(self.m, im)
        im.save(tile_uri, 'png256')


    def循环(自我):
        而真:
            #从队列中取出一个tile并渲染它
            r = self.q.get()
            如果(r == 无):
                self.q.task_done()
                休息
            别的:
                (名称,tile_uri,x,y,z)= r

            存在=“”
            如果 os.path.isfile(tile_uri):
                存在=“存在”
            别的:
                self.render_tile(tile_uri, x, y, z)
            字节=os.stat(tile_uri)[6]
            空=''
            如果字节 == 103:
                空=“空瓷砖”
            self.printLock.acquire()
            打印名称,“:”,z,x,y,存在,空
            self.printLock.release()
            self.q.task_done()



def render_tiles(bbox, mapfile, tile_dir, minZoom=1,maxZoom=18, name="unknown", num_threads=NUM_THREADS):
    print "render_tiles(",bbox, mapfile, tile_dir, minZoom, maxZoom, name,")"

    # 启动渲染线程
    队列 = 队列(32)
    printLock = threading.Lock()
    渲染器 = {}
    对于我在范围内(num_threads):
        renderer = RenderThread(tile_dir, mapfile, queue, printLock, maxZoom)
        render_thread = threading.Thread(target=renderer.loop)
        render_thread.start()
        #print "开始渲染线程 %s" % render_thread.getName()
        渲染器[i] = render_thread

    如果不是 os.path.isdir(tile_dir):
         os.mkdir(tile_dir)

    gprj = GoogleProjection(maxZoom+1)

    ll0 = (bbox[0],bbox[3])
    ll1 = (bbox[2],bbox[1])

    对于范围内的 z (minZoom,maxZoom + 1):
        px0 = gprj.fromLLtoPixel(ll0,z)
        px1 = gprj.fromLLtoPixel(ll1,z)
        打印“fromlattolon”

        # 检查我们是否有目录
        缩放 = "%s" % z
        如果不是 os.path.isdir(tile_dir + zoom):
            os.mkdir(tile_dir + 缩放)
        对于范围内的 x (int(px0[0]/256.0),int(px1[0]/256.0)+1):
            # 验证 x 坐标
            如果(x = 2**z):
                继续
            # 检查我们是否有目录
            str_x = "%s" % x
            如果不是 os.path.isdir(tile_dir + zoom + '/' + str_x):
                os.mkdir(tile_dir + zoom + '/' + str_x)
            对于范围内的 y(int(px0[1]/256.0),int(px1[1]/256.0)+1):
                # 验证 x 坐标
                如果(y = 2**z):
                    继续
                str_y = "%s" % y
                tile_uri = tile_dir + 缩放 + '/' + str_x + '/' + str_y + '.png'
                # 提交要渲染的图块到队列中
                t =(名称,tile_uri,x,y,z)
                queue.put(t)

    # 通过向队列发送空请求来指示渲染线程退出
    对于我在范围内(num_threads):
        queue.put(无)
    # 等待挂起的渲染作业完成
    queue.join()
    对于我在范围内(num_threads):
        渲染器[i].join()



如果 __name__ == "__main__":
    MIN_LON = '29.5732';
    MAX_LON = '35.0360';
    MIN_LAT = '-1.4840';
    MAX_LAT = '4.2144';
    bbox = (MIN_LON, MIN_LAT,MAX_LON, MAX_LAT)
    style_file="/home/mossplix/projects/Dev/mapit/map/static/tilemill/uganda_districts.xml"
    tile_dir="/home/mossplix/projects/UnicefDev/mapit/map/static/tiles/"
    min_zoom=7
    最大缩放=14
    render_tiles(bbox, style_file, tile_dir, min_zoom, max_zoom)

这是 mapnik 配置文件 mapnik config 这是 shapefile。我从 source 编译了 mapnik,所以应该不错。可能是什么问题呢?

4

2 回答 2

3

我可以说那是generate_tiles.py最初的,稍作修改。

MemoryError 表示您正在请求渲染异常大的图像,或者您发现了 Mapnik 错误。

由于前者更有可能我认为您在修改generate_tiles.py. 所以我拿了你的脚本,覆盖了 svn 中的最新版本,并得出了差异的差异:https ://gist.github.com/1197587 。

在第 106 行和第 115 行上,您可能不想使用==not =,因为否则您会生成非常大的 x 和 y 值,这些值是无效的,并且可能是非常大的图像请求的原因(对于给定的图块是错误的)。

于 2011-09-06T14:03:06.997 回答
0

要生成的默认渲染线程数,应大致等于可用的 CPU 内核数 NUM_THREADS = 4

我在 NUM_THREADS=4 时遇到了完全相同的错误。将 NUM_THREADS 的默认值更改为 1。我有一个 i5(每核 4 个内核/1 个线程)并且 NUM_THREADS=4 非常不稳定。使用 NUM_THREADS=1 它可以正常工作。如果它适用于您的 NUM_THREADS=1,请尝试使用 NUM_THREADS=2 和 NUM_THREADS=3 如果没有崩溃。

于 2013-05-23T13:28:18.253 回答