SocialGroupMovementModel.java 13.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * 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 <http://www.gnu.org/licenses/>.
 *
 */

package de.tud.kom.p2psim.impl.topology.movement.modularosm;

23
import java.util.LinkedHashMap;
24
25
26
import java.util.LinkedHashSet;

import de.tud.kom.p2psim.api.scenario.ConfigurationException;
27
import de.tud.kom.p2psim.api.topology.Topology;
28
29
30
31
32
33
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;
Julian Zobel's avatar
wip    
Julian Zobel committed
34
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
35
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
36
37
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tudarmstadt.maki.simonstrator.api.Binder;
38
import de.tudarmstadt.maki.simonstrator.api.Event;
39
import de.tudarmstadt.maki.simonstrator.api.Monitor;
40
import de.tudarmstadt.maki.simonstrator.api.Time;
41
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
42
43
44
45
46
47
48
49

/**
 * 
 * @author Julian Zobel
 * @version 1.0, 28.01.2020
 */
public class SocialGroupMovementModel extends ModularMovementModel {

50
51
52
	private final double MEETING_POINT_DISTANCE = 5;
	private final double LEADER_GROUP_DISTANCE = 10;
	
53
54
55
	protected MovementGroupContainer groupContainer;
	protected IGroupFormingBehavior groupFormingBehavior;
	protected IGroupEncounterBehavior groupEncounterBehavior;
56
		
57
	private LinkedHashSet<SimLocationActuator> singleHosts = new LinkedHashSet<SimLocationActuator>();
58
	private int numberOfSingleHosts;
59
60
		
	
61
62
63
	
	@Override
	public void initialize() {
64
		
65
		if (!initialized) {
66
			
67
68
69
70
71
72
73
74
75
76
77
			groupContainer = MovementGroupContainer.getInstance();
			groupFormingBehavior.initialize(this);
			groupEncounterBehavior.initialize(this);
			
			// Choose single hosts
			if(numberOfSingleHosts > 0) {
				do {
					singleHosts.add(getRandomActuator());
				} while(singleHosts.size() < numberOfSingleHosts);
			}
			
78
79
80
81
82
83
84
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
			VisualizationInjector.injectComponent(modelVisualisation);
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
85
86
87
88
			if (attractionPointViz != null) {
				System.out.println("insert AP viz");
				VisualizationInjector.injectComponent(attractionPointViz);
			}
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

			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);
Julian Zobel's avatar
Julian Zobel committed
105
			attractionAssigment.setAttractionProvider(attractionProvider);
106
107
108
109
110

			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
			for (SimLocationActuator ms : moveableHosts) {
				attractionAssigment.addComponent(ms);
Julian Zobel's avatar
Julian Zobel committed
111
				if(placeNodesAtAP) {
112
					IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
113
114
					ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
							(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));	
115
					attractionAssigment.updateTargetAttractionPoint(ms, assignment);
Julian Zobel's avatar
Julian Zobel committed
116
				}								
117
			}
118
						
119
120
			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

121
122
			// Inform analyzer of resolved movement
			if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {			
123
				Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
124
125
			}
			
126
127
128
129
			// initial move
			move();

			initialized = true;
130
131
		}
	}
132
		
133
	
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
	/**
	 * 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
Julian Zobel's avatar
wip    
Julian Zobel committed
161
	protected void move() {	
162
				
163
164
165
		// Check POIs if groups can be created. Delete groups, if destination reached.
		groupFormingBehavior.manageGroups();
		
166
167
		// Checks if groups encounter each other and applies a specified action to these groups.		
		groupEncounterBehavior.handleEncounters();
168
169
	
		/*	
170
171
		 * Moves all nodes according to definition in group movement method
		 */
172
173
		for (SimLocationActuator host : moveableHosts) {
			assert currentTargets.containsKey(host);
174
						
175
176
177
178
179
180
181
182
183
184
			// Single Host Movement
			if(singleHosts.contains(host) || !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");
			}
185
186
	
			// TODO maybe remodel the group movement to do a whole group?
187
			
188
		}
189
190
		
	
191
192
193
		// TODO Move each group
		
		
