Commit 6308a0f2 authored by Benedikt Kleinmeier's avatar Benedikt Kleinmeier
Browse files

Added new scenario element "AbsorbingArea" to package "org.vadere.state" and included it into GUI.

New scenario element "AbsorbingArea" is not handled in:
- AbsorbingAreaController (this class is missing completely at the moment).
- MigrationAssistant (must add node '"absorbingAreas" : [ ]' to topography tree).
- DefaultConfig (to be able to change color).
- TikzGenerator (must use "topography.getAbsorbingAreas()" to iterate over the new scenario element).
parent 5fa69f1f
......@@ -306,6 +306,7 @@ TopographyCreator.btnTranslation.tooltip=Translate topography
TopographyCreator.btnElementTranslation.tooltip=Translate topography elements
TopographyCreator.btnInsertObstacle.tooltip=Obstacle
TopographyCreator.btnInsertTarget.tooltip=Target
TopographyCreator.btnInsertAbsorbingArea.tooltip=Absorbing Area
TopographyCreator.btnInsertSource.tooltip=Source
TopographyCreator.btnInsertStairs.tooltip=Stairs
TopographyCreator.btnErase.tooltip=Eraser
......
......@@ -298,6 +298,7 @@ TopographyCreator.btnCutTopography.tooltip=Szenario ausschneiden
TopographyCreator.btnInsertPedestrian.tooltip=Fu\u00dfg\u00e4nger
TopographyCreator.btnInsertObstacle.tooltip=Hindernis
TopographyCreator.btnInsertTarget.tooltip=Ziel
TopographyCreator.btnInsertAbsorbingArea.tooltip=Absorbierender Bereich
TopographyCreator.btnTopographyBound.tooltip=Topographie Grenze
TopographyCreator.btnTranslation.tooltip=Topographie verschieben
TopographyCreator.btnElementTranslation.tooltip=Elemente der Topography verschieben
......
......@@ -102,6 +102,9 @@ public abstract class DefaultModel<T extends DefaultConfig> extends Observable i
case TARGET:
c = getConfig().getTargetColor();
break;
case ABSORBING_AREA:
c = Color.RED;
break;
default:
c = Color.RED;
}
......
......@@ -12,14 +12,7 @@ import org.vadere.gui.topographycreator.control.AttributeModifier;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.attributes.scenario.AttributesCar;
import org.vadere.state.attributes.scenario.AttributesTopography;
import org.vadere.state.scenario.Obstacle;
import org.vadere.state.scenario.Pedestrian;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.scenario.Source;
import org.vadere.state.scenario.Stairs;
import org.vadere.state.scenario.Target;
import org.vadere.state.scenario.Teleporter;
import org.vadere.state.scenario.Topography;
import org.vadere.state.scenario.*;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VShape;
......@@ -42,6 +35,7 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
private LinkedList<Stairs> stairs;
private LinkedList<Source> sources;
private LinkedList<Target> targets;
private LinkedList<AbsorbingArea> absorbingAreas;
private Teleporter teleporter;
private LinkedList<ScenarioElement> topographyElements;
private AttributesTopography attributes;
......@@ -57,6 +51,7 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
stairs = new LinkedList<>();
sources = new LinkedList<>();
targets = new LinkedList<>();
absorbingAreas = new LinkedList<>();
topographyElements = new LinkedList<>();
attributes = new AttributesTopography();
}
......@@ -77,6 +72,7 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
}
sources = new LinkedList<>(topography.getSources());
targets = new LinkedList<>(topography.getTargets());
absorbingAreas = new LinkedList<>(topography.getAbsorbingAreas());
teleporter = topography.getTeleporter();
} catch (SecurityException | IllegalArgumentException e) {
e.printStackTrace();
......@@ -90,6 +86,7 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
topographyElements.addAll(pedestrians);
topographyElements.addAll(sources);
topographyElements.addAll(targets);
topographyElements.addAll(absorbingAreas);
}
/**
......@@ -133,6 +130,9 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
for (Target target : targets)
topography.addTarget(target);
for (AbsorbingArea absorbingArea : absorbingAreas)
topography.addAbsorbingArea(absorbingArea);
for (AgentWrapper pedestrian : pedestrians)
topography.addInitialElement(pedestrian.getAgentInitialStore());
......@@ -167,6 +167,8 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
return pedestrians.remove(element);
case TARGET:
return targets.remove(element);
case ABSORBING_AREA:
return absorbingAreas.remove(element);
case SOURCE:
return sources.remove(element);
default:
......@@ -222,12 +224,23 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
this.targets.add(target);
}
public void addAbsorbingArea(final AbsorbingArea absorbingArea) {
this.topographyElements.add(absorbingArea);
this.absorbingAreas.add(absorbingArea);
}
public Target removeLastTarget() {
Target target = targets.removeLast();
topographyElements.remove(target);
return target;
}
public AbsorbingArea removeLastAbsorbingArea() {
AbsorbingArea absorbingArea = absorbingAreas.removeLast();
topographyElements.remove(absorbingArea);
return absorbingArea;
}
public Source removeLastSource() {
Source source = sources.removeLast();
topographyElements.remove(source);
......@@ -274,6 +287,10 @@ public class TopographyBuilder implements Iterable<ScenarioElement> {
return targets.iterator();
}
public Iterator<AbsorbingArea> getAbsorbingAreaIterator() {
return absorbingAreas.iterator();
}
public Iterator<Source> getSourceIterator() {
return sources.iterator();
}
......
......@@ -196,6 +196,9 @@ public class TopographyCreatorModel extends DefaultModel implements IDrawPanelMo
case TARGET:
element = topographyBuilder.removeLastTarget();
break;
case ABSORBING_AREA:
element = topographyBuilder.removeLastAbsorbingArea();
break;
case TELEPORTER:
element = topographyBuilder.removeTeleporter();
break;
......@@ -294,6 +297,9 @@ public class TopographyCreatorModel extends DefaultModel implements IDrawPanelMo
case TARGET:
topographyBuilder.addTarget((org.vadere.state.scenario.Target) shape);
break;
case ABSORBING_AREA:
topographyBuilder.addAbsorbingArea((org.vadere.state.scenario.AbsorbingArea) shape);
break;
case TELEPORTER:
topographyBuilder.setTeleporter((org.vadere.state.scenario.Teleporter) shape);
break;
......
package org.vadere.gui.topographycreator.model;
import org.vadere.state.attributes.Attributes;
import org.vadere.state.attributes.scenario.AttributesObstacle;
import org.vadere.state.attributes.scenario.AttributesSource;
import org.vadere.state.attributes.scenario.AttributesStairs;
import org.vadere.state.attributes.scenario.AttributesTarget;
import org.vadere.state.attributes.scenario.*;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.types.ScenarioElementType;
import org.vadere.util.geometry.shapes.Vector2D;
......@@ -35,6 +32,8 @@ public class TopographyElementFactory {
return new org.vadere.state.scenario.Source(new AttributesSource(-1, shape));
case TARGET:
return new org.vadere.state.scenario.Target(new AttributesTarget(shape));
case ABSORBING_AREA:
return new org.vadere.state.scenario.AbsorbingArea(new AttributesAbsorbingArea(shape));
case PEDESTRIAN:
return new AgentWrapper(((VCircle) shape).getCenter());
default:
......@@ -51,6 +50,8 @@ public class TopographyElementFactory {
return new org.vadere.state.scenario.Source((AttributesSource) attributes);
} else if (attributes instanceof AttributesTarget) {
return new org.vadere.state.scenario.Target((AttributesTarget) attributes);
} else if (attributes instanceof AttributesAbsorbingArea) {
return new org.vadere.state.scenario.AbsorbingArea((AttributesAbsorbingArea) attributes);
} else {
throw new IllegalArgumentException("unsupported Attributes.");
}
......
......@@ -37,6 +37,7 @@ public class TopographyCreatorRenderer extends DefaultRenderer {
renderers[ScenarioElementType.PEDESTRIAN.ordinal()] = this::renderFilledShape;
renderers[ScenarioElementType.SOURCE.ordinal()] = this::renderFilledShape;
renderers[ScenarioElementType.TARGET.ordinal()] = this::renderFilledShape;
renderers[ScenarioElementType.ABSORBING_AREA.ordinal()] = this::renderFilledShape;
renderers[ScenarioElementType.STAIRS.ordinal()] = this::renderStair;
renderers[ScenarioElementType.TELEPORTER.ordinal()] = this::renderFilledShape;
renderers[ScenarioElementType.CAR.ordinal()] = this::renderFilledShape;
......
......@@ -229,6 +229,10 @@ public class TopographyWindow extends JPanel {
TopographyAction switchToTargetAction = new ActionSwitchCategory("switch to targets", panelModel,
ScenarioElementType.TARGET, selectRectangleAction);
/* switch category to absorbing areas action */
TopographyAction switchToAbsorbingAreaAction = new ActionSwitchCategory("switch to absorbing areas", panelModel,
ScenarioElementType.ABSORBING_AREA, selectRectangleAction);
/* switch category to stairs action */
TopographyAction switchToStairsAction = new ActionSwitchCategory("switch to stairs", panelModel,
ScenarioElementType.STAIRS, selectRectangleAction);
......@@ -255,6 +259,7 @@ public class TopographyWindow extends JPanel {
List<Action> obstacleAndTargetDrawModes = new ArrayList<>();
List<Action> sourceDrawModes = new ArrayList<>();
List<Action> absorbingAreaDrawModes = new ArrayList<>();
obstacleAndTargetDrawModes.add(rectangle);
obstacleAndTargetDrawModes.add(pen);
......@@ -265,6 +270,10 @@ public class TopographyWindow extends JPanel {
sourceDrawModes.add(pen2);
sourceDrawModes.add(dot);
absorbingAreaDrawModes.add(rectangle);
absorbingAreaDrawModes.add(pen);
absorbingAreaDrawModes.add(pen2);
/* open obstacle paint method dialog action */
JButton obsButton = new JButton();
TopographyAction openObstacleDialog = new ActionOpenDrawOptionMenu(
......@@ -278,6 +287,12 @@ public class TopographyWindow extends JPanel {
.getResource("/icons/target_icon.png")), panelModel, switchToTargetAction, targetButton,
obstacleAndTargetDrawModes);
/* open absorbing area paint method dialog action */
JButton absorbingAreaButton = new JButton();
TopographyAction openAbsorbingAreaDialog = new ActionOpenDrawOptionMenu("AbsorbingArea", new ImageIcon(Resources.class
.getResource("/icons/emergency_exit.png")), panelModel, switchToAbsorbingAreaAction, absorbingAreaButton,
absorbingAreaDrawModes);
/* open stairs paint method dialog action */
JButton stairsButton = new JButton();
TopographyAction openStairsDialog = new ActionOpenDrawOptionMenu("Stairs", new ImageIcon(Resources.class
......@@ -345,6 +360,8 @@ public class TopographyWindow extends JPanel {
toolbar.addSeparator(new Dimension(5, 50));
addActionToToolbar(toolbar, openObstacleDialog, "TopographyCreator.btnInsertObstacle.tooltip",
obsButton);
addActionToToolbar(toolbar, openAbsorbingAreaDialog, "TopographyCreator.btnInsertAbsorbingArea.tooltip",
absorbingAreaButton);
addActionToToolbar(toolbar, closeDialogAction, "TopographyCreator.btnInsertPedestrian.tooltip");
addActionToToolbar(toolbar, openStairsDialog, "TopographyCreator.btnInsertStairs.tooltip",
stairsButton);
......
......@@ -164,6 +164,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
......@@ -164,6 +164,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
......@@ -164,6 +164,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
......@@ -164,6 +164,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
......@@ -152,6 +152,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
......@@ -164,6 +164,7 @@
"startingWithRedLight" : false,
"nextSpeed" : -1.0
} ],
"absorbingAreas" : [ ],
"sources" : [ {
"id" : 1,
"shape" : {
......
package org.vadere.state.attributes.scenario;
import org.vadere.state.attributes.AttributesEmbedShape;
import org.vadere.util.geometry.shapes.VShape;
/**
* Attributes of an absorbing area, used by "AbsorbingAreaController" during simulation.
*/
public class AttributesAbsorbingArea extends AttributesEmbedShape {
// Variables
private int id = ID_NOT_SET;
/**
* Shape and position.
*/
private VShape shape;
/**
* Waiting time in seconds on this area before absorbing the element.
*/
private double waitingTime = 0;
/**
* Within this distance, pedestrians have reached the absorbing area.
*/
private double deletionDistance = 0.1;
// Constructors
public AttributesAbsorbingArea() {
}
public AttributesAbsorbingArea(final VShape shape) {
this.shape = shape;
}
public AttributesAbsorbingArea(final VShape shape, final int id) {
this.shape = shape;
this.id = id;
}
public AttributesAbsorbingArea(final VShape shape, final int id, double waitingTime, double deletionDistance) {
this.shape = shape;
this.id = id;
this.waitingTime = waitingTime;
this.deletionDistance = deletionDistance;
}
// Getters
public int getId() {
return id;
}
@Override
public VShape getShape() {
return shape;
}
public double getWaitingTime() {
return waitingTime;
}
public double getDeletionDistance() {
return deletionDistance;
}
// Setters
public void setId(int id) {
checkSealed();
this.id = id;
}
@Override
public void setShape(VShape shape) {
this.shape = shape;
}
public void setWaitingTime(double waitingTime) {
checkSealed();
this.waitingTime = waitingTime;
}
public void setDeletionDistance(double deletionDistance) {
checkSealed();
this.deletionDistance = deletionDistance;
}
}
package org.vadere.state.scenario;
import org.vadere.state.attributes.Attributes;
import org.vadere.state.attributes.scenario.AttributesAbsorbingArea;
import org.vadere.state.attributes.scenario.AttributesTarget;
import org.vadere.state.types.ScenarioElementType;
import org.vadere.util.geometry.shapes.VShape;
import java.util.*;
/**
* An area with an arbitrary shape that absorbs agents event if they have not reached their target.
* This can be useful when agents run away from targets (e.g., after a bang event).
*/
public class AbsorbingArea extends ScenarioElement implements Comparable<AbsorbingArea> {
// Variables
private AttributesAbsorbingArea attributes;
private final Map<Integer, Double> enteringTimes;
/**
* Collection of listeners - unordered because it's order is not predictable
* (at least not for clients).
*/
private final Collection<AbsorbingAreaListener> absorbingAreaListeners = new LinkedList<>();
// Constructors
public AbsorbingArea(AttributesAbsorbingArea attributes) {
this(attributes, new HashMap<>());
}
public AbsorbingArea(AttributesAbsorbingArea attributes, Map<Integer, Double> enteringTimes) {
this.attributes = attributes;
this.enteringTimes = enteringTimes;
}
// Getters
public double getWaitingTime() {
return attributes.getWaitingTime();
}
public Map<Integer, Double> getEnteringTimes() {
return enteringTimes;
}
@Override
public int getId() {
return attributes.getId();
}
@Override
public VShape getShape() {
return attributes.getShape();
}
@Override
public ScenarioElementType getType() {
return ScenarioElementType.ABSORBING_AREA;
}
@Override
public AttributesAbsorbingArea getAttributes() {
return attributes;
}
// Setters
@Override
public void setShape(VShape newShape) {
attributes.setShape(newShape);
}
@Override
public void setAttributes(Attributes attributes) {
this.attributes = (AttributesAbsorbingArea) attributes;
}
// Other Methods
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AbsorbingArea)) {
return false;
}
AbsorbingArea other = (AbsorbingArea) obj;
if (attributes == null) {
if (other.attributes != null) {
return false;
}
} else if (!attributes.equals(other.attributes)) {
return false;
}
return true;
}
@Override
public int compareTo(AbsorbingArea otherTarget) {
return this.getId() - otherTarget.getId();
}
/** Models can register a target listener. */
public void addListener(AbsorbingAreaListener listener) {
absorbingAreaListeners.add(listener);
}
public boolean removeListener(TargetListener listener) {
return absorbingAreaListeners.remove(listener);
}
/** Returns an unmodifiable collection. */
public Collection<AbsorbingAreaListener> getAbsorbingAreaListeners() {
return Collections.unmodifiableCollection(absorbingAreaListeners);
}
@Override
public AbsorbingArea clone() {
return new AbsorbingArea((AttributesAbsorbingArea) attributes.clone());
}
}
package org.vadere.state.scenario;
public interface AbsorbingAreaListener {
void reachedAbsorbingArea(Target target, Agent agent);
}
......@@ -2,6 +2,7 @@ package org.vadere.state.scenario;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.commons.math3.analysis.function.Abs;
import org.jetbrains.annotations.NotNull;
import org.vadere.state.attributes.Attributes;
import org.vadere.state.attributes.scenario.AttributesAgent;
......@@ -61,6 +62,11 @@ public class Topography implements DynamicElementMover{
* iteration between frames.
*/
private final LinkedList<Target> targets;
/**
* AbsorbingAreas of scenario by id. Tree maps ensures same update order during
* iteration between frames.
*/
private final LinkedList<AbsorbingArea> absorbingAreas;
/**
* List of obstacles used as a boundary for the whole topography.
......@@ -106,6 +112,7 @@ public class Topography implements DynamicElementMover{
stairs = new LinkedList<>();
sources = new LinkedList<>();
targets = new LinkedList<>();
absorbingAreas = new LinkedList<>();
boundaryObstacles = new LinkedList<>();
allScenarioElements.add(obstacles);
......@@ -151,6 +158,16 @@ public class Topography implements DynamicElementMover{
return null;
}
public AbsorbingArea getAbsorbingArea(int targetId) {
for (AbsorbingArea absorbingArea : this.absorbingAreas) {
if (absorbingArea.getId() == targetId) {
return absorbingArea;
}
}
return null;
}
public double distanceToObstacle(@NotNull IPoint point) {
return this.obstacleDistanceFunction.apply(point);
}
......@@ -167,6 +184,14 @@ public class Topography implements DynamicElementMover{
return getTargets().stream().filter(t -> t.getId() == targetId).anyMatch(targetPredicate);
}
public boolean containsAbsorbingArea(final Predicate<AbsorbingArea> absorbingAreaPredicate) {
return getAbsorbingAreas().stream().anyMatch(absorbingAreaPredicate);
}
public boolean containsAbsorbingArea(final Predicate<AbsorbingArea> absorbingAreaPredicate, final int absorbingAreaId) {
return getAbsorbingAreas().stream().filter(t -> t.getId() == absorbingAreaId).anyMatch(absorbingAreaPredicate);
}
/**
* Returns a list containing Targets with the specific id. This list may be empty.
*/
......@@ -182,6 +207,14 @@ public class Topography implements DynamicElementMover{
.toList())));
}
public Map<Integer, List<VShape>> getAbsorbingAreaShapes() {
return getAbsorbingAreas().stream()
.collect(Collectors