GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
vector/Vlib/box.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/box.c
3
4 \brief Vector library - bounding box
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 SPDX-FileCopyrightText: 2001-2015 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Radim Blazek
12 */
13
14#include <stdlib.h>
15#include <grass/vector.h>
16#include <grass/glocale.h>
17
18/*!
19 \brief Tests if point is in 3D box
20
21 This function considers 3D point and 3D bounding box.
22
23 \par Example
24
25 \verbatim
26 struct bound_box bbox;
27 bbox.N = 135;
28 bbox.S = 125;
29 bbox.E = 220;
30 bbox.W = 215;
31 bbox.T = 340;
32 bbox.B = 330;
33 Vect_point_in_box(217, 130, 335, &bbox);
34 \endverbatim
35
36 \param x coordinate (W-E direction)
37 \param y coordinate (S-N direction)
38 \param z coordinate (B-T direction)
39 \param Box boundary box
40
41 \returns 1 if point is in box
42 \returns 0 if point is not in box
43 */
44int Vect_point_in_box(double x, double y, double z, const struct bound_box *Box)
45{
46
47 return (x >= Box->W && x <= Box->E && y >= Box->S && y <= Box->N &&
48 z >= Box->B && z <= Box->T);
49}
50
51/*!
52 \brief Tests if point is in 2D box
53
54 Only x and y are tested. Top and bottom of the bounding box are ignored.
55
56 \param x coordinate (W-E direction)
57 \param y coordinate (S-N direction)
58 \param Box boundary box (only W, E, S, N are used)
59
60 \returns 1 if point is in box
61 \returns 0 if point is not in box
62 */
63int Vect_point_in_box_2d(double x, double y, const struct bound_box *Box)
64{
65
66 return (x >= Box->W && x <= Box->E && y >= Box->S && y <= Box->N);
67}
68
69/*!
70 \brief Tests for overlap of two boxes
71
72 \param A boundary box A
73 \param B boundary box B
74
75 \return 1 boxes overlap
76 \return 0 boxes do not overlap
77 */
78int Vect_box_overlap(const struct bound_box *A, const struct bound_box *B)
79{
80
81 if (A->E < B->W || A->W > B->E || A->N < B->S || A->S > B->N ||
82 A->T < B->B || A->B > B->T) {
83 return 0;
84 }
85
86 return 1;
87}
88
89/*!
90 \brief Copy box B to box A
91
92 \param A boundary A
93 \param B boundary B
94
95 \return 1
96 */
97int Vect_box_copy(struct bound_box *A, const struct bound_box *B)
98{
99
100 A->N = B->N;
101 A->S = B->S;
102 A->E = B->E;
103 A->W = B->W;
104 A->T = B->T;
105 A->B = B->B;
106
107 return 1;
108}
109
110/*!
111 \brief Extend box A by box B
112
113 \param A boundary A
114 \param B boundary B
115
116 \return 1
117 */
118int Vect_box_extend(struct bound_box *A, const struct bound_box *B)
119{
120
121 if (B->N > A->N)
122 A->N = B->N;
123 if (B->S < A->S)
124 A->S = B->S;
125 if (B->E > A->E)
126 A->E = B->E;
127 if (B->W < A->W)
128 A->W = B->W;
129 if (B->T > A->T)
130 A->T = B->T;
131 if (B->B < A->B)
132 A->B = B->B;
133
134 return 1;
135}
136
137/*!
138 * \brief Clip coordinates to box, if necessary, lines extending outside of a
139 * box.
140 *
141 * A line represented by the coordinates <em>x, y</em> and <em>c_x, c_y</em> is
142 * clipped to the window defined by <em>s</em> (south), <em>n</em> (north),
143 * <em>w</em> (west), and <em>e</em> (east). Note that the following constraints
144 * must be true: w <e s <n The <em>x</em> and <em>c_x</em> are values to be
145 * compared to <em>w</em> and <em>e.</em> The <em>y</em> and <em>c_y</em> are
146 * values to be compared to <em>s</em> and <em>n.</em> The <em>x</em> and
147 * <em>c_x</em> values returned lie between <em>w</em> and <em>e.</em> The
148 * <em>y</em> and <em>c_y</em> values returned lie between <em>s</em> and
149 * <em>n.</em>
150 *
151 * \param x, y coordinates (w, e)
152 * \param c_x,c_y coordinates (s, n)
153 * \param Box boundary box
154 *
155 * \return 1 if any clipping occurred
156 * \return 0 otherwise
157 */
158int Vect_box_clip(double *x, double *y, double *c_x, double *c_y,
159 const struct bound_box *Box)
160{
161 int mod;
162
163 mod = 0;
164
165 if (*x < Box->W) {
166 if (*c_x != *x)
167 *y = *y + (Box->W - *x) / (*c_x - *x) * (*c_y - *y);
168 *x = Box->W;
169 mod = 1;
170 }
171 if (*x > Box->E) {
172 if (*c_x != *x)
173 *y = *y + (Box->E - *x) / (*c_x - *x) * (*c_y - *y);
174 *x = Box->E;
175 mod = 1;
176 }
177 if (*c_x < Box->W) {
178 if (*c_x != *x)
179 *c_y = *c_y + (Box->W - *c_x) / (*x - *c_x) * (*y - *c_y);
180 *c_x = Box->W;
181 mod = 1;
182 }
183 if (*c_x > Box->E) {
184 if (*c_x != *x)
185 *c_y = *c_y + (Box->E - *c_x) / (*x - *c_x) * (*y - *c_y);
186 *c_x = Box->E;
187 mod = 1;
188 }
189 if (*y < Box->S) {
190 if (*c_y != *y)
191 *x = *x + (Box->S - *y) / (*c_y - *y) * (*c_x - *x);
192 *y = Box->S;
193 mod = 1;
194 }
195 if (*y > Box->N) {
196 if (*c_y != *y)
197 *x = *x + (Box->N - *y) / (*c_y - *y) * (*c_x - *x);
198 *y = Box->N;
199 mod = 1;
200 }
201 if (*c_y < Box->S) {
202 if (*c_y != *y)
203 *c_x = *c_x + (Box->S - *c_y) / (*y - *c_y) * (*x - *c_x);
204 *c_y = Box->S;
205 mod = 1;
206 }
207 if (*c_y > Box->N) {
208 if (*c_y != *y)
209 *c_x = *c_x + (Box->N - *c_y) / (*y - *c_y) * (*x - *c_x);
210 *c_y = Box->N;
211 mod = 1;
212 }
213
214 return (mod);
215}
216
217/*!
218 \brief Get bounding box of given feature
219
220 Vector map must be open at topological level and built with level
221 >= GV_BUILD_BASE.
222
223 \param Map vector map
224 \param line feature id
225 \param[out] Box bounding box
226
227 \return 1 on success
228 \return 0 line is dead
229 \return -1 on error
230 */
231int Vect_get_line_box(struct Map_info *Map, int line, struct bound_box *Box)
232{
233 struct Plus_head *Plus;
234 struct P_line *Line;
235 int type;
236 static struct line_pnts *Points = NULL;
237
238 Plus = (struct Plus_head *)&(Map->plus);
239 if (line < 1 || line > Plus->n_lines) {
240 G_warning(_("Attempt to access feature with invalid id (%d)"), line);
241 return -1;
242 }
243
244 Line = Plus->Line[line];
245 if (Line == NULL) { /* dead */
246 Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = NAN;
247 return 0;
248 }
249
250 type = Line->type;
251
252 /* GV_LINES: retrieve box from spatial index */
253 if (type & GV_LINES) {
254 if (dig_find_line_box(Plus, line, Box) == 0) {
255 G_warning(_("Unable to determine bbox for feature %d"), line);
256 return -1;
257 }
258
259 if (!Vect_is_3d(Map)) {
260 Box->T = PORT_DOUBLE_MAX;
261 Box->B = -PORT_DOUBLE_MAX;
262 }
263
264 return 1;
265 }
266
267 /* all other: read line */
268 if (Points == NULL)
269 Points = Vect_new_line_struct();
270
271 Vect_read_line(Map, Points, NULL, line);
272 dig_line_box(Points, Box);
273
274 if (!Vect_is_3d(Map)) {
275 Box->T = PORT_DOUBLE_MAX;
276 Box->B = -PORT_DOUBLE_MAX;
277 }
278
279 return 1;
280}
281
282/*!
283 \brief Get bounding box of area
284
285 Vector map must be open at topological level and built with level
286 >= GV_BUILD_AREAS.
287
288 \param Map vector map
289 \param area area id
290 \param[out] Box bounding box
291
292 \return 1 on success
293 \return 0 area is dead
294 \return -1 on error
295 */
296int Vect_get_area_box(struct Map_info *Map, int area, struct bound_box *Box)
297{
298 struct Plus_head *Plus;
299 struct P_area *Area;
300
301 Plus = (struct Plus_head *)&(Map->plus);
302 if (area < 1 || area > Plus->n_areas) {
303 G_warning(_("Attempt to access area with invalid id (%d)"), area);
304 return -1;
305 }
306
307 Area = Plus->Area[area];
308
309 if (Area == NULL) { /* dead */
310 Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = NAN;
311 return 0;
312 }
313
314 if (dig_find_area_box(Plus, area, Box) == 0) {
315 G_warning(_("Unable to determine bbox for area %d"), area);
316 return -1;
317 }
318
319 if (!Vect_is_3d(Map)) {
320 Box->T = PORT_DOUBLE_MAX;
321 Box->B = -PORT_DOUBLE_MAX;
322 }
323
324 return 1;
325}
326
327/*!
328 \brief Get bounding box of isle
329
330 Vector map must be open at topological level and built with level
331 >= GV_BUILD_AREAS.
332
333 \param Map vector map
334 \param isle isle id
335 \param[out] Box bounding box
336
337 \return 1 on success
338 \return 0 isle is dead / bounding box not found
339 \return -1 on error
340 */
341int Vect_get_isle_box(struct Map_info *Map, int isle, struct bound_box *Box)
342{
343 struct Plus_head *Plus;
344 struct P_isle *Isle;
345
346 Plus = (struct Plus_head *)&(Map->plus);
347
348 if (isle < 1 || isle > Plus->n_isles) {
349 G_warning(_("Attempt to access area with invalid id (%d)"), isle);
350 return -1;
351 }
352
353 Isle = Plus->Isle[isle];
354
355 if (Isle == NULL) { /* dead */
356 Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = NAN;
357 return 0;
358 }
359
360 if (dig_find_isle_box(Plus, isle, Box) == 0) {
361 G_warning(_("Unable to determine bbox for isle %d"), isle);
362 return -1;
363 }
364
365 if (!Vect_is_3d(Map)) {
366 Box->T = PORT_DOUBLE_MAX;
367 Box->B = -PORT_DOUBLE_MAX;
368 }
369
370 return 1;
371}
372
373/*!
374 \brief Get bounding box of map (all features in the map)
375
376 Requires level 2. On level 1 error code is returned.
377
378 \param Map vector map
379 \param[out] Box bounding box
380
381 \return 1 on success
382 \return 0 on error
383 */
385{
386 const struct Plus_head *Plus;
387
388 if (Vect_level(Map) < 2)
389 return 0;
390
391 Plus = &(Map->plus);
392 Vect_box_copy(Box, &(Plus->box));
393
394 return 1;
395}
396
397/*!
398 \brief Get bounding box of map on level 1 (all features in the map)
399
400 This subroutine determines bounding box by reading all features
401 sequentially.
402
403 \param Map vector map
404 \param[out] Box bounding box
405
406 \return 1 on success
407 \return 0 on error
408 */
410{
411 int type;
412 int first = TRUE;
413
414 struct line_pnts *Points;
415 struct bound_box line_box;
416
417 Points = Vect_new_line_struct();
419 const char *map_name = Vect_get_full_name(Map);
420 G_verbose_message(_("Topology not available for vector map <%s>. "
421 "Registering primitives..."),
422 map_name);
423 G_free((void *)map_name);
424 while (TRUE) {
425 /* register line */
426 type = Vect_read_next_line(Map, Points, NULL);
427
428 if (type == -1) {
429 G_warning(_("Unable to read vector map"));
430 return 0;
431 }
432 else if (type == -2) {
433 break;
434 }
435
436 /* update box */
437 dig_line_box(Points, &line_box);
438 if (first == TRUE) {
440 first = FALSE;
441 }
442 else
444 }
446
447 return 1;
448}
449
450/*!
451 \brief Copy region window to bounding box
452
453 \param Window region structure (raster-based)
454 \param[out] Box boundary box (vector-based)
455
456 \return 1 on success
457 \return 0 on error
458 */
459int Vect_region_box(const struct Cell_head *Window, struct bound_box *Box)
460{
461
462 Box->N = Window->north;
463 Box->S = Window->south;
464 Box->E = Window->east;
465 Box->W = Window->west;
466 Box->T = PORT_DOUBLE_MAX;
467 Box->B = -PORT_DOUBLE_MAX;
468
469 return 1;
470}
#define NULL
Definition ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
void G_warning(const char *,...) __attribute__((format(printf
void void G_verbose_message(const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition line.c:75
int Vect_level(struct Map_info *)
Returns level that Map is opened at.
Definition level.c:27
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
const char * Vect_get_full_name(struct Map_info *)
Get fully qualified name of vector map.
int Vect_rewind(struct Map_info *)
Rewind vector map to cause reads to start at beginning.
int Vect_read_next_line(struct Map_info *, struct line_pnts *, struct line_cats *)
Read next vector feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition line.c:43
int Vect_is_3d(struct Map_info *)
Check if vector map is 3D.
#define GV_LINES
#define PORT_DOUBLE_MAX
Limits for portable types.
Definition dig_defines.h:66
int dig_find_area_box(struct Plus_head *, int, struct bound_box *)
Find bounding box for given area.
Definition spindex.c:916
int dig_find_line_box(struct Plus_head *, int, struct bound_box *)
Find box for line.
Definition spindex.c:800
int dig_find_isle_box(struct Plus_head *, int, struct bound_box *)
Find box for isle.
Definition spindex.c:1012
int dig_line_box(const struct line_pnts *, struct bound_box *)
#define N
#define TRUE
Definition gis.h:75
#define FALSE
Definition gis.h:79
#define _(str)
Definition glocale.h:10
float Box[8][3]
Vertices for box.
Definition gsd_objs.c:1451
#define W
Definition ogsf.h:144
2D/3D raster map header (used also for region)
Definition gis.h:443
Vector map info.
Area (topology) info.
Isle (topology) info.
Vector geometry.
char type
Line type.
Basic topology-related info.
struct P_line ** Line
Array of vector geometries.
struct P_area ** Area
Array of areas.
struct P_isle ** Isle
Array of isles.
Bounding box.
Definition dig_structs.h:62
double W
West.
Definition dig_structs.h:78
double T
Top.
Definition dig_structs.h:82
double S
South.
Definition dig_structs.h:70
double N
North.
Definition dig_structs.h:66
double E
East.
Definition dig_structs.h:74
double B
Bottom.
Definition dig_structs.h:86
Feature geometry info - coordinates.
int Vect_get_map_box(struct Map_info *Map, struct bound_box *Box)
Get bounding box of map (all features in the map)
int Vect_point_in_box_2d(double x, double y, const struct bound_box *Box)
Tests if point is in 2D box.
int Vect_region_box(const struct Cell_head *Window, struct bound_box *Box)
Copy region window to bounding box.
int Vect_box_extend(struct bound_box *A, const struct bound_box *B)
Extend box A by box B.
int Vect_get_line_box(struct Map_info *Map, int line, struct bound_box *Box)
Get bounding box of given feature.
int Vect_box_overlap(const struct bound_box *A, const struct bound_box *B)
Tests for overlap of two boxes.
int Vect_box_clip(double *x, double *y, double *c_x, double *c_y, const struct bound_box *Box)
Clip coordinates to box, if necessary, lines extending outside of a box.
int Vect_point_in_box(double x, double y, double z, const struct bound_box *Box)
Tests if point is in 3D box.
int Vect_get_area_box(struct Map_info *Map, int area, struct bound_box *Box)
Get bounding box of area.
int Vect_get_map_box1(struct Map_info *Map, struct bound_box *Box)
Get bounding box of map on level 1 (all features in the map)
int Vect_box_copy(struct bound_box *A, const struct bound_box *B)
Copy box B to box A.
int Vect_get_isle_box(struct Map_info *Map, int isle, struct bound_box *Box)
Get bounding box of isle.
#define x