194
195
196
197
198
199
200
201
202
203
204
205
206
207
		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) {
208
209
210
211
		// This host is a member of a group, thus...
		SocialMovementGroup group = groupContainer.getGroupOfHost(host);	
		
		// if the group is currently gathering at a meeting point...
212
		if(movesToGroupMeetingPoint(host)) {
213
			// if this host has already arrived at the group meeting point..
214
			if(hostIsAtMeetingPoint(host)) {
215
216
217
218
				// ... 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);
219
				}
220
221
222
223
224
225
226
				// ... 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);											
					}					
				}				
227
			}
228
229
			// if the host has not reached the group meeting point, move towards it.
			else {				
230
231
				PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint();
				doLocalMovement(host, mp);
232
233
234
235
236
				
				// inform analyzer group member moves to meeting point
				if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
					Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMoveToMeetingPoint(group, host);								
				}
237
238
			}
		}
239
		// ... but if the group is currently on their way to the destination
240
		else {
241
			// the leader does a local movement
242
			if(groupContainer.isLeader(host)) {
Julian Zobel's avatar
Julian Zobel committed
243
				if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) {		
244
245
246
					// inform analyzer of movement to attraction point
					if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
						Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupMovesToAttractionPoint(group);			
Julian Zobel's avatar
Julian Zobel committed
247
248
					}	
					
249
250
251
252
253
254
255
256
257
258
259
260
261
262
					doLocalMovement(host, destination);		
					
					PositionVector leaderPos = host.getRealPosition();					
					LinkedHashSet<SimLocationActuator> 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);
					}
263
264
265
266
267
268
				}
				else {
					// inform analyzer of waiting group
					if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
						Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupWait(group);
					}		
269
270
271
				}
			}
		}
272
		
273
274
275
276
277
278
279
280
281
282
283
284
285
286
	}
	
	/* 
	 * =====================================================================================================
	 * === 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
	 */
287
	private boolean movesToGroupMeetingPoint(SimLocationActuator host) {
288
289
290
291
292
		PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
		
		if(meetingpoint == null) 
			return false;		
		else if(meetingpoint != groupContainer.getGroupOfHost(host).getDestination())
293
			return true;
294
295
		else		
			return false;
296
297
298
299
300
301
302
303
	}

	/**
	 * 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
	 */
304
305
306
307
308
	private boolean groupGatheredAtMeetingPoint(SocialMovementGroup group) {
	
		for(SimLocationActuator participant : group.getMembers()) {
			if(!hostIsAtMeetingPoint(participant)) {
				return false;
309
310
			}
		}
311
312
		
		return true;
313
314
315
316
317
318
319
320
321
	}

	/**
	 * Returns true if the host reached its current meeting point, false else.
	 * 
	 * @param SimLocationActuator The host to be checked.
	 * @return Boolean
	 * 
	 */
322
	private boolean hostIsAtMeetingPoint(SimLocationActuator host) {
323
324
325
		PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
	
		if(host.getLastLocation().distanceTo(meetingpoint) <= MEETING_POINT_DISTANCE) 			
326
			return true;
327
328
		else
			return false;
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
	}

	/* 
	 * =====================================================================================================
	 * === 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();
345
						
346
347
		// Assign small offset to the host depending on the leaders position.
		PositionVector leaderPos = leader.getRealPosition();
348
		PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE);
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
		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;
	}

Julian Zobel's avatar
wip    
Julian Zobel committed
378
379
380
381
382
383
	public IAttractionAssigmentStrategy getAttractionAssignmentStrategy() {
		return attractionAssigment;
	}
	
	public IGroupFormingBehavior getGroupFormingBehavior() {
		return groupFormingBehavior;
384
385
386
387
388
389
390
391
392
393
	}

	public LocalMovementStrategy getMovementStrategy() {
		return localMovementStrategy;
	}
	
	public void setNumberOfSingleHosts(int numberOfSingleHosts) {
		this.numberOfSingleHosts = numberOfSingleHosts;
	}
	
394
	public LinkedHashSet<SimLocationActuator> getSingleHosts(){
395
396
397
		return singleHosts;
	}	

398
	public LinkedHashMap<SimLocationActuator, PositionVector> getCurrentTargets(){
399
400
		return currentTargets;
	}
401
}