1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
|
2 |
|
3 #include <map> |
|
4 |
|
5 #include <goocanvas.h> |
|
6 #include <glib/gthread.h> |
|
7 |
|
8 #include "mobility-visualizer.h" |
|
9 #include <map> |
|
10 #include "ns3/simulator.h" |
|
11 |
|
12 #define MAX_QUEUE_LENGTH 100 |
|
13 #define MAX_EVENTS 20 |
|
14 #define LOOKAHEAD_SECONDS 10 |
|
15 |
|
16 GtkWidget *g_canvas; |
|
17 |
|
18 int model_init (int argc, char *argv[]); |
|
19 |
|
20 struct Node |
|
21 { |
|
22 GooCanvasItem *m_item; |
|
23 GooCanvasItem *m_vector; |
|
24 void create () |
|
25 { |
|
26 GooCanvasItem *root = goo_canvas_get_root_item (GOO_CANVAS (g_canvas)); |
|
27 m_item = goo_canvas_ellipse_new (root, 0, 0, 2.0, 2.0, |
|
28 "line_width", 0.5, |
|
29 "stroke_color", "black", |
|
30 "fill_color", "red", |
|
31 NULL); |
|
32 |
|
33 m_vector = goo_canvas_polyline_new (root, FALSE, 0, |
|
34 "line_width", 0.3, |
|
35 "stroke_color", "black", |
|
36 "end-arrow", TRUE, |
|
37 "arrow-length", 10.0, |
|
38 "arrow-width", 10.0, |
|
39 NULL); |
|
40 |
|
41 } |
|
42 |
|
43 |
|
44 void update (double x, double y, double vx, double vy) |
|
45 { |
|
46 g_object_set (m_item, "center_x", x, "center_y", y, NULL); |
|
47 |
|
48 if (vx == 0 && vy == 0) |
|
49 { |
|
50 GooCanvasPoints *points = goo_canvas_points_new (0); |
|
51 g_object_set (m_vector, "points", points, NULL); |
|
52 goo_canvas_points_unref (points); |
|
53 } |
|
54 else |
|
55 { |
|
56 GooCanvasPoints *points = goo_canvas_points_new (2); |
|
57 |
|
58 points->coords[0] = x; |
|
59 points->coords[1] = y; |
|
60 points->coords[2] = x + vx; |
|
61 points->coords[3] = y + vy; |
|
62 |
|
63 g_object_set (m_vector, "points", points, NULL); |
|
64 goo_canvas_points_unref (points); |
|
65 } |
|
66 } |
|
67 }; |
|
68 |
|
69 std::map<void*, Node> g_nodes; |
|
70 |
|
71 GTimeVal initialTime = {-1, -1}; |
|
72 gboolean firstTime = TRUE; |
|
73 double g_lookaheadTime = 0; |
|
74 GStaticMutex g_lookaheadTimeMux = G_STATIC_MUTEX_INIT; |
|
75 ViewUpdateData *g_nextData = NULL; |
|
76 |
|
77 |
|
78 GAsyncQueue *queue; |
|
79 |
|
80 #define TIME_SCALE 1 |
|
81 |
|
82 double get_current_time () |
|
83 { |
|
84 GTimeVal currTime; |
|
85 g_get_current_time (&currTime); |
|
86 GTimeVal relativeTime; |
|
87 relativeTime.tv_sec = currTime.tv_sec - initialTime.tv_sec + LOOKAHEAD_SECONDS; |
|
88 relativeTime.tv_usec = currTime.tv_usec; |
|
89 g_time_val_add (&relativeTime, -initialTime.tv_usec); |
|
90 return (relativeTime.tv_sec + 1.0e-6*relativeTime.tv_usec)*TIME_SCALE; |
|
91 } |
|
92 |
|
93 // called from the simulation thread |
|
94 void view_update (ViewUpdateData *updateData) |
|
95 { |
|
96 while ((g_static_mutex_lock (&g_lookaheadTimeMux), g_lookaheadTime) != 0 and updateData->time >= g_lookaheadTime) |
|
97 { |
|
98 g_static_mutex_unlock (&g_lookaheadTimeMux); |
|
99 g_usleep ((gulong) 10e3); |
|
100 } |
|
101 g_static_mutex_unlock (&g_lookaheadTimeMux); |
|
102 g_async_queue_push (queue, updateData); |
|
103 } |
|
104 |
|
105 void view_update_process (ViewUpdateData *updateData) |
|
106 { |
|
107 for (std::vector<NodeUpdate>::const_iterator update |
|
108 = updateData->updateList.begin (); |
|
109 update != updateData->updateList.end (); |
|
110 update++) |
|
111 { |
|
112 if (g_nodes.find (update->node) == g_nodes.end ()) |
|
113 { |
|
114 g_nodes[update->node].create (); |
|
115 } |
|
116 g_nodes[update->node].update (update->x, update->y, update->vx, update->vy); |
|
117 } |
|
118 delete updateData; |
|
119 } |
|
120 |
|
121 gboolean view_update_consumer () |
|
122 { |
|
123 if (firstTime) |
|
124 { |
|
125 firstTime = FALSE; |
|
126 g_get_current_time (&initialTime); |
|
127 } |
|
128 |
|
129 double now = get_current_time (); |
|
130 g_static_mutex_lock (&g_lookaheadTimeMux); |
|
131 g_lookaheadTime = now + LOOKAHEAD_SECONDS; |
|
132 g_static_mutex_unlock (&g_lookaheadTimeMux); |
|
133 |
|
134 if (!g_nextData) |
|
135 g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue); |
|
136 |
|
137 if (!g_nextData) |
|
138 return TRUE; |
|
139 |
|
140 if (g_nextData->time > now) |
|
141 return TRUE; |
|
142 |
|
143 do |
|
144 { |
|
145 view_update_process (g_nextData); |
|
146 g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue); |
|
147 } |
|
148 while (g_nextData && g_nextData->time <= now); |
|
149 |
|
150 return TRUE; |
|
151 } |
|
152 |
|
153 void zoom_changed (GtkAdjustment *adj) |
|
154 { |
|
155 goo_canvas_set_scale (GOO_CANVAS (g_canvas), gtk_adjustment_get_value (adj)); |
|
156 } |
|
157 |
|
158 int main (int argc, char *argv[]) |
|
159 { |
|
160 g_thread_init (NULL); |
|
161 gtk_init (&argc, &argv); |
|
162 double x1 = 0, y1 = 0, x2 = 0, y2 = 0; |
|
163 |
|
164 model_init (argc, argv, &x1, &y1, &x2, &y2); |
|
165 |
|
166 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
|
167 gtk_window_set_default_size (GTK_WINDOW (window), 640, 600); |
|
168 gtk_widget_show (window); |
|
169 g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); |
|
170 |
|
171 GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL, NULL); |
|
172 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); |
|
173 gtk_widget_show (scrolled_win); |
|
174 |
|
175 GtkWidget *vbox = gtk_vbox_new (FALSE, 4); |
|
176 gtk_widget_show (vbox); |
|
177 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, 1, 1, 4); |
|
178 gtk_container_add (GTK_CONTAINER (window), vbox); |
|
179 |
|
180 GtkWidget *hbox = gtk_hbox_new (FALSE, 4); |
|
181 gtk_widget_show (hbox); |
|
182 gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 4); |
|
183 |
|
184 GtkObject *zoom = gtk_adjustment_new (3.0, 0.1, 10.0, 0.2, 1.0, 1.0); |
|
185 gtk_box_pack_start(GTK_BOX (hbox), |
|
186 GTK_WIDGET (g_object_new (GTK_TYPE_SPIN_BUTTON, "adjustment", zoom, |
|
187 "visible", true, "digits", 2, NULL)), |
|
188 false, false, 4); |
|
189 |
|
190 g_canvas = goo_canvas_new (); |
|
191 gtk_widget_set_size_request (GTK_WIDGET (g_canvas), 600, 450); |
|
192 goo_canvas_set_bounds (GOO_CANVAS (g_canvas), -500, -500, 500, 500); |
|
193 g_signal_connect (zoom, "value-changed", G_CALLBACK (zoom_changed), NULL); |
|
194 gtk_adjustment_value_changed (GTK_ADJUSTMENT (zoom)); |
|
195 gtk_widget_show (g_canvas); |
|
196 gtk_container_add (GTK_CONTAINER (scrolled_win), g_canvas); |
|
197 |
|
198 goo_canvas_scroll_to (GOO_CANVAS (g_canvas), 0, 0); |
|
199 |
|
200 // create the bounds rectangle |
|
201 if (x1 != x2) |
|
202 { |
|
203 GooCanvasItem *item = |
|
204 goo_canvas_rect_new (goo_canvas_get_root_item (GOO_CANVAS (g_canvas)), |
|
205 x1, y1, x2-x1, y2-y1, NULL); |
|
206 g_object_set (item, "line-width", 1.0, "stroke-color", "grey", NULL); |
|
207 } |
|
208 |
|
209 queue = g_async_queue_new (); |
|
210 |
|
211 g_timeout_add ((guint) (SAMPLE_INTERVAL*1000), (GSourceFunc) view_update_consumer, NULL); |
|
212 |
|
213 g_thread_create (GThreadFunc (ns3::Simulator::Run), NULL, FALSE, NULL); |
|
214 |
|
215 gtk_main (); |
|
216 |
|
217 return 0; |
|
218 } |
|