Quetzal-CoaTL
The Coalescence Template Library
Loading...
Searching...
No Matches
vicinity.hpp
1// Copyright 2021 Arnaud Becheler <abechele@umich.edu>
2
10
11#pragma once
12
13#include "../graph.hpp"
14#include "concepts.hpp"
15
16#include <boost/graph/adjacency_list.hpp>
17#include <boost/graph/adjacency_matrix.hpp>
18
19#include <cassert>
20
21namespace quetzal::geography
22{
23
24namespace detail
25{
26 bool is_on_top_border(auto index, auto width) {
27 return index < width;
28 }
29
30 bool is_on_bottom_border(auto index, auto width, auto height) {
31 return index >= (height - 1) * width;
32 }
33
34 bool is_on_left_border(auto index, auto width) {
35 return index % width == 0;
36 }
37
38 bool is_on_right_border(auto index, auto width) {
39 return (index + 1) % width == 0;
40 }
41
42 bool is_on_border(auto index, auto width, auto height)
43 {
44 return ( is_on_top_border(index, width) or
45 is_on_bottom_border(index, width, height) or
46 is_on_left_border(index, width) or
47 is_on_right_border(index, width) );
48 }
49
50}
51
53{
54 using connectedness = dense;
55
56 template <class G, two_dimensional S, bounding<G, S> B>
57 void connect(G &graph, S const &grid, B bound_policy) const
58 {
59 using directed_category = typename G::directed_category;
60 using vertex_property = typename G::vertex_property;
61 using edge_property = typename G::edge_property;
62
63 int width = grid.width();
64 int height = grid.height();
65 int num_land_vertices = width * height;
66
67 assert(num_land_vertices > 0 and "trying to initialize a graph from an empty grid.");
68
69 for (auto s = 0; s < num_land_vertices; ++s)
70 {
71 for (auto t = s + 1; t < num_land_vertices; ++t)
72 {
73 detail::edge_construction<edge_property>::delegate(s, t, graph, grid); // (s -> v) == (s <- v) if undirected
74 if constexpr (std::same_as<directed_category, anisotropy>)
75 detail::edge_construction<edge_property>::delegate(t, s, graph, grid); // (s -> v) != (s <- v) because directed
76 }
77
78 if( detail::is_on_border(s, width, height ) )
79 bound_policy(s, graph, grid);
80 }
81 }
82};
83
85{
86 public:
87 using connectedness = sparse;
88
89 private:
90 template <typename G> void connect(auto s, auto t, G &graph, auto const &grid) const
91 {
92 using edge_property = typename G::edge_property;
94 if constexpr (std::same_as<typename G::directed_category, anisotropy>)
96 }
97
98 void connect_top_left_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
99 {
100 bound_policy(s, graph, grid);
101 connect(s, s + 1, graph, grid);
102 connect(s, s + grid.width(), graph, grid);
103 }
104
105 void connect_top_right_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
106 {
107 bound_policy(s, graph, grid);
108 connect(s, s - 1, graph, grid);
109 connect(s, s + grid.width(), graph, grid);
110 }
111
112 void connect_top_border_no_corners(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
113 {
114 bound_policy(s, graph, grid);
115 connect(s, s - 1, graph, grid);
116 connect(s, s + 1, graph, grid);
117 connect(s, s + grid.width(), graph, grid);
118 }
119
120 void connect_bottom_left_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
121 {
122 bound_policy(s, graph, grid);
123 connect(s, s + 1, graph, grid);
124 connect(s, s - grid.width(), graph, grid);
125 }
126
127 void connect_bottom_right_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
128 {
129 bound_policy(s, graph, grid);
130 connect(s, s - 1, graph, grid);
131 connect(s, s - grid.width(), graph, grid);
132 }
133
134 void connect_bottom_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
135 {
136 bound_policy(s, graph, grid);
137 connect(s, s - 1, graph, grid);
138 connect(s, s + 1, graph, grid);
139 connect(s, s - grid.width(), graph, grid);
140 }
141
142 void connect_left_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
143 {
144 bound_policy(s, graph, grid);
145 connect(s, s + 1, graph, grid);
146 connect(s, s - grid.width(), graph, grid);
147 connect(s, s + grid.width(), graph, grid);
148 }
149
150 void connect_right_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
151 {
152 bound_policy(s, graph, grid);
153 connect(s, s - 1, graph, grid);
154 connect(s, s - grid.width(), graph, grid);
155 connect(s, s + grid.width(), graph, grid);
156 }
157
158 void connect_interior_vertices(auto s, auto &graph, auto const &grid) const
159 {
160 connect(s, s + 1, graph, grid);
161 connect(s, s - 1, graph, grid);
162 connect(s, s + grid.width(), graph, grid);
163 connect(s, s - grid.width(), graph, grid);
164 }
165
166 public:
167 template <class G, two_dimensional S, bounding<G, S> B>
168 void connect(G &graph, S const &grid, B bound_policy) const
169 {
170 using directed_category = typename G::directed_category;
171 using vertex_property = typename G::vertex_property;
172 using edge_property = typename G::edge_property;
173
174 int width = grid.width();
175 int height = grid.height();
176 int num_land_vertices = width * height;
177
178 assert(num_land_vertices > 0 and "trying to initialize a graph from an empty grid.");
179
180 for (auto s = 0; s < num_land_vertices; ++s)
181 {
182 int row = s / width;
183 int col = s % width;
184
185 if (row == 0)
186 {
187 if (col == 0)
188 {
189 connect_top_left_corner(s, graph, grid, bound_policy);
190 }
191 else if (col == width - 1)
192 {
193 connect_top_right_corner(s, graph, grid, bound_policy);
194 }
195 else
196 {
197 connect_top_border_no_corners(s, graph, grid, bound_policy);
198 }
199 }
200 else if (row == height - 1)
201 {
202 if (col == 0)
203 {
204 connect_bottom_left_corner(s, graph, grid, bound_policy);
205 }
206 else if (col == width - 1)
207 {
208 connect_bottom_right_corner(s, graph, grid, bound_policy);
209 }
210 else
211 {
212 connect_bottom_border_no_corner(s, graph, grid, bound_policy);
213 }
214 }
215 else if (col == 0)
216 {
217 connect_left_border_no_corner(s, graph, grid, bound_policy);
218 }
219 else if (col == width - 1)
220 {
221 connect_right_border_no_corner(s, graph, grid, bound_policy);
222 }
223 else
224 {
225 connect_interior_vertices(s, graph, grid);
226 }
227 }
228 }
229};
230
232{
233 public:
234 using connectedness = sparse;
235
236 private:
237 template <class G> void connect(auto s, auto t, G &graph, auto const &grid) const
238 {
239 using directed_category = typename G::directed_category;
240 using vertex_property = typename G::vertex_property;
241 using edge_property = typename G::edge_property;
242
243
244 int width = grid.width();
245 int height = grid.height();
246 int num_land_vertices = width * height;
247 assert( s >= 0 );
248 assert( s < num_land_vertices);
249 assert( t >= 0 );
250 assert( t < num_land_vertices);
251
253 if constexpr (std::same_as<directed_category, anisotropy>)
255 }
256
257 void connect_top_left_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
258 {
259 bound_policy(s, graph, grid);
260 connect(s, s + 1, graph, grid);
261 connect(s, s + grid.width(), graph, grid);
262 connect(s, s + grid.width() + 1, graph, grid);
263 }
264
265 void connect_top_right_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
266 {
267 bound_policy(s, graph, grid);
268 connect(s, s - 1, graph, grid);
269 connect(s, s + grid.width(), graph, grid);
270 connect(s, s + grid.width() - 1, graph, grid);
271 }
272
273 void connect_top_border_no_corners(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
274 {
275 bound_policy(s, graph, grid);
276 connect(s, s - 1, graph, grid);
277 connect(s, s + 1, graph, grid);
278 connect(s, s + grid.width(), graph, grid);
279 connect(s, s + grid.width() - 1, graph, grid);
280 connect(s, s + grid.width() + 1, graph, grid);
281 }
282
283 void connect_bottom_left_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
284 {
285 bound_policy(s, graph, grid);
286 connect(s, s + 1, graph, grid);
287 connect(s, s - grid.width(), graph, grid);
288 connect(s, s - grid.width() + 1, graph, grid);
289 }
290
291 void connect_bottom_right_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
292 {
293 bound_policy(s, graph, grid);
294 connect(s, s - 1, graph, grid);
295 connect(s, s - grid.width(), graph, grid);
296 connect(s, s - grid.width() - 1, graph, grid);
297 }
298
299 void connect_bottom_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
300 {
301 bound_policy(s, graph, grid);
302 connect(s, s - 1, graph, grid);
303 connect(s, s + 1, graph, grid);
304 connect(s, s - grid.width(), graph, grid);
305 connect(s, s - grid.width() - 1, graph, grid);
306 connect(s, s - grid.width() + 1, graph, grid);
307 }
308
309 void connect_left_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
310 {
311 bound_policy(s, graph, grid);
312 connect(s, s + 1, graph, grid);
313 connect(s, s - grid.width(), graph, grid);
314 connect(s, s + grid.width(), graph, grid);
315 connect(s, s - grid.width() + 1, graph, grid);
316 connect(s, s + grid.width() + 1, graph, grid);
317 }
318
319 void connect_right_border_no_corner(auto s, auto &graph, auto const &grid, auto const &bound_policy) const
320 {
321 bound_policy(s, graph, grid);
322 connect(s, s - 1, graph, grid);
323 connect(s, s - grid.width(), graph, grid);
324 connect(s, s + grid.width(), graph, grid);
325 connect(s, s - grid.width() - 1, graph, grid);
326 connect(s, s + grid.width() - 1, graph, grid);
327 }
328
329 void connect_interior_vertices(auto s, auto &graph, auto const &grid) const
330 {
331 connect(s, s + 1, graph, grid);
332 connect(s, s - 1, graph, grid);
333 connect(s, s + grid.width(), graph, grid);
334 connect(s, s + grid.width() + 1, graph, grid);
335 connect(s, s + grid.width() - 1, graph, grid);
336 connect(s, s - grid.width(), graph, grid);
337 connect(s, s - grid.width() + 1, graph, grid);
338 connect(s, s - grid.width() - 1, graph, grid);
339 }
340
341 public:
342 template <class G, two_dimensional S, bounding<G, S> B>
343 void connect(G &graph, S const &grid, B bound_policy) const
344 {
345 using directed_category = typename G::directed_category;
346 using vertex_property = typename G::vertex_property;
347 using edge_property = typename G::edge_property;
348
349 int width = grid.width();
350 int height = grid.height();
351 int num_land_vertices = width * height;
352
353 assert(num_land_vertices > 0 and "trying to initialize a graph from an empty grid.");
354
355 for (auto s = 0; s < num_land_vertices; ++s)
356 {
357 int row = s / width;
358 int col = s % width;
359
360 if (row == 0)
361 {
362 if (col == 0)
363 {
364 connect_top_left_corner(s, graph, grid, bound_policy);
365 }
366 else if (col == width - 1)
367 {
368 connect_top_right_corner(s, graph, grid, bound_policy);
369 }
370 else
371 {
372 connect_top_border_no_corners(s, graph, grid, bound_policy);
373 }
374 }
375 else if (row == height - 1)
376 {
377 if (col == 0)
378 {
379 connect_bottom_left_corner(s, graph, grid, bound_policy);
380 }
381 else if (col == width - 1)
382 {
383 connect_bottom_right_corner(s, graph, grid, bound_policy);
384 }
385 else
386 {
387 connect_bottom_border_no_corner(s, graph, grid, bound_policy);
388 }
389 }
390 else if (col == 0)
391 {
392 connect_left_border_no_corner(s, graph, grid, bound_policy);
393 }
394 else if (col == width - 1)
395 {
396 connect_right_border_no_corner(s, graph, grid, bound_policy);
397 }
398 else
399 {
400 connect_interior_vertices(s, graph, grid);
401 }
402 }
403 }
404};
405
406} // namespace quetzal::geography
Definition vicinity.hpp:85
Definition vicinity.hpp:232
Definition graph.hpp:262
Concept to represent the connectedness of a graph.
Definition concepts.hpp:89
Geospatial data formatting and processing.
Definition geography.hpp:17
Definition vicinity.hpp:53
Tag for sparse graph representation.
Definition concepts.hpp:82
Tag for sparse graph representation.
Definition concepts.hpp:75