ModularMovementModel.java 12.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
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;
41
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
42
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.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>
64
 * M2: The {@link ITransitionStrategy}! 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
102
103
104
105
106
	protected PositionVector worldDimensions;

	protected ITransitionStrategy transition;

	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) {
139
140
141
			
			System.out.println("init modular movement model");
			
142
143
144
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
Clemens Krug's avatar
Clemens Krug committed
145
			VisualizationInjector.injectComponent(modelVisualisation);
146
147
148
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
149
150
151
152

			checkConfiguration();

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

158
159
160
161
162
			/*
			 * Scale depending on calculation interval, if interval != 1 Second.
			 */
			localMovementStrategy
					.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
163
			
164
			transition.addAttractionAssignmentListener(this);
165
166
167

			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
168
			for (SimLocationActuator ms : moveableHosts) {
169
170
171
172
173
174
175
176
177
178
179
				transition.addComponent(ms);
			}

			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

			// initial move
			move();

			initialized = true;
		}
	}
180

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

190
	@Override
191
192
	public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
		transition.updateTargetAttractionPoint(actuator, ap);
193
	}	
194
		
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
	private void checkConfiguration() {
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
		if (transition == null) {
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
		if (attractionGenerator == null) {
			throw new ConfigurationException(
					"AttractionGenerator is missing in ModularMovementModel!");
		}
	}

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

232
233
234
235
236
		int tries = 0;
		do {
			destination = new PositionVector(attractionCenter);
			// Gaussian with std = 1 --> >99% of nodes
			PositionVector offset = new PositionVector(
237
238
					rand.nextGaussian() * apRadius / 3,
					rand.nextGaussian() * apRadius / 3);
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
			destination.add(offset);
			// Check constraints
			if (destination.getX() < 0.0
					|| destination.getX() > Binder
							.getComponentOrNull(Topology.class)
							.getWorldDimensions().getX() || destination.getY() < 0.0
					|| destination.getY() > Binder
							.getComponentOrNull(Topology.class)
							.getWorldDimensions().getY()) {
				destination = null;
				if (tries > 100) {
					throw new AssertionError("Unable to find a valid target destination within <100 tries.");
				}
			}
			tries++;
		} while (destination == null);
255

256
		currentTargets.put(component, destination);
257
258
259
	}

	protected void move() {
260
		for (SimLocationActuator component : moveableHosts) {
261
262
			assert currentTargets.containsKey(component);
			doLocalMovement(component, currentTargets.get(component));
263
264
265
266
267
268
269
270
271
272
273
274
275
276
		}
		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
	 */
277
278
279
	protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
		Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
		
280
		if (either.hasLeft()) {
281
			ms.updateCurrentLocation(either.getLeft());
282
283
284
			checkBoundaries(ms);
		} 
		else {
285
			transition.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
286
287
288
		}
	}

289
290
291
292
293
294
295
296
297
298
299
300
301
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
338
339
340
341
342
343
344
	/* 
	 * =====================================================================================================
	 * === HELPER FUNCTIONS
	 * =====================================================================================================
	 */
	/**
	 * Notifies the user if a hosts position lies outside of the specified world size.
	 * Enable asserts to get the notification
	 * 
	 * @param SimLocationActuator The host to be checked
	 */
	public void checkBoundaries(SimLocationActuator ms) {
		assert ms.getRealPosition().getX() >= 0.0
				&& ms.getRealPosition().getX() <= Binder
				.getComponentOrNull(Topology.class)
				.getWorldDimensions().getX();
		assert ms.getRealPosition().getY() >= 0.0
				&& ms.getRealPosition().getY() <= Binder
				.getComponentOrNull(Topology.class)
				.getWorldDimensions().getY();
	}

	@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!");
		}
345
346
347
		this.attractionGenerator = attractionGenerator;
	}

348
349
350
351
352
	public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
		if (localMovementStrategy == null) {
			throw new ConfigurationException(
					"LocalMovementStrategy is missing in ModularMovementModel!");
		}
353
354
355
356
		this.localMovementStrategy = localMovementStrategy;
	}

	public void setITransitionStrategy(ITransitionStrategy transition) {
357
358
359
360
		if (transition == null) {
			throw new ConfigurationException(
					"TransitionStrategy is missing in ModularMovementModel!");
		}
361
362
		this.transition = transition;
	}
363

364
365
366
	public void setIMapVisualization(IMapVisualization mapVisualization) {
		this.mapVisualization = mapVisualization;
	}
367

Clemens Krug's avatar
Clemens Krug committed
368
369
370
371
372
373
	public void setModelVisualisation(ModularMovementModelViz modelVis)
	{
		modelVisualisation = modelVis;
        modelVisualisation.setMovementModel(this);
	}

374
	@Override
375
376
	public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
		return transition.getAssignment(actuator);
377
	}
378
	
379
380
381
382
383
	/**
	 * Only for visualization!
	 * 
	 * @return
	 */
384
	public List<AttractionPoint> getAttractionPoints() {
385
		return new Vector<AttractionPoint>(IAttractionGenerator.attractionPoints);
386
	}
387
}