Files
rpa_vision_v3/core/execution/spatial_index.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40)
- Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard)
- Ollama GPU fonctionnel
- Self-healing interactif
- Dashboard confiance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:23:51 +01:00

101 lines
3.0 KiB
Python

# core/execution/spatial_index.py
"""
Index spatial par grille pour optimisation des requêtes géométriques UI.
Auteur : Dom, Alice Kiro - 19 décembre 2024
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, Iterable, List, Optional, Set, Tuple
from ..models.ui_element import UIElement
def _right(b):
return b[0] + b[2]
def _bottom(b):
return b[1] + b[3]
def _intersects(a, b) -> bool:
ax1, ay1, aw, ah = a
bx1, by1, bw, bh = b
ax2, ay2 = _right(a), _bottom(a)
bx2, by2 = _right(b), _bottom(b)
return not (ax2 <= bx1 or bx2 <= ax1 or ay2 <= by1 or by2 <= ay1)
def _contains_point(b, x, y) -> bool:
return (b[0] <= x <= _right(b)) and (b[1] <= y <= _bottom(b))
@dataclass
class SpatialIndexGrid:
"""
Index spatial simple par grille (très efficace pour UI: rectangles).
- build: O(n)
- query_bbox / query_point: ~O(k) sur les cellules touchées
Auteur : Dom, Alice Kiro - 19 décembre 2024
"""
cell_size: int = 160
_cells: Dict[Tuple[int, int], List[UIElement]] = field(default_factory=dict)
_by_id: Dict[str, UIElement] = field(default_factory=dict)
_built: bool = False
def build(self, elements: List[UIElement]) -> "SpatialIndexGrid":
"""Construit l'index à partir d'une liste d'éléments UI"""
self._cells = {}
self._by_id = {}
for e in elements:
self._by_id[e.element_id] = e
for key in self._cells_for_bbox(e.bbox):
self._cells.setdefault(key, []).append(e)
self._built = True
return self
def _cells_for_bbox(self, bbox) -> Iterable[Tuple[int, int]]:
"""Retourne toutes les cellules touchées par une bbox"""
x, y, w, h = bbox
x2, y2 = x + w, y + h
cs = self.cell_size
cx1 = int(x // cs)
cy1 = int(y // cs)
cx2 = int(x2 // cs)
cy2 = int(y2 // cs)
for cy in range(cy1, cy2 + 1):
for cx in range(cx1, cx2 + 1):
yield (cx, cy)
def query_bbox(self, bbox) -> List[UIElement]:
"""Trouve tous les éléments qui intersectent avec la bbox donnée"""
if not self._built:
return []
seen: Set[str] = set()
out: List[UIElement] = []
for key in self._cells_for_bbox(bbox):
for e in self._cells.get(key, []):
if e.element_id in seen:
continue
seen.add(e.element_id)
if _intersects(e.bbox, bbox):
out.append(e)
return out
def query_point(self, x: int, y: int) -> List[UIElement]:
"""Trouve tous les éléments qui contiennent le point donné"""
if not self._built:
return []
cs = self.cell_size
key = (int(x // cs), int(y // cs))
out = []
for e in self._cells.get(key, []):
if _contains_point(e.bbox, x, y):
out.append(e)
return out