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"
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;
45 /* load the cache file */
46 FILE *file
= cache
->Load(_T("terrain"), _path
);
48 cache_loaded
= raster_tile_cache
.LoadCache(file
);
54 if (!raster_tile_cache
.LoadOverview(path
, world_file
, operation
))
58 /* save the cache file */
59 FILE *file
= cache
->Save(_T("terrain"), _path
);
61 if (raster_tile_cache
.SaveCache(file
))
62 cache
->Commit(_T("terrain"), file
);
64 cache
->Cancel(_T("terrain"), file
);
69 projection
.Set(GetBounds(),
70 raster_tile_cache
.GetFineWidth(),
71 raster_tile_cache
.GetFineHeight());
74 RasterMap::~RasterMap() {
79 AngleToPixel(Angle value
, Angle start
, Angle end
, unsigned width
)
81 return unsigned((value
- start
).Native() * width
/ (end
- start
).Native());
85 RasterMap::SetViewCenter(const GeoPoint
&location
, fixed radius
)
87 if (!raster_tile_cache
.GetInitialised())
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
));
103 RasterMap::GetHeight(const GeoPoint
&location
) const
105 RasterLocation pt
= projection
.ProjectCoarse(location
);
106 return raster_tile_cache
.GetHeight(pt
.x
, pt
.y
);
110 RasterMap::GetInterpolatedHeight(const GeoPoint
&location
) const
112 RasterLocation pt
= projection
.ProjectFine(location
);
113 return raster_tile_cache
.GetInterpolatedHeight(pt
.x
, pt
.y
);
117 RasterMap::ScanLine(const GeoPoint
&start
, const GeoPoint
&end
,
118 short *buffer
, unsigned size
, bool interpolate
) const
120 assert(buffer
!= NULL
);
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
);
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
);
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
);
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
,
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
,
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
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
,
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
,
218 bool changed
= c_int
!= c_destination
||
219 (h
> h_destination
&& c_int
== c_destination
);
221 intx
= projection
.UnprojectCoarse(c_int
);
222 assert(h
>= h_origin
);
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
);
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
252 return projection
.UnprojectCoarse(c_int
);