├── README.md ├── Makefile ├── .gitignore ├── test.cpp ├── scene.h └── scene.cpp /README.md: -------------------------------------------------------------------------------- 1 | AOI 2 | === 3 | 4 | aoi algorithm 5 | see: 6 | http://www.codedump.info/?p=388 (in Chinese) -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all:test.cpp scene.cpp scene.h 2 | g++ -g -c scene.cpp -o scene.o 3 | g++ -g -c test.cpp -o test.o 4 | g++ -g test.o scene.o -o test 5 | 6 | clean: 7 | rm test *.o 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | 9 | # Compiled Static libraries 10 | *.lai 11 | *.la 12 | *.a 13 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "scene.h" 5 | 6 | int main() { 7 | int i = 0; 8 | Scene scene; 9 | 10 | srandom(time(NULL)); 11 | printf("\nbegin add object=============\n"); 12 | for (i = 0; i < 10; ++i) { 13 | scene.Add(i + 1, random() % 50, random() % 50); 14 | } 15 | 16 | printf("\nbegin move object=============\n"); 17 | for (i = 0; i < 100; ++i) { 18 | int x = random() % 50; 19 | int y = random() % 50; 20 | scene.Move(i % 10, x, y); 21 | } 22 | 23 | printf("\nbegin leave object=============\n"); 24 | for (i = 0; i < 10; ++i) { 25 | scene.Leave(i + 1); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /scene.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCENE_H__ 2 | #define __SCENE_H__ 3 | #include 4 | #include 5 | 6 | #define DISTANCE 5 7 | 8 | using namespace std; 9 | 10 | class Scene { 11 | public: 12 | Scene(); 13 | ~Scene(); 14 | 15 | void Add(int id, int x, int y, int distance = DISTANCE); 16 | void Move(int id, int x, int y); 17 | void Leave(int id); 18 | 19 | private: 20 | struct Object { 21 | int x; 22 | int y; 23 | int id; 24 | int radius; 25 | 26 | list::iterator x_pos; 27 | list::iterator y_pos; 28 | 29 | Object(int _id, int _x, int _y, int _radius) 30 | : id(_id) 31 | , x(_x) 32 | , y(_y) 33 | , radius(_radius) { 34 | } 35 | }; 36 | 37 | private: 38 | typedef map ObjMap; 39 | typedef list ObjList; 40 | 41 | void Update(Object *object); 42 | void GetRangeSet(Object *object, ObjMap *set); 43 | void UpdateObjectPosition(Object *object, int x, int y); 44 | 45 | private: 46 | ObjList obj_x_list_; 47 | ObjList obj_y_list_; 48 | ObjMap obj_set_; 49 | 50 | ObjMap move_set_; 51 | ObjMap enter_set_; 52 | ObjMap leave_set_; 53 | }; 54 | 55 | #endif // __SCENE_H__ 56 | -------------------------------------------------------------------------------- /scene.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "scene.h" 5 | 6 | Scene::Scene() { 7 | } 8 | 9 | Scene::~Scene() { 10 | ObjMap::iterator iter, tmp; 11 | for (iter = obj_set_.begin(); iter != obj_set_.end(); ) { 12 | tmp = iter; 13 | ++iter; 14 | delete tmp->second; 15 | } 16 | } 17 | 18 | void Scene::Update(Object *object) { 19 | ObjMap::iterator iter; 20 | 21 | // send ENTER msg 22 | for (iter = enter_set_.begin(); iter != enter_set_.end(); ++iter) { 23 | printf("send [%d, %d:%d]\t ENTER msg to obj [%d, %d:%d]\n", 24 | object->id, object->x, object->y, 25 | iter->first, iter->second->x, iter->second->y); 26 | printf("send [%d, %d:%d]\t ENTER msg to obj [%d, %d:%d]\n", 27 | iter->first, iter->second->x, iter->second->y, 28 | object->id, object->x, object->y); 29 | } 30 | // send MOVE msg 31 | for (iter = move_set_.begin(); iter != move_set_.end(); ++iter) { 32 | printf("send [%d, %d:%d]\t MOVE msg to obj [%d, %d:%d]\n", 33 | object->id, object->x, object->y, 34 | iter->first, iter->second->x, iter->second->y); 35 | } 36 | // send LEAVE msg 37 | for (iter = leave_set_.begin(); iter != leave_set_.end(); ++iter) { 38 | printf("send [%d, %d:%d]\t LEAVE msg to obj [%d, %d:%d]\n", 39 | object->id, object->x, object->y, 40 | iter->first, iter->second->x, iter->second->y); 41 | } 42 | // clean the move, leave, enter set 43 | enter_set_.clear(); 44 | move_set_.clear(); 45 | leave_set_.clear(); 46 | } 47 | 48 | void Scene::Add(int id, int x, int y, int distance) { 49 | if (obj_set_.find(id) != obj_set_.end()) { 50 | return; 51 | } 52 | Object *object = new Object(id, x, y, distance); 53 | obj_set_[object->id] = object; 54 | 55 | ObjList::iterator iter, pos; 56 | bool flag; 57 | ObjMap x_set; 58 | 59 | // iterator x-axis object list 60 | flag = false; 61 | for (iter = obj_x_list_.begin(); iter != obj_x_list_.end(); ++iter) { 62 | int diff = (*iter)->x - object->x; 63 | // into the x set 64 | if (abs(diff) <= distance) { 65 | x_set[(*iter)->id] = *iter; 66 | } 67 | if (!flag && diff > 0) { 68 | pos = iter; 69 | flag = true; 70 | } 71 | if (diff > distance) { 72 | break; 73 | } 74 | } 75 | if (flag) { 76 | obj_x_list_.insert(pos, object); 77 | object->x_pos = --pos; 78 | } else { 79 | obj_x_list_.push_front(object); 80 | object->x_pos = obj_x_list_.begin(); 81 | } 82 | 83 | // iterator y-axis object list 84 | flag = false; 85 | for (iter = obj_y_list_.begin(); iter != obj_y_list_.end(); ++iter) { 86 | int diff = (*iter)->y - object->y; 87 | // into the enter set 88 | if (abs(diff) <= distance && x_set.find((*iter)->id) != x_set.end()) { 89 | enter_set_[(*iter)->id] = *iter; 90 | } 91 | if (!flag && diff > 0) { 92 | pos = iter; 93 | flag = true; 94 | } 95 | if (diff > distance) { 96 | break; 97 | } 98 | } 99 | if (flag) { 100 | obj_y_list_.insert(pos, object); 101 | object->y_pos = --pos; 102 | } else { 103 | obj_y_list_.push_front(object); 104 | object->y_pos = obj_y_list_.begin(); 105 | } 106 | Update(object); 107 | } 108 | 109 | void Scene::UpdateObjectPosition(Object *object, int x, int y) { 110 | int old_x = object->x; 111 | int old_y = object->y; 112 | object->x = x; 113 | object->y = y; 114 | 115 | ObjList::iterator iter, pos; 116 | 117 | // find the new x pos 118 | if (x > old_x) { 119 | if (object->x_pos != obj_x_list_.end()) { 120 | iter = object->x_pos; 121 | ++iter; 122 | obj_x_list_.erase(object->x_pos); 123 | while (iter != obj_x_list_.end()) { 124 | if (object->x - (*iter)->x < 0) { 125 | pos = iter; 126 | break; 127 | } 128 | ++iter; 129 | } 130 | if (iter != obj_x_list_.end()) { 131 | obj_x_list_.insert(pos, object); 132 | object->x_pos = --pos; 133 | } else { 134 | obj_x_list_.push_back(object); 135 | object->x_pos = --obj_x_list_.end(); 136 | } 137 | } 138 | } else if (x < old_x) { 139 | if (object->x_pos != obj_x_list_.begin()) { 140 | iter = object->x_pos; 141 | --iter; 142 | obj_x_list_.erase(object->x_pos); 143 | while (iter != obj_x_list_.begin()) { 144 | if (object->x - (*iter)->x > 0) { 145 | pos = ++iter; 146 | break; 147 | } 148 | --iter; 149 | } 150 | if (iter != obj_x_list_.begin()) { 151 | obj_x_list_.insert(pos, object); 152 | object->x_pos = --pos; 153 | } else { 154 | obj_x_list_.push_front(object); 155 | object->x_pos = obj_x_list_.begin(); 156 | } 157 | } 158 | } 159 | 160 | // find the new y pos 161 | if (y > old_y) { 162 | if (object->y_pos != obj_y_list_.end()) { 163 | iter = object->y_pos; 164 | ++iter; 165 | obj_y_list_.erase(object->y_pos); 166 | while (iter != obj_y_list_.end()) { 167 | if (object->y - (*iter)->y < 0) { 168 | pos = iter; 169 | break; 170 | } 171 | ++iter; 172 | } 173 | if (iter != obj_y_list_.end()) { 174 | obj_y_list_.insert(pos, object); 175 | object->y_pos = --pos; 176 | } else { 177 | obj_y_list_.push_back(object); 178 | object->y_pos = --obj_y_list_.end(); 179 | } 180 | } 181 | } else if (y < old_y) { 182 | if (object->y_pos != obj_y_list_.begin()) { 183 | iter = object->y_pos; 184 | --iter; 185 | obj_y_list_.erase(object->y_pos); 186 | while (iter != obj_y_list_.begin()) { 187 | if (object->y - (*iter)->y > 0) { 188 | pos = ++iter; 189 | break; 190 | } 191 | --iter; 192 | } 193 | if (iter != obj_y_list_.begin()) { 194 | obj_y_list_.insert(pos, object); 195 | object->y_pos = --pos; 196 | } else { 197 | obj_y_list_.push_front(object); 198 | object->y_pos = obj_y_list_.begin(); 199 | } 200 | } 201 | } 202 | } 203 | 204 | void Scene::Move(int id, int x, int y) { 205 | ObjMap::iterator obj_iter = obj_set_.find(id); 206 | if (obj_iter == obj_set_.end()) { 207 | return; 208 | } 209 | Object *object = obj_iter->second; 210 | 211 | ObjList::iterator list_iter; 212 | ObjMap old_set, new_set; 213 | 214 | // get the old set 215 | GetRangeSet(object, &old_set); 216 | 217 | // update object position 218 | UpdateObjectPosition(object, x, y); 219 | 220 | // get the new set 221 | GetRangeSet(object, &new_set); 222 | 223 | // move_set = old_set MIX new_set 224 | ObjMap::iterator iter; 225 | for (iter = old_set.begin(); iter != old_set.end(); ++iter) { 226 | if (new_set.find(iter->first) != new_set.end()) { 227 | move_set_[iter->first] = iter->second; 228 | } 229 | } 230 | 231 | // leave_set = old_set SUB move_set 232 | for (iter = old_set.begin(); iter != old_set.end(); ++iter) { 233 | if (move_set_.find(iter->first) == move_set_.end()) { 234 | leave_set_[iter->first] = iter->second; 235 | } 236 | } 237 | 238 | // enter_set = new_set SUB move_set 239 | for (iter = new_set.begin(); iter != new_set.end(); ++iter) { 240 | if (move_set_.find(iter->first) == move_set_.end()) { 241 | enter_set_[iter->first] = iter->second; 242 | } 243 | } 244 | 245 | Update(object); 246 | } 247 | 248 | void Scene::GetRangeSet(Object *object, ObjMap *set) { 249 | ObjMap x_set; 250 | ObjList::iterator iter; 251 | int distance = object->radius; 252 | 253 | // iterator x-axis object list 254 | if (object->x_pos != obj_x_list_.end()) { 255 | iter = object->x_pos; 256 | while (1) { 257 | ++iter; 258 | if (iter == obj_x_list_.end()) { 259 | break; 260 | } 261 | if (object->x - (*iter)->x > distance) { 262 | break; 263 | } 264 | x_set[(*iter)->id] = *iter; 265 | } 266 | } 267 | if (object->x_pos != obj_x_list_.begin()) { 268 | iter = object->x_pos; 269 | while (1) { 270 | --iter; 271 | if ((*iter)->x - object->x > distance) { 272 | break; 273 | } 274 | x_set[(*iter)->id] = *iter; 275 | if (iter == obj_x_list_.begin()) { 276 | break; 277 | } 278 | } 279 | } 280 | 281 | // iterator y-axis object list 282 | if (object->y_pos != obj_y_list_.end()) { 283 | iter = object->y_pos; 284 | while (1) { 285 | ++iter; 286 | if (iter == obj_y_list_.end()) { 287 | break; 288 | } 289 | if (object->y - (*iter)->y > distance) { 290 | break; 291 | } 292 | if (x_set.find((*iter)->id) != x_set.end()) { 293 | (*set)[(*iter)->id] = *iter; 294 | } 295 | } 296 | } 297 | if (object->y_pos != obj_y_list_.begin()) { 298 | iter = object->y_pos; 299 | while (1) { 300 | --iter; 301 | if ((*iter)->y - object->y > distance) { 302 | break; 303 | } 304 | if (x_set.find((*iter)->id) != x_set.end()) { 305 | (*set)[(*iter)->id] = *iter; 306 | } 307 | if (iter == obj_y_list_.begin()) { 308 | break; 309 | } 310 | } 311 | } 312 | } 313 | 314 | void Scene::Leave(int id) { 315 | ObjMap::iterator obj_iter = obj_set_.find(id); 316 | if (obj_iter == obj_set_.end()) { 317 | return; 318 | } 319 | Object *object = obj_iter->second; 320 | 321 | // get the leave set 322 | GetRangeSet(object, &leave_set_); 323 | Update(object); 324 | 325 | obj_x_list_.erase(object->x_pos); 326 | obj_y_list_.erase(object->y_pos); 327 | obj_set_.erase(object->id); 328 | delete object; 329 | } 330 | --------------------------------------------------------------------------------