]> Pileus Git - aweather/commitdiff
Roam and Wms optimizations
authorAndy Spencer <andy753421@gmail.com>
Wed, 9 Sep 2009 01:25:35 +0000 (01:25 +0000)
committerAndy Spencer <andy753421@gmail.com>
Wed, 9 Sep 2009 01:25:35 +0000 (01:25 +0000)
- Store WmsCacheNode's in RoamTriangle and RoamPoint and shortcut the
  fetch operation when they do not change.

- Added RoamView that stores GL_{MODELVIEW,PROJECTION,VIEWPORT_MATRIX}s
  between calls to gluProject.

- Cache heights (via height_func calls) and screen coordinates in
  RoamPoint to avoid excess gluProject calls.

gen.sh
src/.gitignore
src/gis/Makefile.am
src/gis/gis-opengl.c
src/gis/gpqueue.c
src/gis/gpqueue.h
src/gis/roam.c
src/gis/roam.h
src/gis/wms.c
src/gis/wms.h
src/gis/wms_test.c

diff --git a/gen.sh b/gen.sh
index c883ff89aa60d72c06bddc1119d93f9b5ca34373..aed8c6d408b32e11dc3af6f3c90a9cae3e73a485 100755 (executable)
--- a/gen.sh
+++ b/gen.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 dir=$(dirname $(readlink -f $0))
-CFLAGS="-g -Werror -Wno-unused" \
+CFLAGS="-g -Werror -Wno-unused $CFLAGS" \
 ./autogen.sh \
        "--libdir=$dir/src/plugins" \
        "--datadir=$dir/data" \
index 9a7efac27218cd74d8cbdc1b3dfa4fc594777639..488081715d85f0b50be1f1b910da29200509f584 100644 (file)
@@ -2,8 +2,10 @@
 *.lo
 *.o
 *.so
+*.prof
 .deps
 .libs
+gmon.*
 aweather
 level2
 wsr88ddec
index 9b52348c46f9f6d79d0fa479950859dd25dbb374..84e57d2fbe75436a6f3f5e9864afc1d4ffce9d57 100644 (file)
@@ -39,7 +39,7 @@ pkgconfig_DATA = libgis.pc
 bin_PROGRAMS = gis_test wms_test
 
 gis_test_SOURCES  = gis_test.c gis.h
-gis_test_LDADD    = $(AM_LDADD) libgis.la
+gis_test_LDADD    = $(AM_LDADD) .libs/libgis.a
 
 wms_test_SOURCES  = wms_test.c gis-world.c gis-world.h wms.c wms.h
 wms_test_LDADD    = $(AM_LDADD)
@@ -53,7 +53,7 @@ MAINTAINERCLEANFILES = Makefile.in
 
 test: all
        make -C ../plugins all
-       LD_LIBRARY_PATH=.libs .libs/gis_test
+       ./gis_test
 
 gdb: all
        LD_LIBRARY_PATH=.libs gdb .libs/gis_test
index e1abb07d6dcf24b70aa9cf49a6762be0c895315c..4b8a1d811088b7d218e07ce827ca7ed76b549fd9 100644 (file)
@@ -34,6 +34,7 @@
 #define FOV_DIST   2000.0
 #define MPPX(dist) (4*dist/FOV_DIST)
 
+// #define ROAM_DEBUG
 
 /*************
  * ROAM Code *
@@ -47,28 +48,34 @@ void roam_height_func(RoamPoint *point, gpointer _self)
 {
        GisOpenGL *self = _self;
 
+       gdouble lat, lon, elev;
+       xyz2lle(point->x, point->y, point->z, &lat, &lon, &elev);
+
+#ifdef ROAM_DEBUG
+       lle2xyz(lat, lon, 0, &point->x, &point->y, &point->z);
+       return;
+#endif
+
        gdouble cam_lle[3], cam_xyz[3];
        gis_view_get_location(self->view, &cam_lle[0], &cam_lle[1], &cam_lle[2]);
        lle2xyz(cam_lle[0], cam_lle[1], cam_lle[2], &cam_xyz[0], &cam_xyz[1], &cam_xyz[2]);
 
-       gdouble lat, lon, elev;
-       xyz2lle(point->x, point->y, point->z, &lat, &lon, &elev);
-
        gdouble res = MPPX(distd(cam_xyz, (double*)point));
        //g_message("lat=%f, lon=%f, res=%f", lat, lon, res);
 
-       WmsCacheNode *node = wms_info_fetch_cache(self->srtm, res, lat, lon, NULL, roam_queue_draw, self);
+       point->node = wms_info_fetch_cache(self->srtm, point->node,
+                       res, lat, lon, NULL, roam_queue_draw, self);
 
-       if (node) {
-               WmsBil *bil = node->data;
+       if (point->node) {
+               WmsBil *bil = point->node->data;
 
                gint w = bil->width;
                gint h = bil->height;
 
-               gdouble xmin  = node->latlon[0];
-               gdouble ymin  = node->latlon[1];
-               gdouble xmax  = node->latlon[2];
-               gdouble ymax  = node->latlon[3];
+               gdouble xmin  = point->node->latlon[0];
+               gdouble ymin  = point->node->latlon[1];
+               gdouble xmax  = point->node->latlon[2];
+               gdouble ymax  = point->node->latlon[3];
 
                gdouble xdist = xmax - xmin;
                gdouble ydist = ymax - ymin;
@@ -104,6 +111,15 @@ void roam_height_func(RoamPoint *point, gpointer _self)
 
 void roam_tri_func(RoamTriangle *tri, gpointer _self)
 {
+#ifdef ROAM_DEBUG
+       glBegin(GL_TRIANGLES);
+       glNormal3dv(tri->p.r->norm); glVertex3dv((double*)tri->p.r); 
+       glNormal3dv(tri->p.m->norm); glVertex3dv((double*)tri->p.m); 
+       glNormal3dv(tri->p.l->norm); glVertex3dv((double*)tri->p.l); 
+       glEnd();
+       return;
+#endif
+
        GisOpenGL *self = _self;
        if (tri->error < 0) return;
 
@@ -114,8 +130,10 @@ void roam_tri_func(RoamTriangle *tri, gpointer _self)
        xyz2lle(tri->p.l->x, tri->p.l->y, tri->p.l->z, &lat[2], &lon[2], &elev[2]);
        gdouble lat_max = MAX(MAX(lat[0], lat[1]), lat[2]);
        gdouble lat_min = MIN(MIN(lat[0], lat[1]), lat[2]);
+       gdouble lat_avg = (lat_min+lat_max)/2;
        gdouble lon_max = MAX(MAX(lon[0], lon[1]), lon[2]);
        gdouble lon_min = MIN(MIN(lon[0], lon[1]), lon[2]);
+       gdouble lon_avg = (lon_min+lon_max)/2;
 
        /* Get target resolution */
        gdouble cam_lle[3], cam_xyz[3];
@@ -131,12 +149,23 @@ void roam_tri_func(RoamTriangle *tri, gpointer _self)
         *   - Also fetch center textures that aren't touched by a corner
         *   - Idea: send {lat,lon}{min,max} to fetch_cache and handle it in the recursion */
        /* Fetch textures */
