ModularMovementModel.java 14.2 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
23
24
25
26
27
28
29
30
31
/*
 * 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;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Vector;

import de.tud.kom.p2psim.api.scenario.ConfigurationException;
32
import de.tud.kom.p2psim.api.topology.Topology;
33
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
34
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
35
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
36
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
37
import de.tud.kom.p2psim.impl.simengine.Simulator;
38
import de.tud.kom.p2psim.impl.topology.TopologyFactory;
39
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.AttractionPointViz;
40
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
41
import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization;
Julian Zobel's avatar
wip    
Julian Zobel committed
42
43
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy.AttractionAssignmentListener;
44
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
45
46
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.util.Either;
47
import de.tudarmstadt.maki.simonstrator.api.Binder;
48
49
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
50
import de.tudarmstadt.maki.simonstrator.api.Monitor;
51
import de.tudarmstadt.maki.simonstrator.api.Randoms;
52
import de.tudarmstadt.maki.simonstrator.api.Time;
53
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
54
55
56

/**
 * Modular Movement Model uses different models/strategies to create a movement
57
 * model. In this implementation, it has 3 different models/strategies.
58
 * <p>
59
60
 * M0: AttractionGenerator -> Generates the {@link IAttractionPoint}s and place
 * them on the map. The {@link IAttractionPoint}s can't be moved, because they
61
 * are static POIs from real-world data!
62
 * <p>
63
64
 * M1: A general {@link MovementModel} is not used, because we use static
 * attraction points.
65
 * <p>
Julian Zobel's avatar
wip    
Julian Zobel committed
66
 * M2: The {@link IAttractionAssigmentStrategy}! It takes the Hosts, which should be moved
67
 * around, but calculates only the assignment to the {@link IAttractionPoint}s.
68
69
70
71
72
73
74
75
76
 * It doesn't move the Hosts! It will be only assignment a new AttractionPoint!
 * 
 * <p>
 * M3: The {@link LocalMovementStrategy} is responsible for the movement of the
 * Hosts. It moves the hosts to the assigned AttractionPoint, and if the
 * AttractionPoint has moved, then will be followed. The
 * {@link LocalMovementStrategy} will be called from the
 * {@link ModularMovementModel} to do a Movement!
 * <p>
77
 * This class contains all three components and manage the data exchange.
78
79
80
81
82
83
 * Additionally it contains an periodic operation, which handle the movement of
 * all hosts. This mean, that it will be call the {@link LocalMovementStrategy}
 * with the destination. Please take care, that the handling of the movement of
 * the AttractionPoints will be handled by the movement model in M1! <br>
 * Further it contains an offset for every Host, which will be added to the
 * destination point (AttractionPoint), so that not all hosts, which are
84
 * assigned to one {@link IAttractionPoint}, lies on the same point.<br>
85
 * 
Clemens Krug's avatar
Clemens Krug committed
86
87
88
89
90
91
 * CHANGELOG
 *
 * - 04.01.2017 Clemens Krug: Added the possibility to configure the model
 * visualisation via XML. If not specified, the visualisation will use the
 * {@link ModularMovementModelViz}, just as before. Thus there shouldn't be any problems
 * with older code.
92
 * 
93
 * @author Martin Hellwig, Christoph Muenker
94
 * @version 1.0, 07.07.2015
95
 */
96
public class ModularMovementModel implements MovementModel, EventHandler, AttractionAssignmentListener {
97

98
	protected final int EVENT_MOVE = 1;
99

100
	protected final int EVENT_INIT = 2;
101

102
103
	protected PositionVector worldDimensions;

Julian Zobel's avatar
wip    
Julian Zobel committed
104
	protected IAttractionAssigmentStrategy attractionAssigment;
105
106
107
108

	protected IAttractionGenerator attractionGenerator;

	protected LocalMovementStrategy localMovementStrategy;
109

110
	protected IMapVisualization mapVisualization;
111

112
	protected ModularMovementModelViz modelVisualisation;
113
114
	
	protected AttractionPointViz attractionPointViz;
Clemens Krug's avatar
Clemens Krug committed
115

116
	protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
117

118
	protected Map<SimLocationActuator, PositionVector> currentTargets = new LinkedHashMap<>();
119

120
	protected Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
121

122
	protected boolean initialized = false;
123

124
	protected long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
125

126
	protected Random rand = Randoms.getRandom(ModularMovementModel.class);
127

128
129
	protected boolean placeNodesAtAP = false;
	
130
	public ModularMovementModel() {
131
132
		this.worldDimensions = Binder.getComponentOrNull(Topology.class)
				.getWorldDimensions();
133
		
134
135
136
		// scheduling initalization!
		Event.scheduleImmediately(this, null, EVENT_INIT);
	}
137
138
139
140
		
