diff --git a/CHANGES.html b/CHANGES.html
index c9078c015..625e8eb7d 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -74,9 +74,10 @@ allows to choose between Block Ack policy and Implicit Block Ack Request policy
allows to request an acknowledgment after a configurable number of MPDUs have been
transmitted.
The MaxSize attribute is removed from the QueueBase base class and moved to subclasses. A new MaxSize attribute is therefore added to the DropTailQueue class, while the MaxQueueSize attribute of the WifiMacQueue class is renamed as MaxSize for API consistency.
+ A new sequence and timestamp header variant for applications has been added. The SeqTsEchoHeader contains an additional timestamp field for use in echoing a timestamp back to a sender.
TCP-based applications (OnOffApplication, BulkSendApplication, and PacketSink) support a new header to convey sequence number, timestamp, and size data. Use is controlled by the "EnableSeqTsSizeHeader" attribute.
Added a new trace source PhyRxPayloadBegin in WifiPhy for tracing begin of PSDU reception.
- A new sequence and timestamp header variant for applications has been added. The SeqTsEchoHeader contains an additional timestamp field for use in echoing a timestamp back to a sender.
+Added the class RandomWalk2dOutdoorMobilityModel that models a random walk which does not enter any building.
Changes to existing API:
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index b9acd4ea7..6940bc0cc 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -28,6 +28,7 @@ New user-visible features
- (propagation) 3GPP TR 38.901 pathloss and channel condition models added
- (spectrum) Addition three-gpp-channel-model (part of Integration of the 3GPP TR 38.901 fast fading model)
- (antenna) Addition of three-gpp-antenna-array-model (part of Integration of the 3GPP TR 38.901 fast fading model)
+- (buildings) added a random walk mobility model which does not enter in any building
- (core) CommandLine can now add the Usage message to the Doxygen for the program; see CommandLine for details.
Bugs fixed
diff --git a/src/buildings/examples/outdoor-random-walk-example.cc b/src/buildings/examples/outdoor-random-walk-example.cc
new file mode 100644
index 000000000..cdbed62ce
--- /dev/null
+++ b/src/buildings/examples/outdoor-random-walk-example.cc
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ * Copyright (c) 2019, University of Padova, Dep. of Information Engineering, SIGNET lab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Nicola Baldo for the code adapted from the lena-dual-stripe.cc example
+ * Author: Michele Polese for this version
+ */
+
+#include "ns3/buildings-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("OutdoorRandomWalkExample");
+
+void
+PrintGnuplottableBuildingListToFile (std::string filename)
+{
+ std::ofstream outFile;
+ outFile.open (filename.c_str (), std::ios_base::out | std::ios_base::trunc);
+ if (!outFile.is_open ())
+ {
+ NS_LOG_ERROR ("Can't open file " << filename);
+ return;
+ }
+ uint32_t index = 0;
+ for (BuildingList::Iterator it = BuildingList::Begin (); it != BuildingList::End (); ++it)
+ {
+ ++index;
+ Box box = (*it)->GetBoundaries ();
+ outFile << "set object " << index
+ << " rect from " << box.xMin << "," << box.yMin
+ << " to " << box.xMax << "," << box.yMax
+ << std::endl;
+ }
+}
+
+
+/**
+ * This is an example on how to use the RandomWalk2dOutdoorMobilityModel class.
+ * The script outdoor-random-walk-example.sh can be used to visualize the
+ * positions visited by the random walk.
+ */
+int
+main (int argc, char *argv[])
+{
+ LogComponentEnable ("RandomWalk2dOutdoor", LOG_LEVEL_LOGIC);
+ CommandLine cmd (__FILE__);
+ cmd.Parse (argc, argv);
+
+ // create a grid of buildings
+ double buildingSizeX = 100; // m
+ double buildingSizeY = 50; // m
+ double streetWidth = 25; // m
+ double buildingHeight = 10; // m
+ uint32_t numBuildingsX = 10;
+ uint32_t numBuildingsY = 10;
+ double maxAxisX = (buildingSizeX + streetWidth) * numBuildingsX;
+ double maxAxisY = (buildingSizeY + streetWidth) * numBuildingsY;
+
+ std::vector > buildingVector;
+ for (uint32_t buildingIdX = 0; buildingIdX < numBuildingsX; ++buildingIdX)
+ {
+ for (uint32_t buildingIdY = 0; buildingIdY < numBuildingsY; ++buildingIdY)
+ {
+ Ptr < Building > building;
+ building = CreateObject ();
+
+ building->SetBoundaries (Box (buildingIdX * (buildingSizeX + streetWidth),
+ buildingIdX * (buildingSizeX + streetWidth) + buildingSizeX,
+ buildingIdY * (buildingSizeY + streetWidth),
+ buildingIdY * (buildingSizeY + streetWidth) + buildingSizeY,
+ 0.0, buildingHeight));
+ building->SetNRoomsX (1);
+ building->SetNRoomsY (1);
+ building->SetNFloors (1);
+ buildingVector.push_back (building);
+ }
+ }
+
+ // print the list of buildings to file
+ PrintGnuplottableBuildingListToFile ("buildings.txt");
+
+ // create one node
+ NodeContainer nodes;
+ nodes.Create (1);
+
+ // set the RandomWalk2dOutdoorMobilityModel mobility model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::RandomWalk2dOutdoorMobilityModel",
+ "Bounds", RectangleValue (
+ Rectangle (-streetWidth, maxAxisX, -streetWidth, maxAxisY)));
+ // create an OutdoorPositionAllocator and set its boundaries to match those of the mobility model
+ Ptr position = CreateObject ();
+ Ptr xPos = CreateObject();
+ xPos->SetAttribute ("Min", DoubleValue (-streetWidth));
+ xPos->SetAttribute ("Max", DoubleValue (maxAxisX));
+ Ptr yPos = CreateObject();
+ yPos->SetAttribute ("Min", DoubleValue (-streetWidth));
+ yPos->SetAttribute ("Max", DoubleValue (maxAxisY));
+ position->SetAttribute ("X", PointerValue (xPos));
+ position->SetAttribute ("Y", PointerValue (yPos));
+ mobility.SetPositionAllocator (position);
+ // install the mobility model
+ mobility.Install (nodes.Get (0));
+
+ // enable the traces for the mobility model
+ AsciiTraceHelper ascii;
+ MobilityHelper::EnableAsciiAll (ascii.CreateFileStream ("mobility-trace-example.mob"));
+
+ Simulator::Stop (Seconds (1e4));
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
\ No newline at end of file
diff --git a/src/buildings/examples/outdoor-random-walk-example.sh b/src/buildings/examples/outdoor-random-walk-example.sh
new file mode 100755
index 000000000..09b5bfdf2
--- /dev/null
+++ b/src/buildings/examples/outdoor-random-walk-example.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+# Copyright (c) 2019, University of Padova, Dep. of Information Engineering, SIGNET lab
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation;
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Author: Michele Polese
+
+#
+# Plot the traces generated by outdoor-random-walk-example.cc
+#
+
+cat mobility-trace-example.mob | awk -F " " '{ print $3 }' | awk -F "=" '{ print $2 }' | awk -F ":" '{ print $1" "$2 }' > pos.txt
+cat >aa <
+ * Author: Michele Polese
+ */
+#include "random-walk-2d-outdoor-mobility-model.h"
+#include "ns3/enum.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+#include "ns3/building.h"
+#include "ns3/building-list.h"
+#include
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("RandomWalk2dOutdoor");
+
+NS_OBJECT_ENSURE_REGISTERED (RandomWalk2dOutdoorMobilityModel);
+
+TypeId
+RandomWalk2dOutdoorMobilityModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::RandomWalk2dOutdoorMobilityModel")
+ .SetParent ()
+ .SetGroupName ("Mobility")
+ .AddConstructor ()
+ .AddAttribute ("Bounds",
+ "Bounds of the area to cruise.",
+ RectangleValue (Rectangle (0.0, 100.0, 0.0, 100.0)),
+ MakeRectangleAccessor (&RandomWalk2dOutdoorMobilityModel::m_bounds),
+ MakeRectangleChecker ())
+ .AddAttribute ("Time",
+ "Change current direction and speed after moving for this delay.",
+ TimeValue (Seconds (20.0)),
+ MakeTimeAccessor (&RandomWalk2dOutdoorMobilityModel::m_modeTime),
+ MakeTimeChecker ())
+ .AddAttribute ("Distance",
+ "Change current direction and speed after moving for this distance.",
+ DoubleValue (30.0),
+ MakeDoubleAccessor (&RandomWalk2dOutdoorMobilityModel::m_modeDistance),
+ MakeDoubleChecker ())
+ .AddAttribute ("Mode",
+ "The mode indicates the condition used to "
+ "change the current speed and direction",
+ EnumValue (RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE),
+ MakeEnumAccessor (&RandomWalk2dOutdoorMobilityModel::m_mode),
+ MakeEnumChecker (RandomWalk2dOutdoorMobilityModel::MODE_DISTANCE, "Distance",
+ RandomWalk2dOutdoorMobilityModel::MODE_TIME, "Time"))
+ .AddAttribute ("Direction",
+ "A random variable used to pick the direction (radians).",
+ StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=6.283184]"),
+ MakePointerAccessor (&RandomWalk2dOutdoorMobilityModel::m_direction),
+ MakePointerChecker ())
+ .AddAttribute ("Speed",
+ "A random variable used to pick the speed (m/s)."
+ "The default value is taken from Figure 1 of the paper"
+ "Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.",
+ StringValue ("ns3::NormalRandomVariable[Mean=1.53|Variance=0.040401]"),
+ MakePointerAccessor (&RandomWalk2dOutdoorMobilityModel::m_speed),
+ MakePointerChecker ())
+ .AddAttribute ("Tolerance",
+ "Tolerance for the intersection point with buildings (m)."
+ "It represents a small distance from where the building limit"
+ "is actually placed, for example to represent a sidewalk.",
+ DoubleValue (1e-6),
+ MakeDoubleAccessor (&RandomWalk2dOutdoorMobilityModel::m_epsilon),
+ MakeDoubleChecker ())
+ .AddAttribute ("MaxIterations",
+ "Maximum number of attempts to find an alternative next position"
+ "if the original one is inside a building.",
+ UintegerValue (100),
+ MakeUintegerAccessor (&RandomWalk2dOutdoorMobilityModel::m_maxIter),
+ MakeUintegerChecker ())
+ ;
+ return tid;
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::DoInitialize (void)
+{
+ DoInitializePrivate ();
+ MobilityModel::DoInitialize ();
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::DoInitializePrivate (void)
+{
+ m_helper.Update ();
+ double speed = m_speed->GetValue ();
+ double direction = m_direction->GetValue ();
+ Vector vector (std::cos (direction) * speed,
+ std::sin (direction) * speed,
+ 0.0);
+ m_helper.SetVelocity (vector);
+ m_helper.Unpause ();
+
+ Time delayLeft;
+ if (m_mode == RandomWalk2dOutdoorMobilityModel::MODE_TIME)
+ {
+ delayLeft = m_modeTime;
+ }
+ else
+ {
+ delayLeft = Seconds (m_modeDistance / speed);
+ }
+ DoWalk (delayLeft);
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::DoWalk (Time delayLeft)
+{
+ NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
+
+ Vector position = m_helper.GetCurrentPosition ();
+ Vector speed = m_helper.GetVelocity ();
+ Vector nextPosition = position;
+ nextPosition.x += speed.x * delayLeft.GetSeconds ();
+ nextPosition.y += speed.y * delayLeft.GetSeconds ();
+ m_event.Cancel ();
+
+ // check if the nextPosition is inside a building, or if the line
+ // from position to the next position intersects a building
+ auto outdoorBuilding = IsLineClearOfBuildings (position, nextPosition);
+ bool outdoor = std::get<0> (outdoorBuilding);
+ Ptr building = std::get<1> (outdoorBuilding);
+
+ if (m_bounds.IsInside (nextPosition))
+ {
+ if (outdoor)
+ {
+ m_event = Simulator::Schedule (delayLeft, &RandomWalk2dOutdoorMobilityModel::DoInitializePrivate, this);
+ }
+ else
+ {
+ NS_LOG_LOGIC ("NextPosition would lead into a building");
+ nextPosition = CalculateIntersectionFromOutside (position, nextPosition, building->GetBoundaries ());
+ Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
+ m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::AvoidBuilding, this,
+ delayLeft - delay,
+ nextPosition
+ );
+ }
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Out of bounding box");
+ nextPosition = m_bounds.CalculateIntersection (position, speed);
+ // check that this nextPosition is outdoor
+ auto outdoorBuilding = IsLineClearOfBuildings (position, nextPosition);
+ bool outdoor = std::get<0> (outdoorBuilding);
+ Ptr building = std::get<1> (outdoorBuilding);
+
+ if (outdoor)
+ {
+ Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
+ m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::Rebound, this,
+ delayLeft - delay);
+ }
+ else
+ {
+ NS_LOG_LOGIC ("NextPosition would lead into a building");
+ nextPosition = CalculateIntersectionFromOutside (position, nextPosition, building->GetBoundaries ());
+ Time delay = Seconds ((nextPosition.x - position.x) / speed.x);
+ m_event = Simulator::Schedule (delay, &RandomWalk2dOutdoorMobilityModel::AvoidBuilding, this,
+ delayLeft - delay,
+ nextPosition
+ );
+ }
+ }
+ NS_LOG_LOGIC ("Position " << position << " NextPosition " << nextPosition);
+
+ // store the previous position
+ m_prevPosition = position;
+ NotifyCourseChange ();
+}
+
+std::pair >
+RandomWalk2dOutdoorMobilityModel::IsLineClearOfBuildings ( Vector currentPosition, Vector nextPosition ) const
+{
+ NS_LOG_FUNCTION (this << currentPosition << nextPosition);
+
+ bool intersectBuilding = false;
+ double minIntersectionDistance = std::numeric_limits::max ();
+ Ptr minIntersectionDistanceBuilding;
+
+ for (BuildingList::Iterator bit = BuildingList::Begin (); bit != BuildingList::End (); ++bit)
+ {
+ // check if this building intersects the line between the current and next positions
+ // this checks also if the next position is inside the building
+ if ((*bit)->IsIntersect (currentPosition, nextPosition))
+ {
+ NS_LOG_LOGIC ("Building " << (*bit)->GetBoundaries ()
+ << " intersects the line between " << currentPosition
+ << " and " << nextPosition);
+ auto intersection = CalculateIntersectionFromOutside (
+ currentPosition, nextPosition, (*bit)->GetBoundaries ());
+ double distance = CalculateDistance (intersection, currentPosition);
+ intersectBuilding = true;
+ if (distance < minIntersectionDistance)
+ {
+ minIntersectionDistance = distance;
+ minIntersectionDistanceBuilding = (*bit);
+ }
+ }
+ }
+
+ return std::make_pair (!intersectBuilding, minIntersectionDistanceBuilding);
+}
+
+Vector
+RandomWalk2dOutdoorMobilityModel::CalculateIntersectionFromOutside (const Vector ¤t, const Vector &next, Box boundaries) const
+{
+ NS_LOG_FUNCTION (this << " current " << current << " next " << next);
+ bool inside = boundaries.IsInside (current);
+ NS_ASSERT (!inside);
+
+ // get the closest side
+ Rectangle rect = Rectangle (boundaries.xMin, boundaries.xMax, boundaries.yMin, boundaries.yMax);
+ NS_LOG_INFO ("rect " << rect);
+ Rectangle::Side closestSide = rect.GetClosestSide (current);
+
+ double xIntersect = 0;
+ double yIntersect = 0;
+
+ switch (closestSide)
+ {
+ case Rectangle::RIGHT:
+ NS_LOG_INFO ("The closest side is RIGHT");
+ NS_ABORT_MSG_IF (next.x - current.x == 0, "x position not updated");
+ xIntersect = boundaries.xMax + m_epsilon;
+ yIntersect =
+ (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
+ break;
+ case Rectangle::LEFT:
+ NS_LOG_INFO ("The closest side is LEFT");
+ xIntersect = boundaries.xMin - m_epsilon;
+ NS_ABORT_MSG_IF (next.x - current.x == 0, "x position not updated");
+ yIntersect =
+ (next.y - current.y) / (next.x - current.x) * (xIntersect - current.x) + current.y;
+ break;
+ case Rectangle::TOP:
+ NS_LOG_INFO ("The closest side is TOP");
+ yIntersect = boundaries.yMax + m_epsilon;
+ NS_ABORT_MSG_IF (next.y - current.y == 0, "y position not updated");
+ xIntersect =
+ (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
+ break;
+ case Rectangle::BOTTOM:
+ NS_LOG_INFO ("The closest side is BOTTOM");
+ yIntersect = boundaries.yMin - m_epsilon;
+ NS_ABORT_MSG_IF (next.y - current.y == 0, "y position not updated");
+ xIntersect =
+ (next.x - current.x) / (next.y - current.y) * (yIntersect - current.y) + current.x;
+ break;
+ }
+ NS_LOG_INFO ("xIntersect " << xIntersect << " yIntersect " << yIntersect);
+ return Vector (xIntersect, yIntersect, 0);
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::Rebound (Time delayLeft)
+{
+ NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
+ m_helper.UpdateWithBounds (m_bounds);
+ Vector position = m_helper.GetCurrentPosition ();
+ Vector speed = m_helper.GetVelocity ();
+ switch (m_bounds.GetClosestSide (position))
+ {
+ case Rectangle::RIGHT:
+ NS_LOG_INFO ("The closest side is RIGHT");
+ case Rectangle::LEFT:
+ NS_LOG_INFO ("The closest side is LEFT");
+ speed.x = -speed.x;
+ break;
+ case Rectangle::TOP:
+ NS_LOG_INFO ("The closest side is TOP");
+ case Rectangle::BOTTOM:
+ NS_LOG_INFO ("The closest side is BOTTOM");
+ speed.y = -speed.y;
+ break;
+ }
+ m_helper.SetVelocity (speed);
+ m_helper.Unpause ();
+ DoWalk (delayLeft);
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::AvoidBuilding (Time delayLeft, Vector intersectPosition)
+{
+ NS_LOG_FUNCTION (this << delayLeft.GetSeconds ());
+ m_helper.Update ();
+
+ bool nextWouldBeInside = true;
+ uint32_t iter = 0;
+
+ while (nextWouldBeInside && iter < m_maxIter)
+ {
+ NS_LOG_INFO ("The next position would be inside a building, compute an alternative");
+ iter++;
+ double speed = m_speed->GetValue ();
+ double direction = m_direction->GetValue ();
+ Vector velocityVector (std::cos (direction) * speed,
+ std::sin (direction) * speed,
+ 0.0);
+ m_helper.SetVelocity (velocityVector);
+
+ Vector nextPosition = intersectPosition;
+ nextPosition.x += velocityVector.x * delayLeft.GetSeconds ();
+ nextPosition.y += velocityVector.y * delayLeft.GetSeconds ();
+
+ // check if this is inside the current buildingBox
+ auto outdoorBuilding = IsLineClearOfBuildings (intersectPosition, nextPosition);
+ bool outdoor = std::get<0> (outdoorBuilding);
+
+ if (!outdoor)
+ {
+ NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
+ << nextPosition << " " << outdoor << " building " << std::get<1> (outdoorBuilding)->GetBoundaries ());
+ }
+ else
+ {
+ NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
+ << nextPosition << " " << outdoor);
+ }
+
+ if (outdoor && m_bounds.IsInside (nextPosition))
+ {
+ nextWouldBeInside = false;
+ }
+ }
+
+ // after m_maxIter iterations, the positions tested are all inside
+ // to avoid increasing m_maxIter too much, it is possible to perform a step back
+ // to the previous position and continue from there
+ if (iter >= m_maxIter)
+ {
+ NS_LOG_INFO ("Move back to the previous position");
+
+ // compute the difference between the previous position and the intersection
+ Vector posDiff = m_prevPosition - intersectPosition;
+ // compute the distance
+ double distance = CalculateDistance (m_prevPosition, intersectPosition);
+ double speed = distance / delayLeft.GetSeconds (); // compute the speed
+
+ NS_LOG_LOGIC ("prev " << m_prevPosition
+ << " intersectPosition " << intersectPosition
+ << " diff " << posDiff << " dist " << distance
+ );
+
+ Vector velocityVector (posDiff.x / distance * speed,
+ posDiff.y / distance * speed,
+ 0.0);
+ m_helper.SetVelocity (velocityVector);
+
+ Vector nextPosition = intersectPosition;
+ nextPosition.x += velocityVector.x * delayLeft.GetSeconds ();
+ nextPosition.y += velocityVector.y * delayLeft.GetSeconds ();
+
+ // check if the path is clear
+ auto outdoorBuilding = IsLineClearOfBuildings (intersectPosition, nextPosition);
+ bool outdoor = std::get<0> (outdoorBuilding);
+ if (!outdoor)
+ {
+ NS_LOG_LOGIC ("The position is still inside after "
+ << m_maxIter + 1 << " iterations, loop intersect "
+ << intersectPosition << " nextPosition "
+ << nextPosition << " " << outdoor
+ << " building " << std::get<1> (outdoorBuilding)->GetBoundaries ());
+ // This error may be due to buildings being attached to one another, or to the boundary of the scenario.
+ NS_FATAL_ERROR ("Not able to find an outdoor position. Try to increase the attribute MaxIterations and check the position of the buildings in the scenario.");
+ }
+ else
+ {
+ NS_LOG_LOGIC ("inside loop intersect " << intersectPosition << " nextPosition "
+ << nextPosition << " " << outdoor);
+ }
+ }
+
+ m_helper.Unpause ();
+
+ DoWalk (delayLeft);
+}
+
+void
+RandomWalk2dOutdoorMobilityModel::DoDispose (void)
+{
+ // chain up
+ MobilityModel::DoDispose ();
+}
+Vector
+RandomWalk2dOutdoorMobilityModel::DoGetPosition (void) const
+{
+ m_helper.UpdateWithBounds (m_bounds);
+ return m_helper.GetCurrentPosition ();
+}
+void
+RandomWalk2dOutdoorMobilityModel::DoSetPosition (const Vector &position)
+{
+ NS_ASSERT (m_bounds.IsInside (position));
+ m_helper.SetPosition (position);
+ Simulator::Remove (m_event);
+ m_event = Simulator::ScheduleNow (&RandomWalk2dOutdoorMobilityModel::DoInitializePrivate, this);
+}
+Vector
+RandomWalk2dOutdoorMobilityModel::DoGetVelocity (void) const
+{
+ return m_helper.GetVelocity ();
+}
+int64_t
+RandomWalk2dOutdoorMobilityModel::DoAssignStreams (int64_t stream)
+{
+ m_speed->SetStream (stream);
+ m_direction->SetStream (stream + 1);
+ return 2;
+}
+
+
+} // namespace ns3
\ No newline at end of file
diff --git a/src/buildings/model/random-walk-2d-outdoor-mobility-model.h b/src/buildings/model/random-walk-2d-outdoor-mobility-model.h
new file mode 100644
index 000000000..53ad5f7f9
--- /dev/null
+++ b/src/buildings/model/random-walk-2d-outdoor-mobility-model.h
@@ -0,0 +1,135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * Copyright (c) 2019 University of Padova
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage
+ * Author: Michele Polese
+ */
+
+#ifndef RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
+#define RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H
+
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include "ns3/rectangle.h"
+#include "ns3/random-variable-stream.h"
+#include "ns3/mobility-model.h"
+#include "ns3/constant-velocity-helper.h"
+#include "ns3/building.h"
+
+namespace ns3 {
+
+
+/**
+ * \ingroup mobility
+ * \brief 2D random walk mobility model which avoids buildings.
+ *
+ * This class reuses most of the code of RandomWalk2dMobilityModel,
+ * but adds the awareness of buildings objects which are avoided
+ * by moving users.
+ * Each instance moves with a speed and direction chosen at random
+ * with the user-provided random variables until
+ * either a fixed distance has been walked or until a fixed amount
+ * of time. If we hit one of the boundaries (specified by a rectangle)
+ * of the model, we rebound on the boundary with a reflexive angle
+ * and speed. If we hit one of the buildings, we rebound with a random
+ * direction which makes sure that the next step does not enter the building.
+ *
+ * The default values for the random variable that describes the speed is
+ * taken from Figure 1 in the paper:
+ * Henderson, L.F., 1971. The statistics of crowd fluids. nature, 229(5284), p.381.
+ */
+class RandomWalk2dOutdoorMobilityModel : public MobilityModel
+{
+public:
+ /**
+ * Register this type with the TypeId system.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+ /** An enum representing the different working modes of this module. */
+ enum Mode
+ {
+ MODE_DISTANCE,
+ MODE_TIME
+ };
+
+private:
+ /**
+ * \brief Performs the rebound of the node if it reaches a boundary
+ * \param timeLeft The remaining time of the walk
+ */
+ void Rebound (Time timeLeft);
+ /**
+ * \brief Avoid a building
+ * \param timeLeft The remaining time of the walk
+ * \param intersectPosition The position at which the building is intersected
+ */
+ void AvoidBuilding (Time delayLeft, Vector intersectPosition);
+ /**
+ * Walk according to position and velocity, until distance is reached,
+ * time is reached, or intersection with the bounding box, or building
+ */
+ void DoWalk (Time timeLeft);
+ /**
+ * Perform initialization of the object before MobilityModel::DoInitialize ()
+ */
+ void DoInitializePrivate (void);
+ /**
+ * Check if there is a building between two positions (or if the nextPosition is inside a building).
+ * The code is taken from MmWave3gppBuildingsPropagationLossModel from the NYU/UNIPD ns-3 mmWave module
+ * \param currentPosition The current position of the node
+ * \param nextPosition The position to check
+ * \return a pair with a boolean (true if the line between the two position does not intersect building),
+ * and a pointer which is 0 if the boolean is true, or it points to the building which is intersected
+ */
+ std::pair > IsLineClearOfBuildings (Vector currentPosition, Vector nextPosition ) const;
+ /**
+ * Compute the intersecting point of the box represented by boundaries and the line between current and next
+ * Notice that we only consider a 2d plane
+ * \param current The current position
+ * \param next The next position
+ * \param boundaries The boundaries of the building we will intersect
+ * \return a vector with the position of the intersection
+ */
+ Vector CalculateIntersectionFromOutside (const Vector ¤t, const Vector &next, const Box boundaries) const;
+
+ virtual void DoDispose (void);
+ virtual void DoInitialize (void);
+ virtual Vector DoGetPosition (void) const;
+ virtual void DoSetPosition (const Vector &position);
+ virtual Vector DoGetVelocity (void) const;
+ virtual int64_t DoAssignStreams (int64_t);
+
+ ConstantVelocityHelper m_helper; //!< helper for this object
+ EventId m_event; //!< stored event ID
+ enum Mode m_mode; //!< whether in time or distance mode
+ double m_modeDistance; //!< Change direction and speed after this distance
+ Time m_modeTime; //!< Change current direction and speed after this delay
+ Ptr m_speed; //!< rv for picking speed
+ Ptr m_direction; //!< rv for picking direction
+ Rectangle m_bounds; //!< Bounds of the area to cruise
+ double m_epsilon; //!< Tolerance for the intersection point with buildings
+ uint32_t m_maxIter; //!< Maximum number of tries to find the next position
+ Vector m_prevPosition; //!< Store the previous position in case a step back is needed
+};
+
+
+} // namespace ns3
+
+#endif /* RANDOM_WALK_2D_OUTDOOR_MOBILITY_MODEL_H */
\ No newline at end of file
diff --git a/src/buildings/test/outdoor-random-walk-test.cc b/src/buildings/test/outdoor-random-walk-test.cc
new file mode 100644
index 000000000..6243ab599
--- /dev/null
+++ b/src/buildings/test/outdoor-random-walk-test.cc
@@ -0,0 +1,167 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ns3/abort.h"
+#include "ns3/test.h"
+#include "ns3/config.h"
+#include "ns3/building.h"
+#include "ns3/building-position-allocator.h"
+#include "ns3/random-walk-2d-outdoor-mobility-model.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/pointer.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("OutdoorRandomWalkTest");
+
+/**
+ * Test case for the class OutdoorRandomWalkTestCase. It checks if the
+ * positions visited by the user are outside buildings
+ */
+class OutdoorRandomWalkTestCase : public TestCase
+{
+public:
+ /**
+ * Constructor
+ */
+ OutdoorRandomWalkTestCase ();
+
+ /**
+ * Destructor
+ */
+ virtual ~OutdoorRandomWalkTestCase ();
+
+private:
+ /**
+ * Builds the simulation scenario and perform the tests
+ */
+ virtual void DoRun (void);
+
+ void CheckPositionOutdoor (Ptr model);
+
+ std::vector > m_buildings;
+};
+
+OutdoorRandomWalkTestCase::OutdoorRandomWalkTestCase ()
+ : TestCase ("Test case for the BuildingsChannelConditionModel"), m_buildings ()
+{}
+
+OutdoorRandomWalkTestCase::~OutdoorRandomWalkTestCase ()
+{}
+
+void
+OutdoorRandomWalkTestCase::CheckPositionOutdoor (Ptr model)
+{
+ auto position = model->GetPosition ();
+ for (auto building : m_buildings)
+ {
+ NS_TEST_ASSERT_MSG_EQ (building->IsInside (position), false, "Position " << position << " is inside");
+ }
+}
+
+void
+OutdoorRandomWalkTestCase::DoRun (void)
+{
+ // create a grid of buildings
+ double buildingSizeX = 100; // m
+ double buildingSizeY = 50; // m
+ double streetWidth = 25; // m
+ double buildingHeight = 10; // m
+ uint32_t numBuildingsX = 20;
+ uint32_t numBuildingsY = 20;
+ double maxAxisX = (buildingSizeX + streetWidth) * numBuildingsX;
+ double maxAxisY = (buildingSizeY + streetWidth) * numBuildingsY;
+
+ for (uint32_t buildingIdX = 0; buildingIdX < numBuildingsX; ++buildingIdX)
+ {
+ for (uint32_t buildingIdY = 0; buildingIdY < numBuildingsY; ++buildingIdY)
+ {
+ Ptr < Building > building;
+ building = CreateObject ();
+
+ building->SetBoundaries (Box (buildingIdX * (buildingSizeX + streetWidth),
+ buildingIdX * (buildingSizeX + streetWidth) + buildingSizeX,
+ buildingIdY * (buildingSizeY + streetWidth),
+ buildingIdY * (buildingSizeY + streetWidth) + buildingSizeY,
+ 0.0, buildingHeight));
+ building->SetNRoomsX (1);
+ building->SetNRoomsY (1);
+ building->SetNFloors (1);
+ m_buildings.push_back (building);
+ }
+ }
+
+ // create one node
+ NodeContainer nodes;
+ nodes.Create (1);
+
+ // set the RandomWalk2dOutdoorMobilityModel mobility model
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::RandomWalk2dOutdoorMobilityModel",
+ "Bounds", RectangleValue (
+ Rectangle (-streetWidth, maxAxisX, -streetWidth, maxAxisY)));
+ // create an OutdoorPositionAllocator and set its boundaries to match those of the mobility model
+ Ptr position = CreateObject ();
+ Ptr xPos = CreateObject();
+ xPos->SetAttribute ("Min", DoubleValue (-streetWidth));
+ xPos->SetAttribute ("Max", DoubleValue (maxAxisX));
+ Ptr yPos = CreateObject();
+ yPos->SetAttribute ("Min", DoubleValue (-streetWidth));
+ yPos->SetAttribute ("Max", DoubleValue (maxAxisY));
+ position->SetAttribute ("X", PointerValue (xPos));
+ position->SetAttribute ("Y", PointerValue (yPos));
+ mobility.SetPositionAllocator (position);
+ // install the mobility model
+ mobility.Install (nodes.Get (0));
+
+ auto mobilityModel = nodes.Get (0)->GetObject();
+
+ // get maxChecks positions, check if they are outdoors
+ double testStep = 10; // s
+ int maxChecks = 1000;
+ for (int i = 0; i < maxChecks; ++i)
+ {
+ Simulator::Schedule (Seconds (i * testStep),
+ &OutdoorRandomWalkTestCase::CheckPositionOutdoor, this, mobilityModel);
+ }
+
+ Simulator::Stop (Seconds (maxChecks * testStep + 1));
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
+
+/**
+ * Test suite for the buildings channel condition model
+ */
+class OutdoorRandomWalkTestSuite : public TestSuite
+{
+public:
+ OutdoorRandomWalkTestSuite ();
+};
+
+OutdoorRandomWalkTestSuite::OutdoorRandomWalkTestSuite ()
+ : TestSuite ("outdoor-random-walk-model", UNIT)
+{
+ AddTestCase (new OutdoorRandomWalkTestCase, TestCase::QUICK);
+}
+
+static OutdoorRandomWalkTestSuite OutdoorRandomWalkTestSuite;
diff --git a/src/buildings/wscript b/src/buildings/wscript
index 6a7c356b4..7309429e8 100644
--- a/src/buildings/wscript
+++ b/src/buildings/wscript
@@ -16,6 +16,7 @@ def build(bld):
'helper/building-position-allocator.cc',
'helper/building-allocator.cc',
'helper/buildings-helper.cc',
+ 'model/random-walk-2d-outdoor-mobility-model.cc',
]
module_test = bld.create_ns3_module_test_library('buildings')
@@ -25,6 +26,7 @@ def build(bld):
'test/buildings-pathloss-test.cc',
'test/buildings-shadowing-test.cc',
'test/buildings-channel-condition-model-test.cc',
+ 'test/outdoor-random-walk-test.cc',
]
# Tests encapsulating example programs should be listed here
@@ -48,6 +50,7 @@ def build(bld):
'helper/building-allocator.h',
'helper/building-position-allocator.h',
'helper/buildings-helper.h',
+ 'model/random-walk-2d-outdoor-mobility-model.h',
]
if (bld.env['ENABLE_EXAMPLES']):