2 * Copyright (C) 2009 Andy Spencer <spenceal@rose-hulman.edu>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <gdk/gdkkeysyms.h>
22 #include "gis-marshal.h"
23 #include "gis-viewer.h"
38 static guint signals[NUM_SIGNALS];
45 static void _gis_viewer_fix_location(GisViewer *self)
47 while (self->location[0] < -90) self->location[0] += 180;
48 while (self->location[0] > 90) self->location[0] -= 180;
49 while (self->location[1] < -180) self->location[1] += 360;
50 while (self->location[1] > 180) self->location[1] -= 360;
51 self->location[2] = ABS(self->location[2]);
55 static void _gis_viewer_emit_location_changed(GisViewer *self)
57 g_signal_emit(self, signals[SIG_LOCATION_CHANGED], 0,
62 static void _gis_viewer_emit_rotation_changed(GisViewer *self)
64 g_signal_emit(self, signals[SIG_ROTATION_CHANGED], 0,
69 static void _gis_viewer_emit_time_changed(GisViewer *self)
71 g_signal_emit(self, signals[SIG_TIME_CHANGED], 0,
74 static void _gis_viewer_emit_site_changed(GisViewer *self)
76 g_signal_emit(self, signals[SIG_SITE_CHANGED], 0,
79 static void _gis_viewer_emit_refresh(GisViewer *self)
81 g_signal_emit(self, signals[SIG_REFRESH], 0);
83 static void _gis_viewer_emit_offline(GisViewer *self)
85 g_signal_emit(self, signals[SIG_OFFLINE], 0,
92 static gboolean on_button_press(GisViewer *self, GdkEventButton *event, gpointer _)
94 g_debug("GisViewer: on_button_press - Grabbing focus");
95 gtk_widget_grab_focus(GTK_WIDGET(self));
98 static gboolean on_key_press(GisViewer *self, GdkEventKey *event, gpointer _)
100 g_debug("GisViewer: on_key_press - key=%x, state=%x, plus=%x",
101 event->keyval, event->state, GDK_plus);
103 double lat, lon, elev, pan;
104 gis_viewer_get_location(self, &lat, &lon, &elev);
105 pan = MIN(elev/(EARTH_R/2), 30);
106 guint kv = event->keyval;
108 if (kv == GDK_Left || kv == GDK_h) gis_viewer_pan(self, 0, -pan, 0);
109 else if (kv == GDK_Down || kv == GDK_j) gis_viewer_pan(self, -pan, 0, 0);
110 else if (kv == GDK_Up || kv == GDK_k) gis_viewer_pan(self, pan, 0, 0);
111 else if (kv == GDK_Right || kv == GDK_l) gis_viewer_pan(self, 0, pan, 0);
112 else if (kv == GDK_minus || kv == GDK_o) gis_viewer_zoom(self, 10./9);
113 else if (kv == GDK_plus || kv == GDK_i) gis_viewer_zoom(self, 9./10);
114 else if (kv == GDK_H) gis_viewer_rotate(self, 0, 0, -2);
115 else if (kv == GDK_J) gis_viewer_rotate(self, 2, 0, 0);
116 else if (kv == GDK_K) gis_viewer_rotate(self, -2, 0, 0);
117 else if (kv == GDK_L) gis_viewer_rotate(self, 0, 0, 2);
120 static void on_view_changed(GisViewer *self,
121 gdouble _1, gdouble _2, gdouble _3)
123 gtk_widget_queue_draw(GTK_WIDGET(self));
129 void gis_viewer_set_time(GisViewer *self, const char *time)
131 g_assert(GIS_IS_VIEWER(self));
132 g_debug("GisViewer: set_time - time=%s", time);
134 self->time = g_strdup(time);
135 _gis_viewer_emit_time_changed(self);
138 gchar *gis_viewer_get_time(GisViewer *self)
140 g_assert(GIS_IS_VIEWER(self));
141 g_debug("GisViewer: get_time");
145 void gis_viewer_set_location(GisViewer *self, gdouble lat, gdouble lon, gdouble elev)
147 g_assert(GIS_IS_VIEWER(self));
148 g_debug("GisViewer: set_location");
149 self->location[0] = lat;
150 self->location[1] = lon;
151 self->location[2] = elev;
152 _gis_viewer_fix_location(self);
153 _gis_viewer_emit_location_changed(self);
156 void gis_viewer_get_location(GisViewer *self, gdouble *lat, gdouble *lon, gdouble *elev)
158 g_assert(GIS_IS_VIEWER(self));
159 //g_debug("GisViewer: get_location");
160 *lat = self->location[0];
161 *lon = self->location[1];
162 *elev = self->location[2];
165 void gis_viewer_pan(GisViewer *self, gdouble lat, gdouble lon, gdouble elev)
167 g_assert(GIS_IS_VIEWER(self));
168 g_debug("GisViewer: pan - lat=%8.3f, lon=%8.3f, elev=%8.3f", lat, lon, elev);
169 self->location[0] += lat;
170 self->location[1] += lon;
171 self->location[2] += elev;
172 _gis_viewer_fix_location(self);
173 _gis_viewer_emit_location_changed(self);
176 void gis_viewer_zoom(GisViewer *self, gdouble scale)
178 g_assert(GIS_IS_VIEWER(self));
179 g_debug("GisViewer: zoom");
180 self->location[2] *= scale;
181 _gis_viewer_emit_location_changed(self);
184 void gis_viewer_set_rotation(GisViewer *self, gdouble x, gdouble y, gdouble z)
186 g_assert(GIS_IS_VIEWER(self));
187 g_debug("GisViewer: set_rotation");
188 self->rotation[0] = x;
189 self->rotation[1] = y;
190 self->rotation[2] = z;
191 _gis_viewer_emit_rotation_changed(self);
194 void gis_viewer_get_rotation(GisViewer *self, gdouble *x, gdouble *y, gdouble *z)
196 g_assert(GIS_IS_VIEWER(self));
197 g_debug("GisViewer: get_rotation");
198 *x = self->rotation[0];
199 *y = self->rotation[1];
200 *z = self->rotation[2];
203 void gis_viewer_rotate(GisViewer *self, gdouble x, gdouble y, gdouble z)
205 g_assert(GIS_IS_VIEWER(self));
206 g_debug("GisViewer: rotate - x=%.0f, y=%.0f, z=%.0f", x, y, z);
207 self->rotation[0] += x;
208 self->rotation[1] += y;
209 self->rotation[2] += z;
210 _gis_viewer_emit_rotation_changed(self);
213 /* To be deprecated, use {get,set}_location */
214 void gis_viewer_set_site(GisViewer *self, const gchar *site)
216 g_assert(GIS_IS_VIEWER(self));
217 g_debug("GisViewer: set_site");
219 self->site = g_strdup(site);
220 _gis_viewer_emit_site_changed(self);
223 gchar *gis_viewer_get_site(GisViewer *self)
225 g_assert(GIS_IS_VIEWER(self));
226 g_debug("GisViewer: get_site - %s", self->site);
230 void gis_viewer_refresh(GisViewer *self)
232 g_debug("GisViewer: refresh");
233 _gis_viewer_emit_refresh(self);
236 void gis_viewer_set_offline(GisViewer *self, gboolean offline)
238 g_assert(GIS_IS_VIEWER(self));
239 g_debug("GisViewer: set_offline - %d", offline);
240 self->offline = offline;
241 _gis_viewer_emit_offline(self);
244 gboolean gis_viewer_get_offline(GisViewer *self)
246 g_assert(GIS_IS_VIEWER(self));
247 g_debug("GisViewer: get_offline - %d", self->offline);
248 return self->offline;
251 /* To be implemented by subclasses */
252 void gis_viewer_center_position(GisViewer *self,
253 gdouble lat, gdouble lon, gdouble elev)
255 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
256 if (!klass->center_position)
257 g_warning("GisViewer: center_position - Unimplemented");
258 klass->center_position(self, lat, lon, elev);
261 void gis_viewer_project(GisViewer *self,
262 gdouble lat, gdouble lon, gdouble elev,
263 gdouble *px, gdouble *py, gdouble *pz)
265 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
267 g_warning("GisViewer: project - Unimplemented");
268 klass->project(self, lat, lon, elev, px, py, pz);
271 void gis_viewer_clear_height_func(GisViewer *self)
273 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
274 if (!klass->clear_height_func)
275 g_warning("GisViewer: clear_height_func - Unimplemented");
276 klass->clear_height_func(self);
279 void gis_viewer_set_height_func(GisViewer *self, GisTile *tile,
280 GisHeightFunc height_func, gpointer user_data,
283 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
284 if (!klass->set_height_func)
285 g_warning("GisViewer: set_height_func - Unimplemented");
286 klass->set_height_func(self, tile, height_func, user_data, update);
289 void gis_viewer_render_tile(GisViewer *self, GisTile *tile)
291 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
292 if (!klass->render_tile)
293 g_warning("GisViewer: render_tile - Unimplemented");
294 klass->render_tile(self, tile);
297 void gis_viewer_render_tiles(GisViewer *self, GisTile *root)
299 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
300 if (!klass->render_tiles)
301 g_warning("GisViewer: render_tiles - Unimplemented");
302 klass->render_tiles(self, root);
305 void gis_viewer_begin(GisViewer *self)
307 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
309 g_warning("GisViewer: begin - Unimplemented");
313 void gis_viewer_end(GisViewer *self)
315 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
317 g_warning("GisViewer: end - Unimplemented");
321 void gis_viewer_add(GisViewer *self, GisObject *object)
323 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
325 g_warning("GisViewer: add - Unimplemented");
326 klass->add(self, object);
329 void gis_viewer_remove(GisViewer *self, GisObject *object)
331 GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self);
333 g_warning("GisViewer: remove - Unimplemented");
334 klass->remove(self, object);
340 G_DEFINE_ABSTRACT_TYPE(GisViewer, gis_viewer, GTK_TYPE_DRAWING_AREA);
341 static void gis_viewer_init(GisViewer *self)
343 g_debug("GisViewer: init");
345 self->time = g_strdup("");
346 self->site = g_strdup("");
347 self->location[0] = 40;
348 self->location[1] = -100;
349 self->location[2] = 1.5*EARTH_R;
350 self->rotation[0] = 0;
351 self->rotation[1] = 0;
352 self->rotation[2] = 0;
354 g_signal_connect(self, "key-press-event", G_CALLBACK(on_key_press), NULL);
355 g_signal_connect(self, "button-press-event", G_CALLBACK(on_button_press), NULL);
357 g_signal_connect(self, "location-changed", G_CALLBACK(on_view_changed), NULL);
358 g_signal_connect(self, "rotation-changed", G_CALLBACK(on_view_changed), NULL);
360 static void gis_viewer_finalize(GObject *gobject)
362 g_debug("GisViewer: finalize");
363 GisViewer *self = GIS_VIEWER(gobject);
366 G_OBJECT_CLASS(gis_viewer_parent_class)->finalize(gobject);
368 static void gis_viewer_class_init(GisViewerClass *klass)
370 g_debug("GisViewer: class_init");
371 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
372 gobject_class->finalize = gis_viewer_finalize;
373 signals[SIG_TIME_CHANGED] = g_signal_new(
375 G_TYPE_FROM_CLASS(gobject_class),
380 g_cclosure_marshal_VOID__STRING,
384 signals[SIG_SITE_CHANGED] = g_signal_new(
386 G_TYPE_FROM_CLASS(gobject_class),
391 g_cclosure_marshal_VOID__STRING,
395 signals[SIG_LOCATION_CHANGED] = g_signal_new(
397 G_TYPE_FROM_CLASS(gobject_class),
402 gis_cclosure_marshal_VOID__DOUBLE_DOUBLE_DOUBLE,
408 signals[SIG_ROTATION_CHANGED] = g_signal_new(
410 G_TYPE_FROM_CLASS(gobject_class),
415 gis_cclosure_marshal_VOID__DOUBLE_DOUBLE_DOUBLE,
421 signals[SIG_REFRESH] = g_signal_new(
423 G_TYPE_FROM_CLASS(gobject_class),
428 g_cclosure_marshal_VOID__VOID,
431 signals[SIG_OFFLINE] = g_signal_new(
433 G_TYPE_FROM_CLASS(gobject_class),
438 g_cclosure_marshal_VOID__BOOLEAN,