AbstractMovementModel.java 6.76 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
/*
 * Copyright (c) 2005-2011 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;

import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;

27
import de.tud.kom.p2psim.api.topology.Topology;
28
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
29
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
30
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
31
import de.tud.kom.p2psim.impl.topology.PositionVector;
32
import de.tud.kom.p2psim.impl.topology.TopologyFactory;
33
import de.tudarmstadt.maki.simonstrator.api.Binder;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;

/**
 * Unified movement Models. Can be used inside an Application (virtual Position)
 * or Device (physical Position) or anything else that implements
 * MovementSupported. They support automatic triggering using an Operation or
 * you may trigger them directly from within your Application by calling move()
 * 
 * @author Bjoern Richerzhagen
 * @version 1.0, 04/25/2011
 */
public abstract class AbstractMovementModel implements MovementModel {

50
	private Set<SimLocationActuator> components = new LinkedHashSet<SimLocationActuator>();
51
52
53
54
55
56
57

	protected PositionVector worldDimensions;

	private long timeBetweenMoveOperations = -1;

	private Random random = Randoms.getRandom(AbstractMovementModel.class);

58
59
60
61
62
63
64
65
66
	/**
	 * This default implementation relies on {@link PlacementModel}s to be
	 * configured in the {@link TopologyFactory}
	 */
	@Override
	public void placeComponent(SimLocationActuator actuator) {
		// not supported
	}

67
68
69
70
71
72
73
74
75
76
77
	/**
	 * Gets called periodically (after timeBetweenMoveOperations) or by an
	 * application and should be used to recalculate positions
	 */
	public abstract void move();

	/**
	 * Get all participating Components
	 * 
	 * @return
	 */
78
	protected Set<SimLocationActuator> getComponents() {
79
80
81
82
83
84
85
86
87
88
89
		return components;
	}

	/**
	 * Add a component to this movement-Model (used to keep global information
	 * about all participants in a movement model). Each Component acts as a
	 * callback upon movement of this component
	 * 
	 * @param component
	 */
	@Override
90
	public void addComponent(SimLocationActuator component) {
91
		if (worldDimensions == null) {
92
			worldDimensions = Binder.getComponentOrNull(Topology.class)
Julian Zobel's avatar
Julian Zobel committed
93
					.getWorldDimensions();			
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
		}
		components.add(component);
	}

	/**
	 * Get a valid delta-Vector (does not cross world-boundaries and does not
	 * exceed moveSpeedLimit)
	 * 
	 * @param oldPosition
	 * @param minSpeed
	 * @param maxSpeed
	 * @return
	 */
	protected PositionVector getRandomDeltaWithinSpeed(
			PositionVector oldPosition, double minSpeed, double maxSpeed) {
109
110
111
		return getRandomDelta(oldPosition,
				minSpeed * getTimeBetweenMoveOperations() / Time.SECOND,
				maxSpeed * getTimeBetweenMoveOperations() / Time.SECOND);
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	}

	/**
	 * Get a valid delta-Vector, where each abs(vector) must not exceed
	 * maxLength
	 * 
	 * @param oldPosition
	 * @param minLength
	 * @param maxLength
	 * @return
	 */
	protected PositionVector getRandomDelta(PositionVector oldPosition,
			double minLength, double maxLength) {
		assert minLength <= maxLength;
		PositionVector delta = null;

		if (oldPosition.getDimensions() == 2) {
			double angle = random.nextDouble() * 2 * Math.PI;
			double length = random.nextDouble() * (maxLength - minLength)
					+ minLength;
			double vectorX = -length * Math.sin(angle);
			double vectorY = length * Math.cos(angle);
			delta = new PositionVector(vectorX, vectorY);
		} else {
			throw new AssertionError(
					"Rotation for R3 and larger are not yet implemented. Feel free to do so ;)");
		}

		assert delta.getLength() >= minLength && delta.getLength() <= maxLength;

		return delta;
	}

	/**
	 * Returns if this is a valid position within the boundaries
	 * 
	 * @return
	 */
	protected boolean isValidPosition(PositionVector vector) {
Julian Zobel's avatar
Julian Zobel committed
151
			
152
		for (int i = 0; i < vector.getDimensions(); i++) {
Julian Zobel's avatar
Julian Zobel committed
153
			
154
155
156
157
158
159
160
161
			if (vector.getEntry(i) > getWorldDimension(i)
					|| vector.getEntry(i) < 0) {
				return false;
			}
		}
		return true;
	}

162
163
164
165
166
167
168
169
	/**
	 * Call this method to finally update the location of the given component.
	 * 
	 * @param actuator
	 * @param newPosition
	 */
	protected void updatePosition(SimLocationActuator actuator,
			PositionVector newPosition) {
170
		actuator.updateCurrentLocation(newPosition);
171
172
	}

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
	/**
	 * Returns a random int between from and to, including both interval ends!
	 * 
	 * @param from
	 * @param to
	 * @return
	 */
	protected int getRandomInt(int from, int to) {
		int intervalSize = Math.abs(to - from);
		return (random.nextInt(intervalSize + 1) + from);
	}

	protected double getRandomDouble(double from, double to) {
		double intervalSize = Math.abs(to - from);
		return (random.nextDouble() * intervalSize + from);
	}

	/**
	 * Move models can periodically calculate new positions and notify
	 * listeners, if a position changed. Here you can specify the interval
	 * between these notifications/calculations. If this is set to zero, there
	 * is no periodical execution, which may be useful if you want to call
	 * move() from within an application.
	 * 
	 * @param timeBetweenMoveOperations
	 */
	public void setTimeBetweenMoveOperations(long timeBetweenMoveOperations) {
		if (timeBetweenMoveOperations > 0) {
			this.timeBetweenMoveOperations = timeBetweenMoveOperations;
			assert timeBetweenMoveOperations > 0;
			reschedule();
		}
	}

	protected void reschedule() {
		Event.scheduleWithDelay(timeBetweenMoveOperations, new PeriodicMove(),
				null, 0);
	}

	/**
	 * The time in Simulation units between move operations
	 * 
	 * @return
	 */
	public long getTimeBetweenMoveOperations() {
		return timeBetweenMoveOperations;
	}

	public double getWorldDimension(int dim) {
		return worldDimensions.getEntry(dim);
	}

	/**
	 * Triggers the periodic move
	 * 
	 * @author Bjoern Richerzhagen
	 * @version 1.0, 20.03.2012
	 */
	protected class PeriodicMove implements EventHandler {

		@Override
		public void eventOccurred(Object content, int type) {
			move();
			reschedule();
		}

	}

}