ModularMovementModel.java 12.8 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
194
195
196
197
	private void checkConfiguration() {
		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
233
234
235
		int tries = 0;
		do {
			destination = new PositionVector(attractionCenter);
			// Gaussian with std = 1 --> >99% of nodes
			PositionVector offset = new PositionVector(
236
237
					rand.nextGaussian() * apRadius / 3,
					rand.nextGaussian() * apRadius / 3);
238
239
			destination.add(offset);
			// Check constraints
Julian Zobel's avatar
wip    
Julian Zobel committed
240
			if (!checkBoundaries(destination)) {
241
242
243
244
245
246
247
				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
248
	
249
		currentTargets.put(component, destination);
250
251
252
	}

	protected void move() {
253
		for (SimLocationActuator component : moveableHosts) {
254
255
			assert currentTargets.containsKey(component);
			doLocalMovement(component, currentTargets.get(component));
256
257
258
259
260
261
262
263
264
265
266
267
268
269
		}
		Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
				EVENT_MOVE);
	}

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

284
285
286
287
288
289
290
291
292
293
	/* 
	 * =====================================================================================================
	 * === 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
294
295
296
297
298
299
300
301
	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;
302
303
304
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
	}

	@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!");
		}
338
339
340
		this.attractionGenerator = attractionGenerator;
	}

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

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

357
358
359
	public void setIMapVisualization(IMapVisualization mapVisualization) {
		this.mapVisualization = mapVisualization;
	}
360

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

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