Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

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

Commit 4d276157 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

Merge branch 'master' of https://gitlab.lrz.de/vadere/vadere

parents d8184ebc 1e56749e
Pipeline #72885 failed with stages
in 58 seconds
...@@ -51,6 +51,8 @@ public class AgentRender implements Renderer { ...@@ -51,6 +51,8 @@ public class AgentRender implements Renderer {
} }
private void renderGroup(Pedestrian ped, Graphics2D g) { private void renderGroup(Pedestrian ped, Graphics2D g) {
g.setColor(Color.DARK_GRAY);
g.fill(ped.getShape());
g.setColor(getGroupColor(ped)); g.setColor(getGroupColor(ped));
DefaultRenderer.fill(getShape(ped), g); DefaultRenderer.fill(getShape(ped), g);
} }
......
...@@ -260,6 +260,8 @@ public class TopographyWindow extends JPanel { ...@@ -260,6 +260,8 @@ public class TopographyWindow extends JPanel {
obstacleAndTargetDrawModes.add(pen2); obstacleAndTargetDrawModes.add(pen2);
sourceDrawModes.add(rectangle); sourceDrawModes.add(rectangle);
sourceDrawModes.add(pen);
sourceDrawModes.add(pen2);
sourceDrawModes.add(dot); sourceDrawModes.add(dot);
/* open obstacle paint method dialog action */ /* open obstacle paint method dialog action */
......
...@@ -226,7 +226,8 @@ ...@@ -226,7 +226,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ], } ],
"attributesPedestrian" : { "attributesPedestrian" : {
"radius" : 0.195, "radius" : 0.195,
......
...@@ -353,7 +353,8 @@ ...@@ -353,7 +353,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, { }, {
"source" : null, "source" : null,
"targetIds" : [ 1 ], "targetIds" : [ 1 ],
...@@ -382,7 +383,8 @@ ...@@ -382,7 +383,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ], } ],
"attributesPedestrian" : { "attributesPedestrian" : {
"radius" : 0.195, "radius" : 0.195,
......
...@@ -297,7 +297,8 @@ ...@@ -297,7 +297,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, { }, {
"source" : null, "source" : null,
"targetIds" : [ 1 ], "targetIds" : [ 1 ],
...@@ -326,7 +327,8 @@ ...@@ -326,7 +327,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ], } ],
"attributesPedestrian" : { "attributesPedestrian" : {
"radius" : 0.195, "radius" : 0.195,
......
...@@ -585,7 +585,8 @@ ...@@ -585,7 +585,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, { }, {
"source" : null, "source" : null,
"targetIds" : [ 1 ], "targetIds" : [ 1 ],
...@@ -614,7 +615,8 @@ ...@@ -614,7 +615,8 @@
"isChild" : false, "isChild" : false,
"isLikelyInjured" : false, "isLikelyInjured" : false,
"groupIds" : [ ], "groupIds" : [ ],
"type" : "PEDESTRIAN" "type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ], } ],
"attributesPedestrian" : { "attributesPedestrian" : {
"radius" : 0.195, "radius" : 0.195,
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
}, },
"attributesSimulation" : { "attributesSimulation" : {
"finishTime" : 70.0, "finishTime" : 70.0,
"simTimeStepLength" : 1.4, "simTimeStepLength" : 0.4,
"realTimeSimTimeRatio" : 0.1, "realTimeSimTimeRatio" : 0.1,
"writeSimulationData" : false, "writeSimulationData" : false,
"visualizationEnabled" : true, "visualizationEnabled" : true,
......
...@@ -14,6 +14,8 @@ ScenarioChecker.source.targetIdNotFound=The following target ids where not found ...@@ -14,6 +14,8 @@ ScenarioChecker.source.targetIdNotFound=The following target ids where not found
ScenarioChecker.source.noTargetIdSet=No Target Ids set for Source. ScenarioChecker.source.noTargetIdSet=No Target Ids set for Source.
ScenarioChecker.source.noTargetIdAndNoSpawn=No Target Ids set for Source with SpawnNumber 0. This might be an error. ScenarioChecker.source.noTargetIdAndNoSpawn=No Target Ids set for Source with SpawnNumber 0. This might be an error.
ScenarioChecker.source.idNotUnique=Multiple Sources have the same ID. ScenarioChecker.source.idNotUnique=Multiple Sources have the same ID.
ScenarioChecker.source.spawnAtRandomButNotAtFreeSpace=Combination isSpawnAtRandomPositions=true and isUseFreeSpaceOnly=false not allowed.
ScenarioChecker.source.spawnUseNotAtFreeSpace=Deprecated. Will be removed in future relases. Not all models can handle overlapping pedestrians.
ScenarioChecker.stairs.wrongTreadDim=Stair treadDepth outside of allowed dimension. Change the thread numbers to compensate. ScenarioChecker.stairs.wrongTreadDim=Stair treadDepth outside of allowed dimension. Change the thread numbers to compensate.
ScenarioChecker.target.unused=The target is not used in any source. Remove target to increase performance. ScenarioChecker.target.unused=The target is not used in any source. Remove target to increase performance.
ScenarioChecker.pedestrian.speedsetup=speedDistributionMean must be within min/max range. ScenarioChecker.pedestrian.speedsetup=speedDistributionMean must be within min/max range.
......
...@@ -13,6 +13,8 @@ ScenarioChecker.type.processor.warning=Procesor Warnung ...@@ -13,6 +13,8 @@ ScenarioChecker.type.processor.warning=Procesor Warnung
ScenarioChecker.source.targetIdNotFound=Die folgenden Ziel-IDs wurden nicht im Szenario gefunden. ScenarioChecker.source.targetIdNotFound=Die folgenden Ziel-IDs wurden nicht im Szenario gefunden.
ScenarioChecker.source.noTargetIdSet=In der Quelle wurden keine Ziel Ids vergeben. ScenarioChecker.source.noTargetIdSet=In der Quelle wurden keine Ziel Ids vergeben.
ScenarioChecker.source.noTargetIdAndNoSpawn=In der Quelle wurden keine Ziel Ids vergeben, aber die Spawn Anzahl ist bei 0. ScenarioChecker.source.noTargetIdAndNoSpawn=In der Quelle wurden keine Ziel Ids vergeben, aber die Spawn Anzahl ist bei 0.
ScenarioChecker.source.spawnAtRandomButNotAtFreeSpace=Kombination aus isSpawnAtRandomPositions=true und isUseFreeSpaceOnly=false ist nicht erlaubt.
ScenarioChecker.source.spawnUseNotAtFreeSpace=Deprecated. Dieses Attribut wird in zuk\u00fcnfigen version entfernt. Nicht alle Modell k\u00f6nnen mit \u00fcberlappungen umgehen.
ScenarioChecker.source.idNotUnique=Quellen haben keine eindeutige ID. ScenarioChecker.source.idNotUnique=Quellen haben keine eindeutige ID.
ScenarioChecker.stairs.wrongTreadDim=Stufentiefe ist au\u00dferhalb des Definitionsbereichs. Passen Sie die Anzahl der Stufen entsprechend an. ScenarioChecker.stairs.wrongTreadDim=Stufentiefe ist au\u00dferhalb des Definitionsbereichs. Passen Sie die Anzahl der Stufen entsprechend an.
ScenarioChecker.target.unused=Das Ziel wird von keiner Quelle verwendet. Entferne das Ziel um die Performance zu erh\u00f6hen ScenarioChecker.target.unused=Das Ziel wird von keiner Quelle verwendet. Entferne das Ziel um die Performance zu erh\u00f6hen
......
package org.vadere.simulator.control; package org.vadere.simulator.control;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.control.util.GroupSpawnArray;
import org.vadere.simulator.models.DynamicElementFactory; import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.simulator.models.groups.GroupModel; import org.vadere.simulator.models.groups.GroupModel;
import org.vadere.state.attributes.scenario.AttributesDynamicElement; import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Source; import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography; import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.PointPositioned;
import org.vadere.util.geometry.shapes.VPoint; import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.stream.Collectors;
public class GroupSourceController extends SourceController { public class GroupSourceController extends SourceController {
private static final int NUMBER_OF_REPOSITION_TRIES = 20;
private final GroupModel groupModel; private final GroupModel groupModel;
private LinkedList<Integer> groupsToSpawn; private LinkedList<Integer> groupsToSpawn;
protected final GroupSpawnArray spawnArray;
public GroupSourceController(Topography scenario, Source source, public GroupSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory, DynamicElementFactory dynamicElementFactory,
...@@ -24,6 +36,14 @@ public class GroupSourceController extends SourceController { ...@@ -24,6 +36,14 @@ public class GroupSourceController extends SourceController {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random); super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
this.groupModel = groupModel; this.groupModel = groupModel;
this.groupsToSpawn = new LinkedList<>(); this.groupsToSpawn = new LinkedList<>();
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,
this::testFreeSpace);
} }
@Override @Override
...@@ -38,7 +58,14 @@ public class GroupSourceController extends SourceController { ...@@ -38,7 +58,14 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator(); Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
int groupSize = iter.next(); int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextFreeGroup(groupSize, random, getDynElementsAtSource()); List<VPoint> newGroup = getRealRandomPositions(
groupSize,
random,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
if (newGroup.size() > 0) { if (newGroup.size() > 0) {
// add immediately to Scenario to update DynElementsAtSource // add immediately to Scenario to update DynElementsAtSource
addElementToScenario(newGroup); addElementToScenario(newGroup);
...@@ -51,7 +78,14 @@ public class GroupSourceController extends SourceController { ...@@ -51,7 +78,14 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator(); Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
int groupSize = iter.next(); int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextGroup(groupSize, random, getDynElementsAtSource()); List<VPoint> newGroup = spawnArray.getNextGroup(
groupSize,
random,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
if (newGroup.isEmpty()) if (newGroup.isEmpty())
throw new RuntimeException("Cannot spawn new Group. Source " + source.getId() + " is set " + 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" + "to useFreeSpaceOnly == false but no space is left to spawn group without exactly" +
...@@ -68,7 +102,13 @@ public class GroupSourceController extends SourceController { ...@@ -68,7 +102,13 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator(); Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
int groupSize = iter.next(); int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextFreeGroup(groupSize, getDynElementsAtSource()); List<VPoint> newGroup = spawnArray.getNextFreeGroup(
groupSize,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
if (newGroup != null && !newGroup.isEmpty()) { if (newGroup != null && !newGroup.isEmpty()) {
// add immediately to Scenario to update DynElementsAtSource // add immediately to Scenario to update DynElementsAtSource
addElementToScenario(newGroup); addElementToScenario(newGroup);
...@@ -81,7 +121,13 @@ public class GroupSourceController extends SourceController { ...@@ -81,7 +121,13 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator(); Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
int groupSize = iter.next(); int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextGroup(groupSize, getDynElementsAtSource()); List<VPoint> newGroup = spawnArray.getNextGroup(
groupSize,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
if (newGroup == null || newGroup.isEmpty()) if (newGroup == null || newGroup.isEmpty())
throw new RuntimeException("Cannot spawn new Group. Source " + source.getId() + " is set " + 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" + "to useFreeSpaceOnly == false but no space is left to spawn group without exactly" +
...@@ -99,6 +145,72 @@ public class GroupSourceController extends SourceController { ...@@ -99,6 +145,72 @@ public class GroupSourceController extends SourceController {
} }
} }
/**
* Computes random positions for ONE group based on the blockPedestrianShapes which contains
* the shapes representing the required space for the specified group size. For each required
* position the algorithms tries {@link GroupSourceController#NUMBER_OF_REPOSITION_TRIES} times
* to get a feasible free position for this group.
*
* @param groupSize size of group to spawn at a random positions
* @param random random generator
* @param blockPedestrianShapes the required space of other pedestrians
* @return list of Points representing the group members or an empty list if group cannot be
* placed after {@link GroupSourceController#NUMBER_OF_REPOSITION_TRIES} of tries.
*/
private List<VPoint> getRealRandomPositions(final int groupSize, @NotNull final Random random, @NotNull final List<VShape> blockPedestrianShapes) {
List<VPoint> randomPositions = new ArrayList<>(groupSize);
List<VPoint> defaultPoints = spawnArray.getDefaultGroup(groupSize);
for (int i = 0; i < NUMBER_OF_REPOSITION_TRIES; i++) {
randomPositions = moveRandomInSourceBound(defaultPoints, random);
boolean groupValid = randomPositions.stream()
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.allMatch(candidateShape ->
source.getShape().containsShape(candidateShape) &&
testFreeSpace(candidateShape, blockPedestrianShapes));
if (groupValid) {
return randomPositions;
}
}
return new ArrayList<>();
}
/**
* @param points default points of group members. First allowed position if the spawn would be
* based on the spawn grid.
* @param random random object
* @return transformed set of points based on a random translation and rotation within the
* bound of the source
*/
private List<VPoint> moveRandomInSourceBound(List<VPoint> points, @NotNull final Random random) {
Rectangle2D bound = source.getShape().getBounds2D();
double angle = random.nextDouble() * 2 * Math.PI;
VPoint p0 = points.get(0);
double dxBound = (bound.getX() - p0.getX());
double dyBound = (bound.getY() - p0.getY());
double dxRnd = random.nextDouble() * (bound.getMaxX() - bound.getX());
double dyRnd = random.nextDouble() * (bound.getMaxY() - bound.getY());
AffineTransform at0 = new AffineTransform();
at0.setToTranslation(dxBound, dyBound);
AffineTransform at1 = new AffineTransform();
at1.setToRotation(angle, bound.getX(), bound.getY());
AffineTransform at2 = new AffineTransform();
at2.setToTranslation(dxRnd, dyRnd);
List<VPoint> ret = new ArrayList<>();
points.stream().map(VPoint::asPoint2D).forEach(p -> {
at0.transform(p, p);
at1.transform(p, p);
at2.transform(p, p);
ret.add(new VPoint(p));
}
);
return ret;
}
private void addElementToScenario(List<VPoint> group) { private void addElementToScenario(List<VPoint> group) {
if (!group.isEmpty() && !isMaximumNumberOfSpawnedElementsReached()) { if (!group.isEmpty() && !isMaximumNumberOfSpawnedElementsReached()) {
addNewAgentToScenario(group); addNewAgentToScenario(group);
......
...@@ -3,14 +3,17 @@ package org.vadere.simulator.control; ...@@ -3,14 +3,17 @@ package org.vadere.simulator.control;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.DynamicElementFactory; import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.state.attributes.scenario.AttributesDynamicElement; import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Obstacle;
import org.vadere.state.scenario.Source; import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography; import org.vadere.state.scenario.Topography;
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.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape; import org.vadere.util.geometry.shapes.VShape;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
...@@ -19,15 +22,21 @@ import java.util.stream.Collectors; ...@@ -19,15 +22,21 @@ import java.util.stream.Collectors;
public class SingleSourceController extends SourceController { public class SingleSourceController extends SourceController {
private int numberToSpawn; private int numberToSpawn;
private DynamicElementFactory dynamicElementFactory;
private static final int NUMBER_OF_REPOSITION_TRIES = 10; 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 SingleSpawnArray spawnArray;
public SingleSourceController(Topography scenario, Source source, public SingleSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory, DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement, AttributesDynamicElement attributesDynamicElement,
Random random) { Random random) {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random); super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
this.dynamicElementFactory = dynamicElementFactory; 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 @Override
...@@ -35,18 +44,17 @@ public class SingleSourceController extends SourceController { ...@@ -35,18 +44,17 @@ public class SingleSourceController extends SourceController {
if (!isSourceFinished(simTimeInSec)) { if (!isSourceFinished(simTimeInSec)) {
if (simTimeInSec >= timeOfNextEvent || numberToSpawn > 0) { if (simTimeInSec >= timeOfNextEvent || numberToSpawn > 0) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec); determineNumberOfSpawnsAndNextEvent(simTimeInSec);
List<VPoint> spawnPoints = new LinkedList<>(); List<VPoint> spawnPoints;
if (sourceAttributes.isSpawnAtRandomPositions()) { if (sourceAttributes.isSpawnAtRandomPositions()) {
if (sourceAttributes.isUseFreeSpaceOnly()) { if (sourceAttributes.isUseFreeSpaceOnly()) {
//spawnPoints = spawnArray.getNextFreeRandomSpawnPoints(numberToSpawn, random, getDynElementsAtSource());
spawnPoints = getRealRandomPositions( spawnPoints = getRealRandomPositions(
numberToSpawn, numberToSpawn,
random, random,
getDynElementsAtSource().stream() getDynElementsAtSource().stream()
.map(element -> element.getPosition()) .map(PointPositioned::getPosition)
.map(position -> dynamicElementFactory.getDynamicElementRequiredPlace(position)) .map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList()) .collect(Collectors.toList())
); );
...@@ -54,19 +62,25 @@ public class SingleSourceController extends SourceController { ...@@ -54,19 +62,25 @@ public class SingleSourceController extends SourceController {
assert (numberToSpawn >= 0); assert (numberToSpawn >= 0);
} else { } else {
throw new IllegalArgumentException("use random position without free space only makes no sense."); throw new IllegalArgumentException("use random position without free space only makes no sense.");
/*spawnPoints = spawnArray.getNextRandomSpawnPoints(numberToSpawn, random, getDynElementsAtSource());
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);*/
} }
} else { } else {
if (sourceAttributes.isUseFreeSpaceOnly()) { if (sourceAttributes.isUseFreeSpaceOnly()) {
spawnPoints = spawnArray.getNextFreeSpawnPoints(numberToSpawn, getDynElementsAtSource()); spawnPoints = getRealPositions(
numberToSpawn,
getDynElementsAtSource().stream()
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
numberToSpawn -= spawnPoints.size(); numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0); assert (numberToSpawn >= 0);
} else { } else {
spawnPoints = spawnArray.getNextSpawnPoints(numberToSpawn, getDynElementsAtSource()); spawnPoints = getRealPositions(
numberToSpawn,
new ArrayList<>()
);
numberToSpawn -= spawnPoints.size(); numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0); assert (numberToSpawn >= 0);
} }
...@@ -83,20 +97,37 @@ public class SingleSourceController extends SourceController { ...@@ -83,20 +97,37 @@ public class SingleSourceController extends SourceController {
} }
} }
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 = spawnArray.getNextPosition(blockPedestrianShapes);
if (optPosition.isPresent()) {
VPoint position = optPosition.get();
blockPedestrianShapes.add(dynamicElementFactory.getDynamicElementRequiredPlace(position));
positions.add(position);
}
}
return positions;
}
/** /**
* Computes numberToSpawn or less random positions based on the blockPedestrianShapes which contains the shapes representing the required space of each pedestrian. * Computes numberToSpawn or less random positions based on the blockPedestrianShapes which
* For each required position the algorithms tries {@link SingleSourceController#NUMBER_OF_REPOSITION_TRIES} times to get a feasible free position. * 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 numberToSpawn number of required spawn positions