-       WmsCacheNode *textures[4] = {
-               wms_info_fetch_cache(self->bmng, res, lat_min, lon_min, NULL, roam_queue_draw, self),
-               wms_info_fetch_cache(self->bmng, res, lat_max, lon_min, NULL, roam_queue_draw, self),
-               wms_info_fetch_cache(self->bmng, res, lat_min, lon_max, NULL, roam_queue_draw, self),
-               wms_info_fetch_cache(self->bmng, res, lat_max, lon_max, NULL, roam_queue_draw, self),
-       };
+       tri->nodes[0] = wms_info_fetch_cache(self->bmng, tri->nodes[0], res, lat_min, lon_min, NULL, roam_queue_draw, self);
+       tri->nodes[1] = wms_info_fetch_cache(self->bmng, tri->nodes[1], res, lat_max, lon_min, NULL, roam_queue_draw, self);
+       tri->nodes[2] = wms_info_fetch_cache(self->bmng, tri->nodes[2], res, lat_min, lon_max, NULL, roam_queue_draw, self);
+       tri->nodes[3] = wms_info_fetch_cache(self->bmng, tri->nodes[3], res, lat_max, lon_max, NULL, roam_queue_draw, self);
+       tri->nodes[4] = wms_info_fetch_cache(self->bmng, tri->nodes[4], res, lat_avg, lon_avg, NULL, roam_queue_draw, self);
+       /* Hopefully get all textures at the same resolution to prevent overlaps */
+       //gdouble maxres = 0;
+       //for (int i = 0; i < 5; i++)
+       //      if (tri->nodes[i] && tri->nodes[i]->res > maxres)
+       //              maxres = tri->nodes[i]->res;
+       //if (maxres != 0) {
+       //      tri->nodes[0] = wms_info_fetch_cache(self->bmng, tri->nodes[0], maxres, lat_min, lon_min, NULL, roam_queue_draw, self);
+       //      tri->nodes[1] = wms_info_fetch_cache(self->bmng, tri->nodes[1], maxres, lat_max, lon_min, NULL, roam_queue_draw, self);
+       //      tri->nodes[2] = wms_info_fetch_cache(self->bmng, tri->nodes[2], maxres, lat_min, lon_max, NULL, roam_queue_draw, self);
+       //      tri->nodes[3] = wms_info_fetch_cache(self->bmng, tri->nodes[3], maxres, lat_max, lon_max, NULL, roam_queue_draw, self);
+       //      tri->nodes[4] = wms_info_fetch_cache(self->bmng, tri->nodes[4], maxres, lat_avg, lon_avg, NULL, roam_queue_draw, self);
+       //}
 
        /* Vertex color for hieght map viewing, 8848m == Everest */
        gfloat colors[] = {
@@ -149,18 +178,19 @@ void roam_tri_func(RoamTriangle *tri, gpointer _self)
        /* TODO: Prevent double exposure when of hi-res textures on top of
         * low-res textures when some high-res textures are not yet loaded. */
        glBlendFunc(GL_ONE, GL_ZERO);
-       for (int i = 0; i < 4; i++) {
+       for (int i = 0; i < 5; i++) {
                /* Skip missing textures */
-               if (textures[i] == NULL)
+               if (tri->nodes[i] == NULL)
                        continue;
                /* Skip already drawn textures */
                switch (i) {
-               case 3: if (textures[i] == textures[2]) continue;
-               case 2: if (textures[i] == textures[1]) continue;
-               case 1: if (textures[i] == textures[0]) continue;
+               case 4: if (tri->nodes[i] == tri->nodes[3]) continue;
+               case 3: if (tri->nodes[i] == tri->nodes[2]) continue;
+               case 2: if (tri->nodes[i] == tri->nodes[1]) continue;
+               case 1: if (tri->nodes[i] == tri->nodes[0]) continue;
                }
 
-               WmsCacheNode *node = textures[i];
+               WmsCacheNode *node = tri->nodes[i];
 
                if (node->latlon[0] == -180) {
                        if (lon[0] < -90 || lon[1] < -90 || lon[2] < -90) {
@@ -218,8 +248,13 @@ static void set_visuals(GisOpenGL *self)
        /* Lighting */
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
+#ifdef ROAM_DEBUG
+       float light_ambient[]  = {0.7f, 0.7f, 0.7f, 1.0f};
+       float light_diffuse[]  = {2.0f, 2.0f, 2.0f, 1.0f};
+#else
        float light_ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
        float light_diffuse[]  = {5.0f, 5.0f, 5.0f, 1.0f};
+#endif
        float light_position[] = {-13*EARTH_R, 1*EARTH_R, 3*EARTH_R, 1.0f};
        glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
        glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
@@ -253,8 +288,10 @@ static void set_visuals(GisOpenGL *self)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
 
+#ifndef ROAM_DEBUG
        glCullFace(GL_BACK);
        glEnable(GL_CULL_FACE);
+#endif
 
        glClearDepth(1.0);
        glDepthFunc(GL_LEQUAL);
@@ -288,8 +325,9 @@ static gboolean on_configure(GisOpenGL *self, GdkEventConfigure *event, gpointer
        double ang = atan(height/FOV_DIST);
        gluPerspective(rad2deg(ang)*2, width/height, 1, 20*EARTH_R);
 
-       if (self->sphere)
-               roam_sphere_update_errors(self->sphere);
+#ifndef ROAM_DEBUG
+       roam_sphere_update(self->sphere);
+#endif
 
        gis_opengl_end(self);
        return FALSE;
@@ -311,20 +349,25 @@ static gboolean on_expose(GisOpenGL *self, GdkEventExpose *event, gpointer _)
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
+#ifndef ROAM_DEBUG
        set_visuals(self);
        glEnable(GL_TEXTURE_2D);
        roam_sphere_draw(self->sphere);
+#endif
+
+#ifdef  ROAM_DEBUG
+       set_visuals(self);
+       glColor4f(0.0, 0.0, 9.0, 0.6);
+       glDisable(GL_TEXTURE_2D);
+       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+       roam_sphere_draw(self->sphere);
+#endif
 
        //glDisable(GL_TEXTURE_2D);
        //glEnable(GL_COLOR_MATERIAL);
        //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        //roam_sphere_draw(self->sphere);
 
-       //glColor4f(0.0, 0.0, 9.0, 0.6);
-       //glDisable(GL_TEXTURE_2D);
-       //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-       //roam_sphere_draw(self->sphere);
-
        gis_plugins_foreach(self->plugins, G_CALLBACK(on_expose_plugin), self);
 
        set_visuals(self);
@@ -356,10 +399,20 @@ static gboolean on_key_press(GisOpenGL *self, GdkEventKey *event, gpointer _)
        else if (kv == GDK_Right || kv == GDK_l) gis_view_pan(self->view,  0,   pan, 0);
        else if (kv == GDK_minus || kv == GDK_o) gis_view_zoom(self->view, 10./9);
        else if (kv == GDK_plus  || kv == GDK_i) gis_view_zoom(self->view, 9./10);
-       else if (kv == GDK_H                   ) gis_view_rotate(self->view,  0,  0, -10);
-       else if (kv == GDK_J                   ) gis_view_rotate(self->view,  10, 0,  0);
-       else if (kv == GDK_K                   ) gis_view_rotate(self->view, -10, 0,  0);
-       else if (kv == GDK_L                   ) gis_view_rotate(self->view,  0,  0,  10);
+       else if (kv == GDK_H) gis_view_rotate(self->view,  0,  0, -10);
+       else if (kv == GDK_J) gis_view_rotate(self->view,  10, 0,  0);
+       else if (kv == GDK_K) gis_view_rotate(self->view, -10, 0,  0);
+       else if (kv == GDK_L) gis_view_rotate(self->view,  0,  0,  10);
+
+       /* Testing */
+#ifdef ROAM_DEBUG
+       else if (kv == GDK_n) roam_sphere_split_one(self->sphere);
+       else if (kv == GDK_p) roam_sphere_merge_one(self->sphere);
+       else if (kv == GDK_r) roam_sphere_split_merge(self->sphere);
+       else if (kv == GDK_u) roam_sphere_update(self->sphere);
+       gtk_widget_queue_draw(GTK_WIDGET(self));
+#endif
+
        return TRUE;
 }
 
@@ -368,7 +421,9 @@ static void on_view_changed(GisView *view,
 {
        gis_opengl_begin(self);
        set_visuals(self);
-       roam_sphere_update_errors(self->sphere);
+#ifndef ROAM_DEBUG
+       roam_sphere_update(self->sphere);
+#endif
        gis_opengl_redraw(self);
        gis_opengl_end(self);
 }
@@ -474,7 +529,9 @@ static void gis_opengl_init(GisOpenGL *self)
                        GDK_KEY_PRESS_MASK);
        g_object_set(self, "can-focus", TRUE, NULL);
 
+#ifndef ROAM_DEBUG
        self->sm_source = g_timeout_add(10, (GSourceFunc)on_idle, self);
+#endif
 
        g_signal_connect(self, "realize",            G_CALLBACK(on_realize),      NULL);
        g_signal_connect(self, "configure-event",    G_CALLBACK(on_configure),    NULL);
index 906181c148029a6f44378ec43bd45dea7100a48c..598998762f4f86b1431682efc855c29895d28a26 100644 (file)
@@ -125,6 +125,30 @@ g_pqueue_foreach (GPQueue *pqueue,
   g_pqueue_node_foreach (pqueue->root, NULL, func, user_data);
 }
 
+static void
+g_pqueue_add_ptr_cb (gpointer obj, GPtrArray *ptrs)
+{
+       g_ptr_array_add(ptrs, obj);
+}
+/**
+ * g_pqueue_get_array:
+ * @pqueue: a #GQueue.
+ *
+ * Construct a GPtrArray for the items in pqueue. This can be useful when
+ * updating the priorities of all the elements in pqueue.
+ *
+ * Returns: A GPtrArray containing a pointer to each item in pqueue
+ * 
+ * Since: 2.x
+ */
+GPtrArray *
+g_pqueue_get_array (GPQueue *pqueue)
+{
+       GPtrArray *ptrs = g_ptr_array_new();
+       g_pqueue_foreach(pqueue, (GFunc)g_pqueue_add_ptr_cb, ptrs);
+       return ptrs;
+}
+
 static inline gint
 cmp (GPQueue *pqueue,
      GPQueueNode *a,
index 87f6cf97523cacfee1e2e4df945b73eb91d12a2d..3cadf1856cc76cee6731407498f04b2a24104279 100644 (file)
@@ -38,6 +38,8 @@ void          g_pqueue_foreach                (GPQueue *pqueue,
                                                 GFunc func,
                                                 gpointer user_data);
 
+GPtrArray*     g_pqueue_get_array              (GPQueue *pqueue);
+
 GPQueueHandle  g_pqueue_push                   (GPQueue *pqueue,
                                                 gpointer data);
 
index 1a7b4f8a17ab350e700e5155151f7b7d2dba5304..a95c69705f738ac66f94a39a77878403966fc828 100644 (file)
 
 /**
  * TODO:
- *   - Remove/free unused memory
  *   - Optimize for memory consumption
  *   - Profile for computation speed
- *   - Implement good error algorithm
  *   - Target polygon count/detail
  */
 
+/* Misc */
+RoamView *roam_view_get()
+{
+       RoamView *view = g_new0(RoamView, 1);
+       glGetDoublev (GL_MODELVIEW_MATRIX,  view->model); 
+       glGetDoublev (GL_PROJECTION_MATRIX, view->proj); 
+       glGetIntegerv(GL_VIEWPORT,          view->view);          
+       return view;
+}
+
 /* For GPQueue comparators */
 static gint tri_cmp(RoamTriangle *a, RoamTriangle *b, gpointer data)
 {
@@ -58,25 +66,50 @@ RoamPoint *roam_point_new(double x, double y, double z)
        self->z = z;
        return self;
 }
+RoamPoint *roam_point_dup(RoamPoint *self)
+{
+       RoamPoint *new = g_memdup(self, sizeof(RoamPoint));
+       new->tris = 0;
+       return new;
+}
 void roam_point_add_triangle(RoamPoint *self, RoamTriangle *triangle)
 {
        for (int i = 0; i < 3; i++) {
-               self->norm[i] *= self->refs;
+               self->norm[i] *= self->tris;
                self->norm[i] += triangle->norm[i];
        }
-       self->refs++;
+       self->tris++;
        for (int i = 0; i < 3; i++)
-               self->norm[i] /= self->refs;
+               self->norm[i] /= self->tris;
 }
 void roam_point_remove_triangle(RoamPoint *self, RoamTriangle *triangle)
 {
        for (int i = 0; i < 3; i++) {
-               self->norm[i] *= self->refs;
+               self->norm[i] *= self->tris;
                self->norm[i] -= triangle->norm[i];
        }
-       self->refs--;
+       self->tris--;
        for (int i = 0; i < 3; i++)
-               self->norm[i] /= self->refs;
+               self->norm[i] /= self->tris;
+}
+void roam_point_update(RoamPoint *self, RoamSphere *sphere, gboolean do_height)
+{
+       if (!self->cached) {
+               /* Cache height */
+               if (do_height)
+                       sphere->height_func(self, sphere->user_data);
+
+               /* Cache projection */
+               gluProject(self->x, self->y, self->z,
+                       sphere->view->model, sphere->view->proj, sphere->view->view,
+                       &self->px, &self->py, &self->pz);
+
+               self->cached = TRUE;
+       }
+}
+void roam_point_clear(RoamPoint *self)
+{
+       self->cached = FALSE;
 }
 
 /****************
@@ -108,8 +141,8 @@ RoamTriangle *roam_triangle_new(RoamPoint *l, RoamPoint *m, RoamPoint *r)
        self->norm[2] = pa[0] * pb[1] - pa[1] * pb[0];
 
        double total = sqrt(self->norm[0] * self->norm[0] +
-                          self->norm[1] * self->norm[1] +
-                          self->norm[2] * self->norm[2]);
+                           self->norm[1] * self->norm[1] +
+                           self->norm[2] * self->norm[2]);
 
        self->norm[0] /= total;
        self->norm[1] /= total;
@@ -131,7 +164,8 @@ void roam_triangle_add(RoamTriangle *self,
        roam_point_add_triangle(self->p.m, self);
        roam_point_add_triangle(self->p.r, self);
 
-       roam_triangle_update_error(self, sphere, NULL);
+       if (sphere->view)
+               roam_triangle_update(self, sphere);
 
        self->handle = g_pqueue_push(sphere->triangles, self);
 }
@@ -154,73 +188,71 @@ void roam_triangle_sync_neighbors(RoamTriangle *new, RoamTriangle *old, RoamTria
        else g_assert_not_reached();
 }
 
-gboolean roam_triangle_update_error_visible(RoamPoint *point, double *model, double *proj)
+gboolean roam_point_visible(RoamPoint *self, RoamSphere *sphere)
 {
-       double x, y, z;
-       int view[4] = {0,0,1,1};
-       if (!gluProject(point->x, point->y, point->z, model, proj, view, &x, &y, &z)) {
-               g_warning("RoamTriangle: update_error_visible - gluProject failed");
-               return TRUE;
-       }
-       return !(x < 0 || x > 1 ||
-                y < 0 || y > 1 ||
-                z < 0 || z > 1);
+       gint *view = sphere->view->view;
+       return self->px > view[0] && self->px < view[2] &&
+              self->py > view[1] && self->py < view[3] &&
+              self->pz > 0       && self->pz < 1;
+       //double x, y, z;
+       //int view[4] = {0,0,1,1};
+       //gluProject(self->x, self->y, self->z,
+       //              sphere->view->model, sphere->view->proj, view,
+       //              &x, &y, &z);
+       //return !(x < 0 || x > 1 ||
+       //         y < 0 || y > 1 ||
+       //         z < 0 || z > 1);
 }
-
-void roam_triangle_update_error(RoamTriangle *self, RoamSphere *sphere, GPQueue *triangles)
+gboolean roam_triangle_visible(RoamTriangle *self, RoamSphere *sphere)
 {
-       RoamPoint cur = {
-               (self->p.l->x + self->p.r->x)/2,
-               (self->p.l->y + self->p.r->y)/2,
-               (self->p.l->z + self->p.r->z)/2,
-       };
-       RoamPoint good = cur;
-       roam_sphere_update_point(sphere, &good);
-
-       //g_message("cur = (%+5.2f %+5.2f %+5.2f)  good = (%+5.2f %+5.2f %+5.2f)",
-       //      cur[0], cur[1], cur[2], good[0], good[1], good[2]);
-
-       double model[16], proj[16]; 
-       int view[4]; 
-       glGetError();
-       glGetDoublev(GL_MODELVIEW_MATRIX, model); 
-       glGetDoublev(GL_PROJECTION_MATRIX, proj); 
-       glGetIntegerv(GL_VIEWPORT, view);          
-       if (glGetError() != GL_NO_ERROR) {
-               g_warning("RoamTriangle: update_error - glGet failed");
-               return;
-       }
+       /* Do this with a bounding box */
+       return roam_point_visible(self->p.l, sphere) ||
+              roam_point_visible(self->p.m, sphere) ||
+              roam_point_visible(self->p.r, sphere);
+}
 
-       double scur[3], sgood[3];
-       gluProject( cur.x, cur.y, cur.z, model,proj,view,  &scur[0], &scur[1], &scur[2]);
-       gluProject(good.x,good.y,good.z, model,proj,view, &sgood[0],&sgood[1],&sgood[2]);
+void roam_triangle_update(RoamTriangle *self, RoamSphere *sphere)
+{
+       /* Update points */
+       roam_point_update(self->p.l, sphere, TRUE);
+       roam_point_update(self->p.m, sphere, TRUE);
+       roam_point_update(self->p.r, sphere, TRUE);
 
        /* Not exactly correct, could be out on both sides (middle in) */
-       if (!roam_triangle_update_error_visible(self->p.l, model, proj) && 
-           !roam_triangle_update_error_visible(self->p.m, model, proj) &&
-           !roam_triangle_update_error_visible(self->p.r, model, proj) &&
-           !roam_triangle_update_error_visible(&good,     model, proj)) {
+       if (!roam_triangle_visible(self, sphere)) {
                self->error = -1;
        } else {
-               self->error = sqrt((scur[0]-sgood[0])*(scur[0]-sgood[0]) +
-                                  (scur[1]-sgood[1])*(scur[1]-sgood[1]));
-
-               /* Multiply by size of triangle (todo, do this in screen space) */
-               double sa[3], sb[3], sc[3];
-               double *a = (double*)self->p.l;
-               double *b = (double*)self->p.m;
-               double *c = (double*)self->p.r;
-               gluProject(a[0],a[1],a[2], model,proj,view, &sa[0],&sa[1],&sa[2]);
-               gluProject(b[0],b[1],b[2], model,proj,view, &sb[0],&sb[1],&sb[2]);
-               gluProject(c[0],c[1],c[2], model,proj,view, &sc[0],&sc[1],&sc[2]);
-               double size = -( sa[0]*(sb[1]-sc[1]) + sb[0]*(sc[1]-sa[1]) + sc[0]*(sa[1]-sb[1]) ) / 2.0;
-               //g_message("%f * %f = %f", self->error, size, self->error * size);
+               RoamPoint *l = self->p.l;
+               RoamPoint *m = self->p.m;
+               RoamPoint *r = self->p.r;
+
+               /* TODO: share this with the base */
+               RoamPoint base = { (l->x + r->x)/2,
+                                  (l->y + r->y)/2,
+                                  (l->z + r->z)/2 };
+               RoamPoint good = base;
+               roam_point_update(&base, sphere, FALSE);
+               roam_point_update(&good, sphere, TRUE);
+
+               self->error = sqrt((base.px - good.px) * (base.px - good.px) +
+                                  (base.py - good.py) * (base.py - good.py));
+
+               /* Multiply by size of triangle */
+               double size = -( l->px * (m->py - r->py) +
+                                m->px * (r->py - l->py) +
+                                r->px * (l->py - m->py) ) / 2.0;
+
                /* Size < 0 == backface */
                self->error *= size;
        }
+}
 
-       if (triangles)
-               g_pqueue_priority_changed(triangles, self->handle);
+void roam_triangle_clear(RoamTriangle *self)
+{
+       /* Clear points */
+       roam_point_clear(self->p.l);
+       roam_point_clear(self->p.m);
+       roam_point_clear(self->p.r);
 }
 
 void roam_triangle_split(RoamTriangle *self, RoamSphere *sphere)
@@ -234,13 +266,12 @@ void roam_triangle_split(RoamTriangle *self, RoamSphere *sphere)
 
        RoamTriangle *base = self->t.b;
 
-       /* Calculate midpoint */
+       /* Duplicate midpoint */
        RoamPoint *mid = roam_point_new(
-               (self->p.l->x + self->p.r->x)/2,
-               (self->p.l->y + self->p.r->y)/2,
-               (self->p.l->z + self->p.r->z)/2
-       );
-       roam_sphere_update_point(sphere, mid);
+                       (self->p.l->x + self->p.r->x)/2,
+                       (self->p.l->y + self->p.r->y)/2,
+                       (self->p.l->z + self->p.r->z)/2);
+       roam_point_update(mid, sphere, TRUE);
 
        /* Add new triangles */
        RoamTriangle *sl = roam_triangle_new(self->p.m, mid, self->p.l); // Self Left
@@ -265,9 +296,10 @@ void roam_triangle_split(RoamTriangle *self, RoamSphere *sphere)
 
        /* Add/Remove diamonds */
        RoamDiamond *diamond = roam_diamond_new(self, base, sl, sr, bl, br);
+       roam_diamond_update(diamond, sphere);
        roam_diamond_add(diamond, sphere);
-       roam_diamond_remove(self->diamond, sphere);
-       roam_diamond_remove(base->diamond, sphere);
+       roam_diamond_remove(self->parent, sphere);
+       roam_diamond_remove(base->parent, sphere);
 }
 
 void roam_triangle_draw_normal(RoamTriangle *self)
@@ -298,25 +330,25 @@ RoamDiamond *roam_diamond_new(
 {
        RoamDiamond *self = g_new0(RoamDiamond, 1);
 
-       self->kid[0] = kid0;
-       self->kid[1] = kid1;
-       self->kid[2] = kid2;
-       self->kid[3] = kid3;
+       self->kids[0] = kid0;
+       self->kids[1] = kid1;
+       self->kids[2] = kid2;
+       self->kids[3] = kid3;
 
-       kid0->diamond = self; 
-       kid1->diamond = self; 
-       kid2->diamond = self; 
-       kid3->diamond = self; 
+       kid0->parent = self; 
+       kid1->parent = self; 
+       kid2->parent = self; 
+       kid3->parent = self; 
 
-       self->parent[0] = parent0;
-       self->parent[1] = parent1;
+       self->parents[0] = parent0;
+       self->parents[1] = parent1;
 
        return self;
 }
 void roam_diamond_add(RoamDiamond *self, RoamSphere *sphere)
 {
        self->active = TRUE;
-       roam_diamond_update_error(self, sphere, NULL);
+       self->error  = MAX(self->parents[0]->error, self->parents[1]->error);
        self->handle = g_pqueue_push(sphere->diamonds, self);
 }
 void roam_diamond_remove(RoamDiamond *self, RoamSphere *sphere)
@@ -333,55 +365,57 @@ void roam_diamond_merge(RoamDiamond *self, RoamSphere *sphere)
        sphere->polys -= 2;
 
        /* TODO: pick the best split */
-       RoamTriangle **kid = self->kid;
+       RoamTriangle **kids = self->kids;
 
        /* Create triangles */
-       RoamTriangle *tri  = self->parent[0];
-       RoamTriangle *base = self->parent[1];
+       RoamTriangle *tri  = self->parents[0];
+       RoamTriangle *base = self->parents[1];
 
-       roam_triangle_add(tri,  kid[0]->t.b, base, kid[1]->t.b, sphere);
-       roam_triangle_add(base, kid[2]->t.b, tri,  kid[3]->t.b, sphere);
+       roam_triangle_add(tri,  kids[0]->t.b, base, kids[1]->t.b, sphere);
+       roam_triangle_add(base, kids[2]->t.b, tri,  kids[3]->t.b, sphere);
 
-       roam_triangle_sync_neighbors(tri,  kid[0], kid[0]->t.b);
-       roam_triangle_sync_neighbors(tri,  kid[1], kid[1]->t.b);
-       roam_triangle_sync_neighbors(base, kid[2], kid[2]->t.b);
-       roam_triangle_sync_neighbors(base, kid[3], kid[3]->t.b);
+       roam_triangle_sync_neighbors(tri,  kids[0], kids[0]->t.b);
+       roam_triangle_sync_neighbors(tri,  kids[1], kids[1]->t.b);
+       roam_triangle_sync_neighbors(base, kids[2], kids[2]->t.b);
+       roam_triangle_sync_neighbors(base, kids[3], kids[3]->t.b);
 
        /* Remove triangles */
-       roam_triangle_remove(kid[0], sphere);
-       roam_triangle_remove(kid[1], sphere);
-       roam_triangle_remove(kid[2], sphere);
-       roam_triangle_remove(kid[3], sphere);
+       roam_triangle_remove(kids[0], sphere);
+       roam_triangle_remove(kids[1], sphere);
+       roam_triangle_remove(kids[2], sphere);
+       roam_triangle_remove(kids[3], sphere);
 
        /* Add/Remove triangles */
        if (tri->t.l->t.l == tri->t.r->t.r &&
-           tri->t.l->t.l != tri && tri->diamond)
-               roam_diamond_add(tri->diamond, sphere);
+           tri->t.l->t.l != tri && tri->parent) {
+               roam_diamond_update(tri->parent, sphere);
+               roam_diamond_add(tri->parent, sphere);
+       }
 
        if (base->t.l->t.l == base->t.r->t.r &&
-           base->t.l->t.l != base && base->diamond)
-               roam_diamond_add(base->diamond, sphere);
+           base->t.l->t.l != base && base->parent) {
+               roam_diamond_update(base->parent, sphere);
+               roam_diamond_add(base->parent, sphere);
+       }
  
        /* Remove and free diamond and child triangles */
        roam_diamond_remove(self, sphere);
-       g_assert(self->kid[0]->p.m == self->kid[1]->p.m &&
-                self->kid[1]->p.m == self->kid[2]->p.m &&
-                self->kid[2]->p.m == self->kid[3]->p.m);
-       g_assert(self->kid[0]->p.m->refs == 0);
-       g_free(self->kid[0]->p.m);
-       g_free(self->kid[0]);
-       g_free(self->kid[1]);
-       g_free(self->kid[2]);
-       g_free(self->kid[3]);
+       g_assert(self->kids[0]->p.m == self->kids[1]->p.m &&
+                self->kids[1]->p.m == self->kids[2]->p.m &&
+                self->kids[2]->p.m == self->kids[3]->p.m);
+       g_assert(self->kids[0]->p.m->tris == 0);
+       g_free(self->kids[0]->p.m);
+       g_free(self->kids[0]);
+       g_free(self->kids[1]);
+       g_free(self->kids[2]);
+       g_free(self->kids[3]);
        g_free(self);
 }
-void roam_diamond_update_error(RoamDiamond *self, RoamSphere *sphere, GPQueue *diamonds)
+void roam_diamond_update(RoamDiamond *self, RoamSphere *sphere)
 {
-       roam_triangle_update_error(self->parent[0], sphere, NULL);
-       roam_triangle_update_error(self->parent[1], sphere, NULL);
-       self->error = MAX(self->parent[0]->error, self->parent[1]->error);
-       if (diamonds)
-               g_pqueue_priority_changed(diamonds, self->handle);
+       roam_triangle_update(self->parents[0], sphere);
+       roam_triangle_update(self->parents[1], sphere);
+       self->error = MAX(self->parents[0]->error, self->parents[1]->error);
 }
 
 /**************
@@ -424,8 +458,6 @@ RoamSphere *roam_sphere_new(RoamTriFunc tri_func, RoamHeightFunc height_func, gp
        };
        RoamTriangle *triangles[12];
 
-       for (int i = 0; i < 8; i++)
-               roam_sphere_update_point(self, vertexes[i]);
        for (int i = 0; i < 12; i++)
                triangles[i] = roam_triangle_new(
                        vertexes[_triangles[i][0][0]],
@@ -440,29 +472,33 @@ RoamSphere *roam_sphere_new(RoamTriFunc tri_func, RoamHeightFunc height_func, gp
 
        return self;
 }
-static void roam_sphere_update_errors_cb(gpointer obj, GPtrArray *ptrs)
+void roam_sphere_update(RoamSphere *self)
 {
-       g_ptr_array_add(ptrs, obj);
-}
-void roam_sphere_update_errors(RoamSphere *self)
-{
-       g_debug("RoamSphere: update_errors - polys=%d", self->polys);
-       GPtrArray *ptrs = g_ptr_array_new();
-       g_pqueue_foreach(self->triangles, (GFunc)roam_sphere_update_errors_cb, ptrs);
-       for (int i = 0; i < ptrs->len; i++)
-               roam_triangle_update_error(ptrs->pdata[i], self, self->triangles);
-       g_ptr_array_free(ptrs, TRUE);
+       g_debug("RoamSphere: update - polys=%d", self->polys);
+       if (self->view) g_free(self->view);
+       self->view = roam_view_get();
+
+       GPtrArray *tris = g_pqueue_get_array(self->triangles);
+       GPtrArray *dias = g_pqueue_get_array(self->diamonds);
+
+       for (int i = 0; i < tris->len; i++) {
+               /* Note: this also updates points */
+               RoamTriangle *tri = tris->pdata[i];
+               roam_triangle_clear(tri);
+               roam_triangle_update(tri, self);
+               g_pqueue_priority_changed(self->triangles, tri->handle);
+       }
 
-       ptrs = g_ptr_array_new();
-       g_pqueue_foreach(self->diamonds, (GFunc)roam_sphere_update_errors_cb, ptrs);
-       for (int i = 0; i < ptrs->len; i++)
-               roam_diamond_update_error(ptrs->pdata[i], self, self->diamonds);
-       g_ptr_array_free(ptrs, TRUE);
-}
-void roam_sphere_update_point(RoamSphere *self, RoamPoint *point)
-{
-       self->height_func(point, self->user_data);
+       for (int i = 0; i < dias->len; i++) {
+               RoamDiamond *dia = dias->pdata[i];
+               roam_diamond_update(dia, self);
+               g_pqueue_priority_changed(self->diamonds, dia->handle);
+       }
+
+       g_ptr_array_free(tris, TRUE);
+       g_ptr_array_free(dias, TRUE);
 }
