Commit e4e34fd9 authored by gsavin's avatar gsavin

Commit after merge to solve conflicts

parents d5f746b6 debface1
_______ _______ ______ _______ _________ ______ _______
( ____ \ ____ \ ( ___ \( ___ )\__ __/( __ \( ____ \
| ( \/ ( \/ | ( ) ) ( ) | ) ( | ( \ ) ( \/
| | | (_____ _____| (__/ /| | | | | | | | ) | (_____
| | ____(_____ )_____) __ ( | | | | | | | | | |_____ )
| | \_ ) ) | | ( \ \| | | | | | | | ) | ) |
| (___) |\____) | | )___) ) (___) |___) (___| (__/ )\____) |
(_______)_______) |/ \___/(_______)\_______/(______/\_______)
--framework for boids simulation in GraphStream --
::
_______ _______ ______ _______ _________ ______ _______
( ____ \ ____ \ ( ___ \( ___ )\__ __/( __ \( ____ \
| ( \/ ( \/ | ( ) ) ( ) | ) ( | ( \ ) ( \/
| | | (_____ _____| (__/ /| | | | | | | | ) | (_____
| | ____(_____ )_____) __ ( | | | | | | | | | |_____ )
| | \_ ) ) | | ( \ \| | | | | | | | ) | ) |
| (___) |\____) | | )___) ) (___) |___) (___| (__/ )\____) |
(_______)_______) |/ \___/(_______)\_______/(______/\_______)
A framework for boids simulation in GraphStream
===============================================
The gs-boids package provide an easy way to create a boid-like simulation and extract from it a dynamic graph. The basic idea is to consider one or more species of boids, each with its own parameters as defined by `Craig Reynolds <http://www.red3d.com/cwr/boids/>`_, and to associate with each of these boids a node in a graph. Then for each boid that actually sees another we create an edge. As the boids move in space they see different other boids and therefore the edge set evolves.
Boids
-----
The term boid comes from bird-oid, that is something that mimics the behavior of a real bird flying in flock. They where first imagined by Craig Reynolds as a way to simulate realistic flocks of birds, school of fiches, herds of animals, etc.
The principle is quite simple: each boid has three main behaviors:
* Separation: it tries to avoid colliding others.
* Cohesion: it tries to remain grouped with the others.
* Alignment: it tries to remain in the overall direction of others.
Boids have a limited angle and distance of vision, and therefore only consider others in a small area.
The simulation is iterative, at each step, each boid will consider its neighbors in its vision area and will try to apply the three main behavior laws to determine its new direction and eventually speed.
The result is a simulation where individuals form groups or flocks that fly together, can be split in subgroups or at the contrary merge in one big group.
Some variations can be added to such a simulation, like adding the notion of species, with several groups of boids having distinct parameters, some of them eventually fleeing when seeing another group (like a prey and a predator).
This boid simulation
--------------------
This boid simulation uses this same model, adding the idea of species, as well as some more parameters to fine tune the way groups appear, evolve and disappear.
Graphs from the simulation
--------------------------
By representing each boid with a node, and the visual interaction by an edge (a boid that sees another creates such an edge), we can define an evolving dynamic graph where edges are added or removed dynamically as groups form or disappear.
This is the basic idea of this module. This allows to build a large set of dynamic graph with various properties for testing algorithms on them.
Building
--------
As a facility a Maven POM file is provided to build this module. You will need the gs-core module to use it.
Using
-----
TODO.
......@@ -40,13 +40,43 @@ import org.miv.pherd.Particle;
import org.miv.pherd.geom.Point3;
import org.miv.pherd.geom.Vector3;
/**
* Represents a single bird-oid object.
*
* <p>
* A boid is both a particle in the forces system used to compute the position and motion
* of the object, and a GraphStream node. This allows to consider a graph made of
* all the boids.
* </p>
*
* <p>
* The boid is in fact split in two parts, the {@link Boid} class itself and the
* {@link BoidParticle} inner class that represents the boid in the forces system. The
* boid particle in turn contains a {@link Forces} object that represents all the forces
* exercising on the boid. Globally, the {@link Boid} class acts on the graph and updates
* its position, creating links toward other boids/nodes that it sees, whereas the
* {@link BoidParticle} and the {@link Forces} are used to compute the boid position.
* </p>
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public class Boid extends AdjacencyListNode {
protected final BoidSpecies species;
protected BoidParticle particle;
/** Parameters of this group of boids. */
/** The set of forces acting on this particle. */
protected Forces forces;
public Boid(Graph graph, BoidSpecies species, String id) {
/**
* New boid as a node in the given graph.
*
* @param graph The graph this boids pertains to.
* @param id The boid identifier in the graph and in the force system.
*/
super((AbstractGraph) graph, id);
this.particle = new BoidParticle((Context) graph);
......@@ -54,37 +84,40 @@ public class Boid extends AdjacencyListNode {
this.forces = getDefaultForces();
}
/** Force the position of the boid in space. */
public void setPosition(double x, double y, double z) {
particle.setPosition(x, y, z);
}
/** Actual position of the boid in space. */
public Point3 getPosition() {
return particle.getPosition();
}
/** Set of parameters used by this boid group. */
public BoidSpecies getSpecies() {
return species;
}
/** Change boid group and set of parameters. */
/** The underlying particle of the force system this boids is linked to. */
public BoidParticle getParticle() {
return particle;
}
/**
* The forces acting on the boids, this is a set of vectors and parameters
* computed at each time step.
*/
public Forces getDefaultForces() {
return new Forces.BasicForces();
}
protected void checkNeighborhood(BoidParticle... particles) {
// System.err.printf("Boid %s :%n", id);
if (particles != null) {
Iterator<Boid> it = getNeighborNodeIterator();
LinkedList<Boid> toRemove = null;
// System.err.printf("Sees [ ");
// for(BoidParticle p : particles) {
// System.err.printf("%s ", p.getBoid().id);
// }
// System.err.printf("]%nHas Neighbors [ ");
while (it.hasNext()) {
boolean found = false;
Boid b = it.next();
......@@ -95,17 +128,14 @@ public class Boid extends AdjacencyListNode {
break;
}
}
// System.err.printf("%s(%b)", b.id, found);
if (!found && !forces.isVisible(b.particle, this.getPosition())) {
if (toRemove == null)
toRemove = new LinkedList<Boid>();
// System.err.printf("(del)");
toRemove.add(b);
}
}
// System.err.printf("%n");
if (toRemove != null) {
for (Boid b : toRemove)
......@@ -114,18 +144,20 @@ public class Boid extends AdjacencyListNode {
toRemove.clear();
toRemove = null;
}
// System.err.printf("adds link to [ ");
for (BoidParticle p : particles) {
if (getEdgeBetween(p.getBoid().getId()) == null) {
getGraph().addEdge(getEdgeId(this, p.getBoid()), getId(),
p.getBoid().getId());
// System.err.printf("%s ", p.getBoid().id);
}
}
}
// System.err.printf("]%n");
}
/**
* Compute the edge identifier between two boids knowing their individual identifiers.
* This method ensures the identifiers are always in the same order so that we get the
* same edge whatever the order of the parameters b1 and b2.
*/
public static final String getEdgeId(Boid b1, Boid b2) {
if (b1.hashCode() > b2.hashCode()) {
Boid t = b1;
......@@ -136,15 +168,29 @@ public class Boid extends AdjacencyListNode {
return String.format("%s--%s", b1.getId(), b2.getId());
}
/**
* Internal representation of the boid position, and direction in the forces system.
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
class BoidParticle extends Particle {
/** Direction of the boid. */
protected Vector3 dir;
/** Set of global parameters. */
protected Context ctx;
/** Number of boids in view at each step. */
protected int contacts = 0;
/** Number of boids of my group in view at each step. */
protected int mySpeciesContacts = 0;
protected float energy = 0;
/**
* New particle.
* @param ctx The set of global parameters.
*/
public BoidParticle(Context ctx) {
super(Boid.this.getId(), ctx.random.nextDouble() * (ctx.area * 2)
- ctx.area, ctx.random.nextDouble() * (ctx.area * 2)
......@@ -189,21 +235,17 @@ public class Boid extends AdjacencyListNode {
checkWalls();
nextPos.move(dir);
Boid.this.setAttribute("x", pos.x);
Boid.this.setAttribute("y", pos.y);
Boid.this.setAttribute("z", pos.z);
Boid.this.setAttribute("xyz", pos.x, pos.y, pos.z);
moved = true;
}
@Override
public void inserted() {
}
@Override
public void removed() {
}
public Boid getBoid() {
......@@ -250,4 +292,4 @@ public class Boid extends AdjacencyListNode {
}
}
}
}
}
\ No newline at end of file
......@@ -9,14 +9,13 @@ import org.graphstream.boids.Context;
/**
* Parameters for each boids species.
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public class BoidSpecies implements Iterable<Boid> {
/**
*
*/
private static final long serialVersionUID = 6005548670964581065L;
/** Kinds of parameters. */
public static enum Parameter {
COUNT, ANGLE_OF_VIEW, VIEW_ZONE, SPEED_FACTOR, MAX_SPEED, MIN_SPEED, WIDTH, TRAIL, DIRECTION_FACTOR, ATTRACTION_FACTOR, REPULSION_FACTOR, INERTIA, FEAR_FACTOR
}
......@@ -47,7 +46,7 @@ public class BoidSpecies implements Iterable<Boid> {
/**
* The boid speed at each step. This is the factor by which the speedFactor
* vector is scaled to move the boid at each step. This therefore not only
* accelerate the boid displacement, it also impacts the boid behaviour
* accelerate the boid displacement, it also impacts the boid behavior
* (oscillation around the destination point, etc.)
*/
protected double speedFactor = 0.3f;
......@@ -99,13 +98,13 @@ public class BoidSpecies implements Iterable<Boid> {
protected double fearFactor = 1;
/**
* The species main colour.
* The species main color.
*/
protected Color color = new Color(1, 0, 0);
/**
* The size of the trail in the GUI if any.
*/
// /**
// * The size of the trail in the GUI if any.
// */
protected int trail = 0;
/**
......@@ -114,12 +113,10 @@ public class BoidSpecies implements Iterable<Boid> {
protected int width = 4;
protected HashMap<String, Boid> boids;
private int currentIndex = 0;
private long timestamp = System.nanoTime();
/**
* New default species with a random colour.
* New default species with a random color.
*/
public BoidSpecies(Context ctx, String name) {
this.boids = new HashMap<String, Boid>();
......@@ -132,7 +129,6 @@ public class BoidSpecies implements Iterable<Boid> {
public String getName() {
return name;
}
public Iterator<Boid> iterator() {
return boids.values().iterator();
}
......@@ -164,9 +160,9 @@ public class BoidSpecies implements Iterable<Boid> {
case WIDTH:
width = Integer.parseInt(val);
break;
case TRAIL:
trail = Integer.parseInt(val);
break;
// case TRAIL:
// trail = Integer.parseInt(val);
// break;
case DIRECTION_FACTOR:
directionFactor = Double.parseDouble(val);
break;
......@@ -215,97 +211,185 @@ public class BoidSpecies implements Iterable<Boid> {
public int getPopulation() {
return boids.size();
*/
}
/**
* Change the initial number of boids of this species.
*/
public void setCount(int count) {
while (boids.size() < count)
ctx.addNode(createNewId());
/**
* The species name.
*/
/**
* Change the species name.
*/
}
/**
* The distance at which a boid is seen.
*/
public double getViewZone() {
return viewZone;
}
/**
* Change the distance at which a boid is seen.
*/
public void setViewZone(double viewZone) {
this.viewZone = viewZone;
}
/**
* The boid speed at each step. This is the factor by which the speedFactor
* vector is scaled to move the boid at each step. This therefore not only
* accelerate the boid displacement, it also impacts the boid behavior
* (oscillation around the destination point, etc.)
*/
public double getSpeedFactor() {
return speedFactor;
}
/**
* Change the boid speed at each step.
*/
public void setSpeedFactor(double speedFactor) {
this.speedFactor = speedFactor;
}
/**
* Maximum speed bound.
*/
public double getMaxSpeed() {
return maxSpeed;
}
/**
* Change the maximum speed bound.
*/
public void setMaxSpeed(double maxSpeed) {
this.maxSpeed = maxSpeed;
}
/**
* Minimum speed bound.
*/
public double getMinSpeed() {
return minSpeed;
}
/**
* Change the minimum speed bound.
*/
public void setMinSpeed(double minSpeed) {
this.minSpeed = minSpeed;
}
/**
* The importance of the other boids direction "overall" vector. The
* direction vector is the sum of all the visible boids direction vector
* divided by the number of boids seen. This factor is the importance of
* this direction in the boid direction.
*/
public double getDirectionFactor() {
return directionFactor;
}
/**
* Change the importance of the other boids direction "overall" vector.
*/
public void setDirectionFactor(double directionFactor) {
this.directionFactor = directionFactor;
}
/**
* How much other visible boids attract a boid. The barycenter of the
* visible boids attract a boid. The attraction is the vector between the
* boid an this barycenter. This factor is the importance of this vector in
* the boid direction.
*/
public double getAttractionFactor() {
return attractionFactor;
}
/**
* Change how much other visible boids attract a boid.
*/
public void setAttractionFactor(double attractionFactor) {
this.attractionFactor = attractionFactor;
}
/**
* All the visible boids repulse the boid. The repulsion vector is the sum
* of all the vectors between all other visible boids and the considered
* boid, scaled by the number of visible boids. This factor is the
* importance of this vector in the boid direction.
*/
public double getRepulsionFactor() {
return repulsionFactor;
}
/**
* Change how all the visible boids repulse the boid.
*/
public void setRepulsionFactor(double repulsionFactor) {
this.repulsionFactor = repulsionFactor;
}
/**
* The inertia is the importance of the boid previous direction in the boid
* direction.
*/
public double getInertia() {
return inertia;
}
/**
* Change the inertia is the importance of the boid previous direction in the boid
* direction.
*/
public void setInertia(double inertia) {
this.inertia = inertia;
}
/**
* Factor for repulsion on boids of other species. The fear that this
* species produces on other species.
*/
public double getFearFactor() {
return fearFactor;
}
/**
* Change the factor for repulsion on boids of other species.
*/
public void setFearFactor(double fearFactor) {
this.fearFactor = fearFactor;
}
/**
* The species main color.
*/
public Color getColor() {
return color;
}
/**
* Change the species main color.
*/
public void setColor(Color color) {
this.color = color;
}
public void setTrail(int trail) {
this.trail = trail;
}
// public void setTrail(int trail) {
// this.trail = trail;
// }
/**
* Change the width of the particle in the GUI if any.
*/
public void setWidth(int width) {
this.width = width;
}
......
......@@ -30,9 +30,9 @@
*/
package org.graphstream.boids;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.graphstream.boids.Boid.BoidParticle;
import org.miv.pherd.Particle;
......@@ -41,19 +41,39 @@ import org.miv.pherd.geom.Vector3;
import org.miv.pherd.ntree.Cell;
/**
* Models the forces applied to a boid.
* Models the forces applied to a boid at each step.
*
* <p>
* This object is modified at each computation step to represent the forces applied to
* a boid particle in the forces system. It is in charge of going down the n-tree used
* to represent space and collect all the other boids in the field of view that could influence
* this boid. It then integrates these forces and compute a direction and barycenter (the
* point the boid tries to reach).
* </p>
*
* @author Guilhelm Savin
* @author Antoine Dutot
*
*/
public abstract class Forces {
/** The position the boid tries to reach at each step. */
public Point3 barycenter;
/** The direction of the boid at each step. */
public Vector3 direction;
/** The integrated attraction toward other boids in view at each step. */
public Vector3 attraction;
/** The integrated repulsion from the other boids in view at each step. */
public Vector3 repulsion;
/** The number of boids we are attracted to. */
public int countAtt;
/** The number of boids we are repulsed from. */
public int countRep;
/** Forces all set at zero. */
public Forces() {
barycenter = new Point3();
direction = new Vector3();
......@@ -91,30 +111,42 @@ public abstract class Forces {
boid.setAttribute("force2", repulsion);
}
/** Integrate a repulsion vector. */
public void addRepulsion(Vector3 rep) {
repulsion.add(rep);
countRep++;
}
/** Integrate a direction influence. */
public void addDirection(Vector3 dir) {
direction.add(dir);
countAtt++;
}
/** Integrate an attraction vector. */
public void addAttraction(Vector3 att) {
attraction.add(att);
countAtt++;
}
/** Integrate a new point of influence. */
public void moveBarycenter(Point3 p) {
barycenter.move(p);
}
/** Is the another point is space in the field of view? */
public abstract boolean isVisible(BoidParticle boid, Point3 other);
/**
* A definition of the forces.
* A basic definition of forces for a boid.
*
* <p>
* The kind of forces exercising on a boid can be changed to either use a n-tree or not,
* or to account for other kind of forces or another force model. This is the default
* force system that matches the basic boid definition as defined by Craig Reynolds.
* </p>
*
* @author Guilhelm Savin
* @author Antoine Dutot
*/
public static class BasicForces extends Forces {
......@@ -199,10 +231,6 @@ public abstract class Forces {
}
}
// source.getBoid().checkNeighborhood(
// contacts == null ? null : contacts
// .toArray(new BoidParticle[contacts.size()]));
// barycenter.move( data.getCenter() );
// direction.add( data.getDirection() );
}
......@@ -238,14 +266,14 @@ public abstract class Forces {
// intersection (cases c, d, e and f).
//
// |-a-| +---------+ |-b-|
// | |
// |-c-| |-d-|
// | |
// | |-e-| |
// | |
// |-+----f----+-|
// | |
// +---------+
// | |
// |-c-| |-d-|
// | |
// | |-e-| |
// | |
// |-+----f----+-|
// | |
// +---------+
if (X2 < x1 || X1 > x2)
return false;
......@@ -262,15 +290,23 @@ public abstract class Forces {