75 ComputeBoundary(objects);
78 if (SplitToSubNodes(objects, params)) {
79 std::vector<ObjectPtr> left_subnode_objects;
80 std::vector<ObjectPtr> right_subnode_objects;
81 PartitionObjects(objects, &left_subnode_objects, &right_subnode_objects);
84 if (!left_subnode_objects.empty()) {
86 left_subnode_objects, params, depth + 1));
88 if (!right_subnode_objects.empty()) {
90 right_subnode_objects, params, depth + 1));
105 double min_distance_sqr = std::numeric_limits<double>::infinity();
106 GetNearestObjectInternal(point, &min_distance_sqr, &nearest_object);
107 return nearest_object;
118 const double distance)
const {
119 std::vector<ObjectPtr> result_objects;
120 GetObjectsInternal(point, distance,
Square(distance), &result_objects);
121 return result_objects;
129 return AABox2d({min_x_, min_y_}, {max_x_, max_y_});
133 void InitObjects(
const std::vector<ObjectPtr> &objects) {
134 num_objects_ =
static_cast<int>(objects.size());
135 objects_sorted_by_min_ = objects;
136 objects_sorted_by_max_ = objects;
137 std::sort(objects_sorted_by_min_.begin(), objects_sorted_by_min_.end(),
139 return partition_ == PARTITION_X
140 ? obj1->aabox().min_x() < obj2->aabox().min_x()
141 : obj1->aabox().min_y() < obj2->aabox().min_y();
143 std::sort(objects_sorted_by_max_.begin(), objects_sorted_by_max_.end(),
145 return partition_ == PARTITION_X
146 ? obj1->aabox().max_x() > obj2->aabox().max_x()
147 : obj1->aabox().max_y() > obj2->aabox().max_y();
149 objects_sorted_by_min_bound_.reserve(num_objects_);
150 for (
ObjectPtr object : objects_sorted_by_min_) {
151 objects_sorted_by_min_bound_.push_back(partition_ == PARTITION_X
152 ? object->aabox().min_x()
153 : object->aabox().min_y());
155 objects_sorted_by_max_bound_.reserve(num_objects_);
156 for (
ObjectPtr object : objects_sorted_by_max_) {
157 objects_sorted_by_max_bound_.push_back(partition_ == PARTITION_X
158 ? object->aabox().max_x()
159 : object->aabox().max_y());
163 bool SplitToSubNodes(
const std::vector<ObjectPtr> &objects,
164 const AABoxKDTreeParams ¶ms) {
165 if (params.max_depth >= 0 && depth_ >= params.max_depth) {
168 if (
static_cast<int>(objects.size()) <= std::max(1, params.max_leaf_size)) {
171 if (params.max_leaf_dimension >= 0.0 &&
172 std::max(max_x_ - min_x_, max_y_ - min_y_) <=
173 params.max_leaf_dimension) {
179 double LowerDistanceSquareToPoint(
const Vec2d &point)
const {
181 if (point.x() < min_x_) {
182 dx = min_x_ - point.x();
183 }
else if (point.x() > max_x_) {
184 dx = point.x() - max_x_;
187 if (point.y() < min_y_) {
188 dy = min_y_ - point.y();
189 }
else if (point.y() > max_y_) {
190 dy = point.y() - max_y_;
192 return dx * dx + dy * dy;
195 double UpperDistanceSquareToPoint(
const Vec2d &point)
const {
197 (point.x() > mid_x_ ? (point.x() - min_x_) : (point.x() - max_x_));
199 (point.y() > mid_y_ ? (point.y() - min_y_) : (point.y() - max_y_));
200 return dx * dx + dy * dy;
203 void GetAllObjects(std::vector<ObjectPtr> *
const result_objects)
const {
204 result_objects->insert(result_objects->end(),
205 objects_sorted_by_min_.begin(),
206 objects_sorted_by_min_.end());
207 if (left_subnode_ !=
nullptr) {
208 left_subnode_->GetAllObjects(result_objects);
210 if (right_subnode_ !=
nullptr) {
211 right_subnode_->GetAllObjects(result_objects);
215 void GetObjectsInternal(
const Vec2d &point,
const double distance,
216 const double distance_sqr,
217 std::vector<ObjectPtr> *
const result_objects)
const {
218 if (LowerDistanceSquareToPoint(point) > distance_sqr) {
221 if (UpperDistanceSquareToPoint(point) <= distance_sqr) {
222 GetAllObjects(result_objects);
225 const double pvalue = (partition_ == PARTITION_X ? point.x() : point.y());
226 if (pvalue < partition_position_) {
227 const double limit = pvalue + distance;
228 for (
int i = 0; i < num_objects_; ++i) {
229 if (objects_sorted_by_min_bound_[i] > limit) {
232 ObjectPtr object = objects_sorted_by_min_[i];
233 if (object->DistanceSquareTo(point) <= distance_sqr) {
234 result_objects->push_back(
object);
238 const double limit = pvalue - distance;
239 for (
int i = 0; i < num_objects_; ++i) {
240 if (objects_sorted_by_max_bound_[i] < limit) {
243 ObjectPtr object = objects_sorted_by_max_[i];
244 if (object->DistanceSquareTo(point) <= distance_sqr) {
245 result_objects->push_back(
object);
249 if (left_subnode_ !=
nullptr) {
250 left_subnode_->GetObjectsInternal(point, distance, distance_sqr,
253 if (right_subnode_ !=
nullptr) {
254 right_subnode_->GetObjectsInternal(point, distance, distance_sqr,
259 void GetNearestObjectInternal(
const Vec2d &point,
260 double *
const min_distance_sqr,
262 if (LowerDistanceSquareToPoint(point) >= *min_distance_sqr -
kMathEpsilon) {
265 const double pvalue = (partition_ == PARTITION_X ? point.x() : point.y());
266 const bool search_left_first = (pvalue < partition_position_);
267 if (search_left_first) {
268 if (left_subnode_ !=
nullptr) {
269 left_subnode_->GetNearestObjectInternal(point, min_distance_sqr,
273 if (right_subnode_ !=
nullptr) {
274 right_subnode_->GetNearestObjectInternal(point, min_distance_sqr,
282 if (search_left_first) {
283 for (
int i = 0; i < num_objects_; ++i) {
284 const double bound = objects_sorted_by_min_bound_[i];
285 if (bound > pvalue &&
Square(bound - pvalue) > *min_distance_sqr) {
288 ObjectPtr object = objects_sorted_by_min_[i];
289 const double distance_sqr =
object->DistanceSquareTo(point);
290 if (distance_sqr < *min_distance_sqr) {
291 *min_distance_sqr = distance_sqr;
292 *nearest_object = object;
296 for (
int i = 0; i < num_objects_; ++i) {
297 const double bound = objects_sorted_by_max_bound_[i];
298 if (bound < pvalue &&
Square(bound - pvalue) > *min_distance_sqr) {
301 ObjectPtr object = objects_sorted_by_max_[i];
302 const double distance_sqr =
object->DistanceSquareTo(point);
303 if (distance_sqr < *min_distance_sqr) {
304 *min_distance_sqr = distance_sqr;
305 *nearest_object = object;
312 if (search_left_first) {
313 if (right_subnode_ !=
nullptr) {
314 right_subnode_->GetNearestObjectInternal(point, min_distance_sqr,
318 if (left_subnode_ !=
nullptr) {
319 left_subnode_->GetNearestObjectInternal(point, min_distance_sqr,
325 void ComputeBoundary(
const std::vector<ObjectPtr> &objects) {
326 min_x_ = std::numeric_limits<double>::infinity();
327 min_y_ = std::numeric_limits<double>::infinity();
328 max_x_ = -std::numeric_limits<double>::infinity();
329 max_y_ = -std::numeric_limits<double>::infinity();
331 min_x_ = std::fmin(min_x_, object->aabox().min_x());
332 max_x_ = std::fmax(max_x_, object->aabox().max_x());
333 min_y_ = std::fmin(min_y_, object->aabox().min_y());
334 max_y_ = std::fmax(max_y_, object->aabox().max_y());
336 mid_x_ = (min_x_ + max_x_) / 2.0;
337 mid_y_ = (min_y_ + max_y_) / 2.0;
338 ACHECK(!std::isinf(max_x_) && !std::isinf(max_y_) && !std::isinf(min_x_) &&
340 <<
"the provided object box size is infinity";
343 void ComputePartition() {
344 if (max_x_ - min_x_ >= max_y_ - min_y_) {
345 partition_ = PARTITION_X;
346 partition_position_ = (min_x_ + max_x_) / 2.0;
348 partition_ = PARTITION_Y;
349 partition_position_ = (min_y_ + max_y_) / 2.0;
353 void PartitionObjects(
const std::vector<ObjectPtr> &objects,
354 std::vector<ObjectPtr> *
const left_subnode_objects,
355 std::vector<ObjectPtr> *
const right_subnode_objects) {
356 left_subnode_objects->clear();
357 right_subnode_objects->clear();
358 std::vector<ObjectPtr> other_objects;
359 if (partition_ == PARTITION_X) {
361 if (object->aabox().max_x() <= partition_position_) {
362 left_subnode_objects->push_back(
object);
363 }
else if (object->aabox().min_x() >= partition_position_) {
364 right_subnode_objects->push_back(
object);
366 other_objects.push_back(
object);
371 if (object->aabox().max_y() <= partition_position_) {
372 left_subnode_objects->push_back(
object);
373 }
else if (object->aabox().min_y() >= partition_position_) {
374 right_subnode_objects->push_back(
object);
376 other_objects.push_back(
object);
380 InitObjects(other_objects);
384 int num_objects_ = 0;
385 std::vector<ObjectPtr> objects_sorted_by_min_;
386 std::vector<ObjectPtr> objects_sorted_by_max_;
387 std::vector<double> objects_sorted_by_min_bound_;
388 std::vector<double> objects_sorted_by_max_bound_;
403 Partition partition_ = PARTITION_X;
404 double partition_position_ = 0.0;
406 std::unique_ptr<AABoxKDTree2dNode<ObjectType>> left_subnode_ =
nullptr;
407 std::unique_ptr<AABoxKDTree2dNode<ObjectType>> right_subnode_ =
nullptr;