	public void setPlaceNodes(boolean placeNodes) {
		this.placeNodesAtAP = placeNodes;
	}
141
142
143
144
145
146

	/**
	 * This Method will be not called from the Components. So we call this
	 * manually!
	 */
	public void initialize() {
147

148
		if (!initialized) {
Julian Zobel's avatar
wip    
Julian Zobel committed
149
						
150
151
152
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
Clemens Krug's avatar
Clemens Krug committed
153
			VisualizationInjector.injectComponent(modelVisualisation);
154
155
156
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
157
158
159
160
			if (attractionPointViz != null) {
				System.out.println("insert AP viz");
				VisualizationInjector.injectComponent(attractionPointViz);
			}
161
162
163
164

			checkConfiguration();

			// setWayPointModel
165
166
167
168
			localMovementStrategy.setObstacleModel(Binder
					.getComponentOrNull(Topology.class).getObstacleModel());
			localMovementStrategy.setWaypointModel(Binder
					.getComponentOrNull(Topology.class).getWaypointModel());
169

170
171
172
173
174
			/*
			 * Scale depending on calculation interval, if interval != 1 Second.
			 */
			localMovementStrategy
					.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
175
			
Julian Zobel's avatar
wip    
Julian Zobel committed
176
			attractionAssigment.addAttractionAssignmentListener(this);
177
178
179

			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
180
			for (SimLocationActuator ms : moveableHosts) {
Julian Zobel's avatar
wip    
Julian Zobel committed
181
				attractionAssigment.addComponent(ms);
182
183
184
185
186
187
188
189
				
				if(placeNodesAtAP) {
					IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
					double apRadius = (assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0);
					
					ms.updateCurrentLocation(this.addGaussianOffsetToPosition(new PositionVector(assignment), apRadius / 3));	
					attractionAssigment.updateTargetAttractionPoint(ms, assignment);
				}				
190
191
192
193
194
195
196
197
			}

			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

			// initial move
			move();

			initialized = true;
198
199
200
			
			// Inform analyzer of resolved movement
			if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {			
201
				Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
202
203
			}
			
204
205
		}
	}
206

207
208
209
210
211
212
213
214
	/**
	 * This default implementation relies on {@link PlacementModel}s to be
	 * configured in the {@link TopologyFactory}
	 */
	@Override
	public void placeComponent(SimLocationActuator actuator) {
		// not supported
	}
215

216
	@Override
217
	public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) {
Julian Zobel's avatar
wip    
Julian Zobel committed
218
		attractionAssigment.updateTargetAttractionPoint(actuator, ap);
219
	}	
220
		
221
	protected void checkConfiguration() {
222
223
224
225
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
226
		if (attractionAssigment == null) {
227
228
229
230
231
232
233
234
235
236
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
		if (attractionGenerator == null) {
			throw new ConfigurationException(
					"AttractionGenerator is missing in ModularMovementModel!");
		}
	}

	@Override
237
	public void addComponent(SimLocationActuator comp) {
238
		moveableHosts.add(comp);
239
240
241
		if (!routeSensorComponents.containsKey(comp)) {
			routeSensorComponents.put(comp, new RouteSensorComponent(comp));
		}
242
	}
243
	
244
245
	@Override
	public void updatedAttractionAssignment(SimLocationActuator component,
246
			IAttractionPoint newAssignment) {
Julian Zobel's avatar
wip    
Julian Zobel committed
247
				
248
249
250
251
252
		/*
		 * Use this method to calculate the offset and target location for a
		 * host.
		 */
		PositionVector attractionCenter = (PositionVector) newAssignment;
253
		PositionVector destination = null;
254
255
256
		/*
		 * Even if an AP does not have a radius, we slightly offset
		 */
Julian Zobel's avatar
wip    
Julian Zobel committed
257
		double apRadius = (newAssignment.hasRadius() ? Math.max(newAssignment.getRadius(), 25.0) : 25.0);
258

259
260
		int tries = 0;
		do {
261
			destination = addGaussianOffsetToPosition(attractionCenter, apRadius / 3);		
262
			// Check constraints
Julian Zobel's avatar
wip    
Julian Zobel committed
263
			if (!checkBoundaries(destination)) {
264
265
266
267
268
269
270
				destination = null;
				if (tries > 100) {
					throw new AssertionError("Unable to find a valid target destination within <100 tries.");
				}
			}
			tries++;
		} while (destination == null);
Julian Zobel's avatar
wip    
Julian Zobel committed
271
	
272
		currentTargets.put(component, destination);
273
274
275
	}

	protected void move() {
276
		for (SimLocationActuator component : moveableHosts) {
277
278
			assert currentTargets.containsKey(component);
			doLocalMovement(component, currentTargets.get(component));
279
		}
280
		
281
282
283
		Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
				EVENT_MOVE);
	}
