Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
graphstream
gs-boids
Commits
536f6f16
Commit
536f6f16
authored
Apr 21, 2011
by
gsavin
Browse files
Initial source commit.
parent
b81e937b
Changes
17
Hide whitespace changes
Inline
Side-by-side
lib/glutil.jar
0 → 100644
View file @
536f6f16
File added
src/org/graphstream/boids/Boid.java
0 → 100644
View file @
536f6f16
/*
* Copyright 2006 - 2011
* Julien Baudry <julien.baudry@graphstream-project.org>
* Antoine Dutot <antoine.dutot@graphstream-project.org>
* Yoann Pigné <yoann.pigne@graphstream-project.org>
* Guilhelm Savin <guilhelm.savin@graphstream-project.org>
*
* This file is part of GraphStream <http://graphstream-project.org>.
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
package
org.graphstream.boids
;
import
java.util.Iterator
;
import
java.util.LinkedList
;
import
org.graphstream.graph.Graph
;
import
org.graphstream.graph.implementations.AdjacencyListNode
;
import
org.miv.pherd.Particle
;
import
org.miv.pherd.geom.Point3
;
import
org.miv.pherd.geom.Vector3
;
public
class
Boid
extends
AdjacencyListNode
{
protected
BoidParticle
particle
;
protected
BoidSpecies
species
;
protected
Forces
forces
;
public
Boid
(
Graph
graph
,
String
id
)
{
super
(
graph
,
id
);
particle
=
new
BoidParticle
((
Context
)
graph
);
species
=
((
Context
)
graph
).
getDefaultSpecies
();
forces
=
getDefaultForces
();
}
public
void
setPosition
(
double
x
,
double
y
,
double
z
)
{
particle
.
setPosition
(
x
,
y
,
z
);
}
public
Point3
getPosition
()
{
return
particle
.
getPosition
();
}
public
BoidSpecies
getSpecies
()
{
return
species
;
}
public
void
setSpecies
(
BoidSpecies
species
)
{
this
.
species
=
species
;
}
public
BoidParticle
getParticle
()
{
return
particle
;
}
public
Forces
getDefaultForces
()
{
return
new
Forces
.
BasicForces
();
}
protected
void
attributeChanged
(
String
sourceId
,
long
timeId
,
String
attribute
,
AttributeChangeEvent
event
,
Object
oldValue
,
Object
newValue
)
{
if
(
attribute
.
equals
(
"species"
))
{
Context
ctx
=
(
Context
)
getGraph
();
BoidSpecies
species
=
ctx
.
getOrCreateSpecies
(
newValue
.
toString
());
this
.
species
=
species
;
}
super
.
attributeChanged
(
sourceId
,
timeId
,
attribute
,
event
,
oldValue
,
newValue
);
}
protected
void
checkNeighborhood
(
BoidParticle
...
particles
)
{
if
(
particles
!=
null
)
{
Iterator
<
Boid
>
it
=
getNeighborNodeIterator
();
LinkedList
<
Boid
>
toRemove
=
null
;
while
(
it
.
hasNext
())
{
boolean
found
=
false
;
Boid
b
=
it
.
next
();
for
(
BoidParticle
p
:
particles
)
if
(
p
.
getId
().
equals
(
b
.
getParticle
().
getId
()))
{
found
=
true
;
break
;
}
if
(!
found
)
{
if
(
toRemove
==
null
)
toRemove
=
new
LinkedList
<
Boid
>();
toRemove
.
add
(
b
);
}
}
if
(
toRemove
!=
null
)
{
for
(
Boid
b
:
toRemove
)
getGraph
().
removeEdge
(
getEdgeId
(
this
,
b
));
toRemove
.
clear
();
toRemove
=
null
;
}
for
(
BoidParticle
p
:
particles
)
{
if
(
getEdgeBetween
(
p
.
getBoid
().
getId
())
==
null
)
getGraph
().
addEdge
(
getEdgeId
(
this
,
p
.
getBoid
()),
getId
(),
p
.
getBoid
().
getId
());
}
}
}
public
static
final
String
getEdgeId
(
Boid
b1
,
Boid
b2
)
{
if
(
b1
.
hashCode
()
>
b2
.
hashCode
())
{
Boid
t
=
b1
;
b1
=
b2
;
b2
=
t
;
}
return
String
.
format
(
"%s--%s"
,
b1
.
getId
(),
b2
.
getId
());
}
class
BoidParticle
extends
Particle
{
protected
Vector3
dir
;
protected
Context
ctx
;
protected
int
contacts
=
0
;
protected
int
mySpeciesContacts
=
0
;
protected
float
energy
=
0
;
public
BoidParticle
(
Context
ctx
)
{
super
(
Boid
.
this
.
getId
(),
ctx
.
random
.
nextDouble
()
*
(
ctx
.
area
*
2
)
-
ctx
.
area
,
ctx
.
random
.
nextDouble
()
*
(
ctx
.
area
*
2
)
-
ctx
.
area
,
0
);
this
.
dir
=
new
Vector3
(
ctx
.
random
.
nextDouble
(),
ctx
.
random
.
nextDouble
(),
0
);
this
.
ctx
=
ctx
;
}
public
void
move
(
int
time
)
{
contacts
=
0
;
mySpeciesContacts
=
0
;
forces
.
compute
(
Boid
.
this
,
cell
.
getTree
().
getRootCell
());
forces
.
direction
.
scalarMult
(
species
.
directionFactor
);
forces
.
attraction
.
scalarMult
(
species
.
attractionFactor
);
forces
.
repulsion
.
scalarMult
(
species
.
repulsionFactor
);
dir
.
scalarMult
(
species
.
inertia
);
dir
.
add
(
forces
.
direction
);
dir
.
add
(
forces
.
attraction
);
dir
.
add
(
forces
.
repulsion
);
if
(
ctx
.
normalizeMode
)
{
double
len
=
dir
.
normalize
();
if
(
len
<=
species
.
minSpeed
)
len
=
species
.
minSpeed
;
else
if
(
len
>=
species
.
maxSpeed
)
len
=
species
.
maxSpeed
;
dir
.
scalarMult
(
species
.
speedFactor
*
len
);
}
else
{
dir
.
scalarMult
(
species
.
speedFactor
);
}
if
(
ctx
.
storeForcesAttributes
)
forces
.
store
(
this
);
checkWalls
();
nextPos
.
move
(
dir
);
Boid
.
this
.
setAttribute
(
"x"
,
pos
.
x
);
Boid
.
this
.
setAttribute
(
"y"
,
pos
.
y
);
Boid
.
this
.
setAttribute
(
"z"
,
pos
.
z
);
moved
=
true
;
}
public
void
inserted
()
{
}
public
void
removed
()
{
}
public
Boid
getBoid
()
{
return
Boid
.
this
;
}
public
void
setPosition
(
double
x
,
double
y
,
double
z
)
{
initPos
(
x
,
y
,
z
);
}
/**
* Check the boid does not go out of the space walls.
*/
protected
void
checkWalls
()
{
// /float area = ctx.area;
float
aarea
=
0.000001f
;
if
(
nextPos
.
x
+
dir
.
data
[
0
]
<=
ctx
.
getSpace
().
getLoAnchor
().
x
+
aarea
)
{
nextPos
.
x
=
ctx
.
getSpace
().
getLoAnchor
().
x
+
aarea
;
dir
.
data
[
0
]
=
-
dir
.
data
[
0
];
}
else
if
(
nextPos
.
x
+
dir
.
data
[
0
]
>=
ctx
.
getSpace
().
getHiAnchor
().
x
-
aarea
)
{
nextPos
.
x
=
ctx
.
getSpace
().
getHiAnchor
().
x
-
aarea
;
dir
.
data
[
0
]
=
-
dir
.
data
[
0
];
}
if
(
nextPos
.
y
+
dir
.
data
[
1
]
<=
ctx
.
getSpace
().
getLoAnchor
().
y
+
aarea
)
{
nextPos
.
y
=
ctx
.
getSpace
().
getLoAnchor
().
y
+
aarea
;
dir
.
data
[
1
]
=
-
dir
.
data
[
1
];
}
else
if
(
nextPos
.
y
+
dir
.
data
[
1
]
>=
ctx
.
getSpace
().
getHiAnchor
().
y
-
aarea
)
{
nextPos
.
y
=
ctx
.
getSpace
().
getHiAnchor
().
y
-
aarea
;
dir
.
data
[
1
]
=
-
dir
.
data
[
1
];
}
if
(
nextPos
.
z
+
dir
.
data
[
2
]
<=
ctx
.
getSpace
().
getLoAnchor
().
z
+
aarea
)
{
nextPos
.
z
=
ctx
.
getSpace
().
getLoAnchor
().
z
+
aarea
;
dir
.
data
[
2
]
=
-
dir
.
data
[
2
];
}
else
if
(
nextPos
.
z
+
dir
.
data
[
2
]
>=
ctx
.
getSpace
().
getHiAnchor
().
z
-
aarea
)
{
nextPos
.
z
=
ctx
.
getSpace
().
getHiAnchor
().
z
-
aarea
;
dir
.
data
[
2
]
=
-
dir
.
data
[
2
];
}
}
}
}
src/org/graphstream/boids/BoidCellData.java
0 → 100644
View file @
536f6f16
package
org.graphstream.boids
;
import
java.util.Iterator
;
import
org.graphstream.boids.Boid.BoidParticle
;
import
org.miv.pherd.Particle
;
import
org.miv.pherd.geom.Vector3
;
import
org.miv.pherd.ntree.BarycenterCellData
;
import
org.miv.pherd.ntree.Cell
;
import
org.miv.pherd.ntree.CellData
;
import
org.miv.pherd.ntree.NTreeListener
;
/**
* Compute both the barycenter and average direction of the particles in the
* box.
*
* XXX TODO there are bugs here, verify this code and reuse it in the boid
* computation (actually the ntree is used only to go faster in searching
* neighbors).
*
* @author Antoine Dutot
* @since 2007
*/
public
class
BoidCellData
extends
BarycenterCellData
{
// Attributes
public
Vector3
dir
;
// Constructors
public
BoidCellData
()
{
super
();
dir
=
new
Vector3
(
0
,
0
,
0
);
}
// Access
public
Vector3
getDirection
()
{
return
dir
;
}
@Override
public
CellData
newCellData
()
{
return
new
BoidCellData
();
}
// Commands
@Override
public
void
recompute
()
{
float
x
=
0
;
float
y
=
0
;
float
z
=
0
;
float
n
=
0
;
dir
.
fill
(
0
);
weight
=
cell
.
getPopulation
();
if
(
cell
.
isLeaf
())
{
Iterator
<?
extends
Particle
>
particles
=
cell
.
getParticles
();
while
(
particles
.
hasNext
())
{
Particle
p
=
particles
.
next
();
if
(
p
instanceof
BoidParticle
)
{
BoidParticle
particle
=
(
BoidParticle
)
p
;
x
+=
particle
.
getPosition
().
x
;
y
+=
particle
.
getPosition
().
y
;
z
+=
particle
.
getPosition
().
z
;
dir
.
add
(
particle
.
dir
);
n
++;
}
}
if
(
n
>
0
)
{
x
/=
n
;
y
/=
n
;
z
/=
n
;
}
center
.
set
(
x
,
y
,
z
);
// dir.normalize();
if
(
n
>
0
)
dir
.
scalarDiv
(
n
);
}
else
{
float
subcnt
=
cell
.
getSpace
().
getDivisions
();
float
totpop
=
cell
.
getPopulation
();
int
verif
=
0
;
if
(
totpop
>
0
)
{
for
(
int
i
=
0
;
i
<
subcnt
;
++
i
)
{
Cell
subcell
=
cell
.
getSub
(
i
);
BoidCellData
data
=
(
BoidCellData
)
subcell
.
getData
();
float
pop
=
subcell
.
getPopulation
();
verif
+=
pop
;
x
+=
data
.
center
.
x
*
pop
;
y
+=
data
.
center
.
y
*
pop
;
z
+=
data
.
center
.
z
*
pop
;
dir
.
add
(
data
.
dir
);
}
assert
verif
==
totpop
:
"Discrepancy in population counts ?"
;
x
/=
totpop
;
y
/=
totpop
;
z
/=
totpop
;
}
center
.
set
(
x
,
y
,
z
);
// dir.normalize();
if
(
totpop
>
0
)
dir
.
scalarDiv
(
totpop
);
}
for
(
NTreeListener
listener
:
cell
.
getTree
().
getListeners
())
{
listener
.
cellData
(
cell
.
getId
(),
"barycenter"
,
this
);
}
}
}
\ No newline at end of file
src/org/graphstream/boids/BoidSpecies.java
0 → 100644
View file @
536f6f16
package
org.graphstream.boids
;
import
java.awt.Color
;
import
java.util.HashMap
;
import
org.graphstream.boids.Context
;
/**
* Parameters for each boids species.
*
* @author Antoine Dutot
*/
public
class
BoidSpecies
extends
HashMap
<
String
,
Boid
>
{
/**
*
*/
private
static
final
long
serialVersionUID
=
6005548670964581065L
;
// Attributes
/**
* Shared settings.
*/
protected
Context
ctx
;
public
static
enum
Parameter
{
COUNT
,
VIEW_ZONE
,
SPEED_FACTOR
,
MAX_SPEED
,
MIN_SPEED
,
WIDTH
,
TRAIL
,
DIRECTION_FACTOR
,
ATTRACTION_FACTOR
,
REPULSION_FACTOR
,
INERTIA
,
FEAR_FACTOR
}
/**
* Initial number of boids of this species.
*/
public
int
count
=
200
;
/**
* The species name.
*/
public
String
name
=
randomName
();
/**
* The distance at which a boid is seen.
*/
public
double
viewZone
=
0.2f
;
/**
* 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
* (oscillation around the destination point, etc.)
*/
public
double
speedFactor
=
0.5f
;
/**
* Maximum speed bound.
*/
public
double
maxSpeed
=
1
f
;
/**
* Minimum speed bound.
*/
public
double
minSpeed
=
0.04f
;
/**
* 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
directionFactor
=
0.075f
;
/**
* 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
attractionFactor
=
0.1f
;
/**
* 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
repulsionFactor
=
0.002f
;
/**
* The inertia is the importance of the boid previous direction in the boid
* direction.
*/
public
double
inertia
=
1.2f
;
/**
* Factor for repulsion on boids of other species. The fear that this
* species produces on other species.
*/
public
double
fearFactor
=
1
;
/**
* The species main colour.
*/
public
Color
color
=
new
Color
(
1
,
0
,
0
);
/**
* The size of the trail in the GUI if any.
*/
public
int
trail
=
0
;
/**
* The width of the particle in the GUI if any.
*/
public
int
width
=
4
;
//protected DemographicManager demographicManager;
// Constructors
/**
* New default species with a random colour.
*/
public
BoidSpecies
(
Context
ctx
,
String
name
)
{
this
.
ctx
=
ctx
;
this
.
name
=
name
;
this
.
color
=
new
Color
(
ctx
.
random
.
nextFloat
(),
ctx
.
random
.
nextFloat
(),
ctx
.
random
.
nextFloat
());
}
// Access
// Commands
private
int
currentIndex
=
0
;
private
long
timestamp
=
System
.
nanoTime
();
public
void
set
(
String
p
,
String
val
)
throws
IllegalArgumentException
{
Parameter
param
=
Parameter
.
valueOf
(
p
.
toUpperCase
());
set
(
param
,
val
);
}
public
void
set
(
Parameter
p
,
String
val
)
{
switch
(
p
)
{
case
COUNT:
count
=
Integer
.
parseInt
(
val
);
break
;
case
VIEW_ZONE:
viewZone
=
Double
.
parseDouble
(
val
);
System
.
out
.
printf
(
"%s view zone : %f\n"
,
name
,
viewZone
);
break
;
case
SPEED_FACTOR:
speedFactor
=
Double
.
parseDouble
(
val
);
break
;
case
MAX_SPEED:
maxSpeed
=
Double
.
parseDouble
(
val
);
break
;
case
MIN_SPEED:
minSpeed
=
Double
.
parseDouble
(
val
);
break
;
case
WIDTH:
width
=
Integer
.
parseInt
(
val
);
break
;
case
TRAIL:
trail
=
Integer
.
parseInt
(
val
);
break
;
case
DIRECTION_FACTOR:
directionFactor
=
Double
.
parseDouble
(
val
);
break
;
case
ATTRACTION_FACTOR:
attractionFactor
=
Double
.
parseDouble
(
val
);
break
;
case
REPULSION_FACTOR:
repulsionFactor
=
Double
.
parseDouble
(
val
);
break
;
case
INERTIA:
inertia
=
Double
.
parseDouble
(
val
);
break
;
case
FEAR_FACTOR:
fearFactor
=
Double
.
parseDouble
(
val
);
break
;
}
}
public
String
createNewId
()
{
return
String
.
format
(
"%s_%x_%x"
,
name
,
timestamp
,
currentIndex
++);
}
public
void
register
(
Boid
b
)
{
put
(
b
.
getId
(),
b
);
}
public
void
unregister
(
Boid
b
)
{
remove
(
b
.
getId
());
}
public
void
terminateLoop
()
{
// Do nothing.
// Can be used by extending classes.
}
protected
static
String
randomName
()
{
return
String
.
format
(
"%c%c%c%c%c"
,
(
char
)
(
64
+
Math
.
random
()
*
26
),
(
char
)
(
64
+
Math
.
random
()
*
26
),
(
char
)
(
64
+
Math
.
random
()
*
26
),
(
char
)
(
64
+
Math
.
random
()
*
26
),
(
char
)
(
64
+
Math
.
random
()
*
26
));
}
public
int
getPopulation
()
{
return
size
();
}
public
int
getCount
()
{
return
count
;
}
public
void
setCount
(
int
count
)
{
this
.
count
=
count
;