ModularMultiTypeMovementModel.java 11 KB
Newer Older
1
2
3
4
5
package de.tud.kom.p2psim.impl.topology.movement.modularosm;

import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
6
import de.tud.kom.p2psim.impl.topology.movement.local.RouteImpl;
7
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
8
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
9
10
import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.Binder;
11
import de.tudarmstadt.maki.simonstrator.api.Monitor;
Clemens Krug's avatar
Clemens Krug committed
12
import de.tudarmstadt.maki.simonstrator.api.NodeDebugMonitor;
13
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
14
15

import java.util.HashMap;
Clemens Krug's avatar
Clemens Krug committed
16
import java.util.LinkedList;
Clemens Krug's avatar
Clemens Krug committed
17
import java.util.List;
18
19

/**
20
 * This class is meant to be used with the RealWorldStreetsMovement
21
22
 * and allows changes of the movement type and the used {@link ITransitionStrategy} mid-simulation
 * on a per-host basis. It acts like the {@link ModularMovementModel}, but each of the {@link SimLocationActuator}s
Clemens Krug's avatar
Clemens Krug committed
23
 * can have a different movement type and {@link ITransitionStrategy}. All routes and targets will be
24
 * calculated accordingly. <BR><BR>
25
 *
Clemens Krug's avatar
Clemens Krug committed
26
27
28
 * Originally the whole movement system within the simonstrator platform was not intended to be manipulable
 * by an application since only overlays were implemented which in a real world would reside on handheld devices
 * for example and should therefore not be able to manipulate the movement of the node/user.
Clemens Krug's avatar
Clemens Krug committed
29
 * But demand changed and for some systems it is inevitable to be able to control/influence the movement. Therefore
Clemens Krug's avatar
Clemens Krug committed
30
31
 * this class was created to fill the gap and provide access to the movement from outside the internal system.
 *
32
 * USAGE:
Clemens Krug's avatar
Clemens Krug committed
33
34
35
36
 * So, since the movement of a person in real life could not be controlled by anyone but the person itself,
 * the access to this class is only provided from the simrunner project since it is responsible for the simulation
 * of the "real-life" parts of the simonstrator platform. From within this project you have access to the
 * {@link de.tud.kom.p2psim.impl.topology.DefaultTopologyComponent} from where you can access this movement model.
37
 * If you want to use different movement types, all you have to do is
Clemens Krug's avatar
Clemens Krug committed
38
 * (besides selecting this model in your config) call the {@link #setMovementType(SimLocationActuator, String)}
39
40
41
42
43
44
45
 * for each of your components.<BR>
 *
 * The used {@link ITransitionStrategy} can be changed on runtime, too. However, the first
 * TransitionStrategy specified in the config will be used as default, and will be applied if there is
 * no further strategy specified for a specific host. To use multiple strategies, add them to your
 * config just as the first one. To set a specific strategy for a specific host, call the {@link #setTransitionForComponent(SimLocationActuator, Class)}
 * with the second parameter being the class of the transition strategy you want to use.
46
47
48
49
50
51
52
 *
 * NOTE: All the movement types you are using need to be specified in you config for the
 * {@link RealWorldStreetsMovement}. E.g if you are using 'car' and 'foot' movement types,
 * in you config the MovementType for the {@link RealWorldStreetsMovement} should be specified as 'car,foot'.
 * If not done properly there won't be an error, but the movement behaviour will be strange.
 *
 * @author Clemens Krug
53
54
55
56
 */
public class ModularMultiTypeMovementModel extends ModularMovementModel
{
    private HashMap<SimLocationActuator, String> movementTypes;
57
58
    private HashMap<SimLocationActuator, ITransitionStrategy> transitions;
    private HashMap<Class, ITransitionStrategy> supportedTransitions;
Clemens Krug's avatar
Clemens Krug committed
59
60
61
62
63
    private LinkedList<MultiTypeMovementListener> movementListeners = new LinkedList<>();

    /**
     * Suppresses notifications to {@link de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.AttractionAssignmentListener}s.
     */
64
    private boolean suppressListenerNotify = false;
65
66
67
68
69

    public ModularMultiTypeMovementModel()
    {
        super();
        movementTypes = new HashMap<>();
70
71
        transitions = new HashMap<>();
        supportedTransitions = new HashMap<>();
72
73
    }

74
75
76
77
78
    @Override
    public void initialize()
    {
        super.initialize();

79
        suppressListenerNotify = true;
80
81
82
83
84
85
86
87
        for(ITransitionStrategy strategy : supportedTransitions.values())
        {
            strategy.setAttractionPoints(transition.getAllAttractionPoints());
            strategy.addAttractionAssignmentListener(this);
            for (SimLocationActuator ms : moveableHosts) {
                strategy.addComponent(ms);
            }
        }
88
        suppressListenerNotify = false;
89
    }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

