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
        double x = center.getLongitudeOrX();
        double y = center.getLatitudeOrY();
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 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));

    }
}