Commit cfd3e5e1 authored by Benedikt Kleinmeier's avatar Benedikt Kleinmeier
Browse files

Added "GroupMembership" to "PsychologyStatus" and use it in "ThreatCognitionModel"

parent 556a1ba2
package org.vadere.simulator.control.psychology.cognition;
import org.vadere.state.psychology.cognition.GroupMembership;
import org.vadere.state.psychology.cognition.SelfCategory;
import org.vadere.state.psychology.perception.types.Bang;
import org.vadere.state.psychology.perception.types.ElapsedTime;
......@@ -8,6 +9,8 @@ import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Suppose a threat (a {@link Bang}) occurred.
......@@ -30,6 +33,8 @@ public class ThreatCognitionModel implements ICognitionModel {
}
@Override
// TODO: Maybe, use also use cooperative behavior from "CooperativeCognitionModel".
// Refactor this long if-else cascade so that it is easier to read.
public void update(Collection<Pedestrian> pedestrians) {
for (Pedestrian pedestrian : pedestrians) {
if (pedestrian.getMostImportantStimulus() instanceof Bang) {
......@@ -39,21 +44,40 @@ public class ThreatCognitionModel implements ICognitionModel {
} else if (pedestrian.getMostImportantStimulus() instanceof ElapsedTime) {
if (pedestrian.getPerceivedThreat() != null) {
if (pedIsInsideThreatArea(pedestrian, (Bang) pedestrian.getPerceivedThreat())) {
pedestrian.setSelfCategory(SelfCategory.INSIDE_THREAT_AREA);
} else {
pedestrian.setSelfCategory(SelfCategory.OUTSIDE_THREAT_AREA);
}
} else {
// TODO: Imitate behavior if recognizing an in-group member.
// Maybe, use also cooperative behavior from "CooperativeCognitionModel".
// TODO: A pedestrian needs boolean variable "isInGroup" or another enum
// "Member { IN_GROUP, OUT_GROUP, OUT_GROUP_FRIENDLY, OUT_GROUP_NEUTRAL_ OUT_GROUP_HOSTILE }"
// if (pedestrian.getPerceivedThreat() != null) => These peds perceived a threat!
// else checkIfSearchRadiusContainsAThreatedPed
pedestrian.setSelfCategory(SelfCategory.TARGET_ORIENTED);
}
} else { // These agents did not perceive a threat but are aware of other threatened agents.
// TODO: Pedestrians must be spawned with a random "GroupMembership".
if (pedestrian.getGroupMembership() == GroupMembership.OUT_GROUP) {
pedestrian.setSelfCategory(SelfCategory.TARGET_ORIENTED);
} else if (pedestrian.getGroupMembership() == GroupMembership.IN_GROUP) {
// If a threatened pedestrian is identified, use the same reaction as if
// the current "pedestrian" would have perceived the same threat.
// I.e., store the perceived threat and use "INSIDE_THREAT_AREA" to
// accelerate and search for a safe zone.
List<Pedestrian> threatenedPedestrians = getClosestPedestriansWithSelfCategory(pedestrian, SelfCategory.OUTSIDE_THREAT_AREA);
if (threatenedPedestrians.isEmpty() == false) {
Pedestrian threatedPedestrian = threatenedPedestrians.get(0);
assert threatedPedestrian.getPerceivedThreat() != null;
pedestrian.setPerceivedThreat(threatedPedestrian.getPerceivedThreat());
pedestrian.setSelfCategory(SelfCategory.INSIDE_THREAT_AREA);
} else {
pedestrian.setSelfCategory(SelfCategory.TARGET_ORIENTED);
}
} else {
throw new IllegalArgumentException("Can only process \"OUT_GROUP\" and \"IN_GROUP\" group membership!");
}
}
} else {
throw new IllegalArgumentException("Can only process \"Bang\" and \"ElapsedTime\" stimuli!");
}
......@@ -68,4 +92,32 @@ public class ThreatCognitionModel implements ICognitionModel {
return isInsideThreatArea;
}
private void imitateClosestInGroupMember(Pedestrian pedestrian) {
}
private List<Pedestrian> getClosestPedestriansWithSelfCategory(Pedestrian pedestrian, SelfCategory expectedSelfCategory) {
VPoint positionOfPedestrian = pedestrian.getPosition();
List<Pedestrian> closestPedestrians = topography.getSpatialMap(Pedestrian.class)
.getObjects(positionOfPedestrian, pedestrian.getAttributes().getSearchRadius());
// Filter out "me" and pedestrians which are further away from target than "me".
closestPedestrians = closestPedestrians.stream()
.filter(candidate -> pedestrian.getId() != candidate.getId())
.filter(candidate -> pedestrian.getSelfCategory() == expectedSelfCategory)
.collect(Collectors.toList());
// Sort by distance away from "me".
closestPedestrians = closestPedestrians.stream()
.sorted((pedestrian1, pedestrian2) ->
Double.compare(
positionOfPedestrian.distance(pedestrian1.getPosition()),
positionOfPedestrian.distance(pedestrian2.getPosition())
))
.collect(Collectors.toList());
return closestPedestrians;
}
}
package org.vadere.state.psychology;
import org.vadere.state.psychology.cognition.GroupMembership;
import org.vadere.state.psychology.cognition.SelfCategory;
import org.vadere.state.psychology.perception.types.Stimulus;
......@@ -7,31 +8,34 @@ public class PsychologyStatus {
// Member Variables
private Stimulus mostImportantStimulus;
// TODO: Maybe, implement some kind of memory instead of only a perceived threat.
private Stimulus perceivedThreat;
private Stimulus perceivedThreat; // TODO: Maybe, implement some kind of memory instead of just a perceived threat.
private SelfCategory selfCategory;
private GroupMembership groupMembership;
// Constructors
public PsychologyStatus() {
this(null, null, SelfCategory.TARGET_ORIENTED);
this(null, null, SelfCategory.TARGET_ORIENTED, GroupMembership.OUT_GROUP);
}
public PsychologyStatus(Stimulus mostImportantStimulus, Stimulus perceivedThreat, SelfCategory selfCategory) {
public PsychologyStatus(Stimulus mostImportantStimulus, Stimulus perceivedThreat, SelfCategory selfCategory, GroupMembership groupMembership) {
this.mostImportantStimulus = mostImportantStimulus;
this.perceivedThreat = perceivedThreat;
this.selfCategory = selfCategory;
this.groupMembership = groupMembership;
}
public PsychologyStatus(PsychologyStatus other) {
this.mostImportantStimulus = other.getMostImportantStimulus() != null ? other.getMostImportantStimulus().clone() : null;
this.perceivedThreat = other.getPerceivedThreat() != null ? other.getPerceivedThreat().clone() : null;
this.selfCategory = other.getSelfCategory();
this.groupMembership = other.getGroupMembership();
}
// Getter
public Stimulus getMostImportantStimulus() { return mostImportantStimulus; }
public Stimulus getPerceivedThreat() { return perceivedThreat; }
public SelfCategory getSelfCategory() { return selfCategory; }
public GroupMembership getGroupMembership() { return groupMembership; }
// Setter
public void setMostImportantStimulus(Stimulus mostImportantStimulus) {
......@@ -46,4 +50,8 @@ public class PsychologyStatus {
this.selfCategory = selfCategory;
}
public void setGroupMembership(GroupMembership groupMembership) {
this.groupMembership = groupMembership;
}
}
......@@ -2,7 +2,7 @@ package org.vadere.state.psychology.cognition;
/**
* According to the self-categorization theory ("reicher-2010"), people define
* themselves as member of social categories (see{@link SelfCategory}). When
* themselves as a member of social categories (see{@link SelfCategory}). When
* people share the same {@link SelfCategory}, they often act collectively
* if they feel as in-group member to this category.
*
......
......@@ -2,15 +2,16 @@ package org.vadere.state.psychology.cognition;
/**
* According to the self-categorization theory ("reicher-2010"), people define
* themselves as member of a social category. Often, people act collectively
* when being in the same category. E.g., protesters - which define themselves
* as protesters - walk together during a demonstration.
* themselves as a member of social categories. People can have multiple
* categories, e.g., father, football fan, colleague. At a specific point in
* time, only one category is salient.
*
* Our agents can use these categorizations to derive a specific behavior.
* E.g., if an agents is "COOPERATIVE", the pedestrian swaps places
* with other "COOPERATIVE" pedestrians.
* Our agents use these categorizations to derive a specific behavior.
* E.g., if an agents is "COOPERATIVE" (category), the pedestrian swaps places
* (behavior) with other "COOPERATIVE" pedestrians (only if both feel committed
* to this category as in-group member, see {@łink GroupMembership}.
*
* Watch out: The self category of an agent can change during a simulation.
* Usually, the self category of an agent changes during a simulation.
*/
public enum SelfCategory {
TARGET_ORIENTED,
......
......@@ -2,6 +2,7 @@ package org.vadere.state.scenario;
import org.vadere.state.attributes.scenario.AttributesAgent;
import org.vadere.state.psychology.PsychologyStatus;
import org.vadere.state.psychology.cognition.GroupMembership;
import org.vadere.state.psychology.cognition.SelfCategory;
import org.vadere.state.psychology.perception.types.Stimulus;
import org.vadere.state.simulation.FootStep;
......@@ -22,12 +23,13 @@ public class Pedestrian extends Agent {
public static final double INVALID_NEXT_EVENT_TIME = -1.0;
// Variables
// TODO: All these variables belong to Isabella's "social identity" branch
// which was never merged with "master". On "master", these variables should be unused.
// Therefore, delete them.
private int idAsTarget; // TODO should actually be an attribute or a member of a subclass
private boolean isChild; // TODO should actually be an attribute or a member of a subclass
private boolean isLikelyInjured; // TODO should actually be an attribute or a member of a subclass
// TODO: Save also "Stimulus perceivedThreat" and "SelfCategory ingroup".
// Maybe here, or in "PsychologyStatus".
private PsychologyStatus psychologyStatus;
private LinkedList<Integer> groupIds; // TODO should actually be an attribute or a member of a subclass
......@@ -63,7 +65,7 @@ public class Pedestrian extends Agent {
idAsTarget = -1;
isChild = false;
isLikelyInjured = false;
psychologyStatus = new PsychologyStatus(null, null, SelfCategory.TARGET_ORIENTED);
psychologyStatus = new PsychologyStatus(null, null, SelfCategory.TARGET_ORIENTED, GroupMembership.OUT_GROUP);
groupIds = new LinkedList<>();
groupSizes = new LinkedList<>();
modelPedestrianMap = new HashMap<>();
......@@ -106,6 +108,7 @@ public class Pedestrian extends Agent {
public Stimulus getMostImportantStimulus() { return psychologyStatus.getMostImportantStimulus(); }
public Stimulus getPerceivedThreat() { return psychologyStatus.getPerceivedThreat(); }
public SelfCategory getSelfCategory() { return psychologyStatus.getSelfCategory(); }
public GroupMembership getGroupMembership() { return psychologyStatus.getGroupMembership(); }
public LinkedList<Integer> getGroupIds() { return groupIds; }
public LinkedList<Integer> getGroupSizes() {
return groupSizes;
......@@ -153,8 +156,9 @@ public class Pedestrian extends Agent {
this.isLikelyInjured = likelyInjured;
}
public void setMostImportantStimulus(Stimulus mostImportantStimulus) { psychologyStatus.setMostImportantStimulus(mostImportantStimulus); }
public void setSelfCategory(SelfCategory selfCategory) { psychologyStatus.setSelfCategory(selfCategory); }
public void setPerceivedThreat(Stimulus perceivedThreat) { psychologyStatus.setPerceivedThreat(perceivedThreat); }
public void setSelfCategory(SelfCategory selfCategory) { psychologyStatus.setSelfCategory(selfCategory); }
public void setGroupMembership(GroupMembership groupMembership) { psychologyStatus.setGroupMembership(groupMembership); }
public void setGroupIds(LinkedList<Integer> groupIds) {
this.groupIds = groupIds;
}
......@@ -180,10 +184,7 @@ public class Pedestrian extends Agent {
}
public void clearFootSteps() {
// getLast() is always the most recent (made sure in VTrajectory.add)
// This statement is for security and should mostly have no effect (only if someone did not use method
// "addFootStepToTrajectory" to add another foot step to the trajectory)
if(!trajectory.isEmpty()){
if (!trajectory.isEmpty()){
trajectory.clear();
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment