RandomInAreaTransitionStrategy.java 5.38 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;

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;

import java.util.*;

/**
Clemens Krug's avatar
Clemens Krug committed
16
17
18
19
20
 * 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
21
 */
Clemens Krug's avatar
Clemens Krug committed
22
23


24
25
26
27
28
29
public class RandomInAreaTransitionStrategy implements ITransitionStrategy
{
    private Random random;

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

Clemens Krug's avatar
Clemens Krug committed
30
31
32
    /**
     * These are the target area centers the clients have assigned.
     */
33
    private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
Clemens Krug's avatar
Clemens Krug committed
34
35
36
37

    /**
     * These are the current spots inside the target area where the client is currently heading.
     */
38
    private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();
Clemens Krug's avatar
Clemens Krug committed
39
    private Map<SimLocationActuator, Integer> currentSearchRadius = new HashMap<>();
40
41
42

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

Clemens Krug's avatar
Clemens Krug committed
43
44
45
    /**
     * The radius the target area should have. Should be set via XML config file.
     */
46
47
48
49
50
51
52
53
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
    private int defaultRadius;

    public RandomInAreaTransitionStrategy()
    {
        random = Randoms.getRandom(this.getClass());
    }

    @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
83

84
85
86
87
88
        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
89
            currentSearchRadius.put(ms, defaultRadius);
90
91
92
93
94
95
        }
        listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
    }

    @Override
    public void reachedAttractionPoint(SimLocationActuator ms) {
Clemens Krug's avatar
Clemens Krug committed
96
        currentTarget.put(ms, nextRandomPosition(assignments.get(ms), currentSearchRadius.get(ms)));
97
98
99
100
101
102
        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
103
        currentTarget.put(comp, nextRandomPosition(attractionPoint, currentSearchRadius.get(comp)));
104
105
106
        listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
    }

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

112
113
114
115
116
    public void setDefaultRadius(int radius)
    {
        this.defaultRadius = radius;
    }

117
118
119
120
121
122
    /**
     * 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.
     */
123
124
    private BasicAttractionPoint nextRandomPosition(Location center, int radius)
    {
Clemens Krug's avatar
Clemens Krug committed
125
        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
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
151
152
153
        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));

    }
}