-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaccumulate_funcs.h
171 lines (153 loc) · 4.54 KB
/
accumulate_funcs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <stdlib.h>
#include "global.h"
#define INDEX(row, col) ((size_t)(row) * ncols + (col))
#define DIR_NULL (unsigned char)dir_map->null_value
#define DIR(row, col) dir_map->cells.byte[INDEX(row, col)]
#define ACCUM(row, col) accum_map->cells.uint32[INDEX(row, col)]
#define FIND_UP(row, col) ( \
(row > 0 ? \
(col > 0 && DIR(row - 1, col - 1) == SE ? NW : 0) | \
(DIR(row - 1, col) == S ? N : 0) | \
(col < ncols - 1 && DIR(row - 1, col + 1) == SW ? NE : 0) : 0) | \
(col > 0 && DIR(row, col - 1) == E ? W : 0) | \
(col < ncols - 1 && DIR(row, col + 1) == W ? E : 0) | \
(row < nrows - 1 ? \
(col > 0 && DIR(row + 1, col - 1) == NE ? SW : 0) | \
(DIR(row + 1, col) == N ? S : 0) | \
(col < ncols - 1 && DIR(row + 1, col + 1) == NW ? SE : 0) : 0))
#ifdef USE_LESS_MEMORY
#define ACCUMULATE accumulate_lessmem
#define UP(row, col) FIND_UP(row, col)
#else
#define ACCUMULATE accumulate_moremem
#define UP(row, col) up_cells[INDEX(row, col)]
static unsigned char *up_cells;
#endif
static int nrows, ncols;
static void trace_down(struct raster_map *, struct raster_map *, int, int,
int);
static int sum_up(struct raster_map *, struct raster_map *, int, int);
void ACCUMULATE(struct raster_map *dir_map, struct raster_map *accum_map)
{
int row, col;
nrows = dir_map->nrows;
ncols = dir_map->ncols;
#ifndef USE_LESS_MEMORY
up_cells = calloc((size_t)nrows * ncols, sizeof *up_cells);
#pragma omp parallel for schedule(dynamic) private(col)
for (row = 0; row < nrows; row++) {
for (col = 0; col < ncols; col++)
if (DIR(row, col) != DIR_NULL)
UP(row, col) = FIND_UP(row, col);
}
#endif
#pragma omp parallel for schedule(dynamic) private(col)
for (row = 0; row < nrows; row++) {
for (col = 0; col < ncols; col++)
/* if the current cell is not null and has no upstream cells, start
* tracing down */
if (DIR(row, col) != DIR_NULL && !UP(row, col))
trace_down(dir_map, accum_map, row, col, 1);
}
#ifndef USE_LESS_MEMORY
free(up_cells);
#endif
}
static void trace_down(struct raster_map *dir_map,
struct raster_map *accum_map, int row, int col,
int accum)
{
int accum_up = 0;
/* accumulate the current cell itself */
ACCUM(row, col) = accum;
/* find the downstream cell */
switch (DIR(row, col)) {
case NW:
row--;
col--;
break;
case N:
row--;
break;
case NE:
row--;
col++;
break;
case W:
col--;
break;
case E:
col++;
break;
case SW:
row++;
col--;
break;
case S:
row++;
break;
case SE:
row++;
col++;
break;
}
/* if the downstream cell is null or any upstream cells of the downstream
* cell have never been visited, stop tracing down */
if (row < 0 || row >= nrows || col < 0 || col >= ncols ||
DIR(row, col) == DIR_NULL ||
!(accum_up = sum_up(dir_map, accum_map, row, col)))
return;
/* use gcc -O2 or -O3 flags for tail-call optimization
* (-foptimize-sibling-calls) */
trace_down(dir_map, accum_map, row, col, accum_up + 1);
}
/* if any upstream cells have never been visited, 0 is returned; otherwise, the
* sum of upstream accumulation is returned */
static int sum_up(struct raster_map *dir_map, struct raster_map *accum_map,
int row, int col)
{
int up = UP(row, col);
int sum = 0, accum;
#pragma omp flush(accum_map)
if (up & NW) {
if (!(accum = ACCUM(row - 1, col - 1)))
return 0;
sum += accum;
}
if (up & N) {
if (!(accum = ACCUM(row - 1, col)))
return 0;
sum += accum;
}
if (up & NE) {
if (!(accum = ACCUM(row - 1, col + 1)))
return 0;
sum += accum;
}
if (up & W) {
if (!(accum = ACCUM(row, col - 1)))
return 0;
sum += accum;
}
if (up & E) {
if (!(accum = ACCUM(row, col + 1)))
return 0;
sum += accum;
}
if (up & SW) {
if (!(accum = ACCUM(row + 1, col - 1)))
return 0;
sum += accum;
}
if (up & S) {
if (!(accum = ACCUM(row + 1, col)))
return 0;
sum += accum;
}
if (up & SE) {
if (!(accum = ACCUM(row + 1, col + 1)))
return 0;
sum += accum;
}
return sum;
}