def sync(self): """ Update a peak pyramid. Pyramids with large tilesizes warp slow at high zoomlevels. The use of a peak pyramid with a small tilesize on top of the main pyramid solves that. """ path = os.path.join(self.path, self.PEAK) info = self.actualinfo if os.path.exists(path): shutil.rmtree(path) peak = Pyramid(path) dataset = self.get_dataset(info['top_tile']) # Base of peak is one higher than tile base = MEM.Create('', info['tilesize'][0] // 2, info['tilesize'][1] // 2, 1, info['datatype']) base.SetProjection(info['projection']) base.GetRasterBand(1).SetNoDataValue(info['nodatavalue']) base.SetGeoTransform( scale_geotransform(dataset.GetGeoTransform(), 2), ) base.GetRasterBand(1).Fill(info['nodatavalue']) rasters.reproject(dataset, base) peak.add(base, sync=False, blocksize=(256, 256), tilesize=(256, 256))
def warpinto(self, dataset): """ Warp data from the pyramid into dataset. """ # if no pyramid info, pyramid is empty. info = self.info if info is None: return # get bounds in pyramids projection bounds = get_bounds(dataset=dataset, projection=info['projection']) level = max(info['min_level'], get_level(bounds['pixel'])) # warp from peak if appropriate if level > info['max_level'] and 'peak' in info: return info['peak'].warpinto(dataset) # This is the top of the main pyramid (level == max_level) or the peak if level >= info['max_level']: tiles = info['top_tile'], else: tiles = get_tiles( tilesize=info['tilesize'], level=level, extent=vectors.Geometry(bounds['raster']).extent, ) for source in self.get_datasets(tiles): rasters.reproject(source, dataset)
def sync(self): """ Create or replace the peak with current data. """ ### XXX # Only create an empty file with name of peakpath open(self.peakpath, 'w') return cropped = [] for dataset in self.get_datasets(-1): cropped.append(crop(dataset)) extents = [dataset2outline(c).extent for c in cropped] x1, y1, x2, y2 = zip(*extents) x1, y1, x2, y2 = min(x1), min(y1), max(x2), max(y2) geotransform = x1, (x2 - x1) / 256, 0, y2, 0, (y1 - y2) / 256 # create fd, temppath = tempfile.mkstemp(dir=self.path, prefix=b'.pyramid.tmp.') dataset = GDAL_DRIVER_GTIFF.Create(temppath, 256, 256, self.raster_count, self.data_type, get_options(block_size=(256, 256))) dataset.SetProjection(projections.get_wkt(self.projection)) dataset.SetGeoTransform(geotransform) for i in range(self.raster_count): dataset.GetRasterBand(i + 1).SetNoDataValue(self.no_data_value) for c in cropped: rasters.reproject(c, dataset) dataset = None os.close(fd) os.rename(temppath, self.peakpath)
def warp(path_and_blocks): """ Warp global transport into specified blocks from dataset at path. """ path, blocks = path_and_blocks for i, j in blocks: dataset = rasters.Dataset(gdal.Open(path, gdal.GA_Update)) block = dataset.read_block((i, -j - 1)) rasters.reproject(source=transport.dataset, target=block['dataset']) block['dataset'].FlushCache() # really update underlying numpy array dataset.write_block((i, -j - 1), block['array'])
def get_promoted(self, tile, info): """ Return parent tile. Reproject tiles dataset into parent dataset. """ parent = get_parent(tile) source = self.get_dataset(tile) target = self.get_dataset(tile=parent, info=info) rasters.reproject(source, target) return parent
def add(self, dataset=None, sync=True, **kwargs): """ If there is no dataset, check if locked and reload. Any kwargs are used to override dataset projection and datatype, nodatavalue, tilesize. Kwargs are ignored if data already exists in the pyramid. Sync indicates wether to build a synced peak on top of the pyramid. """ self.lock() if dataset is None: # unlock and return return self.unlock() # use pyramid info if possible, otherwise use dataset and kwargs info = self.actualinfo if info is None: info = get_info(dataset) info.update(kwargs) if not self.path.endswith(self.PEAK): info.update(peak=Pyramid(os.path.join(self.path, self.PEAK))) # get bounds in pyramids projection bounds = get_bounds(dataset=dataset, projection=info['projection']) # derive baselevel min_level = info.get('min_level', get_level(bounds['pixel'])) # find new top tile top_tile = get_top_tile(geometry=bounds['raster'], tilesize=info['tilesize'], blocksize=info['blocksize']) # walk and reproject tiles = walk_tiles(tile=top_tile, stop=min_level, geometry=bounds['raster']) children = collections.defaultdict(list) previous_level = min_level for tile in tiles: # Get the dataset target = self.get_dataset(tile=tile, info=info) # To aggregate or not if tile.level == previous_level + 1: while children[previous_level]: rasters.reproject( children[previous_level].pop(), target ) else: rasters.reproject(dataset, target) target = None # Writes the header children[tile.level].append(self.get_dataset(tile)) previous_level = tile.level # sync old and new toptiles lo, hi = top_tile, info.get('top_tile', top_tile) if hi.level < lo.level: hi, lo = lo, hi # swap while lo.level < hi.level: lo = self.get_promoted(tile=lo, info=info) while lo.indices != hi.indices: lo = self.get_promoted(tile=lo, info=info) hi = self.get_promoted(tile=hi, info=info) # Update peak if sync: self.sync() self.unlock()
def warpinto(self, dataset): """ Warp appropriate tiles into dataset. """ for source in self.get_datasets(dataset): rasters.reproject(source, dataset)