+
 void roam_sphere_split_one(RoamSphere *self)
 {
        RoamTriangle *to_split = g_pqueue_peek(self->triangles);
@@ -479,18 +515,25 @@ gint roam_sphere_split_merge(RoamSphere *self)
 {
        gint iters = 0, max_iters = 500;
        gint target = 2000;
-       while (self->polys < target && iters++ < max_iters)
-               roam_sphere_split_one(self);
-       while (self->polys > target && iters++ < max_iters)
-               roam_sphere_merge_one(self);
+
+       if (!self->view)
+               return 0;
+
+       if (target - self->polys > 100)
+               while (self->polys < target && iters++ < max_iters)
+                       roam_sphere_split_one(self);
+
+       if (self->polys - target > 100)
+               while (self->polys > target && iters++ < max_iters)
+                       roam_sphere_merge_one(self);
+
        while (((RoamTriangle*)g_pqueue_peek(self->triangles))->error >
               ((RoamDiamond *)g_pqueue_peek(self->diamonds ))->error &&
               iters++ < max_iters) {
+               roam_sphere_merge_one(self);
                roam_sphere_split_one(self);
-               if (((RoamTriangle*)g_pqueue_peek(self->triangles))->error >
-                   ((RoamDiamond *)g_pqueue_peek(self->diamonds ))->error)
-                       roam_sphere_merge_one(self);
        }
+
        return iters;
 }
 void roam_sphere_draw(RoamSphere *self)
@@ -503,9 +546,9 @@ void roam_sphere_draw_normals(RoamSphere *self)
 }
 static void roam_sphere_free_tri(RoamTriangle *tri)
 {
-       if (--tri->p.l->refs == 0) g_free(tri->p.l);
-       if (--tri->p.m->refs == 0) g_free(tri->p.m);
-       if (--tri->p.r->refs == 0) g_free(tri->p.r);
+       if (--tri->p.l->tris == 0) g_free(tri->p.l);
+       if (--tri->p.m->tris == 0) g_free(tri->p.m);
+       if (--tri->p.r->tris == 0) g_free(tri->p.r);
        g_free(tri);
 }
 void roam_sphere_free(RoamSphere *self)
