From 5b0d4a3f91c424a06365c1c90c4e1c9bc4767b90 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Wed, 9 Sep 2009 01:25:35 +0000 Subject: [PATCH] Roam and Wms optimizations - 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 | 2 +- src/.gitignore | 2 + src/gis/Makefile.am | 4 +- src/gis/gis-opengl.c | 125 +++++++++++----- src/gis/gpqueue.c | 24 +++ src/gis/gpqueue.h | 2 + src/gis/roam.c | 341 ++++++++++++++++++++++++------------------- src/gis/roam.h | 40 +++-- src/gis/wms.c | 76 +++++++--- src/gis/wms.h | 20 ++- src/gis/wms_test.c | 4 +- 11 files changed, 410 insertions(+), 230 deletions(-) diff --git a/gen.sh b/gen.sh index c883ff8..aed8c6d 100755 --- 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" \ diff --git a/src/.gitignore b/src/.gitignore index 9a7efac..4880817 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -2,8 +2,10 @@ *.lo *.o *.so +*.prof .deps .libs +gmon.* aweather level2 wsr88ddec diff --git a/src/gis/Makefile.am b/src/gis/Makefile.am index 9b52348..84e57d2 100644 --- a/src/gis/Makefile.am +++ b/src/gis/Makefile.am @@ -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 diff --git a/src/gis/gis-opengl.c b/src/gis/gis-opengl.c index e1abb07..4b8a1d8 100644 --- a/src/gis/gis-opengl.c +++ b/src/gis/gis-opengl.c @@ -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); diff --git a/src/gis/gpqueue.c b/src/gis/gpqueue.c index 906181c..5989987 100644 --- a/src/gis/gpqueue.c +++ b/src/gis/gpqueue.c @@ -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, diff --git a/src/gis/gpqueue.h b/src/gis/gpqueue.h index 87f6cf9..3cadf18 100644 --- a/src/gis/gpqueue.h +++ b/src/gis/gpqueue.h @@ -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); diff --git a/src/gis/roam.c b/src/gis/roam.c index 1a7b4f8..a95c697 100644 --- a/src/gis/roam.c +++ b/src/gis/roam.c @@ -26,13 +26,21 @@ /** * 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) diff --git a/src/gis/roam.h b/src/gis/roam.h index c255812..3d2fced 100644 --- a/src/gis/roam.h +++ b/src/gis/roam.h @@ -19,8 +19,10 @@ #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); diff --git a/src/gis/wms.c b/src/gis/wms.c index 51f69bc..92a3476 100644 --- a/src/gis/wms.c +++ b/src/gis/wms.c @@ -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; } diff --git a/src/gis/wms.h b/src/gis/wms.h index dfe6b7d..a419e74 100644 --- a/src/gis/wms.h +++ b/src/gis/wms.h @@ -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); diff --git a/src/gis/wms_test.c b/src/gis/wms_test.c index 3ea977e..2eb4500 100644 --- a/src/gis/wms_test.c +++ b/src/gis/wms_test.c @@ -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(); -- 2.43.2