The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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(