-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgrid.go
144 lines (119 loc) · 3.67 KB
/
grid.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package aoi
import "sync"
var (
// Define direction vectors for the eight directions by populating dx and dy arrays.
dx = []int{-1, -1, -1, 0, 0, 1, 1, 1}
dy = []int{-1, 0, 1, -1, 1, -1, 0, 1}
)
// Grid represents a grid with a unique identifier and entities within it.
type Grid struct {
GID int // Grid ID
Entities sync.Map // Entities within the current grid
}
// GridManager implements AOI (Area of Interest) using a rectangular grid.
type GridManager struct {
StartX int // X-coordinate of the left boundary of the AOI
StartY int // Y-coordinate of the upper boundary of the AOI
AreaWidth int // Width of each grid (assuming square grids)
GridCount int // Number of grids in each row/column
grids map[int]*Grid
pool sync.Pool
}
// NewGrid creates a new grid with the specified ID.
func NewGrid(gid int) *Grid {
return &Grid{
GID: gid,
}
}
// NewGridManager initializes a new GridManager with the specified parameters.
func NewGridManager(startX, startY, areaWidth, gridCount int) AOI {
manager := &GridManager{
StartX: startX,
StartY: startY,
AreaWidth: areaWidth,
GridCount: gridCount,
grids: make(map[int]*Grid),
}
manager.pool.New = func() interface{} {
return make([]*Grid, 0, 9)
}
// Initialize grids with unique IDs
for y := 0; y < gridCount; y++ {
for x := 0; x < gridCount; x++ {
// Grid ID calculation: ID = IDy * nx + IDx (using grid coordinates to obtain grid ID)
gID := y*gridCount + x
manager.grids[gID] = NewGrid(gID)
}
}
return manager
}
// gridWidth calculates the width of each grid.
func (g *GridManager) gridWidth() int {
return g.AreaWidth / g.GridCount
}
// getGIDByPos calculates the grid ID based on the given coordinates.
func (g *GridManager) getGIDByPos(x, y float64) int {
gx := (int(x) - g.StartX) / g.gridWidth()
gy := (int(y) - g.StartY) / g.gridWidth()
return gy*g.GridCount + gx
}
// getSurroundGrids retrieves information about the surrounding nine grids based on the given grid ID.
func (g *GridManager) getSurroundGrids(gID int) []*Grid {
grids := g.pool.Get().([]*Grid)
defer func() {
grids = grids[:0]
g.pool.Put(grids)
}()
if _, ok := g.grids[gID]; !ok {
return grids
}
grids = append(grids, g.grids[gID])
// Calculate the coordinates of the grid based on the grid ID
x, y := gID%g.GridCount, gID/g.GridCount
// Add information about the eight neighboring grids
for i := 0; i < 8; i++ {
newX := x + dx[i]
newY := y + dy[i]
if newX >= 0 && newX < g.GridCount && newY >= 0 && newY < g.GridCount {
grids = append(grids, g.grids[newY*g.GridCount+newX])
}
}
return grids
}
// Add adds an entity to the appropriate grid based on its coordinates.
func (g *GridManager) Add(x, y float64, key string) {
entity := entityPool.Get().(*Entity)
entity.X = x
entity.Y = y
entity.Key = key
ID := g.getGIDByPos(x, y)
grid := g.grids[ID]
grid.Entities.Store(key, entity)
}
// Delete removes an entity from the grid based on its coordinates.
func (g *GridManager) Delete(x, y float64, key string) {
ID := g.getGIDByPos(x, y)
grid := g.grids[ID]
if entity, ok := grid.Entities.Load(key); ok {
grid.Entities.Delete(key)
entityPool.Put(entity)
}
}
// Search retrieves a list of entity keys within the specified coordinates' range.
func (g *GridManager) Search(x, y float64) []string {
result := resultPool.Get().([]string)
defer func() {
result = result[:0]
resultPool.Put(result)
}()
ID := g.getGIDByPos(x, y)
grids := g.getSurroundGrids(ID)
// Collect entity keys from the surrounding grids
for _, grid := range grids {
grid.Entities.Range(func(_, value interface{}) bool {
result = append(result, value.(*Entity).Key)
return true
})
}
return result
}