ModularMovementModel.java 13 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.IAttractionGenerator;
40
import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization;
Julian Zobel's avatar
wip    
Julian Zobel committed
41
42
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy.AttractionAssignmentListener;
43
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
44
45
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.util.Either;
46
import de.tudarmstadt.maki.simonstrator.api.Binder;
47
48
49
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
50
import de.tudarmstadt.maki.simonstrator.api.Time;
51
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
52
53
54

/**
 * Modular Movement Model uses different models/strategies to create a movement
55
 * model. In this implementation, it has 3 different models/strategies.
56
57
 * <p>
 * M0: AttractionGenerator -> Generates the {@link AttractionPoint}s and place
58
59
 * them on the map. The {@link AttractionPoint}s can't be moved, because they
 * are static POIs from real-world data!
60
 * <p>
61
62
 * M1: A general {@link MovementModel} is not used, because we use static
 * attraction points.
63
 * <p>
Julian Zobel's avatar
wip    
Julian Zobel committed
64
 * M2: The {@link IAttractionAssigmentStrategy}! It takes the Hosts, which should be moved
65
66
67
68
69
70
71
72
73
74
 * around, but calculates only the assignment to the {@link AttractionPoint}s.
 * 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>
75
 * This class contains all three components and manage the data exchange.
76
77
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
 * assigned to one {@link AttractionPoint}, lies on the same point.<br>
 * 
Clemens Krug's avatar
Clemens Krug committed
84
85
86
87
88
89
 * 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.
90
 * 
91
 * @author Martin Hellwig, Christoph Muenker
92
 * @version 1.0, 07.07.2015
93
 */
94
public class ModularMovementModel implements MovementModel, EventHandler, AttractionAssignmentListener {
95

96
	protected final int EVENT_MOVE = 1;
97

98
	protected final int EVENT_INIT = 2;
99

100
101
	protected PositionVector worldDimensions;

Julian Zobel's avatar
wip    
Julian Zobel committed
102
	protected IAttractionAssigmentStrategy attractionAssigment;
103
104
105
106

	protected IAttractionGenerator attractionGenerator;

	protected LocalMovementStrategy localMovementStrategy;
107

108
	protected IMapVisualization mapVisualization;
109

110
	protected ModularMovementModelViz modelVisualisation;
Clemens Krug's avatar
Clemens Krug committed
111

112
	protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
113

114
	protected Map<SimLocationActuator, PositionVector> currentTargets = new LinkedHashMap<>();
115

116
	protected Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
117

118
	protected boolean initialized = false;
119

120
	protected long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
121

122
	protected Random rand = Randoms.getRandom(ModularMovementModel.class);
123
124

	public ModularMovementModel() {
125
126
		this.worldDimensions = Binder.getComponentOrNull(Topology.class)
				.getWorldDimensions();
127
		
128
129
130
131
132
133
134
135
136
		// 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() {
137

138
		if (!initialized) {
Julian Zobel's avatar
wip    
Julian Zobel committed
139
						
140
141
142
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
Clemens Krug's avatar
Clemens Krug committed
143
			VisualizationInjector.injectComponent(modelVisualisation);
144
145
146
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
147
148
149
150

			checkConfiguration();

			// setWayPointModel
151
152
153
154
			localMovementStrategy.setObstacleModel(Binder
					.getComponentOrNull(Topology.class).getObstacleModel());
			localMovementStrategy.setWaypointModel(Binder
					.getComponentOrNull(Topology.class).getWaypointModel());
155

156
157
158
159
160
			/*
			 * Scale depending on calculation interval, if interval != 1 Second.
			 */
			localMovementStrategy
					.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
161
			
Julian Zobel's avatar
wip    
Julian Zobel committed
162
			attractionAssigment.addAttractionAssignmentListener(this);
163
164
165

			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
166
			for (SimLocationActuator ms : moveableHosts) {
Julian Zobel's avatar
wip    
Julian Zobel committed
167
				attractionAssigment.addComponent(ms);
168
169
170
171
172
173
174
175
176
177
			}

			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

			// initial move
			move();

			initialized = true;
		}
	}
178

179
180
181
182
183
184
185
186
	/**
	 * This default implementation relies on {@link PlacementModel}s to be
	 * configured in the {@link TopologyFactory}
	 */
	@Override
	public void placeComponent(SimLocationActuator actuator) {
		// not supported
	}
187

188
	@Override
189
	public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
Julian Zobel's avatar
wip    
Julian Zobel committed
190
		attractionAssigment.updateTargetAttractionPoint(actuator, ap);
191
	}	
