Collision Checker
container_grid_inl.h
Go to the documentation of this file.
1 #ifndef CPP_COLLISION_INCLUDE_COLLISION_GRID_VIRTUAL_H_
2 #define CPP_COLLISION_INCLUDE_COLLISION_GRID_VIRTUAL_H_
3 
4 #include <stdint.h>
7 
14 
15 namespace collision {
16 namespace detail {
17 namespace accelerators {
18 
19 template <class DIRECTION = HorizontalGrid>
20 inline AABB getAABB(const CollisionObject* obj) {
22  AABB a = (static_cast<const RectangleOBB*>(obj))->getAABB_fast();
23  return a;
24  } else {
25  auto aabb_fcl = obj->getAABB();
26  return AABB(*aabb_fcl);
27  }
28 }
29 
30 template <class DIRECTION = HorizontalGrid>
31 inline AABB getAABB(const ShapeGroup* sg_ptr) {
32  auto sg_aabb = sg_ptr->getAABB();
33  return AABB(*sg_aabb);
34 }
35 
37  AABB& bounds, int& orientation) {
38  bounds = getAABB<HorizontalGrid>(sg_ptr);
39  if (bounds.x_max - bounds.x_min > bounds.y_max - bounds.y_min) {
40  orientation = 0;
41  } else {
42  orientation = 1;
43  }
44  return 0;
45 }
46 
49  int& orientation) {
50  double min_x = std::numeric_limits<double>::max();
51  double max_x = std::numeric_limits<double>::min();
52  double min_y = std::numeric_limits<double>::max();
53  double max_y = std::numeric_limits<double>::min();
54  if (objects_in.size() == 0) {
55  min_x = 0;
56  max_x = 0;
57  min_y = 0;
58  max_y = 0;
59  }
60 
61  for (auto obj : objects_in) {
62  AABB aabb = getAABB(obj);
63 
64  min_x = std::min(min_x, aabb.x_min);
65  min_y = std::min(min_y, aabb.y_min);
66  max_x = std::max(max_x, aabb.x_max);
67  max_y = std::max(max_y, aabb.y_max);
68  }
69 
70  bounds = AABB(min_x, max_x, min_y, max_y);
71  if (bounds.x_max - bounds.x_min > bounds.y_max - bounds.y_min) {
72  orientation = 0;
73  } else {
74  orientation = 1;
75  bounds.swapAxes();
76  }
77  return 0;
78 }
79 
80 class GridCell {
81  public:
83  objects.push_back(obj);
84  return 0;
85  }
86 
88  std::set<CollisionObject*>& candidates) {
89  for (auto obj : objects) {
90  if (proxy.mask & obj.mask) {
91  candidates.insert(obj.obj_ptr);
92  }
93  }
94  return 0;
95  }
96 
97  std::vector<ObjectProxy> objects;
98 };
99 
100 typedef Eigen::Matrix<uint64_t, Eigen::Dynamic, 1> VectorXi64;
101 
102 template <class DIRECTION = HorizontalGrid>
103 class ContainerGrid {
104  public:
105  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
106  ContainerGrid(AABB* rotated_bounds, const ContainerSettings& sett) {
107  constructHelper(rotated_bounds->x_min, rotated_bounds->x_max,
108  rotated_bounds->y_min, rotated_bounds->y_max, sett);
109  }
110 
111  ContainerGrid(const ShapeGroup* sg_ptr, AABB* rotated_bounds,
112  const ContainerSettings& sett) {
113  constructHelper(rotated_bounds->x_min, rotated_bounds->x_max,
114  rotated_bounds->y_min, rotated_bounds->y_max, sett);
115  for (auto obj : sg_ptr->unpack()) {
116  addObject(obj.get());
117  }
118  finalizeCreation();
119  }
120 
122  AABB* rotated_bounds, const ContainerSettings& sett) {
123  constructHelper(rotated_bounds->x_min, rotated_bounds->x_max,
124  rotated_bounds->y_min, rotated_bounds->y_max, sett);
125 
126  for (auto obj : objects_in) {
127  addObject(obj);
128  }
129  finalizeCreation();
130  };
131 
132  int addObject(const CollisionObject* obj) {
134  AABB aabb = getAABB(obj);
135 
136  int cell_start = getCell_first(aabb.x_min);
137  int cell_end = getCell_first(aabb.x_max);
138  registerObjectId(obj);
139  aabbs_.push_back(aabb);
140  aabbs_2_.emplace_back(aabb);
141 
142  ObjectProxy proxy = CreateProxy(obj, aabbs_.back());
143  for (int i = cell_start; i <= cell_end; i++) {
144  cells_[i].addObject(proxy);
145  }
146  return 0;
147  }
148  return -1;
149  }
150 
151  int numcands() const { return numcands_; }
152 
153  int numchecks() const { return numchecks_; }
154 
156  const ContainerCollisionRequest& req) {
157  bool res = false;
158  bool skip_obb_bbox = !req.test_obb_bbox;
160  AABB aabb = getAABB(obj);
161  AABB_SAT2D aabb2(aabb);
162 
163  int cell_start = getCell_first(aabb.x_min);
164  int cell_end = getCell_first(aabb.x_max);
165  ObjectProxy proxy = CreateProxy(obj, aabb);
167  aligned_vector<int> collision_candidates;
168  aligned_vector<int> collision_candidates2;
169 
170  {
172 
173  for (int i = cell_start; i <= cell_end; i++) {
174  numchecks_ += cells_[i].objects.size();
175  getCandidates(proxy, i, collision_candidates);
176  }
177  }
178  if (req.enable_verification) {
179  aligned_vector<int> collision_candidates2;
180  {
181  for (int i = 0; i < objects_optimized_id_.size(); i++) {
182  // ground truth collisions between AABBs excluding border collisions
183  if (AABB_SAT2D(getAABB(object_by_id_[objects_optimized_id_[i]]))
184  .collides_eps(AABB_SAT2D(aabb), -1e-11)) {
185  collision_candidates2.push_back(objects_optimized_id_[i]);
186  }
187  }
188  }
189 
190  std::sort(collision_candidates2.begin(), collision_candidates2.end());
191  std::set<int> collision_candidates_set;
192  for (auto el : collision_candidates) {
193  collision_candidates_set.insert(el);
194  }
195  std::sort(collision_candidates.begin(), collision_candidates.end());
196  int found_count = std::unique(collision_candidates.begin(),
197  collision_candidates.end()) -
198  collision_candidates.begin();
199  int real_count = std::unique(collision_candidates2.begin(),
200  collision_candidates2.end()) -
201  collision_candidates2.begin();
202 
203  volatile int missed = real_count - found_count;
204 
205  bool bMissed = false;
206 
207  for (auto el : collision_candidates2) {
208  if (collision_candidates_set.find(el) ==
209  collision_candidates_set.end()) {
210  bMissed = true;
211  break;
212  }
213  }
214 
215  if (missed > 0 || bMissed) {
216  std::cout << "broadphase verification: miss\n";
217  throw std::exception();
218  return -1;
219  }
220  }
221 
222  {
223  volatile STACK_TIMER tim(TIMER_grid_narrowphase);
224  collision_checked_id_.fill(0);
225  int numcands_local = 0;
226  if (obj->getCollisionObjectType() == OBJ_TYPE_OBB_BOX && all_obbs_) {
227  const RectangleOBB* obb1 = static_cast<const RectangleOBB*>(obj);
228  std::vector<OBB_SAT2D, Eigen::aligned_allocator<OBB_SAT2D>>
229  obb1_fast_container;
230  obb1_fast_container.emplace_back(obb1->center(), obb1->r_x() * 2,
231  obb1->r_y() * 2, obb1->local_x_axis(),
232  obb1->local_y_axis());
233 
234  for (auto el : collision_candidates) {
235  if ((el < 0) || (el >= fast_obbs_.size())) {
236  std::cout << "internal error";
237  throw std::exception();
238  }
239 
240  if (!collision_checked_id_(el)) {
241  collision_checked_id_(el) = 1;
242  numcands_local += 1;
243 
244  if (skip_obb_bbox || aabbs_2_[el].collides(aabb2)) {
245  if (fast_obbs_[el].overlaps(*(obb1_fast_container.begin()))) {
246  numcands_ += numcands_local;
247  return 1;
248  }
249  }
250  }
251  }
252  } else if (optimize_triangles_ &&
254  all_triangles_) {
255  const RectangleOBB* obb1 = static_cast<const RectangleOBB*>(obj);
256  std::vector<OBB_SAT2D, Eigen::aligned_allocator<OBB_SAT2D>>
257  obb1_fast_container;
258  obb1_fast_container.emplace_back(obb1->center(), obb1->r_x() * 2,
259  obb1->r_y() * 2, obb1->local_x_axis(),
260  obb1->local_y_axis());
261 
262  for (auto el : collision_candidates) {
263  if (!collision_checked_id_(el)) {
264  collision_checked_id_(el) = 1;
265 
266  numcands_local += 1;
267 
268  if (aabbs_2_[el].collides(aabb2)) {
269  collision_candidates2.push_back(el);
270  }
271  }
272  }
273  for (auto el : collision_candidates2) {
274  if (sat2dChecks::overlaps(fast_triangles_[el],
275  (*(obb1_fast_container.begin())))) {
276  numcands_ += numcands_local;
277  return 1;
278  }
279  }
280  } else {
281  for (auto el : collision_candidates) {
282  if (!collision_checked_id_(el)) {
283  collision_checked_id_(el) = 1;
284 
285  numcands_local += 1;
286 
287  if (aabbs_2_[el].collides(aabb2)) {
288  collision_candidates2.push_back(el);
289  }
290  }
291  }
292  for (auto el : collision_candidates2) {
293  if (object_by_id_[el]->collide(*obj)) {
294  numcands_ += numcands_local;
295  return 1;
296  }
297  }
298  }
299  numcands_ += numcands_local;
300  }
301  return 0;
302  }
303  int windowQuery(AABB& aabb, aligned_vector<int>& candidates) {
305  AABB_SAT2D aabb2(aabb);
306  int cell_start = getCell_first(aabb.x_min);
307  int cell_end = getCell_first(aabb.x_max);
308  ObjectProxy proxy = CreateProxy(0, aabb);
309  aligned_vector<int> collision_candidates;
311  {
313 
314  for (int i = cell_start; i <= cell_end; i++) {
315  numchecks_ += cells_[i].objects.size();
316  getCandidates(proxy, i, collision_candidates);
317  }
318  }
319  collision_checked_id_.fill(0);
320  int numcands_local = 0;
321  for (auto el : collision_candidates) {
322  if (!collision_checked_id_(el)) {
323  collision_checked_id_(el) = 1;
324 
325  if (aabbs_2_[el].collides(aabb2)) {
326  numcands_local += 1;
327  candidates.push_back(el);
328  }
329  }
330  }
331  numcands_ += numcands_local;
332  return 0;
333  }
334 
335  private:
336  inline int getCandidates(ObjectProxy& proxy, int cell_ind,
337  aligned_vector<int>& candidates) {
338  uint64_t proxy_mask = proxy.mask;
339 
340  int cell_start_idx = cell_start_[cell_ind];
341  int cell_end_idx = cell_end_[cell_ind];
342  if (cell_end_idx < cell_start_idx) return 0;
343  auto object_iterator = objects_optimized_id_.begin() + cell_start_idx;
344  uint64_t* mask_iterator = masks_optimized_.data() + cell_start_idx;
345 
346  for (int obj_idx = cell_start_idx; obj_idx <= cell_end_idx; obj_idx++) {
347  if (*mask_iterator & proxy_mask) {
348  candidates.push_back(*object_iterator);
349  }
350  object_iterator++;
351  mask_iterator++;
352  }
353  return 0;
354  }
355 
356  inline int getObjectId(const collision::CollisionObject* obj) {
357  auto search = object_ids_.find(obj);
358  if (search != object_ids_.end()) {
359  return search->second;
360  } else
361  throw std::exception();
362  }
363 
364  inline int finalizeCreation(void) {
365  cell_start_.resize(cells_.size());
366  cell_end_.resize(cells_.size());
367  int total_objects = 0;
368  for (auto cell : cells_) {
369  total_objects += cell.objects.size();
370  }
371  objects_optimized_id_.clear();
372  object_by_id_.clear();
373  object_by_id_.resize(object_ids_.size());
374  collision_checked_id_ = Eigen::VectorXi::Zero(object_ids_.size());
375 
376  masks_optimized_ = VectorXi64::Zero(total_objects);
377  res_mask_optimized_ = Eigen::VectorXi::Zero(total_objects);
378 
379  all_obbs_ = true;
380  all_triangles_ = optimize_triangles_;
381 
382  for (int i = 0; i < cells_.size(); i++) {
383  cell_start_[i] = objects_optimized_id_.size();
384  for (auto el : cells_[i].objects) {
385  if (all_obbs_ &&
386  el.obj_ptr->getCollisionObjectType() != OBJ_TYPE_OBB_BOX) {
387  all_obbs_ = false;
388  }
389 
390  if (all_triangles_ &&
391  el.obj_ptr->getCollisionObjectType() != OBJ_TYPE_TRIANGLE) {
392  all_triangles_ = false;
393  }
394 
395  objects_optimized_id_.push_back(getObjectId(el.obj_ptr));
396  object_by_id_[objects_optimized_id_.back()] = el.obj_ptr;
397  masks_optimized_[objects_optimized_id_.size() - 1] = el.mask;
398  }
399  cell_end_[i] = objects_optimized_id_.size() - 1;
400  }
401  return 0;
402  }
403 
404  inline uint64_t get_mask(const AABB& obj) {
405  int cell_second_start = getCell_second(obj.y_min);
406  int cell_second_end = getCell_second(obj.y_max);
407  uint64_t mask = 0;
408  uint64_t cur_one = (uint64_t)0x1 << cell_second_start;
409  for (int i = cell_second_start; i <= cell_second_end; i++) {
410  mask |= cur_one;
411  cur_one <<= 1;
412  }
413  return mask;
414  }
415 
416  inline ObjectProxy CreateProxy(const CollisionObject* obj,
417  const collision::AABB& aabb) {
418  uint64_t mask = get_mask(aabb);
419  return ObjectProxy{mask, const_cast<CollisionObject*>(obj)};
420  // return ObjectProxy{mask,const_cast<CollisionObject*>(obj), aabb};
421  }
422 
423  int registerObjectId(const CollisionObject* obj) {
424  object_ids_.insert(std::make_pair(obj, (int)object_ids_.size()));
426  const collision::RectangleOBB* obb_in =
427  static_cast<const collision::RectangleOBB*>(obj);
428 
429  fast_obbs_.emplace_back(obb_in->center(), obb_in->r_x() * 2,
430  obb_in->r_y() * 2, obb_in->local_x_axis(),
431  obb_in->local_y_axis());
432  }
433  if (optimize_triangles_) {
435  const collision::Triangle* tri_in =
436  static_cast<const collision::Triangle*>(obj);
437 
438  fast_triangles_.emplace_back(*tri_in);
439  }
440  }
441  return 0;
442  }
443 
444  static inline AABB getAABB(const CollisionObject* obj) {
446  AABB a = (static_cast<const RectangleOBB*>(obj))->getAABB_fast();
447  return a;
448  } else {
449  auto aabb_fcl = obj->getAABB();
450  return AABB(*aabb_fcl);
451  }
452  }
453 
454  inline int getCell_first(double first) {
455  if (first < first_start_) return 0;
456  if (first >= first_end_) return cells_.size() - 1;
457  return std::floor((first - first_start_) * inv_cell_size_first_) + 1;
458  }
459 
460  inline int getCell_second(double second) {
461  if (second < second_start_) return 0;
462  if (second >= second_end_) return cells_second_size_full - 1;
463  return std::floor((second - second_start_) * inv_cell_size_second_) + 1;
464  }
465 
466  static constexpr int cells_second_size = 62;
467  static constexpr int cells_second_size_full = cells_second_size + 2;
468  std::vector<GridCell> cells_;
469  std::vector<AABB> aabbs_;
470  std::vector<AABB_SAT2D> aabbs_2_;
471 
472  VectorXi64 masks_optimized_;
473  Eigen::VectorXi res_mask_optimized_;
474  aligned_vector<int> objects_optimized_id_;
475  aligned_vector<CollisionObject*> object_by_id_;
476  std::vector<OBB_SAT2D, Eigen::aligned_allocator<OBB_SAT2D>> fast_obbs_;
477  Eigen::VectorXi collision_checked_id_;
478 
479  std::map<const CollisionObject*, int> object_ids_;
480 
481  aligned_vector<int> cell_start_;
482  aligned_vector<int> cell_end_;
483 
484  std::vector<Triangle_SAT2D, Eigen::aligned_allocator<Triangle_SAT2D>>
485  fast_triangles_;
486  bool all_obbs_;
487  bool all_triangles_;
488 
489  bool optimize_triangles_;
490 
491  int numcells_;
492  double inv_cell_size_first_;
493  double inv_cell_size_second_;
494  double first_start_;
495  double first_end_;
496  double gridlen_;
497  double second_start_;
498  double second_end_;
499  double gridlen_second_;
500 
501  int numchecks_;
502  int numcands_;
503 
504  void constructHelper(double x_start, double x_end, double y_start,
505  double y_end, const ContainerSettings& sett) {
506  numcells_ = sett.num_cells;
507  cells_.resize(numcells_ + 2);
508  first_end_ = x_end;
509  first_start_ = x_start;
510  gridlen_ = first_end_ - first_start_;
511  second_end_ = y_end;
512  second_start_ = y_start;
513  gridlen_second_ = second_end_ - second_start_;
514  numchecks_ = 0;
515  numcands_ = 0;
516  inv_cell_size_first_ = (double)numcells_ / gridlen_;
517  inv_cell_size_second_ = (double)cells_second_size / gridlen_second_;
518  optimize_triangles_ = sett.optimize_triangles;
519  }
520 };
521 } // namespace accelerators
522 } // namespace detail
523 } // namespace collision
524 
525 #endif /* CPP_COLLISION_INCLUDE_COLLISION_GRID_VIRTUAL_H_ */
Eigen::Vector2d local_y_axis() const
ContainerGrid(const ShapeGroup *sg_ptr, AABB *rotated_bounds, const ContainerSettings &sett)
Oriented rectangle.
Definition: rectangle_obb.h:19
#define TIMER_START(x)
Definition: application.h:47
std::vector< T, boost::alignment::aligned_allocator< T, 16 > > aligned_vector
Definition: declarations.h:9
int getBestGridOrientationAndBounds(const ShapeGroup *sg_ptr, AABB &bounds, int &orientation)
double y_min
Definition: aabb.h:11
#define TIMER_grid_narrowphase
Definition: application.h:35
ContainerGrid(aligned_vector< collision::CollisionObject *> objects_in, AABB *rotated_bounds, const ContainerSettings &sett)
virtual CollisionObjectClass getCollisionObjectClass() const
Triangle.
Definition: triangle.h:17
std::vector< ShapeConstPtr > unpack() const
Returns Vector of all shapes contained inside the ShapeGroup.
Definition: shape_group.cc:187
Eigen::Matrix< uint64_t, Eigen::Dynamic, 1 > VectorXi64
std::shared_ptr< const collision::RectangleAABB > getAABB() const
Definition: shape_group.cc:21
bool collides_eps(const AABB_SAT2D &other, double eps)
Definition: aabb_sat2d.h:36
ShapeGroup can contain simple shapes.
Definition: shape_group.h:33
#define TIMER_grid_hashing
Definition: application.h:37
AABB getAABB(const CollisionObject *obj)
int checkCollision(const CollisionObject *obj, const ContainerCollisionRequest &req)
int orientation(Point p, Point q, Point r)
virtual CollisionObjectType getCollisionObjectType() const
#define TIMER_STOP(x)
Definition: application.h:48
int windowQuery(AABB &aabb, aligned_vector< int > &candidates)
double x_max
Definition: aabb.h:10
double x_min
Definition: aabb.h:9
int getCandidates(ObjectProxy &proxy, std::set< CollisionObject *> &candidates)
virtual std::shared_ptr< const collision::RectangleAABB > getAABB() const =0
Base class for CollisionObjects and some of their groups.
Eigen::Vector2d local_x_axis() const
EIGEN_MAKE_ALIGNED_OPERATOR_NEW ContainerGrid(AABB *rotated_bounds, const ContainerSettings &sett)
void swapAxes(void)
Definition: aabb.h:33
bool overlaps(const Triangle_SAT2D &tri, const OBB_SAT2D &obb)
Definition: sat2d_checks.cc:56
#define TIMER_grid_candidates
Definition: application.h:34
Eigen::Vector2d center() const
Get geometric center of shape.
Definition: shape.cc:16
double y_max
Definition: aabb.h:12
#define STACK_TIMER
Definition: application.h:11