Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
nb_types.NamedUniTuple(int64, 2, Point),
nb_types.NamedUniTuple(int64, 2, Point)
), nopython=True, cache=True, nogil=True)
def max_tiles_available(image_shape, tile_shape, stride):
ath = (image_shape[0] / float(stride[0])) / tile_shape[0]
atw = (image_shape[1] / float(stride[1])) / tile_shape[1]
return ath, atw
self.origin_y = origin_y
self.shape = shape or max(data.shape for data in data_arrays if data is not None)
assert None not in (self.cell_width, self.cell_height, self.origin_x, self.origin_y, self.shape)
# how many of the higher resolution channel tiles (smaller geographic area) make
# up a low resolution channel tile
self._channel_factors = tuple(
self.shape[0] / float(chn.shape[0]) if chn is not None else 1. for chn in data_arrays)
self._lowest_factor = max(self._channel_factors)
self._lowest_rez = Resolution(abs(self.cell_height * self._lowest_factor),
abs(self.cell_width * self._lowest_factor))
# Where does this image lie in this lonely world
self.calc = TileCalculator(
self.name,
self.shape,
Point(x=self.origin_x, y=self.origin_y),
Resolution(dy=abs(self.cell_height), dx=abs(self.cell_width)),
self.tile_shape,
self.texture_shape,
wrap_lon=self.wrap_lon
)
# Reset texture state, if we change things to know which texture
# don't need to be updated then this can be removed/changed
self.texture_state.reset()
self._need_texture_upload = True
self._need_vertex_update = True
# Reset the tiling logic to force a retile
# even though we might be looking at the exact same spot
self._latest_tile_box = None
self.image_tiles_avail = (self.image_shape[0] / self.tile_shape[0], self.image_shape[1] / self.tile_shape[1])
self.wrap_lon = wrap_lon
self.proj = Proj(projection)
self.image_extents_box = e = Box(
bottom=np.float64(self.ul_origin[0] - self.image_shape[0] * self.pixel_rez.dy),
top=np.float64(self.ul_origin[0]),
left=np.float64(self.ul_origin[1]),
right=np.float64(self.ul_origin[1] + self.image_shape[1] * self.pixel_rez.dx),
)
# Array of points across the image space to be used as an estimate of image coverage
# Used when checking if the image is viewable on the current canvas's projection
self.image_mesh = np.meshgrid(np.linspace(e.left, e.right, IMAGE_MESH_SIZE),
np.linspace(e.bottom, e.top, IMAGE_MESH_SIZE))
self.image_mesh = np.column_stack((self.image_mesh[0].ravel(), self.image_mesh[1].ravel(),))
self.image_center = Point(self.ul_origin.y - self.image_shape[0] / 2. * self.pixel_rez.dy,
self.ul_origin.x + self.image_shape[1] / 2. * self.pixel_rez.dx)
# size of tile in image projection
self.tile_size = Resolution(self.pixel_rez.dy * self.tile_shape[0], self.pixel_rez.dx * self.tile_shape[1])
self.overview_stride = self.calc_overview_stride()
def calc_tile_fraction(tiy, tix, stride_y, stride_x, image_y, image_x, tile_y, tile_x): # image_shape, tile_shape):
# def calc_tile_fraction(tiy, tix, stride, image_shape, tile_shape):
# mt = max_tiles_available(image_shape, tile_shape, stride)
mt = max_tiles_available(Point(image_y, image_x), Point(tile_y, tile_x), Point(stride_y, stride_x))
if tix < -mt[1] / 2. + 0.5:
# left edge tile
offset_x = -mt[1] / 2. + 0.5 - tix
factor_x = 1 - offset_x
elif mt[1] / 2. + 0.5 - tix < 1:
# right edge tile
offset_x = 0.
factor_x = mt[1] / 2. + 0.5 - tix
else:
# full tile
offset_x = 0.
factor_x = 1.
if tiy < -mt[0] / 2. + 0.5:
# left edge tile
y_slice, x_slice = self.calc.overview_stride
nfo["data"] = data[y_slice, x_slice]
# Update kwargs to reflect the new spatial resolution of the overview image
nfo["cell_width"] = self.cell_width * x_slice.step
nfo["cell_height"] = self.cell_height * y_slice.step
# Tell the texture state that we are adding a tile that should never expire and should always exist
nfo["texture_tile_index"] = ttile_idx = self.texture_state.add_tile((0, 0, 0), expires=False)
self._texture.set_tile_data(ttile_idx, self._normalize_data(nfo["data"]))
# Handle wrapping around the anti-meridian so there is a -180/180 continuous image
num_tiles = 1 if not self.wrap_lon else 2
tl = TESS_LEVEL * TESS_LEVEL
nfo["texture_coordinates"] = np.empty((6 * num_tiles * tl, 2), dtype=np.float32)
nfo["vertex_coordinates"] = np.empty((6 * num_tiles * tl, 2), dtype=np.float32)
factor_rez, offset_rez = self.calc.calc_tile_fraction(0, 0,
Point(np.int64(y_slice.step), np.int64(x_slice.step)))
nfo["texture_coordinates"][:6 * tl, :2] = self.calc.calc_texture_coordinates(ttile_idx, factor_rez, offset_rez,
tessellation_level=TESS_LEVEL)
nfo["vertex_coordinates"][:6 * tl, :2] = self.calc.calc_vertex_coordinates(0, 0, y_slice.step, x_slice.step,
factor_rez, offset_rez,
tessellation_level=TESS_LEVEL)
self._set_vertex_tiles(nfo["vertex_coordinates"], nfo["texture_coordinates"])
self.image_tiles_avail = (self.image_shape[0] / self.tile_shape[0], self.image_shape[1] / self.tile_shape[1])
self.wrap_lon = wrap_lon
self.proj = Proj(projection)
self.image_extents_box = e = Box(
bottom=np.float64(self.ul_origin[0] - self.image_shape[0] * self.pixel_rez.dy),
top=np.float64(self.ul_origin[0]),
left=np.float64(self.ul_origin[1]),
right=np.float64(self.ul_origin[1] + self.image_shape[1] * self.pixel_rez.dx),
)
# Array of points across the image space to be used as an estimate of image coverage
# Used when checking if the image is viewable on the current canvas's projection
self.image_mesh = np.meshgrid(np.linspace(e.left, e.right, IMAGE_MESH_SIZE),
np.linspace(e.bottom, e.top, IMAGE_MESH_SIZE))
self.image_mesh = np.column_stack((self.image_mesh[0].ravel(), self.image_mesh[1].ravel(),))
self.image_center = Point(self.ul_origin.y - self.image_shape[0] / 2. * self.pixel_rez.dy,
self.ul_origin.x + self.image_shape[1] / 2. * self.pixel_rez.dx)
# size of tile in image projection
self.tile_size = Resolution(self.pixel_rez.dy * self.tile_shape[0], self.pixel_rez.dx * self.tile_shape[1])
self.overview_stride = self.calc_overview_stride()
ntw = np.ceil((pv.right - tix0 * tw) / tw + 0.5)
# now add the extras
if x_bottom > 0:
nth += int(x_bottom)
if x_left > 0:
tix0 -= int(x_left)
ntw += int(x_left)
if x_top > 0:
tiy0 -= int(x_top)
nth += int(x_top)
if x_right > 0:
ntw += int(x_right)
# Total number of tiles in this image at this stride (could be fractional)
ath, atw = max_tiles_available(Point(image_shape_y, image_shape_x),
Point(tile_shape_y, tile_shape_x),
Point(stride_y, stride_x))
# truncate to the available tiles
hw = atw / 2.
hh = ath / 2.
# center tile is half pixel off because we want center of the center
# tile to be at the center of the image
if tix0 < -hw + 0.5:
ntw += hw - 0.5 + tix0
tix0 = -hw + 0.5
if tiy0 < -hh + 0.5:
nth += hh - 0.5 + tiy0
tiy0 = -hh + 0.5
# add 0.5 to include the "end of the tile" since the r and b are exclusive
if tix0 + ntw > hw + 0.5:
ntw = hw + 0.5 - tix0
# now add the extras
if x_bottom > 0:
nth += int(x_bottom)
if x_left > 0:
tix0 -= int(x_left)
ntw += int(x_left)
if x_top > 0:
tiy0 -= int(x_top)
nth += int(x_top)
if x_right > 0:
ntw += int(x_right)
# Total number of tiles in this image at this stride (could be fractional)
ath, atw = max_tiles_available(Point(image_shape_y, image_shape_x),
Point(tile_shape_y, tile_shape_x),
Point(stride_y, stride_x))
# truncate to the available tiles
hw = atw / 2.
hh = ath / 2.
# center tile is half pixel off because we want center of the center
# tile to be at the center of the image
if tix0 < -hw + 0.5:
ntw += hw - 0.5 + tix0
tix0 = -hw + 0.5
if tiy0 < -hh + 0.5:
nth += hh - 0.5 + tiy0
tiy0 = -hh + 0.5
# add 0.5 to include the "end of the tile" since the r and b are exclusive
if tix0 + ntw > hw + 0.5:
ntw = hw + 0.5 - tix0
if tiy0 + nth > hh + 0.5:
nth = hh + 0.5 - tiy0
ul_origin (float, float): (y, x) in world coords specifies upper-left coordinate of the image
pixel_rez (float, float): (dy, dx) in world coords per pixel ascending from corner [0,0],
as measured near zero_point
tile_shape (int, int): the pixel dimensions (h:int, w:int) of the GPU tiling we want to use
texture_shape (int, int): the size of the texture being used (h, w) in number of tiles
Notes:
- Tiling is aligned to pixels, not world
- World coordinates are eqm such that 0,0 matches 0°N 0°E, going north/south +-90° and west/east +-180°
- Data coordinates are pixels with b l or b r corner being 0,0
"""
super(TileCalculator, self).__init__()
self.name = name
self.image_shape = Point(np.int64(image_shape[0]), np.int64(image_shape[1]))
self.ul_origin = Point(*ul_origin)
self.pixel_rez = Resolution(np.float64(pixel_rez[0]), np.float64(pixel_rez[1]))
self.tile_shape = Point(np.int64(tile_shape[0]), np.int64(tile_shape[1]))
# in units of tiles:
self.texture_shape = texture_shape
# in units of data elements (float32):
self.texture_size = (self.texture_shape[0] * self.tile_shape[0], self.texture_shape[1] * self.tile_shape[1])
self.image_tiles_avail = (self.image_shape[0] / self.tile_shape[0], self.image_shape[1] / self.tile_shape[1])
self.wrap_lon = wrap_lon
self.proj = Proj(projection)
self.image_extents_box = e = Box(
bottom=np.float64(self.ul_origin[0] - self.image_shape[0] * self.pixel_rez.dy),
top=np.float64(self.ul_origin[0]),
left=np.float64(self.ul_origin[1]),
right=np.float64(self.ul_origin[1] + self.image_shape[1] * self.pixel_rez.dx),