android/GlueIOIOPort: fix spurious errors after IOIO baud rate change
[xcsoar.git] / src / Terrain / RasterMap.cpp
blob6b34a60118223278929f29a2ddcfbd2b5eaec0cc
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "Terrain/RasterMap.hpp"
25 #include "Geo/GeoClip.hpp"
26 #include "IO/FileCache.hpp"
27 #include "Util/ConvertString.hpp"
29 #include <algorithm>
30 #include <assert.h>
31 #include <string.h>
33 static char *
34 ToNarrowPath(const TCHAR *src)
36 return WideToACPConverter(src).StealDup();
39 RasterMap::RasterMap(const TCHAR *_path, const TCHAR *world_file,
40 FileCache *cache, OperationEnvironment &operation)
41 :path(ToNarrowPath(_path))
43 bool cache_loaded = false;
44 if (cache != NULL) {
45 /* load the cache file */
46 FILE *file = cache->Load(_T("terrain"), _path);
47 if (file != NULL) {
48 cache_loaded = raster_tile_cache.LoadCache(file);
49 fclose(file);
53 if (!cache_loaded) {
54 if (!raster_tile_cache.LoadOverview(path, world_file, operation))
55 return;
57 if (cache != NULL) {
58 /* save the cache file */
59 FILE *file = cache->Save(_T("terrain"), _path);
60 if (file != NULL) {
61 if (raster_tile_cache.SaveCache(file))
62 cache->Commit(_T("terrain"), file);
63 else
64 cache->Cancel(_T("terrain"), file);
69 projection.Set(GetBounds(),
70 raster_tile_cache.GetFineWidth(),
71 raster_tile_cache.GetFineHeight());
74 RasterMap::~RasterMap() {
75 free(path);
78 static unsigned
79 AngleToPixel(Angle value, Angle start, Angle end, unsigned width)
81 return unsigned((value - start).Native() * width / (end - start).Native());
84 void
85 RasterMap::SetViewCenter(const GeoPoint &location, fixed radius)
87 if (!raster_tile_cache.GetInitialised())
88 return;
90 const GeoBounds &bounds = GetBounds();
92 int x = AngleToPixel(location.longitude, bounds.GetWest(), bounds.GetEast(),
93 raster_tile_cache.GetWidth());
95 int y = AngleToPixel(location.latitude, bounds.GetNorth(), bounds.GetSouth(),
96 raster_tile_cache.GetHeight());
98 raster_tile_cache.UpdateTiles(path, x, y,
99 projection.DistancePixelsCoarse(radius));
102 short
103 RasterMap::GetHeight(const GeoPoint &location) const
105 RasterLocation pt = projection.ProjectCoarse(location);
106 return raster_tile_cache.GetHeight(pt.x, pt.y);
109 short
110 RasterMap::GetInterpolatedHeight(const GeoPoint &location) const
112 RasterLocation pt = projection.ProjectFine(location);
113 return raster_tile_cache.GetInterpolatedHeight(pt.x, pt.y);
116 void
117 RasterMap::ScanLine(const GeoPoint &start, const GeoPoint &end,
118 short *buffer, unsigned size, bool interpolate) const
120 assert(buffer != NULL);
121 assert(size > 0);
123 const short invalid = RasterBuffer::TERRAIN_INVALID;
125 const fixed total_distance = start.Distance(end);
126 if (!positive(total_distance)) {
127 std::fill(buffer, buffer + size, invalid);
128 return;
131 /* clip the line to the map bounds */
133 GeoPoint clipped_start = start, clipped_end = end;
134 const GeoClip clip(GetBounds());
135 if (!clip.ClipLine(clipped_start, clipped_end)) {
136 std::fill(buffer, buffer + size, invalid);
137 return;
140 fixed clipped_start_distance =
141 std::max(clipped_start.Distance(start), fixed(0));
142 fixed clipped_end_distance =
143 std::max(clipped_end.Distance(start), fixed(0));
145 /* calculate the offsets of the clipped range within the buffer */
147 unsigned clipped_start_offset =
148 (unsigned)(size * clipped_start_distance / total_distance);
149 unsigned clipped_end_offset =
150 uround(size * clipped_end_distance / total_distance);
151 if (clipped_end_offset > size)
152 clipped_end_offset = size;
153 if (clipped_start_offset + 2 > clipped_end_offset) {
154 std::fill(buffer, buffer + size, invalid);
155 return;
158 assert(clipped_start_offset < size);
159 assert(clipped_end_offset <= size);
161 /* fill the two regions which are outside the map */
163 std::fill(buffer, buffer + clipped_start_offset, invalid);
164 std::fill(buffer + clipped_end_offset, buffer + size, invalid);
166 /* now scan the middle part which is within the map */
168 const unsigned max_x = raster_tile_cache.GetFineWidth();
169 const unsigned max_y = raster_tile_cache.GetFineHeight();
171 RasterLocation raster_start = projection.ProjectFine(clipped_start);
172 if (raster_start.x >= max_x)
173 raster_start.x = max_x - 1;
174 if (raster_start.y >= max_y)
175 raster_start.y = max_y - 1;
177 RasterLocation raster_end = projection.ProjectFine(clipped_end);
178 if (raster_end.x >= max_x)
179 raster_end.x = max_x - 1;
180 if (raster_end.y >= max_y)
181 raster_end.y = max_y - 1;
183 raster_tile_cache.ScanLine(raster_start, raster_end,
184 buffer + clipped_start_offset,
185 clipped_end_offset - clipped_start_offset,
186 interpolate);
189 bool
190 RasterMap::FirstIntersection(const GeoPoint &origin, const int h_origin,
191 const GeoPoint &destination, const int h_destination,
192 const int h_virt, const int h_ceiling,
193 const int h_safety,
194 GeoPoint &intx, int &h) const
196 const RasterLocation c_origin = projection.ProjectCoarse(origin);
197 const RasterLocation c_destination = projection.ProjectCoarse(destination);
198 const int c_diff = c_origin.ManhattanDistance(c_destination);
199 const bool can_climb = (h_destination< h_virt);
201 intx = destination; h = h_destination; // fallback, pass
202 if (c_diff==0) {
203 return false; // no distance
206 const int slope_fact = (((int)h_virt) << RASTER_SLOPE_FACT) / c_diff;
207 const int vh_origin = std::max(h_origin,
208 h_destination
209 - ((c_diff * slope_fact) >> RASTER_SLOPE_FACT));
211 RasterLocation c_int;
212 if (raster_tile_cache.FirstIntersection(c_origin.x, c_origin.y,
213 c_destination.x, c_destination.y,
214 vh_origin, h_destination,
215 slope_fact, h_ceiling, h_safety,
216 c_int, h,
217 can_climb)) {
218 bool changed = c_int != c_destination ||
219 (h > h_destination && c_int == c_destination);
220 if (changed) {
221 intx = projection.UnprojectCoarse(c_int);
222 assert(h>= h_origin);
224 return changed;
225 } else {
226 return false;
230 GeoPoint
231 RasterMap::Intersection(const GeoPoint& origin,
232 const int h_origin, const int h_glide,
233 const GeoPoint& destination) const
235 const RasterLocation c_origin = projection.ProjectCoarse(origin);
236 const RasterLocation c_destination = projection.ProjectCoarse(destination);
237 const int c_diff = c_origin.ManhattanDistance(c_destination);
238 if (c_diff==0) {
239 return destination; // no distance
241 const int slope_fact = (((int)h_glide) << RASTER_SLOPE_FACT) / c_diff;
243 RasterLocation c_int =
244 raster_tile_cache.Intersection(c_origin.x, c_origin.y,
245 c_destination.x, c_destination.y,
246 h_origin, slope_fact);
248 if (c_int == c_destination) // made it to grid location, return exact location
249 // of destination
250 return destination;
252 return projection.UnprojectCoarse(c_int);