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 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 {
}
private void renderGroup(Pedestrian ped, Graphics2D g) {
g.setColor(Color.DARK_GRAY);
g.fill(ped.getShape());
g.setColor(getGroupColor(ped));
DefaultRenderer.fill(getShape(ped), g);
}
......
......@@ -260,6 +260,8 @@ public class TopographyWindow extends JPanel {
obstacleAndTargetDrawModes.add(pen2);
sourceDrawModes.add(rectangle);
sourceDrawModes.add(pen);
sourceDrawModes.add(pen2);
sourceDrawModes.add(dot);
/* open obstacle paint method dialog action */
......
......@@ -226,7 +226,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ],
"attributesPedestrian" : {
"radius" : 0.195,
......
......@@ -353,7 +353,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, {
"source" : null,
"targetIds" : [ 1 ],
......@@ -382,7 +383,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ],
"attributesPedestrian" : {
"radius" : 0.195,
......
......@@ -297,7 +297,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, {
"source" : null,
"targetIds" : [ 1 ],
......@@ -326,7 +327,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ],
"attributesPedestrian" : {
"radius" : 0.195,
......
......@@ -585,7 +585,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
}, {
"source" : null,
"targetIds" : [ 1 ],
......@@ -614,7 +615,8 @@
"isChild" : false,
"isLikelyInjured" : false,
"groupIds" : [ ],
"type" : "PEDESTRIAN"
"type" : "PEDESTRIAN",
"groupSizes" : [ ]
} ],
"attributesPedestrian" : {
"radius" : 0.195,
......
......@@ -69,7 +69,7 @@
},
"attributesSimulation" : {
"finishTime" : 70.0,
"simTimeStepLength" : 1.4,
"simTimeStepLength" : 0.4,
"realTimeSimTimeRatio" : 0.1,
"writeSimulationData" : false,
"visualizationEnabled" : true,
......
......@@ -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.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.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.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.
......
......@@ -13,6 +13,8 @@ ScenarioChecker.type.processor.warning=Procesor Warnung
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.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.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
......
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.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.PointPositioned;
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.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class GroupSourceController extends SourceController {
private static final int NUMBER_OF_REPOSITION_TRIES = 20;
private final GroupModel groupModel;
private LinkedList<Integer> groupsToSpawn;
protected final GroupSpawnArray spawnArray;
public GroupSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
......@@ -24,6 +36,14 @@ public class GroupSourceController extends SourceController {
super(scenario, source, dynamicElementFactory, attributesDynamicElement, random);
this.groupModel = groupModel;
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
......@@ -38,7 +58,14 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
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) {
// add immediately to Scenario to update DynElementsAtSource
addElementToScenario(newGroup);
......@@ -51,7 +78,14 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
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())
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" +
......@@ -68,7 +102,13 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
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()) {
// add immediately to Scenario to update DynElementsAtSource
addElementToScenario(newGroup);
......@@ -81,7 +121,13 @@ public class GroupSourceController extends SourceController {
Iterator<Integer> iter = groupsToSpawn.iterator();
while (iter.hasNext()) {
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())
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" +
......@@ -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) {
if (!group.isEmpty() && !isMaximumNumberOfSpawnedElementsReached()) {
addNewAgentToScenario(group);
......
......@@ -3,14 +3,17 @@ package org.vadere.simulator.control;
import org.jetbrains.annotations.NotNull;
import org.vadere.simulator.models.DynamicElementFactory;
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.simulator.control.util.SingleSpawnArray;
import org.vadere.util.geometry.PointPositioned;
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.Rectangle2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
......@@ -19,15 +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 SingleSpawnArray spawnArray;
public SingleSourceController(Topography scenario, Source source,
DynamicElementFactory dynamicElementFactory,
AttributesDynamicElement attributesDynamicElement,
Random 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
......@@ -35,18 +44,17 @@ 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()) {
if (sourceAttributes.isUseFreeSpaceOnly()) {
//spawnPoints = spawnArray.getNextFreeRandomSpawnPoints(numberToSpawn, random, getDynElementsAtSource());
spawnPoints = getRealRandomPositions(
numberToSpawn,
random,
getDynElementsAtSource().stream()
.map(element -> element.getPosition())
.map(position -> dynamicElementFactory.getDynamicElementRequiredPlace(position))
.map(PointPositioned::getPosition)
.map(dynamicElementFactory::getDynamicElementRequiredPlace)
.collect(Collectors.toList())
);
......@@ -54,19 +62,25 @@ public class SingleSourceController extends SourceController {
assert (numberToSpawn >= 0);
} else {
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 {
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();
assert (numberToSpawn >= 0);
} else {
spawnPoints = spawnArray.getNextSpawnPoints(numberToSpawn, getDynElementsAtSource());
spawnPoints = getRealPositions(
numberToSpawn,
new ArrayList<>()
);
numberToSpawn -= spawnPoints.size();
assert (numberToSpawn >= 0);
}
......@@ -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.
* 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++) {
Optional<VPoint> optRandomPosition = getNextRandomPosition(random, blockPedestrianShapes, NUMBER_OF_REPOSITION_TRIES);
for (int i = 0; i < numberToSpawn; i++) {
Optional<VPoint> optRandomPosition = getNextRandomPosition(random, blockPedestrianShapes, NUMBER_OF_POINT_SEARCH, NUMBER_OF_REPOSITION_TRIES);
if (optRandomPosition.isPresent()) {
VPoint randomPosition = optRandomPosition.get();
......@@ -108,16 +139,26 @@ public class SingleSourceController extends SourceController {
return randomPositions;
}
private Optional<VPoint> getNextRandomPosition(@NotNull final Random random, @NotNull final List<VShape> blockPedestrianShapes, final int tries) {
private Optional<VPoint> getNextRandomPosition(@NotNull final Random random, @NotNull final List<VShape> blockPedestrianShapes,
final int tries_find_valid_point, final int tries_reposition) {
Rectangle2D rec = source.getShape().getBounds2D();
for(int i = 0; i < tries; i++) {
VPoint randomPoint = new VPoint(rec.getMinX() + random.nextDouble() * rec.getWidth(), rec.getMinY() + random.nextDouble() * rec.getHeight());
VShape freeSpaceRequired = dynamicElementFactory.getDynamicElementRequiredPlace(randomPoint);
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) {
randomPoint = new VPoint(rec.getMinX() + random.nextDouble() * rec.getWidth(), rec.getMinY() + random.nextDouble() * rec.getHeight());
freeSpaceRequired = dynamicElementFactory.getDynamicElementRequiredPlace(randomPoint);
pointFound = source.getShape().containsShape(freeSpaceRequired);
j++;
}
// no intersection with other free spaces (obstacles & other pedestrians)
if(blockPedestrianShapes.stream().noneMatch(shape -> shape.intersects(freeSpaceRequired))
&& this.getTopography().getObstacles().stream().noneMatch(obs -> obs.getShape().intersects(freeSpaceRequired))) {
if (testFreeSpace(freeSpaceRequired, blockPedestrianShapes)) {
return Optional.of(randomPoint);
}
}
......@@ -125,7 +166,6 @@ public class SingleSourceController extends SourceController {
return Optional.empty();
}
@Override
protected boolean isQueueEmpty() {
return numberToSpawn == 0;
......
......@@ -8,16 +8,15 @@ 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.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.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
......@@ -25,21 +24,22 @@ import java.util.Random;
public abstract class SourceController {
protected final double NO_EVENT = Double.MAX_VALUE;
public static final double SPAWN_BUFFER_SIZE = 0.03;
// public static final double SPAWN_BUFFER_SIZE = 0.03;
protected final Source source;
private final DynamicElementFactory dynamicElementFactory;
protected final DynamicElementFactory dynamicElementFactory;
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;
protected final AttributesDynamicElement attributesDynamicElement;
protected int dynamicElementsCreatedTotal;
protected final SpawnArray spawnArray;
public SourceController(Topography scenario, Source source,
......@@ -53,11 +53,6 @@ public abstract class SourceController {
this.topography = scenario;
this.random = random;
VRectangle elementBound = new VRectangle(dynamicElementFactory.getDynamicElementRequiredPlace(new VPoint(0,0)).getBounds2D());
this.spawnArray = new SpawnArray(new VRectangle(source.getShape().getBounds2D()),
new VRectangle(0, 0,elementBound.getWidth() + SPAWN_BUFFER_SIZE, elementBound.getHeight() + SPAWN_BUFFER_SIZE));
timeOfNextEvent = sourceAttributes.getStartTime();
try {
DistributionFactory factory = DistributionFactory
......@@ -69,15 +64,16 @@ public abstract class SourceController {
}
}
/**
* @return List of DynamicElements within a circle, which surrounds the source shape completely
*/
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);
return getDynElementsAtPosition(source.getShape().getCircumCircle());
}
protected List<DynamicElement> getDynElementsAtPosition(VPoint sourcePosition, double radius) {
protected List<DynamicElement> getDynElementsAtPosition(VCircle circumCircle) {
LinkedCellsGrid<DynamicElement> dynElements = topography.getSpatialMap(DynamicElement.class);
return dynElements.getObjects(sourcePosition, radius);
return dynElements.getObjects(circumCircle.getCenter(), circumCircle.getRadius());
}
abstract public void update(double simTimeInSec);
......@@ -107,6 +103,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);
......@@ -131,8 +135,8 @@ public abstract class SourceController {