24.09., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

Commit 72b623d6 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck

add test for polygon shaped sources

parent a733de64
package org.vadere.simulator.control;
import org.vadere.simulator.control.util.GroupSpawnArray;
import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.simulator.models.groups.GroupModel;
import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import org.vadere.state.util.GroupSpawnArray;
import org.vadere.util.geometry.PointPositioned;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
......@@ -30,11 +30,12 @@ public class GroupSourceController extends SourceController {
this.groupModel = groupModel;
this.groupsToSpawn = new LinkedList<>();
VRectangle elementBound = new VRectangle(dynamicElementFactory.getDynamicElementRequiredPlace(new VPoint(0,0)).getBounds2D());
VRectangle elementBound = new VRectangle(dynamicElementFactory.getDynamicElementRequiredPlace(new VPoint(0, 0)).getBounds2D());
this.spawnArray = new GroupSpawnArray(source.getShape(),
new VRectangle(0, 0,elementBound.getWidth() , elementBound.getHeight()),
dynamicElementFactory::getDynamicElementRequiredPlace);
new VRectangle(0, 0, elementBound.getWidth(), elementBound.getHeight()),
dynamicElementFactory::getDynamicElementRequiredPlace,
this::testFreeSpace);
}
......
......@@ -6,7 +6,7 @@ import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Obstacle;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import org.vadere.state.util.SpawnArray;
import org.vadere.simulator.control.util.SingleSpawnArray;
import org.vadere.util.geometry.PointPositioned;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
......@@ -14,7 +14,6 @@ import org.vadere.util.geometry.shapes.VShape;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
......@@ -23,20 +22,21 @@ import java.util.stream.Collectors;
public class SingleSourceController extends SourceController {
private int numberToSpawn;
private DynamicElementFactory dynamicElementFactory;
private static final int NUMBER_OF_REPOSITION_TRIES = 10;
private static final int NUMBER_OF_POINT_SEARCH = 1_000; // todo based on shape and position of source
private SpawnArray spawnArray;
private SingleSpawnArray spawnArray;
public SingleSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random) {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
VRectangle elementBound = new VRectangle(dynamicElementFactory.getDynamicElementRequiredPlace(new VPoint(0,0)).getBounds2D());
this.spawnArray = new SpawnArray(source.getShape(),
new VRectangle(0, 0,elementBound.getWidth(), elementBound.getHeight()),
dynamicElementFactory::getDynamicElementRequiredPlace);
VRectangle elementBound = new VRectangle(dynamicElementFactory.getDynamicElementRequiredPlace(new VPoint(0, 0)).getBounds2D());
this.spawnArray = new SingleSpawnArray(source.getShape(),
new VRectangle(0, 0, elementBound.getWidth(), elementBound.getHeight()),
this.dynamicElementFactory::getDynamicElementRequiredPlace,
this::testFreeSpace);
}
@Override
......@@ -44,7 +44,7 @@ public class SingleSourceController extends SourceController {
if (!isSourceFinished(simTimeInSec)) {
if (simTimeInSec >= timeOfNextEvent || numberToSpawn > 0) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec);
List<VPoint> spawnPoints = new LinkedList<>();
List<VPoint> spawnPoints;
if (sourceAttributes.isSpawnAtRandomPositions()) {
......@@ -54,7 +54,7 @@ public class SingleSourceController extends SourceController {
random,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(position -> dynamicElementFactory.getDynamicElementRequiredPlace(position))
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
......@@ -71,7 +71,7 @@ public class SingleSourceController extends SourceController {
numberToSpawn,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(position -> dynamicElementFactory.getDynamicElementRequiredPlace(position))
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
numberToSpawn -= spawnPoints.size();
......@@ -97,11 +97,11 @@ public class SingleSourceController extends SourceController {
}
}
private List<VPoint> getRealPositions(final int numberToSpawn, @NotNull final List<VShape> blockPedestrianShapes){
private List<VPoint> getRealPositions(final int numberToSpawn, @NotNull final List<VShape> blockPedestrianShapes) {
List<VPoint> positions = new ArrayList<>(numberToSpawn);
for(int i = 0; i < numberToSpawn; i++) {
Optional<VPoint> optPosition = getNextPosition(blockPedestrianShapes, spawnArray.getAllowedSpawnPoints());
for (int i = 0; i < numberToSpawn; i++) {
Optional<VPoint> optPosition = spawnArray.getNextPosition(blockPedestrianShapes);
if (optPosition.isPresent()) {
VPoint position = optPosition.get();
......@@ -112,32 +112,21 @@ public class SingleSourceController extends SourceController {
return positions;
}
private Optional<VPoint> getNextPosition(List<VShape> blockPedestrianShapes, List<VPoint> spawnPoints) {
for (VPoint spawnPoint : spawnPoints){
VShape freeSpaceRequired = dynamicElementFactory.getDynamicElementRequiredPlace(spawnPoint);
if (testFreeSpace(freeSpaceRequired, blockPedestrianShapes)){
return Optional.of(spawnPoint);
}
}
return Optional.empty();
}
/**
* Computes numberToSpawn or less random positions based on the blockPedestrianShapes which contains the shapes representing the required space of each pedestrian.
* For each required position the algorithms tries {@link SingleSourceController#NUMBER_OF_REPOSITION_TRIES} times to get a feasible free position.
* Computes numberToSpawn or less random positions based on the blockPedestrianShapes which
* contains the shapes representing the required space of each pedestrian. For each required
* position the algorithms tries {@link SingleSourceController#NUMBER_OF_REPOSITION_TRIES} times
* to get a feasible free position.
*
* @param numberToSpawn number of required spawn positions
* @param random random generator
* @param blockPedestrianShapes the required space of other pedestrians
* @param blockPedestrianShapes the required space of other pedestrians
* @return numberToSpawn or less random feasible positions
*/
private List<VPoint> getRealRandomPositions(final int numberToSpawn, @NotNull final Random random, @NotNull final List<VShape> blockPedestrianShapes) {
List<VPoint> randomPositions = new ArrayList<>(numberToSpawn);
for(int i = 0; i < numberToSpawn; i++) {
for (int i = 0; i < numberToSpawn; i++) {
Optional<VPoint> optRandomPosition = getNextRandomPosition(random, blockPedestrianShapes, NUMBER_OF_POINT_SEARCH, NUMBER_OF_REPOSITION_TRIES);
if (optRandomPosition.isPresent()) {
......@@ -155,13 +144,13 @@ public class SingleSourceController extends SourceController {
final int tries_find_valid_point, final int tries_reposition) {
Rectangle2D rec = source.getShape().getBounds2D();
for(int i = 0; i < tries_reposition; i++) {
for (int i = 0; i < tries_reposition; i++) {
VShape freeSpaceRequired = null;
VPoint randomPoint = null;
boolean pointFound = false;
// find point in source boundary
int j = 0;
while(j < tries_find_valid_point && !pointFound){
while (j < tries_find_valid_point && !pointFound) {
randomPoint = new VPoint(rec.getMinX() + random.nextDouble() * rec.getWidth(), rec.getMinY() + random.nextDouble() * rec.getHeight());
freeSpaceRequired = dynamicElementFactory.getDynamicElementRequiredPlace(randomPoint);
pointFound = source.getShape().containsShape(freeSpaceRequired);
......@@ -169,7 +158,7 @@ public class SingleSourceController extends SourceController {
}
// no intersection with other free spaces (obstacles & other pedestrians)
if(testFreeSpace(freeSpaceRequired, blockPedestrianShapes)) {
if (testFreeSpace(freeSpaceRequired, blockPedestrianShapes)) {
return Optional.of(randomPoint);
}
}
......@@ -177,12 +166,6 @@ public class SingleSourceController extends SourceController {
return Optional.empty();
}
private boolean testFreeSpace(final VShape freeSpace, final List<VShape> blockPedestrianShapes){
return blockPedestrianShapes.stream().noneMatch(shape -> shape.intersects(freeSpace)) &&
this.getTopography().getObstacles().stream()
.map(Obstacle::getShape).noneMatch(shape -> shape.intersects(freeSpace));
}
@Override
protected boolean isQueueEmpty() {
return numberToSpawn == 0;
......
......@@ -8,11 +8,13 @@ import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.Car;
import org.vadere.state.scenario.DistributionFactory;
import org.vadere.state.scenario.DynamicElement;
import org.vadere.state.scenario.Obstacle;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.LinkedCellsGrid;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VShape;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
......@@ -30,7 +32,9 @@ public abstract class SourceController {
private final Topography topography;
protected final Random random;
/** <code>null</code>, if there is no next event. */
/**
* <code>null</code>, if there is no next event.
*/
protected Double timeOfNextEvent;
protected RealDistribution distribution;
protected final AttributesSource sourceAttributes;
......@@ -98,6 +102,14 @@ public abstract class SourceController {
&& dynamicElementsCreatedTotal >= maxNumber;
}
protected boolean testFreeSpace(final VShape freeSpace, final List<VShape> blockPedestrianShapes) {
boolean pedOverlap = blockPedestrianShapes.stream().noneMatch(shape -> shape.intersects(freeSpace));
boolean obstOverlap = this.getTopography().getObstacles().stream()
.map(Obstacle::getShape).noneMatch(shape -> shape.intersects(freeSpace));
return pedOverlap && obstOverlap;
}
abstract protected boolean isQueueEmpty();
abstract protected void determineNumberOfSpawnsAndNextEvent(double simTimeInSec);
......@@ -122,8 +134,8 @@ public abstract class SourceController {
}
/**
* note that most models create their own pedestrians and ignore the attributes given here.
* the source is mostly used to set the position and target ids, not the attributes.
* note that most models create their own pedestrians and ignore the attributes given here. the
* source is mostly used to set the position and target ids, not the attributes.
*/
protected void addNewAgentToScenario(final List<VPoint> position) {
position.forEach(p -> addNewAgentToScenario(p));
......
package org.vadere.state.util;
package org.vadere.simulator.control.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Simplifies placement of a group within a There are two placement strategies
* supported.
* Simplifies placement of a group within a There are two placement strategies supported.
* <li>NoneOverlapping:</li>
* With this strategy a group spawns do not overlap. E.g The first 2x2 Group will start at (0,0) and
* the second at (2,0) under the assumption the underlying source is big enough to hold two 2x2
......@@ -61,25 +59,24 @@ public class GroupPlacementHelper {
this.groupPlacementCountY = boundedShapeGridCellsY - (dimGy - 1);
validSpawnPointsForGroupInBound = new ArrayList<>();
for(int i = 0; i < getOverlappingGroupCount(); i++){ // i group spawn location
if (isGridCellWithinSource(validSpawnPointMapInBoundShape, i)){
for (int i = 0; i < getOverlappingGroupCount(); i++) { // i group spawn location
if (isGridCellWithinSource(validSpawnPointMapInBoundShape, i)) {
validSpawnPointsForGroupInBound.add(i);
}
}
}
/**
*
* @param validSpawnPointMapInBoundShape mapping of rectangular bound grid to valid coordinates
* within the source shape
* @param groupIndex groupIndex specifying the first ped within one group.
* @return true if all positions within the group are contained
* within the source shape.
* @param groupIndex groupIndex specifying the first ped within one group.
* @return true if all positions within the group are contained within the source
* shape.
*/
boolean isGridCellWithinSource(HashMap<Integer, Integer> validSpawnPointMapInBoundShape, int groupIndex){
for (int pedIndexInGroup = 0; pedIndexInGroup < groupSize; pedIndexInGroup++){
boolean isGridCellWithinSource(HashMap<Integer, Integer> validSpawnPointMapInBoundShape, int groupIndex) {
for (int pedIndexInGroup = 0; pedIndexInGroup < groupSize; pedIndexInGroup++) {
boolean isValid = validSpawnPointMapInBoundShape.containsKey(getOverlappingIndex(groupIndex, pedIndexInGroup));
if (!isValid){
if (!isValid) {
return false;
}
}
......@@ -87,10 +84,10 @@ public class GroupPlacementHelper {
}
/**
* @param groupNumber zero-Based number of group of groupSize with the overlapping strategy
* @return zero-Based index within {@link GroupSpawnArray} corresponding to groupNumber and index i
* @return zero-Based index within {@link GroupSpawnArray} corresponding to groupNumber and
* index i
*/
public int getOverlappingStart(int groupNumber) {
return (groupNumber % groupPlacementCountX) + // offset in x
......@@ -101,9 +98,9 @@ public class GroupPlacementHelper {
* Overlapping strategy
*
* @param groupNumberInBound zero-Based number of group
* @param i zero-Based index within group. Must be smaller than groupSize
* @return zero-Based index within {@link GroupSpawnArray} corresponding to groupNumber and index
* i
* @param i zero-Based index within group. Must be smaller than groupSize
* @return zero-Based index within {@link GroupSpawnArray} corresponding to groupNumber and
* index i
*/
public int getOverlappingIndex(int groupNumberInBound, int i) {
assert i < groupSize;
......@@ -115,7 +112,7 @@ public class GroupPlacementHelper {
return groupPlacementCountX * groupPlacementCountY;
}
public ArrayList<Integer> getValidSpawnPointsForGroupInBound(){
public ArrayList<Integer> getValidSpawnPointsForGroupInBound() {
return validSpawnPointsForGroupInBound;
}
......
package org.vadere.state.util;
package org.vadere.simulator.control.util;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.shapes.VPoint;
......@@ -18,21 +18,21 @@ import java.util.function.Function;
* <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).
* 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** |-----------------------------
* (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.
* 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
......@@ -45,7 +45,6 @@ import java.util.function.Function;
*
* <h2>{@link #getNextFreeGroup(int, Random, List)} (with Random Object)</h2>
* same as above but it will use a Randomize groupNumber Iterator.
*
*/
public class GroupSpawnArray extends SpawnArray {
......@@ -56,24 +55,29 @@ public class GroupSpawnArray extends SpawnArray {
private HashMap<Integer, GroupPlacementHelper> groupPlacementHelpers;
public GroupSpawnArray(final VShape boundShape, final VRectangle spawnElementBound, Function<VPoint, VShape> shapeProducer) {
super(boundShape, spawnElementBound, shapeProducer);
public GroupSpawnArray(final VShape boundShape,
final VRectangle spawnElementBound,
Function<VPoint, VShape> shapeProducer,
SpawnOverlapCheck testFreeSpace) {
super(boundShape, spawnElementBound, shapeProducer, testFreeSpace);
nextGroupPos = new HashMap<>();
groupPlacementHelpers = new HashMap<>();
}
private ArrayList<Integer> shufflePoints(ArrayList<Integer> list, Random rnd){
private ArrayList<Integer> shufflePoints(ArrayList<Integer> list, Random rnd) {
Collections.shuffle(list, rnd);
list.trimToSize();
return list;
}
// ring buffer. start with
private ArrayList<Integer> startWith (ArrayList<Integer> list, int start){
List<Integer> list1 = list.subList(start, list.size());
List<Integer> list2 = list.subList(0, start);
private ArrayList<Integer> startWith(ArrayList<Integer> list, int start) {
Integer startIndex = list.indexOf(start);
startIndex = startIndex == -1 ? 0 : startIndex;
List<Integer> list1 = list.subList(startIndex, list.size());
List<Integer> list2 = list.subList(0, startIndex);
ArrayList<Integer> ret = new ArrayList<>(list.size());
ret.addAll(list1);
ret.addAll(list2);
......@@ -98,26 +102,25 @@ public class GroupSpawnArray extends SpawnArray {
shufflePoints(pHelper.getValidSpawnPointsForGroupInBound(), rnd));
}
public LinkedList<VPoint> getNextFreeGroup(int groupSize, @NotNull final List<VShape> blockPedestrianShapes) {
public LinkedList<VPoint> getNextFreeGroup(int groupSize, @NotNull final List<VShape> blockPedestrianShapes) {
GroupPlacementHelper pHelper = getHelper(groupSize);
return nextFreeGroupPos(pHelper, blockPedestrianShapes, pHelper.getValidSpawnPointsForGroupInBound());
}
public LinkedList<VPoint> getNextFreeGroup(int groupSize, Random rnd, @NotNull final List<VShape> blockPedestrianShapes) {
public LinkedList<VPoint> getNextFreeGroup(int groupSize, Random rnd, @NotNull final List<VShape> blockPedestrianShapes) {
GroupPlacementHelper pHelper = getHelper(groupSize);
return nextFreeGroupPos(pHelper,
blockPedestrianShapes,
shufflePoints(pHelper.getValidSpawnPointsForGroupInBound(), rnd));
blockPedestrianShapes,
shufflePoints(pHelper.getValidSpawnPointsForGroupInBound(), rnd));
}
/**
*
* @param pHelper Helper object to address allowedSpawnPoints based on groupNumber and
* interGroupIndex see class comment for definition of groupNumber and
* interGroupIndex
* @param blockPedestrianShapes List of Shapes element to test for overlap
* @param groupNumbers ArrayList iteration order of groupNumbers
* @return List of allowedSpawnPoints used for the next group.
* @param pHelper Helper object to address allowedSpawnPoints based on groupNumber
* and interGroupIndex see class comment for definition of
* groupNumber and interGroupIndex
* @param blockPedestrianShapes List of Shapes element to test for overlap
* @param groupNumbers ArrayList iteration order of groupNumbers
* @return List of allowedSpawnPoints used for the next group.
*/
private LinkedList<VPoint> nextFreeGroupPos(
GroupPlacementHelper pHelper, @NotNull final List<VShape> blockPedestrianShapes,
......@@ -137,9 +140,8 @@ public class GroupSpawnArray extends SpawnArray {
int index = validSpawnPointMapInBoundShape.get(pHelper.getOverlappingIndex(next, i));
VPoint candidatePoint = allowedSpawnPoints.get(index).clone();
VShape candidateShape = shapeProducer.apply(candidatePoint);
boolean isOccupied = blockPedestrianShapes
.parallelStream().anyMatch(existingPed -> existingPed.intersects(candidateShape));
if (!isOccupied) {
boolean isFreeSpace = testFreeSpace.checkFreeSpace(candidateShape, blockPedestrianShapes);
if (isFreeSpace) {
points.add(candidatePoint);
} else {
points = new LinkedList<>();
......
package org.vadere.simulator.control.util;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
public class SingleSpawnArray extends SpawnArray {
public SingleSpawnArray(VShape boundShape,
VRectangle spawnElementBound,
Function<VPoint, VShape> shapeProducer,
SpawnOverlapCheck testFreeSpace) {
super(boundShape, spawnElementBound, shapeProducer, testFreeSpace);
}
public Optional<VPoint> getNextPosition(@NotNull final List<VShape> blockPedestrianShapes) {
for (VPoint spawnPoint : allowedSpawnPoints) {
VShape freeSpaceRequired = shapeProducer.apply(spawnPoint);
if (testFreeSpace.checkFreeSpace(freeSpaceRequired, blockPedestrianShapes)) {
return Optional.of(spawnPoint);
}
}
return Optional.empty();
}
}
package org.vadere.state.util;
package org.vadere.simulator.control.util;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
......@@ -19,20 +19,26 @@ public class SpawnArray {
// number of spawn elements in x and y Dimension.
protected int xDim;
protected int yDim;
protected final ArrayList<VPoint> allowedSpawnPoints;
protected VPoint firstSpawnPoint;
protected double eX, eY;
// map valid boundGrid coordinates to #allowedSpawnPoints ArrayList index.
protected HashMap<Integer,Integer> validSpawnPointMapInBoundShape;
protected HashMap<Integer, Integer> validSpawnPointMapInBoundShape;
protected final ArrayList<VPoint> allowedSpawnPoints;
protected Function<VPoint, VShape> shapeProducer;
protected SpawnOverlapCheck testFreeSpace;
public SpawnArray(final VShape boundShape, final VRectangle spawnElementBound,
Function<VPoint, VShape> shapeProducer) {
this.spawnElementBound = spawnElementBound;
protected int nextSpawnPoint;
public SpawnArray(final VShape boundShape,
final VRectangle spawnElementBound,
Function<VPoint, VShape> shapeProducer,
SpawnOverlapCheck testFreeSpace) {
this.bound = new VRectangle(boundShape.getBounds2D());
this.spawnElementBound = spawnElementBound;
this.shapeProducer = shapeProducer;
this.testFreeSpace = testFreeSpace;
xDim = (int) (bound.width / spawnElementBound.width);
yDim = (int) (bound.height / spawnElementBound.height);
......@@ -70,9 +76,10 @@ public class SpawnArray {
}
}
allowedSpawnPoints.trimToSize();
nextSpawnPoint = 0;
}
public List<VPoint> getAllowedSpawnPoints(){
public List<VPoint> getAllowedSpawnPoints() {
return allowedSpawnPoints;
}
}
package org.vadere.simulator.control.util;
import org.vadere.util.geometry.shapes.VShape;
import java.util.List;
@FunctionalInterface
public interface SpawnOverlapCheck {
/**
* Check if the candidateShape can be placed without overlaping any blockPedestrianShapes. Note:
* The implementation can also test other Shapes such as obstacles if this is needed.
*
* @param candidateShape VShape to be placed in new source
* @param blockPedestrianShapes List of VShapes the candidateShape must not overlap with
* @return true if candidateShape does not overlap blockPedestrianShapes false if an
* overlap occurs.
*/
boolean checkFreeSpace(VShape candidateShape, List<VShape> blockPedestrianShapes);
}
......@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class GroupSourceControllerTest extends TestSourceControllerUsingConstantSpawnRate {
......@@ -60,7 +59,8 @@ public class GroupSourceControllerTest extends TestSourceControllerUsingConstant
public void testUpdateEqualStartAndEndTime() {
SourceTestAttributesBuilder builder = new SourceTestAttributesBuilder()
.setOneTimeSpawn(0)
.setSourceDim(5.0, 5.0)
.setUseFreeSpaceOnly(true)
.setSourceDim(15.0, 15.0)
.setGroupSizeDistribution(0.0, 0.5, 0.5)
.setGroupSizeDistributionMock(2, 2, 3, 3);
......@@ -144,7 +144,7 @@ public class GroupSourceControllerTest extends TestSourceControllerUsingConstant
@Test
public void testUpdateUseFreeSpaceOnly() {
double d = new AttributesAgent().getRadius() * 2 + SourceController.SPAWN_BUFFER_SIZE;
double d = new AttributesAgent().getRadius() * 2;
SourceTestAttributesBuilder builder = new SourceTestAttributesBuilder()
.setOneTimeSpawn(0)
.setSpawnNumber(100)
......@@ -252,7 +252,7 @@ public class GroupSourceControllerTest extends TestSourceControllerUsingConstant
@Test
public void testUseFreeSpaceOnly() {
// expected: not stop spawning before all pedestrians are created (even after end time)
double d = new AttributesAgent().getRadius() * 2 + SourceController.SPAWN_BUFFER_SIZE;
double d = new AttributesAgent().getRadius() * 2;
double startTime = 0;
double endTime = 1;
int spawnNumber = 100;
......@@ -346,7 +346,6 @@ public class GroupSourceControllerTest extends TestSourceControllerUsingConstant
}
@Test
public void testMaxSpawnNumberTotalWithLargeEndTimeAndSpawnNumberGreater1() {
int maxSpawnNumberTotal = 4; // <-- exhausted!
......
package org.vadere.simulator.control;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Random;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
......@@ -22,9 +17,13 @@ import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import java.util.ArrayList;
import java.util.Random;
import static org.junit.Assert.assertEquals;
public class TestSourceControllerUsingConstantSpawnRate {
protected long randomSeed = 0;
ArrayList<SourceTestData> sourceTestData;
......@@ -45,6 +44,7 @@ public class TestSourceControllerUsingConstantSpawnRate {
return new SingleSourceControllerFactory();
}
public void initialize(SourceTestAttributesBuilder builder) {
SourceTestData d = new SourceTestData();
......@@ -52,7 +52,7 @@ public class TestSourceControllerUsingConstantSpawnRate {
d.attributesSource = builder.getResult();
d.attributesPedestrian = new AttributesAgent();
d.random = new Random(randomSeed);
d.random = new Random(builder.getRandomSeed());
d.source = new Source(d.attributesSource);
d.pedestrianFactory = new DynamicElementFactory() {
......@@ -168,7 +168,7 @@ public class TestSourceControllerUsingConstantSpawnRate {
.setOneTimeSpawn(0)
.setSpawnNumber(100)
.setUseFreeSpaceOnly(true)