284
285
286
287
288
289
290
291
	
	public PositionVector addGaussianOffsetToPosition(PositionVector position, double std) {
		PositionVector offsetPosition = new PositionVector(position);
		// Gaussian with std = 1 --> >99% of nodes
		PositionVector offset = new PositionVector(rand.nextGaussian() * std, rand.nextGaussian() * std);
		offsetPosition.add(offset);
		return offsetPosition;
	}
292
293
294
295
296
297
298
299
300
301

	/**
	 * 
	 * Ask the local movement strategy for the next position. It may return the
	 * next position or a boolean with true to notify the movement model that it
	 * can't get any closer to the current way point.
	 * 
	 * @param ms
	 * @param destination
	 */
302
303
304
	protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
		Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
		
305
		if (either.hasLeft()) {
306
			ms.updateCurrentLocation(either.getLeft());
Julian Zobel's avatar
wip    
Julian Zobel committed
307
308
309
			if(!checkBoundaries(ms.getRealPosition())) {
				System.err.println("Modular Movement Model: Host moved outside of simulated area!");
			}				
310
311
		} 
		else {
Julian Zobel's avatar
wip    
Julian Zobel committed
312
			attractionAssigment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
313
314
315
		}
	}

316
317
318
319
320
321
322
323
324
325
	/* 
	 * =====================================================================================================
	 * === HELPER FUNCTIONS
	 * =====================================================================================================
	 */
	/**
	 * Notifies the user if a hosts position lies outside of the specified world size.
	 * Enable asserts to get the notification
	 * 
	 */
Julian Zobel's avatar
wip    
Julian Zobel committed
326
327
328
329
330
331
332
333
	public boolean checkBoundaries(PositionVector position) {		
		if(position.getX() >= 0.0 
				&& position.getX() <= Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX() 
				&& position.getY() >= 0.0 
				&& position.getY() <= Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY())
			return true;
		else
			return false;
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
	}

	@Override
	public void eventOccurred(Object content, int type) {
		if (type == EVENT_INIT) {
			initialize();
		} else if (type == EVENT_MOVE) {
			move();
		}
	}
	
	/* 
	 * =====================================================================================================
	 * === GETTER AND SETTER FUNCTIONS
	 * =====================================================================================================
	 */
	public Set<SimLocationActuator> getAllLocationActuators() {
		return moveableHosts;
	}

	@Override
	public void setTimeBetweenMoveOperations(long time) {
		if (time > 0) {
			this.timeBetweenMoveOperation = time;
		} else {
			throw new ConfigurationException(
					"time is negative for the Move Operations");
		}
	}

	
	public void setIAttractionGenerator(IAttractionGenerator attractionGenerator) {
		if (attractionGenerator == null) {
			throw new ConfigurationException(
					"AttractionGenerator is missing in ModularMovementModel!");
		}
370
371
372
		this.attractionGenerator = attractionGenerator;
	}

373
374
375
376
377
	public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
378
379
380
		this.localMovementStrategy = localMovementStrategy;
	}

Julian Zobel's avatar
wip    
Julian Zobel committed
381
	public void setITransitionStrategy(IAttractionAssigmentStrategy transition) {
382
383
384
385
		if (transition == null) {
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
386
		this.attractionAssigment = transition;
387
	}
388

389
390
391
	public void setIMapVisualization(IMapVisualization mapVisualization) {
		this.mapVisualization = mapVisualization;
	}
392

Clemens Krug's avatar
Clemens Krug committed
393
394
395
396
397
398
	public void setModelVisualisation(ModularMovementModelViz modelVis)
	{
		modelVisualisation = modelVis;
        modelVisualisation.setMovementModel(this);
	}

399
	@Override
400
	public IAttractionPoint getTargetLocation(SimLocationActuator actuator) {
Julian Zobel's avatar
wip    
Julian Zobel committed
401
		return attractionAssigment.getAssignment(actuator);
402
	}
403
	
404
405
406
407
408
	/**
	 * Only for visualization!
	 * 
	 * @return
	 */
409
410
	public List<IAttractionPoint> getAttractionPoints() {
		return new Vector<IAttractionPoint>(IAttractionGenerator.attractionPoints);
411
	}
412
413
414
415
	
	public void setAttractionPointViz(AttractionPointViz viz) {
		this.attractionPointViz = viz;
	}
416
}