index c2558122169a4d8936b35a524f50e88018a36489..3d2fced0a3e11cbf16ce271ad8094bbdc7222063 100644 (file)
 #define __ROAM_H__
 
 #include "gpqueue.h"
+#include "wms.h"
 
 /* Roam */
+typedef struct _RoamView     RoamView;
 typedef struct _RoamPoint    RoamPoint;
 typedef struct _RoamTriangle RoamTriangle;
 typedef struct _RoamDiamond  RoamDiamond;
@@ -28,18 +30,32 @@ typedef struct _RoamSphere   RoamSphere;
 typedef void (*RoamTriFunc)(RoamTriangle *triangle, gpointer user_data);
 typedef void (*RoamHeightFunc)(RoamPoint *point, gpointer user_data);
 
+/* Misc */
+struct _RoamView {
+       gdouble model[16];
+       gdouble proj[16]; 
+       gint view[4]; 
+};
+
 /*************
  * RoamPoint *
  *************/
 struct _RoamPoint {
-       double x,y,z;
-       double coords;  // Texture coordinantes 
-       double norm[3]; // Vertex normal
-       int    refs;    // Reference count
+       gdouble  x,y,z;     // Model coordinates
+       gdouble  px,py,pz;  // Projected coordinates
+
+       gboolean cached;    // Height/projection cached
+
+       gint     tris;      // Associated triangles
+       gdouble  norm[3];   // Vertex normal
+
+       WmsCacheNode *node; // TODO: don't depend on wms
 };
 RoamPoint *roam_point_new(double x, double y, double z);
 void roam_point_add_triangle(RoamPoint *point, RoamTriangle *triangle);
 void roam_point_remove_triangle(RoamPoint *point, RoamTriangle *triangle);
