ModularMovementModel.java 13.6 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

	public ModularMovementModel() {
129
130
		this.worldDimensions = Binder.getComponentOrNull(Topology.class)
				.getWorldDimensions();
131
		
132
133
134
135
136
137
138
139
140
		// scheduling initalization!
		Event.scheduleImmediately(this, null, EVENT_INIT);
	}

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

142
		if (!initialized) {
Julian Zobel's avatar
wip    
Julian Zobel committed
143
						
144
145
146
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
Clemens Krug's avatar
Clemens Krug committed
147
			VisualizationInjector.injectComponent(modelVisualisation);
148
149
150
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
151
152
153
154
			if (attractionPointViz != null) {
				System.out.println("insert AP viz");
				VisualizationInjector.injectComponent(attractionPointViz);
			}
155
156
157
158

			checkConfiguration();

			// setWayPointModel
159
160
161
162
			localMovementStrategy.setObstacleModel(Binder
					.getComponentOrNull(Topology.class).getObstacleModel());
			localMovementStrategy.setWaypointModel(Binder
					.getComponentOrNull(Topology.class).getWaypointModel());
163

164
165
166
167
168
			/*
			 * Scale depending on calculation interval, if interval != 1 Second.
			 */
			localMovementStrategy
					.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
169
			
Julian Zobel's avatar
wip    
Julian Zobel committed
170
			attractionAssigment.addAttractionAssignmentListener(this);
171
172
173

			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
174
			for (SimLocationActuator ms : moveableHosts) {
Julian Zobel's avatar
wip    
Julian Zobel committed
175
				attractionAssigment.addComponent(ms);
176
177
178
179
180
181
182
183
			}

			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

			// initial move
			move();

			initialized = true;
184
185
186
			
			// Inform analyzer of resolved movement
			if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {			
187
				Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
188
189
			}
			
190
191
		}
	}
192

193
194
195
196
197
198
199
200
	/**
	 * This default implementation relies on {@link PlacementModel}s to be
	 * configured in the {@link TopologyFactory}
	 */
	@Override
	public void placeComponent(SimLocationActuator actuator) {
		// not supported
	}
201

202
	@Override
203
	public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) {
Julian Zobel's avatar
wip    
Julian Zobel committed
204
		attractionAssigment.updateTargetAttractionPoint(actuator, ap);
205
	}	
206
		
207
	protected void checkConfiguration() {
208
209
210
211
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
212
		if (attractionAssigment == null) {
213
214
215
216
217
218
219
220
221
222
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
		if (attractionGenerator == null) {
			throw new ConfigurationException(
					"AttractionGenerator is missing in ModularMovementModel!");
		}
	}

	@Override
223
	public void addComponent(SimLocationActuator comp) {
224
		moveableHosts.add(comp);
225
226
227
		if (!routeSensorComponents.containsKey(comp)) {
			routeSensorComponents.put(comp, new RouteSensorComponent(comp));
		}
228
	}
229
	
230
231
	@Override
	public void updatedAttractionAssignment(SimLocationActuator component,
232
			IAttractionPoint newAssignment) {
Julian Zobel's avatar
wip    
Julian Zobel committed
233
				
234
235
236
237
238
		/*
		 * Use this method to calculate the offset and target location for a
		 * host.
		 */
		PositionVector attractionCenter = (PositionVector) newAssignment;
239
		PositionVector destination = null;
240
241
242
		/*
		 * Even if an AP does not have a radius, we slightly offset
		 */
Julian Zobel's avatar
wip    
Julian Zobel committed
243
		double apRadius = (newAssignment.hasRadius() ? Math.max(newAssignment.getRadius(), 25.0) : 25.0);
244

245
246
		int tries = 0;
		do {
247
			destination = addGaussianOffsetToPosition(attractionCenter, apRadius / 3);		
248
			// Check constraints
Julian Zobel's avatar
wip    
Julian Zobel committed
249
			if (!checkBoundaries(destination)) {
250
251
252
253
254
255
256
				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
257
	
258
		currentTargets.put(component, destination);
259
260
261
	}

	protected void move() {
262
		for (SimLocationActuator component : moveableHosts) {
263
264
			assert currentTargets.containsKey(component);
			doLocalMovement(component, currentTargets.get(component));
265
		}
266
		
267
268
269
		Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
				EVENT_MOVE);
	}
270
271
272
273
274
275
276
277
	
	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;
	}
278
279
280
281
282
283
284
285
286
287

	/**
	 * 
	 * 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
	 */
288
289
290
	protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
		Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
		
291
		if (either.hasLeft()) {
292
			ms.updateCurrentLocation(either.getLeft());
Julian Zobel's avatar
wip    
Julian Zobel committed
293
294
295
			if(!checkBoundaries(ms.getRealPosition())) {
				System.err.println("Modular Movement Model: Host moved outside of simulated area!");
			}				
296
297
		} 
		else {
Julian Zobel's avatar
wip    
Julian Zobel committed
298
			attractionAssigment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
299
300
301
		}
	}

302
303
304
305
306
307
308
309
310
311
	/* 
	 * =====================================================================================================
	 * === 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
312
313
314
315
316
317
318
319
	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;
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
	}

	@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!");
		}
356
357
358
		this.attractionGenerator = attractionGenerator;
	}

359
360
361
362
363
	public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
364
365
366
		this.localMovementStrategy = localMovementStrategy;
	}

Julian Zobel's avatar
wip    
Julian Zobel committed
367
	public void setITransitionStrategy(IAttractionAssigmentStrategy transition) {
368
369
370
371
		if (transition == null) {
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
372
		this.attractionAssigment = transition;
373
	}
374

375
376
377
	public void setIMapVisualization(IMapVisualization mapVisualization) {
		this.mapVisualization = mapVisualization;
	}
378

Clemens Krug's avatar
Clemens Krug committed
379
380
381
382
383
384
	public void setModelVisualisation(ModularMovementModelViz modelVis)
	{
		modelVisualisation = modelVis;
        modelVisualisation.setMovementModel(this);
	}

385
	@Override
386
	public IAttractionPoint getTargetLocation(SimLocationActuator actuator) {
Julian Zobel's avatar
wip    
Julian Zobel committed
387
		return attractionAssigment.getAssignment(actuator);
388
	}
389
	
390
391
392
393
394
	/**
	 * Only for visualization!
	 * 
	 * @return
	 */
395
396
	public List<IAttractionPoint> getAttractionPoints() {
		return new Vector<IAttractionPoint>(IAttractionGenerator.attractionPoints);
397
	}
398
399
400
401
	
	public void setAttractionPointViz(AttractionPointViz viz) {
		this.attractionPointViz = viz;
	}
402
}