re-factored the way tiles are passed from quadtree through rendernode
This commit is contained in:
@@ -215,23 +215,6 @@ class QuadtreeGen(object):
|
|||||||
self._decrease_depth()
|
self._decrease_depth()
|
||||||
|
|
||||||
|
|
||||||
def _get_range_by_path(self, path):
|
|
||||||
"""Returns the x, y chunk coordinates of this tile"""
|
|
||||||
x, y = self.mincol, self.minrow
|
|
||||||
|
|
||||||
xsize = self.maxcol
|
|
||||||
ysize = self.maxrow
|
|
||||||
|
|
||||||
for p in path:
|
|
||||||
if p in (1, 3):
|
|
||||||
x += xsize
|
|
||||||
if p in (2, 3):
|
|
||||||
y += ysize
|
|
||||||
xsize //= 2
|
|
||||||
ysize //= 2
|
|
||||||
|
|
||||||
return x, y
|
|
||||||
|
|
||||||
def get_chunks_in_range(self, colstart, colend, rowstart, rowend):
|
def get_chunks_in_range(self, colstart, colend, rowstart, rowend):
|
||||||
"""Get chunks that are relevant to the tile rendering function that's
|
"""Get chunks that are relevant to the tile rendering function that's
|
||||||
rendering that range"""
|
rendering that range"""
|
||||||
@@ -270,17 +253,13 @@ class QuadtreeGen(object):
|
|||||||
"""
|
"""
|
||||||
for path in iterate_base4(self.p):
|
for path in iterate_base4(self.p):
|
||||||
# Get the range for this tile
|
# Get the range for this tile
|
||||||
colstart, rowstart = self._get_range_by_path(path)
|
tile = Tile.from_path(path)
|
||||||
colend = colstart + 2
|
|
||||||
rowend = rowstart + 4
|
|
||||||
|
|
||||||
# This image is rendered at(relative to the worker's destdir):
|
# Put this in the batch to be submited to the pool.
|
||||||
tilepath = [str(x) for x in path]
|
# The quadtree object gets replaced by the caller in rendernode.py,
|
||||||
tilepath = os.sep.join(tilepath)
|
# but we still have to let them know which quadtree this tile
|
||||||
#logging.debug("this is rendered at %s", dest)
|
# belongs to.
|
||||||
|
yield [self, tile]
|
||||||
# Put this in the batch to be submited to the pool
|
|
||||||
yield [self,colstart, colend, rowstart, rowend, tilepath]
|
|
||||||
|
|
||||||
def get_innertiles(self,zoom):
|
def get_innertiles(self,zoom):
|
||||||
"""Same as get_worldtiles but for the inntertile routine.
|
"""Same as get_worldtiles but for the inntertile routine.
|
||||||
@@ -360,53 +339,37 @@ class QuadtreeGen(object):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def render_worldtile(self, chunks, colstart, colend, rowstart, rowend, path, poi_queue=None):
|
def render_worldtile(self, tile):
|
||||||
"""Renders just the specified chunks into a tile and save it. Unlike usual
|
"""Renders the given tile. All the other relevant information is
|
||||||
python conventions, rowend and colend are inclusive. Additionally, the
|
already stored in this quadtree object or in self.world.
|
||||||
chunks around the edges are half-way cut off (so that neighboring tiles
|
|
||||||
will render the other half)
|
|
||||||
|
|
||||||
chunks is a list of (col, row, chunkx, chunky, filename) of chunk
|
The image is rendered and saved to disk in the place this quadtree is
|
||||||
images that are relevant to this call (with their associated regions)
|
configured to store images.
|
||||||
|
|
||||||
The image is saved to path+"."+self.imgformat
|
|
||||||
|
|
||||||
If there are no chunks, this tile is not saved (if it already exists, it is
|
If there are no chunks, this tile is not saved (if it already exists, it is
|
||||||
deleted)
|
deleted)
|
||||||
|
|
||||||
Standard tile size has colend-colstart=2 and rowend-rowstart=4
|
|
||||||
|
|
||||||
There is no return value
|
There is no return value
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# width of one chunk is 384. Each column is half a chunk wide. The total
|
|
||||||
# width is (384 + 192*(numcols-1)) since the first column contributes full
|
|
||||||
# width, and each additional one contributes half since they're staggered.
|
|
||||||
# However, since we want to cut off half a chunk at each end (384 less
|
|
||||||
# pixels) and since (colend - colstart + 1) is the number of columns
|
|
||||||
# inclusive, the equation simplifies to:
|
|
||||||
width = 192 * (colend - colstart)
|
|
||||||
# Same deal with height
|
|
||||||
height = 96 * (rowend - rowstart)
|
|
||||||
|
|
||||||
# The standard tile size is 3 columns by 5 rows, which works out to 384x384
|
poi_queue = self.world.poi_q
|
||||||
# pixels for 8 total chunks. (Since the chunks are staggered but the grid
|
|
||||||
# is not, some grid coordinates do not address chunks) The two chunks on
|
|
||||||
# the middle column are shown in full, the two chunks in the middle row are
|
|
||||||
# half cut off, and the four remaining chunks are one quarter shown.
|
|
||||||
# The above example with cols 0-3 and rows 0-4 has the chunks arranged like this:
|
|
||||||
# 0,0 2,0
|
|
||||||
# 1,1
|
|
||||||
# 0,2 2,2
|
|
||||||
# 1,3
|
|
||||||
# 0,4 2,4
|
|
||||||
|
|
||||||
# Due to how the tiles fit together, we may need to render chunks way above
|
|
||||||
# this (since very few chunks actually touch the top of the sky, some tiles
|
|
||||||
# way above this one are possibly visible in this tile). Render them
|
|
||||||
# anyways just in case). "chunks" should include up to rowstart-16
|
|
||||||
|
|
||||||
|
path = os.path.join(self.full_tiledir, *(str(x) for x in tile.path))
|
||||||
imgpath = path + "." + self.imgformat
|
imgpath = path + "." + self.imgformat
|
||||||
|
|
||||||
|
# Tiles always involve 3 columns of chunks and 5 rows of tiles (end
|
||||||
|
# ranges are inclusive)
|
||||||
|
colstart = tile.col
|
||||||
|
colend = colstart + 2
|
||||||
|
rowstart = tile.row
|
||||||
|
rowend = rowstart + 4
|
||||||
|
|
||||||
|
width = 384
|
||||||
|
height = 384
|
||||||
|
|
||||||
|
# Calculate which chunks are relevant to this tile
|
||||||
|
chunks = self.get_chunks_in_range(colstart, colend, rowstart, rowend)
|
||||||
|
|
||||||
world = self.world
|
world = self.world
|
||||||
#stat the file, we need to know if it exists or it's mtime
|
#stat the file, we need to know if it exists or it's mtime
|
||||||
try:
|
try:
|
||||||
@@ -618,3 +581,54 @@ class DirtyTiles(object):
|
|||||||
for path in child.iterate_dirty():
|
for path in child.iterate_dirty():
|
||||||
path.append(c)
|
path.append(c)
|
||||||
yield path
|
yield path
|
||||||
|
|
||||||
|
class Tile(object):
|
||||||
|
"""A simple container class that represents a single render-tile.
|
||||||
|
|
||||||
|
A render-tile is a tile that is rendered, not a tile composed of other
|
||||||
|
tiles.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__slots__ = ("col", "row", "path")
|
||||||
|
def __init__(self, col, row, path):
|
||||||
|
"""Initialize the tile obj with the given parameters. It's probably
|
||||||
|
better to use one of the other constructors though
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.col = col
|
||||||
|
self.row = row
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_path(cls, path):
|
||||||
|
"""Constructor that takes a path and computes the col,row address of
|
||||||
|
the tile and constructs a new tile object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
depth = len(path)
|
||||||
|
|
||||||
|
# Radius of the world in chunk cols/rows
|
||||||
|
xradius = 2**depth
|
||||||
|
yradius = 2*2**depth
|
||||||
|
|
||||||
|
x = -xradius
|
||||||
|
y = -yradius
|
||||||
|
xsize = xradius
|
||||||
|
ysize = yradius
|
||||||
|
|
||||||
|
for p in path:
|
||||||
|
if p in (1,3):
|
||||||
|
x += xsize
|
||||||
|
if p in (2,3):
|
||||||
|
y += ysize
|
||||||
|
xsize //= 2
|
||||||
|
ysize //= 2
|
||||||
|
|
||||||
|
return cls(x, y, path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def compute_path(cls, col, row, depth):
|
||||||
|
"""Constructor that takes a col,row of a tile and computes the path.
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ class RenderNode(object):
|
|||||||
|
|
||||||
@catch_keyboardinterrupt
|
@catch_keyboardinterrupt
|
||||||
def render_worldtile_batch(batch):
|
def render_worldtile_batch(batch):
|
||||||
# batch is a list. Each item is [quadtree_id, colstart, colend, rowstart, rowend, tilepath]
|
# batch is a list of items to process. Each item is [quadtree_id, Tile object]
|
||||||
global child_rendernode
|
global child_rendernode
|
||||||
rendernode = child_rendernode
|
rendernode = child_rendernode
|
||||||
count = 0
|
count = 0
|
||||||
@@ -356,20 +356,9 @@ def render_worldtile_batch(batch):
|
|||||||
for job in batch:
|
for job in batch:
|
||||||
count += 1
|
count += 1
|
||||||
quadtree = rendernode.quadtrees[job[0]]
|
quadtree = rendernode.quadtrees[job[0]]
|
||||||
colstart = job[1]
|
tile = job[1]
|
||||||
colend = job[2]
|
|
||||||
rowstart = job[3]
|
quadtree.render_worldtile(tile)
|
||||||
rowend = job[4]
|
|
||||||
path = job[5]
|
|
||||||
poi_queue = quadtree.world.poi_q
|
|
||||||
path = quadtree.full_tiledir+os.sep+path
|
|
||||||
# (even if tilechunks is empty, render_worldtile will delete
|
|
||||||
# existing images if appropriate)
|
|
||||||
# And uses these chunks
|
|
||||||
tilechunks = quadtree.get_chunks_in_range(colstart, colend, rowstart,rowend)
|
|
||||||
#logging.debug(" tilechunks: %r", tilechunks)
|
|
||||||
|
|
||||||
quadtree.render_worldtile(tilechunks,colstart, colend, rowstart, rowend, path, poi_queue)
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@catch_keyboardinterrupt
|
@catch_keyboardinterrupt
|
||||||
|
|||||||
Reference in New Issue
Block a user