RandomInAreaTransitionStrategy.java 5.08 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
39
40
41
    private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();

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

Clemens Krug's avatar
Clemens Krug committed
42
43
44
    /**
     * The radius the target area should have. Should be set via XML config file.
     */
45
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
    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
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
        if(!assignments.containsKey(ms))
        {
            AttractionPoint aPoint = aPoints.iterator().next();
            assignments.put(ms, aPoint);
            currentTarget.put(ms, nextRandomPosition(aPoint, defaultRadius));
        }
        listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
    }

    @Override
    public void reachedAttractionPoint(SimLocationActuator ms) {
        currentTarget.put(ms, nextRandomPosition(assignments.get(ms), defaultRadius));
        listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
    }

    @Override
    public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
        assignments.put(comp, attractionPoint);
        currentTarget.put(comp, nextRandomPosition(attractionPoint, defaultRadius));
        listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
    }

    public void setDefaultRadius(int radius)
    {
        this.defaultRadius = radius;
    }

110
111
112
113
114
115
    /**
     * 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.
     */
116
117
    private BasicAttractionPoint nextRandomPosition(Location center, int radius)
    {
Clemens Krug's avatar
Clemens Krug committed
118
119
        assert defaultRadius > 0 : "An area radius must be specified for the RandomInAreaTransitionStrategy! Did you set the 'DefaultRadius' property for this transition?";

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
        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));

    }
}