mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
提交RVO寻路
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2ce9624f28d4a21895096978accd208
|
||||
timeCreated: 1708498100
|
@@ -0,0 +1,8 @@
|
||||
using RVO;
|
||||
|
||||
namespace Plugins.JNGame.Sync.Frame.AStar.RVO2
|
||||
{
|
||||
public class JNRVO2Simulator : Simulator
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6cb8cf568a74351b80ac824ae622734
|
||||
timeCreated: 1708509872
|
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0950c0aa028d5c747b6a5b42e0707b3c
|
||||
folderAsset: yes
|
||||
timeCreated: 1509520805
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,730 @@
|
||||
/*
|
||||
* Agent.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines an agent in the simulation.</summary>
|
||||
*/
|
||||
internal class Agent
|
||||
{
|
||||
internal IList<KeyValuePair<float, Agent>> agentNeighbors_ = new List<KeyValuePair<float, Agent>>();
|
||||
internal IList<KeyValuePair<float, Obstacle>> obstacleNeighbors_ = new List<KeyValuePair<float, Obstacle>>();
|
||||
internal IList<Line> orcaLines_ = new List<Line>();
|
||||
internal Vector2 position_;
|
||||
internal Vector2 prefVelocity_;
|
||||
internal Vector2 velocity_;
|
||||
internal int id_ = 0;
|
||||
internal int maxNeighbors_ = 0;
|
||||
internal float maxSpeed_ = 0.0f;
|
||||
internal float neighborDist_ = 0.0f;
|
||||
internal float radius_ = 0.0f;
|
||||
internal float timeHorizon_ = 0.0f;
|
||||
internal float timeHorizonObst_ = 0.0f;
|
||||
internal bool needDelete_ = false;
|
||||
|
||||
private Vector2 newVelocity_;
|
||||
|
||||
/**
|
||||
* <summary>Computes the neighbors of this agent.</summary>
|
||||
*/
|
||||
internal void computeNeighbors(Simulator simulator)
|
||||
{
|
||||
obstacleNeighbors_.Clear();
|
||||
float rangeSq = RVOMath.sqr(timeHorizonObst_ * maxSpeed_ + radius_);
|
||||
simulator.kdTree_.computeObstacleNeighbors(this, rangeSq);
|
||||
|
||||
agentNeighbors_.Clear();
|
||||
|
||||
if (maxNeighbors_ > 0)
|
||||
{
|
||||
rangeSq = RVOMath.sqr(neighborDist_);
|
||||
simulator.kdTree_.computeAgentNeighbors(this, ref rangeSq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the new velocity of this agent.</summary>
|
||||
*/
|
||||
internal void computeNewVelocity(Simulator simulator)
|
||||
{
|
||||
orcaLines_.Clear();
|
||||
|
||||
float invTimeHorizonObst = 1.0f / timeHorizonObst_;
|
||||
|
||||
/* Create obstacle ORCA lines. */
|
||||
for (int i = 0; i < obstacleNeighbors_.Count; ++i)
|
||||
{
|
||||
|
||||
Obstacle obstacle1 = obstacleNeighbors_[i].Value;
|
||||
Obstacle obstacle2 = obstacle1.next_;
|
||||
|
||||
Vector2 relativePosition1 = obstacle1.point_ - position_;
|
||||
Vector2 relativePosition2 = obstacle2.point_ - position_;
|
||||
|
||||
/*
|
||||
* Check if velocity obstacle of obstacle is already taken care
|
||||
* of by previously constructed obstacle ORCA lines.
|
||||
*/
|
||||
bool alreadyCovered = false;
|
||||
|
||||
for (int j = 0; j < orcaLines_.Count; ++j)
|
||||
{
|
||||
if (RVOMath.det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON && RVOMath.det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON)
|
||||
{
|
||||
alreadyCovered = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyCovered)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not yet covered. Check for collisions. */
|
||||
float distSq1 = RVOMath.absSq(relativePosition1);
|
||||
float distSq2 = RVOMath.absSq(relativePosition2);
|
||||
|
||||
float radiusSq = RVOMath.sqr(radius_);
|
||||
|
||||
Vector2 obstacleVector = obstacle2.point_ - obstacle1.point_;
|
||||
float s = (-relativePosition1 * obstacleVector) / RVOMath.absSq(obstacleVector);
|
||||
float distSqLine = RVOMath.absSq(-relativePosition1 - s * obstacleVector);
|
||||
|
||||
Line line;
|
||||
|
||||
if (s < 0.0f && distSq1 <= radiusSq)
|
||||
{
|
||||
/* Collision with left vertex. Ignore if non-convex. */
|
||||
if (obstacle1.convex_)
|
||||
{
|
||||
line.point = new Vector2(0.0f, 0.0f);
|
||||
line.direction = RVOMath.normalize(new Vector2(-relativePosition1.y(), relativePosition1.x()));
|
||||
orcaLines_.Add(line);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (s > 1.0f && distSq2 <= radiusSq)
|
||||
{
|
||||
/*
|
||||
* Collision with right vertex. Ignore if non-convex or if
|
||||
* it will be taken care of by neighboring obstacle.
|
||||
*/
|
||||
if (obstacle2.convex_ && RVOMath.det(relativePosition2, obstacle2.direction_) >= 0.0f)
|
||||
{
|
||||
line.point = new Vector2(0.0f, 0.0f);
|
||||
line.direction = RVOMath.normalize(new Vector2(-relativePosition2.y(), relativePosition2.x()));
|
||||
orcaLines_.Add(line);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (s >= 0.0f && s < 1.0f && distSqLine <= radiusSq)
|
||||
{
|
||||
/* Collision with obstacle segment. */
|
||||
line.point = new Vector2(0.0f, 0.0f);
|
||||
line.direction = -obstacle1.direction_;
|
||||
orcaLines_.Add(line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* No collision. Compute legs. When obliquely viewed, both legs
|
||||
* can come from a single vertex. Legs extend cut-off line when
|
||||
* non-convex vertex.
|
||||
*/
|
||||
|
||||
Vector2 leftLegDirection, rightLegDirection;
|
||||
|
||||
if (s < 0.0f && distSqLine <= radiusSq)
|
||||
{
|
||||
/*
|
||||
* Obstacle viewed obliquely so that left vertex
|
||||
* defines velocity obstacle.
|
||||
*/
|
||||
if (!obstacle1.convex_)
|
||||
{
|
||||
/* Ignore obstacle. */
|
||||
continue;
|
||||
}
|
||||
|
||||
obstacle2 = obstacle1;
|
||||
|
||||
float leg1 = RVOMath.sqrt(distSq1 - radiusSq);
|
||||
leftLegDirection = new Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
|
||||
rightLegDirection = new Vector2(relativePosition1.x() * leg1 + relativePosition1.y() * radius_, -relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
|
||||
}
|
||||
else if (s > 1.0f && distSqLine <= radiusSq)
|
||||
{
|
||||
/*
|
||||
* Obstacle viewed obliquely so that
|
||||
* right vertex defines velocity obstacle.
|
||||
*/
|
||||
if (!obstacle2.convex_)
|
||||
{
|
||||
/* Ignore obstacle. */
|
||||
continue;
|
||||
}
|
||||
|
||||
obstacle1 = obstacle2;
|
||||
|
||||
float leg2 = RVOMath.sqrt(distSq2 - radiusSq);
|
||||
leftLegDirection = new Vector2(relativePosition2.x() * leg2 - relativePosition2.y() * radius_, relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
|
||||
rightLegDirection = new Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Usual situation. */
|
||||
if (obstacle1.convex_)
|
||||
{
|
||||
float leg1 = RVOMath.sqrt(distSq1 - radiusSq);
|
||||
leftLegDirection = new Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Left vertex non-convex; left leg extends cut-off line. */
|
||||
leftLegDirection = -obstacle1.direction_;
|
||||
}
|
||||
|
||||
if (obstacle2.convex_)
|
||||
{
|
||||
float leg2 = RVOMath.sqrt(distSq2 - radiusSq);
|
||||
rightLegDirection = new Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right vertex non-convex; right leg extends cut-off line. */
|
||||
rightLegDirection = obstacle1.direction_;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Legs can never point into neighboring edge when convex
|
||||
* vertex, take cutoff-line of neighboring edge instead. If
|
||||
* velocity projected on "foreign" leg, no constraint is added.
|
||||
*/
|
||||
|
||||
Obstacle leftNeighbor = obstacle1.previous_;
|
||||
|
||||
bool isLeftLegForeign = false;
|
||||
bool isRightLegForeign = false;
|
||||
|
||||
if (obstacle1.convex_ && RVOMath.det(leftLegDirection, -leftNeighbor.direction_) >= 0.0f)
|
||||
{
|
||||
/* Left leg points into obstacle. */
|
||||
leftLegDirection = -leftNeighbor.direction_;
|
||||
isLeftLegForeign = true;
|
||||
}
|
||||
|
||||
if (obstacle2.convex_ && RVOMath.det(rightLegDirection, obstacle2.direction_) <= 0.0f)
|
||||
{
|
||||
/* Right leg points into obstacle. */
|
||||
rightLegDirection = obstacle2.direction_;
|
||||
isRightLegForeign = true;
|
||||
}
|
||||
|
||||
/* Compute cut-off centers. */
|
||||
Vector2 leftCutOff = invTimeHorizonObst * (obstacle1.point_ - position_);
|
||||
Vector2 rightCutOff = invTimeHorizonObst * (obstacle2.point_ - position_);
|
||||
Vector2 cutOffVector = rightCutOff - leftCutOff;
|
||||
|
||||
/* Project current velocity on velocity obstacle. */
|
||||
|
||||
/* Check if current velocity is projected on cutoff circles. */
|
||||
float t = obstacle1 == obstacle2 ? 0.5f : ((velocity_ - leftCutOff) * cutOffVector) / RVOMath.absSq(cutOffVector);
|
||||
float tLeft = (velocity_ - leftCutOff) * leftLegDirection;
|
||||
float tRight = (velocity_ - rightCutOff) * rightLegDirection;
|
||||
|
||||
if ((t < 0.0f && tLeft < 0.0f) || (obstacle1 == obstacle2 && tLeft < 0.0f && tRight < 0.0f))
|
||||
{
|
||||
/* Project on left cut-off circle. */
|
||||
Vector2 unitW = RVOMath.normalize(velocity_ - leftCutOff);
|
||||
|
||||
line.direction = new Vector2(unitW.y(), -unitW.x());
|
||||
line.point = leftCutOff + radius_ * invTimeHorizonObst * unitW;
|
||||
orcaLines_.Add(line);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (t > 1.0f && tRight < 0.0f)
|
||||
{
|
||||
/* Project on right cut-off circle. */
|
||||
Vector2 unitW = RVOMath.normalize(velocity_ - rightCutOff);
|
||||
|
||||
line.direction = new Vector2(unitW.y(), -unitW.x());
|
||||
line.point = rightCutOff + radius_ * invTimeHorizonObst * unitW;
|
||||
orcaLines_.Add(line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Project on left leg, right leg, or cut-off line, whichever is
|
||||
* closest to velocity.
|
||||
*/
|
||||
float distSqCutoff = (t < 0.0f || t > 1.0f || obstacle1 == obstacle2) ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (leftCutOff + t * cutOffVector));
|
||||
float distSqLeft = tLeft < 0.0f ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (leftCutOff + tLeft * leftLegDirection));
|
||||
float distSqRight = tRight < 0.0f ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (rightCutOff + tRight * rightLegDirection));
|
||||
|
||||
if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
|
||||
{
|
||||
/* Project on cut-off line. */
|
||||
line.direction = -obstacle1.direction_;
|
||||
line.point = leftCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
|
||||
orcaLines_.Add(line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (distSqLeft <= distSqRight)
|
||||
{
|
||||
/* Project on left leg. */
|
||||
if (isLeftLegForeign)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
line.direction = leftLegDirection;
|
||||
line.point = leftCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
|
||||
orcaLines_.Add(line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Project on right leg. */
|
||||
if (isRightLegForeign)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
line.direction = -rightLegDirection;
|
||||
line.point = rightCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
|
||||
orcaLines_.Add(line);
|
||||
}
|
||||
|
||||
int numObstLines = orcaLines_.Count;
|
||||
|
||||
float invTimeHorizon = 1.0f / timeHorizon_;
|
||||
|
||||
/* Create agent ORCA lines. */
|
||||
for (int i = 0; i < agentNeighbors_.Count; ++i)
|
||||
{
|
||||
Agent other = agentNeighbors_[i].Value;
|
||||
|
||||
Vector2 relativePosition = other.position_ - position_;
|
||||
Vector2 relativeVelocity = velocity_ - other.velocity_;
|
||||
float distSq = RVOMath.absSq(relativePosition);
|
||||
float combinedRadius = radius_ + other.radius_;
|
||||
float combinedRadiusSq = RVOMath.sqr(combinedRadius);
|
||||
|
||||
Line line;
|
||||
Vector2 u;
|
||||
|
||||
if (distSq > combinedRadiusSq)
|
||||
{
|
||||
/* No collision. */
|
||||
Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
|
||||
|
||||
/* Vector from cutoff center to relative velocity. */
|
||||
float wLengthSq = RVOMath.absSq(w);
|
||||
float dotProduct1 = w * relativePosition;
|
||||
|
||||
if (dotProduct1 < 0.0f && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq)
|
||||
{
|
||||
/* Project on cut-off circle. */
|
||||
float wLength = RVOMath.sqrt(wLengthSq);
|
||||
Vector2 unitW = w / wLength;
|
||||
|
||||
line.direction = new Vector2(unitW.y(), -unitW.x());
|
||||
u = (combinedRadius * invTimeHorizon - wLength) * unitW;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Project on legs. */
|
||||
float leg = RVOMath.sqrt(distSq - combinedRadiusSq);
|
||||
|
||||
if (RVOMath.det(relativePosition, w) > 0.0f)
|
||||
{
|
||||
/* Project on left leg. */
|
||||
line.direction = new Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Project on right leg. */
|
||||
line.direction = -new Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
|
||||
}
|
||||
|
||||
float dotProduct2 = relativeVelocity * line.direction;
|
||||
u = dotProduct2 * line.direction - relativeVelocity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Collision. Project on cut-off circle of time timeStep. */
|
||||
float invTimeStep = 1.0f / simulator.timeStep_;
|
||||
|
||||
/* Vector from cutoff center to relative velocity. */
|
||||
Vector2 w = relativeVelocity - invTimeStep * relativePosition;
|
||||
|
||||
float wLength = RVOMath.abs(w);
|
||||
Vector2 unitW = w / wLength;
|
||||
|
||||
line.direction = new Vector2(unitW.y(), -unitW.x());
|
||||
u = (combinedRadius * invTimeStep - wLength) * unitW;
|
||||
}
|
||||
|
||||
line.point = velocity_ + 0.5f * u;
|
||||
orcaLines_.Add(line);
|
||||
}
|
||||
|
||||
int lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, ref newVelocity_);
|
||||
|
||||
if (lineFail < orcaLines_.Count)
|
||||
{
|
||||
linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, ref newVelocity_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Inserts an agent neighbor into the set of neighbors of this
|
||||
* agent.</summary>
|
||||
*
|
||||
* <param name="agent">A pointer to the agent to be inserted.</param>
|
||||
* <param name="rangeSq">The squared range around this agent.</param>
|
||||
*/
|
||||
internal void insertAgentNeighbor(Agent agent, ref float rangeSq)
|
||||
{
|
||||
if (this != agent)
|
||||
{
|
||||
float distSq = RVOMath.absSq(position_ - agent.position_);
|
||||
|
||||
if (distSq < rangeSq)
|
||||
{
|
||||
if (agentNeighbors_.Count < maxNeighbors_)
|
||||
{
|
||||
agentNeighbors_.Add(new KeyValuePair<float, Agent>(distSq, agent));
|
||||
}
|
||||
|
||||
int i = agentNeighbors_.Count - 1;
|
||||
|
||||
while (i != 0 && distSq < agentNeighbors_[i - 1].Key)
|
||||
{
|
||||
agentNeighbors_[i] = agentNeighbors_[i - 1];
|
||||
--i;
|
||||
}
|
||||
|
||||
agentNeighbors_[i] = new KeyValuePair<float, Agent>(distSq, agent);
|
||||
|
||||
if (agentNeighbors_.Count == maxNeighbors_)
|
||||
{
|
||||
rangeSq = agentNeighbors_[agentNeighbors_.Count - 1].Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Inserts a static obstacle neighbor into the set of neighbors
|
||||
* of this agent.</summary>
|
||||
*
|
||||
* <param name="obstacle">The number of the static obstacle to be
|
||||
* inserted.</param>
|
||||
* <param name="rangeSq">The squared range around this agent.</param>
|
||||
*/
|
||||
internal void insertObstacleNeighbor(Obstacle obstacle, float rangeSq)
|
||||
{
|
||||
Obstacle nextObstacle = obstacle.next_;
|
||||
|
||||
float distSq = RVOMath.distSqPointLineSegment(obstacle.point_, nextObstacle.point_, position_);
|
||||
|
||||
if (distSq < rangeSq)
|
||||
{
|
||||
obstacleNeighbors_.Add(new KeyValuePair<float, Obstacle>(distSq, obstacle));
|
||||
|
||||
int i = obstacleNeighbors_.Count - 1;
|
||||
|
||||
while (i != 0 && distSq < obstacleNeighbors_[i - 1].Key)
|
||||
{
|
||||
obstacleNeighbors_[i] = obstacleNeighbors_[i - 1];
|
||||
--i;
|
||||
}
|
||||
obstacleNeighbors_[i] = new KeyValuePair<float, Obstacle>(distSq, obstacle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Updates the two-dimensional position and two-dimensional
|
||||
* velocity of this agent.</summary>
|
||||
*/
|
||||
internal void update(Simulator simulator)
|
||||
{
|
||||
velocity_ = newVelocity_;
|
||||
position_ += velocity_ * simulator.timeStep_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Solves a one-dimensional linear program on a specified line
|
||||
* subject to linear constraints defined by lines and a circular
|
||||
* constraint.</summary>
|
||||
*
|
||||
* <returns>True if successful.</returns>
|
||||
*
|
||||
* <param name="lines">Lines defining the linear constraints.</param>
|
||||
* <param name="lineNo">The specified line constraint.</param>
|
||||
* <param name="radius">The radius of the circular constraint.</param>
|
||||
* <param name="optVelocity">The optimization velocity.</param>
|
||||
* <param name="directionOpt">True if the direction should be optimized.
|
||||
* </param>
|
||||
* <param name="result">A reference to the result of the linear program.
|
||||
* </param>
|
||||
*/
|
||||
private bool linearProgram1(IList<Line> lines, int lineNo, float radius, Vector2 optVelocity, bool directionOpt, ref Vector2 result)
|
||||
{
|
||||
float dotProduct = lines[lineNo].point * lines[lineNo].direction;
|
||||
float discriminant = RVOMath.sqr(dotProduct) + RVOMath.sqr(radius) - RVOMath.absSq(lines[lineNo].point);
|
||||
|
||||
if (discriminant < 0.0f)
|
||||
{
|
||||
/* Max speed circle fully invalidates line lineNo. */
|
||||
return false;
|
||||
}
|
||||
|
||||
float sqrtDiscriminant = RVOMath.sqrt(discriminant);
|
||||
float tLeft = -dotProduct - sqrtDiscriminant;
|
||||
float tRight = -dotProduct + sqrtDiscriminant;
|
||||
|
||||
for (int i = 0; i < lineNo; ++i)
|
||||
{
|
||||
float denominator = RVOMath.det(lines[lineNo].direction, lines[i].direction);
|
||||
float numerator = RVOMath.det(lines[i].direction, lines[lineNo].point - lines[i].point);
|
||||
|
||||
if (RVOMath.fabs(denominator) <= RVOMath.RVO_EPSILON)
|
||||
{
|
||||
/* Lines lineNo and i are (almost) parallel. */
|
||||
if (numerator < 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
float t = numerator / denominator;
|
||||
|
||||
if (denominator >= 0.0f)
|
||||
{
|
||||
/* Line i bounds line lineNo on the right. */
|
||||
tRight = Math.Min(tRight, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Line i bounds line lineNo on the left. */
|
||||
tLeft = Math.Max(tLeft, t);
|
||||
}
|
||||
|
||||
if (tLeft > tRight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (directionOpt)
|
||||
{
|
||||
/* Optimize direction. */
|
||||
if (optVelocity * lines[lineNo].direction > 0.0f)
|
||||
{
|
||||
/* Take right extreme. */
|
||||
result = lines[lineNo].point + tRight * lines[lineNo].direction;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Take left extreme. */
|
||||
result = lines[lineNo].point + tLeft * lines[lineNo].direction;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Optimize closest point. */
|
||||
float t = lines[lineNo].direction * (optVelocity - lines[lineNo].point);
|
||||
|
||||
if (t < tLeft)
|
||||
{
|
||||
result = lines[lineNo].point + tLeft * lines[lineNo].direction;
|
||||
}
|
||||
else if (t > tRight)
|
||||
{
|
||||
result = lines[lineNo].point + tRight * lines[lineNo].direction;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = lines[lineNo].point + t * lines[lineNo].direction;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Solves a two-dimensional linear program subject to linear
|
||||
* constraints defined by lines and a circular constraint.</summary>
|
||||
*
|
||||
* <returns>The number of the line it fails on, and the number of lines
|
||||
* if successful.</returns>
|
||||
*
|
||||
* <param name="lines">Lines defining the linear constraints.</param>
|
||||
* <param name="radius">The radius of the circular constraint.</param>
|
||||
* <param name="optVelocity">The optimization velocity.</param>
|
||||
* <param name="directionOpt">True if the direction should be optimized.
|
||||
* </param>
|
||||
* <param name="result">A reference to the result of the linear program.
|
||||
* </param>
|
||||
*/
|
||||
private int linearProgram2(IList<Line> lines, float radius, Vector2 optVelocity, bool directionOpt, ref Vector2 result)
|
||||
{
|
||||
if (directionOpt)
|
||||
{
|
||||
/*
|
||||
* Optimize direction. Note that the optimization velocity is of
|
||||
* unit length in this case.
|
||||
*/
|
||||
result = optVelocity * radius;
|
||||
}
|
||||
else if (RVOMath.absSq(optVelocity) > RVOMath.sqr(radius))
|
||||
{
|
||||
/* Optimize closest point and outside circle. */
|
||||
result = RVOMath.normalize(optVelocity) * radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Optimize closest point and inside circle. */
|
||||
result = optVelocity;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.Count; ++i)
|
||||
{
|
||||
if (RVOMath.det(lines[i].direction, lines[i].point - result) > 0.0f)
|
||||
{
|
||||
/* Result does not satisfy constraint i. Compute new optimal result. */
|
||||
Vector2 tempResult = result;
|
||||
if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, ref result))
|
||||
{
|
||||
result = tempResult;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Solves a two-dimensional linear program subject to linear
|
||||
* constraints defined by lines and a circular constraint.</summary>
|
||||
*
|
||||
* <param name="lines">Lines defining the linear constraints.</param>
|
||||
* <param name="numObstLines">Count of obstacle lines.</param>
|
||||
* <param name="beginLine">The line on which the 2-d linear program
|
||||
* failed.</param>
|
||||
* <param name="radius">The radius of the circular constraint.</param>
|
||||
* <param name="result">A reference to the result of the linear program.
|
||||
* </param>
|
||||
*/
|
||||
private void linearProgram3(IList<Line> lines, int numObstLines, int beginLine, float radius, ref Vector2 result)
|
||||
{
|
||||
float distance = 0.0f;
|
||||
|
||||
for (int i = beginLine; i < lines.Count; ++i)
|
||||
{
|
||||
if (RVOMath.det(lines[i].direction, lines[i].point - result) > distance)
|
||||
{
|
||||
/* Result does not satisfy constraint of line i. */
|
||||
IList<Line> projLines = new List<Line>();
|
||||
for (int ii = 0; ii < numObstLines; ++ii)
|
||||
{
|
||||
projLines.Add(lines[ii]);
|
||||
}
|
||||
|
||||
for (int j = numObstLines; j < i; ++j)
|
||||
{
|
||||
Line line;
|
||||
|
||||
float determinant = RVOMath.det(lines[i].direction, lines[j].direction);
|
||||
|
||||
if (RVOMath.fabs(determinant) <= RVOMath.RVO_EPSILON)
|
||||
{
|
||||
/* Line i and line j are parallel. */
|
||||
if (lines[i].direction * lines[j].direction > 0.0f)
|
||||
{
|
||||
/* Line i and line j point in the same direction. */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Line i and line j point in opposite direction. */
|
||||
line.point = 0.5f * (lines[i].point + lines[j].point);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
line.point = lines[i].point + (RVOMath.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
|
||||
}
|
||||
|
||||
line.direction = RVOMath.normalize(lines[j].direction - lines[i].direction);
|
||||
projLines.Add(line);
|
||||
}
|
||||
|
||||
Vector2 tempResult = result;
|
||||
if (linearProgram2(projLines, radius, new Vector2(-lines[i].direction.y(), lines[i].direction.x()), true, ref result) < projLines.Count)
|
||||
{
|
||||
/*
|
||||
* This should in principle not happen. The result is by
|
||||
* definition already in the feasible region of this
|
||||
* linear program. If it fails, it is due to small
|
||||
* floating point error, and the current result is kept.
|
||||
*/
|
||||
result = tempResult;
|
||||
}
|
||||
|
||||
distance = RVOMath.det(lines[i].direction, lines[i].point - result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c89cdc06092e4cfab700ca0a1b02396a
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
* KdTree.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines k-D trees for agents and static obstacles in the
|
||||
* simulation.</summary>
|
||||
*/
|
||||
internal class KdTree
|
||||
{
|
||||
/**
|
||||
* <summary>Defines a node of an agent k-D tree.</summary>
|
||||
*/
|
||||
private struct AgentTreeNode
|
||||
{
|
||||
internal int begin_;
|
||||
internal int end_;
|
||||
internal int left_;
|
||||
internal int right_;
|
||||
internal float maxX_;
|
||||
internal float maxY_;
|
||||
internal float minX_;
|
||||
internal float minY_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Defines a pair of scalar values.</summary>
|
||||
*/
|
||||
private struct FloatPair
|
||||
{
|
||||
private float a_;
|
||||
private float b_;
|
||||
|
||||
/**
|
||||
* <summary>Constructs and initializes a pair of scalar
|
||||
* values.</summary>
|
||||
*
|
||||
* <param name="a">The first scalar value.</returns>
|
||||
* <param name="b">The second scalar value.</returns>
|
||||
*/
|
||||
internal FloatPair(float a, float b)
|
||||
{
|
||||
a_ = a;
|
||||
b_ = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns true if the first pair of scalar values is less
|
||||
* than the second pair of scalar values.</summary>
|
||||
*
|
||||
* <returns>True if the first pair of scalar values is less than the
|
||||
* second pair of scalar values.</returns>
|
||||
*
|
||||
* <param name="pair1">The first pair of scalar values.</param>
|
||||
* <param name="pair2">The second pair of scalar values.</param>
|
||||
*/
|
||||
public static bool operator <(FloatPair pair1, FloatPair pair2)
|
||||
{
|
||||
return pair1.a_ < pair2.a_ || !(pair2.a_ < pair1.a_) && pair1.b_ < pair2.b_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns true if the first pair of scalar values is less
|
||||
* than or equal to the second pair of scalar values.</summary>
|
||||
*
|
||||
* <returns>True if the first pair of scalar values is less than or
|
||||
* equal to the second pair of scalar values.</returns>
|
||||
*
|
||||
* <param name="pair1">The first pair of scalar values.</param>
|
||||
* <param name="pair2">The second pair of scalar values.</param>
|
||||
*/
|
||||
public static bool operator <=(FloatPair pair1, FloatPair pair2)
|
||||
{
|
||||
return (pair1.a_ == pair2.a_ && pair1.b_ == pair2.b_) || pair1 < pair2;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns true if the first pair of scalar values is
|
||||
* greater than the second pair of scalar values.</summary>
|
||||
*
|
||||
* <returns>True if the first pair of scalar values is greater than
|
||||
* the second pair of scalar values.</returns>
|
||||
*
|
||||
* <param name="pair1">The first pair of scalar values.</param>
|
||||
* <param name="pair2">The second pair of scalar values.</param>
|
||||
*/
|
||||
public static bool operator >(FloatPair pair1, FloatPair pair2)
|
||||
{
|
||||
return !(pair1 <= pair2);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns true if the first pair of scalar values is
|
||||
* greater than or equal to the second pair of scalar values.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>True if the first pair of scalar values is greater than
|
||||
* or equal to the second pair of scalar values.</returns>
|
||||
*
|
||||
* <param name="pair1">The first pair of scalar values.</param>
|
||||
* <param name="pair2">The second pair of scalar values.</param>
|
||||
*/
|
||||
public static bool operator >=(FloatPair pair1, FloatPair pair2)
|
||||
{
|
||||
return !(pair1 < pair2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Defines a node of an obstacle k-D tree.</summary>
|
||||
*/
|
||||
private class ObstacleTreeNode
|
||||
{
|
||||
internal Obstacle obstacle_;
|
||||
internal ObstacleTreeNode left_;
|
||||
internal ObstacleTreeNode right_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>The maximum size of an agent k-D tree leaf.</summary>
|
||||
*/
|
||||
private const int MAX_LEAF_SIZE = 10;
|
||||
|
||||
private Agent[] agents_;
|
||||
private AgentTreeNode[] agentTree_;
|
||||
private ObstacleTreeNode obstacleTree_;
|
||||
|
||||
/**
|
||||
* <summary>Builds an agent k-D tree.</summary>
|
||||
*/
|
||||
internal void buildAgentTree(Simulator simulator)
|
||||
{
|
||||
if (agents_ == null || agents_.Length != simulator.agents_.Count)
|
||||
{
|
||||
agents_ = new Agent[simulator.agents_.Count];
|
||||
|
||||
for (int i = 0; i < agents_.Length; ++i)
|
||||
{
|
||||
agents_[i] = simulator.agents_[i];
|
||||
}
|
||||
|
||||
agentTree_ = new AgentTreeNode[2 * agents_.Length];
|
||||
|
||||
for (int i = 0; i < agentTree_.Length; ++i)
|
||||
{
|
||||
agentTree_[i] = new AgentTreeNode();
|
||||
}
|
||||
}
|
||||
|
||||
if (agents_.Length != 0)
|
||||
{
|
||||
buildAgentTreeRecursive(0, agents_.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Builds an obstacle k-D tree.</summary>
|
||||
*/
|
||||
internal void buildObstacleTree(Simulator simulator)
|
||||
{
|
||||
obstacleTree_ = new ObstacleTreeNode();
|
||||
|
||||
IList<Obstacle> obstacles = new List<Obstacle>(simulator.obstacles_.Count);
|
||||
|
||||
for (int i = 0; i < simulator.obstacles_.Count; ++i)
|
||||
{
|
||||
obstacles.Add(simulator.obstacles_[i]);
|
||||
}
|
||||
|
||||
obstacleTree_ = buildObstacleTreeRecursive(simulator,obstacles);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the agent neighbors of the specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="agent">The agent for which agent neighbors are to be
|
||||
* computed.</param>
|
||||
* <param name="rangeSq">The squared range around the agent.</param>
|
||||
*/
|
||||
internal void computeAgentNeighbors(Agent agent, ref float rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(agent, ref rangeSq, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the obstacle neighbors of the specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="agent">The agent for which obstacle neighbors are to be
|
||||
* computed.</param>
|
||||
* <param name="rangeSq">The squared range around the agent.</param>
|
||||
*/
|
||||
internal void computeObstacleNeighbors(Agent agent, float rangeSq)
|
||||
{
|
||||
queryObstacleTreeRecursive(agent, rangeSq, obstacleTree_);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Queries the visibility between two points within a specified
|
||||
* radius.</summary>
|
||||
*
|
||||
* <returns>True if q1 and q2 are mutually visible within the radius;
|
||||
* false otherwise.</returns>
|
||||
*
|
||||
* <param name="q1">The first point between which visibility is to be
|
||||
* tested.</param>
|
||||
* <param name="q2">The second point between which visibility is to be
|
||||
* tested.</param>
|
||||
* <param name="radius">The radius within which visibility is to be
|
||||
* tested.</param>
|
||||
*/
|
||||
internal bool queryVisibility(Vector2 q1, Vector2 q2, float radius)
|
||||
{
|
||||
return queryVisibilityRecursive(q1, q2, radius, obstacleTree_);
|
||||
}
|
||||
|
||||
internal int queryNearAgent(Vector2 point, float radius)
|
||||
{
|
||||
float rangeSq = float.MaxValue;
|
||||
int agentNo = -1;
|
||||
queryAgentTreeRecursive(point, ref rangeSq, ref agentNo, 0);
|
||||
if (rangeSq < radius*radius)
|
||||
return agentNo;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Recursive method for building an agent k-D tree.</summary>
|
||||
*
|
||||
* <param name="begin">The beginning agent k-D tree node node index.
|
||||
* </param>
|
||||
* <param name="end">The ending agent k-D tree node index.</param>
|
||||
* <param name="node">The current agent k-D tree node index.</param>
|
||||
*/
|
||||
private void buildAgentTreeRecursive(int begin, int end, int node)
|
||||
{
|
||||
agentTree_[node].begin_ = begin;
|
||||
agentTree_[node].end_ = end;
|
||||
agentTree_[node].minX_ = agentTree_[node].maxX_ = agents_[begin].position_.x_;
|
||||
agentTree_[node].minY_ = agentTree_[node].maxY_ = agents_[begin].position_.y_;
|
||||
|
||||
for (int i = begin + 1; i < end; ++i)
|
||||
{
|
||||
agentTree_[node].maxX_ = Math.Max(agentTree_[node].maxX_, agents_[i].position_.x_);
|
||||
agentTree_[node].minX_ = Math.Min(agentTree_[node].minX_, agents_[i].position_.x_);
|
||||
agentTree_[node].maxY_ = Math.Max(agentTree_[node].maxY_, agents_[i].position_.y_);
|
||||
agentTree_[node].minY_ = Math.Min(agentTree_[node].minY_, agents_[i].position_.y_);
|
||||
}
|
||||
|
||||
if (end - begin > MAX_LEAF_SIZE)
|
||||
{
|
||||
/* No leaf node. */
|
||||
bool isVertical = agentTree_[node].maxX_ - agentTree_[node].minX_ > agentTree_[node].maxY_ - agentTree_[node].minY_;
|
||||
float splitValue = 0.5f * (isVertical ? agentTree_[node].maxX_ + agentTree_[node].minX_ : agentTree_[node].maxY_ + agentTree_[node].minY_);
|
||||
|
||||
int left = begin;
|
||||
int right = end;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
while (left < right && (isVertical ? agents_[left].position_.x_ : agents_[left].position_.y_) < splitValue)
|
||||
{
|
||||
++left;
|
||||
}
|
||||
|
||||
while (right > left && (isVertical ? agents_[right - 1].position_.x_ : agents_[right - 1].position_.y_) >= splitValue)
|
||||
{
|
||||
--right;
|
||||
}
|
||||
|
||||
if (left < right)
|
||||
{
|
||||
Agent tempAgent = agents_[left];
|
||||
agents_[left] = agents_[right - 1];
|
||||
agents_[right - 1] = tempAgent;
|
||||
++left;
|
||||
--right;
|
||||
}
|
||||
}
|
||||
|
||||
int leftSize = left - begin;
|
||||
|
||||
if (leftSize == 0)
|
||||
{
|
||||
++leftSize;
|
||||
++left;
|
||||
++right;
|
||||
}
|
||||
|
||||
agentTree_[node].left_ = node + 1;
|
||||
agentTree_[node].right_ = node + 2 * leftSize;
|
||||
|
||||
buildAgentTreeRecursive(begin, left, agentTree_[node].left_);
|
||||
buildAgentTreeRecursive(left, end, agentTree_[node].right_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Recursive method for building an obstacle k-D tree.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>An obstacle k-D tree node.</returns>
|
||||
*
|
||||
* <param name="obstacles">A list of obstacles.</param>
|
||||
*/
|
||||
private ObstacleTreeNode buildObstacleTreeRecursive(Simulator simulator,IList<Obstacle> obstacles)
|
||||
{
|
||||
if (obstacles.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ObstacleTreeNode node = new ObstacleTreeNode();
|
||||
|
||||
int optimalSplit = 0;
|
||||
int minLeft = obstacles.Count;
|
||||
int minRight = obstacles.Count;
|
||||
|
||||
for (int i = 0; i < obstacles.Count; ++i)
|
||||
{
|
||||
int leftSize = 0;
|
||||
int rightSize = 0;
|
||||
|
||||
Obstacle obstacleI1 = obstacles[i];
|
||||
Obstacle obstacleI2 = obstacleI1.next_;
|
||||
|
||||
/* Compute optimal split node. */
|
||||
for (int j = 0; j < obstacles.Count; ++j)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Obstacle obstacleJ1 = obstacles[j];
|
||||
Obstacle obstacleJ2 = obstacleJ1.next_;
|
||||
|
||||
float j1LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ1.point_);
|
||||
float j2LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ2.point_);
|
||||
|
||||
if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
|
||||
{
|
||||
++leftSize;
|
||||
}
|
||||
else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
|
||||
{
|
||||
++rightSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
++leftSize;
|
||||
++rightSize;
|
||||
}
|
||||
|
||||
if (new FloatPair(Math.Max(leftSize, rightSize), Math.Min(leftSize, rightSize)) >= new FloatPair(Math.Max(minLeft, minRight), Math.Min(minLeft, minRight)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (new FloatPair(Math.Max(leftSize, rightSize), Math.Min(leftSize, rightSize)) < new FloatPair(Math.Max(minLeft, minRight), Math.Min(minLeft, minRight)))
|
||||
{
|
||||
minLeft = leftSize;
|
||||
minRight = rightSize;
|
||||
optimalSplit = i;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Build split node. */
|
||||
IList<Obstacle> leftObstacles = new List<Obstacle>(minLeft);
|
||||
|
||||
for (int n = 0; n < minLeft; ++n)
|
||||
{
|
||||
leftObstacles.Add(null);
|
||||
}
|
||||
|
||||
IList<Obstacle> rightObstacles = new List<Obstacle>(minRight);
|
||||
|
||||
for (int n = 0; n < minRight; ++n)
|
||||
{
|
||||
rightObstacles.Add(null);
|
||||
}
|
||||
|
||||
int leftCounter = 0;
|
||||
int rightCounter = 0;
|
||||
int i = optimalSplit;
|
||||
|
||||
Obstacle obstacleI1 = obstacles[i];
|
||||
Obstacle obstacleI2 = obstacleI1.next_;
|
||||
|
||||
for (int j = 0; j < obstacles.Count; ++j)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Obstacle obstacleJ1 = obstacles[j];
|
||||
Obstacle obstacleJ2 = obstacleJ1.next_;
|
||||
|
||||
float j1LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ1.point_);
|
||||
float j2LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ2.point_);
|
||||
|
||||
if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
|
||||
{
|
||||
leftObstacles[leftCounter++] = obstacles[j];
|
||||
}
|
||||
else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
|
||||
{
|
||||
rightObstacles[rightCounter++] = obstacles[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Split obstacle j. */
|
||||
float t = RVOMath.det(obstacleI2.point_ - obstacleI1.point_, obstacleJ1.point_ - obstacleI1.point_) / RVOMath.det(obstacleI2.point_ - obstacleI1.point_, obstacleJ1.point_ - obstacleJ2.point_);
|
||||
|
||||
Vector2 splitPoint = obstacleJ1.point_ + t * (obstacleJ2.point_ - obstacleJ1.point_);
|
||||
|
||||
Obstacle newObstacle = new Obstacle();
|
||||
newObstacle.point_ = splitPoint;
|
||||
newObstacle.previous_ = obstacleJ1;
|
||||
newObstacle.next_ = obstacleJ2;
|
||||
newObstacle.convex_ = true;
|
||||
newObstacle.direction_ = obstacleJ1.direction_;
|
||||
|
||||
newObstacle.id_ = simulator.obstacles_.Count;
|
||||
|
||||
simulator.obstacles_.Add(newObstacle);
|
||||
|
||||
obstacleJ1.next_ = newObstacle;
|
||||
obstacleJ2.previous_ = newObstacle;
|
||||
|
||||
if (j1LeftOfI > 0.0f)
|
||||
{
|
||||
leftObstacles[leftCounter++] = obstacleJ1;
|
||||
rightObstacles[rightCounter++] = newObstacle;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightObstacles[rightCounter++] = obstacleJ1;
|
||||
leftObstacles[leftCounter++] = newObstacle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.obstacle_ = obstacleI1;
|
||||
node.left_ = buildObstacleTreeRecursive(simulator,leftObstacles);
|
||||
node.right_ = buildObstacleTreeRecursive(simulator,rightObstacles);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
private void queryAgentTreeRecursive(Vector2 position, ref float rangeSq, ref int agentNo, int node)
|
||||
{
|
||||
if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
|
||||
{
|
||||
for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
|
||||
{
|
||||
float distSq = RVOMath.absSq(position - agents_[i].position_);
|
||||
if (distSq < rangeSq)
|
||||
{
|
||||
rangeSq = distSq;
|
||||
agentNo = agents_[i].id_;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float distSqLeft = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minX_ - position.x_)) + RVOMath.sqr(Math.Max(0.0f, position.x_ - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minY_ - position.y_)) + RVOMath.sqr(Math.Max(0.0f, position.y_ - agentTree_[agentTree_[node].left_].maxY_));
|
||||
float distSqRight = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minX_ - position.x_)) + RVOMath.sqr(Math.Max(0.0f, position.x_ - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minY_ - position.y_)) + RVOMath.sqr(Math.Max(0.0f, position.y_ - agentTree_[agentTree_[node].right_].maxY_));
|
||||
|
||||
if (distSqLeft < distSqRight)
|
||||
{
|
||||
if (distSqLeft < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].left_);
|
||||
|
||||
if (distSqRight < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].right_);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distSqRight < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].right_);
|
||||
|
||||
if (distSqLeft < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].left_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Recursive method for computing the agent neighbors of the
|
||||
* specified agent.</summary>
|
||||
*
|
||||
* <param name="agent">The agent for which agent neighbors are to be
|
||||
* computed.</param>
|
||||
* <param name="rangeSq">The squared range around the agent.</param>
|
||||
* <param name="node">The current agent k-D tree node index.</param>
|
||||
*/
|
||||
private void queryAgentTreeRecursive(Agent agent, ref float rangeSq, int node)
|
||||
{
|
||||
if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
|
||||
{
|
||||
for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
|
||||
{
|
||||
agent.insertAgentNeighbor(agents_[i], ref rangeSq);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float distSqLeft = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minX_ - agent.position_.x_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.x_ - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minY_ - agent.position_.y_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.y_ - agentTree_[agentTree_[node].left_].maxY_));
|
||||
float distSqRight = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minX_ - agent.position_.x_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.x_ - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minY_ - agent.position_.y_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.y_ - agentTree_[agentTree_[node].right_].maxY_));
|
||||
|
||||
if (distSqLeft < distSqRight)
|
||||
{
|
||||
if (distSqLeft < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left_);
|
||||
|
||||
if (distSqRight < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right_);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distSqRight < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right_);
|
||||
|
||||
if (distSqLeft < rangeSq)
|
||||
{
|
||||
queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Recursive method for computing the obstacle neighbors of the
|
||||
* specified agent.</summary>
|
||||
*
|
||||
* <param name="agent">The agent for which obstacle neighbors are to be
|
||||
* computed.</param>
|
||||
* <param name="rangeSq">The squared range around the agent.</param>
|
||||
* <param name="node">The current obstacle k-D node.</param>
|
||||
*/
|
||||
private void queryObstacleTreeRecursive(Agent agent, float rangeSq, ObstacleTreeNode node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
Obstacle obstacle1 = node.obstacle_;
|
||||
Obstacle obstacle2 = obstacle1.next_;
|
||||
|
||||
float agentLeftOfLine = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, agent.position_);
|
||||
|
||||
queryObstacleTreeRecursive(agent, rangeSq, agentLeftOfLine >= 0.0f ? node.left_ : node.right_);
|
||||
|
||||
float distSqLine = RVOMath.sqr(agentLeftOfLine) / RVOMath.absSq(obstacle2.point_ - obstacle1.point_);
|
||||
|
||||
if (distSqLine < rangeSq)
|
||||
{
|
||||
if (agentLeftOfLine < 0.0f)
|
||||
{
|
||||
/*
|
||||
* Try obstacle at this node only if agent is on right side of
|
||||
* obstacle (and can see obstacle).
|
||||
*/
|
||||
agent.insertObstacleNeighbor(node.obstacle_, rangeSq);
|
||||
}
|
||||
|
||||
/* Try other side of line. */
|
||||
queryObstacleTreeRecursive(agent, rangeSq, agentLeftOfLine >= 0.0f ? node.right_ : node.left_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Recursive method for querying the visibility between two
|
||||
* points within a specified radius.</summary>
|
||||
*
|
||||
* <returns>True if q1 and q2 are mutually visible within the radius;
|
||||
* false otherwise.</returns>
|
||||
*
|
||||
* <param name="q1">The first point between which visibility is to be
|
||||
* tested.</param>
|
||||
* <param name="q2">The second point between which visibility is to be
|
||||
* tested.</param>
|
||||
* <param name="radius">The radius within which visibility is to be
|
||||
* tested.</param>
|
||||
* <param name="node">The current obstacle k-D node.</param>
|
||||
*/
|
||||
private bool queryVisibilityRecursive(Vector2 q1, Vector2 q2, float radius, ObstacleTreeNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Obstacle obstacle1 = node.obstacle_;
|
||||
Obstacle obstacle2 = obstacle1.next_;
|
||||
|
||||
float q1LeftOfI = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q1);
|
||||
float q2LeftOfI = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q2);
|
||||
float invLengthI = 1.0f / RVOMath.absSq(obstacle2.point_ - obstacle1.point_);
|
||||
|
||||
if (q1LeftOfI >= 0.0f && q2LeftOfI >= 0.0f)
|
||||
{
|
||||
return queryVisibilityRecursive(q1, q2, radius, node.left_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.right_));
|
||||
}
|
||||
|
||||
if (q1LeftOfI <= 0.0f && q2LeftOfI <= 0.0f)
|
||||
{
|
||||
return queryVisibilityRecursive(q1, q2, radius, node.right_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.left_));
|
||||
}
|
||||
|
||||
if (q1LeftOfI >= 0.0f && q2LeftOfI <= 0.0f)
|
||||
{
|
||||
/* One can see through obstacle from left to right. */
|
||||
return queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_);
|
||||
}
|
||||
|
||||
float point1LeftOfQ = RVOMath.leftOf(q1, q2, obstacle1.point_);
|
||||
float point2LeftOfQ = RVOMath.leftOf(q1, q2, obstacle2.point_);
|
||||
float invLengthQ = 1.0f / RVOMath.absSq(q2 - q1);
|
||||
|
||||
return point1LeftOfQ * point2LeftOfQ >= 0.0f && RVOMath.sqr(point1LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && RVOMath.sqr(point2LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 843e733cda984e1f9609e15ea17aae14
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Line.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines a directed line.</summary>
|
||||
*/
|
||||
public struct Line
|
||||
{
|
||||
public Vector2 direction;
|
||||
public Vector2 point;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 561d472d76e84e58bf85b3a4500de88e
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Obstacle.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines static obstacles in the simulation.</summary>
|
||||
*/
|
||||
internal class Obstacle
|
||||
{
|
||||
|
||||
internal Obstacle next_;
|
||||
internal Obstacle previous_;
|
||||
internal Vector2 direction_;
|
||||
internal Vector2 point_;
|
||||
internal int id_;
|
||||
internal bool convex_;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b53ac8ae25f4c2b9045a0e4d598eda3
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* RVOMath.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Contains functions and constants used in multiple classes.
|
||||
* </summary>
|
||||
*/
|
||||
public struct RVOMath
|
||||
{
|
||||
/**
|
||||
* <summary>A sufficiently small positive number.</summary>
|
||||
*/
|
||||
internal const float RVO_EPSILON = 0.00001f;
|
||||
|
||||
/**
|
||||
* <summary>Computes the length of a specified two-dimensional vector.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector whose length is to be
|
||||
* computed.</param>
|
||||
* <returns>The length of the two-dimensional vector.</returns>
|
||||
*/
|
||||
public static float abs(Vector2 vector)
|
||||
{
|
||||
return sqrt(absSq(vector));
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the squared length of a specified two-dimensional
|
||||
* vector.</summary>
|
||||
*
|
||||
* <returns>The squared length of the two-dimensional vector.</returns>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector whose squared length
|
||||
* is to be computed.</param>
|
||||
*/
|
||||
public static float absSq(Vector2 vector)
|
||||
{
|
||||
return vector * vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the normalization of the specified two-dimensional
|
||||
* vector.</summary>
|
||||
*
|
||||
* <returns>The normalization of the two-dimensional vector.</returns>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector whose normalization
|
||||
* is to be computed.</param>
|
||||
*/
|
||||
public static Vector2 normalize(Vector2 vector)
|
||||
{
|
||||
return vector / abs(vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the determinant of a two-dimensional square matrix
|
||||
* with rows consisting of the specified two-dimensional vectors.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The determinant of the two-dimensional square matrix.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="vector1">The top row of the two-dimensional square
|
||||
* matrix.</param>
|
||||
* <param name="vector2">The bottom row of the two-dimensional square
|
||||
* matrix.</param>
|
||||
*/
|
||||
internal static float det(Vector2 vector1, Vector2 vector2)
|
||||
{
|
||||
return vector1.x_ * vector2.y_ - vector1.y_ * vector2.x_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the squared distance from a line segment with the
|
||||
* specified endpoints to a specified point.</summary>
|
||||
*
|
||||
* <returns>The squared distance from the line segment to the point.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="vector1">The first endpoint of the line segment.</param>
|
||||
* <param name="vector2">The second endpoint of the line segment.
|
||||
* </param>
|
||||
* <param name="vector3">The point to which the squared distance is to
|
||||
* be calculated.</param>
|
||||
*/
|
||||
internal static float distSqPointLineSegment(Vector2 vector1, Vector2 vector2, Vector2 vector3)
|
||||
{
|
||||
float r = ((vector3 - vector1) * (vector2 - vector1)) / absSq(vector2 - vector1);
|
||||
|
||||
if (r < 0.0f)
|
||||
{
|
||||
return absSq(vector3 - vector1);
|
||||
}
|
||||
|
||||
if (r > 1.0f)
|
||||
{
|
||||
return absSq(vector3 - vector2);
|
||||
}
|
||||
|
||||
return absSq(vector3 - (vector1 + r * (vector2 - vector1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the absolute value of a float.</summary>
|
||||
*
|
||||
* <returns>The absolute value of the float.</returns>
|
||||
*
|
||||
* <param name="scalar">The float of which to compute the absolute
|
||||
* value.</param>
|
||||
*/
|
||||
internal static float fabs(float scalar)
|
||||
{
|
||||
return Math.Abs(scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the signed distance from a line connecting the
|
||||
* specified points to a specified point.</summary>
|
||||
*
|
||||
* <returns>Positive when the point c lies to the left of the line ab.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="a">The first point on the line.</param>
|
||||
* <param name="b">The second point on the line.</param>
|
||||
* <param name="c">The point to which the signed distance is to be
|
||||
* calculated.</param>
|
||||
*/
|
||||
internal static float leftOf(Vector2 a, Vector2 b, Vector2 c)
|
||||
{
|
||||
return det(a - c, b - a);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the square of a float.</summary>
|
||||
*
|
||||
* <returns>The square of the float.</returns>
|
||||
*
|
||||
* <param name="scalar">The float to be squared.</param>
|
||||
*/
|
||||
internal static float sqr(float scalar)
|
||||
{
|
||||
return scalar * scalar;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the square root of a float.</summary>
|
||||
*
|
||||
* <returns>The square root of the float.</returns>
|
||||
*
|
||||
* <param name="scalar">The float of which to compute the square root.
|
||||
* </param>
|
||||
*/
|
||||
internal static float sqrt(float scalar)
|
||||
{
|
||||
return (float)Math.Sqrt(scalar);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd22ac7d066645e1bd1e8b9ca83a11a5
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,936 @@
|
||||
/*
|
||||
* Simulator.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines the simulation.</summary>
|
||||
*/
|
||||
public class Simulator
|
||||
{
|
||||
/**
|
||||
* <summary>Defines a worker.</summary>
|
||||
*/
|
||||
private class Worker
|
||||
{
|
||||
private ManualResetEvent doneEvent_;
|
||||
private int end_;
|
||||
private int start_;
|
||||
|
||||
/**
|
||||
* <summary>Constructs and initializes a worker.</summary>
|
||||
*
|
||||
* <param name="start">Start.</param>
|
||||
* <param name="end">End.</param>
|
||||
* <param name="doneEvent">Done event.</param>
|
||||
*/
|
||||
internal Worker(int start, int end, ManualResetEvent doneEvent)
|
||||
{
|
||||
start_ = start;
|
||||
end_ = end;
|
||||
doneEvent_ = doneEvent;
|
||||
}
|
||||
|
||||
internal void config(int start, int end)
|
||||
{
|
||||
start_ = start;
|
||||
end_ = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Performs a simulation step.</summary>
|
||||
*
|
||||
* <param name="obj">Unused.</param>
|
||||
*/
|
||||
internal void step(Simulator simulator)
|
||||
{
|
||||
for (int index = start_; index < end_; ++index)
|
||||
{
|
||||
simulator.agents_[index].computeNeighbors(simulator);
|
||||
simulator.agents_[index].computeNewVelocity(simulator);
|
||||
}
|
||||
doneEvent_.Set();
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>updates the two-dimensional position and
|
||||
* two-dimensional velocity of each agent.</summary>
|
||||
*
|
||||
* <param name="obj">Unused.</param>
|
||||
*/
|
||||
internal void update(Simulator simulator)
|
||||
{
|
||||
for (int index = start_; index < end_; ++index)
|
||||
{
|
||||
simulator.agents_[index].update(simulator);
|
||||
}
|
||||
|
||||
doneEvent_.Set();
|
||||
}
|
||||
}
|
||||
|
||||
internal IDictionary<int, int> agentNo2indexDict_;
|
||||
internal IDictionary<int, int> index2agentNoDict_;
|
||||
internal IList<Agent> agents_;
|
||||
internal IList<Obstacle> obstacles_;
|
||||
internal KdTree kdTree_;
|
||||
internal float timeStep_;
|
||||
|
||||
private Agent defaultAgent_;
|
||||
private ManualResetEvent[] doneEvents_;
|
||||
private Worker[] workers_;
|
||||
private int numWorkers_;
|
||||
private int workerAgentCount_;
|
||||
private float globalTime_;
|
||||
|
||||
public void delAgent(int agentNo)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].needDelete_ = true;
|
||||
}
|
||||
|
||||
void updateDeleteAgent()
|
||||
{
|
||||
bool isDelete = false;
|
||||
for (int i = agents_.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (agents_[i].needDelete_)
|
||||
{
|
||||
agents_.RemoveAt(i);
|
||||
isDelete = true;
|
||||
}
|
||||
}
|
||||
if (isDelete)
|
||||
onDelAgent();
|
||||
}
|
||||
|
||||
static int s_totalID = 0;
|
||||
/**
|
||||
* <summary>Adds a new agent with default properties to the simulation.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The number of the agent, or -1 when the agent defaults have
|
||||
* not been set.</returns>
|
||||
*
|
||||
* <param name="position">The two-dimensional starting position of this
|
||||
* agent.</param>
|
||||
*/
|
||||
public int addAgent(Vector2 position)
|
||||
{
|
||||
if (defaultAgent_ == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Agent agent = new Agent();
|
||||
agent.id_ = s_totalID;
|
||||
s_totalID++;
|
||||
agent.maxNeighbors_ = defaultAgent_.maxNeighbors_;
|
||||
agent.maxSpeed_ = defaultAgent_.maxSpeed_;
|
||||
agent.neighborDist_ = defaultAgent_.neighborDist_;
|
||||
agent.position_ = position;
|
||||
agent.radius_ = defaultAgent_.radius_;
|
||||
agent.timeHorizon_ = defaultAgent_.timeHorizon_;
|
||||
agent.timeHorizonObst_ = defaultAgent_.timeHorizonObst_;
|
||||
agent.velocity_ = defaultAgent_.velocity_;
|
||||
agents_.Add(agent);
|
||||
onAddAgent();
|
||||
return agent.id_;
|
||||
}
|
||||
|
||||
void onDelAgent()
|
||||
{
|
||||
agentNo2indexDict_.Clear();
|
||||
index2agentNoDict_.Clear();
|
||||
|
||||
for (int i = 0; i < agents_.Count; i++)
|
||||
{
|
||||
int agentNo = agents_[i].id_;
|
||||
agentNo2indexDict_.Add(agentNo, i);
|
||||
index2agentNoDict_.Add(i, agentNo);
|
||||
}
|
||||
}
|
||||
|
||||
void onAddAgent()
|
||||
{
|
||||
if (agents_.Count == 0)
|
||||
return;
|
||||
|
||||
int index = agents_.Count - 1;
|
||||
int agentNo = agents_[index].id_;
|
||||
agentNo2indexDict_.Add(agentNo, index);
|
||||
index2agentNoDict_.Add(index, agentNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Adds a new agent to the simulation.</summary>
|
||||
*
|
||||
* <returns>The number of the agent.</returns>
|
||||
*
|
||||
* <param name="position">The two-dimensional starting position of this
|
||||
* agent.</param>
|
||||
* <param name="neighborDist">The maximum distance (center point to
|
||||
* center point) to other agents this agent takes into account in the
|
||||
* navigation. The larger this number, the longer the running time of
|
||||
* the simulation. If the number is too low, the simulation will not be
|
||||
* safe. Must be non-negative.</param>
|
||||
* <param name="maxNeighbors">The maximum number of other agents this
|
||||
* agent takes into account in the navigation. The larger this number,
|
||||
* the longer the running time of the simulation. If the number is too
|
||||
* low, the simulation will not be safe.</param>
|
||||
* <param name="timeHorizon">The minimal amount of time for which this
|
||||
* agent's velocities that are computed by the simulation are safe with
|
||||
* respect to other agents. The larger this number, the sooner this
|
||||
* agent will respond to the presence of other agents, but the less
|
||||
* freedom this agent has in choosing its velocities. Must be positive.
|
||||
* </param>
|
||||
* <param name="timeHorizonObst">The minimal amount of time for which
|
||||
* this agent's velocities that are computed by the simulation are safe
|
||||
* with respect to obstacles. The larger this number, the sooner this
|
||||
* agent will respond to the presence of obstacles, but the less freedom
|
||||
* this agent has in choosing its velocities. Must be positive.</param>
|
||||
* <param name="radius">The radius of this agent. Must be non-negative.
|
||||
* </param>
|
||||
* <param name="maxSpeed">The maximum speed of this agent. Must be
|
||||
* non-negative.</param>
|
||||
* <param name="velocity">The initial two-dimensional linear velocity of
|
||||
* this agent.</param>
|
||||
*/
|
||||
public int addAgent(Vector2 position, float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
|
||||
{
|
||||
Agent agent = new Agent();
|
||||
agent.id_ = s_totalID;
|
||||
s_totalID++;
|
||||
agent.maxNeighbors_ = maxNeighbors;
|
||||
agent.maxSpeed_ = maxSpeed;
|
||||
agent.neighborDist_ = neighborDist;
|
||||
agent.position_ = position;
|
||||
agent.radius_ = radius;
|
||||
agent.timeHorizon_ = timeHorizon;
|
||||
agent.timeHorizonObst_ = timeHorizonObst;
|
||||
agent.velocity_ = velocity;
|
||||
agents_.Add(agent);
|
||||
onAddAgent();
|
||||
return agent.id_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Adds a new obstacle to the simulation.</summary>
|
||||
*
|
||||
* <returns>The number of the first vertex of the obstacle, or -1 when
|
||||
* the number of vertices is less than two.</returns>
|
||||
*
|
||||
* <param name="vertices">List of the vertices of the polygonal obstacle
|
||||
* in counterclockwise order.</param>
|
||||
*
|
||||
* <remarks>To add a "negative" obstacle, e.g. a bounding polygon around
|
||||
* the environment, the vertices should be listed in clockwise order.
|
||||
* </remarks>
|
||||
*/
|
||||
public int addObstacle(IList<Vector2> vertices)
|
||||
{
|
||||
if (vertices.Count < 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int obstacleNo = obstacles_.Count;
|
||||
|
||||
for (int i = 0; i < vertices.Count; ++i)
|
||||
{
|
||||
Obstacle obstacle = new Obstacle();
|
||||
obstacle.point_ = vertices[i];
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
obstacle.previous_ = obstacles_[obstacles_.Count - 1];
|
||||
obstacle.previous_.next_ = obstacle;
|
||||
}
|
||||
|
||||
if (i == vertices.Count - 1)
|
||||
{
|
||||
obstacle.next_ = obstacles_[obstacleNo];
|
||||
obstacle.next_.previous_ = obstacle;
|
||||
}
|
||||
|
||||
obstacle.direction_ = RVOMath.normalize(vertices[(i == vertices.Count - 1 ? 0 : i + 1)] - vertices[i]);
|
||||
|
||||
if (vertices.Count == 2)
|
||||
{
|
||||
obstacle.convex_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
obstacle.convex_ = (RVOMath.leftOf(vertices[(i == 0 ? vertices.Count - 1 : i - 1)], vertices[i], vertices[(i == vertices.Count - 1 ? 0 : i + 1)]) >= 0.0f);
|
||||
}
|
||||
|
||||
obstacle.id_ = obstacles_.Count;
|
||||
obstacles_.Add(obstacle);
|
||||
}
|
||||
|
||||
return obstacleNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Clears the simulation.</summary>
|
||||
*/
|
||||
public void Clear()
|
||||
{
|
||||
agents_ = new List<Agent>();
|
||||
agentNo2indexDict_ = new Dictionary<int, int>();
|
||||
index2agentNoDict_ = new Dictionary<int, int>();
|
||||
defaultAgent_ = null;
|
||||
kdTree_ = new KdTree();
|
||||
obstacles_ = new List<Obstacle>();
|
||||
globalTime_ = 0.0f;
|
||||
timeStep_ = 0.1f;
|
||||
|
||||
SetNumWorkers(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Performs a simulation step and updates the two-dimensional
|
||||
* position and two-dimensional velocity of each agent.</summary>
|
||||
*
|
||||
* <returns>The global time after the simulation step.</returns>
|
||||
*/
|
||||
public float doStep()
|
||||
{
|
||||
updateDeleteAgent();
|
||||
|
||||
if (workers_ == null)
|
||||
{
|
||||
workers_ = new Worker[numWorkers_];
|
||||
doneEvents_ = new ManualResetEvent[workers_.Length];
|
||||
workerAgentCount_ = getNumAgents();
|
||||
|
||||
for (int block = 0; block < workers_.Length; ++block)
|
||||
{
|
||||
doneEvents_[block] = new ManualResetEvent(false);
|
||||
workers_[block] = new Worker(block * getNumAgents() / workers_.Length, (block + 1) * getNumAgents() / workers_.Length, doneEvents_[block]);
|
||||
}
|
||||
}
|
||||
|
||||
if (workerAgentCount_ != getNumAgents())
|
||||
{
|
||||
workerAgentCount_ = getNumAgents();
|
||||
for (int block = 0; block < workers_.Length; ++block)
|
||||
{
|
||||
workers_[block].config(block * getNumAgents() / workers_.Length, (block + 1) * getNumAgents() / workers_.Length);
|
||||
}
|
||||
}
|
||||
|
||||
kdTree_.buildAgentTree(this);
|
||||
|
||||
for (int block = 0; block < workers_.Length; ++block)
|
||||
{
|
||||
workers_[block].step(this);
|
||||
}
|
||||
|
||||
for (int block = 0; block < workers_.Length; ++block)
|
||||
{
|
||||
doneEvents_[block].Reset();
|
||||
workers_[block].update(this);
|
||||
}
|
||||
|
||||
globalTime_ += timeStep_;
|
||||
|
||||
return globalTime_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the specified agent neighbor of the specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The number of the neighboring agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose agent neighbor is
|
||||
* to be retrieved.</param>
|
||||
* <param name="neighborNo">The number of the agent neighbor to be
|
||||
* retrieved.</param>
|
||||
*/
|
||||
public int getAgentAgentNeighbor(int agentNo, int neighborNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].agentNeighbors_[neighborNo].Value.id_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the maximum neighbor count of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The present maximum neighbor count of the agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum neighbor
|
||||
* count is to be retrieved.</param>
|
||||
*/
|
||||
public int getAgentMaxNeighbors(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].maxNeighbors_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the maximum speed of a specified agent.</summary>
|
||||
*
|
||||
* <returns>The present maximum speed of the agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum speed is
|
||||
* to be retrieved.</param>
|
||||
*/
|
||||
public float getAgentMaxSpeed(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].maxSpeed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the maximum neighbor distance of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The present maximum neighbor distance of the agent.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum neighbor
|
||||
* distance is to be retrieved.</param>
|
||||
*/
|
||||
public float getAgentNeighborDist(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].neighborDist_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the count of agent neighbors taken into account to
|
||||
* compute the current velocity for the specified agent.</summary>
|
||||
*
|
||||
* <returns>The count of agent neighbors taken into account to compute
|
||||
* the current velocity for the specified agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose count of agent
|
||||
* neighbors is to be retrieved.</param>
|
||||
*/
|
||||
public int getAgentNumAgentNeighbors(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].agentNeighbors_.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the count of obstacle neighbors taken into account
|
||||
* to compute the current velocity for the specified agent.</summary>
|
||||
*
|
||||
* <returns>The count of obstacle neighbors taken into account to
|
||||
* compute the current velocity for the specified agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose count of obstacle
|
||||
* neighbors is to be retrieved.</param>
|
||||
*/
|
||||
public int getAgentNumObstacleNeighbors(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].obstacleNeighbors_.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the specified obstacle neighbor of the specified
|
||||
* agent.</summary>
|
||||
*
|
||||
* <returns>The number of the first vertex of the neighboring obstacle
|
||||
* edge.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose obstacle neighbor
|
||||
* is to be retrieved.</param>
|
||||
* <param name="neighborNo">The number of the obstacle neighbor to be
|
||||
* retrieved.</param>
|
||||
*/
|
||||
public int getAgentObstacleNeighbor(int agentNo, int neighborNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].obstacleNeighbors_[neighborNo].Value.id_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the ORCA constraints of the specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>A list of lines representing the ORCA constraints.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose ORCA constraints
|
||||
* are to be retrieved.</param>
|
||||
*
|
||||
* <remarks>The halfplane to the left of each line is the region of
|
||||
* permissible velocities with respect to that ORCA constraint.
|
||||
* </remarks>
|
||||
*/
|
||||
public IList<Line> getAgentOrcaLines(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].orcaLines_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the two-dimensional position of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The present two-dimensional position of the (center of the)
|
||||
* agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* position is to be retrieved.</param>
|
||||
*/
|
||||
public Vector2 getAgentPosition(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].position_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the two-dimensional preferred velocity of a
|
||||
* specified agent.</summary>
|
||||
*
|
||||
* <returns>The present two-dimensional preferred velocity of the agent.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* preferred velocity is to be retrieved.</param>
|
||||
*/
|
||||
public Vector2 getAgentPrefVelocity(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].prefVelocity_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the radius of a specified agent.</summary>
|
||||
*
|
||||
* <returns>The present radius of the agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose radius is to be
|
||||
* retrieved.</param>
|
||||
*/
|
||||
public float getAgentRadius(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].radius_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the time horizon of a specified agent.</summary>
|
||||
*
|
||||
* <returns>The present time horizon of the agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose time horizon is
|
||||
* to be retrieved.</param>
|
||||
*/
|
||||
public float getAgentTimeHorizon(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].timeHorizon_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the time horizon with respect to obstacles of a
|
||||
* specified agent.</summary>
|
||||
*
|
||||
* <returns>The present time horizon with respect to obstacles of the
|
||||
* agent.</returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose time horizon with
|
||||
* respect to obstacles is to be retrieved.</param>
|
||||
*/
|
||||
public float getAgentTimeHorizonObst(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].timeHorizonObst_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the two-dimensional linear velocity of a specified
|
||||
* agent.</summary>
|
||||
*
|
||||
* <returns>The present two-dimensional linear velocity of the agent.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* linear velocity is to be retrieved.</param>
|
||||
*/
|
||||
public Vector2 getAgentVelocity(int agentNo)
|
||||
{
|
||||
return agents_[agentNo2indexDict_[agentNo]].velocity_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the global time of the simulation.</summary>
|
||||
*
|
||||
* <returns>The present global time of the simulation (zero initially).
|
||||
* </returns>
|
||||
*/
|
||||
public float getGlobalTime()
|
||||
{
|
||||
return globalTime_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the count of agents in the simulation.</summary>
|
||||
*
|
||||
* <returns>The count of agents in the simulation.</returns>
|
||||
*/
|
||||
public int getNumAgents()
|
||||
{
|
||||
return agents_.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the count of obstacle vertices in the simulation.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The count of obstacle vertices in the simulation.</returns>
|
||||
*/
|
||||
public int getNumObstacleVertices()
|
||||
{
|
||||
return obstacles_.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the count of workers.</summary>
|
||||
*
|
||||
* <returns>The count of workers.</returns>
|
||||
*/
|
||||
public int GetNumWorkers()
|
||||
{
|
||||
return numWorkers_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the two-dimensional position of a specified obstacle
|
||||
* vertex.</summary>
|
||||
*
|
||||
* <returns>The two-dimensional position of the specified obstacle
|
||||
* vertex.</returns>
|
||||
*
|
||||
* <param name="vertexNo">The number of the obstacle vertex to be
|
||||
* retrieved.</param>
|
||||
*/
|
||||
public Vector2 getObstacleVertex(int vertexNo)
|
||||
{
|
||||
return obstacles_[vertexNo].point_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the number of the obstacle vertex succeeding the
|
||||
* specified obstacle vertex in its polygon.</summary>
|
||||
*
|
||||
* <returns>The number of the obstacle vertex succeeding the specified
|
||||
* obstacle vertex in its polygon.</returns>
|
||||
*
|
||||
* <param name="vertexNo">The number of the obstacle vertex whose
|
||||
* successor is to be retrieved.</param>
|
||||
*/
|
||||
public int getNextObstacleVertexNo(int vertexNo)
|
||||
{
|
||||
return obstacles_[vertexNo].next_.id_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the number of the obstacle vertex preceding the
|
||||
* specified obstacle vertex in its polygon.</summary>
|
||||
*
|
||||
* <returns>The number of the obstacle vertex preceding the specified
|
||||
* obstacle vertex in its polygon.</returns>
|
||||
*
|
||||
* <param name="vertexNo">The number of the obstacle vertex whose
|
||||
* predecessor is to be retrieved.</param>
|
||||
*/
|
||||
public int getPrevObstacleVertexNo(int vertexNo)
|
||||
{
|
||||
return obstacles_[vertexNo].previous_.id_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the time step of the simulation.</summary>
|
||||
*
|
||||
* <returns>The present time step of the simulation.</returns>
|
||||
*/
|
||||
public float getTimeStep()
|
||||
{
|
||||
return timeStep_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Processes the obstacles that have been added so that they
|
||||
* are accounted for in the simulation.</summary>
|
||||
*
|
||||
* <remarks>Obstacles added to the simulation after this function has
|
||||
* been called are not accounted for in the simulation.</remarks>
|
||||
*/
|
||||
public void processObstacles()
|
||||
{
|
||||
kdTree_.buildObstacleTree(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Performs a visibility query between the two specified points
|
||||
* with respect to the obstacles.</summary>
|
||||
*
|
||||
* <returns>A boolean specifying whether the two points are mutually
|
||||
* visible. Returns true when the obstacles have not been processed.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="point1">The first point of the query.</param>
|
||||
* <param name="point2">The second point of the query.</param>
|
||||
* <param name="radius">The minimal distance between the line connecting
|
||||
* the two points and the obstacles in order for the points to be
|
||||
* mutually visible (optional). Must be non-negative.</param>
|
||||
*/
|
||||
public bool queryVisibility(Vector2 point1, Vector2 point2, float radius)
|
||||
{
|
||||
return kdTree_.queryVisibility(point1, point2, radius);
|
||||
}
|
||||
|
||||
public int queryNearAgent(Vector2 point, float radius)
|
||||
{
|
||||
if (getNumAgents() == 0)
|
||||
return -1;
|
||||
return kdTree_.queryNearAgent(point, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the default properties for any new agent that is added.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="neighborDist">The default maximum distance (center point
|
||||
* to center point) to other agents a new agent takes into account in
|
||||
* the navigation. The larger this number, the longer he running time of
|
||||
* the simulation. If the number is too low, the simulation will not be
|
||||
* safe. Must be non-negative.</param>
|
||||
* <param name="maxNeighbors">The default maximum number of other agents
|
||||
* a new agent takes into account in the navigation. The larger this
|
||||
* number, the longer the running time of the simulation. If the number
|
||||
* is too low, the simulation will not be safe.</param>
|
||||
* <param name="timeHorizon">The default minimal amount of time for
|
||||
* which a new agent's velocities that are computed by the simulation
|
||||
* are safe with respect to other agents. The larger this number, the
|
||||
* sooner an agent will respond to the presence of other agents, but the
|
||||
* less freedom the agent has in choosing its velocities. Must be
|
||||
* positive.</param>
|
||||
* <param name="timeHorizonObst">The default minimal amount of time for
|
||||
* which a new agent's velocities that are computed by the simulation
|
||||
* are safe with respect to obstacles. The larger this number, the
|
||||
* sooner an agent will respond to the presence of obstacles, but the
|
||||
* less freedom the agent has in choosing its velocities. Must be
|
||||
* positive.</param>
|
||||
* <param name="radius">The default radius of a new agent. Must be
|
||||
* non-negative.</param>
|
||||
* <param name="maxSpeed">The default maximum speed of a new agent. Must
|
||||
* be non-negative.</param>
|
||||
* <param name="velocity">The default initial two-dimensional linear
|
||||
* velocity of a new agent.</param>
|
||||
*/
|
||||
public void setAgentDefaults(float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
|
||||
{
|
||||
if (defaultAgent_ == null)
|
||||
{
|
||||
defaultAgent_ = new Agent();
|
||||
}
|
||||
|
||||
defaultAgent_.maxNeighbors_ = maxNeighbors;
|
||||
defaultAgent_.maxSpeed_ = maxSpeed;
|
||||
defaultAgent_.neighborDist_ = neighborDist;
|
||||
defaultAgent_.radius_ = radius;
|
||||
defaultAgent_.timeHorizon_ = timeHorizon;
|
||||
defaultAgent_.timeHorizonObst_ = timeHorizonObst;
|
||||
defaultAgent_.velocity_ = velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the maximum neighbor count of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum neighbor
|
||||
* count is to be modified.</param>
|
||||
* <param name="maxNeighbors">The replacement maximum neighbor count.
|
||||
* </param>
|
||||
*/
|
||||
public void setAgentMaxNeighbors(int agentNo, int maxNeighbors)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].maxNeighbors_ = maxNeighbors;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the maximum speed of a specified agent.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum speed is
|
||||
* to be modified.</param>
|
||||
* <param name="maxSpeed">The replacement maximum speed. Must be
|
||||
* non-negative.</param>
|
||||
*/
|
||||
public void setAgentMaxSpeed(int agentNo, float maxSpeed)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].maxSpeed_ = maxSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the maximum neighbor distance of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose maximum neighbor
|
||||
* distance is to be modified.</param>
|
||||
* <param name="neighborDist">The replacement maximum neighbor distance.
|
||||
* Must be non-negative.</param>
|
||||
*/
|
||||
public void setAgentNeighborDist(int agentNo, float neighborDist)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].neighborDist_ = neighborDist;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the two-dimensional position of a specified agent.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* position is to be modified.</param>
|
||||
* <param name="position">The replacement of the two-dimensional
|
||||
* position.</param>
|
||||
*/
|
||||
public void setAgentPosition(int agentNo, Vector2 position)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].position_ = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the two-dimensional preferred velocity of a specified
|
||||
* agent.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* preferred velocity is to be modified.</param>
|
||||
* <param name="prefVelocity">The replacement of the two-dimensional
|
||||
* preferred velocity.</param>
|
||||
*/
|
||||
public void setAgentPrefVelocity(int agentNo, Vector2 prefVelocity)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].prefVelocity_ = prefVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the radius of a specified agent.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose radius is to be
|
||||
* modified.</param>
|
||||
* <param name="radius">The replacement radius. Must be non-negative.
|
||||
* </param>
|
||||
*/
|
||||
public void setAgentRadius(int agentNo, float radius)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].radius_ = radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the time horizon of a specified agent with respect to
|
||||
* other agents.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose time horizon is
|
||||
* to be modified.</param>
|
||||
* <param name="timeHorizon">The replacement time horizon with respect
|
||||
* to other agents. Must be positive.</param>
|
||||
*/
|
||||
public void setAgentTimeHorizon(int agentNo, float timeHorizon)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].timeHorizon_ = timeHorizon;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the time horizon of a specified agent with respect to
|
||||
* obstacles.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose time horizon with
|
||||
* respect to obstacles is to be modified.</param>
|
||||
* <param name="timeHorizonObst">The replacement time horizon with
|
||||
* respect to obstacles. Must be positive.</param>
|
||||
*/
|
||||
public void setAgentTimeHorizonObst(int agentNo, float timeHorizonObst)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].timeHorizonObst_ = timeHorizonObst;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the two-dimensional linear velocity of a specified
|
||||
* agent.</summary>
|
||||
*
|
||||
* <param name="agentNo">The number of the agent whose two-dimensional
|
||||
* linear velocity is to be modified.</param>
|
||||
* <param name="velocity">The replacement two-dimensional linear
|
||||
* velocity.</param>
|
||||
*/
|
||||
public void setAgentVelocity(int agentNo, Vector2 velocity)
|
||||
{
|
||||
agents_[agentNo2indexDict_[agentNo]].velocity_ = velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the global time of the simulation.</summary>
|
||||
*
|
||||
* <param name="globalTime">The global time of the simulation.</param>
|
||||
*/
|
||||
public void setGlobalTime(float globalTime)
|
||||
{
|
||||
globalTime_ = globalTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the number of workers.</summary>
|
||||
*
|
||||
* <param name="numWorkers">The number of workers.</param>
|
||||
*/
|
||||
public void SetNumWorkers(int numWorkers)
|
||||
{
|
||||
numWorkers_ = numWorkers;
|
||||
|
||||
if (numWorkers_ <= 0)
|
||||
{
|
||||
int completionPorts;
|
||||
ThreadPool.GetMinThreads(out numWorkers_, out completionPorts);
|
||||
}
|
||||
workers_ = null;
|
||||
workerAgentCount_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Sets the time step of the simulation.</summary>
|
||||
*
|
||||
* <param name="timeStep">The time step of the simulation. Must be
|
||||
* positive.</param>
|
||||
*/
|
||||
public void setTimeStep(float timeStep)
|
||||
{
|
||||
timeStep_ = timeStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Constructs and initializes a simulation.</summary>
|
||||
*/
|
||||
protected Simulator()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb91eae09aaa4ddd9584412824b4ba8c
|
||||
timeCreated: 1708509745
|
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Vector2.cs
|
||||
* RVO2 Library C#
|
||||
*
|
||||
* Copyright 2008 University of North Carolina at Chapel Hill
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Please send all bug reports to <geom@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
|
||||
* Dept. of Computer Science
|
||||
* 201 S. Columbia St.
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg.
|
||||
* Chapel Hill, N.C. 27599-3175
|
||||
* United States of America
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/RVO2/>
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RVO
|
||||
{
|
||||
/**
|
||||
* <summary>Defines a two-dimensional vector.</summary>
|
||||
*/
|
||||
public struct Vector2
|
||||
{
|
||||
internal float x_;
|
||||
internal float y_;
|
||||
|
||||
/**
|
||||
* <summary>Constructs and initializes a two-dimensional vector from the
|
||||
* specified xy-coordinates.</summary>
|
||||
*
|
||||
* <param name="x">The x-coordinate of the two-dimensional vector.
|
||||
* </param>
|
||||
* <param name="y">The y-coordinate of the two-dimensional vector.
|
||||
* </param>
|
||||
*/
|
||||
public Vector2(float x, float y)
|
||||
{
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the string representation of this vector.</summary>
|
||||
*
|
||||
* <returns>The string representation of this vector.</returns>
|
||||
*/
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + x_.ToString(new CultureInfo("").NumberFormat) + "," + y_.ToString(new CultureInfo("").NumberFormat) + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the x-coordinate of this two-dimensional vector.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The x-coordinate of the two-dimensional vector.</returns>
|
||||
*/
|
||||
public float x()
|
||||
{
|
||||
return x_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Returns the y-coordinate of this two-dimensional vector.
|
||||
* </summary>
|
||||
*
|
||||
* <returns>The y-coordinate of the two-dimensional vector.</returns>
|
||||
*/
|
||||
public float y()
|
||||
{
|
||||
return y_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the dot product of the two specified
|
||||
* two-dimensional vectors.</summary>
|
||||
*
|
||||
* <returns>The dot product of the two specified two-dimensional
|
||||
* vectors.</returns>
|
||||
*
|
||||
* <param name="vector1">The first two-dimensional vector.</param>
|
||||
* <param name="vector2">The second two-dimensional vector.</param>
|
||||
*/
|
||||
public static float operator *(Vector2 vector1, Vector2 vector2)
|
||||
{
|
||||
return vector1.x_ * vector2.x_ + vector1.y_ * vector2.y_;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the scalar multiplication of the specified
|
||||
* two-dimensional vector with the specified scalar value.</summary>
|
||||
*
|
||||
* <returns>The scalar multiplication of the specified two-dimensional
|
||||
* vector with the specified scalar value.</returns>
|
||||
*
|
||||
* <param name="scalar">The scalar value.</param>
|
||||
* <param name="vector">The two-dimensional vector.</param>
|
||||
*/
|
||||
public static Vector2 operator *(float scalar, Vector2 vector)
|
||||
{
|
||||
return vector * scalar;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the scalar multiplication of the specified
|
||||
* two-dimensional vector with the specified scalar value.</summary>
|
||||
*
|
||||
* <returns>The scalar multiplication of the specified two-dimensional
|
||||
* vector with the specified scalar value.</returns>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector.</param>
|
||||
* <param name="scalar">The scalar value.</param>
|
||||
*/
|
||||
public static Vector2 operator *(Vector2 vector, float scalar)
|
||||
{
|
||||
return new Vector2(vector.x_ * scalar, vector.y_ * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the scalar division of the specified
|
||||
* two-dimensional vector with the specified scalar value.</summary>
|
||||
*
|
||||
* <returns>The scalar division of the specified two-dimensional vector
|
||||
* with the specified scalar value.</returns>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector.</param>
|
||||
* <param name="scalar">The scalar value.</param>
|
||||
*/
|
||||
public static Vector2 operator /(Vector2 vector, float scalar)
|
||||
{
|
||||
return new Vector2(vector.x_ / scalar, vector.y_ / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the vector sum of the two specified two-dimensional
|
||||
* vectors.</summary>
|
||||
*
|
||||
* <returns>The vector sum of the two specified two-dimensional vectors.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="vector1">The first two-dimensional vector.</param>
|
||||
* <param name="vector2">The second two-dimensional vector.</param>
|
||||
*/
|
||||
public static Vector2 operator +(Vector2 vector1, Vector2 vector2)
|
||||
{
|
||||
return new Vector2(vector1.x_ + vector2.x_, vector1.y_ + vector2.y_);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the vector difference of the two specified
|
||||
* two-dimensional vectors</summary>
|
||||
*
|
||||
* <returns>The vector difference of the two specified two-dimensional
|
||||
* vectors.</returns>
|
||||
*
|
||||
* <param name="vector1">The first two-dimensional vector.</param>
|
||||
* <param name="vector2">The second two-dimensional vector.</param>
|
||||
*/
|
||||
public static Vector2 operator -(Vector2 vector1, Vector2 vector2)
|
||||
{
|
||||
return new Vector2(vector1.x_ - vector2.x_, vector1.y_ - vector2.y_);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Computes the negation of the specified two-dimensional
|
||||
* vector.</summary>
|
||||
*
|
||||
* <returns>The negation of the specified two-dimensional vector.
|
||||
* </returns>
|
||||
*
|
||||
* <param name="vector">The two-dimensional vector.</param>
|
||||
*/
|
||||
public static Vector2 operator -(Vector2 vector)
|
||||
{
|
||||
return new Vector2(-vector.x_, -vector.y_);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e3cacbab9ea44c3a3f2778d7d63d56f
|
||||
timeCreated: 1708509745
|
Reference in New Issue
Block a user