2 * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 gchar *gis_tile_path_table[2][2] = {
27 GisTile *gis_tile_new(GisTile *parent,
28 gdouble n, gdouble s, gdouble e, gdouble w)
30 GisTile *self = g_object_new(GIS_TYPE_TILE, NULL);
31 self->parent = parent;
36 self->atime = time(NULL);
40 gchar *gis_tile_get_path(GisTile *child)
42 /* This could be easily cached if necessasairy */
45 for (GisTile *parent = child->parent; parent; child = parent, parent = child->parent)
46 gis_tile_foreach_index(child, x, y)
47 if (parent->children[x][y] == child)
48 parts = g_list_prepend(parts, gis_tile_path_table[x][y]);
49 GString *path = g_string_new("");
50 for (; parts; parts = parts->next)
51 g_string_append(path, parts->data);
53 return g_string_free(path, FALSE);
56 gdouble _gis_tile_get_min_dist(GisTile *self,
57 gdouble lat, gdouble lon, gdouble elev)
59 gdouble tlat = lat > self->edge.n ? self->edge.n :
60 lat < self->edge.s ? self->edge.s : lat;
61 gdouble tlon = lon > self->edge.e ? self->edge.e :
62 lon < self->edge.w ? self->edge.w : lon;
63 gdouble telev = 0; // TODO: elevation at rlat,rlon
64 //if (lat == tlat && lon == tlon)
65 // return elev; /* Shortcut? */
67 lle2xyz( lat, lon, elev, a+0, a+1, a+2);
68 lle2xyz(tlat, tlon, telev, b+0, b+1, b+2);
72 gboolean _gis_tile_needs_split(GisTile *self,
73 gdouble max_res, gint width, gint height,
74 gdouble lat, gdouble lon, gdouble elev)
76 gdouble lat_point = self->edge.n < 0 ? self->edge.n :
77 self->edge.s > 0 ? self->edge.s : 0;
78 gdouble min_dist = _gis_tile_get_min_dist(self, lat, lon, elev);
79 gdouble view_res = MPPX(min_dist);
80 gdouble lon_dist = self->edge.e - self->edge.w;
81 gdouble tile_res = ll2m(lon_dist, lat_point)/width;
83 /* This isn't really right, but it helps with memory since we don't (yet?) test if the tile
85 gdouble scale = elev / min_dist;
87 //g_message("tile=(%7.2f %7.2f %7.2f %7.2f) "
88 // "eye=(%9.1f %9.1f %9.1f) "
89 // "elev=%9.1f / dist=%9.1f = %f",
90 // self->edge.n, self->edge.s, self->edge.e, self->edge.w,
92 // elev, min_dist, scale);
94 if (tile_res < max_res)
96 return view_res < tile_res;
99 void gis_tile_update(GisTile *self,
100 gdouble res, gint width, gint height,
101 gdouble lat, gdouble lon, gdouble elev,
102 GisTileLoadFunc load_func, gpointer user_data)
104 self->atime = time(NULL);
105 //g_debug("GisTile: update - %p->atime = %u", self, (guint)self->atime);
106 gdouble lat_dist = self->edge.n - self->edge.s;
107 gdouble lon_dist = self->edge.e - self->edge.w;
108 if (_gis_tile_needs_split(self, res, width, height, lat, lon, elev)) {
109 gdouble lat_step = lat_dist / G_N_ELEMENTS(self->children);
110 gdouble lon_step = lon_dist / G_N_ELEMENTS(self->children[0]);
112 gis_tile_foreach_index(self, x, y) {
113 if (!self->children[x][y]) {
114 self->children[x][y] = gis_tile_new(self,
115 self->edge.n-(lat_step*(x+0)),
116 self->edge.n-(lat_step*(x+1)),
117 self->edge.w+(lon_step*(y+1)),
118 self->edge.w+(lon_step*(y+0)));
119 load_func(self->children[x][y], user_data);
121 gis_tile_update(self->children[x][y],
124 load_func, user_data);
129 GisTile *gis_tile_find(GisTile *self, gdouble lat, gdouble lon)
131 gint rows = G_N_ELEMENTS(self->children);
132 gint cols = G_N_ELEMENTS(self->children[0]);
134 gdouble lat_step = (self->edge.n - self->edge.s) / rows;
135 gdouble lon_step = (self->edge.e - self->edge.w) / cols;
137 gdouble lat_offset = self->edge.n - lat;;
138 gdouble lon_offset = lon - self->edge.w;
140 gint row = lat_offset / lat_step;
141 gint col = lon_offset / lon_step;
143 if (lon == 180) col--;
144 if (lat == -90) row--;
146 //if (lon == 180 || lon == -180)
147 // g_message("lat=%f,lon=%f step=%f,%f off=%f,%f row=%d/%d,col=%d/%d",
148 // lat,lon, lat_step,lon_step, lat_offset,lon_offset, row,rows,col,cols);
150 if (row < 0 || row >= rows || col < 0 || col >= cols)
152 else if (self->children[row][col] && self->children[row][col]->data)
153 return gis_tile_find(self->children[row][col], lat, lon);
158 GisTile *gis_tile_gc(GisTile *self, time_t atime,
159 GisTileFreeFunc free_func, gpointer user_data)
163 gboolean has_children = FALSE;
165 gis_tile_foreach_index(self, x, y) {
166 self->children[x][y] = gis_tile_gc(
167 self->children[x][y], atime,
168 free_func, user_data);
169 if (self->children[x][y])
172 //g_debug("GisTile: gc - %p->atime=%u < atime=%u",
173 // self, (guint)self->atime, (guint)atime);
174 if (!has_children && self->atime < atime && self->data) {
175 free_func(self, user_data);
182 void gis_tile_free(GisTile *self, GisTileFreeFunc free_func, gpointer user_data)
187 gis_tile_foreach(self, child)
188 gis_tile_free(child, free_func, user_data);
190 free_func(self, user_data);
191 g_object_unref(self);
195 G_DEFINE_TYPE(GisTile, gis_tile, GIS_TYPE_OBJECT);
196 static void gis_tile_init(GisTile *self) { }
197 static void gis_tile_class_init(GisTileClass *klass) { }