/* * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab * * This file is part of PeerfactSim.KOM. * * PeerfactSim.KOM is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * PeerfactSim.KOM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PeerfactSim.KOM. If not, see . * */ package de.tud.kom.p2psim.impl.topology.movement.modularosm; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import de.tud.kom.p2psim.api.scenario.ConfigurationException; import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy; import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.MovementGroupContainer; import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup; import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupencounter.IGroupEncounterBehavior; import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming.IGroupFormingBehavior; import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy; import de.tud.kom.p2psim.impl.topology.util.PositionVector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; import de.tud.kom.p2psim.impl.util.Either; import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.Monitor; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint; /** * * @author Julian Zobel * @version 1.0, 28.01.2020 */ public class SocialGroupMovementModel extends ModularMovementModel { private final double MEETING_POINT_DISTANCE = 5; private final double LEADER_GROUP_DISTANCE = 10; protected MovementGroupContainer groupContainer; protected IGroupFormingBehavior groupFormingBehavior; protected IGroupEncounterBehavior groupEncounterBehavior; protected IAttractionAssigmentStrategy groupAttractionAssignment; private LinkedHashSet singleHosts = new LinkedHashSet(); private int numberOfSingleHosts; @Override public void initialize() { if (!initialized) { groupContainer = MovementGroupContainer.getInstance(); groupFormingBehavior.initialize(this); groupEncounterBehavior.initialize(this); // Choose single hosts if(numberOfSingleHosts > 0) { do { singleHosts.add(getRandomActuator()); } while(singleHosts.size() < numberOfSingleHosts); } if (modelVisualisation == null) { modelVisualisation = new ModularMovementModelViz(this); } VisualizationInjector.injectComponent(modelVisualisation); if (mapVisualization != null) { VisualizationInjector.injectComponent(mapVisualization); } if (attractionPointViz != null) { System.out.println("insert AP viz"); VisualizationInjector.injectComponent(attractionPointViz); } checkConfiguration(); // setWayPointModel localMovementStrategy.setObstacleModel(Binder .getComponentOrNull(Topology.class).getObstacleModel()); localMovementStrategy.setWaypointModel(Binder .getComponentOrNull(Topology.class).getWaypointModel()); /* * Scale depending on calculation interval, if interval != 1 Second. */ localMovementStrategy .setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND); attractionAssigment.addAttractionAssignmentListener(this); attractionAssigment.setAttractionProvider(attractionProvider); groupAttractionAssignment.addAttractionAssignmentListener(this); groupAttractionAssignment.setAttractionProvider(attractionProvider); // This adds the mobile hosts (smartphones/users) to the transition // strategy for (SimLocationActuator ms : moveableHosts) { if(singleHosts.contains(ms)) { attractionAssigment.addComponent(ms); if(placeNodesAtAP) { IAttractionPoint assignment = attractionAssigment.getAssignment(ms); ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment), (assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0))); attractionAssigment.updateTargetAttractionPoint(ms, assignment); } } else { groupAttractionAssignment.addComponent(ms); if(placeNodesAtAP) { IAttractionPoint assignment = groupAttractionAssignment.getAssignment(ms); ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment), (assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0))); groupAttractionAssignment.updateTargetAttractionPoint(ms, assignment); } } // //attractionAssigment.addComponent(ms); // if(placeNodesAtAP) { // IAttractionPoint assignment = attractionAssigment.getAssignment(ms); // ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment), // (assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0))); // attractionAssigment.updateTargetAttractionPoint(ms, assignment); // } } setTimeBetweenMoveOperations(timeBetweenMoveOperation); // Inform analyzer of resolved movement if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) { Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts); } // initial move move(); initialized = true; } } /** * Returns a random SimLocationActuator component from the set of moveable hosts. * * @return SimLocationActuator */ private SimLocationActuator getRandomActuator() { int index = rand.nextInt(moveableHosts.size()); int i = 0; for(SimLocationActuator actuator : moveableHosts) { if(i == index) { return actuator; } i++; } return null; } /** * The movement model. * 1) Updates the number of hosts within each attraction point. * 2) Creates and deletes groups, if necessary. * 3) Applies encounter action to meeting groups. * 4) Moves the hosts using doGroupMovement, movement style depends on role of the host (Leader, Participant, Single) */ @Override protected void move() { // Check POIs if groups can be created. Delete groups, if destination reached. groupFormingBehavior.manageGroups(); // Checks if groups encounter each other and applies a specified action to these groups. groupEncounterBehavior.handleEncounters(); /* * Moves all nodes according to definition in group movement method */ for (SimLocationActuator host : moveableHosts) { assert currentTargets.containsKey(host); // Single Host Movement if(singleHosts.contains(host)) { super.doLocalMovement(host, currentTargets.get(host)); } else if( !groupContainer.isGroupMember(host)) { doLocalMovement(host, currentTargets.get(host)); } else if(groupContainer.isGroupMember(host)){ doGroupMovement(host, currentTargets.get(host)); } else { throw new UnsupportedOperationException("SimLocationActuator " + host + " is neither in a group nor a single node"); } // TODO maybe remodel the group movement to do a whole group? } // TODO Move each group Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE); } @Override protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) { Either either = localMovementStrategy.nextPosition(ms, destination); if (either.hasLeft()) { ms.updateCurrentLocation(either.getLeft()); if(!checkBoundaries(ms.getRealPosition())) { System.err.println("Social Group Movement Model: Host moved outside of simulated area!"); } } else { groupAttractionAssignment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint()); } } /** * Applies movement of the host according to different circumstances: * * Towards Destination: Host is not a group member || Group has met at meeting point successfully. * Towards MeetingPoint: Host if group member and has not reached meeting point yet. * No movement: Host reached meeting point, but still waits for group members to arrive. * * @param SimLocationActuator The host to move. * @param PositionVector Destination of the host. */ protected void doGroupMovement(SimLocationActuator host, PositionVector destination) { // This host is a member of a group, thus... SocialMovementGroup group = groupContainer.getGroupOfHost(host); // if the group is currently gathering at a meeting point... if(movesToGroupMeetingPoint(host)) { // if this host has already arrived at the group meeting point.. if(hostIsAtMeetingPoint(host)) { // ... and if the whole group is also at the meeting point... if(groupGatheredAtMeetingPoint(group)) { // remove the meeting point and thus, start moving towards the actual destination group.setMeetingPoint(null); } // ... but the group is not gathered at the meeting point, do nothing and wait for the rest. else { // inform analyzer of waiting group members if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) { Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMemberWaitAtMeetingPoint(group, host); } } } // if the host has not reached the group meeting point, move towards it. else { PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint(); doLocalMovement(host, mp); // inform analyzer group member moves to meeting point if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) { Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMoveToMeetingPoint(group, host); } } } // ... but if the group is currently on their way to the destination else { // the leader does a local movement if(groupContainer.isLeader(host)) { if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) { // inform analyzer of movement to attraction point if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) { Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupMovesToAttractionPoint(group); } doLocalMovement(host, destination); PositionVector leaderPos = host.getRealPosition(); LinkedHashSet groupMembers = groupContainer.getGroupMembers(host); groupMembers.remove(host); // remove leader for (SimLocationActuator groupMember : groupMembers) { // Assign small offset to the host depending on the leaders position. PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE); PositionVector newPos = leaderPos.plus(offset); // Update location of host, which will be around the leaders location. groupMember.updateCurrentLocation(newPos); } } else { // inform analyzer of waiting group if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) { Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupWait(group); } } } } } @Override public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) { if(singleHosts.contains(actuator)) { super.changeTargetLocation(actuator, ap); } else { groupAttractionAssignment.updateTargetAttractionPoint(actuator, ap); actuator.setMovementSpeed(this.speedProvider.calculateSpeed()); } } @Override public IAttractionPoint getTargetLocation(SimLocationActuator actuator) { if(singleHosts.contains(actuator)) { return attractionAssigment.getAssignment(actuator); } else { return groupAttractionAssignment.getAssignment(actuator); } } /* * ===================================================================================================== * === MEETING POINT FUNCTIONS * ===================================================================================================== */ /** * Checks if a host is currently on its way to a meeting point or to its destination. * Returns true if moving towards meeting point, false else. * * @param SimLocationActuator The host to be checked. * @return Boolean */ private boolean movesToGroupMeetingPoint(SimLocationActuator host) { PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint(); if(meetingpoint == null) return false; else if(meetingpoint != groupContainer.getGroupOfHost(host).getDestination()) return true; else return false; } /** * Returns true, if all group members of a host including the host itself reached the meeting point, false else. * * @param SimLocationActuator The host to be checked. * @return Boolean */ private boolean groupGatheredAtMeetingPoint(SocialMovementGroup group) { for(SimLocationActuator participant : group.getMembers()) { if(!hostIsAtMeetingPoint(participant)) { return false; } } return true; } /** * Returns true if the host reached its current meeting point, false else. * * @param SimLocationActuator The host to be checked. * @return Boolean * */ private boolean hostIsAtMeetingPoint(SimLocationActuator host) { PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint(); if(host.getLastLocation().distanceTo(meetingpoint) <= MEETING_POINT_DISTANCE) return true; else return false; } /* * ===================================================================================================== * === MOVEMENT FUNCTIONS * ===================================================================================================== */ /** * Host position adapts to leaders position by taking the leader position and adding a small offset * * @param SimLocationActuator The host to be moved. */ private void followLeader(SimLocationActuator host) { SimLocationActuator leader = groupContainer.getGroupOfHost(host).getLeader(); // Assign small offset to the host depending on the leaders position. PositionVector leaderPos = leader.getRealPosition(); PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE); PositionVector newPos = leaderPos.plus(offset); // Update location of host, which will be around the leaders location. host.updateCurrentLocation(newPos); } /* * ===================================================================================================== * === GETTER AND SETTER FUNCTIONS * ===================================================================================================== */ public void setGroupFormingBehavior(IGroupFormingBehavior defaultGroupForming) { if (defaultGroupForming == null) { throw new ConfigurationException( "GroupFormingStrategy is missing in ModularMovementModel!"); } this.groupFormingBehavior = defaultGroupForming; } public void setGroupEncounterBehavior(IGroupEncounterBehavior defaultGroupEncounterBehavior) { if (defaultGroupEncounterBehavior == null) { throw new ConfigurationException( "GroupEncounterStrategy is missing in ModularMovementModel!"); } this.groupEncounterBehavior = defaultGroupEncounterBehavior; } public IAttractionAssigmentStrategy getAttractionAssignmentStrategy() { return this.groupAttractionAssignment; } public IGroupFormingBehavior getGroupFormingBehavior() { return groupFormingBehavior; } public LocalMovementStrategy getMovementStrategy() { return localMovementStrategy; } public void setNumberOfSingleHosts(int numberOfSingleHosts) { this.numberOfSingleHosts = numberOfSingleHosts; } public LinkedHashSet getSingleHosts(){ return singleHosts; } public LinkedHashMap getCurrentTargets(){ return currentTargets; } public void setGroupAttractionAssignmentStrategy(IAttractionAssigmentStrategy groupAttractionAssignment) { if (groupAttractionAssignment == null) { throw new ConfigurationException( "IAttractionAssigmentStrategy for Groups is missing in SocialGroupMovementModel!"); } this.groupAttractionAssignment = groupAttractionAssignment; } }