+void roam_point_update(RoamPoint *point, RoamSphere *sphere, gboolean do_height);
+void roam_point_clear(RoamPoint *self);
 
 /****************
  * RoamTriangle *
@@ -47,17 +63,19 @@ void roam_point_remove_triangle(RoamPoint *point, RoamTriangle *triangle);
 struct _RoamTriangle {
        struct { RoamPoint    *l,*m,*r; } p;
        struct { RoamTriangle *l,*b,*r; } t;
-       RoamDiamond *diamond;
+       RoamDiamond *parent;
        double norm[3];
        double error;
        GPQueueHandle handle;
+
+       WmsCacheNode *nodes[5]; // TODO: don't depend on wms
 };
 RoamTriangle *roam_triangle_new(RoamPoint *l, RoamPoint *m, RoamPoint *r);
 void roam_triangle_add(RoamTriangle *triangle,
                RoamTriangle *left, RoamTriangle *base, RoamTriangle *right,
                RoamSphere *sphere);
 void roam_triangle_remove(RoamTriangle *triangle, RoamSphere *sphere);
-void roam_triangle_update_error(RoamTriangle *triangle, RoamSphere *sphere, GPQueue *triangles);
+void roam_triangle_update(RoamTriangle *triangle, RoamSphere *sphere);
 void roam_triangle_split(RoamTriangle *triangle, RoamSphere *sphere);
 void roam_triangle_draw_normal(RoamTriangle *triangle);
 
@@ -65,8 +83,8 @@ void roam_triangle_draw_normal(RoamTriangle *triangle);
  * RoamDiamond *
  ***************/
 struct _RoamDiamond {
-       RoamTriangle *kid[4];
-       RoamTriangle *parent[2];
+       RoamTriangle *kids[4];
+       RoamTriangle *parents[2];
        double error;
        gboolean active;
        GPQueueHandle handle;
@@ -78,7 +96,7 @@ RoamDiamond *roam_diamond_new(
 void roam_diamond_add(RoamDiamond *diamond, RoamSphere *sphere);
 void roam_diamond_remove(RoamDiamond *diamond, RoamSphere *sphere);
 void roam_diamond_merge(RoamDiamond *diamond, RoamSphere *sphere);
-void roam_diamond_update_error(RoamDiamond *self, RoamSphere *sphere, GPQueue *diamonds);
+void roam_diamond_update(RoamDiamond *self, RoamSphere *sphere);
 
 /**************
  * RoamSphere *
@@ -86,14 +104,14 @@ void roam_diamond_update_error(RoamDiamond *self, RoamSphere *sphere, GPQueue *d
 struct _RoamSphere {
        GPQueue *triangles;
        GPQueue *diamonds;
+       RoamView *view;
        RoamTriFunc tri_func;
        RoamHeightFunc height_func;
        gpointer user_data;
        gint polys;
 };
 RoamSphere *roam_sphere_new(RoamTriFunc tri_func, RoamHeightFunc height_func, gpointer user_data);
-void roam_sphere_update_errors(RoamSphere *sphere);
-void roam_sphere_update_point(RoamSphere *sphere, RoamPoint *point);
+void roam_sphere_update(RoamSphere *sphere);
 void roam_sphere_split_one(RoamSphere *sphere);
 void roam_sphere_merge_one(RoamSphere *sphere);
 gint roam_sphere_split_merge(RoamSphere *sphere);
index 51f69bc8ca8379189d134027cdf493b1f1bfab88..92a3476a8422c73e0422e84acaa330aa026ac884 100644 (file)
@@ -79,7 +79,8 @@ gchar *wms_make_uri(WmsInfo *info, gdouble xmin, gdouble ymin, gdouble xmax, gdo
 /****************
  * WmsCacheNode *
  ****************/
-WmsCacheNode *wms_cache_node_new(gdouble xmin, gdouble ymin, gdouble xmax, gdouble ymax)
+WmsCacheNode *wms_cache_node_new(WmsCacheNode *parent,
+               gdouble xmin, gdouble ymin, gdouble xmax, gdouble ymax, gint width)
 {
        WmsCacheNode *self = g_new0(WmsCacheNode, 1);
        //g_debug("WmsCacheNode: new - %p %+7.3f,%+7.3f,%+7.3f,%+7.3f",
@@ -88,6 +89,11 @@ WmsCacheNode *wms_cache_node_new(gdouble xmin, gdouble ymin, gdouble xmax, gdoub
        self->latlon[1] = ymin;
        self->latlon[2] = xmax;
        self->latlon[3] = ymax;
+       self->parent    = parent;
+       if (ymin <= 0 && ymax >= 0)
+               self->res = ll2m(xmax-xmin, 0)/width;
+       else
+               self->res = ll2m(xmax-xmin, MIN(ABS(ymin),ABS(ymax)))/width;
        return self;
 }
 
@@ -125,10 +131,10 @@ WmsInfo *wms_info_new(WmsLoader loader, WmsFreeer freeer,
        self->width        = width;
        self->height       = height;
 
-       self->max_age      = 30;
+       self->max_age      = 60;
        self->atime        = time(NULL);
        self->gc_source    = g_timeout_add_seconds(1, (GSourceFunc)wms_info_gc, self);
-       self->cache_root   = wms_cache_node_new(-180, -90, 180, 90);
+       self->cache_root   = wms_cache_node_new(NULL, -180, -90, 180, 90, width);
        self->soup         = soup_session_async_new();
        return self;
 }
@@ -225,8 +231,8 @@ void wms_info_cache(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
                }
 
                /* Break if current resolution (m/px) is good enough */
-               if (ll2m(xdist, cur_lat)/info->width < resolution  ||
-                   ll2m(xdist, cur_lat)/info->width < info->resolution)
+               if (ll2m(xdist, cur_lat)/info->width <= resolution  ||
+                   ll2m(xdist, cur_lat)/info->width <= info->resolution)
                        break;
 
                /* Get locations for the correct sub-tile */
@@ -246,7 +252,8 @@ void wms_info_cache(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
                g_string_append_printf(target_path, "/%d%d", xpos, ypos);
                if (target_node->children[xpos][ypos] == NULL)
                        target_node->children[xpos][ypos] =
-                               wms_cache_node_new(xmin, ymin, xmax, ymax);
+                               wms_cache_node_new(target_node,
+                                       xmin, ymin, xmax, ymax, info->width);
                target_node = target_node->children[xpos][ypos];
        }
 
@@ -297,36 +304,46 @@ void wms_info_cache(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
                g_string_free(target_path, TRUE);
        }
 }
-WmsCacheNode *wms_info_fetch(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
+/* TODO:
+ *   - Store WmsCacheNode in point and then use parent pointers to go up/down
+ *   - If resolution doesn't change, tell caller to skip remaining calculations
+ */
+WmsCacheNode *wms_info_fetch(WmsInfo *info, WmsCacheNode *root,
+               gdouble resolution, gdouble lat, gdouble lon,
                gboolean *correct)
 {
+       if (root && root->data && !root->caching &&
+           root->latlon[0] <= lon && lon <= root->latlon[2] &&
+           root->latlon[1] <= lat && lat <= root->latlon[3] &&
+           root->res <= resolution &&
+           (!root->parent || root->parent->res > resolution)) {
+               *correct = TRUE;
+               info->atime = time(NULL);
+               root->atime = info->atime;
+               return root;
+       }
+
        if (info->cache_root == NULL) {
                *correct = FALSE;
                return NULL;
        }
        WmsCacheNode *node = info->cache_root;
        WmsCacheNode *best = (node && node->data ? node : NULL);
-       gdouble x=lon, y=lat;
-       gdouble xmin=-180, ymin=-90, xmax=180, ymax=90;
-       gdouble xdist = xmax - xmin;
-       gdouble ydist = ymax - ymin;
+       gdouble xmin=-180, ymin=-90, xmax=180, ymax=90, xdist=360, ydist=180;
        gdouble cur_lat = 0;
        int xpos=0, ypos=0;
-       while (ll2m(xdist, cur_lat)/info->width > resolution  &&
-              ll2m(xdist, cur_lat)/info->width > info->resolution) {
+       gdouble cur_res = ll2m(xdist, cur_lat)/info->width;
+       while (cur_res > resolution  &&
+              cur_res > info->resolution) {
 
-               xpos = (int)(((x - xmin) / xdist) * 4);
-               ypos = (int)(((y - ymin) / ydist) * 4);
-               //g_message("%d = (int)(((%f - %f) / %f) * 4)",
-               //              xpos, x, xmin, xdist);
+               xpos = ((lon - xmin) / xdist) * 4;
+               ypos = ((lat - ymin) / ydist) * 4;
                if (xpos == 4) xpos--;
                if (ypos == 4) ypos--;
                xdist /= 4;
                ydist /= 4;
                xmin = xmin + xdist*(xpos+0);
                ymin = ymin + ydist*(ypos+0);
-               xmax = xmin + xdist;
-               ymax = ymin + ydist; 
                cur_lat = MIN(ABS(ymin), ABS(ymax));
 
                node = node->children[xpos][ypos];
@@ -334,6 +351,8 @@ WmsCacheNode *wms_info_fetch(WmsInfo *info, gdouble resolution, gdouble lat, gdo
                        break;
                if (node->data)
                        best = node;
+
+               cur_res = ll2m(xdist, cur_lat)/info->width;
        }
        if (correct)
                *correct = (node && node == best);
@@ -343,13 +362,19 @@ WmsCacheNode *wms_info_fetch(WmsInfo *info, gdouble resolution, gdouble lat, gdo
        return best;
 }
 
-WmsCacheNode *wms_info_fetch_cache(WmsInfo *info, gdouble res, gdouble lat, gdouble lon,
+WmsCacheNode *wms_info_fetch_cache(WmsInfo *info, WmsCacheNode *root,
+               gdouble res, gdouble lat, gdouble lon,
                WmsChunkCallback chunk_callback, WmsDoneCallback done_callback, gpointer user_data)
 {
+       /* Fetch a node, if it isn't cached, cache it, also keep it's parent cached */
        gboolean correct;
-       WmsCacheNode *node = wms_info_fetch(info, res, lat, lon, &correct);
+       WmsCacheNode *node = wms_info_fetch(info, root, res, lat, lon, &correct);
        if (!node || !correct)
                wms_info_cache(info, res, lat, lon, chunk_callback, done_callback, user_data);
+       //else if (node->parent && node->parent->data == NULL)
+       //      wms_info_cache(info, node->parent->res, lat, lon, chunk_callback, done_callback, user_data);
+       //else if  (node->parent)
+       //      node->parent->atime = node->atime;
        return node;
 }
 
@@ -357,8 +382,8 @@ WmsCacheNode *wms_info_fetch_cache(WmsInfo *info, gdouble res, gdouble lat, gdou
 static WmsCacheNode *wms_info_gc_cb(WmsInfo *self, WmsCacheNode *node)
 {
        gboolean empty = FALSE;
-       if (node->data && !node->caching &&
-           self->atime - node->atime > self->max_age) {
+       if (self->atime - node->atime > self->max_age &&
+           node->data && node != self->cache_root && !node->caching) {
                g_debug("WmsInfo: gc - expired node %p", node);
                self->freeer(node);
                node->data = NULL;
@@ -373,8 +398,13 @@ static WmsCacheNode *wms_info_gc_cb(WmsInfo *self, WmsCacheNode *node)
                        }
        if (empty) {
                g_debug("WmsInfo: gc - empty branch %p", node);
+               /* 
+                * TODO: Don't prune nodes while we're caching WmsCacheNodes in the Roam triangles
+                * and points
                g_free(node);
                return NULL;
+               */
+               return node;
        } else {
                return node;
        }
index dfe6b7dd6ed94b4302b64e577a0286904c76caa9..a419e74cf0cc12480df6432807bd1d2e1be7bc4f 100644 (file)
@@ -35,13 +35,15 @@ typedef void (*WmsFreeer)(WmsCacheNode *node);
  ****************/
 struct _WmsCacheNode {
        gpointer data;
-       gdouble latlon[4]; // xmin,ymin,xmax,ymax
+       gdouble  latlon[4]; // xmin,ymin,xmax,ymax
+       gdouble  res;       // xmin,ymin,xmax,ymax
        gboolean caching;
-       time_t atime;
+       time_t   atime;
+       WmsCacheNode *parent;
        WmsCacheNode *children[4][4];
 };
 
-WmsCacheNode *wms_cache_node_new(gdouble xmin, gdouble ymin, gdouble xmax, gdouble ymax);
+WmsCacheNode *wms_cache_node_new(WmsCacheNode *parent, gdouble xmin, gdouble ymin, gdouble xmax, gdouble ymax, gint width);
 
 void wms_cache_node_free(WmsCacheNode *node, WmsFreeer freeer);
 
@@ -49,8 +51,6 @@ void wms_cache_node_free(WmsCacheNode *node, WmsFreeer freeer);
  * WmsInfo *
  ***********/
 struct _WmsInfo {
-       WmsLoader loader;
-       WmsFreeer freeer;
        gchar *uri_prefix;
        gchar *uri_layer;
        gchar *uri_format;
@@ -63,8 +63,10 @@ struct _WmsInfo {
        guint  max_age;
        guint  gc_source;
        time_t atime;
+       WmsLoader     loader;
+       WmsFreeer     freeer;
        WmsCacheNode *cache_root;
-       SoupSession *soup;
+       SoupSession  *soup;
 };
 
 WmsInfo *wms_info_new(WmsLoader loader, WmsFreeer freeer,
@@ -76,10 +78,12 @@ void wms_info_cache(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
                WmsChunkCallback chunk_callback, WmsDoneCallback done_callback,
                gpointer user_data);
 
-WmsCacheNode *wms_info_fetch(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
+WmsCacheNode *wms_info_fetch(WmsInfo *info, WmsCacheNode *root,
+               gdouble resolution, gdouble lat, gdouble lon,
                gboolean *correct);
 
-WmsCacheNode *wms_info_fetch_cache(WmsInfo *info, gdouble resolution, gdouble lat, gdouble lon,
+WmsCacheNode *wms_info_fetch_cache(WmsInfo *info, WmsCacheNode *root,
+               gdouble resolution, gdouble lat, gdouble lon,
                WmsChunkCallback chunk_callback, WmsDoneCallback done_callback,
                gpointer user_data);
 
index 3ea977eedb8692a54e150d2887980829df9ee6f9..2eb4500fa1c323a120191f3909dc172ea677a068 100644 (file)
@@ -69,10 +69,10 @@ int main(int argc, char **argv)
        gdouble res = 200, lon = -101.76, lat = 46.85;
 
        WmsInfo *bmng_info = wms_info_new_for_bmng(bmng_pixbuf_loader, bmng_pixbuf_freeer);
-       wms_info_cache(bmng_info, res, lat, lon, chunk_callback, done_callback, &bmng_state);
+       wms_info_fetch_cache(bmng_info, NULL, res, lat, lon, chunk_callback, done_callback, &bmng_state);
 
        WmsInfo *srtm_info = wms_info_new_for_srtm(srtm_pixbuf_loader, srtm_pixbuf_freeer);
-       wms_info_cache(srtm_info, res, lat, lon, chunk_callback, done_callback, &srtm_state);
+       wms_info_fetch_cache(srtm_info, NULL, res, lat, lon, chunk_callback, done_callback, &srtm_state);
 
        gtk_widget_show_all(win);
        gtk_main();