Agent2d.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * Agent2d.cpp
  3. * RVO2 Library
  4. *
  5. * Copyright 2008 University of North Carolina at Chapel Hill
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * Please send all bug reports to <geom@cs.unc.edu>.
  20. *
  21. * The authors may be contacted via:
  22. *
  23. * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
  24. * Dept. of Computer Science
  25. * 201 S. Columbia St.
  26. * Frederick P. Brooks, Jr. Computer Science Bldg.
  27. * Chapel Hill, N.C. 27599-3175
  28. * United States of America
  29. *
  30. * <http://gamma.cs.unc.edu/RVO2/>
  31. */
  32. #include "Agent2d.h"
  33. #include "KdTree2d.h"
  34. #include "Obstacle2d.h"
  35. namespace RVO2D {
  36. Agent2D::Agent2D() : maxNeighbors_(0), maxSpeed_(0.0f), neighborDist_(0.0f), radius_(0.0f), timeHorizon_(0.0f), timeHorizonObst_(0.0f), id_(0) { }
  37. void Agent2D::computeNeighbors(RVOSimulator2D *sim_)
  38. {
  39. obstacleNeighbors_.clear();
  40. float rangeSq = sqr(timeHorizonObst_ * maxSpeed_ + radius_);
  41. sim_->kdTree_->computeObstacleNeighbors(this, rangeSq);
  42. agentNeighbors_.clear();
  43. if (maxNeighbors_ > 0) {
  44. rangeSq = sqr(neighborDist_);
  45. sim_->kdTree_->computeAgentNeighbors(this, rangeSq);
  46. }
  47. }
  48. /* Search for the best new velocity. */
  49. void Agent2D::computeNewVelocity(RVOSimulator2D *sim_)
  50. {
  51. orcaLines_.clear();
  52. const float invTimeHorizonObst = 1.0f / timeHorizonObst_;
  53. /* Create obstacle ORCA lines. */
  54. for (size_t i = 0; i < obstacleNeighbors_.size(); ++i) {
  55. const Obstacle2D *obstacle1 = obstacleNeighbors_[i].second;
  56. const Obstacle2D *obstacle2 = obstacle1->nextObstacle_;
  57. const Vector2 relativePosition1 = obstacle1->point_ - position_;
  58. const Vector2 relativePosition2 = obstacle2->point_ - position_;
  59. /*
  60. * Check if velocity obstacle of obstacle is already taken care of by
  61. * previously constructed obstacle ORCA lines.
  62. */
  63. bool alreadyCovered = false;
  64. for (size_t j = 0; j < orcaLines_.size(); ++j) {
  65. if (det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVO_EPSILON && det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVO_EPSILON) {
  66. alreadyCovered = true;
  67. break;
  68. }
  69. }
  70. if (alreadyCovered) {
  71. continue;
  72. }
  73. /* Not yet covered. Check for collisions. */
  74. const float distSq1 = absSq(relativePosition1);
  75. const float distSq2 = absSq(relativePosition2);
  76. const float radiusSq = sqr(radius_);
  77. const Vector2 obstacleVector = obstacle2->point_ - obstacle1->point_;
  78. const float s = (-relativePosition1 * obstacleVector) / absSq(obstacleVector);
  79. const float distSqLine = absSq(-relativePosition1 - s * obstacleVector);
  80. Line line;
  81. if (s < 0.0f && distSq1 <= radiusSq) {
  82. /* Collision with left vertex. Ignore if non-convex. */
  83. if (obstacle1->isConvex_) {
  84. line.point = Vector2(0.0f, 0.0f);
  85. line.direction = normalize(Vector2(-relativePosition1.y(), relativePosition1.x()));
  86. orcaLines_.push_back(line);
  87. }
  88. continue;
  89. }
  90. else if (s > 1.0f && distSq2 <= radiusSq) {
  91. /* Collision with right vertex. Ignore if non-convex
  92. * or if it will be taken care of by neighoring obstace */
  93. if (obstacle2->isConvex_ && det(relativePosition2, obstacle2->unitDir_) >= 0.0f) {
  94. line.point = Vector2(0.0f, 0.0f);
  95. line.direction = normalize(Vector2(-relativePosition2.y(), relativePosition2.x()));
  96. orcaLines_.push_back(line);
  97. }
  98. continue;
  99. }
  100. else if (s >= 0.0f && s < 1.0f && distSqLine <= radiusSq) {
  101. /* Collision with obstacle segment. */
  102. line.point = Vector2(0.0f, 0.0f);
  103. line.direction = -obstacle1->unitDir_;
  104. orcaLines_.push_back(line);
  105. continue;
  106. }
  107. /*
  108. * No collision.
  109. * Compute legs. When obliquely viewed, both legs can come from a single
  110. * vertex. Legs extend cut-off line when nonconvex vertex.
  111. */
  112. Vector2 leftLegDirection, rightLegDirection;
  113. if (s < 0.0f && distSqLine <= radiusSq) {
  114. /*
  115. * Obstacle viewed obliquely so that left vertex
  116. * defines velocity obstacle.
  117. */
  118. if (!obstacle1->isConvex_) {
  119. /* Ignore obstacle. */
  120. continue;
  121. }
  122. obstacle2 = obstacle1;
  123. const float leg1 = std::sqrt(distSq1 - radiusSq);
  124. leftLegDirection = Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
  125. rightLegDirection = Vector2(relativePosition1.x() * leg1 + relativePosition1.y() * radius_, -relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
  126. }
  127. else if (s > 1.0f && distSqLine <= radiusSq) {
  128. /*
  129. * Obstacle viewed obliquely so that
  130. * right vertex defines velocity obstacle.
  131. */
  132. if (!obstacle2->isConvex_) {
  133. /* Ignore obstacle. */
  134. continue;
  135. }
  136. obstacle1 = obstacle2;
  137. const float leg2 = std::sqrt(distSq2 - radiusSq);
  138. leftLegDirection = Vector2(relativePosition2.x() * leg2 - relativePosition2.y() * radius_, relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
  139. rightLegDirection = Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
  140. }
  141. else {
  142. /* Usual situation. */
  143. if (obstacle1->isConvex_) {
  144. const float leg1 = std::sqrt(distSq1 - radiusSq);
  145. leftLegDirection = Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
  146. }
  147. else {
  148. /* Left vertex non-convex; left leg extends cut-off line. */
  149. leftLegDirection = -obstacle1->unitDir_;
  150. }
  151. if (obstacle2->isConvex_) {
  152. const float leg2 = std::sqrt(distSq2 - radiusSq);
  153. rightLegDirection = Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
  154. }
  155. else {
  156. /* Right vertex non-convex; right leg extends cut-off line. */
  157. rightLegDirection = obstacle1->unitDir_;
  158. }
  159. }
  160. /*
  161. * Legs can never point into neighboring edge when convex vertex,
  162. * take cutoff-line of neighboring edge instead. If velocity projected on
  163. * "foreign" leg, no constraint is added.
  164. */
  165. const Obstacle2D *const leftNeighbor = obstacle1->prevObstacle_;
  166. bool isLeftLegForeign = false;
  167. bool isRightLegForeign = false;
  168. if (obstacle1->isConvex_ && det(leftLegDirection, -leftNeighbor->unitDir_) >= 0.0f) {
  169. /* Left leg points into obstacle. */
  170. leftLegDirection = -leftNeighbor->unitDir_;
  171. isLeftLegForeign = true;
  172. }
  173. if (obstacle2->isConvex_ && det(rightLegDirection, obstacle2->unitDir_) <= 0.0f) {
  174. /* Right leg points into obstacle. */
  175. rightLegDirection = obstacle2->unitDir_;
  176. isRightLegForeign = true;
  177. }
  178. /* Compute cut-off centers. */
  179. const Vector2 leftCutoff = invTimeHorizonObst * (obstacle1->point_ - position_);
  180. const Vector2 rightCutoff = invTimeHorizonObst * (obstacle2->point_ - position_);
  181. const Vector2 cutoffVec = rightCutoff - leftCutoff;
  182. /* Project current velocity on velocity obstacle. */
  183. /* Check if current velocity is projected on cutoff circles. */
  184. const float t = (obstacle1 == obstacle2 ? 0.5f : ((velocity_ - leftCutoff) * cutoffVec) / absSq(cutoffVec));
  185. const float tLeft = ((velocity_ - leftCutoff) * leftLegDirection);
  186. const float tRight = ((velocity_ - rightCutoff) * rightLegDirection);
  187. if ((t < 0.0f && tLeft < 0.0f) || (obstacle1 == obstacle2 && tLeft < 0.0f && tRight < 0.0f)) {
  188. /* Project on left cut-off circle. */
  189. const Vector2 unitW = normalize(velocity_ - leftCutoff);
  190. line.direction = Vector2(unitW.y(), -unitW.x());
  191. line.point = leftCutoff + radius_ * invTimeHorizonObst * unitW;
  192. orcaLines_.push_back(line);
  193. continue;
  194. }
  195. else if (t > 1.0f && tRight < 0.0f) {
  196. /* Project on right cut-off circle. */
  197. const Vector2 unitW = normalize(velocity_ - rightCutoff);
  198. line.direction = Vector2(unitW.y(), -unitW.x());
  199. line.point = rightCutoff + radius_ * invTimeHorizonObst * unitW;
  200. orcaLines_.push_back(line);
  201. continue;
  202. }
  203. /*
  204. * Project on left leg, right leg, or cut-off line, whichever is closest
  205. * to velocity.
  206. */
  207. const float distSqCutoff = ((t < 0.0f || t > 1.0f || obstacle1 == obstacle2) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (leftCutoff + t * cutoffVec)));
  208. const float distSqLeft = ((tLeft < 0.0f) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (leftCutoff + tLeft * leftLegDirection)));
  209. const float distSqRight = ((tRight < 0.0f) ? std::numeric_limits<float>::infinity() : absSq(velocity_ - (rightCutoff + tRight * rightLegDirection)));
  210. if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight) {
  211. /* Project on cut-off line. */
  212. line.direction = -obstacle1->unitDir_;
  213. line.point = leftCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
  214. orcaLines_.push_back(line);
  215. continue;
  216. }
  217. else if (distSqLeft <= distSqRight) {
  218. /* Project on left leg. */
  219. if (isLeftLegForeign) {
  220. continue;
  221. }
  222. line.direction = leftLegDirection;
  223. line.point = leftCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
  224. orcaLines_.push_back(line);
  225. continue;
  226. }
  227. else {
  228. /* Project on right leg. */
  229. if (isRightLegForeign) {
  230. continue;
  231. }
  232. line.direction = -rightLegDirection;
  233. line.point = rightCutoff + radius_ * invTimeHorizonObst * Vector2(-line.direction.y(), line.direction.x());
  234. orcaLines_.push_back(line);
  235. continue;
  236. }
  237. }
  238. const size_t numObstLines = orcaLines_.size();
  239. const float invTimeHorizon = 1.0f / timeHorizon_;
  240. /* Create agent ORCA lines. */
  241. for (size_t i = 0; i < agentNeighbors_.size(); ++i) {
  242. const Agent2D *const other = agentNeighbors_[i].second;
  243. //const float timeHorizon_mod = (avoidance_priority_ - other->avoidance_priority_ + 1.0f) * 0.5f;
  244. //const float invTimeHorizon = (1.0f / timeHorizon_) * timeHorizon_mod;
  245. const Vector2 relativePosition = other->position_ - position_;
  246. const Vector2 relativeVelocity = velocity_ - other->velocity_;
  247. const float distSq = absSq(relativePosition);
  248. const float combinedRadius = radius_ + other->radius_;
  249. const float combinedRadiusSq = sqr(combinedRadius);
  250. Line line;
  251. Vector2 u;
  252. if (distSq > combinedRadiusSq) {
  253. /* No collision. */
  254. const Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
  255. /* Vector from cutoff center to relative velocity. */
  256. const float wLengthSq = absSq(w);
  257. const float dotProduct1 = w * relativePosition;
  258. if (dotProduct1 < 0.0f && sqr(dotProduct1) > combinedRadiusSq * wLengthSq) {
  259. /* Project on cut-off circle. */
  260. const float wLength = std::sqrt(wLengthSq);
  261. const Vector2 unitW = w / wLength;
  262. line.direction = Vector2(unitW.y(), -unitW.x());
  263. u = (combinedRadius * invTimeHorizon - wLength) * unitW;
  264. }
  265. else {
  266. /* Project on legs. */
  267. const float leg = std::sqrt(distSq - combinedRadiusSq);
  268. if (det(relativePosition, w) > 0.0f) {
  269. /* Project on left leg. */
  270. line.direction = Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
  271. }
  272. else {
  273. /* Project on right leg. */
  274. line.direction = -Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
  275. }
  276. const float dotProduct2 = relativeVelocity * line.direction;
  277. u = dotProduct2 * line.direction - relativeVelocity;
  278. }
  279. }
  280. else {
  281. /* Collision. Project on cut-off circle of time timeStep. */
  282. const float invTimeStep = 1.0f / sim_->timeStep_;
  283. /* Vector from cutoff center to relative velocity. */
  284. const Vector2 w = relativeVelocity - invTimeStep * relativePosition;
  285. const float wLength = abs(w);
  286. const Vector2 unitW = w / wLength;
  287. line.direction = Vector2(unitW.y(), -unitW.x());
  288. u = (combinedRadius * invTimeStep - wLength) * unitW;
  289. }
  290. line.point = velocity_ + 0.5f * u;
  291. orcaLines_.push_back(line);
  292. }
  293. size_t lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, newVelocity_);
  294. if (lineFail < orcaLines_.size()) {
  295. linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, newVelocity_);
  296. }
  297. }
  298. void Agent2D::insertAgentNeighbor(const Agent2D *agent, float &rangeSq)
  299. {
  300. // no point processing same agent
  301. if (this == agent) {
  302. return;
  303. }
  304. // ignore other agent if layers/mask bitmasks have no matching bit
  305. if ((avoidance_mask_ & agent->avoidance_layers_) == 0) {
  306. return;
  307. }
  308. // ignore other agent if this agent is below or above
  309. if ((elevation_ > agent->elevation_ + agent->height_) || (elevation_ + height_ < agent->elevation_)) {
  310. return;
  311. }
  312. if (avoidance_priority_ > agent->avoidance_priority_) {
  313. return;
  314. }
  315. const float distSq = absSq(position_ - agent->position_);
  316. if (distSq < rangeSq) {
  317. if (agentNeighbors_.size() < maxNeighbors_) {
  318. agentNeighbors_.push_back(std::make_pair(distSq, agent));
  319. }
  320. size_t i = agentNeighbors_.size() - 1;
  321. while (i != 0 && distSq < agentNeighbors_[i - 1].first) {
  322. agentNeighbors_[i] = agentNeighbors_[i - 1];
  323. --i;
  324. }
  325. agentNeighbors_[i] = std::make_pair(distSq, agent);
  326. if (agentNeighbors_.size() == maxNeighbors_) {
  327. rangeSq = agentNeighbors_.back().first;
  328. }
  329. }
  330. }
  331. void Agent2D::insertObstacleNeighbor(const Obstacle2D *obstacle, float rangeSq)
  332. {
  333. const Obstacle2D *const nextObstacle = obstacle->nextObstacle_;
  334. // ignore obstacle if no matching layer/mask
  335. if ((avoidance_mask_ & nextObstacle->avoidance_layers_) == 0) {
  336. return;
  337. }
  338. // ignore obstacle if below or above
  339. if ((elevation_ > obstacle->elevation_ + obstacle->height_) || (elevation_ + height_ < obstacle->elevation_)) {
  340. return;
  341. }
  342. const float distSq = distSqPointLineSegment(obstacle->point_, nextObstacle->point_, position_);
  343. if (distSq < rangeSq) {
  344. obstacleNeighbors_.push_back(std::make_pair(distSq, obstacle));
  345. size_t i = obstacleNeighbors_.size() - 1;
  346. while (i != 0 && distSq < obstacleNeighbors_[i - 1].first) {
  347. obstacleNeighbors_[i] = obstacleNeighbors_[i - 1];
  348. --i;
  349. }
  350. obstacleNeighbors_[i] = std::make_pair(distSq, obstacle);
  351. }
  352. //}
  353. }
  354. void Agent2D::update(RVOSimulator2D *sim_)
  355. {
  356. velocity_ = newVelocity_;
  357. position_ += velocity_ * sim_->timeStep_;
  358. }
  359. bool linearProgram1(const std::vector<Line> &lines, size_t lineNo, float radius, const Vector2 &optVelocity, bool directionOpt, Vector2 &result)
  360. {
  361. const float dotProduct = lines[lineNo].point * lines[lineNo].direction;
  362. const float discriminant = sqr(dotProduct) + sqr(radius) - absSq(lines[lineNo].point);
  363. if (discriminant < 0.0f) {
  364. /* Max speed circle fully invalidates line lineNo. */
  365. return false;
  366. }
  367. const float sqrtDiscriminant = std::sqrt(discriminant);
  368. float tLeft = -dotProduct - sqrtDiscriminant;
  369. float tRight = -dotProduct + sqrtDiscriminant;
  370. for (size_t i = 0; i < lineNo; ++i) {
  371. const float denominator = det(lines[lineNo].direction, lines[i].direction);
  372. const float numerator = det(lines[i].direction, lines[lineNo].point - lines[i].point);
  373. if (std::fabs(denominator) <= RVO_EPSILON) {
  374. /* Lines lineNo and i are (almost) parallel. */
  375. if (numerator < 0.0f) {
  376. return false;
  377. }
  378. else {
  379. continue;
  380. }
  381. }
  382. const float t = numerator / denominator;
  383. if (denominator >= 0.0f) {
  384. /* Line i bounds line lineNo on the right. */
  385. tRight = std::min(tRight, t);
  386. }
  387. else {
  388. /* Line i bounds line lineNo on the left. */
  389. tLeft = std::max(tLeft, t);
  390. }
  391. if (tLeft > tRight) {
  392. return false;
  393. }
  394. }
  395. if (directionOpt) {
  396. /* Optimize direction. */
  397. if (optVelocity * lines[lineNo].direction > 0.0f) {
  398. /* Take right extreme. */
  399. result = lines[lineNo].point + tRight * lines[lineNo].direction;
  400. }
  401. else {
  402. /* Take left extreme. */
  403. result = lines[lineNo].point + tLeft * lines[lineNo].direction;
  404. }
  405. }
  406. else {
  407. /* Optimize closest point. */
  408. const float t = lines[lineNo].direction * (optVelocity - lines[lineNo].point);
  409. if (t < tLeft) {
  410. result = lines[lineNo].point + tLeft * lines[lineNo].direction;
  411. }
  412. else if (t > tRight) {
  413. result = lines[lineNo].point + tRight * lines[lineNo].direction;
  414. }
  415. else {
  416. result = lines[lineNo].point + t * lines[lineNo].direction;
  417. }
  418. }
  419. return true;
  420. }
  421. size_t linearProgram2(const std::vector<Line> &lines, float radius, const Vector2 &optVelocity, bool directionOpt, Vector2 &result)
  422. {
  423. if (directionOpt) {
  424. /*
  425. * Optimize direction. Note that the optimization velocity is of unit
  426. * length in this case.
  427. */
  428. result = optVelocity * radius;
  429. }
  430. else if (absSq(optVelocity) > sqr(radius)) {
  431. /* Optimize closest point and outside circle. */
  432. result = normalize(optVelocity) * radius;
  433. }
  434. else {
  435. /* Optimize closest point and inside circle. */
  436. result = optVelocity;
  437. }
  438. for (size_t i = 0; i < lines.size(); ++i) {
  439. if (det(lines[i].direction, lines[i].point - result) > 0.0f) {
  440. /* Result does not satisfy constraint i. Compute new optimal result. */
  441. const Vector2 tempResult = result;
  442. if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, result)) {
  443. result = tempResult;
  444. return i;
  445. }
  446. }
  447. }
  448. return lines.size();
  449. }
  450. void linearProgram3(const std::vector<Line> &lines, size_t numObstLines, size_t beginLine, float radius, Vector2 &result)
  451. {
  452. float distance = 0.0f;
  453. for (size_t i = beginLine; i < lines.size(); ++i) {
  454. if (det(lines[i].direction, lines[i].point - result) > distance) {
  455. /* Result does not satisfy constraint of line i. */
  456. std::vector<Line> projLines(lines.begin(), lines.begin() + static_cast<ptrdiff_t>(numObstLines));
  457. for (size_t j = numObstLines; j < i; ++j) {
  458. Line line;
  459. float determinant = det(lines[i].direction, lines[j].direction);
  460. if (std::fabs(determinant) <= RVO_EPSILON) {
  461. /* Line i and line j are parallel. */
  462. if (lines[i].direction * lines[j].direction > 0.0f) {
  463. /* Line i and line j point in the same direction. */
  464. continue;
  465. }
  466. else {
  467. /* Line i and line j point in opposite direction. */
  468. line.point = 0.5f * (lines[i].point + lines[j].point);
  469. }
  470. }
  471. else {
  472. line.point = lines[i].point + (det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
  473. }
  474. line.direction = normalize(lines[j].direction - lines[i].direction);
  475. projLines.push_back(line);
  476. }
  477. const Vector2 tempResult = result;
  478. if (linearProgram2(projLines, radius, Vector2(-lines[i].direction.y(), lines[i].direction.x()), true, result) < projLines.size()) {
  479. /* This should in principle not happen. The result is by definition
  480. * already in the feasible region of this linear program. If it fails,
  481. * it is due to small floating point error, and the current result is
  482. * kept.
  483. */
  484. result = tempResult;
  485. }
  486. distance = det(lines[i].direction, lines[i].point - result);
  487. }
  488. }
  489. }
  490. }