2
* Function added to r.proj
3
* GNU GPL by Morten Hulden <morten@ngb.se>, August 2000
5
* bordwalk.c - projects the border cell centers of a map or region
6
* to check whether they are inside the borders of another map/region
7
* in a different location, and adjusts the cell header so
8
* only overlapping areas are included. The function is called by main,
9
* first to project the output region into the input map and trim the
10
* borders of this in order to get a smaller map, and faster and less hungry
11
* memory allocation. Then main calls the function again, but reversed,
12
* to project the input map on the output region, trimming this down to
13
* the smallest possible rectangular region.
15
* Simply using corner and midpoints (original r.proj) will only work
16
* between cylindrical projections. In other projections, though he input
17
* map is always a rectangular area, the projected output can be of almost
18
* any shape and its position can be rotated any way. It can even be a
21
* In many projections, especially when large areas are displayed, the edges
22
* of rectangular GRASS regions do not necessarily represent east, west, north
23
* and south. Naming the region edges accordingly (as is regions and cellhd) can be
24
* misleading. (Well, invite code readers/writers to make assumptions anyway. Don't
25
* assume north is really direction north in this code ;)
30
#include <grass/gis.h>
31
#include <grass/gprojects.h>
32
#include <grass/glocale.h>
34
void bordwalk(struct Cell_head *from_hd, struct Cell_head *to_hd,
35
struct pj_info *from_pj, struct pj_info *to_pj)
42
/* Set some (un)reasonable defaults before we walk the borders */
44
xmax = to_hd->west - 0.000001;
45
xmin = to_hd->east + 0.000001;
46
ymin = to_hd->north + 0.000001;
47
ymax = to_hd->south - 0.000001;
52
for (idx = from_hd->west + from_hd->ew_res / 2; idx < from_hd->east;
53
idx += from_hd->ew_res) {
55
hy = from_hd->north - from_hd->ns_res / 2;
56
if (pj_do_proj(&hx, &hy, from_pj, to_pj) < 0)
58
/* check if we are within the region, but allow for some 'almost inside' points */
59
/* (should probably be a factor based on input and output resolutions) */
60
if (!(hx < to_hd->west - to_hd->ew_res) &&
61
!(hx > to_hd->east + to_hd->ew_res) &&
62
!(hy < to_hd->south - to_hd->ns_res) &&
63
!(hy > to_hd->north + to_hd->ns_res)) {
64
xmin = !(hx > xmin) ? hx : xmin;
65
xmax = !(hx < xmax) ? hx : xmax;
66
ymin = !(hy > ymin) ? hy : ymin;
67
ymax = !(hy < ymax) ? hy : ymax;
71
G_debug(3, "Top: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin, xmax,
75
for (idx = from_hd->north - from_hd->ns_res / 2; idx > from_hd->south;
76
idx -= from_hd->ns_res) {
77
hx = from_hd->east - from_hd->ew_res / 2;
79
if (pj_do_proj(&hx, &hy, from_pj, to_pj) < 0)
81
if (!(hx < to_hd->west - to_hd->ew_res) &&
82
!(hx > to_hd->east + to_hd->ew_res) &&
83
!(hy < to_hd->south - to_hd->ns_res) &&
84
!(hy > to_hd->north + to_hd->ns_res)) {
85
xmin = !(hx > xmin) ? hx : xmin;
86
xmax = !(hx < xmax) ? hx : xmax;
87
ymin = !(hy > ymin) ? hy : ymin;
88
ymax = !(hy < ymax) ? hy : ymax;
92
G_debug(3, "Right: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin, xmax,
96
for (idx = from_hd->east - from_hd->ew_res / 2; idx > from_hd->west;
97
idx -= from_hd->ew_res) {
99
hy = from_hd->south + from_hd->ns_res / 2;
100
if (pj_do_proj(&hx, &hy, from_pj, to_pj) < 0)
102
if (!(hx < to_hd->west - to_hd->ew_res) &&
103
!(hx > to_hd->east + to_hd->ew_res) &&
104
!(hy < to_hd->south - to_hd->ns_res) &&
105
!(hy > to_hd->north + to_hd->ns_res)) {
106
xmin = !(hx > xmin) ? hx : xmin;
107
xmax = !(hx < xmax) ? hx : xmax;
108
ymin = !(hy > ymin) ? hy : ymin;
109
ymax = !(hy < ymax) ? hy : ymax;
113
G_debug(3, "Bottom: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin, xmax,
117
for (idx = from_hd->south + from_hd->ns_res / 2; idx < from_hd->north;
118
idx += from_hd->ns_res) {
119
hx = from_hd->west + from_hd->ew_res / 2;
121
if (pj_do_proj(&hx, &hy, from_pj, to_pj) < 0)
123
if (!(hx < to_hd->west - to_hd->ew_res) &&
124
!(hx > to_hd->east + to_hd->ew_res) &&
125
!(hy < to_hd->south - to_hd->ns_res) &&
126
!(hy > to_hd->north + to_hd->ns_res)) {
127
xmin = !(hx > xmin) ? hx : xmin;
128
xmax = !(hx < xmax) ? hx : xmax;
129
ymin = !(hy > ymin) ? hy : ymin;
130
ymax = !(hy < ymax) ? hy : ymax;
134
G_debug(3, "Left: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin, xmax,
137
/* check some special cases by reversing the projection */
139
if (xmin > to_hd->west) {
140
hx = to_hd->west + to_hd->ew_res / 2;
141
hy = to_hd->south + (to_hd->north - to_hd->south) / 2;
142
if (!(pj_do_proj(&hx, &hy, to_pj, from_pj) < 0) &&
143
!(hx < from_hd->west) && !(hx > from_hd->east) &&
144
!(hy < from_hd->south) && !(hy > from_hd->north))
145
xmin = to_hd->west + to_hd->ew_res / 2;
148
if (xmax < to_hd->east) {
149
hx = to_hd->east - to_hd->ew_res / 2;
150
hy = to_hd->south + (to_hd->north - to_hd->south) / 2;
151
if (!(pj_do_proj(&hx, &hy, to_pj, from_pj) < 0) &&
152
!(hx < from_hd->west) && !(hx > from_hd->east) &&
153
!(hy < from_hd->south) && !(hy > from_hd->north))
154
xmax = to_hd->east - to_hd->ew_res / 2;
157
if (ymin > to_hd->south) {
158
hx = to_hd->west + (to_hd->east - to_hd->west) / 2;
159
hy = to_hd->south + to_hd->ns_res / 2;
160
if (!(pj_do_proj(&hx, &hy, to_pj, from_pj) < 0) &&
161
!(hx < from_hd->west) && !(hx > from_hd->east) &&
162
!(hy < from_hd->south) && !(hy > from_hd->north))
163
ymin = to_hd->south + to_hd->ns_res / 2;
166
if (ymax < to_hd->north) {
167
hx = to_hd->west + (to_hd->east - to_hd->west) / 2;
168
hy = to_hd->north - to_hd->ns_res / 2;
169
if (!(pj_do_proj(&hx, &hy, to_pj, from_pj) < 0) &&
170
!(hx < from_hd->west) && !(hx > from_hd->east) &&
171
!(hy < from_hd->south) && !(hy > from_hd->north))
172
ymax = to_hd->north - to_hd->ns_res / 2;
175
G_debug(3, "Extra check: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin,
178
/* if we still have some unresonable default minmax left, then abort */
180
if ((xmin > to_hd->east) || (xmax < to_hd->west)
181
|| (ymin > to_hd->north) || (ymax < to_hd->south))
182
G_fatal_error(_("Input raster map is outside current region"));
184
if (xmin < to_hd->west + to_hd->ew_res / 2)
185
xmin = to_hd->west + to_hd->ew_res / 2;
186
if (xmax > to_hd->east - to_hd->ew_res / 2)
187
xmax = to_hd->east - to_hd->ew_res / 2;
188
if (ymin < to_hd->south + to_hd->ns_res / 2)
189
ymin = to_hd->south + to_hd->ns_res / 2;
190
if (ymax > to_hd->north - to_hd->ns_res / 2)
191
ymax = to_hd->north - to_hd->ns_res / 2;
193
/* adjust to edges */
195
idx = (int)floor(G_easting_to_col(xmin, to_hd));
196
xmin = G_col_to_easting(idx + 0.0, to_hd);
197
idx = (int)floor(G_easting_to_col(xmax, to_hd));
198
xmax = G_col_to_easting(idx + 1.0, to_hd);
199
idx = (int)floor(G_northing_to_row(ymin, to_hd));
200
ymin = G_row_to_northing(idx + 1.0, to_hd);
201
idx = (int)floor(G_northing_to_row(ymax, to_hd));
202
ymax = G_row_to_northing(idx + 0.0, to_hd);
204
to_hd->west = (xmin < to_hd->west) ? to_hd->west : xmin;
205
to_hd->east = (xmax > to_hd->east) ? to_hd->east : xmax;
206
to_hd->south = (ymin < to_hd->south) ? to_hd->south : ymin;
207
to_hd->north = (ymax > to_hd->north) ? to_hd->north : ymax;
209
G_debug(3, "Final check: xmin: %f; xmax: %f; ymin: %f; ymax: %f", xmin,