A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
random-walk-2d-outdoor-mobility-model.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006,2007 INRIA
3 * Copyright (c) 2019 University of Padova
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19 * Author: Michele Polese <michele.polese@gmail.com>
20 */
22
23#include "ns3/building-list.h"
24#include "ns3/building.h"
25#include "ns3/double.h"
26#include "ns3/enum.h"
27#include "ns3/log.h"
28#include "ns3/pointer.h"
29#include "ns3/simulator.h"
30#include "ns3/string.h"
31#include "ns3/uinteger.h"
32
33#include <cmath>
34
35namespace ns3
36{
37
38NS_LOG_COMPONENT_DEFINE("RandomWalk2dOutdoor");
39
40NS_OBJECT_ENSURE_REGISTERED(RandomWalk2dOutdoorMobilityModel);
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::RandomWalk2dOutdoorMobilityModel")
48 .SetGroupName("Mobility")
49 .AddConstructor<RandomWalk2dOutdoorMobilityModel>()
50 .AddAttribute("Bounds",
51 "Bounds of the area to cruise.",
52 RectangleValue(Rectangle(0.0, 100.0, 0.0, 100.0)),
53 MakeRectangleAccessor(&RandomWalk2dOutdoorMobilityModel::m_bounds),
54 MakeRectangleChecker())
55 .AddAttribute("Time",
56 "Change current direction and speed after moving for this delay.",
57 TimeValue(Seconds(20.0)),
60 .AddAttribute("Distance",
61 "Change current direction and speed after moving for this distance.",
62 DoubleValue(30.0),
64 MakeDoubleChecker<double>())
65 .AddAttribute("Mode",
66 "The mode indicates the condition used to "
67 "change the current speed and direction",
71 "Distance",
73 "Time"))
74 .AddAttribute("Direction",
75 "A random variable used to pick the direction (radians).",
76 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=6.283184]"),
78 MakePointerChecker<RandomVariableStream>())
79 .AddAttribute(
80 "Speed",
81 "A random variable used to pick the speed (m/s)."
82 "The default value is taken from Figure 1 of the paper"
83 "Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.",
84 StringValue("ns3::NormalRandomVariable[Mean=1.53|Variance=0.040401]"),
86 MakePointerChecker<RandomVariableStream>())
87 .AddAttribute("Tolerance",
88 "Tolerance for the intersection point with buildings (m)."
89 "It represents a small distance from where the building limit"
90 "is actually placed, for example to represent a sidewalk.",
91 DoubleValue(1e-6),
93 MakeDoubleChecker<double>())
94 .AddAttribute("MaxIterations",
95 "Maximum number of attempts to find an alternative next position"
96 "if the original one is inside a building.",
97 UintegerValue(100),
99 MakeUintegerChecker<uint32_t>());
100 return tid;
101}
102
103void
105{
108}
109
110void
112{
114 double speed = m_speed->GetValue();
115 double direction = m_direction->GetValue();
116 Vector vector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
117 m_helper.SetVelocity(vector);
119
120 Time delayLeft;
122 {
123 delayLeft = m_modeTime;
124 }
125 else
126 {
127 delayLeft = Seconds(m_modeDistance / speed);
128 }
129 DoWalk(delayLeft);
130}
131
132void
134{
135 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
136
137 Vector position = m_helper.GetCurrentPosition();
138 Vector speed = m_helper.GetVelocity();
139 Vector nextPosition = position;
140 nextPosition.x += speed.x * delayLeft.GetSeconds();
141 nextPosition.y += speed.y * delayLeft.GetSeconds();
142 m_event.Cancel();
143
144 // check if the nextPosition is inside a building, or if the line
145 // from position to the next position intersects a building
146 auto outdoorBuilding = IsLineClearOfBuildings(position, nextPosition);
147 bool outdoor = std::get<0>(outdoorBuilding);
148 Ptr<Building> building = std::get<1>(outdoorBuilding);
149
150 if (m_bounds.IsInside(nextPosition))
151 {
152 if (outdoor)
153 {
154 m_event = Simulator::Schedule(delayLeft,
156 this);
157 }
158 else
159 {
160 NS_LOG_LOGIC("NextPosition would lead into a building");
161 nextPosition =
162 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
163 Time delay = Seconds((nextPosition.x - position.x) / speed.x);
166 this,
167 delayLeft - delay,
168 nextPosition);
169 }
170 }
171 else
172 {
173 NS_LOG_LOGIC("Out of bounding box");
174 nextPosition = m_bounds.CalculateIntersection(position, speed);
175 // check that this nextPosition is outdoor
176 auto outdoorBuilding = IsLineClearOfBuildings(position, nextPosition);
177 bool outdoor = std::get<0>(outdoorBuilding);
178 Ptr<Building> building = std::get<1>(outdoorBuilding);
179
180 if (outdoor)
181 {
182 Time delay = Seconds((nextPosition.x - position.x) / speed.x);
185 this,
186 delayLeft - delay);
187 }
188 else
189 {
190 NS_LOG_LOGIC("NextPosition would lead into a building");
191 nextPosition =
192 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
193 Time delay = Seconds((nextPosition.x - position.x) / speed.x);
196 this,
197 delayLeft - delay,
198 nextPosition);
199 }
200 }
201 NS_LOG_LOGIC("Position " << position << " NextPosition " << nextPosition);
202
203 // store the previous position
204 m_prevPosition = position;
206}
207
208std::pair<bool, Ptr<Building>>
210 Vector nextPosition) const
211{
212 NS_LOG_FUNCTION(this << currentPosition << nextPosition);
213
214 bool intersectBuilding = false;
215 double minIntersectionDistance = std::numeric_limits<double>::max();
216 Ptr<Building> minIntersectionDistanceBuilding;
217
219 {
220 // check if this building intersects the line between the current and next positions
221 // this checks also if the next position is inside the building
222 if ((*bit)->IsIntersect(currentPosition, nextPosition))
223 {
224 NS_LOG_LOGIC("Building " << (*bit)->GetBoundaries() << " intersects the line between "
225 << currentPosition << " and " << nextPosition);
226 auto intersection = CalculateIntersectionFromOutside(currentPosition,
227 nextPosition,
228 (*bit)->GetBoundaries());
229 double distance = CalculateDistance(intersection, currentPosition);
230 intersectBuilding = true;
231 if (distance < minIntersectionDistance)
232 {
233 minIntersectionDistance = distance;
234 minIntersectionDistanceBuilding = (*bit);
235 }
236 }
237 }
238
239 return std::make_pair(!intersectBuilding, minIntersectionDistanceBuilding);
240}
241
242Vector
244 const Vector& next,
245 Box boundaries) const
246{
247 NS_LOG_FUNCTION(this << " current " << current << " next " << next);
248 bool inside = boundaries.IsInside(current);
249 NS_ASSERT(!inside);
250
251 // get the closest side
252 Rectangle rect = Rectangle(boundaries.xMin, boundaries.xMax, boundaries.yMin, boundaries.yMax);
253 NS_LOG_INFO("rect " << rect);
254 Rectangle::Side closestSide = rect.GetClosestSide(current);
255
256 double xIntersect = 0;
257 double yIntersect = 0;
258
259 switch (closestSide)
260 {
261 case Rectangle::RIGHT:
262 NS_LOG_INFO("The closest side is RIGHT");
263 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
264 xIntersect = boundaries.xMax + m_epsilon;
265 yIntersect =
266 (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
267 break;
268 case Rectangle::LEFT:
269 NS_LOG_INFO("The closest side is LEFT");
270 xIntersect = boundaries.xMin - m_epsilon;
271 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
272 yIntersect =
273 (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
274 break;
275 case Rectangle::TOP:
276 NS_LOG_INFO("The closest side is TOP");
277 yIntersect = boundaries.yMax + m_epsilon;
278 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
279 xIntersect =
280 (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
281 break;
283 NS_LOG_INFO("The closest side is BOTTOM");
284 yIntersect = boundaries.yMin - m_epsilon;
285 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
286 xIntersect =
287 (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
288 break;
289 }
290 NS_LOG_INFO("xIntersect " << xIntersect << " yIntersect " << yIntersect);
291 return Vector(xIntersect, yIntersect, 0);
292}
293
294void
296{
297 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
299 Vector position = m_helper.GetCurrentPosition();
300 Vector speed = m_helper.GetVelocity();
301 switch (m_bounds.GetClosestSide(position))
302 {
303 case Rectangle::RIGHT:
304 NS_LOG_INFO("The closest side is RIGHT");
305 case Rectangle::LEFT:
306 NS_LOG_INFO("The closest side is LEFT");
307 speed.x = -speed.x;
308 break;
309 case Rectangle::TOP:
310 NS_LOG_INFO("The closest side is TOP");
312 NS_LOG_INFO("The closest side is BOTTOM");
313 speed.y = -speed.y;
314 break;
315 }
316 m_helper.SetVelocity(speed);
318 DoWalk(delayLeft);
319}
320
321void
322RandomWalk2dOutdoorMobilityModel::AvoidBuilding(Time delayLeft, Vector intersectPosition)
323{
324 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
326
327 bool nextWouldBeInside = true;
328 uint32_t iter = 0;
329
330 while (nextWouldBeInside && iter < m_maxIter)
331 {
332 NS_LOG_INFO("The next position would be inside a building, compute an alternative");
333 iter++;
334 double speed = m_speed->GetValue();
335 double direction = m_direction->GetValue();
336 Vector velocityVector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
337 m_helper.SetVelocity(velocityVector);
338
339 Vector nextPosition = intersectPosition;
340 nextPosition.x += velocityVector.x * delayLeft.GetSeconds();
341 nextPosition.y += velocityVector.y * delayLeft.GetSeconds();
342
343 // check if this is inside the current buildingBox
344 auto outdoorBuilding = IsLineClearOfBuildings(intersectPosition, nextPosition);
345 bool outdoor = std::get<0>(outdoorBuilding);
346
347 if (!outdoor)
348 {
349 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
350 << nextPosition << " " << outdoor << " building "
351 << std::get<1>(outdoorBuilding)->GetBoundaries());
352 }
353 else
354 {
355 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
356 << nextPosition << " " << outdoor);
357 }
358
359 if (outdoor && m_bounds.IsInside(nextPosition))
360 {
361 nextWouldBeInside = false;
362 }
363 }
364
365 // after m_maxIter iterations, the positions tested are all inside
366 // to avoid increasing m_maxIter too much, it is possible to perform a step back
367 // to the previous position and continue from there
368 if (iter >= m_maxIter)
369 {
370 NS_LOG_INFO("Move back to the previous position");
371
372 // compute the difference between the previous position and the intersection
373 Vector posDiff = m_prevPosition - intersectPosition;
374 // compute the distance
375 double distance = CalculateDistance(m_prevPosition, intersectPosition);
376 double speed = distance / delayLeft.GetSeconds(); // compute the speed
377
378 NS_LOG_LOGIC("prev " << m_prevPosition << " intersectPosition " << intersectPosition
379 << " diff " << posDiff << " dist " << distance);
380
381 Vector velocityVector(posDiff.x / distance * speed, posDiff.y / distance * speed, 0.0);
382 m_helper.SetVelocity(velocityVector);
383
384 Vector nextPosition = intersectPosition;
385 nextPosition.x += velocityVector.x * delayLeft.GetSeconds();
386 nextPosition.y += velocityVector.y * delayLeft.GetSeconds();
387
388 // check if the path is clear
389 auto outdoorBuilding = IsLineClearOfBuildings(intersectPosition, nextPosition);
390 bool outdoor = std::get<0>(outdoorBuilding);
391 if (!outdoor)
392 {
393 NS_LOG_LOGIC("The position is still inside after "
394 << m_maxIter + 1 << " iterations, loop intersect " << intersectPosition
395 << " nextPosition " << nextPosition << " " << outdoor << " building "
396 << std::get<1>(outdoorBuilding)->GetBoundaries());
397 // This error may be due to buildings being attached to one another, or to the boundary
398 // of the scenario.
400 "Not able to find an outdoor position. Try to increase the attribute MaxIterations "
401 "and check the position of the buildings in the scenario.");
402 }
403 else
404 {
405 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
406 << nextPosition << " " << outdoor);
407 }
408 }
409
411
412 DoWalk(delayLeft);
413}
414
415void
417{
418 // chain up
420}
421
422Vector
424{
427}
428
429void
431{
432 NS_ASSERT(m_bounds.IsInside(position));
433 m_helper.SetPosition(position);
436}
437
438Vector
440{
441 return m_helper.GetVelocity();
442}
443
444int64_t
446{
447 m_speed->SetStream(stream);
448 m_direction->SetStream(stream + 1);
449 return 2;
450}
451
452} // namespace ns3
a 3d box
Definition: box.h:35
double yMax
The y coordinate of the top bound of the box.
Definition: box.h:116
bool IsInside(const Vector &position) const
Definition: box.cc:54
double xMin
The x coordinate of the left bound of the box.
Definition: box.h:110
double yMin
The y coordinate of the bottom bound of the box.
Definition: box.h:114
double xMax
The x coordinate of the right bound of the box.
Definition: box.h:112
std::vector< Ptr< Building > >::const_iterator Iterator
Const Iterator.
Definition: building-list.h:41
static Iterator End()
static Iterator Begin()
Vector GetCurrentPosition() const
Get current position vector.
Vector GetVelocity() const
Get velocity; if paused, will return a zero vector.
void Update() const
Update position, if not paused, from last position and time of last update.
void UpdateWithBounds(const Rectangle &rectangle) const
Update position, if not paused, from last position and time of last update.
void Unpause()
Resume mobility from current position at current velocity.
void SetPosition(const Vector &position)
Set position vector.
void SetVelocity(const Vector &vel)
Set new velocity vector.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:56
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
Keep track of the current position and velocity of an object.
void NotifyCourseChange() const
Must be invoked by subclasses when the course of the position changes to notify course change listene...
virtual void DoInitialize()
Initialize() implementation.
Definition: object.cc:360
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:353
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
virtual double GetValue()=0
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
2D random walk mobility model which avoids buildings.
void AvoidBuilding(Time delayLeft, Vector intersectPosition)
Avoid a building.
void DoInitializePrivate()
Perform initialization of the object before MobilityModel::DoInitialize ()
int64_t DoAssignStreams(int64_t) override
The default implementation does nothing but return the passed-in parameter.
double m_modeDistance
Change direction and speed after this distance.
ConstantVelocityHelper m_helper
helper for this object
Vector m_prevPosition
Store the previous position in case a step back is needed.
void Rebound(Time timeLeft)
Performs the rebound of the node if it reaches a boundary.
uint32_t m_maxIter
Maximum number of tries to find the next position.
Vector CalculateIntersectionFromOutside(const Vector &current, const Vector &next, const Box boundaries) const
Compute the intersecting point of the box represented by boundaries and the line between current and ...
Ptr< RandomVariableStream > m_direction
rv for picking direction
void DoDispose() override
Destructor implementation.
double m_epsilon
Tolerance for the intersection point with buildings.
void DoWalk(Time delayLeft)
Walk according to position and velocity, until distance is reached, time is reached,...
std::pair< bool, Ptr< Building > > IsLineClearOfBuildings(Vector currentPosition, Vector nextPosition) const
Check if there is a building between two positions (or if the nextPosition is inside a building).
static TypeId GetTypeId()
Register this type with the TypeId system.
void DoInitialize() override
Initialize() implementation.
Time m_modeTime
Change current direction and speed after this delay.
Ptr< RandomVariableStream > m_speed
rv for picking speed
a 2d rectangle
Definition: rectangle.h:35
Side GetClosestSide(const Vector &position) const
Definition: rectangle.cc:56
bool IsInside(const Vector &position) const
Definition: rectangle.cc:49
Vector CalculateIntersection(const Vector &current, const Vector &speed) const
Definition: rectangle.cc:178
Side
enum for naming sides
Definition: rectangle.h:41
AttributeValue implementation for Rectangle.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
static void Remove(const EventId &id)
Remove an event from the event list.
Definition: simulator.cc:266
Hold variables of type string.
Definition: string.h:56
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
AttributeValue implementation for Time.
Definition: nstime.h:1423
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:205
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1444
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double CalculateDistance(const Vector3D &a, const Vector3D &b)
Definition: vector.cc:109
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163