Commit ac78f73f authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

fix bug in pedestrian spawn algorithm when peds are spawend exactly the same spot.

parent 7fd11634
Pipeline #62603 failed with stages
in 2 minutes and 54 seconds
......@@ -31,7 +31,6 @@ public class GroupSourceController extends SourceController {
if (!isSourceFinished(simTimeInSec)) {
if (simTimeInSec >= timeOfNextEvent || !groupsToSpawn.isEmpty()) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec);
LinkedList<List<VPoint>> spawnGroups = new LinkedList<>();
if (sourceAttributes.isSpawnAtRandomPositions()) {
......@@ -40,7 +39,7 @@ public class GroupSourceController extends SourceController {
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextFreeGroup(groupSize, random, getDynElementsAtSource());
if (newGroup != null) {
if (newGroup.size() > 0) {
// add immediately to Scenario to update DynElementsAtSource
addElementToScenario(newGroup);
iter.remove();
......@@ -53,7 +52,7 @@ public class GroupSourceController extends SourceController {
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextGroup(groupSize, random, getDynElementsAtSource());
if (newGroup == null)
if (newGroup.size() == 0)
throw new RuntimeException("Cannot spawn new Group. Source " + source.getId() + " is set " +
"to useFreeSpaceOnly == false but no space is left to spawn group without exactly" +
"overlapping with neighbours which can cause numerical problems. Use useFreeSpaceOnly == true (default)" +
......
......@@ -34,17 +34,7 @@ public class SingleSourceController extends SourceController {
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
} else {
for (int i = 0; i < numberToSpawn; i++) {
VPoint nextRandomSpawnPoint = spawnArray.getNextRandomSpawnPoint(getDynElementsAtSource(), random);
if (nextRandomSpawnPoint == null){
throw new RuntimeException("Cannot spawn new Pedestrian. Source " + source.getId() + " is set " +
"to useFreeSpaceOnly == false but no space is left to spawn group without exactly" +
"overlapping with neighbours which can cause numerical problems. Use useFreeSpaceOnly == true (default)" +
"to queue Pedestrians.");
}
spawnPoints.add(nextRandomSpawnPoint);
}
spawnPoints = spawnArray.getNextRandomSpawnPoints(numberToSpawn, random, getDynElementsAtSource());
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
}
......@@ -56,16 +46,7 @@ public class SingleSourceController extends SourceController {
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
} else {
for (int i = 0; i < numberToSpawn; i++) {
VPoint nextSpawnPoint = spawnArray.getNextSpawnPoint(getDynElementsAtSource());
if (nextSpawnPoint == null){
throw new RuntimeException("Cannot spawn new Pedestrian. Source " + source.getId() + " is set " +
"to useFreeSpaceOnly == false but no space is left to spawn group without exactly" +
"overlapping with neighbours which can cause numerical problems. Use useFreeSpaceOnly == true (default)" +
"to queue Pedestrians.");
}
spawnPoints.add(nextSpawnPoint);
}
spawnPoints = spawnArray.getNextSpawnPoints(numberToSpawn, getDynElementsAtSource());
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
}
......
package org.vadere.simulator.control;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.vadere.simulator.control.factory.GroupSourceControllerFactory;
......@@ -377,7 +376,6 @@ public class GroupSourceControllerTest extends TestSourceControllerUsingConstant
}
@Test
@Ignore
public void multipleSources() {
SourceTestAttributesBuilder builder1 = new SourceTestAttributesBuilder()
.setDistributionClass(TestSourceControllerUsingDistributions.ConstantTestDistribution.class)
......
......@@ -116,5 +116,7 @@ public class GroupPlacementHelper {
return overlapXGroupCount * overlapYGroupCount;
}
public int getGroupSize() {
return groupSize;
}
}
......@@ -12,23 +12,81 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* Defines spawn points for a source and returns valid coordinates for spawning.
* <h1>Single Pedestrians</h1>
*
* The single spawn algorithm divides the source in a grid based on the width of the pedestrians.
* This grid is used to place newly spawn pedestrians. These points are called spawnPoints and
* are saved as an 1D-array. Based on the Source Attribute values one of the four functions will
* be used to select the next spawnPoints.
*
* <h2>{@link #getNextSpawnPoints(int, List)}</h2>
* use the next free spawn point in order (0..n) to place the next pedestrian. This function will
* try to place up to maxPoints pedestrian an will wrap around to spawnPoint 0 if needed. Also this
* function will allow overlapping pedestrians a complete overlap is not allowed due to numerical
* problems in OE-solvers.
*
* <h2>{@link #getNextRandomSpawnPoints(int, Random, List)}</h2>
* same as above but the spawn points will be shuffled prior to iteration.
*
* <h2>{@link #getNextFreeSpawnPoints(int, List)}</h2>
* same as above but it will be ensured that the new pedestrian does not overlap with any part of
* an existing pedestrian.
*
* <h2>{@link #getNextFreeRandomSpawnPoints(int, Random, List)}</h2>
* sam es above but the spawn points will be shuffled prior to iteration and overlapping will be
* tested.
*
*
* <h1>Groups</h1>
*
* Groups are spawn as a rectangle (axb) with the smallest possible deviation of a and b. The
* groupNumber is zero-based index counting possible spawn point for a group (see below). The
* spawn positions (groupNumbers) will overlap. Depending on the selected Attributes the algorithm
* will test in advance if the groupNumber is free (not occupied).
*
* (0) (1) (2) (3) (4) (5) (6) (7) (8) <-- groupNumber--------------
* | **00 | 0**0 | 00** | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |-----------------------------
* | **00 | 0**0 | 00** | **00 | 0**0 | 00** | 0000 | 0000 | 0000 |-----------------------------
* | 0000 | 0000 | 0000 | **00 | 0**0 | 00** | **00 | 0**0 | 00** |-----------------------------
* | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | **00 | 0**0 | 00** |-----------------------------
*
* <h2>{@link #getNextGroup(int, List)} (without Random Object)</h2>
* Iterate through the groupNumbers in order (0-->8) but remember the last used groupNumber for
* each groupSize in the HashMap nextGroupPos. The Iteration order is generated with lambada
* expressions. Also getNextGroup allows overlapping spawning a complete overlap is not allowed due
* to numerical problems in OE-Solvers which would loop forever.
*
* <h2>{@link #getNextGroup(int, Random, List)} (with Random Object)</h2>
* Same as before with the distinction that the groupNumbers as iterated in a random order. This
* function will update the the HashMap nextGroupPos but this is not a problem because in this case
* the nextGroupPos is not used.
*
* <h2>{@link #getNextFreeGroup(int, List)} (without Random Object)</h2>
* This function will always iterate in order order (0-->8) and will use the first free groupNumber
* available. This function ignores the nextGroupPos HashMap.
*
* <h2>{@link #getNextFreeGroup(int, Random, List)} (with Random Object)</h2>
* same as above but it will use a Randomize groupNumber Iterator.
*
*/
public class SpawnArray {
private static Logger logger = LogManager.getLogger(SpawnArray.class);
private static final double EPSILON = 0.001;
private static final double EPSILON = 0.01;
private final VPoint[] spawnPoints;
private final VRectangle spawnElementBound;
// number of spawn elements in x and y Dimension.
private int xDim;
private int yDim;
private int nextPoint;
private int nextIndex;
// not an index put a way to calculate the index 1..n where n is the number of possible ways to place a given group
// key: groupSize
// value: number of next group.
......@@ -66,7 +124,7 @@ public class SpawnArray {
for (int i = 0; i < spawnPoints.length; i++) {
spawnPoints[i] = firstSpawnPoint.add(new VPoint(2 * eX * (i % xDim), 2 * eY * (i / xDim)));
}
nextPoint = 0;
nextIndex = 0;
nextGroupPos = new HashMap<>();
groupPlacementHelpers = new HashMap<>();
......@@ -84,7 +142,7 @@ public class SpawnArray {
* @return next SpawnPointIndex used to spawn underling spawnElementBound
*/
public int getNextSpawnPointIndex() {
return nextPoint;
return nextIndex;
}
/**
......@@ -98,56 +156,22 @@ public class SpawnArray {
// Check here for a complete overlap (With epsilon) and use different cell in this case
// caller must handle return null.
@Deprecated
public VPoint getNextSpawnPoint(final List<DynamicElement> neighbours) {
VPoint ret = null;
for (VPoint spawnPoint : spawnPoints) {
VPoint tmp = spawnPoints[nextPoint].clone();
nextPoint = (nextPoint + 1) % spawnPoints.length;
boolean isSpotOccupied = neighbours.stream().anyMatch(n -> n.getShape().getCentroid().equals(tmp, EPSILON));
if (!isSpotOccupied) {
ret = tmp;
break;
}
}
return ret;
public LinkedList<VPoint> getNextSpawnPoints(int maxPoints, final List<DynamicElement> neighbours) {
return spawnPoints(maxPoints,
neighbours,
(n, p) -> n.getShape().getCentroid().equals(p, EPSILON) ,
len -> startWith(nextIndex, len)); // define spawn order (use next index)
}
// spawn without checking for free space does not make sense.
// Check here for a complete overlap (With epsilon) and use different cell in this case
// caller must handle return null.
@Deprecated
public VPoint getNextRandomSpawnPoint(final List<DynamicElement> neighbours, Random rnd) {
List<Integer> indexList = IntStream.range(0, spawnPoints.length)
.boxed().collect(Collectors.toList());
Collections.shuffle(indexList, rnd);
VPoint ret = null;
for (Integer i : indexList) {
VPoint tmp = spawnPoints[i].clone();
boolean isSpotOccupied = neighbours.stream().anyMatch(n -> n.getShape().getCentroid().equals(tmp, EPSILON));
if (!isSpotOccupied){
ret = tmp;
break;
}
}
return ret;
}
/**
* @param neighbours Test against this List. Caller must ensure that this neighbours are in the
* vicinity of the source bound.
* @return first free space within the spawn points.
*/
public VPoint getNextFreeSpawnPoint(final List<DynamicElement> neighbours) {
double d = getMaxElementDim() / 2; // radius.
for (VPoint p : spawnPoints) {
boolean overlap = neighbours.parallelStream().anyMatch(n -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)));
if (!overlap) {
return p.clone();
}
}
return null;
public LinkedList<VPoint> getNextRandomSpawnPoints(int maxPoints, Random rnd, final List<DynamicElement> neighbours) {
return spawnPoints(maxPoints,
neighbours,
(n, p) -> n.getShape().getCentroid().equals(p, EPSILON) ,
len -> shufflePoints(rnd, len)); // define spawn order (use random index)
}
/**
......@@ -158,30 +182,49 @@ public class SpawnArray {
*/
public LinkedList<VPoint> getNextFreeSpawnPoints(int maxPoints, final List<DynamicElement> neighbours) {
double d = getMaxElementDim() / 2; // radius.
LinkedList<VPoint> points = new LinkedList<>();
for (VPoint p : spawnPoints) {
boolean overlap = neighbours.parallelStream().anyMatch(n -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)));
if (!overlap) {
points.add(p);
if (points.size() == maxPoints) {
break;
}
}
}
return points;
return spawnPoints(maxPoints,
neighbours,
(n, p ) -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)),
len -> startWith(nextIndex, len)); // define spawn order (use next index)
}
public LinkedList<VPoint> getNextFreeRandomSpawnPoints(int maxPoints, Random rnd, final List<DynamicElement> neighbours) {
double d = getMaxElementDim() / 2; // radius.
return spawnPoints(maxPoints,
neighbours,
(n, p ) -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)),
(len) -> shufflePoints(rnd, len)); // define spawn order (use random index)
}
/**
*
* @param maxPoints Maximum number of Pedestrain to spawn
* @param neighbours Pedestrian already spawned
* @param testOverlap function defining if at the current position a neighbour already occupies the spot
* @param spawnPointOrder function defining the order in which the spawn points are iterated.
* @return new spawn points
*/
private LinkedList<VPoint> spawnPoints(int maxPoints, final List<DynamicElement> neighbours,
BiFunction<DynamicElement, VPoint, Boolean> testOverlap,
Function<Integer, ArrayList<Integer>> spawnPointOrder){
LinkedList<VPoint> points = new LinkedList<>();
List<Integer> randInt = IntStream.range(0, spawnPoints.length).boxed().collect(Collectors.toList());
Collections.shuffle(randInt, rnd);
for (Integer i : randInt) {
VPoint p = spawnPoints[i];
boolean overlap = neighbours.parallelStream().anyMatch(n -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)));
if (!overlap) {
points.add(p);
// generate iterator order based on spawnPointOrder function.
ArrayList<Integer> pointOrder = spawnPointOrder.apply(spawnPoints.length);
ListIterator<Integer> iter = pointOrder.listIterator();
while (iter.hasNext()){
Integer next = iter.next();
VPoint tmp = spawnPoints[next];
boolean isOccupied = neighbours.parallelStream().anyMatch(n -> testOverlap.apply(n, tmp));
if (!isOccupied){
points.add(tmp.clone());
if (points.size() == maxPoints) {
// remember next spawn position. If this is the last on, wrap around and use
// the first element of pointOrder ArrayList.
nextIndex = iter.hasNext() ? iter.next() : pointOrder.get(0);
break;
}
}
......@@ -189,86 +232,98 @@ public class SpawnArray {
return points;
}
private ArrayList<Integer> shufflePoints(Random rnd, int len){
ArrayList<Integer> ret = IntStream.range(0, len)
.boxed().collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(ret, rnd);
ret.trimToSize();
return ret;
}
private ArrayList<Integer> defaultOrder (int len){
ArrayList<Integer> ret = IntStream.range(0, len).boxed().collect(Collectors.toCollection(ArrayList::new));
ret.trimToSize();
return ret;
}
// ring buffer. start with
private ArrayList<Integer> startWith (int start, int len){
ArrayList<Integer> ret = IntStream.concat(IntStream.range(start, len), IntStream.range(0, start)).boxed()
.collect(Collectors.toCollection(ArrayList::new));
ret.trimToSize();
return ret;
}
// Groups
@Deprecated
public LinkedList<VPoint> getNextGroup(int groupSize, final List<DynamicElement> neighbours) {
return nextFreeGroupPos(groupSize, null, neighbours, true);
GroupPlacementHelper pHelper = getHelper(groupSize);
return nextFreeGroupPos(pHelper,
neighbours,
(n,p) -> n.getShape().getCentroid().equals(p, EPSILON),
len -> startWith(nextGroupPos.getOrDefault(pHelper.getGroupSize(), 0), len));
}
public LinkedList<VPoint> getNextGroup(int groupSize, Random rnd, final List<DynamicElement> neighbours) {
return nextFreeGroupPos(groupSize, rnd, neighbours, true);
GroupPlacementHelper pHelper = getHelper(groupSize);
return nextFreeGroupPos(pHelper,
neighbours,
(n,p) -> n.getShape().getCentroid().equals(p, EPSILON),
len -> shufflePoints(rnd, len));
}
/**
* This function only can spawn overlapping groups but the possible location is tested if it is
* free. A source of the size 4x4 hast 9 possible spawn locations for a group of the size 4.
* Each location is test if all spots within the group are free. If so this location is return.
*
* | **00 | 0**0 | 00** | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |-----------------------------
* | **00 | 0**0 | 00** | **00 | 0**0 | 00** | 0000 | 0000 | 0000 |-----------------------------
* | 0000 | 0000 | 0000 | **00 | 0**0 | 00** | **00 | 0**0 | 00** |-----------------------------
* | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | **00 | 0**0 | 00** |-----------------------------
*
* @param groupSize size of group which should be spawned
* @return Point List or null if no free location is found for given group size.
*/
public LinkedList<VPoint> getNextFreeGroup(int groupSize, final List<DynamicElement> neighbours) {
return nextFreeGroupPos(groupSize, null, neighbours, false);
GroupPlacementHelper pHelper = getHelper(groupSize);
double d = getMaxElementDim() / 2; // radius.
return nextFreeGroupPos(pHelper,
neighbours,
(n, p) -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)),
this::defaultOrder);
}
public LinkedList<VPoint> getNextFreeGroup(int groupSize, Random rnd, final List<DynamicElement> neighbours) {
return nextFreeGroupPos(groupSize, rnd, neighbours, false);
GroupPlacementHelper pHelper = getHelper(groupSize);
double d = getMaxElementDim() / 2; // radius.
return nextFreeGroupPos(pHelper,
neighbours,
(n, p) -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)),
len -> shufflePoints(rnd, len));
}
private LinkedList<VPoint> nextFreeGroupPos(int groupSize, Random rnd, final List<DynamicElement> neighbours, boolean allowOverlap) {
/**
*
* @param pHelper Helper object to address spawnPoints based on groupNumber and
* interGroupIndex see class comment for definition of groupNumber and
* interGroupIndex
* @param neighbours List of dynamic element to test for overlap
* @param testOverlap Function to test if a neighbour occupies the current groupNumber
* @param spawnPointOrder ArrayList generator to define iteration order of groupNumbers
* @return List of spawnPoints used for the next group.
*/
private LinkedList<VPoint> nextFreeGroupPos(
GroupPlacementHelper pHelper, final List<DynamicElement> neighbours,
BiFunction<DynamicElement, VPoint, Boolean> testOverlap,
Function<Integer, ArrayList<Integer>> spawnPointOrder) {
int groupSize = pHelper.getGroupSize();
if (groupSize > spawnPoints.length)
throw new IndexOutOfBoundsException("GroupSize: " + groupSize
+ "to big for source. Max Groupsize of source is " + spawnPoints.length);
GroupPlacementHelper pHelper;
if (groupPlacementHelpers.containsKey(groupSize)) {
pHelper = groupPlacementHelpers.get(groupSize);
} else {
pHelper = new GroupPlacementHelper(xDim, yDim, groupSize);
groupPlacementHelpers.put(groupSize, pHelper);
}
double d = getMaxElementDim() / 2; // radius.
LinkedList<VPoint> points = new LinkedList<>();
//over all overlapping groups in source
boolean isOccupied = true;
ArrayList<Integer> groupNumbers;
if (rnd != null) {
groupNumbers = IntStream.range(0, pHelper.getOverlappingGroupCount())
.boxed().collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(groupNumbers, rnd);
} else {
groupNumbers = IntStream.range(0, pHelper.getOverlappingGroupCount())
.boxed().collect(Collectors.toCollection(ArrayList::new));
}
groupNumbers.trimToSize();
// generate iterator order based on spawnPointOrder function.
ArrayList<Integer> groupNumbers = spawnPointOrder.apply(pHelper.getOverlappingGroupCount());
// run through all possible group placements. If allowOverlap is set we must start from
// the next group pos saved in the the nextGroupPos map. The if variable g is not used
// and only is used to run through all placements options. The currently used index
// is currentGroupPos.
int currentGroupPos = allowOverlap ? nextGroupPos.getOrDefault(groupSize, 0) : 0;
for (int g=0 ; g < groupNumbers.size(); g++) {
// test if at currentGroupPos all places within the group are free or
// (in the case of allowOverlap) only the centroid of the new group members does not
// overlap with existing neighbours
ListIterator<Integer> iter = groupNumbers.listIterator();
while (iter.hasNext()) {
Integer next = iter.next();
for (int i = 0; i < groupSize; i++) {
int index = pHelper.getOverlappingIndex(currentGroupPos, i);
int index = pHelper.getOverlappingIndex(next, i);
VPoint p = spawnPoints[index].clone();
if (allowOverlap){
isOccupied = neighbours.parallelStream().anyMatch(n -> n.getShape().getCentroid().equals(p, EPSILON));
} else {
isOccupied = neighbours.parallelStream().anyMatch(n -> ((n.getShape().distance(p) < d) || n.getShape().contains(p)));
}
boolean isOccupied = neighbours.parallelStream().anyMatch(n -> testOverlap.apply(n, p));
if (!isOccupied) {
points.add(p);
} else {
......@@ -276,22 +331,27 @@ public class SpawnArray {
break;
}
}
currentGroupPos = (currentGroupPos + 1) % pHelper.getOverlappingGroupCount();
// if a group was found with no overlapping point break and return group.
if (!isOccupied) {
if (points.size() == groupSize) {
// remember next position for groupSize for next spawn event. this is the last position
// wrap around and use first element of groupNumbers ArrayList
nextGroupPos.put(groupSize, iter.hasNext() ? iter.next() : groupNumbers.get(0));
break;
}
}
nextGroupPos.put(groupSize, currentGroupPos);
return points;
}
if (points.size() < groupSize) {
return null;
private GroupPlacementHelper getHelper(int groupSize) {
GroupPlacementHelper pHelper;
if (groupPlacementHelpers.containsKey(groupSize)) {
pHelper = groupPlacementHelpers.get(groupSize);
} else {
return points;
pHelper = new GroupPlacementHelper(xDim, yDim, groupSize);
groupPlacementHelpers.put(groupSize, pHelper);
}
return pHelper;
}
}
......@@ -105,22 +105,22 @@ public class SpawnArrayTest {
// first Point
List<DynamicElement> dynamicElements = createMock(0.5);
VPoint p = spawnArray.getNextSpawnPoint(dynamicElements);
VPoint p = spawnArray.getNextSpawnPoints(1, dynamicElements).getFirst();
assertEquals("Point does not match", p, new VPoint(1.5, 1.5));
assertEquals("Next Element does not match", 1, spawnArray.getNextSpawnPointIndex());
// 10 more points
IntStream.range(0, 10).forEach(i -> spawnArray.getNextSpawnPoint(dynamicElements));
IntStream.range(0, 10).forEach(i -> spawnArray.getNextSpawnPoints(1, dynamicElements));
assertEquals("Next Element does not match", 11, spawnArray.getNextSpawnPointIndex());
VPoint first = new VPoint(source.x + elementBound.width / 2, source.y + elementBound.height / 2);
assertEquals("Point does not match", spawnArray.getNextSpawnPoint(dynamicElements),
assertEquals("Point does not match", spawnArray.getNextSpawnPoints(1, dynamicElements).getFirst(),
new VPoint(first.x + 2 * 2 * elementBound.width / 2, first.y + 1 * 2 * elementBound.height / 2));
// now at point 12 because getNextSpawnPoint() increments NextPointIndex
// now at point 12 because getNextSpawnPoints() increments NextPointIndex
// spawn 81 more to wrapp around to point 12.
IntStream.range(0, 81).forEach(i -> spawnArray.getNextSpawnPoint(dynamicElements));
IntStream.range(0, 81).forEach(i -> spawnArray.getNextSpawnPoints(1, dynamicElements));
assertEquals("Next Element does not match", 12, spawnArray.getNextSpawnPointIndex());
assertEquals("Point does not match", spawnArray.getNextSpawnPoint(dynamicElements),
assertEquals("Point does not match", spawnArray.getNextSpawnPoints(1, dynamicElements).getFirst(),
new VPoint(first.x + 3 * 2 * elementBound.width / 2, first.y + 1 * 2 * elementBound.height / 2));
VPoint[] spawnPoints = spawnArray.getSpawnPoints();
......@@ -129,7 +129,7 @@ public class SpawnArrayTest {
spawnPoints[13].add(new VPoint(0, 0.0003)), // match within Epsilon (use next)
spawnPoints[14].add(new VPoint(0.3, 0)) // match outside Epsilon (use this one)
);
assertEquals("Point does not match", spawnArray.getNextSpawnPoint(dynamicElements2), spawnPoints[14]);
assertEquals("Point does not match", spawnArray.getNextSpawnPoints(1, dynamicElements2).getFirst(), spawnPoints[14]);
assertEquals("Next Element does not match", 15, spawnArray.getNextSpawnPointIndex());
}
......@@ -147,7 +147,7 @@ public class SpawnArrayTest {
spawnPoints[2],
spawnPoints[3].add(new VPoint(0, 0.0003))
);
assertEquals("there should be no free spot", null, spawnArray.getNextSpawnPoint(dynamicElements));
assertEquals("there should be no free spot", 0, spawnArray.getNextSpawnPoints(1, dynamicElements).size());
}
......@@ -158,14 +158,14 @@ public class SpawnArrayTest {
spawnArray = new SpawnArray(source, elementBound);
assertEquals("Number of spawn points does not match", 4, spawnArray.getSpawnPoints().length);
assertNull("There should not be a free spot.", spawnArray.getNextFreeSpawnPoint(
createMock(0.5, spawnArray.getSpawnPoints())));
assertEquals("There should not be a free spot.", 0, spawnArray.getNextFreeSpawnPoints(1,
createMock(0.5, spawnArray.getSpawnPoints())).size() );
VPoint[] spawnPoints = spawnArray.getSpawnPoints();
assertNotEquals("Point 1 is occupied and should not be returned", spawnPoints[1], spawnArray.getNextFreeSpawnPoint(
createMock(0.5, spawnPoints[1])
assertNotEquals("Point 1 is occupied and should not be returned", spawnPoints[1],
spawnArray.getNextFreeSpawnPoints(1, createMock(0.5, spawnPoints[1])
));
assertNotNull("There should be three valid points", spawnArray.getNextFreeSpawnPoint(
createMock(0.5, spawnPoints[1])