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 "building-list.h"
24#include "building.h"
25
26#include "ns3/double.h"
27#include "ns3/enum.h"
28#include "ns3/log.h"
29#include "ns3/pointer.h"
30#include "ns3/simulator.h"
31#include "ns3/string.h"
32#include "ns3/uinteger.h"
33
34#include <cmath>
35#include <limits>
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("RandomWalk2dOutdoor");
41
42NS_OBJECT_ENSURE_REGISTERED(RandomWalk2dOutdoorMobilityModel);
43
44TypeId
46{
47 static TypeId tid =
48 TypeId("ns3::RandomWalk2dOutdoorMobilityModel")
50 .SetGroupName("Mobility")
51 .AddConstructor<RandomWalk2dOutdoorMobilityModel>()
52 .AddAttribute("Bounds",
53 "Bounds of the area to cruise.",
54 RectangleValue(Rectangle(0.0, 100.0, 0.0, 100.0)),
57 .AddAttribute("Time",
58 "Change current direction and speed after moving for this delay.",
59 TimeValue(Seconds(20.0)),
62 .AddAttribute("Distance",
63 "Change current direction and speed after moving for this distance.",
64 DoubleValue(30.0),
66 MakeDoubleChecker<double>())
67 .AddAttribute("Mode",
68 "The mode indicates the condition used to "
69 "change the current speed and direction",
71 MakeEnumAccessor<Mode>(&RandomWalk2dOutdoorMobilityModel::m_mode),
73 "Distance",
75 "Time"))
76 .AddAttribute("Direction",
77 "A random variable used to pick the direction (radians).",
78 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=6.283184]"),
80 MakePointerChecker<RandomVariableStream>())
81 .AddAttribute(
82 "Speed",
83 "A random variable used to pick the speed (m/s)."
84 "The default value is taken from Figure 1 of the paper"
85 "Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.",
86 StringValue("ns3::NormalRandomVariable[Mean=1.53|Variance=0.040401]"),
88 MakePointerChecker<RandomVariableStream>())
89 .AddAttribute("Tolerance",
90 "Tolerance for the intersection point with buildings (m)."
91 "It represents a small distance from where the building limit"
92 "is actually placed, for example to represent a sidewalk.",
93 DoubleValue(1e-6),
95 MakeDoubleChecker<double>())
96 .AddAttribute("MaxIterations",
97 "Maximum number of attempts to find an alternative next position"
98 "if the original one is inside a building.",
99 UintegerValue(100),
101 MakeUintegerChecker<uint32_t>());
102 return tid;
103}
104
105void
107{
110}
111
112void
114{
116 double speed = m_speed->GetValue();
117 double direction = m_direction->GetValue();
118 Vector velocity(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
119 m_helper.SetVelocity(velocity);
121
122 Time delayLeft;
124 {
125 delayLeft = m_modeTime;
126 }
127 else
128 {
129 delayLeft = Seconds(m_modeDistance / speed);
130 }
131 DoWalk(delayLeft);
132}
133
134void
136{
137 if (delayLeft.IsNegative())
138 {
139 NS_LOG_INFO(this << " Ran out of time");
140 return;
141 }
142 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
143
144 Vector position = m_helper.GetCurrentPosition();
145 Vector velocity = m_helper.GetVelocity();
146 Vector nextPosition = position;
147 nextPosition.x += velocity.x * delayLeft.GetSeconds();
148 nextPosition.y += velocity.y * delayLeft.GetSeconds();
149 m_event.Cancel();
150
151 // check if the nextPosition is inside a building, or if the line
152 // from position to the next position intersects a building
153 auto outdoorBuilding = IsLineClearOfBuildings(position, nextPosition);
154 bool outdoor = std::get<0>(outdoorBuilding);
155 Ptr<Building> building = std::get<1>(outdoorBuilding);
156
157 if (m_bounds.IsInside(nextPosition))
158 {
159 if (outdoor)
160 {
161 m_event = Simulator::Schedule(delayLeft,
163 this);
164 }
165 else
166 {
167 NS_LOG_LOGIC("NextPosition would lead into a building");
168 nextPosition =
169 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
170
171 double delaySecondsX = std::numeric_limits<double>::max();
172 double delaySecondsY = std::numeric_limits<double>::max();
173 if (velocity.x != 0)
174 {
175 delaySecondsX = std::abs((nextPosition.x - position.x) / velocity.x);
176 }
177 if (velocity.y != 0)
178 {
179 delaySecondsY = std::abs((nextPosition.y - position.y) / velocity.y);
180 }
181 Time delay = Seconds(std::min(delaySecondsX, delaySecondsY));
184 this,
185 delayLeft - delay,
186 nextPosition);
187 }
188 }
189 else
190 {
191 NS_LOG_LOGIC("Out of bounding box");
192 nextPosition = m_bounds.CalculateIntersection(position, velocity);
193 // check that this nextPosition is outdoor
194 auto outdoorBuilding = IsLineClearOfBuildings(position, nextPosition);
195 bool outdoor = std::get<0>(outdoorBuilding);
196 Ptr<Building> building = std::get<1>(outdoorBuilding);
197
198 if (outdoor)
199 {
200 double delaySeconds = std::numeric_limits<double>::max();
201 if (velocity.x != 0)
202 {
203 delaySeconds =
204 std::min(delaySeconds, std::abs((nextPosition.x - position.x) / velocity.x));
205 }
206 else if (velocity.y != 0)
207 {
208 delaySeconds =
209 std::min(delaySeconds, std::abs((nextPosition.y - position.y) / velocity.y));
210 }
211 else
212 {
213 NS_ABORT_MSG("RandomWalk2dOutdoorMobilityModel::DoWalk: unable to calculate the "
214 "rebound time "
215 "(the node is stationary).");
216 }
217 Time delay = Seconds(delaySeconds);
220 this,
221 delayLeft - delay);
222 }
223 else
224 {
225 NS_LOG_LOGIC("NextPosition would lead into a building");
226 nextPosition =
227 CalculateIntersectionFromOutside(position, nextPosition, building->GetBoundaries());
228
229 double delaySecondsX = std::numeric_limits<double>::max();
230 double delaySecondsY = std::numeric_limits<double>::max();
231 if (velocity.x != 0)
232 {
233 delaySecondsX =
234 std::min(delaySecondsX, std::abs((nextPosition.x - position.x) / velocity.x));
235 }
236 if (velocity.y != 0)
237 {
238 delaySecondsY =
239 std::min(delaySecondsY, std::abs((nextPosition.y - position.y) / velocity.y));
240 }
241 if (delaySecondsX == std::numeric_limits<double>::max() &&
242 delaySecondsY == std::numeric_limits<double>::max())
243 {
244 NS_ABORT_MSG("RandomWalk2dOutdoorMobilityModel::DoWalk: unable to calculate the "
245 "rebound time "
246 "(the node is stationary).");
247 }
248
249 Time delay = Seconds(std::min(delaySecondsX, delaySecondsY));
252 this,
253 delayLeft - delay,
254 nextPosition);
255 }
256 }
257 NS_LOG_LOGIC("Position " << position << " NextPosition " << nextPosition);
258
259 // store the previous position
260 m_prevPosition = position;
262}
263
264std::pair<bool, Ptr<Building>>
266 Vector nextPosition) const
267{
268 NS_LOG_FUNCTION(this << currentPosition << nextPosition);
269
270 bool intersectBuilding = false;
271 double minIntersectionDistance = std::numeric_limits<double>::max();
272 Ptr<Building> minIntersectionDistanceBuilding;
273
274 for (auto bit = BuildingList::Begin(); bit != BuildingList::End(); ++bit)
275 {
276 // check if this building intersects the line between the current and next positions
277 // this checks also if the next position is inside the building
278 if ((*bit)->IsIntersect(currentPosition, nextPosition))
279 {
280 NS_LOG_LOGIC("Building " << (*bit)->GetBoundaries() << " intersects the line between "
281 << currentPosition << " and " << nextPosition);
282 auto intersection = CalculateIntersectionFromOutside(currentPosition,
283 nextPosition,
284 (*bit)->GetBoundaries());
285 double distance = CalculateDistance(intersection, currentPosition);
286 intersectBuilding = true;
287 if (distance < minIntersectionDistance)
288 {
289 minIntersectionDistance = distance;
290 minIntersectionDistanceBuilding = (*bit);
291 }
292 }
293 }
294
295 return std::make_pair(!intersectBuilding, minIntersectionDistanceBuilding);
296}
297
298Vector
300 const Vector& next,
301 Box boundaries) const
302{
303 NS_LOG_FUNCTION(this << " current " << current << " next " << next);
304 bool inside = boundaries.IsInside(current);
305 NS_ASSERT(!inside);
306
307 // get the closest side
308 Rectangle rect = Rectangle(boundaries.xMin, boundaries.xMax, boundaries.yMin, boundaries.yMax);
309 NS_LOG_DEBUG("rect " << rect);
310 Rectangle::Side closestSide = rect.GetClosestSideOrCorner(current);
311
312 double xIntersect = 0;
313 double yIntersect = 0;
314
315 switch (closestSide)
316 {
318 NS_LOG_DEBUG("The closest side is RIGHT");
319 xIntersect = boundaries.xMax + m_epsilon;
320 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
321 yIntersect =
322 (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
323 break;
325 NS_LOG_DEBUG("The closest side is LEFT");
326 xIntersect = boundaries.xMin - m_epsilon;
327 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
328 yIntersect =
329 (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
330 break;
332 NS_LOG_DEBUG("The closest side is TOP");
333 yIntersect = boundaries.yMax + m_epsilon;
334 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
335 xIntersect =
336 (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
337 break;
339 NS_LOG_DEBUG("The closest side is BOTTOM");
340 yIntersect = boundaries.yMin - m_epsilon;
341 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
342 xIntersect =
343 (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
344 break;
346 NS_LOG_DEBUG("The closest side is TOPRIGHT");
347 xIntersect = boundaries.xMax + m_epsilon;
348 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
349 yIntersect = boundaries.yMax + m_epsilon;
350 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
351 break;
353 NS_LOG_DEBUG("The closest side is TOPLEFT");
354 xIntersect = boundaries.xMin - m_epsilon;
355 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
356 yIntersect = boundaries.yMax + m_epsilon;
357 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
358 break;
360 NS_LOG_DEBUG("The closest side is BOTTOMRIGHT");
361 xIntersect = boundaries.xMax + m_epsilon;
362 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
363 yIntersect = boundaries.yMin - m_epsilon;
364 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
365 break;
367 NS_LOG_DEBUG("The closest side is BOTTOMLEFT");
368 xIntersect = boundaries.xMin - m_epsilon;
369 NS_ABORT_MSG_IF(next.x - current.x == 0, "x position not updated");
370 yIntersect = boundaries.yMin - m_epsilon;
371 NS_ABORT_MSG_IF(next.y - current.y == 0, "y position not updated");
372 break;
373 }
374 NS_LOG_DEBUG("xIntersect " << xIntersect << " yIntersect " << yIntersect);
375 return Vector(xIntersect, yIntersect, 0);
376}
377
378void
380{
381 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
383 Vector position = m_helper.GetCurrentPosition();
384 Vector velocity = m_helper.GetVelocity();
385 switch (m_bounds.GetClosestSideOrCorner(position))
386 {
389 NS_LOG_DEBUG("The closest side is RIGHT or LEFT");
390 velocity.x = -velocity.x;
391 break;
394 NS_LOG_DEBUG("The closest side is TOP or BOTTOM");
395 velocity.y = -velocity.y;
396 break;
401 NS_LOG_DEBUG("The closest side is a corner");
402 velocity.x = -velocity.x;
403 velocity.y = -velocity.y;
404 break;
405 }
406 m_helper.SetVelocity(velocity);
408 DoWalk(delayLeft);
409}
410
411void
412RandomWalk2dOutdoorMobilityModel::AvoidBuilding(Time delayLeft, Vector intersectPosition)
413{
414 NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
416
417 bool nextWouldBeInside = true;
418 uint32_t iter = 0;
419
420 while (nextWouldBeInside && iter < m_maxIter)
421 {
422 NS_LOG_INFO("The next position would be inside a building, compute an alternative");
423 iter++;
424 double speed = m_speed->GetValue();
425 double direction = m_direction->GetValue();
426 Vector velocityVector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
427 m_helper.SetVelocity(velocityVector);
428
429 Vector nextPosition = intersectPosition;
430 nextPosition.x += velocityVector.x * delayLeft.GetSeconds();
431 nextPosition.y += velocityVector.y * delayLeft.GetSeconds();
432
433 // check if this is inside the current buildingBox
434 auto outdoorBuilding = IsLineClearOfBuildings(intersectPosition, nextPosition);
435 bool outdoor = std::get<0>(outdoorBuilding);
436
437 if (!outdoor)
438 {
439 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
440 << nextPosition << " " << outdoor << " building "
441 << std::get<1>(outdoorBuilding)->GetBoundaries());
442 }
443 else
444 {
445 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
446 << nextPosition << " " << outdoor);
447 }
448
449 if (outdoor && m_bounds.IsInside(nextPosition))
450 {
451 nextWouldBeInside = false;
452 }
453 }
454
455 // after m_maxIter iterations, the positions tested are all inside
456 // to avoid increasing m_maxIter too much, it is possible to perform a step back
457 // to the previous position and continue from there
458 if (iter >= m_maxIter)
459 {
460 NS_LOG_INFO("Move back to the previous position");
461
462 // compute the difference between the previous position and the intersection
463 Vector posDiff = m_prevPosition - intersectPosition;
464 // compute the distance
465 double distance = CalculateDistance(m_prevPosition, intersectPosition);
466 double speed = distance / delayLeft.GetSeconds(); // compute the speed
467
468 NS_LOG_LOGIC("prev " << m_prevPosition << " intersectPosition " << intersectPosition
469 << " diff " << posDiff << " dist " << distance);
470
471 Vector velocityVector(posDiff.x / distance * speed, posDiff.y / distance * speed, 0.0);
472 m_helper.SetVelocity(velocityVector);
473
474 Vector nextPosition = intersectPosition;
475 nextPosition.x += velocityVector.x * delayLeft.GetSeconds();
476 nextPosition.y += velocityVector.y * delayLeft.GetSeconds();
477
478 // check if the path is clear
479 auto outdoorBuilding = IsLineClearOfBuildings(intersectPosition, nextPosition);
480 bool outdoor = std::get<0>(outdoorBuilding);
481 if (!outdoor)
482 {
483 NS_LOG_LOGIC("The position is still inside after "
484 << m_maxIter + 1 << " iterations, loop intersect " << intersectPosition
485 << " nextPosition " << nextPosition << " " << outdoor << " building "
486 << std::get<1>(outdoorBuilding)->GetBoundaries());
487 // This error may be due to buildings being attached to one another, or to the boundary
488 // of the scenario.
490 "Not able to find an outdoor position. Try to increase the attribute MaxIterations "
491 "and check the position of the buildings in the scenario.");
492 }
493 else
494 {
495 NS_LOG_LOGIC("inside loop intersect " << intersectPosition << " nextPosition "
496 << nextPosition << " " << outdoor);
497 }
498 }
499
501
502 DoWalk(delayLeft);
503}
504
505void
507{
508 // chain up
510}
511
512Vector
514{
517}
518
519void
521{
522 NS_ASSERT(m_bounds.IsInside(position));
523 m_helper.SetPosition(position);
526}
527
528Vector
530{
531 return m_helper.GetVelocity();
532}
533
534int64_t
536{
537 m_speed->SetStream(stream);
538 m_direction->SetStream(stream + 1);
539 return 2;
540}
541
542} // 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
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:62
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:451
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:444
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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 GetClosestSideOrCorner(const Vector &position) const
Definition: rectangle.cc:64
bool IsInside(const Vector &position) const
Definition: rectangle.cc:50
Vector CalculateIntersection(const Vector &current, const Vector &speed) const
Definition: rectangle.cc:152
Side
enum for naming sides
Definition: rectangle.h:41
AttributeValue implementation for Rectangle.
Definition: rectangle.h:125
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
static void Remove(const EventId &id)
Remove an event from the event list.
Definition: simulator.cc:275
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:403
bool IsNegative() const
Exactly equivalent to t <= 0.
Definition: nstime.h:324
AttributeValue implementation for Time.
Definition: nstime.h:1413
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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 > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
Ptr< const AttributeAccessor > MakeRectangleAccessor(T1 a1)
Definition: rectangle.h:125
Ptr< const AttributeChecker > MakeRectangleChecker()
Definition: rectangle.cc:187
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
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(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#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_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:1326
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:189
double CalculateDistance(const Vector3D &a, const Vector3D &b)
Definition: vector.cc:109