859 lines
28 KiB
C++
859 lines
28 KiB
C++
/*
|
|
* Copyright (c) 2007 INRIA
|
|
* 2009,2010 Contributors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*
|
|
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
|
* Contributors: Thomas Waldecker <twaldecker@rocketmail.com>
|
|
* Martín Giachino <martin.giachino@gmail.com>
|
|
*
|
|
* Brief description: Implementation of a ns2 movement trace file reader.
|
|
*
|
|
* This implementation is based on the ns2 movement documentation of ns2
|
|
* as described in http://www.isi.edu/nsnam/ns/doc/node172.html
|
|
*
|
|
* Valid trace files use the following ns2 statements:
|
|
*
|
|
* $node set X_ x1
|
|
* $node set Y_ y1
|
|
* $node set Z_ z1
|
|
* $ns at $time $node setdest x2 y2 speed
|
|
* $ns at $time $node set X_ x1
|
|
* $ns at $time $node set Y_ Y1
|
|
* $ns at $time $node set Z_ Z1
|
|
*
|
|
*/
|
|
|
|
#include "ns2-mobility-helper.h"
|
|
|
|
#include "ns3/constant-velocity-mobility-model.h"
|
|
#include "ns3/log.h"
|
|
#include "ns3/node-list.h"
|
|
#include "ns3/node.h"
|
|
#include "ns3/simulator.h"
|
|
|
|
#include <fstream>
|
|
#include <map>
|
|
#include <sstream>
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("Ns2MobilityHelper");
|
|
|
|
// Constants definitions
|
|
#define NS2_AT "at"
|
|
#define NS2_X_COORD "X_"
|
|
#define NS2_Y_COORD "Y_"
|
|
#define NS2_Z_COORD "Z_"
|
|
#define NS2_SETDEST "setdest"
|
|
#define NS2_SET "set"
|
|
#define NS2_NS_SCH "$ns_"
|
|
|
|
/**
|
|
* Type to maintain line parsed and its values
|
|
*/
|
|
struct ParseResult
|
|
{
|
|
std::vector<std::string> tokens; //!< tokens from a line
|
|
std::vector<int> ivals; //!< int values for each tokens
|
|
std::vector<bool> has_ival; //!< points if a tokens has an int value
|
|
std::vector<double> dvals; //!< double values for each tokens
|
|
std::vector<bool> has_dval; //!< points if a tokens has a double value
|
|
std::vector<std::string> svals; //!< string value for each token
|
|
};
|
|
|
|
/**
|
|
* Keeps last movement schedule. If new movement occurs during
|
|
* a current one, node stopping must be cancels (stored in a proper
|
|
* event ID), actually reached point must be calculated and new
|
|
* velocity must be calculated in accordance with actually reached
|
|
* destination.
|
|
*/
|
|
struct DestinationPoint
|
|
{
|
|
Vector m_startPosition; //!< Start position of last movement
|
|
Vector m_speed; //!< Speed of the last movement (needed to derive reached destination at next
|
|
//!< schedule = start + velocity * actuallyTravelled)
|
|
Vector m_finalPosition; //!< Final destination to be reached before next schedule. Replaced with
|
|
//!< actually reached if needed.
|
|
EventId m_stopEvent; //!< Event scheduling node's stop. May be canceled if needed.
|
|
double m_travelStartTime; //!< Travel start time is needed to calculate actually traveled time
|
|
double m_targetArrivalTime; //!< When a station arrives to a destination
|
|
|
|
DestinationPoint()
|
|
: m_startPosition(Vector(0, 0, 0)),
|
|
m_speed(Vector(0, 0, 0)),
|
|
m_finalPosition(Vector(0, 0, 0)),
|
|
m_travelStartTime(0),
|
|
m_targetArrivalTime(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Parses a line of ns2 mobility
|
|
* @param str the string to parse
|
|
* @returns The parsed line
|
|
*/
|
|
static ParseResult ParseNs2Line(const std::string& str);
|
|
|
|
/**
|
|
* Put out blank spaces at the start and end of a line
|
|
* @param str input line
|
|
* @returns the line trimmed
|
|
*/
|
|
static std::string TrimNs2Line(const std::string& str);
|
|
|
|
/**
|
|
* Checks if a string represents a number or it has others characters than digits and point.
|
|
* @param s the string to check
|
|
* @returns true if the string represents a number
|
|
*/
|
|
static bool IsNumber(const std::string& s);
|
|
|
|
/**
|
|
* Check if s string represents a numeric value
|
|
* @param str string to check
|
|
* @param ret numeric value to return
|
|
* @return true if string represents a numeric value
|
|
*/
|
|
template <class T>
|
|
static bool IsVal(const std::string& str, T& ret);
|
|
|
|
/**
|
|
* Checks if the value between brackets is a correct nodeId number
|
|
* @param str string to check
|
|
* @returns true if the string represents a nodeId number
|
|
*/
|
|
static bool HasNodeIdNumber(std::string str);
|
|
|
|
/**
|
|
* Gets nodeId number in string format from the string like $node_(4)
|
|
* @param str string to de-tokenize
|
|
* @returns A string with the nodeId number
|
|
*/
|
|
static std::string GetNodeIdFromToken(std::string str);
|
|
|
|
/**
|
|
* Get node id number in int format
|
|
* @param pr the ParseResult to analyze
|
|
* @returns the node ID (as an int)
|
|
*/
|
|
static int GetNodeIdInt(ParseResult pr);
|
|
|
|
/**
|
|
* Get node id number in string format
|
|
* @param pr the ParseResult to analyze
|
|
* @returns the node ID (as a string)
|
|
*/
|
|
static std::string GetNodeIdString(ParseResult pr);
|
|
|
|
/**
|
|
* Add one coord to a vector position
|
|
* @param actPos actual position (overwritten)
|
|
* @param coord coordinate (x, y, or z)
|
|
* @param value value of the coordinate
|
|
* @return The vector of the position
|
|
*/
|
|
static Vector SetOneInitialCoord(Vector actPos, std::string& coord, double value);
|
|
|
|
/**
|
|
* Check if this corresponds to a line like this: $node_(0) set X_ 123
|
|
* @param pr the ParseResult to analyze
|
|
* @returns true if the ParseResult looks like a coordinate without a scheduled time
|
|
*/
|
|
static bool IsSetInitialPos(ParseResult pr);
|
|
|
|
/**
|
|
* Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) setdest 2 3 4"
|
|
* @param pr the ParseResult to analyze
|
|
* @returns true if the ParseResult looks like a coordinate with a scheduled time and destination
|
|
*/
|
|
static bool IsSchedSetPos(ParseResult pr);
|
|
|
|
/**
|
|
* Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) set X_ 2"
|
|
* @param pr the ParseResult to analyze
|
|
* @returns true if the ParseResult looks like a coordinate with a scheduled time
|
|
*/
|
|
static bool IsSchedMobilityPos(ParseResult pr);
|
|
|
|
/**
|
|
* Set waypoints and speed for movement.
|
|
* @param model mobility model
|
|
* @param lastPos last position
|
|
* @param at initial movement time
|
|
* @param xFinalPosition final position (X axis)
|
|
* @param yFinalPosition final position (Y axis)
|
|
* @param speed movement speed
|
|
* @returns A descriptor of the movement
|
|
*/
|
|
static DestinationPoint SetMovement(Ptr<ConstantVelocityMobilityModel> model,
|
|
Vector lastPos,
|
|
double at,
|
|
double xFinalPosition,
|
|
double yFinalPosition,
|
|
double speed);
|
|
|
|
/**
|
|
* Set initial position for a node
|
|
* @param model mobility model
|
|
* @param coord coordinate (x, y, or z)
|
|
* @param coordVal value of the coordinate
|
|
* @return The vector of the position
|
|
*/
|
|
static Vector SetInitialPosition(Ptr<ConstantVelocityMobilityModel> model,
|
|
std::string coord,
|
|
double coordVal);
|
|
|
|
/**
|
|
* Schedule a set of position for a node
|
|
* @param model mobility model
|
|
* @param at initial movement time
|
|
* @param coord coordinate (x, y, or z)
|
|
* @param coordVal value of the coordinate
|
|
* @return The vector of the position at the given time
|
|
*/
|
|
static Vector SetSchedPosition(Ptr<ConstantVelocityMobilityModel> model,
|
|
double at,
|
|
std::string coord,
|
|
double coordVal);
|
|
|
|
Ns2MobilityHelper::Ns2MobilityHelper(std::string filename)
|
|
: m_filename(filename)
|
|
{
|
|
std::ifstream file(m_filename, std::ios::in);
|
|
if (!(file.is_open()))
|
|
{
|
|
NS_FATAL_ERROR("Could not open trace file " << m_filename
|
|
<< " for reading, aborting here \n");
|
|
}
|
|
}
|
|
|
|
Ptr<ConstantVelocityMobilityModel>
|
|
Ns2MobilityHelper::GetMobilityModel(std::string idString, const ObjectStore& store) const
|
|
{
|
|
std::istringstream iss;
|
|
iss.str(idString);
|
|
uint32_t id(0);
|
|
iss >> id;
|
|
Ptr<Object> object = store.Get(id);
|
|
if (!object)
|
|
{
|
|
return nullptr;
|
|
}
|
|
Ptr<ConstantVelocityMobilityModel> model = object->GetObject<ConstantVelocityMobilityModel>();
|
|
if (!model)
|
|
{
|
|
model = CreateObject<ConstantVelocityMobilityModel>();
|
|
object->AggregateObject(model);
|
|
}
|
|
return model;
|
|
}
|
|
|
|
void
|
|
Ns2MobilityHelper::ConfigNodesMovements(const ObjectStore& store) const
|
|
{
|
|
std::map<int, DestinationPoint> last_pos; // Stores previous movement scheduled for each node
|
|
|
|
//*****************************************************************
|
|
// Parse the file the first time to get the initial node positions.
|
|
//*****************************************************************
|
|
|
|
// Look through the whole the file for the the initial node
|
|
// positions to make this helper robust to handle trace files with
|
|
// the initial node positions at the end.
|
|
std::ifstream file(m_filename, std::ios::in);
|
|
if (file.is_open())
|
|
{
|
|
while (!file.eof())
|
|
{
|
|
int iNodeId = 0;
|
|
std::string nodeId;
|
|
std::string line;
|
|
|
|
getline(file, line);
|
|
|
|
// ignore empty lines
|
|
if (line.empty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ParseResult pr = ParseNs2Line(line); // Parse line and obtain tokens
|
|
|
|
// Check if the line corresponds with setting the initial
|
|
// node positions
|
|
if (pr.tokens.size() != 4)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Get the node Id
|
|
nodeId = GetNodeIdString(pr);
|
|
iNodeId = GetNodeIdInt(pr);
|
|
if (iNodeId == -1)
|
|
{
|
|
NS_LOG_ERROR("Node number couldn't be obtained (corrupted file?): " << line
|
|
<< "\n");
|
|
continue;
|
|
}
|
|
|
|
// get mobility model of node
|
|
Ptr<ConstantVelocityMobilityModel> model = GetMobilityModel(nodeId, store);
|
|
|
|
// if model not exists, continue
|
|
if (!model)
|
|
{
|
|
NS_LOG_ERROR("Unknown node ID (corrupted file?): " << nodeId << "\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* In this case a initial position is being seted
|
|
* line like $node_(0) set X_ 151.05190721688197
|
|
*/
|
|
if (IsSetInitialPos(pr))
|
|
{
|
|
DestinationPoint point;
|
|
// coord coord value
|
|
point.m_finalPosition = SetInitialPosition(model, pr.tokens[2], pr.dvals[3]);
|
|
last_pos[iNodeId] = point;
|
|
|
|
// Log new position
|
|
NS_LOG_DEBUG("Positions after parse for node "
|
|
<< iNodeId << " " << nodeId
|
|
<< " position = " << last_pos[iNodeId].m_finalPosition);
|
|
}
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
//*****************************************************************
|
|
// Parse the file a second time to get the rest of its values
|
|
//*****************************************************************
|
|
|
|
// The reason the file is parsed again is to make this helper robust
|
|
// to handle trace files with the initial node positions at the end.
|
|
file.open(m_filename, std::ios::in);
|
|
if (file.is_open())
|
|
{
|
|
while (!file.eof())
|
|
{
|
|
int iNodeId = 0;
|
|
std::string nodeId;
|
|
std::string line;
|
|
|
|
getline(file, line);
|
|
|
|
// ignore empty lines
|
|
if (line.empty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ParseResult pr = ParseNs2Line(line); // Parse line and obtain tokens
|
|
|
|
// Check if the line corresponds with one of the three types of line
|
|
if (pr.tokens.size() != 4 && pr.tokens.size() != 7 && pr.tokens.size() != 8)
|
|
{
|
|
NS_LOG_ERROR("Line has not correct number of parameters (corrupted file?): "
|
|
<< line << "\n");
|
|
continue;
|
|
}
|
|
|
|
// Get the node Id
|
|
nodeId = GetNodeIdString(pr);
|
|
iNodeId = GetNodeIdInt(pr);
|
|
if (iNodeId == -1)
|
|
{
|
|
NS_LOG_ERROR("Node number couldn't be obtained (corrupted file?): " << line
|
|
<< "\n");
|
|
continue;
|
|
}
|
|
|
|
// get mobility model of node
|
|
Ptr<ConstantVelocityMobilityModel> model = GetMobilityModel(nodeId, store);
|
|
|
|
// if model not exists, continue
|
|
if (!model)
|
|
{
|
|
NS_LOG_ERROR("Unknown node ID (corrupted file?): " << nodeId << "\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* In this case a initial position is being seted
|
|
* line like $node_(0) set X_ 151.05190721688197
|
|
*/
|
|
if (IsSetInitialPos(pr))
|
|
{
|
|
// This is the second time this file has been parsed,
|
|
// and the initial node positions were already set the
|
|
// first time. So, do nothing this time with this line.
|
|
continue;
|
|
}
|
|
|
|
else // NOW EVENTS TO BE SCHEDULED
|
|
{
|
|
// This is a scheduled event, so time at should be present
|
|
double at;
|
|
|
|
if (!IsNumber(pr.tokens[2]))
|
|
{
|
|
NS_LOG_WARN("Time is not a number: " << pr.tokens[2]);
|
|
continue;
|
|
}
|
|
|
|
at = pr.dvals[2]; // set time at
|
|
|
|
if (at < 0)
|
|
{
|
|
NS_LOG_WARN("Time is less than cero: " << at);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* In this case a new waypoint is added
|
|
* line like $ns_ at 1 "$node_(0) setdest 2 3 4"
|
|
*/
|
|
if (IsSchedMobilityPos(pr))
|
|
{
|
|
if (last_pos[iNodeId].m_targetArrivalTime > at)
|
|
{
|
|
NS_LOG_LOGIC("Did not reach a destination! stoptime = "
|
|
<< last_pos[iNodeId].m_targetArrivalTime << ", at = " << at);
|
|
double actuallytraveled = at - last_pos[iNodeId].m_travelStartTime;
|
|
Vector reached = Vector(last_pos[iNodeId].m_startPosition.x +
|
|
last_pos[iNodeId].m_speed.x * actuallytraveled,
|
|
last_pos[iNodeId].m_startPosition.y +
|
|
last_pos[iNodeId].m_speed.y * actuallytraveled,
|
|
0);
|
|
NS_LOG_LOGIC("Final point = " << last_pos[iNodeId].m_finalPosition
|
|
<< ", actually reached = " << reached);
|
|
last_pos[iNodeId].m_stopEvent.Cancel();
|
|
last_pos[iNodeId].m_finalPosition = reached;
|
|
}
|
|
// last position time X coord Y
|
|
// coord velocity
|
|
last_pos[iNodeId] = SetMovement(model,
|
|
last_pos[iNodeId].m_finalPosition,
|
|
at,
|
|
pr.dvals[5],
|
|
pr.dvals[6],
|
|
pr.dvals[7]);
|
|
|
|
// Log new position
|
|
NS_LOG_DEBUG("Positions after parse for node "
|
|
<< iNodeId << " " << nodeId
|
|
<< " position =" << last_pos[iNodeId].m_finalPosition);
|
|
}
|
|
|
|
/*
|
|
* Scheduled set position
|
|
* line like $ns_ at 4.634906291962 "$node_(0) set X_ 28.675920486450"
|
|
*/
|
|
else if (IsSchedSetPos(pr))
|
|
{
|
|
// time coordinate coord value
|
|
last_pos[iNodeId].m_finalPosition =
|
|
SetSchedPosition(model, at, pr.tokens[5], pr.dvals[6]);
|
|
if (last_pos[iNodeId].m_targetArrivalTime > at)
|
|
{
|
|
last_pos[iNodeId].m_stopEvent.Cancel();
|
|
}
|
|
last_pos[iNodeId].m_targetArrivalTime = at;
|
|
last_pos[iNodeId].m_travelStartTime = at;
|
|
// Log new position
|
|
NS_LOG_DEBUG("Positions after parse for node "
|
|
<< iNodeId << " " << nodeId
|
|
<< " position =" << last_pos[iNodeId].m_finalPosition);
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_WARN("Format Line is not correct: " << line << "\n");
|
|
}
|
|
}
|
|
}
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
ParseResult
|
|
ParseNs2Line(const std::string& str)
|
|
{
|
|
ParseResult ret;
|
|
std::istringstream s;
|
|
std::string line;
|
|
|
|
// ignore comments (#)
|
|
size_t pos_sharp = str.find_first_of('#');
|
|
if (pos_sharp != std::string::npos)
|
|
{
|
|
line = str.substr(0, pos_sharp);
|
|
}
|
|
else
|
|
{
|
|
line = str;
|
|
}
|
|
|
|
line = TrimNs2Line(line);
|
|
|
|
// If line hasn't a correct node Id
|
|
if (!HasNodeIdNumber(line))
|
|
{
|
|
NS_LOG_WARN("Line has no node Id: " << line);
|
|
return ret;
|
|
}
|
|
|
|
s.str(line);
|
|
|
|
while (!s.eof())
|
|
{
|
|
std::string x;
|
|
s >> x;
|
|
if (x.empty())
|
|
{
|
|
continue;
|
|
}
|
|
ret.tokens.push_back(x);
|
|
int ii(0);
|
|
double d(0);
|
|
if (HasNodeIdNumber(x))
|
|
{
|
|
x = GetNodeIdFromToken(x);
|
|
}
|
|
ret.has_ival.push_back(IsVal<int>(x, ii));
|
|
ret.ivals.push_back(ii);
|
|
ret.has_dval.push_back(IsVal<double>(x, d));
|
|
ret.dvals.push_back(d);
|
|
ret.svals.push_back(x);
|
|
}
|
|
|
|
size_t tokensLength = ret.tokens.size(); // number of tokens in line
|
|
size_t lasTokenLength = ret.tokens[tokensLength - 1].size(); // length of the last token
|
|
|
|
// if it is a scheduled set _[XYZ] or a setdest I need to remove the last "
|
|
// and re-calculate values
|
|
if ((tokensLength == 7 || tokensLength == 8) &&
|
|
(ret.tokens[tokensLength - 1][lasTokenLength - 1] == '"'))
|
|
{
|
|
// removes " from the last position
|
|
ret.tokens[tokensLength - 1] = ret.tokens[tokensLength - 1].substr(0, lasTokenLength - 1);
|
|
|
|
std::string x;
|
|
x = ret.tokens[tokensLength - 1];
|
|
|
|
if (HasNodeIdNumber(x))
|
|
{
|
|
x = GetNodeIdFromToken(x);
|
|
}
|
|
|
|
// Re calculate values
|
|
int ii(0);
|
|
double d(0);
|
|
ret.has_ival[tokensLength - 1] = IsVal<int>(x, ii);
|
|
ret.ivals[tokensLength - 1] = ii;
|
|
ret.has_dval[tokensLength - 1] = IsVal<double>(x, d);
|
|
ret.dvals[tokensLength - 1] = d;
|
|
ret.svals[tokensLength - 1] = x;
|
|
}
|
|
else if ((tokensLength == 9 && ret.tokens[tokensLength - 1] == "\"") ||
|
|
(tokensLength == 8 && ret.tokens[tokensLength - 1] == "\""))
|
|
{
|
|
// if the line has the " character in this way: $ns_ at 1 "$node_(0) setdest 2 2 1 "
|
|
// or in this: $ns_ at 4 "$node_(0) set X_ 2 " we need to ignore this last token
|
|
|
|
ret.tokens.erase(ret.tokens.begin() + tokensLength - 1);
|
|
ret.has_ival.erase(ret.has_ival.begin() + tokensLength - 1);
|
|
ret.ivals.erase(ret.ivals.begin() + tokensLength - 1);
|
|
ret.has_dval.erase(ret.has_dval.begin() + tokensLength - 1);
|
|
ret.dvals.erase(ret.dvals.begin() + tokensLength - 1);
|
|
ret.svals.erase(ret.svals.begin() + tokensLength - 1);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::string
|
|
TrimNs2Line(const std::string& s)
|
|
{
|
|
std::string ret = s;
|
|
|
|
while (!ret.empty() && isblank(ret[0]))
|
|
{
|
|
ret.erase(0, 1); // Removes blank spaces at the beginning of the line
|
|
}
|
|
|
|
while (!ret.empty() && (isblank(ret[ret.size() - 1]) || (ret[ret.size() - 1] == ';')))
|
|
{
|
|
ret.erase(ret.size() - 1, 1); // Removes blank spaces from at end of line
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
IsNumber(const std::string& s)
|
|
{
|
|
char* endp;
|
|
strtod(s.c_str(), &endp);
|
|
return endp == s.c_str() + s.size();
|
|
}
|
|
|
|
template <class T>
|
|
bool
|
|
IsVal(const std::string& str, T& ret)
|
|
{
|
|
if (str.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsNumber(str))
|
|
{
|
|
std::istringstream s(str);
|
|
s >> ret;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
HasNodeIdNumber(std::string str)
|
|
{
|
|
// find brackets
|
|
std::string::size_type startNodeId = str.find_first_of('('); // index of left bracket
|
|
std::string::size_type endNodeId = str.find_first_of(')'); // index of right bracket
|
|
|
|
// Get de nodeId in a string and in a int value
|
|
std::string nodeId; // node id
|
|
|
|
// if no brackets, continue!
|
|
if (startNodeId == std::string::npos || endNodeId == std::string::npos)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
nodeId = str.substr(startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
|
|
|
|
// is number is integer is not negative
|
|
return IsNumber(nodeId) && nodeId.find_first_of('.') == std::string::npos && nodeId[0] != '-';
|
|
}
|
|
|
|
std::string
|
|
GetNodeIdFromToken(std::string str)
|
|
{
|
|
if (HasNodeIdNumber(str))
|
|
{
|
|
// find brackets
|
|
std::string::size_type startNodeId = str.find_first_of('('); // index of left bracket
|
|
std::string::size_type endNodeId = str.find_first_of(')'); // index of right bracket
|
|
|
|
return str.substr(startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
|
|
}
|
|
else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
int
|
|
GetNodeIdInt(ParseResult pr)
|
|
{
|
|
int result = -1;
|
|
switch (pr.tokens.size())
|
|
{
|
|
case 4: // line like $node_(0) set X_ 11
|
|
result = pr.ivals[0];
|
|
break;
|
|
case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
|
|
case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
|
|
result = pr.ivals[3];
|
|
break;
|
|
default:
|
|
result = -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Get node id number in string format
|
|
std::string
|
|
GetNodeIdString(ParseResult pr)
|
|
{
|
|
switch (pr.tokens.size())
|
|
{
|
|
case 4: // line like $node_(0) set X_ 11
|
|
return pr.svals[0];
|
|
case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
|
|
case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
|
|
return pr.svals[3];
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
Vector
|
|
SetOneInitialCoord(Vector position, std::string& coord, double value)
|
|
{
|
|
// set the position for the coord.
|
|
if (coord == NS2_X_COORD)
|
|
{
|
|
position.x = value;
|
|
NS_LOG_DEBUG("X=" << value);
|
|
}
|
|
else if (coord == NS2_Y_COORD)
|
|
{
|
|
position.y = value;
|
|
NS_LOG_DEBUG("Y=" << value);
|
|
}
|
|
else if (coord == NS2_Z_COORD)
|
|
{
|
|
position.z = value;
|
|
NS_LOG_DEBUG("Z=" << value);
|
|
}
|
|
return position;
|
|
}
|
|
|
|
bool
|
|
IsSetInitialPos(ParseResult pr)
|
|
{
|
|
// number of tokens has $node_( ? has "set" has
|
|
// double for position?
|
|
return pr.tokens.size() == 4 && HasNodeIdNumber(pr.tokens[0]) && pr.tokens[1] == NS2_SET &&
|
|
pr.has_dval[3]
|
|
// coord name is X_, Y_ or Z_ ?
|
|
&& (pr.tokens[2] == NS2_X_COORD || pr.tokens[2] == NS2_Y_COORD ||
|
|
pr.tokens[2] == NS2_Z_COORD);
|
|
}
|
|
|
|
bool
|
|
IsSchedSetPos(ParseResult pr)
|
|
{
|
|
// correct number of tokens, has $ns_ and at
|
|
return pr.tokens.size() == 7 && pr.tokens[0] == NS2_NS_SCH && pr.tokens[1] == NS2_AT &&
|
|
pr.tokens[4] == NS2_SET && pr.has_dval[2] &&
|
|
pr.has_dval[3] // has set and double value for time and nodeid
|
|
&& (pr.tokens[5] == NS2_X_COORD || pr.tokens[5] == NS2_Y_COORD ||
|
|
pr.tokens[5] == NS2_Z_COORD) // has X_, Y_ or Z_?
|
|
&& pr.has_dval[2]; // time is a number
|
|
}
|
|
|
|
bool
|
|
IsSchedMobilityPos(ParseResult pr)
|
|
{
|
|
// number of tokens and has $ns_ and has at
|
|
return pr.tokens.size() == 8 && pr.tokens[0] == NS2_NS_SCH &&
|
|
pr.tokens[1] == NS2_AT
|
|
// time x coord y coord velocity are numbers?
|
|
&& pr.has_dval[2] && pr.has_dval[5] && pr.has_dval[6] && pr.has_dval[7] &&
|
|
pr.tokens[4] == NS2_SETDEST; // and has setdest
|
|
}
|
|
|
|
DestinationPoint
|
|
SetMovement(Ptr<ConstantVelocityMobilityModel> model,
|
|
Vector last_pos,
|
|
double at,
|
|
double xFinalPosition,
|
|
double yFinalPosition,
|
|
double speed)
|
|
{
|
|
DestinationPoint retval;
|
|
retval.m_startPosition = last_pos;
|
|
retval.m_finalPosition = last_pos;
|
|
retval.m_travelStartTime = at;
|
|
retval.m_targetArrivalTime = at;
|
|
|
|
if (speed == 0)
|
|
{
|
|
// We have to maintain last position, and stop the movement
|
|
retval.m_stopEvent = Simulator::Schedule(Seconds(at),
|
|
&ConstantVelocityMobilityModel::SetVelocity,
|
|
model,
|
|
Vector(0, 0, 0));
|
|
return retval;
|
|
}
|
|
if (speed > 0)
|
|
{
|
|
// first calculate the time; time = distance / speed
|
|
double time = std::sqrt(std::pow(xFinalPosition - retval.m_finalPosition.x, 2) +
|
|
std::pow(yFinalPosition - retval.m_finalPosition.y, 2)) /
|
|
speed;
|
|
NS_LOG_DEBUG("at=" << at << " time=" << time);
|
|
if (time == 0)
|
|
{
|
|
return retval;
|
|
}
|
|
// now calculate the xSpeed = distance / time
|
|
double xSpeed = (xFinalPosition - retval.m_finalPosition.x) / time;
|
|
double ySpeed = (yFinalPosition - retval.m_finalPosition.y) / time; // & same with ySpeed
|
|
retval.m_speed = Vector(xSpeed, ySpeed, 0);
|
|
|
|
// quick and dirty set zSpeed = 0
|
|
double zSpeed = 0;
|
|
|
|
NS_LOG_DEBUG("Calculated Speed: X=" << xSpeed << " Y=" << ySpeed << " Z=" << zSpeed);
|
|
|
|
// Set the Values
|
|
Simulator::Schedule(Seconds(at),
|
|
&ConstantVelocityMobilityModel::SetVelocity,
|
|
model,
|
|
Vector(xSpeed, ySpeed, zSpeed));
|
|
retval.m_stopEvent = Simulator::Schedule(Seconds(at + time),
|
|
&ConstantVelocityMobilityModel::SetVelocity,
|
|
model,
|
|
Vector(0, 0, 0));
|
|
retval.m_finalPosition.x += xSpeed * time;
|
|
retval.m_finalPosition.y += ySpeed * time;
|
|
retval.m_targetArrivalTime += time;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
Vector
|
|
SetInitialPosition(Ptr<ConstantVelocityMobilityModel> model, std::string coord, double coordVal)
|
|
{
|
|
model->SetPosition(SetOneInitialCoord(model->GetPosition(), coord, coordVal));
|
|
|
|
Vector position;
|
|
position.x = model->GetPosition().x;
|
|
position.y = model->GetPosition().y;
|
|
position.z = model->GetPosition().z;
|
|
|
|
return position;
|
|
}
|
|
|
|
// Schedule a set of position for a node
|
|
Vector
|
|
SetSchedPosition(Ptr<ConstantVelocityMobilityModel> model,
|
|
double at,
|
|
std::string coord,
|
|
double coordVal)
|
|
{
|
|
// update position
|
|
model->SetPosition(SetOneInitialCoord(model->GetPosition(), coord, coordVal));
|
|
|
|
Vector position;
|
|
position.x = model->GetPosition().x;
|
|
position.y = model->GetPosition().y;
|
|
position.z = model->GetPosition().z;
|
|
|
|
// Schedule next positions
|
|
Simulator::Schedule(Seconds(at), &ConstantVelocityMobilityModel::SetPosition, model, position);
|
|
|
|
return position;
|
|
}
|
|
|
|
void
|
|
Ns2MobilityHelper::Install() const
|
|
{
|
|
Install(NodeList::Begin(), NodeList::End());
|
|
}
|
|
|
|
} // namespace ns3
|