/* * 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.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; 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.attraction.IAttractionGenerator; import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.hostcount.IAttractionPointHostCounter; 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.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; /** * * @author Julian Zobel * @version 1.0, 28.01.2020 */ public class SocialGroupMovementModel extends ModularMovementModel { protected MovementGroupContainer groupContainer; protected IGroupFormingBehavior groupFormingBehavior; protected IGroupEncounterBehavior groupEncounterBehavior; protected IAttractionPointHostCounter attractionPointHostCounter; private Set singleHosts = new LinkedHashSet(); private int numberOfSingleHosts; private boolean placeNodesAtAP = false; public void setPlaceNodes(boolean placeNodes) { this.placeNodesAtAP = placeNodes; } @Override public void initialize() { if (!initialized) { groupContainer = MovementGroupContainer.getInstance(); attractionPointHostCounter.initialize(this); 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); } 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); // This adds the mobile hosts (smartphones/users) to the transition // strategy for (SimLocationActuator ms : moveableHosts) { attractionAssigment.addComponent(ms); if(placeNodesAtAP) ms.updateCurrentLocation(attractionAssigment.getAssignment(ms)); } setTimeBetweenMoveOperations(timeBetweenMoveOperation); // 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() { // Update the number of hosts within each attraction point. attractionPointHostCounter.updateHostCount(); // 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 component : moveableHosts) { assert currentTargets.containsKey(component); doGroupMovement(component, currentTargets.get(component)); } Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE); } /** * 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) { // Single Host Movement if(singleHosts.contains(host) || !groupContainer.isGroupMember(host)) { doLocalMovement(host, destination); } // Group Related Movement else if(groupContainer.isGroupMember(host)){ if(movesToGroupMeetingPoint(host)) { if(hostIsAtMeetingPoint(host)) { if(groupAtMP(host)) { SocialMovementGroup group = groupContainer.getGroupOfHost(host); AttractionPoint currAp = group.getLeader().getCurrentTargetAttractionPoint(); PositionVector currDest = group.getDestination(); group.setMeetingPoint(currDest); for(SimLocationActuator participant : group.getMembers()) { attractionAssigment.updateTargetAttractionPoint(participant, currAp); } } } // MP not reached. Move to MP. else { PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint(); doLocalMovement(host, mp); } } // MP reached. Move to destination. else { if(groupContainer.isLeader(host)) { if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) { doLocalMovement(host, destination); } } else { followLeader(host); } } } } /* * ===================================================================================================== * === 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 mp = groupContainer.getGroupOfHost(host).getMeetingPoint(); PositionVector dest = groupContainer.getGroupOfHost(host).getDestination(); if(mp != dest) { return true; } 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 groupAtMP(SimLocationActuator host) { Set participants = groupContainer.getGroupMembers(host); int counter = 0; for(SimLocationActuator participant : participants) { if(hostIsAtMeetingPoint(participant)) { counter++; } } if(counter == participants.size()) { return true; } return false; } /** * 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 currMP = groupContainer.getGroupOfHost(host).getMeetingPoint(); // Setting the required distance to the meeting point to maximum of 2 meters // This is equivalent to a distance of group members in real life double distance = host.getLastLocation().distanceTo(currMP); if(distance <= 5) { return true; } 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(); if(leader.getCurrentTargetAttractionPoint() == null) { System.out.println(); } AttractionPoint leaderDestination = leader.getCurrentTargetAttractionPoint(); AttractionPoint hostDestination = host.getCurrentTargetAttractionPoint(); // Update target attraction point if not already done if(leaderDestination != null && hostDestination != leaderDestination) { attractionAssigment.updateTargetAttractionPoint(host, leaderDestination); } int o = 10; // Assign small offset to the host depending on the leaders position. PositionVector leaderPos = leader.getRealPosition(); PositionVector offset = new PositionVector(rand.nextInt(o), rand.nextInt(o)); 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 void setAttractionPointHostCounter(IAttractionPointHostCounter attractionPointHostCounter) { if (attractionPointHostCounter == null) { throw new ConfigurationException( "HostCountStrategy is missing in ModularMovementModel!"); } this.attractionPointHostCounter = attractionPointHostCounter; } public IAttractionAssigmentStrategy getAttractionAssignmentStrategy() { return attractionAssigment; } public IGroupFormingBehavior getGroupFormingBehavior() { return groupFormingBehavior; } public LocalMovementStrategy getMovementStrategy() { return localMovementStrategy; } public IAttractionPointHostCounter getAttractionPointHostCounter() { return attractionPointHostCounter; } public void setNumberOfSingleHosts(int numberOfSingleHosts) { this.numberOfSingleHosts = numberOfSingleHosts; } public Set getSingleHosts(){ return singleHosts; } public Map getCurrentTargets(){ return currentTargets; } /** * Only for visualization! * * @return */ public List getAttractionPoints() { return new Vector(IAttractionGenerator.attractionPoints); } }