GUI: improved performance for dense compelted heat maps

This commit is contained in:
2026-04-22 11:35:11 +02:00
parent 3c4a500b4c
commit 6a6d183284
+88 -26
View File
@@ -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],