    @Override
    protected void doLocalMovement(SimLocationActuator ms, PositionVector destination)
    {
        assert localMovementStrategy instanceof RealWorldStreetsMovement: "ModularMultiTypeMovementModel can only be used with RealWorldStreetsMovement!";

        Either<PositionVector, Boolean> either;
        if(movementTypes.containsKey(ms)) either =  ((RealWorldStreetsMovement) localMovementStrategy).nextPosition(ms, destination, movementTypes.get(ms));
        else either = localMovementStrategy.nextPosition(ms, destination);

        if (either.hasLeft()) {
            ms.updateCurrentLocation(either.getLeft());
			/*
			 * Check for negative or out of bound coordinates!
			 */
            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();
        } else {
114
115
116
117
118
119
            if(transitions.containsKey(ms)) {
            	transitions.get(ms).reachedAttractionPoint(ms);
            }
            else {
            	transition.reachedAttractionPoint(ms);
            }
Clemens Krug's avatar
Clemens Krug committed
120
            movementListeners.forEach(l -> l.onTransition(ms));
121
122
123
        }
    }

124
125
126
127
128
129
    /**
     * Sets the movement type for the specified {@link SimLocationActuator}. Movement types can be for example
     * 'car' or 'foot'. Used types need to be specified in the config at the {@link RealWorldStreetsMovement}.
     * @param ms The SimLocationActuator
     * @param movementType the movement type
     */
130
131
132
133
    public void setMovementType(SimLocationActuator ms, String movementType)
    {
        movementTypes.put(ms, movementType);
    }
134

135
136
137
138
139
    /**
     * Returns the current movement type for this {@link SimLocationActuator} as String.
     * @param ms The SimLocationActuator
     * @return the current movement type
     */
140
141
142
143
    public String getMovementType(SimLocationActuator ms)
    {
        return movementTypes.get(ms);
    }
144

145
    /**
Clemens Krug's avatar
Clemens Krug committed
146
147
148
     * Return the currently used transitions strategy of the specified component
     * @param ms the component
     * @return the current transition strategy
149
     */
Clemens Krug's avatar
Clemens Krug committed
150
151
152
153
154
155
156
157
158
159
160
    public ITransitionStrategy getTransitionForComponent(SimLocationActuator ms)
    {
        return transitions.get(ms);
    }

    /**
     * Gets one of the supported transition strategies.
     * @param strategy The class of the strategy which should be returned.
     * @return The specified strategy
     */
    public ITransitionStrategy getTransitionStrategy(Class strategy)
161
162
163
164
165
166
167
168
    {
        ITransitionStrategy selectedStrategy = supportedTransitions.get(strategy);
        if(selectedStrategy == null)
        {
            throw new UnsupportedOperationException(
                    String.format("ModularMultiTypeMovementModel: TransitionStrategy %s ist not supported!", strategy.toString()));
        }

Clemens Krug's avatar
Clemens Krug committed
169
170
171
172
173
174
175
176
177
178
179
180
        return selectedStrategy;
    }

    /**
     * Sets the {@link ITransitionStrategy} for the specified {@link SimLocationActuator}. Used strategies
     * need to be registered in the config.
     * @param ms The SimLocationActuator
     * @param strategy the strategy to use
     */
    public void setTransitionForComponent(SimLocationActuator ms, Class strategy)
    {
        changeTransitionStrategy(ms, getTransitionStrategy(strategy));
181
182
    }

183
184
185
186
187
    /**
     * Changes the transition strategy of the specified {@link SimLocationActuator}.
     * @param ms The SimLocationActuator
     * @param newStrategy the new strategy to use
     */
188
189
190
191
192
193
194
195
    private void changeTransitionStrategy(SimLocationActuator ms, ITransitionStrategy newStrategy)
    {
        ITransitionStrategy usedStrategy = transitions.containsKey(ms) ? transitions.get(ms) : transition;
        newStrategy.updateTargetAttractionPoint(ms, usedStrategy.getAssignment(ms));
        transitions.put(ms, newStrategy);
        Monitor.log(ModularMultiTypeMovementModel.class, Monitor.Level.DEBUG, String.format("Client %s changed his transition strategy from %s to %s", ms.getHost().getId().toString(), usedStrategy.getClass(), newStrategy.getClass()));
    }

Clemens Krug's avatar
Clemens Krug committed
196
197
198
199
200
201
202
203
204
205
206
    /**
     * Returns a list of points representing the current route of the component. Points are
     * in x / y values of the own world.
     * @param ms the component
     * @return list of movement points.
     */
    public List<PositionVector> getMovementPoints(SimLocationActuator ms)
    {
        return ((RealWorldStreetsMovement) localMovementStrategy).getMovementPoints(ms);
    }

207
208
209
210
211
    public RealWorldStreetsMovement getMovementStrategy()
    {
        return (RealWorldStreetsMovement) localMovementStrategy;
    }

212
213
214
215
    /**
     * Sets the default {@link ITransitionStrategy} for the specified {@link SimLocationActuator}.
     * @param ms The SimLocationActuator
     */
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    public void returnToDefaultTransition(SimLocationActuator ms)
    {
        transitions.remove(ms);
    }

    @Override
    public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
        if(transitions.containsKey(actuator)) transitions.get(actuator).updateTargetAttractionPoint(actuator, ap);
        else transition.updateTargetAttractionPoint(actuator, ap);
    }

    @Override
    public void setITransitionStrategy(ITransitionStrategy transition) {
        if(supportedTransitions.size() == 0) this.transition = transition;
        supportedTransitions.put(transition.getClass(), transition);
    }

    @Override
    public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
        if(transitions.containsKey(actuator)) return transitions.get(actuator).getAssignment(actuator);
        else return transition.getAssignment(actuator);
    }
238
239
240
241
242
243
244

    @Override
    public void updatedAttractionAssignment(SimLocationActuator component, AttractionPoint newAssignment) {
        //Notifications of listeners get suppressed in setup phase to prevent multiple assignments of destinations.
        if(suppressListenerNotify) return;
        super.updatedAttractionAssignment(component, newAssignment);
    }
Clemens Krug's avatar
Clemens Krug committed
245
246
247
248
249
250
251
252
253
254

    public void addMovementListener(MultiTypeMovementListener listener)
    {
        movementListeners.add(listener);
    }

    public void removeMovementListener(MultiTypeMovementListener listener)
    {
        movementListeners.remove(listener);
    }
255
}