added tests - no sogs yet
parent
8f8da4ea10
commit
cdbac1c921
|
@ -42,7 +42,7 @@ namespace Flocking
|
|||
private Random m_rndnums = new Random (Environment.TickCount);
|
||||
|
||||
private FlockingModel m_model;
|
||||
private FlowMap m_flowMap;
|
||||
private FlowField m_flowField;
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
@ -57,13 +57,13 @@ namespace Flocking
|
|||
/// <param name='mf'>
|
||||
/// Mf. max force / acceleration this boid can extert
|
||||
/// </param>
|
||||
public Boid (string id, FlockingModel model, FlowMap flowMap)
|
||||
public Boid (string id, FlockingModel model, FlowField flowField)
|
||||
{
|
||||
m_id = id;
|
||||
m_acc = Vector3.Zero;
|
||||
m_vel = new Vector3 (m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1), m_rndnums.Next (-1, 1));
|
||||
m_model = model;
|
||||
m_flowMap = flowMap;
|
||||
m_flowField = flowField;
|
||||
}
|
||||
|
||||
public Vector3 Location {
|
||||
|
@ -91,6 +91,7 @@ namespace Flocking
|
|||
Flock (boids);
|
||||
|
||||
// our first priority is to not hurt ourselves
|
||||
// so adjust where we would like to go to avoid hitting things
|
||||
AvoidObstacles ();
|
||||
|
||||
// then we want to avoid any threats
|
||||
|
@ -211,51 +212,14 @@ namespace Flocking
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// Borders this instance.
|
||||
/// if we get too close wrap us around
|
||||
/// CHANGE THIS to navigate away from whatever it is we are too close to
|
||||
/// navigate away from whatever it is we are too close to
|
||||
/// </summary>
|
||||
void AvoidObstacles ()
|
||||
{
|
||||
//look tolerance metres ahead
|
||||
Vector3 normVel = Vector3.Normalize(m_vel);
|
||||
Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance);
|
||||
if( m_flowMap.WouldHitObstacle( m_loc, inFront ) ) {
|
||||
AdjustVelocityToAvoidObstacles ();
|
||||
|
||||
}
|
||||
m_acc += m_flowField.AdjustVelocity( m_loc, m_vel, m_model.Tolerance );
|
||||
}
|
||||
|
||||
void AdjustVelocityToAvoidObstacles ()
|
||||
{
|
||||
for( int i = 1; i < 5; i++ ) {
|
||||
Vector3 normVel = Vector3.Normalize(m_vel);
|
||||
int xDelta = m_rndnums.Next (-i, i);
|
||||
int yDelta = m_rndnums.Next (-i, i);
|
||||
int zDelta = m_rndnums.Next (-i, i);
|
||||
normVel.X += xDelta;
|
||||
normVel.Y += yDelta;
|
||||
normVel.Z += zDelta;
|
||||
Vector3 inFront = m_loc + Vector3.Multiply(normVel, m_model.Tolerance);
|
||||
if( !m_flowMap.WouldHitObstacle( m_loc, inFront ) ) {
|
||||
m_vel.X += xDelta;
|
||||
m_vel.Y += yDelta;
|
||||
m_vel.Z += zDelta;
|
||||
//m_log.Info("avoided");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//m_log.Info("didn't avoid");
|
||||
// try increaing our acceleration
|
||||
// or try decreasing our acceleration
|
||||
// or turn around - coz where we came from was OK
|
||||
if (m_loc.X < 5 || m_loc.X > 250)
|
||||
m_vel.X = -m_vel.X;
|
||||
if (m_loc.Y < 5 || m_loc.Y > 250)
|
||||
m_vel.Y = -m_vel.Y;
|
||||
if (m_loc.Z < 21 || m_loc.Z > 271 )
|
||||
m_vel.Z = -m_vel.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Separate ourselves from the specified boids.
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
<include name="FlockingModel.cs" />
|
||||
<include name="FlockingModule.cs" />
|
||||
<include name="FlockingView.cs" />
|
||||
<include name="FlowField.cs" />
|
||||
<include name="FlowFieldTest.cs" />
|
||||
<include name="FlowMap.cs" />
|
||||
<include name="Util.cs" />
|
||||
</sources>
|
||||
|
@ -30,12 +32,14 @@
|
|||
</lib>
|
||||
<include name="../../../bin/log4net.dll"/>
|
||||
<include name="../../../bin/Nini.dll"/>
|
||||
<include name="../../../bin/nunit.framework.dll"/>
|
||||
<include name="../../../bin/OpenMetaverse.dll"/>
|
||||
<include name="../../../bin/OpenMetaverseTypes.dll"/>
|
||||
<include name="../../../bin/OpenSim.Framework.dll"/>
|
||||
<include name="../../../bin/OpenSim.Framework.Communications.dll"/>
|
||||
<include name="../../../bin/OpenSim.Framework.Console.dll"/>
|
||||
<include name="../../../bin/OpenSim.Region.Framework.dll"/>
|
||||
<include name="../../../bin/OpenSim.Tests.Common.dll"/>
|
||||
<include name="System.dll" />
|
||||
<include name="System.Drawing.dll" />
|
||||
<include name="System.Xml.dll" />
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Flocking
|
|||
public class FlockingModel
|
||||
{
|
||||
private List<Boid> m_flock = new List<Boid>();
|
||||
private FlowMap m_flowMap;
|
||||
private FlowField m_flowField;
|
||||
private float m_maxSpeed;
|
||||
private float m_maxForce;
|
||||
private float m_neighbourDistance;
|
||||
|
@ -63,21 +63,15 @@ namespace Flocking
|
|||
|
||||
void AddBoid (string name)
|
||||
{
|
||||
Boid boid = new Boid (name, this, m_flowMap);
|
||||
Boid boid = new Boid (name, this, m_flowField);
|
||||
|
||||
// find an initial random location for this Boid
|
||||
// somewhere not within an obstacle
|
||||
int xInit = m_rnd.Next(m_flowMap.LengthX);
|
||||
int yInit = m_rnd.Next(m_flowMap.LengthY);
|
||||
int zInit = m_rnd.Next(m_flowMap.LengthZ);
|
||||
|
||||
while( m_flowMap.IsWithinObstacle( xInit, yInit, zInit ) ){
|
||||
xInit = m_rnd.Next(m_flowMap.LengthX);
|
||||
yInit = m_rnd.Next(m_flowMap.LengthY);
|
||||
zInit = m_rnd.Next(m_flowMap.LengthZ);
|
||||
}
|
||||
|
||||
boid.Location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit));
|
||||
int xInit = m_rnd.Next(Util.SCENE_SIZE);
|
||||
int yInit = m_rnd.Next(Util.SCENE_SIZE);
|
||||
int zInit = m_rnd.Next(Util.SCENE_SIZE);
|
||||
Vector3 location = new Vector3 (Convert.ToSingle(xInit), Convert.ToSingle(yInit), Convert.ToSingle(zInit));
|
||||
boid.Location = location + m_flowField.AdjustVelocity(location, Vector3.UnitZ, 5f);
|
||||
m_flock.Add (boid);
|
||||
}
|
||||
|
||||
|
@ -102,9 +96,9 @@ namespace Flocking
|
|||
}
|
||||
|
||||
|
||||
public void Initialise (int num, FlowMap flowMap)
|
||||
public void Initialise (int num, FlowField flowField)
|
||||
{
|
||||
m_flowMap = flowMap;
|
||||
m_flowField = flowField;
|
||||
for (int i = 0; i < num; i++) {
|
||||
AddBoid ("boid"+i );
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ namespace Flocking
|
|||
|
||||
public void AddRegion (Scene scene)
|
||||
{
|
||||
m_log.Info ("ADDING FLOCKING");
|
||||
//m_log.Info ("ADDING FLOCKING");
|
||||
m_scene = scene;
|
||||
if (m_enabled) {
|
||||
//register commands
|
||||
|
@ -112,11 +112,14 @@ namespace Flocking
|
|||
if (m_enabled) {
|
||||
|
||||
//make a flow map for this scene
|
||||
FlowMap flowMap = new FlowMap(scene );
|
||||
flowMap.Initialise();
|
||||
//FlowMap flowMap = new FlowMap(scene );
|
||||
//flowMap.Initialise();
|
||||
|
||||
//build a proper flow field based on the scene
|
||||
FlowField field = new FlowField(scene, new Vector3(128f, 128f, 128f), 200, 200, 200);
|
||||
|
||||
// Generate initial flock values
|
||||
m_model.Initialise (m_flockSize, flowMap);
|
||||
m_model.Initialise (m_flockSize, field);
|
||||
|
||||
// who is the owner for the flock in this region
|
||||
m_owner = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
|
@ -282,7 +285,8 @@ namespace Flocking
|
|||
{
|
||||
if (ShouldHandleCmd ()) {
|
||||
bool inWorld = IsInWorldCmd (ref args);
|
||||
ShowResponse ("Num Boids = " + m_model.Size, inWorld);
|
||||
string str = "Num Boids = " + m_model.Size;
|
||||
ShowResponse (str, inWorld);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace Flocking
|
||||
{
|
||||
public class FlowField
|
||||
{
|
||||
private const int BUFFER = 5;
|
||||
private Scene m_scene;
|
||||
private float m_startX;
|
||||
private float m_startY;
|
||||
private float m_startZ;
|
||||
private float m_endX;
|
||||
private float m_endY;
|
||||
private float m_endZ;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Flocking.FlowField"/> class.
|
||||
/// </summary>
|
||||
/// <param name='scene'>
|
||||
/// Scene.
|
||||
/// </param>
|
||||
/// <param name='centre'>
|
||||
/// Centre.
|
||||
/// </param>
|
||||
/// <param name='width'>
|
||||
/// Width.
|
||||
/// </param>
|
||||
/// <param name='depth'>
|
||||
/// Depth.
|
||||
/// </param>
|
||||
/// <param name='height'>
|
||||
/// Height.
|
||||
/// </param>
|
||||
///
|
||||
public FlowField (Scene scene, Vector3 centre, int width, int depth, int height)
|
||||
{
|
||||
m_scene = scene;
|
||||
|
||||
m_startX = Math.Max( BUFFER, centre.X - width/2f);
|
||||
m_startY = Math.Max( BUFFER, centre.Y - depth/2f);
|
||||
m_startZ = Math.Max( BUFFER, centre.Z - height/2f);
|
||||
m_endX = Math.Min( Util.SCENE_SIZE - BUFFER, centre.X + width/2f);
|
||||
m_endY = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Y + depth/2f);
|
||||
m_endZ = Math.Min( Util.SCENE_SIZE - BUFFER, centre.Z + height/2f);
|
||||
|
||||
// build the flow field over the given bounds
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// build a flow field on the scene at the specified centre
|
||||
/// position in the scene and of extent given by width, depth and height.
|
||||
/// </summary>
|
||||
public void Initialize() {
|
||||
foreach( SceneObjectGroup sog in m_scene.Entities.GetAllByType<SceneObjectGroup>() ) {
|
||||
float offsetHeight;
|
||||
Vector3 size = sog.GetAxisAlignedBoundingBox( out offsetHeight );
|
||||
Vector3 pos = sog.AbsolutePosition;
|
||||
|
||||
// color in the flow field with the strength at this pos due to
|
||||
// this sog
|
||||
for( int x = 0; x < size.X; x++ ) {
|
||||
for( int y = 0; y < size.Y; y++ ) {
|
||||
for( int z = 0; z < size.Z; z++ ) {
|
||||
if( IsWithinFlowField(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 AdjustVelocity (Vector3 loc, Vector3 vel, float lookAheadDist)
|
||||
{
|
||||
Vector3 normVel = Vector3.Normalize(vel);
|
||||
Vector3 inFront = loc + normVel * lookAheadDist;
|
||||
Vector3 adjustedDestintation = inFront + FieldStrength(inFront);
|
||||
Vector3 newVel = Vector3.Normalize(adjustedDestintation - loc) * Vector3.Mag(vel);
|
||||
return newVel;
|
||||
}
|
||||
|
||||
public Vector3 FieldStrength (Vector3 inFront)
|
||||
{
|
||||
Vector3 retVal = Vector3.Zero;
|
||||
|
||||
//keep us in bounds
|
||||
if( inFront.X > m_endX ) retVal.X -= inFront.X - m_endX;
|
||||
if( inFront.Y > m_endY ) retVal.Y -= inFront.Y - m_endY;
|
||||
if( inFront.Z > m_endZ ) retVal.Z -= inFront.Z - m_endZ;
|
||||
if( inFront.X < m_startX ) retVal.X += m_startX - inFront.X;
|
||||
if( inFront.Y < m_startY ) retVal.Y += m_startY - inFront.Y;
|
||||
if( inFront.Z < m_startZ ) retVal.Z += m_startZ - inFront.Z;
|
||||
|
||||
//now get the field strength at the inbounds position
|
||||
Vector3 strength = LookUp( inFront + retVal);
|
||||
|
||||
return retVal + strength;
|
||||
}
|
||||
|
||||
public Vector3 LookUp (Vector3 par1)
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Tests.Common;
|
||||
using OpenSim.Tests.Common.Mock;
|
||||
|
||||
|
||||
namespace Flocking
|
||||
{
|
||||
[TestFixture()]
|
||||
public class FlowFieldTest
|
||||
{
|
||||
[Test()]
|
||||
public void TestEmptyFlowField ()
|
||||
{
|
||||
Scene scene = SceneSetupHelpers.SetupScene();
|
||||
|
||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
||||
Vector3 strength = field.FieldStrength (centre);
|
||||
Assert.That( strength == Vector3.Zero);
|
||||
}
|
||||
|
||||
[Test()]
|
||||
public void TestWeCanMoveFreely ()
|
||||
{
|
||||
Scene scene = SceneSetupHelpers.SetupScene();
|
||||
|
||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
||||
Vector3 pos = new Vector3(100f, 100f,100f);
|
||||
Vector3 velocity = new Vector3(20f, 0f, 0f);
|
||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
||||
Console.WriteLine( newVel );
|
||||
Assert.That(newVel == velocity);
|
||||
Vector3 newPos = pos+newVel;
|
||||
Assert.That( newPos.X < 150f);
|
||||
}
|
||||
|
||||
[Test()]
|
||||
public void TestWeDontFallOfTheEdge ()
|
||||
{
|
||||
Scene scene = SceneSetupHelpers.SetupScene();
|
||||
|
||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
||||
|
||||
Vector3 pos = new Vector3(140f, 100f,100f);
|
||||
Vector3 velocity = new Vector3(20f, 0f, 0f);
|
||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
||||
Console.WriteLine( newVel );
|
||||
Vector3 newPos = pos+newVel;
|
||||
Assert.That( newPos.X < 150f);
|
||||
Assert.That(velocity != newVel);
|
||||
|
||||
pos = new Vector3(60f, 100f, 100f);
|
||||
velocity = new Vector3(-20f, 0f, 0f);
|
||||
newVel = field.AdjustVelocity(pos, velocity, 10);
|
||||
newPos = pos+newVel;
|
||||
Assert.That( newPos.X > 50f );
|
||||
Assert.That(velocity != newVel);
|
||||
}
|
||||
|
||||
[Test()]
|
||||
public void TestWeCanCopeWithCorners ()
|
||||
{
|
||||
Scene scene = SceneSetupHelpers.SetupScene();
|
||||
|
||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
||||
Vector3 pos = new Vector3(140f, 140f,140f);
|
||||
Vector3 velocity = new Vector3(20f, 20f, 20f); // going to hit the corner
|
||||
Vector3 newVel = field.AdjustVelocity (pos, velocity, 10);
|
||||
Console.WriteLine( newVel );
|
||||
Vector3 newPos = pos+newVel;
|
||||
Assert.That( newPos.X < 150f);
|
||||
Assert.That( newPos.Y < 150f);
|
||||
Assert.That( newPos.Z < 150f);
|
||||
Assert.That(velocity != newVel);
|
||||
}
|
||||
|
||||
[Test()]
|
||||
[Ignore()]
|
||||
public void TestNonEmptyFlowField ()
|
||||
{
|
||||
Scene scene = SceneSetupHelpers.SetupScene();
|
||||
Vector3 centre = new Vector3 (100f, 100f, 100f);
|
||||
SceneObjectGroup sceneObjectGroup = AddSog (centre, new Vector3(10f,10f,10f));
|
||||
scene.AddNewSceneObject(sceneObjectGroup, false);
|
||||
|
||||
FlowField field = new FlowField(scene, centre, 50, 50, 50);
|
||||
Vector3 strength = field.FieldStrength (centre);
|
||||
Assert.That( strength != Vector3.Zero);
|
||||
|
||||
}
|
||||
|
||||
public static SceneObjectGroup AddSog (Vector3 position, Vector3 size)
|
||||
{
|
||||
UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010");
|
||||
string part1Name = "part1";
|
||||
UUID part1Id = new UUID("00000000-0000-0000-0000-000000000001");
|
||||
string part2Name = "part2";
|
||||
UUID part2Id = new UUID("00000000-0000-0000-0000-000000000002");
|
||||
|
||||
SceneObjectPart part1
|
||||
= new SceneObjectPart(ownerId, PrimitiveBaseShape.Default, position, Quaternion.Identity, Vector3.Zero)
|
||||
{ Name = part1Name, UUID = part1Id };
|
||||
part1.Scale =size;
|
||||
SceneObjectGroup so = new SceneObjectGroup(part1);
|
||||
|
||||
return so;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,8 +29,11 @@ using OpenMetaverse;
|
|||
|
||||
namespace Flocking
|
||||
{
|
||||
|
||||
public class Util
|
||||
{
|
||||
public const int SCENE_SIZE = 256;
|
||||
|
||||
public static Vector3 Limit (Vector3 initial, float maxLen)
|
||||
{
|
||||
float currLen = initial.Length ();
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
<Reference name="System.Drawing" />
|
||||
<Reference name="System.Xml"/>
|
||||
<Reference name="Nini" path="../../../bin/" />
|
||||
<Reference name="nunit.framework" path="../../../bin/" />
|
||||
<Reference name="OpenSim.Framework" path="../../../bin/" />
|
||||
<Reference name="OpenSim.Tests.Common" path="../../../bin/" />
|
||||
<Reference name="OpenSim.Framework.Communications" path="../../../bin/" />
|
||||
<Reference name="OpenSim.Region.Framework" path="../../../bin/" />
|
||||
<Reference name="OpenSim.Framework.Console" path="../../../bin/" />
|
||||
|
|
Loading…
Reference in New Issue