RandomInAreaTransitionStrategy.java 5.52 KB
Newer Older
1
2
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;

3
4
5
6
7
8
9
10
11
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

12
13
14
15
16
17
18
19
20
21
22
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;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;

/**
Clemens Krug's avatar
Clemens Krug committed
23
24
25
26
27
 * This {@link ITransitionStrategy} makes clients move around randomly in a specified area. You can specify the target
 * area center via the {@link #updateTargetAttractionPoint(SimLocationActuator, AttractionPoint)} method. The client will then start
 * to roam the area randomly till a new target area is assigned.
 *
 * @author Clemens Krug
28
 */
Clemens Krug's avatar
Clemens Krug committed
29
30


31
32
public class RandomInAreaTransitionStrategy implements ITransitionStrategy
{
33
34
	private final Random random = Randoms
			.getRandom(RandomInAreaTransitionStrategy.class);
35
36
37

    private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();

Clemens Krug's avatar
Clemens Krug committed
38
39
40
    /**
     * These are the target area centers the clients have assigned.
     */
41
    private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
Clemens Krug's avatar
Clemens Krug committed
42
43
44
45

    /**
     * These are the current spots inside the target area where the client is currently heading.
     */
46
    private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();
Clemens Krug's avatar
Clemens Krug committed
47
    private Map<SimLocationActuator, Integer> currentSearchRadius = new HashMap<>();
48
49
50

    private List<AttractionAssignmentListener> listeners = new LinkedList<>();

Clemens Krug's avatar
Clemens Krug committed
51
52
53
    /**
     * The radius the target area should have. Should be set via XML config file.
     */
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    private int defaultRadius;

    @Override
    public AttractionPoint getAssignment(SimLocationActuator comp)
    {
        return currentTarget.get(comp);
    }

    @Override
    public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
    {
        listeners.add(listener);
    }

    @Override
    public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
    {
        listeners.remove(listener);
    }

    @Override
    public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
        aPoints.addAll(attractionPoints);
    }

    @Override
    public Set<AttractionPoint> getAllAttractionPoints() {
        return aPoints;
    }

    @Override
    public void addComponent(SimLocationActuator ms) {
Clemens Krug's avatar
Clemens Krug committed
86

87
88
89
90
91
        if(!assignments.containsKey(ms))
        {
            AttractionPoint aPoint = aPoints.iterator().next();
            assignments.put(ms, aPoint);
            currentTarget.put(ms, nextRandomPosition(aPoint, defaultRadius));
Clemens Krug's avatar
Clemens Krug committed
92
            currentSearchRadius.put(ms, defaultRadius);
93
94
95
96
97
98
        }
        listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
    }

    @Override
    public void reachedAttractionPoint(SimLocationActuator ms) {
Clemens Krug's avatar
Clemens Krug committed
99
        currentTarget.put(ms, nextRandomPosition(assignments.get(ms), currentSearchRadius.get(ms)));
100
101
102
103
104
105
        listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
    }

    @Override
    public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
        assignments.put(comp, attractionPoint);
Clemens Krug's avatar
Clemens Krug committed
106
        currentTarget.put(comp, nextRandomPosition(attractionPoint, currentSearchRadius.get(comp)));
107
108
109
        listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
    }

Clemens Krug's avatar
Clemens Krug committed
110
111
112
113
114
    public void setSearchRadiusForComponent(SimLocationActuator ms, int radius)
    {
        currentSearchRadius.put(ms, radius);
    }

115
116
117
118
119
    public void setDefaultRadius(int radius)
    {
        this.defaultRadius = radius;
    }

120
121
122
123
124
125
    /**
     * Calculates a random point within a given circular area.
     * @param center The center of the area.
     * @param radius The radius of the area.
     * @return A random position within the area.
     */
126
127
    private BasicAttractionPoint nextRandomPosition(Location center, int radius)
    {
Clemens Krug's avatar
Clemens Krug committed
128
        assert radius > 0 : "An area radius must be specified for the RandomInAreaTransitionStrategy! Did you set the 'DefaultRadius' property for this transition?";
Clemens Krug's avatar
Clemens Krug committed
129

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
        double x = center.getLongitude();
        double y = center.getLatitude();

        double newX = -1;
        double newY = -1;

        int tries = 0;

        while(newX < 0.0 || newX > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX()
                || newY < 0.0 || newY > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY())
        {
            double calcRadius = random.nextDouble() * radius;
            double calcAngle = random.nextDouble() * 360;

            newX = x + Math.sin(calcAngle) * calcRadius;
            newY = y + Math.cos(calcAngle) * calcRadius;
            tries++;

            if(tries > 100) throw new AssertionError("Unable to find a valid target destination within <100 tries.");
        }

        Monitor.log(this.getClass(), Monitor.Level.DEBUG, "Next random position is " + newX + " / " + newY);

        return new BasicAttractionPoint("RNDPOS", new PositionVector(newX, newY));

    }
}