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

implement SourceController for groups.

parent 4f518de1
package org.vadere.simulator.control;
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.util.geometry.shapes.VPoint;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
public class GroupSourceController extends SourceController {
private final GroupModel groupModel;
private LinkedList<Integer> groupsToSpawn;
public GroupSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random, GroupModel groupModel) {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
this.groupModel = groupModel;
this.groupsToSpawn = new LinkedList<>();
}
@Override
public void update(double simTimeInSec) {
if (!isSourceFinished(simTimeInSec)) {
if (simTimeInSec >= timeOfNextEvent || !groupsToSpawn.isEmpty()) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec);
LinkedList<List<VPoint>> spawnGroups = new LinkedList<>();
if (sourceAttributes.isSpawnAtRandomPositions()) {
if (sourceAttributes.isUseFreeSpaceOnly()) {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextFreeGroup(groupSize, random, getDynElementsAtSource());
if (newGroup != null) {
spawnGroups.add(newGroup);
iter.remove();
} else {
break; // FIFO Spawn. The rest of the queue at next time step
}
}
} else {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextGroup(groupSize, random);
spawnGroups.add(newGroup);
iter.remove();
}
}
} else {
if (sourceAttributes.isUseFreeSpaceOnly()) {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextFreeGroup(groupSize, getDynElementsAtSource());
if (newGroup != null) {
spawnGroups.add(newGroup);
iter.remove();
} else {
break; // FIFO Spawn. The rest of the queue at next time step
}
}
} else {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
int groupSize = iter.next();
List<VPoint> newGroup = spawnArray.getNextGroup(groupSize);
spawnGroups.add(newGroup);
iter.remove();
}
}
}
for (List<VPoint> group : spawnGroups) {
if (!isMaximumNumberOfSpawnedElementsReached()) {
addNewAgentToScenario(group);
dynamicElementsCreatedTotal++;
}
}
}
}
}
private void getNewGroupSizeFromModel() {
for (int i = 0; i < sourceAttributes.getSpawnNumber(); i++) {
int groupSize = groupModel.getGroupFactory(source.getId()).createNewGroup();
groupsToSpawn.add(groupSize);
}
}
@Override
protected boolean isQueueEmpty() {
return false;
}
@Override
protected void determineNumberOfSpawnsAndNextEvent(double simTimeInSec) {
while (timeOfNextEvent <= simTimeInSec) {
getNewGroupSizeFromModel();
createNextEvent();
}
}
}
......@@ -2,6 +2,7 @@ package org.vadere.simulator.control;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.simulator.control.factory.SourceControllerFactory;
import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.simulator.models.MainModel;
import org.vadere.simulator.models.Model;
......@@ -69,6 +70,7 @@ public class Simulation {
/** Hold the topography in an extra field for convenience. */
private final Topography topography;
private final ProcessorManager processorManager;
private final SourceControllerFactory sourceControllerFactory;
public Simulation(MainModel mainModel, double startTimeInSec, final String name, ScenarioStore scenarioStore,
List<PassiveCallback> passiveCallbacks, Random random, ProcessorManager processorManager) {
......@@ -85,6 +87,7 @@ public class Simulation {
this.simTimeInSec = startTimeInSec;
this.models = mainModel.getSubmodels();
this.sourceControllerFactory = mainModel.getSourceControllerFactory();
// TODO [priority=normal] [task=bugfix] - the attributesCar are missing in initialize' parameters
this.dynamicElementFactory = mainModel;
......@@ -108,8 +111,9 @@ public class Simulation {
// create source and target controllers
for (Source source : topography.getSources()) {
sourceControllers
.add(new SourceController(topography, source, dynamicElementFactory, attributesAgent, random));
SourceController sc = this.sourceControllerFactory
.create(topography, source, dynamicElementFactory, attributesAgent, random);
sourceControllers.add(sc);
}
for (Target target : topography.getTargets()) {
targetControllers.add(new TargetController(topography, target));
......
package org.vadere.simulator.control;
import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.LinkedList;
import java.util.Random;
public class SingleSourceController extends SourceController {
private int numberToSpawn;
public SingleSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random) {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
}
@Override
public void update(double simTimeInSec) {
if (!isSourceFinished(simTimeInSec)) {
if (simTimeInSec >= timeOfNextEvent || numberToSpawn > 0) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec);
LinkedList<VPoint> spawnPoints = new LinkedList<>();
if (sourceAttributes.isSpawnAtRandomPositions()) {
if (sourceAttributes.isUseFreeSpaceOnly()) {
spawnPoints = spawnArray.getNextFreeRandomSpawnPoints(numberToSpawn, random, getDynElementsAtSource());
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
} else {
for (int i = 0; i < numberToSpawn; i++) {
spawnPoints.add(spawnArray.getNextRandomSpawnPoint(random));
}
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
}
} else {
if (sourceAttributes.isUseFreeSpaceOnly()) {
spawnPoints = spawnArray.getNextFreeSpawnPoints(numberToSpawn, getDynElementsAtSource());
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
} else {
for (int i = 0; i < numberToSpawn; i++) {
spawnPoints.add(spawnArray.getNextSpawnPoint());
}
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
}
}
for (VPoint spawnPoint : spawnPoints) {
if (!isMaximumNumberOfSpawnedElementsReached()) {
addNewAgentToScenario(spawnPoint);
dynamicElementsCreatedTotal++;
}
}
}
}
}
@Override
protected boolean isQueueEmpty() {
return numberToSpawn == 0;
}
@Override
protected void determineNumberOfSpawnsAndNextEvent(double simTimeInSec) {
while (timeOfNextEvent <= simTimeInSec) {
numberToSpawn += sourceAttributes.getSpawnNumber();
createNextEvent();
}
}
}
package org.vadere.simulator.control;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.apache.commons.math3.distribution.RealDistribution;
import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.state.attributes.scenario.AttributesAgent;
......@@ -15,48 +10,49 @@ import org.vadere.state.scenario.Car;
import org.vadere.state.scenario.DistributionFactory;
import org.vadere.state.scenario.DynamicElement;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import org.vadere.state.util.SpawnArray;
import org.vadere.util.geometry.LinkedCellsGrid;
import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.math.MathUtil;
import org.vadere.util.geometry.shapes.VRectangle;
public class SourceController {
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
protected final Source source;
protected DynamicElementFactory dynamicElementFactory;
protected final Topography topography;
protected final Random random;
private final AttributesSource sourceAttributes;
private AttributesDynamicElement attributesDynamicElement;
public abstract class SourceController {
// TODO [priority=high] [task=refactoring] remove this from the SourceController and add a new attribute.
// This is ONLY used for "useFreeSpaceOnly".
private VCircle dynamicElementShape;
protected final double NO_EVENT = Double.MAX_VALUE;
private int dynamicElementsToCreate;
private int dynamicElementsCreatedTotal;
protected final Source source;
private final DynamicElementFactory dynamicElementFactory;
private final Topography topography;
protected final Random random;
/** <code>null</code>, if there is no next event. */
private Double timeOfNextEvent;
private RealDistribution distribution;
protected Double timeOfNextEvent;
protected RealDistribution distribution;
protected final AttributesSource sourceAttributes;
protected final AttributesDynamicElement attributesDynamicElement;
protected int dynamicElementsCreatedTotal;
protected final SpawnArray spawnArray;
public SourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement, Random random) {
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random) {
this.source = source;
this.sourceAttributes = source.getAttributes();
this.attributesDynamicElement = attributesDynamicElement;
this.dynamicElementFactory = dynamicElementFactory;
this.topography = scenario;
this.random = random;
this.attributesDynamicElement = attributesDynamicElement;
this.dynamicElementShape = getDynamicElementShape();
dynamicElementsToCreate = 0;
dynamicElementsCreatedTotal = 0;
this.spawnArray = new SpawnArray(new VRectangle(source.getShape().getBounds2D()),
new VRectangle(0, 0, getDynamicElementShape().getRadius() * 2, getDynamicElementShape().getRadius() * 2));
timeOfNextEvent = sourceAttributes.getStartTime();
try {
......@@ -69,70 +65,58 @@ public class SourceController {
}
}
public void update(double simTimeInSec) {
useDistributionSpawnAlgorithm(simTimeInSec);
}
private boolean isPositionWorkingForSpawn(VPoint position) {
if (sourceAttributes.isUseFreeSpaceOnly()) {
// Verify if position is obstructed by other pedestrian.
for (ScenarioElement neighbor : getDynElementsAtPosition(position, dynamicElementShape)) {
if (neighbor.getShape().distance(position) < dynamicElementShape.getRadius() * 2) {
// Position may be obstructed by other pedestrian. Hence, don't create pedestrian now but try again next frame.
return false;
}
}
}
return true;
}
private VCircle getDynamicElementShape() {
if (attributesDynamicElement instanceof AttributesAgent) {
return new VCircle(((AttributesAgent) attributesDynamicElement).getRadius());
}
return new VCircle(0.2);
protected List<DynamicElement> getDynElementsAtSource() {
Rectangle2D rec = source.getShape().getBounds2D();
double maxDim = rec.getWidth() > rec.getHeight() ? rec.getWidth() : rec.getHeight();
return getDynElementsAtPosition(source.getShape().getCentroid(), maxDim / 2);
}
private List<DynamicElement> getDynElementsAtPosition(VPoint sourcePosition, VCircle dynElementShape) {
protected List<DynamicElement> getDynElementsAtPosition(VPoint sourcePosition, double radius) {
LinkedCellsGrid<DynamicElement> dynElements = topography.getSpatialMap(DynamicElement.class);
return dynElements.getObjects(sourcePosition, dynElementShape.getRadius() * 3);
return dynElements.getObjects(sourcePosition, radius);
}
private void useDistributionSpawnAlgorithm(double simTimeInSec) {
if (!isSourceFinished(simTimeInSec)) {
if (hasNextEvent()) {
processNextEventWhenItIsTime(simTimeInSec);
}
tryToSpawnOutstandingDynamicElements();
}
}
abstract public void update(double simTimeInSec);
private boolean isSourceFinished(double simTimeInSec) {
protected boolean isSourceFinished(double simTimeInSec) {
if (isMaximumNumberOfSpawnedElementsReached()) {
return true;
}
if (isSourceWithOneSingleSpawnEvent()) {
return dynamicElementsCreatedTotal == sourceAttributes.getSpawnNumber();
}
return isAfterSourceEndTime(simTimeInSec) && dynamicElementsToCreate == 0;
return isAfterSourceEndTime(simTimeInSec) && isQueueEmpty();
}
protected boolean isSourceWithOneSingleSpawnEvent() {
return sourceAttributes.getStartTime() == sourceAttributes.getEndTime();
}
protected boolean isAfterSourceEndTime(double time) {
return time > sourceAttributes.getEndTime();
}
private boolean hasNextEvent() {
return timeOfNextEvent != null;
protected boolean isMaximumNumberOfSpawnedElementsReached() {
final int maxNumber = sourceAttributes.getMaxSpawnNumberTotal();
return maxNumber != AttributesSource.NO_MAX_SPAWN_NUMBER_TOTAL
&& dynamicElementsCreatedTotal >= maxNumber;
}
private void processNextEventWhenItIsTime(double simTimeInSec) {
if (simTimeInSec >= timeOfNextEvent) {
determineNumberOfSpawnsAndNextEvent(simTimeInSec);
private VCircle getDynamicElementShape() {
if (attributesDynamicElement instanceof AttributesAgent) {
return new VCircle(((AttributesAgent) attributesDynamicElement).getRadius());
}
return new VCircle(0.2);
}
private void determineNumberOfSpawnsAndNextEvent(double simTimeInSec) {
dynamicElementsToCreate += sourceAttributes.getSpawnNumber();
abstract protected boolean isQueueEmpty();
abstract protected void determineNumberOfSpawnsAndNextEvent(double simTimeInSec);
protected void createNextEvent() {
if (isSourceWithOneSingleSpawnEvent()) {
timeOfNextEvent = null;
timeOfNextEvent = NO_EVENT;
return;
}
......@@ -140,43 +124,20 @@ public class SourceController {
timeOfNextEvent += distribution.sample();
if (isAfterSourceEndTime(timeOfNextEvent)) {
timeOfNextEvent = null;
return;
timeOfNextEvent = NO_EVENT;
}
// If timeOfNextEvent still behind current time -> start an (indirect) recursion
processNextEventWhenItIsTime(simTimeInSec);
}
private boolean isMaximumNumberOfSpawnedElementsReached() {
final int maxNumber = sourceAttributes.getMaxSpawnNumberTotal();
return maxNumber != AttributesSource.NO_MAX_SPAWN_NUMBER_TOTAL
&& dynamicElementsCreatedTotal >= maxNumber;
}
private boolean isSourceWithOneSingleSpawnEvent() {
return sourceAttributes.getStartTime() == sourceAttributes.getEndTime();
}
private boolean isAfterSourceEndTime(double time) {
return time > sourceAttributes.getEndTime();
}
private void tryToSpawnOutstandingDynamicElements() {
for (VPoint position : getDynamicElementPositions(dynamicElementsToCreate)) {
if (!isMaximumNumberOfSpawnedElementsReached() && isPositionWorkingForSpawn(position)) {
addNewAgentToScenario(position);
dynamicElementsToCreate--;
dynamicElementsCreatedTotal++;
}
}
}
/**
* 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 DynamicElement addNewAgentToScenario(final VPoint position) {
protected void addNewAgentToScenario(final List<VPoint> position) {
position.forEach(p -> addNewAgentToScenario(p));
}
protected void addNewAgentToScenario(final VPoint position) {
Agent newElement = (Agent) createDynamicElement(position);
// TODO [priority=high] [task=refactoring] this is bad programming. Why is the target list added later?
......@@ -190,8 +151,6 @@ public class SourceController {
}
topography.addElement(newElement);
return newElement;
}
private DynamicElement createDynamicElement(final VPoint position) {
......@@ -210,41 +169,4 @@ public class SourceController {
result.setSource(source);
return result;
}
private LinkedList<VPoint> getDynamicElementPositions(int numDynamicElements) {
LinkedList<VPoint> positions = new LinkedList<>();
Rectangle2D rect = source.getShape().getBounds2D();
int numPedX = numDynamicElements;
double ds = 0;
if (rect.getHeight() == 0 && rect.getWidth() == 0) {
rect = new Rectangle2D.Double(rect.getMinX(), rect.getMinY(), 0.2,
0.2);
}
ds = Math.sqrt((rect.getWidth() * rect.getHeight()) / numDynamicElements);
numPedX = (int) Math.ceil(rect.getWidth() / ds);
double[][] quasiRandoms = null;
if (sourceAttributes.isSpawnAtRandomPositions()) {
quasiRandoms = MathUtil.quasiRandom2D(random, numDynamicElements,
rect.getWidth(), rect.getHeight(), 1.0);
}
for (int iDE = 0; iDE < numDynamicElements; ++iDE) {
VPoint pos;
if (sourceAttributes.isSpawnAtRandomPositions()) {
pos = new VPoint(quasiRandoms[iDE][0] + rect.getMinX(),
quasiRandoms[iDE][1] + rect.getMinY());
} else {
pos = new VPoint(rect.getMinX() + (iDE % numPedX) * ds,
rect.getMinY() + (iDE / numPedX) * ds);
}
positions.add(pos);
}
return positions;
}
}
package org.vadere.simulator.control.factory;
import org.vadere.simulator.control.GroupSourceController;
import org.vadere.simulator.control.SourceController;
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 java.util.Random;
public class GroupSourceControllerFactory extends SourceControllerFactory {
private final GroupModel groupModel;
public GroupSourceControllerFactory(GroupModel groupModel) {
this.groupModel = groupModel;
}
@Override
public SourceController create(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random) {
return new GroupSourceController(scenario, source, dynamicElementFactory, attributesDynamicElement, random, groupModel);
}
}
package org.vadere.simulator.control.factory;
import org.vadere.simulator.control.SingleSourceController;
import org.vadere.simulator.control.SourceController;
import org.vadere.simulator.models.DynamicElementFactory;
import org.vadere.state.attributes.scenario.AttributesDynamicElement;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Topography;
import java.util.Random;
public class SingleSourceControllerFactory extends SourceControllerFactory {
@Override
public SourceController create(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random random) {
return new SingleSourceController(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
}
}