GUI: improved performance for dense compelted heat maps
This commit is contained in:
@@ -138,16 +138,16 @@ class RasterGridManager(QObject):
|
||||
if not self._is_grid_visible(grid):
|
||||
return None
|
||||
|
||||
start_anchor = grid.start_pxl(self.__geom)
|
||||
start_picture = self.__geom.sample_to_picture(start_anchor)
|
||||
cell = grid.grid_size_pxl(self.__geom)
|
||||
|
||||
cell_w = float(cell.x)
|
||||
cell_h = float(cell.y)
|
||||
|
||||
if cell_w <= 0 or cell_h <= 0:
|
||||
return None
|
||||
|
||||
start_anchor = grid.start_pxl(self.__geom)
|
||||
start_picture = self.__geom.sample_to_picture(start_anchor)
|
||||
|
||||
return float(start_picture.x), float(start_picture.y), cell_w, cell_h
|
||||
|
||||
def _grid_bounds_rect(self, grid: RasterGridRequest) -> QRectF | None:
|
||||
@@ -480,6 +480,10 @@ class RasterGridManager(QObject):
|
||||
if visible_rect is not None and not visible_rect.isEmpty() and not bounds.intersects(visible_rect):
|
||||
return
|
||||
|
||||
if values is not None and (cell_w < 3.0 or cell_h < 3.0):
|
||||
if self._draw_completed_grid_fast(painter, grid, values, alpha, visible_rect):
|
||||
return
|
||||
|
||||
painter.save()
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing, False)
|
||||
|
||||
@@ -497,42 +501,35 @@ class RasterGridManager(QObject):
|
||||
grid, visible_rect, start_x, start_y, cell_w, cell_h
|
||||
)
|
||||
|
||||
stride_x = 1
|
||||
stride_y = 1
|
||||
if values is not None:
|
||||
min_fill_px = 2.0
|
||||
stride_x = max(1, int(math.ceil(min_fill_px / max(cell_w, 1e-9))))
|
||||
stride_y = max(1, int(math.ceil(min_fill_px / max(cell_h, 1e-9))))
|
||||
|
||||
for y in range(min_y, max_y, stride_y):
|
||||
for y in range(min_y, max_y):
|
||||
py = start_y + y * cell_h
|
||||
draw_h = max(1.0, cell_h * stride_y)
|
||||
|
||||
for x in range(min_x, max_x, stride_x):
|
||||
for x in range(min_x, max_x):
|
||||
px = start_x + x * cell_w
|
||||
draw_w = max(1.0, cell_w * stride_x)
|
||||
|
||||
if values is None:
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
painter.drawRect(QRect(round(px), round(py), round(draw_w), round(draw_h)))
|
||||
painter.drawRect(QRect(round(px), round(py), round(cell_w), round(cell_h)))
|
||||
continue
|
||||
|
||||
value = self._block_value(
|
||||
values,
|
||||
grid.n_x,
|
||||
x,
|
||||
min(x + stride_x, grid.n_x),
|
||||
y,
|
||||
min(y + stride_y, grid.n_y),
|
||||
)
|
||||
if value is None:
|
||||
idx = x + y * grid.n_x
|
||||
if (
|
||||
len(values) <= idx
|
||||
or values[idx] is None
|
||||
or math.isnan(values[idx])
|
||||
or values[idx] < 0
|
||||
):
|
||||
continue
|
||||
|
||||
brush = float_to_viridis_brush((value - min_value) / diff, alpha=alpha)
|
||||
painter.fillRect(QRectF(px, py, draw_w, draw_h), brush)
|
||||
brush = float_to_viridis_brush((values[idx] - min_value) / diff, alpha=alpha)
|
||||
painter.fillRect(QRectF(px, py, max(1.0, cell_w), max(1.0, cell_h)), brush)
|
||||
|
||||
if values is None:
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
else:
|
||||
painter.setPen(QPen(QColor(114, 159, 207, min(255, alpha + 40)), 1, Qt.PenStyle.SolidLine))
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
painter.drawRect(bounds)
|
||||
|
||||
painter.restore()
|
||||
|
||||
@@ -592,6 +589,71 @@ class RasterGridManager(QObject):
|
||||
painter.restore()
|
||||
return True
|
||||
|
||||
def _draw_completed_grid_fast(
|
||||
self,
|
||||
painter: QPainter,
|
||||
grid: RasterGridRequest,
|
||||
values: List[float] | List[int],
|
||||
alpha: int,
|
||||
visible_rect: QRectF | None,
|
||||
) -> bool:
|
||||
geo = self._grid_pixel_geometry(grid)
|
||||
if geo is None:
|
||||
return False
|
||||
|
||||
start_x, start_y, cell_w, cell_h = geo
|
||||
bounds = self._grid_bounds_rect(grid)
|
||||
if bounds is None:
|
||||
return False
|
||||
|
||||
if visible_rect is not None and not visible_rect.isEmpty() and not bounds.intersects(visible_rect):
|
||||
return True
|
||||
|
||||
valid_values = [x for x in values if x is not None and not math.isnan(x) and x >= 0]
|
||||
min_value = min(valid_values, default=0)
|
||||
max_value = max(valid_values, default=1)
|
||||
diff = 1 if min_value == max_value else (max_value - min_value)
|
||||
|
||||
min_x, max_x, min_y, max_y = self._visible_index_range(
|
||||
grid, visible_rect, start_x, start_y, cell_w, cell_h
|
||||
)
|
||||
|
||||
min_fill_px = 3.0
|
||||
stride_x = max(1, int(math.ceil(min_fill_px / max(cell_w, 1e-9))))
|
||||
stride_y = max(1, int(math.ceil(min_fill_px / max(cell_h, 1e-9))))
|
||||
|
||||
painter.save()
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing, False)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
|
||||
for y in range(min_y, max_y, stride_y):
|
||||
py = start_y + y * cell_h
|
||||
draw_h = max(1.0, cell_h * stride_y)
|
||||
|
||||
for x in range(min_x, max_x, stride_x):
|
||||
px = start_x + x * cell_w
|
||||
draw_w = max(1.0, cell_w * stride_x)
|
||||
|
||||
value = self._block_value(
|
||||
values,
|
||||
grid.n_x,
|
||||
x,
|
||||
min(x + stride_x, grid.n_x),
|
||||
y,
|
||||
min(y + stride_y, grid.n_y),
|
||||
)
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
brush = float_to_viridis_brush((value - min_value) / diff, alpha=alpha)
|
||||
painter.fillRect(QRectF(px, py, draw_w, draw_h), brush)
|
||||
|
||||
painter.setPen(QPen(QColor(114, 159, 207, min(255, alpha + 40)), 1, Qt.PenStyle.SolidLine))
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
painter.drawRect(bounds)
|
||||
|
||||
painter.restor
|
||||
|
||||
def _block_value(
|
||||
self,
|
||||
values: List[float] | List[int],
|
||||
|
||||
Reference in New Issue
Block a user