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 "RasterTileCache.hpp"
25 #include "Terrain/RasterLocation.hpp"
37 * Replaces "water" samples with 0.
41 ReplaceWater0(short h
)
43 return RasterBuffer::IsWater(h
) ? 0 : h
;
47 RasterTileCache::FirstIntersection(const int x0
, const int y0
,
48 const int x1
, const int y1
,
51 const int slope_fact
, const int h_ceiling
,
53 RasterLocation
&_location
, int &_h
,
54 const bool can_climb
) const
56 RasterLocation
location(x0
, y0
);
57 if (location
.x
>= width
|| location
.y
>= height
)
58 // origin is outside overall bounds
61 const short h_origin2
= GetFieldDirect(x0
, y0
).first
;
62 if (RasterBuffer::IsInvalid(h_origin2
)) {
68 if (!RasterBuffer::IsSpecial(h_origin2
))
69 h_origin
= std::max(h_origin
, (int)h_origin2
);
71 h_dest
= std::max(h_dest
, h_origin
);
73 // line algorithm parameters
74 const int dx
= abs(x1
-x0
);
75 const int dy
= abs(y1
-y0
);
77 const int sx
= (x0
< x1
)? 1: -1;
78 const int sy
= (y0
< y1
)? 1: -1;
80 // max number of steps to walk
81 const int max_steps
= (dx
+dy
);
82 // calculate number of fine steps to produce a step on the overview field
83 const int step_fine
= std::max(1, max_steps
>> INTERSECT_BITS
);
84 // number of steps for update to the overview map
85 const int step_coarse
= std::max(1<< OVERVIEW_BITS
, step_fine
);
87 // number of steps to be cleared after climbing over obstruction
88 const int intersect_steps
= 32;
90 // counter for steps to reach next position to be checked on the field.
91 unsigned step_counter
= 0;
92 // total counter of fine steps
95 // number of steps since intersection
96 int intersect_counter
= 0;
99 printf("# max steps %d\n", max_steps
);
100 printf("# step coarse %d\n", step_coarse
);
101 printf("# step fine %d\n", step_fine
);
104 // early exit if origin is too high (should not occur)
105 if (h_origin
> h_ceiling
) {
107 printf("# fint start above ceiling %d %d\n", h_origin
, h_ceiling
);
109 _location
= location
;
115 printf("# fint width %d height %d\n", width
, height
);
118 // location of last point within ceiling limit that doesnt intersect
119 RasterLocation last_clear_location
= location
;
120 int last_clear_h
= h_origin
;
126 if (location
.x
>= width
|| location
.y
>= height
)
127 break; // outside bounds
129 const auto field_direct
= GetFieldDirect(location
.x
, location
.y
);
130 if (RasterBuffer::IsInvalid(field_direct
.first
))
133 const int h_terrain
= ReplaceWater0(field_direct
.first
) + h_safety
;
134 step_counter
= field_direct
.second
? step_fine
: step_coarse
;
136 // calculate height of glide so far
137 const int dh
= (total_steps
* slope_fact
) >> RASTER_SLOPE_FACT
;
139 // current aircraft height
140 int h_int
= dh
+ h_origin
;
142 h_int
= std::min(h_int
, h_dest
);
146 printf("%d %d %d %d %d # fint\n", location
.x
, location
.y
, h_int
, h_terrain
, h_ceiling
);
149 // this point has intersected if aircraft is below terrain height
150 const bool this_intersecting
= (h_int
< h_terrain
);
152 if (this_intersecting
) {
153 intersect_counter
= 1;
155 // when intersecting, consider origin to have started higher
156 const int h_jump
= h_terrain
- h_int
;
160 // if intersecting beyond desired destination height, allow dest height
162 if (h_terrain
> h_dest
)
165 // if can't climb, must jump so path is pure glide
172 if (h_int
> h_ceiling
) {
173 _location
= last_clear_location
;
176 printf("# fint reach ceiling\n");
178 return true; // reached ceiling
181 if (!this_intersecting
) {
182 if (intersect_counter
) {
183 intersect_counter
+= step_counter
;
185 // was intersecting, now cleared.
186 // exit with small height above terrain
188 printf("# fint int->clear\n");
190 if (intersect_counter
>= intersect_steps
) {
191 _location
= location
;
196 last_clear_location
= location
;
197 last_clear_h
= h_int
;
202 if (!intersect_counter
&& (total_steps
== max_steps
)) {
204 printf("# fint cleared\n");
209 const int e2
= 2*err
;
226 // early exit due to inability to find clearance after intersecting
227 if (intersect_counter
) {
228 _location
= last_clear_location
;
231 printf("# fint early exit\n");
238 inline std::pair
<short, bool>
239 RasterTileCache::GetFieldDirect(const unsigned px
, const unsigned py
) const
244 const RasterTile
&tile
= tiles
.Get(px
/ tile_width
, py
/ tile_height
);
245 if (tile
.IsEnabled())
246 return std::make_pair(tile
.GetHeight(px
, py
), true);
248 // still not found, so go to overview
250 // The overview might not cover the whole tile, if width or height are not
251 // a multiple of 2^OVERVIEW_BITS.
252 unsigned x_overview
= px
>> OVERVIEW_BITS
;
253 unsigned y_overview
= py
>> OVERVIEW_BITS
;
254 assert(x_overview
<= overview
.GetWidth());
255 assert(y_overview
<= overview
.GetHeight());
257 if (x_overview
== overview
.GetWidth())
259 if (y_overview
== overview
.GetHeight())
262 return std::make_pair(overview
.Get(x_overview
, y_overview
), false);
266 RasterTileCache::Intersection(const int x0
, const int y0
,
267 const int x1
, const int y1
,
269 const int slope_fact
) const
271 RasterLocation
location(x0
, y0
);
273 if (location
.x
>= width
|| location
.y
>= height
)
274 // origin is outside overall bounds
277 // line algorithm parameters
278 const int dx
= abs(x1
-x0
);
279 const int dy
= abs(y1
-y0
);
281 const int sx
= (x0
< x1
)? 1: -1;
282 const int sy
= (y0
< y1
)? 1: -1;
284 // max number of steps to walk
285 const int max_steps
= (dx
+dy
);
286 // calculate number of fine steps to produce a step on the overview field
288 // step size at selected refinement level
289 const int refine_step
= max_steps
>> 5;
291 // number of steps for update to the fine map
292 const int step_fine
= std::max(1, refine_step
);
293 // number of steps for update to the overview map
294 const int step_coarse
= std::max(1<< OVERVIEW_BITS
, step_fine
);
296 // counter for steps to reach next position to be checked on the field.
297 unsigned step_counter
= 0;
298 // total counter of fine steps
302 printf("# max steps %d\n", max_steps
);
303 printf("# step coarse %d\n", step_coarse
);
304 printf("# step fine %d\n", step_fine
);
307 RasterLocation last_clear_location
= location
;
308 int last_clear_h
= h_origin
;
314 if (location
.x
>= width
|| location
.y
>= height
)
315 break; // outside bounds
317 const auto field_direct
= GetFieldDirect(location
.x
, location
.y
);
318 if (RasterBuffer::IsInvalid(field_direct
.first
))
321 const int h_terrain
= ReplaceWater0(field_direct
.first
);
322 step_counter
= field_direct
.second
? step_fine
: step_coarse
;
324 // calculate height of glide so far
325 const int dh
= (total_steps
* slope_fact
) >> RASTER_SLOPE_FACT
;
327 // current aircraft height
328 const int h_int
= h_origin
- dh
;
330 if (h_int
< h_terrain
) {
331 if (refine_step
<3) // can't refine any further
332 return RasterLocation(last_clear_location
.x
, last_clear_location
.y
);
335 return Intersection(last_clear_location
.x
, last_clear_location
.y
,
336 location
.x
, location
.y
, last_clear_h
, slope_fact
);
340 break; // reached max range
342 last_clear_location
= location
;
343 last_clear_h
= h_int
;
346 if (total_steps
> max_steps
)
349 const int e2
= 2*err
;
366 // if we reached invalid terrain, assume we can hit MSL
367 return RasterLocation(x1
, y1
);