Collision Checker
container_box2d_inl.h
Go to the documentation of this file.
1 #ifndef CPP_COLLISION_INCLUDE_COLLISION_GRID_BOX2D_H_
2 #define CPP_COLLISION_INCLUDE_COLLISION_GRID_BOX2D_H_
3 
4 #include <stdint.h>
8 
9 #include <box2d/b2_dynamic_tree.h>
10 #include <boost/align/aligned_allocator.hpp>
11 
18 
19 template <typename T>
20 using aligned_vector =
21  std::vector<T, boost::alignment::aligned_allocator<T, 16>>;
22 
23 namespace collision {
24 namespace detail {
25 namespace accelerators {
27  public:
29  : candidates_(&candidates){
30 
31  };
32  bool QueryCallback(int obj_id) {
33  candidates_->push_back(obj_id);
34  return true;
35  }
36 
38 };
39 
40 typedef Eigen::Matrix<uint64_t, Eigen::Dynamic, 1> VectorXi64;
41 
43  public:
44  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
45 
47  const ContainerSettings& sett) {
48  constructHelper();
49 
50  for (auto obj : objects_in) {
51  addObject(obj);
52  }
53  double min_x = std::numeric_limits<double>::max();
54  double max_x = std::numeric_limits<double>::min();
55  double min_y = std::numeric_limits<double>::max();
56  double max_y = std::numeric_limits<double>::min();
57  for (auto obj : objects_in) {
58  AABB aabb = getAABB(obj);
59 
60  min_x = std::min(min_x, aabb.x_min);
61  min_y = std::min(min_y, aabb.y_min);
62  max_x = std::max(max_x, aabb.x_max);
63  max_y = std::max(max_y, aabb.y_max);
64  }
65 
66  broadphase_manager_ = new b2DynamicTree();
67 
68  finalizeCreation();
69  }
70 
71  ContainerBox2D(const ShapeGroup* sg_ptr, const ContainerSettings& sett) {
72  constructHelper();
73  for (auto obj : sg_ptr->unpack()) {
74  addObject(obj.get());
75  }
76 
77  auto sg_aabb = sg_ptr->getAABB();
78  double min_x = sg_aabb->min()(0);
79  double min_y = sg_aabb->min()(1);
80  double max_x = sg_aabb->max()(0);
81  double max_y = sg_aabb->max()(1);
82 
83  broadphase_manager_ = new b2DynamicTree();
84 
85  finalizeCreation();
86  }
87 
88  virtual ~ContainerBox2D() {
89  if (broadphase_manager_) delete broadphase_manager_;
90  }
91 
92  int addObject(const CollisionObject* obj) {
94  AABB aabb = getAABB(obj);
95 
96  registerObjectId(obj);
97  aabbs_.push_back(aabb);
98  ObjectProxy proxy = CreateProxy(obj, aabbs_.back());
99  objects_.push_back(proxy);
100  return 0;
101  }
102  return -1;
103  }
104 
105  inline int checkCollision(const CollisionObject* obj,
106  const ContainerCollisionRequest& req) {
107  bool res = false;
109  AABB aabb = getAABB(obj);
110 
111  ObjectProxy proxy = CreateProxy(obj, aabb);
113  aligned_vector<int> collision_candidates;
114 
115  {
117 
118  numchecks_ += objects_.size();
119  getCandidates(proxy, collision_candidates);
120  }
121  if (req.enable_verification) {
122  aligned_vector<int> collision_candidates2;
123  {
124  for (int i = 0; i < objects_optimized_id_.size(); i++) {
125  // ground truth collisions between AABBs including border collisions
126  if (AABB_SAT2D(getAABB(object_by_id_[objects_optimized_id_[i]]))
127  .collides_eps(AABB_SAT2D(aabb), -1e-11)) {
128  collision_candidates2.push_back(objects_optimized_id_[i]);
129  }
130  }
131  }
132 
133  std::sort(collision_candidates2.begin(), collision_candidates2.end());
134  std::set<int> collision_candidates_set;
135  for (auto el : collision_candidates) {
136  collision_candidates_set.insert(el);
137  }
138  std::sort(collision_candidates.begin(), collision_candidates.end());
139  int found_count = std::unique(collision_candidates.begin(),
140  collision_candidates.end()) -
141  collision_candidates.begin();
142  int real_count = std::unique(collision_candidates2.begin(),
143  collision_candidates2.end()) -
144  collision_candidates2.begin();
145 
146  volatile int missed = real_count - found_count;
147 
148  bool bMissed = false;
149 
150  for (auto el : collision_candidates2) {
151  if (collision_candidates_set.find(el) ==
152  collision_candidates_set.end()) {
153  bMissed = true;
154  break;
155  }
156  }
157 
158  if (missed > 0 || bMissed) {
159  std::cout << "broadphase verification: miss\n";
160  throw std::exception();
161  return -1;
162  }
163  }
164  {
166  collision_checked_id_.fill(0);
167  int numcands_local = 0;
168  if (obj->getCollisionObjectType() == OBJ_TYPE_OBB_BOX && all_obbs_) {
169  const RectangleOBB* obb1 = static_cast<const RectangleOBB*>(obj);
170  std::vector<OBB_SAT2D, Eigen::aligned_allocator<OBB_SAT2D>>
171  obb1_fast_container;
172  obb1_fast_container.emplace_back(obb1->center(), obb1->r_x() * 2,
173  obb1->r_y() * 2, obb1->local_x_axis(),
174  obb1->local_y_axis());
175 
176  for (auto el : collision_candidates) {
177  if ((el < 0) || (el >= fast_obbs_.size())) {
178  std::cout << "internal error";
179  throw std::exception();
180  }
181  if (!collision_checked_id_(el)) {
182  collision_checked_id_(el) = 1;
183  numcands_local += 1;
184  if (fast_obbs_[el].overlaps(*(obb1_fast_container.begin())))
185 
186  {
187  numcands_ += numcands_local;
188  return 1;
189  }
190  }
191  }
192  } else {
193  for (auto el : collision_candidates) {
194  if (!collision_checked_id_(el)) {
195  numcands_local += 1;
196  collision_checked_id_(el) = 1;
197 
198  if (object_by_id_[el]->collide(*obj)) {
199  numcands_ += numcands_local;
200  return 1;
201  }
202  }
203  }
204  }
205  numcands_ += numcands_local;
206  }
207  return 0;
208  }
209 
210  inline int numchecks() const { return numchecks_; }
211 
212  inline int numcands() const { return numcands_; }
213 
214  private:
215  b2DynamicTree* broadphase_manager_;
216 
217  std::vector<AABB> aabbs_;
218  std::vector<b2AABB> box2d_objects_;
219 
220  std::vector<ObjectProxy> objects_;
221 
222  VectorXi64 masks_optimized_;
223  Eigen::VectorXi res_mask_optimized_;
224  aligned_vector<int> objects_optimized_id_;
225  aligned_vector<CollisionObject*> object_by_id_;
226  std::vector<OBB_SAT2D, Eigen::aligned_allocator<OBB_SAT2D>> fast_obbs_;
227  Eigen::VectorXi collision_checked_id_;
228 
229  std::map<const CollisionObject*, int> object_ids_;
230 
231  bool all_obbs_;
232 
233  int numchecks_;
234  int numcands_;
235 
236  void constructHelper(void) {
237  numchecks_ = 0;
238  numcands_ = 0;
239  broadphase_manager_ = 0;
240  }
241 
242  inline int finalizeCreation(void) {
243  int total_objects = 0;
244  total_objects += objects_.size();
245 
246  objects_optimized_id_.clear();
247  object_by_id_.clear();
248  object_by_id_.resize(object_ids_.size());
249  collision_checked_id_ = Eigen::VectorXi::Zero(object_ids_.size());
250 
251  masks_optimized_ = VectorXi64::Zero(total_objects);
252  res_mask_optimized_ = Eigen::VectorXi::Zero(total_objects);
253 
254  all_obbs_ = true;
255  for (auto el : objects_) {
256  if (all_obbs_ &&
257  el.obj_ptr->getCollisionObjectType() != OBJ_TYPE_OBB_BOX) {
258  all_obbs_ = false;
259  }
260 
261  objects_optimized_id_.push_back(getObjectId(el.obj_ptr));
262  object_by_id_[objects_optimized_id_.back()] = el.obj_ptr;
263  masks_optimized_[objects_optimized_id_.size() - 1] = el.mask;
264  auto curAABB = &aabbs_[objects_optimized_id_.back()];
266  (curAABB->x_max - curAABB->x_min) / 2,
267  (curAABB->y_max - curAABB->y_min) / 2,
268  Eigen::Vector2d((curAABB->x_max + curAABB->x_min) / 2,
269  (curAABB->y_max + curAABB->y_min) / 2)));
270  box2d_objects_.emplace_back();
271  float eps = 1e-5;
272  box2d_objects_.back().lowerBound =
273  b2Vec2(curAABB->x_min - eps, curAABB->y_min - eps);
274  box2d_objects_.back().upperBound =
275  b2Vec2(curAABB->x_max + eps, curAABB->y_max + eps);
276  }
277  for (auto id : objects_optimized_id_) {
278  broadphase_manager_->CreateProxy(box2d_objects_[id],
279  &objects_optimized_id_[id]);
280  }
281 
282  return 0;
283  }
284 
285  inline int getCandidates(ObjectProxy& proxy,
286  aligned_vector<int>& candidates) {
287  AABB curAABB = getAABB(proxy.obj_ptr);
288  b2AABB b2Obj;
289  float eps = 1e-5;
290  b2Obj.lowerBound = b2Vec2(curAABB.x_min - eps, curAABB.y_min - eps);
291  b2Obj.upperBound = b2Vec2(curAABB.x_max + eps, curAABB.y_max + eps);
292  aligned_vector<int> candidates2;
293  ContainerCollisionRequestDataBox2D reqData(candidates2);
294  broadphase_manager_->Query(&reqData, b2Obj);
295  for (auto el : candidates2) {
296  candidates.push_back(*((int*)(broadphase_manager_->GetUserData(el))));
297  }
298  return 0;
299  }
300 
301  inline int getObjectId(const collision::CollisionObject* obj) {
302  auto search = object_ids_.find(obj);
303  if (search != object_ids_.end()) {
304  return search->second;
305  } else
306  throw std::exception();
307  }
308 
309  inline uint64_t get_mask(const AABB& obj) { return 0; }
310 
311  inline ObjectProxy CreateProxy(const CollisionObject* obj,
312  const collision::AABB& aabb) {
313  uint64_t mask = get_mask(aabb);
314  return ObjectProxy{mask, const_cast<CollisionObject*>(obj)};
315  // return ObjectProxy{mask,const_cast<CollisionObject*>(obj), aabb};
316  }
317 
318  int registerObjectId(const CollisionObject* obj) {
319  object_ids_.insert(std::make_pair(obj, (int)object_ids_.size()));
321  const collision::RectangleOBB* obb_in =
322  static_cast<const collision::RectangleOBB*>(obj);
323 
324  fast_obbs_.emplace_back(obb_in->center(), obb_in->r_x() * 2,
325  obb_in->r_y() * 2, obb_in->local_x_axis(),
326  obb_in->local_y_axis());
327  }
328  return 0;
329  }
330 
331  inline AABB getAABB(const CollisionObject* obj) {
333  AABB a = (static_cast<const RectangleOBB*>(obj))->getAABB_fast();
334  return a;
335  } else {
336  auto aabb_fcl = obj->getAABB();
337  return AABB(*aabb_fcl);
338  }
339  }
340 };
341 } // namespace accelerators
342 } // namespace detail
343 } // namespace collision
344 
345 #endif /* CPP_COLLISION_INCLUDE_COLLISION_GRID_FCL_H_ */
Eigen::Vector2d local_y_axis() const
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
double y_min
Definition: aabb.h:11
#define TIMER_grid_narrowphase
Definition: application.h:35
virtual CollisionObjectClass getCollisionObjectClass() const
std::vector< ShapeConstPtr > unpack() const
Returns Vector of all shapes contained inside the ShapeGroup.
Definition: shape_group.cc:187
std::vector< T, boost::alignment::aligned_allocator< T, 16 > > aligned_vector
std::shared_ptr< const RectangleAABB > RectangleAABBConstPtr
Eigen::Matrix< uint64_t, Eigen::Dynamic, 1 > VectorXi64
std::shared_ptr< const collision::RectangleAABB > getAABB() const
Definition: shape_group.cc:21
EIGEN_MAKE_ALIGNED_OPERATOR_NEW ContainerBox2D(aligned_vector< collision::CollisionObject *> objects_in, const ContainerSettings &sett)
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)
ContainerBox2D(const ShapeGroup *sg_ptr, const ContainerSettings &sett)
virtual CollisionObjectType getCollisionObjectType() const
Axis-aligned rectangle.
#define TIMER_STOP(x)
Definition: application.h:48
double x_max
Definition: aabb.h:10
double x_min
Definition: aabb.h:9
virtual std::shared_ptr< const collision::RectangleAABB > getAABB() const =0
int checkCollision(const CollisionObject *obj, const ContainerCollisionRequest &req)
Base class for CollisionObjects and some of their groups.
Eigen::Vector2d local_x_axis() const
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