Artem Sukhodolskyi 820879b79f initial commit
2025-10-21 12:55:17 +02:00

122 lines
2.7 KiB
Go

package app
import (
"sync"
)
const (
ChunkSize = 16
)
// Point represents the request body for setting cell position
type Point struct {
X, Y int
}
// Area represents the visible area for SSE updates
type Area struct {
X, Y, Width, Height int
}
// Contains checks if a point is within the SSE area
func (a Area) Contains(x int, y int) bool {
return x >= a.X && x <= a.X+a.Width && y >= a.Y && y <= a.Y+a.Height
}
// SpatialHashMap implements spatial hashing for efficient point storage and retrieval
type SpatialHashMap struct {
mu sync.RWMutex
db *SQLiteEngine
}
// NewSpatialHashMap creates a new spatial hash map
func NewSpatialHashMap(dbPath string) (*SpatialHashMap, error) {
db, err := CreateSQLite(dbPath)
if err != nil {
return nil, err
}
return &SpatialHashMap{
db: db,
}, nil
}
func (s *SpatialHashMap) InitSchema() error {
err := s.db.Execute(
`CREATE TABLE IF NOT EXISTS spatial_hashmap (
cluster_x INTEGER NOT NULL,
cluster_y INTEGER NOT NULL,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
PRIMARY KEY (cluster_x, cluster_y, x, y)) WITHOUT ROWID`)
if err != nil {
return err
}
return nil
}
// getHash calculates the hash coordinates for a given point
func (s *SpatialHashMap) getHash(x, y int) Point {
return Point{X: x / ChunkSize, Y: y / ChunkSize}
}
// Insert adds a point to the spatial hash map
func (s *SpatialHashMap) Insert(x, y int) error {
s.mu.Lock()
defer s.mu.Unlock()
key := s.getHash(x, y)
err := s.db.Execute(
"INSERT INTO spatial_hashmap (cluster_x, cluster_y, x, y) VALUES (?, ?, ?, ?)",
key.X, key.Y, x, y)
if err != nil {
return err
}
return nil
}
// Remove removes a point from the spatial hash map
func (s *SpatialHashMap) Remove(x, y int) error {
s.mu.Lock()
defer s.mu.Unlock()
key := s.getHash(x, y)
err := s.db.Execute(
"DELETE FROM spatial_hashmap WHERE cluster_x = ? AND cluster_y = ? AND x = ? AND y = ?",
key.X, key.Y, x, y)
if err != nil {
return err
}
return nil
}
// GetLocalPoints returns all points within the given bounding box
func (s *SpatialHashMap) GetLocalPoints(area Area) []Point {
hashStart, hashEnd := s.getHash(area.X, area.Y), s.getHash(area.X+area.Width, area.Y+area.Height)
rows, err := s.db.Query(
"SELECT x, y FROM spatial_hashmap WHERE cluster_x BETWEEN ? AND ? AND cluster_y BETWEEN ? AND ?",
hashStart.X, hashEnd.X, hashStart.Y, hashEnd.Y)
if err != nil {
return nil
}
defer rows.Close()
localPoints := make([]Point, 0)
for rows.Next() {
var x, y int
if err := rows.Scan(&x, &y); err != nil {
continue
}
localPoints = append(localPoints, Point{X: x, Y: y})
}
return localPoints
}
func (s *SpatialHashMap) Close() error {
if s.db != nil {
return s.db.Close()
}
return nil
}