spacemap.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package tamias
  2. import "container/list"
  3. import "fmt"
  4. import "exp/iterable"
  5. // Spacemap is an alternative implementation of the spacehash
  6. type SpaceMapElement interface{
  7. GetBB() (*BB)
  8. }
  9. type SpaceMapKey uint64
  10. type SpaceMapCell struct {
  11. Shapes * list.List
  12. }
  13. type rawSpaceMap map[SpaceMapKey] SpaceMapCell
  14. type SpaceMap struct {
  15. table map[SpaceMapKey] SpaceMapCell;
  16. // Number of cells in the table.
  17. numcells int
  18. // Dimensions of the cells.
  19. cellsize Float
  20. // Incremented on every query
  21. stamp int
  22. }
  23. func (cell * SpaceMapCell) Init() (* SpaceMapCell) {
  24. cell.Shapes = list.New()
  25. return cell
  26. }
  27. // Find finds a space map element in a cell, or return nil if not found
  28. func (cell * SpaceMapCell) Find(el SpaceMapElement) (SpaceMapElement){
  29. finder := func (val interface {}) (bool) {
  30. testel := val.(SpaceMapElement)
  31. return el == testel
  32. }
  33. found := iterable.Find((cell.Shapes), finder)
  34. if found == nil { return nil }
  35. return found.(SpaceMapElement)
  36. }
  37. // Removes as space map element from a space map cell and removes it,
  38. // or return nil if not found
  39. func (cell * SpaceMapCell) Remove(el SpaceMapElement) (SpaceMapElement) {
  40. var e *list.Element
  41. for e = cell.Shapes.Front() ; e != nil ; e = e.Next() {
  42. val := e.Value
  43. if val.(SpaceMapElement) == el {
  44. cell.Shapes.Remove(e)
  45. return el
  46. }
  47. }
  48. return nil
  49. }
  50. // Insert inserts a space map element into the cell
  51. func (cell * SpaceMapCell) Insert(el SpaceMapElement) (SpaceMapElement) {
  52. cell.Shapes.PushBack(el)
  53. return el
  54. }
  55. func (cell * SpaceMapCell) String() (string) {
  56. return fmt.Sprint("SpaceMap: ", iterable.Data(cell.Shapes))
  57. }
  58. // SpaceMapAllocate allocates a new spacemap and returns a pointer to it
  59. func SpaceMapAllocate() (* SpaceMap) {
  60. return &SpaceMap{}
  61. }
  62. // Init initializes the SpaceMap with the given cell size and amount of cells
  63. func (sm * SpaceMap) Init(cellsize Float, numcells int) (*SpaceMap) {
  64. sm.numcells = numcells
  65. sm.cellsize = cellsize
  66. sm.table = make(rawSpaceMap, sm.numcells)
  67. for i := 0; i < sm.numcells ; i++ {
  68. cell, ok := sm.table[SpaceMapKey(i)]
  69. if !ok {
  70. cell = SpaceMapCell{}
  71. cell.Init()
  72. sm.table[SpaceMapKey(i)] = cell
  73. }
  74. cell.Init()
  75. }
  76. return sm
  77. }
  78. func SpaceMapNew(cellsize Float, numcells int) (*SpaceMap) {
  79. return new(SpaceMap).Init(cellsize, numcells)
  80. }
  81. // The hash function itself.
  82. func space_hash(x, y, n uint64) (SpaceMapKey) {
  83. return SpaceMapKey((x*1640531513 ^ y*2654435789) % n)
  84. }
  85. // cellDimensions finds the dimensions of a bounds box in cell coordinates.
  86. // Returns them in order left, top, right, bottom
  87. func (sm * SpaceMap) cellDimensions(bb * BB) (int, int, int, int) {
  88. dim := sm.cellsize
  89. // Fix by ShiftZ
  90. l := (bb.L / dim).floor_int()
  91. t := (bb.T / dim).floor_int()
  92. r := (bb.R / dim).floor_int()
  93. b := (bb.B / dim).floor_int()
  94. return l, t, r, b
  95. }
  96. // Insert inserts an element into the SpaceMap
  97. func (sm * SpaceMap) Insert(el SpaceMapElement) (SpaceMapElement) {
  98. bb := el.GetBB()
  99. l, t, r, b := sm.cellDimensions(bb)
  100. fmt.Println("Insert!", l, "->", r, " & ", t,"->", b)
  101. // the bounds box may be in several cells, so iterate over them
  102. for i := l ; i <= r ; i++ {
  103. for j := b ; j <= t ; j++ {
  104. cell := sm.FindPoint(i, j)
  105. old := cell.Find(el)
  106. if old != nil { fmt.Println("Skip!", i, j); continue }
  107. // Already in this spatial cell. Move on to the next one
  108. fmt.Println("Inserting element: ", i, j)
  109. cell.Insert(el)
  110. // Add it to this cell.
  111. }
  112. }
  113. return el
  114. }
  115. // Looks up the SpaceMapCell that the point with coordinates X and Y is in.
  116. // returns nil if not found
  117. func (sm * SpaceMap) FindPoint(x, y int) (*SpaceMapCell) {
  118. xx := uint64(x)
  119. yy := uint64(y)
  120. hk := space_hash(xx, yy, uint64(sm.numcells))
  121. fmt.Println("hk: ", hk)
  122. cell := sm.table[hk]
  123. return &cell
  124. }
  125. // Looks up the SpaceMapCell that the vector is in
  126. func (sm * SpaceMap) FindVect(p Vect) (*SpaceMapCell) {
  127. return sm.FindPoint( int(p.X.Floor()), int(p.Y.Floor()) )
  128. }
  129. // Returns a vector with all SpaceMapElements in the given bounds box.
  130. // Or returns nil if nothing was found
  131. func (sm * SpaceMap) FindBB(bb *BB) (* list.List) {
  132. result := list.New()
  133. num := 0
  134. l, t, r, b := sm.cellDimensions(bb)
  135. // the bounds box may be in several cells, so iterate over them
  136. for i := l ; i <= r ; i++ {
  137. for j := t ; j <= b ; j++ {
  138. cell := sm.FindPoint(i, j)
  139. for found := range cell.Shapes.Iter() {
  140. result.PushBack(found)
  141. num++
  142. }
  143. }
  144. }
  145. if num < 1 { return nil }
  146. return result
  147. }
  148. // RehashObject moves the object to the right hash bucket.
  149. // Call this after it has moved.
  150. func (sm * SpaceMap) RehashObject(el SpaceMapElement) {
  151. }
  152. func (sm * SpaceMap) String() (string) {
  153. return fmt.Sprint("SpaceMap: ", sm.table )
  154. }