|
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
|
2 /* |
|
3 * Copyright (c) 2007 INRIA |
|
4 * All rights reserved. |
|
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 */ |
|
21 #include "ns3/random-variable-default-value.h" |
|
22 #include "ns3/rectangle-default-value.h" |
|
23 #include "ns3/simulator.h" |
|
24 #include <algorithm> |
|
25 #include <cmath> |
|
26 #include "random-direction-position.h" |
|
27 |
|
28 namespace ns3 { |
|
29 |
|
30 const double RandomDirectionPosition::PI = 3.1415; |
|
31 const InterfaceId RandomDirectionPosition::iid = |
|
32 MakeInterfaceId ("RandomDirectionPosition", Position::iid); |
|
33 const ClassId RandomDirectionPosition::cid = |
|
34 MakeClassId<RandomDirectionPosition,double,double> ("RandomDirectionPosition", |
|
35 RandomDirectionPosition::iid); |
|
36 |
|
37 |
|
38 static RandomVariableDefaultValue |
|
39 g_speedVariable ("RandomDirectionSpeed", |
|
40 "A random variable to control the speed of a RandomDirection mobility model.", |
|
41 "Uniform:1:2"); |
|
42 |
|
43 static RandomVariableDefaultValue |
|
44 g_pauseVariable ("RandomDirectionPause", |
|
45 "A random variable to control the duration of of the pause of a RandomDiretion mobility model.", |
|
46 "Constant:2"); |
|
47 |
|
48 static RectangleDefaultValue |
|
49 g_rectangle ("RandomDirectionArea", |
|
50 "The bounding area for the RandomDirection model.", |
|
51 -100, 100, -100, 100); |
|
52 |
|
53 |
|
54 RandomDirectionParameters::RandomDirectionParameters () |
|
55 : m_xMin (g_rectangle.GetMinX ()), |
|
56 m_xMax (g_rectangle.GetMaxX ()), |
|
57 m_yMin (g_rectangle.GetMinY ()), |
|
58 m_yMax (g_rectangle.GetMaxY ()), |
|
59 m_speedVariable (g_speedVariable.GetCopy ()), |
|
60 m_pauseVariable (g_pauseVariable.GetCopy ()) |
|
61 {} |
|
62 RandomDirectionParameters::RandomDirectionParameters (double xMin, double xMax, double yMin, double yMax) |
|
63 : m_xMin (xMin), |
|
64 m_xMax (xMax), |
|
65 m_yMin (yMin), |
|
66 m_yMax (yMax), |
|
67 m_speedVariable (g_speedVariable.GetCopy ()), |
|
68 m_pauseVariable (g_pauseVariable.GetCopy ()) |
|
69 {} |
|
70 RandomDirectionParameters::RandomDirectionParameters (double xMin, double xMax, double yMin, double yMax, |
|
71 const RandomVariable &speedVariable, |
|
72 const RandomVariable &pauseVariable) |
|
73 : m_xMin (xMin), |
|
74 m_xMax (xMax), |
|
75 m_yMin (yMin), |
|
76 m_yMax (yMax), |
|
77 m_speedVariable (speedVariable.Copy ()), |
|
78 m_pauseVariable (pauseVariable.Copy ()) |
|
79 {} |
|
80 |
|
81 RandomDirectionParameters::~RandomDirectionParameters () |
|
82 { |
|
83 delete m_speedVariable; |
|
84 delete m_pauseVariable; |
|
85 m_speedVariable = 0; |
|
86 m_pauseVariable = 0; |
|
87 } |
|
88 |
|
89 void |
|
90 RandomDirectionParameters::SetSpeed (const RandomVariable &speedVariable) |
|
91 { |
|
92 delete m_speedVariable; |
|
93 m_speedVariable = speedVariable.Copy (); |
|
94 } |
|
95 void |
|
96 RandomDirectionParameters::SetPause (const RandomVariable &pauseVariable) |
|
97 { |
|
98 delete m_pauseVariable; |
|
99 m_pauseVariable = pauseVariable.Copy (); |
|
100 } |
|
101 void |
|
102 RandomDirectionParameters::SetBounds (double xMin, double xMax, double yMin, double yMax) |
|
103 { |
|
104 m_xMin = xMin; |
|
105 m_yMin = yMin; |
|
106 m_xMax = xMax; |
|
107 m_yMax = yMax; |
|
108 } |
|
109 |
|
110 Ptr<RandomDirectionParameters> |
|
111 RandomDirectionPosition::GetDefaultParameters (void) |
|
112 { |
|
113 static Ptr<RandomDirectionParameters> parameters = Create<RandomDirectionParameters> (); |
|
114 if (parameters->m_xMin != g_rectangle.GetMinX () || |
|
115 parameters->m_yMin != g_rectangle.GetMinY () || |
|
116 parameters->m_xMax != g_rectangle.GetMaxX () || |
|
117 parameters->m_yMax != g_rectangle.GetMaxY () || |
|
118 g_speedVariable.IsDirty () || |
|
119 g_pauseVariable.IsDirty ()) |
|
120 { |
|
121 parameters = Create<RandomDirectionParameters> (); |
|
122 g_speedVariable.ClearDirtyFlag (); |
|
123 g_pauseVariable.ClearDirtyFlag (); |
|
124 } |
|
125 return parameters; |
|
126 } |
|
127 |
|
128 |
|
129 RandomDirectionPosition::RandomDirectionPosition () |
|
130 : m_parameters (GetDefaultParameters ()), |
|
131 m_x (0.0), |
|
132 m_y (0.0), |
|
133 m_dx (0.0), |
|
134 m_dy (0.0), |
|
135 m_prevTime (Simulator::Now ()), |
|
136 m_pauseStart (Simulator::Now ()) |
|
137 { |
|
138 SetInterfaceId (RandomDirectionPosition::iid); |
|
139 InitializeDirectionAndSpeed (); |
|
140 } |
|
141 bool |
|
142 RandomDirectionPosition::CheckPosition (void) const |
|
143 { |
|
144 return |
|
145 m_x <= m_parameters->m_xMax && |
|
146 m_x >= m_parameters->m_xMin && |
|
147 m_y <= m_parameters->m_yMax && |
|
148 m_y >= m_parameters->m_yMin; |
|
149 } |
|
150 |
|
151 RandomDirectionPosition::RandomDirectionPosition (double x, double y) |
|
152 : m_parameters (GetDefaultParameters ()), |
|
153 m_x (x), |
|
154 m_y (y), |
|
155 m_dx (0.0), |
|
156 m_dy (0.0), |
|
157 m_prevTime (Simulator::Now ()), |
|
158 m_pauseStart (Simulator::Now ()) |
|
159 { |
|
160 SetInterfaceId (RandomDirectionPosition::iid); |
|
161 NS_ASSERT (CheckPosition ()); |
|
162 InitializeDirectionAndSpeed (); |
|
163 } |
|
164 RandomDirectionPosition::RandomDirectionPosition (Ptr<RandomDirectionParameters> parameters) |
|
165 : m_parameters (parameters), |
|
166 m_x (0.0), |
|
167 m_y (0.0), |
|
168 m_dx (0.0), |
|
169 m_dy (0.0), |
|
170 m_prevTime (Simulator::Now ()), |
|
171 m_pauseStart (Simulator::Now ()) |
|
172 { |
|
173 SetInterfaceId (RandomDirectionPosition::iid); |
|
174 InitializeDirectionAndSpeed (); |
|
175 NS_ASSERT (CheckPosition ()); |
|
176 } |
|
177 RandomDirectionPosition::RandomDirectionPosition (Ptr<RandomDirectionParameters> parameters, |
|
178 double x, double y) |
|
179 : m_parameters (parameters), |
|
180 m_x (x), |
|
181 m_y (y), |
|
182 m_dx (0.0), |
|
183 m_dy (0.0), |
|
184 m_prevTime (Simulator::Now ()), |
|
185 m_pauseStart (Simulator::Now ()) |
|
186 { |
|
187 SetInterfaceId (RandomDirectionPosition::iid); |
|
188 InitializeDirectionAndSpeed (); |
|
189 NS_ASSERT (CheckPosition ()); |
|
190 } |
|
191 void |
|
192 RandomDirectionPosition::DoDispose (void) |
|
193 { |
|
194 m_parameters = 0; |
|
195 // chain up. |
|
196 Position::DoDispose (); |
|
197 } |
|
198 enum RandomDirectionPosition::Side |
|
199 RandomDirectionPosition::CalculateIntersection (double &x, double &y) |
|
200 { |
|
201 double xMin = m_parameters->m_xMin; |
|
202 double xMax = m_parameters->m_xMax; |
|
203 double yMin = m_parameters->m_yMin; |
|
204 double yMax = m_parameters->m_yMax; |
|
205 double xMaxY = m_y + (xMax - m_x) / m_dx * m_dy; |
|
206 double xMinY = m_y + (xMin - m_x) / m_dx * m_dy; |
|
207 double yMaxX = m_x + (yMax - m_y) / m_dy * m_dx; |
|
208 double yMinX = m_x + (yMin - m_y) / m_dy * m_dx; |
|
209 bool xMaxOk = xMaxY <= yMax && xMaxY >= yMin; |
|
210 bool xMinOk = xMinY <= yMax && xMinY >= yMin; |
|
211 bool yMaxOk = yMaxX <= xMax && yMaxX >= xMin; |
|
212 bool yMinOk = yMinX <= xMax && yMinX >= xMin; |
|
213 if (xMaxOk && m_dx >= 0) |
|
214 { |
|
215 x = xMax; |
|
216 y = xMaxY; |
|
217 return RandomDirectionPosition::RIGHT; |
|
218 } |
|
219 else if (xMinOk && m_dx <= 0) |
|
220 { |
|
221 x = xMin; |
|
222 y = xMinY; |
|
223 return RandomDirectionPosition::LEFT; |
|
224 } |
|
225 else if (yMaxOk && m_dy >= 0) |
|
226 { |
|
227 x = yMaxX; |
|
228 y = yMax; |
|
229 return RandomDirectionPosition::TOP; |
|
230 } |
|
231 else if (yMinOk && m_dy <= 0) |
|
232 { |
|
233 x = yMinX; |
|
234 y = yMin; |
|
235 return RandomDirectionPosition::BOTTOM; |
|
236 } |
|
237 else |
|
238 { |
|
239 NS_ASSERT (false); |
|
240 // quiet compiler |
|
241 return RandomDirectionPosition::RIGHT; |
|
242 } |
|
243 } |
|
244 void |
|
245 RandomDirectionPosition::InitializeDirectionAndSpeed (void) |
|
246 { |
|
247 double direction = UniformVariable::GetSingleValue (0, 2 * PI); |
|
248 SetDirectionAndSpeed (direction); |
|
249 } |
|
250 void |
|
251 RandomDirectionPosition::SetDirectionAndSpeed (double direction) |
|
252 { |
|
253 double speed = m_parameters->m_speedVariable->GetValue (); |
|
254 m_dx = std::cos (direction) * speed; |
|
255 m_dy = std::sin (direction) * speed; |
|
256 double x, y; |
|
257 m_side = CalculateIntersection (x, y); |
|
258 double deltaX = x - m_x; |
|
259 double deltaY = y - m_y; |
|
260 double distance = sqrt (deltaX * deltaX + deltaY * deltaY); |
|
261 double seconds = distance / speed; |
|
262 double pause = m_parameters->m_pauseVariable->GetValue (); |
|
263 m_pauseStart = Simulator::Now () + Seconds (seconds); |
|
264 m_prevTime = Simulator::Now (); |
|
265 m_event = Simulator::Schedule (Seconds (seconds + pause), |
|
266 &RandomDirectionPosition::ResetDirectionAndSpeed, this); |
|
267 } |
|
268 void |
|
269 RandomDirectionPosition::ResetDirectionAndSpeed (void) |
|
270 { |
|
271 Update (); |
|
272 double direction = UniformVariable::GetSingleValue (0, PI); |
|
273 switch (m_side) |
|
274 { |
|
275 case RandomDirectionPosition::RIGHT: |
|
276 direction += PI / 2; |
|
277 break; |
|
278 case RandomDirectionPosition::LEFT: |
|
279 direction += - PI / 2; |
|
280 break; |
|
281 case RandomDirectionPosition::TOP: |
|
282 direction += PI; |
|
283 break; |
|
284 case RandomDirectionPosition::BOTTOM: |
|
285 direction += 0.0; |
|
286 break; |
|
287 } |
|
288 SetDirectionAndSpeed (direction); |
|
289 NotifyCourseChange (); |
|
290 } |
|
291 void |
|
292 RandomDirectionPosition::Update (void) const |
|
293 { |
|
294 Time end = std::min (Simulator::Now (), m_pauseStart); |
|
295 if (m_prevTime >= end) |
|
296 { |
|
297 return; |
|
298 } |
|
299 Time deltaTime = end - m_prevTime; |
|
300 m_prevTime = Simulator::Now (); |
|
301 double deltaS = deltaTime.GetSeconds (); |
|
302 NS_ASSERT (CheckPosition ()); |
|
303 m_x += m_dx * deltaS; |
|
304 m_y += m_dy * deltaS; |
|
305 // round to closest boundaries. |
|
306 m_x = std::min (m_x, m_parameters->m_xMax); |
|
307 m_x = std::max (m_x, m_parameters->m_xMin); |
|
308 m_y = std::min (m_y, m_parameters->m_yMax); |
|
309 m_y = std::max (m_y, m_parameters->m_yMin); |
|
310 NS_ASSERT (CheckPosition ()); |
|
311 } |
|
312 void |
|
313 RandomDirectionPosition::DoGet (double &x, double &y, double &z) const |
|
314 { |
|
315 Update (); |
|
316 x = m_x; |
|
317 y = m_y; |
|
318 z = 0; |
|
319 } |
|
320 void |
|
321 RandomDirectionPosition::DoSet (double x, double y, double z) |
|
322 { |
|
323 bool changed = false; |
|
324 if (m_x != x || m_y != y) |
|
325 { |
|
326 changed = true; |
|
327 } |
|
328 m_x = x; |
|
329 m_y = y; |
|
330 m_prevTime = Simulator::Now (); |
|
331 m_pauseStart = Simulator::Now (); |
|
332 Simulator::Remove (m_event); |
|
333 InitializeDirectionAndSpeed (); |
|
334 NotifyCourseChange (); |
|
335 } |
|
336 |
|
337 |
|
338 |
|
339 } // namespace ns3 |