X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgis-tile.c;h=7a0f0b832851c8e8d91535ad4844be651dfe4d6d;hb=82adb52036f7330bb6d47e354c24bcc13c34dd34;hp=ab45616a0e9b2d6d67b65d6b564908d2facb59b6;hpb=2e575e2c348f44d3c723ac344b7296492c76f77a;p=grits diff --git a/src/gis-tile.c b/src/gis-tile.c index ab45616..7a0f0b8 100644 --- a/src/gis-tile.c +++ b/src/gis-tile.c @@ -35,6 +35,7 @@ GisTile *gis_tile_new(GisTile *parent, self->edge.s = s; self->edge.e = e; self->edge.w = w; + self->atime = time(NULL); return self; } @@ -54,6 +55,124 @@ gchar *gis_tile_get_path(GisTile *child) return g_string_free(path, FALSE); } +gdouble _gis_tile_get_min_dist(GisTile *self, + gdouble lat, gdouble lon, gdouble elev) +{ + gdouble tlat = lat > self->edge.n ? self->edge.n : + lat < self->edge.s ? self->edge.s : lat; + gdouble tlon = lon > self->edge.e ? self->edge.e : + lon < self->edge.w ? self->edge.w : lon; + gdouble telev = 0; // TODO: elevation at rlat,rlon + //if (lat == tlat && lon == tlon) + // return elev; /* Shortcut? */ + gdouble a[3], b[3]; + lle2xyz( lat, lon, elev, a+0, a+1, a+2); + lle2xyz(tlat, tlon, telev, b+0, b+1, b+2); + return distd(a, b); +} + +gboolean _gis_tile_needs_split(GisTile *self, + gdouble max_res, gint width, gint height, + gdouble lat, gdouble lon, gdouble elev) +{ + gdouble lat_point = self->edge.n < 0 ? self->edge.n : + self->edge.s > 0 ? self->edge.s : 0; + gdouble min_dist = _gis_tile_get_min_dist(self, lat, lon, elev); + gdouble view_res = MPPX(min_dist); + gdouble lon_dist = self->edge.e - self->edge.w; + gdouble tile_res = ll2m(lon_dist, lat_point)/width; + + /* This isn't really right, but it helps with memory since we don't (yet?) test if the tile + * would be drawn */ + gdouble scale = elev / min_dist; + view_res /= scale; + //g_message("tile=(%7.2f %7.2f %7.2f %7.2f) " + // "eye=(%9.1f %9.1f %9.1f) " + // "elev=%9.1f / dist=%9.1f = %f", + // self->edge.n, self->edge.s, self->edge.e, self->edge.w, + // lat, lon, elev, + // elev, min_dist, scale); + + if (tile_res < max_res) + return FALSE; + return view_res < tile_res; +} + +void gis_tile_update(GisTile *self, + gdouble res, gint width, gint height, + gdouble lat, gdouble lon, gdouble elev, + GisTileLoadFunc load_func, gpointer user_data) +{ + self->atime = time(NULL); + //g_debug("GisTile: update - %p->atime = %u", self, (guint)self->atime); + gdouble lat_dist = self->edge.n - self->edge.s; + gdouble lon_dist = self->edge.e - self->edge.w; + if (_gis_tile_needs_split(self, res, width, height, lat, lon, elev)) { + gdouble lat_step = lat_dist / G_N_ELEMENTS(self->children); + gdouble lon_step = lon_dist / G_N_ELEMENTS(self->children[0]); + int x, y; + gis_tile_foreach_index(self, x, y) { + if (!self->children[x][y]) { + self->children[x][y] = gis_tile_new(self, + self->edge.n-(lat_step*(x+0)), + self->edge.n-(lat_step*(x+1)), + self->edge.w+(lon_step*(y+1)), + self->edge.w+(lon_step*(y+0))); + load_func(self->children[x][y], user_data); + } + gis_tile_update(self->children[x][y], + res, width, height, + lat, lon, elev, + load_func, user_data); + } + } +} + +GisTile *gis_tile_find(GisTile *self, gdouble lat, gdouble lon) +{ + gint rows = G_N_ELEMENTS(self->children); + gint cols = G_N_ELEMENTS(self->children[0]); + + gdouble lat_step = (self->edge.n - self->edge.s) / rows; + gdouble lon_step = (self->edge.e - self->edge.w) / cols; + + gdouble lat_offset = self->edge.n - lat;; + gdouble lon_offset = lon - self->edge.w; + + gint row = lat_offset / lat_step; + gint col = lon_offset / lon_step; + + if (row < 0 || row >= rows || col < 0 || col >= cols) + return NULL; + else if (self->children[row][col] && self->children[row][col]->data) + return gis_tile_find(self->children[row][col], lat, lon); + else + return self; +} + +GisTile *gis_tile_gc(GisTile *self, time_t atime, + GisTileFreeFunc free_func, gpointer user_data) +{ + if (!self) + return NULL; + gboolean has_children = FALSE; + int x, y; + gis_tile_foreach_index(self, x, y) { + self->children[x][y] = gis_tile_gc( + self->children[x][y], atime, + free_func, user_data); + if (self->children[x][y]) + has_children = TRUE; + } + //g_debug("GisTile: gc - %p->atime=%u < atime=%u", + // self, (guint)self->atime, (guint)atime); + if (!has_children && self->atime < atime && self->data) { + free_func(self, user_data); + g_free(self); + return NULL; + } + return self; +} void gis_tile_free(GisTile *self, GisTileFreeFunc free_func, gpointer user_data) {