192
		
193
	protected void checkConfiguration() {
194
195
196
197
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
198
		if (attractionAssigment == null) {
199
200
201
202
203
204
205
206
207
208
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
		if (attractionGenerator == null) {
			throw new ConfigurationException(
					"AttractionGenerator is missing in ModularMovementModel!");
		}
	}

	@Override
209
	public void addComponent(SimLocationActuator comp) {
210
		moveableHosts.add(comp);
211
212
213
		if (!routeSensorComponents.containsKey(comp)) {
			routeSensorComponents.put(comp, new RouteSensorComponent(comp));
		}
214
	}
215
	
216
217
218
	@Override
	public void updatedAttractionAssignment(SimLocationActuator component,
			AttractionPoint newAssignment) {
Julian Zobel's avatar
wip    
Julian Zobel committed
219
				
220
221
222
223
224
		/*
		 * Use this method to calculate the offset and target location for a
		 * host.
		 */
		PositionVector attractionCenter = (PositionVector) newAssignment;
225
		PositionVector destination = null;
226
227
228
		/*
		 * Even if an AP does not have a radius, we slightly offset
		 */
Julian Zobel's avatar
wip    
Julian Zobel committed
229
		double apRadius = (newAssignment.hasRadius() ? Math.max(newAssignment.getRadius(), 25.0) : 25.0);
230

231
232
		int tries = 0;
		do {
233
			destination = addGaussianOffsetToPosition(attractionCenter, apRadius / 3);		
234
			// Check constraints
Julian Zobel's avatar
wip    
Julian Zobel committed
235
			if (!checkBoundaries(destination)) {
236
237
238
239
240
241
242
				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
243
	
244
		currentTargets.put(component, destination);
245
246
247
	}

	protected void move() {
248
		for (SimLocationActuator component : moveableHosts) {
249
250
			assert currentTargets.containsKey(component);
			doLocalMovement(component, currentTargets.get(component));
251
252
253
254
		}
		Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
				EVENT_MOVE);
	}
255
256
257
258
259
260
261
262
	
	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;
	}
263
264
265
266
267
268
269
270
271
272

	/**
	 * 
	 * 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
	 */
273
274
275
	protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
		Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
		
276
		if (either.hasLeft()) {
277
			ms.updateCurrentLocation(either.getLeft());
Julian Zobel's avatar
wip    
Julian Zobel committed
278
279
280
			if(!checkBoundaries(ms.getRealPosition())) {
				System.err.println("Modular Movement Model: Host moved outside of simulated area!");
			}				
281
282
		} 
		else {
Julian Zobel's avatar
wip    
Julian Zobel committed
283
			attractionAssigment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
284
285
286
		}
	}

287
288
289
290
291
292
293
294
295
296
	/* 
	 * =====================================================================================================
	 * === 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
297
298
299
300
301
302
303
304
	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;
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
	}

	@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!");
		}
341
342
343
		this.attractionGenerator = attractionGenerator;
	}

344
345
346
347
348
	public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
349
350
351
		this.localMovementStrategy = localMovementStrategy;
	}

Julian Zobel's avatar
wip    
Julian Zobel committed
352
	public void setITransitionStrategy(IAttractionAssigmentStrategy transition) {
353
354
355
356
		if (transition == null) {
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
357
		this.attractionAssigment = transition;
358
	}
359

360
361
362
	public void setIMapVisualization(IMapVisualization mapVisualization) {
		this.mapVisualization = mapVisualization;
	}
363

Clemens Krug's avatar
Clemens Krug committed
364
365
366
367
368
369
	public void setModelVisualisation(ModularMovementModelViz modelVis)
	{
		modelVisualisation = modelVis;
        modelVisualisation.setMovementModel(this);
	}

370
	@Override
371
	public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
Julian Zobel's avatar
wip    
Julian Zobel committed
372
		return attractionAssigment.getAssignment(actuator);
373
	}
374
	
375
376
377
378
379
	/**
	 * Only for visualization!
	 * 
	 * @return
	 */
380
	public List<AttractionPoint> getAttractionPoints() {
381
		return new Vector<AttractionPoint>(IAttractionGenerator.attractionPoints);
382
	}
383
}