Path: blob/master/thirdparty/rvo2/rvo2_2d/KdTree2d.cpp
9904 views
/*1* KdTree2d.cpp2* RVO2 Library3*4* Copyright 2008 University of North Carolina at Chapel Hill5*6* Licensed under the Apache License, Version 2.0 (the "License");7* you may not use this file except in compliance with the License.8* You may obtain a copy of the License at9*10* http://www.apache.org/licenses/LICENSE-2.011*12* Unless required by applicable law or agreed to in writing, software13* distributed under the License is distributed on an "AS IS" BASIS,14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15* See the License for the specific language governing permissions and16* limitations under the License.17*18* Please send all bug reports to <[email protected]>.19*20* The authors may be contacted via:21*22* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha23* Dept. of Computer Science24* 201 S. Columbia St.25* Frederick P. Brooks, Jr. Computer Science Bldg.26* Chapel Hill, N.C. 27599-317527* United States of America28*29* <http://gamma.cs.unc.edu/RVO2/>30*/3132#include "KdTree2d.h"3334#include "Agent2d.h"35#include "RVOSimulator2d.h"36#include "Obstacle2d.h"3738namespace RVO2D {39KdTree2D::KdTree2D(RVOSimulator2D *sim) : obstacleTree_(NULL), sim_(sim) { }4041KdTree2D::~KdTree2D()42{43deleteObstacleTree(obstacleTree_);44}4546void KdTree2D::buildAgentTree(std::vector<Agent2D *> agents)47{48agents_.swap(agents);4950if (!agents_.empty()) {51agentTree_.resize(2 * agents_.size() - 1);52buildAgentTreeRecursive(0, agents_.size(), 0);53}54}5556void KdTree2D::buildAgentTreeRecursive(size_t begin, size_t end, size_t node)57{58agentTree_[node].begin = begin;59agentTree_[node].end = end;60agentTree_[node].minX = agentTree_[node].maxX = agents_[begin]->position_.x();61agentTree_[node].minY = agentTree_[node].maxY = agents_[begin]->position_.y();6263for (size_t i = begin + 1; i < end; ++i) {64agentTree_[node].maxX = std::max(agentTree_[node].maxX, agents_[i]->position_.x());65agentTree_[node].minX = std::min(agentTree_[node].minX, agents_[i]->position_.x());66agentTree_[node].maxY = std::max(agentTree_[node].maxY, agents_[i]->position_.y());67agentTree_[node].minY = std::min(agentTree_[node].minY, agents_[i]->position_.y());68}6970if (end - begin > MAX_LEAF_SIZE) {71/* No leaf node. */72const bool isVertical = (agentTree_[node].maxX - agentTree_[node].minX > agentTree_[node].maxY - agentTree_[node].minY);73const float splitValue = (isVertical ? 0.5f * (agentTree_[node].maxX + agentTree_[node].minX) : 0.5f * (agentTree_[node].maxY + agentTree_[node].minY));7475size_t left = begin;76size_t right = end;7778while (left < right) {79while (left < right && (isVertical ? agents_[left]->position_.x() : agents_[left]->position_.y()) < splitValue) {80++left;81}8283while (right > left && (isVertical ? agents_[right - 1]->position_.x() : agents_[right - 1]->position_.y()) >= splitValue) {84--right;85}8687if (left < right) {88std::swap(agents_[left], agents_[right - 1]);89++left;90--right;91}92}9394if (left == begin) {95++left;96++right;97}9899agentTree_[node].left = node + 1;100agentTree_[node].right = node + 2 * (left - begin);101102buildAgentTreeRecursive(begin, left, agentTree_[node].left);103buildAgentTreeRecursive(left, end, agentTree_[node].right);104}105}106107void KdTree2D::buildObstacleTree(std::vector<Obstacle2D *> obstacles)108{109deleteObstacleTree(obstacleTree_);110111obstacleTree_ = buildObstacleTreeRecursive(obstacles);112}113114115KdTree2D::ObstacleTreeNode *KdTree2D::buildObstacleTreeRecursive(const std::vector<Obstacle2D *> &obstacles)116{117if (obstacles.empty()) {118return NULL;119}120else {121ObstacleTreeNode *const node = new ObstacleTreeNode;122123size_t optimalSplit = 0;124size_t minLeft = obstacles.size();125size_t minRight = obstacles.size();126127for (size_t i = 0; i < obstacles.size(); ++i) {128size_t leftSize = 0;129size_t rightSize = 0;130131const Obstacle2D *const obstacleI1 = obstacles[i];132const Obstacle2D *const obstacleI2 = obstacleI1->nextObstacle_;133134/* Compute optimal split node. */135for (size_t j = 0; j < obstacles.size(); ++j) {136if (i == j) {137continue;138}139140const Obstacle2D *const obstacleJ1 = obstacles[j];141const Obstacle2D *const obstacleJ2 = obstacleJ1->nextObstacle_;142143const float j1LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ1->point_);144const float j2LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ2->point_);145146if (j1LeftOfI >= -RVO_EPSILON && j2LeftOfI >= -RVO_EPSILON) {147++leftSize;148}149else if (j1LeftOfI <= RVO_EPSILON && j2LeftOfI <= RVO_EPSILON) {150++rightSize;151}152else {153++leftSize;154++rightSize;155}156157if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) >= std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) {158break;159}160}161162if (std::make_pair(std::max(leftSize, rightSize), std::min(leftSize, rightSize)) < std::make_pair(std::max(minLeft, minRight), std::min(minLeft, minRight))) {163minLeft = leftSize;164minRight = rightSize;165optimalSplit = i;166}167}168169/* Build split node. */170std::vector<Obstacle2D *> leftObstacles(minLeft);171std::vector<Obstacle2D *> rightObstacles(minRight);172173size_t leftCounter = 0;174size_t rightCounter = 0;175const size_t i = optimalSplit;176177const Obstacle2D *const obstacleI1 = obstacles[i];178const Obstacle2D *const obstacleI2 = obstacleI1->nextObstacle_;179180for (size_t j = 0; j < obstacles.size(); ++j) {181if (i == j) {182continue;183}184185Obstacle2D *const obstacleJ1 = obstacles[j];186Obstacle2D *const obstacleJ2 = obstacleJ1->nextObstacle_;187188const float j1LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ1->point_);189const float j2LeftOfI = leftOf(obstacleI1->point_, obstacleI2->point_, obstacleJ2->point_);190191if (j1LeftOfI >= -RVO_EPSILON && j2LeftOfI >= -RVO_EPSILON) {192leftObstacles[leftCounter++] = obstacles[j];193}194else if (j1LeftOfI <= RVO_EPSILON && j2LeftOfI <= RVO_EPSILON) {195rightObstacles[rightCounter++] = obstacles[j];196}197else {198/* Split obstacle j. */199const float t = det(obstacleI2->point_ - obstacleI1->point_, obstacleJ1->point_ - obstacleI1->point_) / det(obstacleI2->point_ - obstacleI1->point_, obstacleJ1->point_ - obstacleJ2->point_);200201const Vector2 splitpoint = obstacleJ1->point_ + t * (obstacleJ2->point_ - obstacleJ1->point_);202203Obstacle2D *const newObstacle = new Obstacle2D();204newObstacle->point_ = splitpoint;205newObstacle->prevObstacle_ = obstacleJ1;206newObstacle->nextObstacle_ = obstacleJ2;207newObstacle->isConvex_ = true;208newObstacle->unitDir_ = obstacleJ1->unitDir_;209210newObstacle->id_ = sim_->obstacles_.size();211212sim_->obstacles_.push_back(newObstacle);213214obstacleJ1->nextObstacle_ = newObstacle;215obstacleJ2->prevObstacle_ = newObstacle;216217if (j1LeftOfI > 0.0f) {218leftObstacles[leftCounter++] = obstacleJ1;219rightObstacles[rightCounter++] = newObstacle;220}221else {222rightObstacles[rightCounter++] = obstacleJ1;223leftObstacles[leftCounter++] = newObstacle;224}225}226}227228node->obstacle = obstacleI1;229node->left = buildObstacleTreeRecursive(leftObstacles);230node->right = buildObstacleTreeRecursive(rightObstacles);231return node;232}233}234235void KdTree2D::computeAgentNeighbors(Agent2D *agent, float &rangeSq) const236{237queryAgentTreeRecursive(agent, rangeSq, 0);238}239240void KdTree2D::computeObstacleNeighbors(Agent2D *agent, float rangeSq) const241{242queryObstacleTreeRecursive(agent, rangeSq, obstacleTree_);243}244245void KdTree2D::deleteObstacleTree(ObstacleTreeNode *node)246{247if (node != NULL) {248deleteObstacleTree(node->left);249deleteObstacleTree(node->right);250delete node;251}252}253254void KdTree2D::queryAgentTreeRecursive(Agent2D *agent, float &rangeSq, size_t node) const255{256if (agentTree_[node].end - agentTree_[node].begin <= MAX_LEAF_SIZE) {257for (size_t i = agentTree_[node].begin; i < agentTree_[node].end; ++i) {258agent->insertAgentNeighbor(agents_[i], rangeSq);259}260}261else {262const float distSqLeft = sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minX - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].left].maxX)) + sqr(std::max(0.0f, agentTree_[agentTree_[node].left].minY - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].left].maxY));263264const float distSqRight = sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minX - agent->position_.x())) + sqr(std::max(0.0f, agent->position_.x() - agentTree_[agentTree_[node].right].maxX)) + sqr(std::max(0.0f, agentTree_[agentTree_[node].right].minY - agent->position_.y())) + sqr(std::max(0.0f, agent->position_.y() - agentTree_[agentTree_[node].right].maxY));265266if (distSqLeft < distSqRight) {267if (distSqLeft < rangeSq) {268queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);269270if (distSqRight < rangeSq) {271queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);272}273}274}275else {276if (distSqRight < rangeSq) {277queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].right);278279if (distSqLeft < rangeSq) {280queryAgentTreeRecursive(agent, rangeSq, agentTree_[node].left);281}282}283}284285}286}287288void KdTree2D::queryObstacleTreeRecursive(Agent2D *agent, float rangeSq, const ObstacleTreeNode *node) const289{290if (node == NULL) {291return;292}293else {294const Obstacle2D *const obstacle1 = node->obstacle;295const Obstacle2D *const obstacle2 = obstacle1->nextObstacle_;296297const float agentLeftOfLine = leftOf(obstacle1->point_, obstacle2->point_, agent->position_);298299queryObstacleTreeRecursive(agent, rangeSq, (agentLeftOfLine >= 0.0f ? node->left : node->right));300301const float distSqLine = sqr(agentLeftOfLine) / absSq(obstacle2->point_ - obstacle1->point_);302303if (distSqLine < rangeSq) {304if (agentLeftOfLine < 0.0f) {305/*306* Try obstacle at this node only if agent is on right side of307* obstacle (and can see obstacle).308*/309agent->insertObstacleNeighbor(node->obstacle, rangeSq);310}311312/* Try other side of line. */313queryObstacleTreeRecursive(agent, rangeSq, (agentLeftOfLine >= 0.0f ? node->right : node->left));314315}316}317}318319bool KdTree2D::queryVisibility(const Vector2 &q1, const Vector2 &q2, float radius) const320{321return queryVisibilityRecursive(q1, q2, radius, obstacleTree_);322}323324bool KdTree2D::queryVisibilityRecursive(const Vector2 &q1, const Vector2 &q2, float radius, const ObstacleTreeNode *node) const325{326if (node == NULL) {327return true;328}329else {330const Obstacle2D *const obstacle1 = node->obstacle;331const Obstacle2D *const obstacle2 = obstacle1->nextObstacle_;332333const float q1LeftOfI = leftOf(obstacle1->point_, obstacle2->point_, q1);334const float q2LeftOfI = leftOf(obstacle1->point_, obstacle2->point_, q2);335const float invLengthI = 1.0f / absSq(obstacle2->point_ - obstacle1->point_);336337if (q1LeftOfI >= 0.0f && q2LeftOfI >= 0.0f) {338return queryVisibilityRecursive(q1, q2, radius, node->left) && ((sqr(q1LeftOfI) * invLengthI >= sqr(radius) && sqr(q2LeftOfI) * invLengthI >= sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node->right));339}340else if (q1LeftOfI <= 0.0f && q2LeftOfI <= 0.0f) {341return queryVisibilityRecursive(q1, q2, radius, node->right) && ((sqr(q1LeftOfI) * invLengthI >= sqr(radius) && sqr(q2LeftOfI) * invLengthI >= sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node->left));342}343else if (q1LeftOfI >= 0.0f && q2LeftOfI <= 0.0f) {344/* One can see through obstacle from left to right. */345return queryVisibilityRecursive(q1, q2, radius, node->left) && queryVisibilityRecursive(q1, q2, radius, node->right);346}347else {348const float point1LeftOfQ = leftOf(q1, q2, obstacle1->point_);349const float point2LeftOfQ = leftOf(q1, q2, obstacle2->point_);350const float invLengthQ = 1.0f / absSq(q2 - q1);351352return (point1LeftOfQ * point2LeftOfQ >= 0.0f && sqr(point1LeftOfQ) * invLengthQ > sqr(radius) && sqr(point2LeftOfQ) * invLengthQ > sqr(radius) && queryVisibilityRecursive(q1, q2, radius, node->left) && queryVisibilityRecursive(q1, q2, radius, node->right));353}354}355}356}357358359