added tests - no sogs yet

stable0711
Jon Cundill 2011-07-16 08:56:20 +01:00
parent 8f8da4ea10
commit cdbac1c921
8 changed files with 259 additions and 62 deletions

View File

@ -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.

View File

@ -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" />

View File

@ -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 );
}

View File

@ -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);
}
}

108
Flocking/FlowField.cs Normal file
View File

@ -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;
}
}
}

118
Flocking/FlowFieldTest.cs Normal file
View File

@ -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;
}
}
}

View File

@ -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 ();

View File

@ -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/" />