A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ns2-mobility-helper.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 INRIA
4  * 2009,2010 Contributors
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  * Contributors: Thomas Waldecker <twaldecker@rocketmail.com>
21  * Martín Giachino <martin.giachino@gmail.com>
22  *
23  * Brief description: Implementation of a ns2 movement trace file reader.
24  *
25  * This implementation is based on the ns2 movement documentation of ns2
26  * as described in http://www.isi.edu/nsnam/ns/doc/node172.html
27  *
28  * Valid trace files use the following ns2 statements:
29  *
30  * $node set X_ x1
31  * $node set Y_ y1
32  * $node set Z_ z1
33  * $ns at $time $node setdest x2 y2 speed
34  * $ns at $time $node set X_ x1
35  * $ns at $time $node set Y_ Y1
36  * $ns at $time $node set Z_ Z1
37  *
38  */
39 
40 
41 #include <fstream>
42 #include <sstream>
43 #include <map>
44 #include "ns3/log.h"
45 #include "ns3/unused.h"
46 #include "ns3/simulator.h"
47 #include "ns3/node-list.h"
48 #include "ns3/node.h"
49 #include "ns3/constant-velocity-mobility-model.h"
50 #include "ns2-mobility-helper.h"
51 
52 NS_LOG_COMPONENT_DEFINE ("Ns2MobilityHelper");
53 
54 using namespace std;
55 
56 namespace ns3 {
57 
58 // Constants definitions
59 #define NS2_AT "at"
60 #define NS2_X_COORD "X_"
61 #define NS2_Y_COORD "Y_"
62 #define NS2_Z_COORD "Z_"
63 #define NS2_SETDEST "setdest"
64 #define NS2_SET "set"
65 #define NS2_NODEID "$node_("
66 #define NS2_NS_SCH "$ns_"
67 
68 
69 // Type to maintain line parsed and its values
71 {
72  vector<string> tokens; // tokens from a line
73  vector<int> ivals; // int values for each tokens
74  vector<bool> has_ival; // points if a tokens has an int value
75  vector<double> dvals; // double values for each tokens
76  vector<bool> has_dval; // points if a tokens has a double value
77  vector<string> svals; // string value for each token
78 };
87 {
88  Vector m_startPosition; // Start position of last movement
89  Vector m_speed; // Speed of the last movement (needed to derive reached destination at next schedule = start + velocity * actuallyTravelled)
90  Vector m_finalPosition; // Final destination to be reached before next schedule. Replaced with actually reached if needed.
91  EventId m_stopEvent; // Event scheduling node's stop. May be canceled if needed.
92  double m_travelStartTime; // Travel start time is needed to calculate actually traveled time
93  double m_targetArrivalTime; // When a station arrives to a destination
95  m_startPosition (Vector (0,0,0)),
96  m_speed (Vector (0,0,0)),
97  m_finalPosition (Vector (0,0,0)),
98  m_travelStartTime (0),
99  m_targetArrivalTime (0)
100  {};
101 };
102 
103 
104 // Parses a line of ns2 mobility
105 static ParseResult ParseNs2Line (const string& str);
106 
107 // Put out blank spaces at the start and end of a line
108 static string TrimNs2Line (const string& str);
109 
110 // Checks if a string represents a number or it has others characters than digits an point.
111 static bool IsNumber (const string& s);
112 
113 // Check if s string represents a numeric value
114 template<class T>
115 static bool IsVal (const string& str, T& ret);
116 
117 // Checks if the value between brackets is a correct nodeId number
118 static bool HasNodeIdNumber (string str);
119 
120 // Gets nodeId number in string format from the string like $node_(4)
121 static string GetNodeIdFromToken (string str);
122 
123 // Get node id number in int format
124 static int GetNodeIdInt (ParseResult pr);
125 
126 // Get node id number in string format
127 static string GetNodeIdString (ParseResult pr);
128 
129 // Add one coord to a vector position
130 static Vector SetOneInitialCoord (Vector actPos, string& coord, double value);
131 
132 // Check if this corresponds to a line like this: $node_(0) set X_ 123
133 static bool IsSetInitialPos (ParseResult pr);
134 
135 // Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) setdest 2 3 4"
136 static bool IsSchedSetPos (ParseResult pr);
137 
138 // Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) set X_ 2"
139 static bool IsSchedMobilityPos (ParseResult pr);
140 
141 // Set waypoints and speed for movement.
142 static DestinationPoint SetMovement (Ptr<ConstantVelocityMobilityModel> model, Vector lastPos, double at,
143  double xFinalPosition, double yFinalPosition, double speed);
144 
145 // Set initial position for a node
146 static Vector SetInitialPosition (Ptr<ConstantVelocityMobilityModel> model, string coord, double coordVal);
147 
148 // Schedule a set of position for a node
149 static Vector SetSchedPosition (Ptr<ConstantVelocityMobilityModel> model, double at, string coord, double coordVal);
150 
151 
152 Ns2MobilityHelper::Ns2MobilityHelper (std::string filename)
153  : m_filename (filename)
154 {
155  std::ifstream file (m_filename.c_str (), std::ios::in);
156  if (!(file.is_open ())) NS_FATAL_ERROR("Could not open trace file " << m_filename.c_str() << " for reading, aborting here \n");
157 }
158 
160 Ns2MobilityHelper::GetMobilityModel (std::string idString, const ObjectStore &store) const
161 {
162  std::istringstream iss;
163  iss.str (idString);
164  uint32_t id (0);
165  iss >> id;
166  Ptr<Object> object = store.Get (id);
167  if (object == 0)
168  {
169  return 0;
170  }
172  if (model == 0)
173  {
174  model = CreateObject<ConstantVelocityMobilityModel> ();
175  object->AggregateObject (model);
176  }
177  return model;
178 }
179 
180 
181 void
183 {
184  map<int, DestinationPoint> last_pos; // Stores previous movement scheduled for each node
185 
186  //*****************************************************************
187  // Parse the file the first time to get the initial node positions.
188  //*****************************************************************
189 
190  // Look through the whole the file for the the initial node
191  // positions to make this helper robust to handle trace files with
192  // the initial node positions at the end.
193  std::ifstream file (m_filename.c_str (), std::ios::in);
194  if (file.is_open ())
195  {
196  while (!file.eof () )
197  {
198  int iNodeId = 0;
199  std::string nodeId;
200  std::string line;
201 
202  getline (file, line);
203 
204  // ignore empty lines
205  if (line.empty ())
206  {
207  continue;
208  }
209 
210  ParseResult pr = ParseNs2Line (line); // Parse line and obtain tokens
211 
212  // Check if the line corresponds with setting the initial
213  // node positions
214  if (pr.tokens.size () != 4)
215  {
216  continue;
217  }
218 
219  // Get the node Id
220  nodeId = GetNodeIdString (pr);
221  iNodeId = GetNodeIdInt (pr);
222  if (iNodeId == -1)
223  {
224  NS_LOG_ERROR ("Node number couldn't be obtained (corrupted file?): " << line << "\n");
225  continue;
226  }
227 
228  // get mobility model of node
230 
231  // if model not exists, continue
232  if (model == 0)
233  {
234  NS_LOG_ERROR ("Unknown node ID (corrupted file?): " << nodeId << "\n");
235  continue;
236  }
237 
238 
239  /*
240  * In this case a initial position is being seted
241  * line like $node_(0) set X_ 151.05190721688197
242  */
243  if (IsSetInitialPos (pr))
244  {
245  DestinationPoint point;
246  // coord coord value
247  point.m_finalPosition = SetInitialPosition (model, pr.tokens[2], pr.dvals[3]);
248  last_pos[iNodeId] = point;
249 
250  // Log new position
251  NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId <<
252  " position = " << last_pos[iNodeId].m_finalPosition);
253  }
254  }
255  file.close ();
256  }
257 
258  //*****************************************************************
259  // Parse the file a second time to get the rest of its values
260  //*****************************************************************
261 
262  // The reason the file is parsed again is to make this helper robust
263  // to handle trace files with the initial node positions at the end.
264  file.open (m_filename.c_str (), std::ios::in);
265  if (file.is_open ())
266  {
267  while (!file.eof () )
268  {
269  int iNodeId = 0;
270  std::string nodeId;
271  std::string line;
272 
273  getline (file, line);
274 
275  // ignore empty lines
276  if (line.empty ())
277  {
278  continue;
279  }
280 
281  ParseResult pr = ParseNs2Line (line); // Parse line and obtain tokens
282 
283  // Check if the line corresponds with one of the three types of line
284  if (pr.tokens.size () != 4 && pr.tokens.size () != 7 && pr.tokens.size () != 8)
285  {
286  NS_LOG_ERROR ("Line has not correct number of parameters (corrupted file?): " << line << "\n");
287  continue;
288  }
289 
290  // Get the node Id
291  nodeId = GetNodeIdString (pr);
292  iNodeId = GetNodeIdInt (pr);
293  if (iNodeId == -1)
294  {
295  NS_LOG_ERROR ("Node number couldn't be obtained (corrupted file?): " << line << "\n");
296  continue;
297  }
298 
299  // get mobility model of node
301 
302  // if model not exists, continue
303  if (model == 0)
304  {
305  NS_LOG_ERROR ("Unknown node ID (corrupted file?): " << nodeId << "\n");
306  continue;
307  }
308 
309 
310  /*
311  * In this case a initial position is being seted
312  * line like $node_(0) set X_ 151.05190721688197
313  */
314  if (IsSetInitialPos (pr))
315  {
316  // This is the second time this file has been parsed,
317  // and the initial node positions were already set the
318  // first time. So, do nothing this time with this line.
319  continue;
320  }
321 
322  else // NOW EVENTS TO BE SCHEDULED
323  {
324 
325  // This is a scheduled event, so time at should be present
326  double at;
327 
328  if (!IsNumber (pr.tokens[2]))
329  {
330  NS_LOG_WARN ("Time is not a number: " << pr.tokens[2]);
331  continue;
332  }
333 
334  at = pr.dvals[2]; // set time at
335 
336  if ( at < 0 )
337  {
338  NS_LOG_WARN ("Time is less than cero: " << at);
339  continue;
340  }
341 
342 
343 
344  /*
345  * In this case a new waypoint is added
346  * line like $ns_ at 1 "$node_(0) setdest 2 3 4"
347  */
348  if (IsSchedMobilityPos (pr))
349  {
350  if (last_pos[iNodeId].m_targetArrivalTime > at)
351  {
352  NS_LOG_LOGIC ("Did not reach a destination! stoptime = " << last_pos[iNodeId].m_targetArrivalTime << ", at = "<< at);
353  double actuallytraveled = at - last_pos[iNodeId].m_travelStartTime;
354  Vector reached = Vector (
355  last_pos[iNodeId].m_startPosition.x + last_pos[iNodeId].m_speed.x * actuallytraveled,
356  last_pos[iNodeId].m_startPosition.y + last_pos[iNodeId].m_speed.y * actuallytraveled,
357  0
358  );
359  NS_LOG_LOGIC ("Final point = " << last_pos[iNodeId].m_finalPosition << ", actually reached = " << reached);
360  last_pos[iNodeId].m_stopEvent.Cancel ();
361  last_pos[iNodeId].m_finalPosition = reached;
362  }
363  // last position time X coord Y coord velocity
364  last_pos[iNodeId] = SetMovement (model, last_pos[iNodeId].m_finalPosition, at, pr.dvals[5], pr.dvals[6], pr.dvals[7]);
365 
366  // Log new position
367  NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId << " position =" << last_pos[iNodeId].m_finalPosition);
368  }
369 
370 
371  /*
372  * Scheduled set position
373  * line like $ns_ at 4.634906291962 "$node_(0) set X_ 28.675920486450"
374  */
375  else if (IsSchedSetPos (pr))
376  {
377  // time coordinate coord value
378  last_pos[iNodeId].m_finalPosition = SetSchedPosition (model, at, pr.tokens[5], pr.dvals[6]);
379  if (last_pos[iNodeId].m_targetArrivalTime > at)
380  {
381  last_pos[iNodeId].m_stopEvent.Cancel ();
382  }
383  last_pos[iNodeId].m_targetArrivalTime = at;
384  last_pos[iNodeId].m_travelStartTime = at;
385  // Log new position
386  NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId <<
387  " position =" << last_pos[iNodeId].m_finalPosition);
388  }
389  else
390  {
391  NS_LOG_WARN ("Format Line is not correct: " << line << "\n");
392  }
393  }
394  }
395  file.close ();
396  }
397 }
398 
399 
401 ParseNs2Line (const string& str)
402 {
403  ParseResult ret;
404  istringstream s;
405  string line;
406 
407  // ignore comments (#)
408  size_t pos_sharp = str.find_first_of ('#');
409  if (pos_sharp != string::npos)
410  {
411  line = str.substr (0, pos_sharp);
412  }
413  else
414  {
415  line = str;
416  }
417 
418  line = TrimNs2Line (line);
419 
420  // If line hasn't a correct node Id
421  if (!HasNodeIdNumber (line))
422  {
423  NS_LOG_WARN ("Line has no node Id: " << line);
424  return ret;
425  }
426 
427  s.str (line);
428 
429  while (!s.eof ())
430  {
431  string x;
432  s >> x;
433  if (x.length () == 0)
434  {
435  continue;
436  }
437  ret.tokens.push_back (x);
438  int ii (0);
439  double d (0);
440  if (HasNodeIdNumber (x))
441  {
442  x = GetNodeIdFromToken (x);
443  }
444  ret.has_ival.push_back (IsVal<int> (x, ii));
445  ret.ivals.push_back (ii);
446  ret.has_dval.push_back (IsVal<double> (x, d));
447  ret.dvals.push_back (d);
448  ret.svals.push_back (x);
449  }
450 
451  size_t tokensLength = ret.tokens.size (); // number of tokens in line
452  size_t lasTokenLength = ret.tokens[tokensLength - 1].size (); // length of the last token
453 
454  // if it is a scheduled set _[XYZ] or a setdest I need to remove the last "
455  // and re-calculate values
456  if ( (tokensLength == 7 || tokensLength == 8)
457  && (ret.tokens[tokensLength - 1][lasTokenLength - 1] == '"') )
458  {
459 
460  // removes " from the last position
461  ret.tokens[tokensLength - 1] = ret.tokens[tokensLength - 1].substr (0,lasTokenLength - 1);
462 
463  string x;
464  x = ret.tokens[tokensLength - 1];
465 
466  if (HasNodeIdNumber (x))
467  {
468  x = GetNodeIdFromToken (x);
469  }
470 
471  // Re calculate values
472  int ii (0);
473  double d (0);
474  ret.has_ival[tokensLength - 1] = IsVal<int> (x, ii);
475  ret.ivals[tokensLength - 1] = ii;
476  ret.has_dval[tokensLength - 1] = IsVal<double> (x, d);
477  ret.dvals[tokensLength - 1] = d;
478  ret.svals[tokensLength - 1] = x;
479 
480  }
481  else if ( (tokensLength == 9 && ret.tokens[tokensLength - 1] == "\"")
482  || (tokensLength == 8 && ret.tokens[tokensLength - 1] == "\""))
483  {
484  // if the line has the " character in this way: $ns_ at 1 "$node_(0) setdest 2 2 1 "
485  // or in this: $ns_ at 4 "$node_(0) set X_ 2 " we need to ignore this last token
486 
487  ret.tokens.erase (ret.tokens.begin () + tokensLength - 1);
488  ret.has_ival.erase (ret.has_ival.begin () + tokensLength - 1);
489  ret.ivals.erase (ret.ivals.begin () + tokensLength - 1);
490  ret.has_dval.erase (ret.has_dval.begin () + tokensLength - 1);
491  ret.dvals.erase (ret.dvals.begin () + tokensLength - 1);
492  ret.svals.erase (ret.svals.begin () + tokensLength - 1);
493 
494  }
495 
496 
497 
498  return ret;
499 }
500 
501 
502 string
503 TrimNs2Line (const string& s)
504 {
505  string ret = s;
506 
507  while (ret.size () > 0 && isblank (ret[0]))
508  {
509  ret.erase (0, 1); // Removes blank spaces at the begining of the line
510  }
511 
512  while (ret.size () > 0 && isblank (ret[ret.size () - 1]))
513  {
514  ret.erase (ret.size () - 1, 1); // Removes blank spaces from at end of line
515  }
516 
517  return ret;
518 }
519 
520 
521 bool
522 IsNumber (const string& s)
523 {
524  char *endp;
525  double v = strtod (s.c_str (), &endp); // declared with warn_unused_result
526  NS_UNUSED (v); // suppress "set but not used" compiler warning
527  return endp == s.c_str () + s.size ();
528 }
529 
530 
531 template<class T>
532 bool IsVal (const string& str, T& ret)
533 {
534  if (str.size () == 0)
535  {
536  return false;
537  }
538  else if (IsNumber (str))
539  {
540  string s2 = str;
541  istringstream s (s2);
542  s >> ret;
543  return true;
544  }
545  else
546  {
547  return false;
548  }
549 }
550 
551 
552 bool
553 HasNodeIdNumber (string str)
554 {
555 
556  // find brackets
557  std::string::size_type startNodeId = str.find_first_of ("("); // index of left bracket
558  std::string::size_type endNodeId = str.find_first_of (")"); // index of right bracket
559 
560  // Get de nodeId in a string and in a int value
561  std::string nodeId; // node id
562 
563  // if no brackets, continue!
564  if (startNodeId == std::string::npos || endNodeId == std::string::npos)
565  {
566  return false;
567  }
568 
569  nodeId = str.substr (startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
570 
571  // is number is integer is not negative
572  if (IsNumber (nodeId) && (nodeId.find_first_of (".") == std::string::npos) && (nodeId[0] != '-'))
573  {
574  return true;
575  }
576  else
577  {
578  return false;
579  }
580 }
581 
582 
583 string
584 GetNodeIdFromToken (string str)
585 {
586  if (HasNodeIdNumber (str))
587  {
588  // find brackets
589  std::string::size_type startNodeId = str.find_first_of ("("); // index of left bracket
590  std::string::size_type endNodeId = str.find_first_of (")"); // index of right bracket
591 
592  return str.substr (startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
593  }
594  else
595  {
596  return "";
597  }
598 }
599 
600 
601 int
603 {
604  int result = -1;
605  switch (pr.tokens.size ())
606  {
607  case 4: // line like $node_(0) set X_ 11
608  result = pr.ivals[0];
609  break;
610  case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
611  result = pr.ivals[3];
612  break;
613  case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
614  result = pr.ivals[3];
615  break;
616  default:
617  result = -1;
618  }
619  return result;
620 }
621 
622 // Get node id number in string format
623 string
625 {
626  switch (pr.tokens.size ())
627  {
628  case 4: // line like $node_(0) set X_ 11
629  return pr.svals[0];
630  break;
631  case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
632  return pr.svals[3];
633  break;
634  case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
635  return pr.svals[3];
636  break;
637  default:
638  return "";
639  }
640 }
641 
642 
643 Vector
644 SetOneInitialCoord (Vector position, string& coord, double value)
645 {
646 
647  // set the position for the coord.
648  if (coord == NS2_X_COORD)
649  {
650  position.x = value;
651  NS_LOG_DEBUG ("X=" << value);
652  }
653  else if (coord == NS2_Y_COORD)
654  {
655  position.y = value;
656  NS_LOG_DEBUG ("Y=" << value);
657  }
658  else if (coord == NS2_Z_COORD)
659  {
660  position.z = value;
661  NS_LOG_DEBUG ("Z=" << value);
662  }
663  return position;
664 }
665 
666 
667 bool
669 {
670  // number of tokens has $node_( ? has "set" has doble for position?
671  return pr.tokens.size () == 4 && HasNodeIdNumber (pr.tokens[0]) && pr.tokens[1] == NS2_SET && pr.has_dval[3]
672  // coord name is X_, Y_ or Z_ ?
673  && (pr.tokens[2] == NS2_X_COORD || pr.tokens[2] == NS2_Y_COORD || pr.tokens[2] == NS2_Z_COORD);
674 
675 }
676 
677 
678 bool
680 {
681  // correct number of tokens, has $ns_ and at
682  return pr.tokens.size () == 7 && pr.tokens[0] == NS2_NS_SCH && pr.tokens[1] == NS2_AT
683  && pr.tokens[4] == NS2_SET && pr.has_dval[2] && pr.has_dval[3] // has set and double value for time and nodeid
684  && ( pr.tokens[5] == NS2_X_COORD || pr.tokens[5] == NS2_Y_COORD || pr.tokens[5] == NS2_Z_COORD) // has X_, Y_ or Z_?
685  && pr.has_dval[2]; // time is a number
686 }
687 
688 bool
690 {
691  // number of tokens and has $ns_ and has at
692  return pr.tokens.size () == 8 && pr.tokens[0] == NS2_NS_SCH && pr.tokens[1] == NS2_AT
693  // time x coord y coord velocity are numbers?
694  && pr.has_dval[2] && pr.has_dval[5] && pr.has_dval[6] && pr.has_dval[7]
695  && pr.tokens[4] == NS2_SETDEST; // and has setdest
696 
697 }
698 
699 DestinationPoint
701  double xFinalPosition, double yFinalPosition, double speed)
702 {
703  DestinationPoint retval;
704  retval.m_startPosition = last_pos;
705  retval.m_finalPosition = last_pos;
706  retval.m_travelStartTime = at;
707  retval.m_targetArrivalTime = at;
708 
709  if (speed == 0)
710  {
711  // We have to maintain last position, and stop the movement
713  Vector (0, 0, 0));
714  return retval;
715  }
716  if (speed > 0)
717  {
718  // first calculate the time; time = distance / speed
719  double time = sqrt (pow (xFinalPosition - retval.m_finalPosition.x, 2) + pow (yFinalPosition - retval.m_finalPosition.y, 2)) / speed;
720  NS_LOG_DEBUG ("at=" << at << " time=" << time);
721  if (time == 0)
722  {
723  return retval;
724  }
725  // now calculate the xSpeed = distance / time
726  double xSpeed = (xFinalPosition - retval.m_finalPosition.x) / time;
727  double ySpeed = (yFinalPosition - retval.m_finalPosition.y) / time; // & same with ySpeed
728  retval.m_speed = Vector (xSpeed, ySpeed, 0);
729 
730  // quick and dirty set zSpeed = 0
731  double zSpeed = 0;
732 
733  NS_LOG_DEBUG ("Calculated Speed: X=" << xSpeed << " Y=" << ySpeed << " Z=" << zSpeed);
734 
735  // Set the Values
736  Simulator::Schedule (Seconds (at), &ConstantVelocityMobilityModel::SetVelocity, model, Vector (xSpeed, ySpeed, zSpeed));
738  retval.m_finalPosition.x += xSpeed * time;
739  retval.m_finalPosition.y += ySpeed * time;
740  retval.m_targetArrivalTime += time;
741  }
742  return retval;
743 }
744 
745 
746 Vector
747 SetInitialPosition (Ptr<ConstantVelocityMobilityModel> model, string coord, double coordVal)
748 {
749  model->SetPosition (SetOneInitialCoord (model->GetPosition (), coord, coordVal));
750 
751  Vector position;
752  position.x = model->GetPosition ().x;
753  position.y = model->GetPosition ().y;
754  position.z = model->GetPosition ().z;
755 
756  return position;
757 }
758 
759 // Schedule a set of position for a node
760 Vector
761 SetSchedPosition (Ptr<ConstantVelocityMobilityModel> model, double at, string coord, double coordVal)
762 {
763  // update position
764  model->SetPosition (SetOneInitialCoord (model->GetPosition (), coord, coordVal));
765 
766  Vector position;
767  position.x = model->GetPosition ().x;
768  position.y = model->GetPosition ().y;
769  position.z = model->GetPosition ().z;
770 
771  // Chedule next positions
773 
774  return position;
775 }
776 
777 void
779 {
781 }
782 
783 } // namespace ns3