1
2 /****************************************************************************
3 *
4 * MODULE: v.patch
5 * AUTHOR(S): Dave Gerdes, U.S.Army Construction Engineering Research Laboratory
6 * (original contributor)
7 * Radim Blazek <radim.blazek gmail.com> (update to GRASS 6)
8 * Glynn Clements <glynn gclements.plus.com>, Markus Neteler <neteler itc.it>,
9 * Martin Landa <landa.martin gmail.com> (bbox)
10 * PURPOSE:
11 * COPYRIGHT: (C) 2002-2006 by the GRASS Development Team
12 *
13 * This program is free software under the GNU General Public
14 * License (>=v2). Read the file COPYING that comes with GRASS
15 * for details.
16 *
17 *****************************************************************************/
18 /*
19 ** v.patch input=file1,file2,.... output=composite
20 **
21 ** patch 2 or more vector maps together creating composite
22 **
23 **
24 ** no checking is done for overlapping lines.
25 ** header information will have to be editted afterwards.
26 */
27
28 /*
29 ** Written by Dave Gerdes 8/1988, US Army Construction Engineering Research Lab
30 ** Upgrade to 5.7 Radim Blazek
31 */
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <math.h>
36 #include <grass/gis.h>
37 #include <grass/vector.h>
38 #include <grass/dbmi.h>
39 #include <grass/glocale.h>
40
41 int patch(struct Map_info *, struct Map_info *, int, int *,
42 struct Map_info *);
43 int copy_records(dbDriver * driver_in, dbString * table_name_in,
44 dbDriver * driver_out, dbString * table_name_out,
45 char *, int, int);
46 int max_cat(struct Map_info *Map, int layer);
47
main(int argc,char * argv[])48 int main(int argc, char *argv[])
49 {
50 int i, ret;
51 char *in_name, *out_name, *bbox_name;
52 struct GModule *module;
53 struct Option *old, *new, *bbox;
54 struct Flag *append, *table_flag, *no_topo;
55 struct Flag *no_input_topo_flag, *force_z_flag;
56 struct Map_info InMap, OutMap, BBoxMap;
57 int n_files;
58 int do_table;
59 struct field_info *fi_in, *fi_out;
60 dbString sql, table_name_in, table_name_out;
61 dbDriver *driver_in, *driver_out;
62 dbTable *table_in, *table_out;
63 char *key = NULL;
64 int keycol = -1;
65 int maxcat = 0;
66 int out_is_3d = WITHOUT_Z;
67 char colnames[4096];
68 double snap = -1;
69
70 G_gisinit(argv[0]);
71
72 module = G_define_module();
73 G_add_keyword(_("vector"));
74 G_add_keyword(_("geometry"));
75 G_add_keyword(_("level1"));
76
77 module->description = _("Creates a new vector map "
78 "by combining other vector maps.");
79
80 old = G_define_standard_option(G_OPT_V_INPUTS);
81
82 new = G_define_standard_option(G_OPT_V_OUTPUT);
83
84 bbox = G_define_standard_option(G_OPT_V_OUTPUT);
85 bbox->required = NO;
86 bbox->key = "bbox";
87 bbox->description =
88 _("Name for output vector map where bounding boxes of input vector maps are written to");
89
90 no_input_topo_flag = G_define_flag();
91 no_input_topo_flag->key = 'n';
92 no_input_topo_flag->label = _("Do not expect input with topology");
93 no_input_topo_flag->description =
94 _("Applicable when input is points without topology");
95
96 force_z_flag = G_define_flag();
97 force_z_flag->key = 'z';
98 force_z_flag->label = _("Expect z coordinate even when not using topology");
99 force_z_flag->description =
100 _("Applicable when input is points with z coordinate but without topology");
101
102 table_flag = G_define_flag();
103 table_flag->key = 'e';
104 table_flag->label = _("Copy also attribute table");
105 table_flag->description =
106 _("Only the table of layer 1 is currently supported");
107
108 append = G_define_flag();
109 append->key = 'a';
110 append->description = _("Append files to existing file "
111 "(overwriting existing files must be activated)");
112
113 no_topo = G_define_standard_flag(G_FLG_V_TOPO);
114
115 if (G_parser(argc, argv))
116 exit(EXIT_FAILURE);
117
118 out_name = new->answer;
119 bbox_name = bbox->answer;
120 do_table = table_flag->answer;
121
122 db_init_string(&table_name_in);
123 db_init_string(&table_name_out);
124 db_init_string(&sql);
125
126 i = 0;
127 while (old->answers[i]) {
128 in_name = old->answers[i++];
129 Vect_check_input_output_name(in_name, new->answer, G_FATAL_EXIT);
130
131 Vect_set_open_level(no_input_topo_flag->answer ? 1 : 2);
132 if (Vect_open_old_head(&InMap, in_name, "") < 0)
133 G_fatal_error(_("Unable to open vector map <%s>"), in_name);
134
135 if (out_is_3d != WITH_Z && Vect_is_3d(&InMap))
136 out_is_3d = WITH_Z;
137
138 Vect_close(&InMap);
139 }
140 if (force_z_flag->answer)
141 out_is_3d = WITH_Z;
142
143 table_out = NULL;
144 fi_in = NULL;
145 fi_out = NULL;
146 *colnames = '\0';
147 /* Check input table structures */
148 if (do_table) {
149 if (append->answer) {
150 Vect_set_open_level(1);
151 if (Vect_open_old_head(&OutMap, out_name, G_mapset()) < 0)
152 G_fatal_error(_("Unable to open vector map <%s>"), out_name);
153
154 fi_out = Vect_get_field(&OutMap, 1);
155 if (fi_out) {
156 key = G_store(fi_out->key);
157 driver_out =
158 db_start_driver_open_database(fi_out->driver,
159 fi_out->database);
160 if (!driver_out) {
161 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
162 fi_out->database, fi_out->driver);
163 }
164 db_set_error_handler_driver(driver_out);
165
166 db_set_string(&table_name_out, fi_out->table);
167 if (db_describe_table(driver_out, &table_name_out, &table_out)
168 != DB_OK) {
169 G_fatal_error(_("Unable to describe table <%s>"),
170 fi_out->table);
171 }
172 db_close_database_shutdown_driver(driver_out);
173 }
174 Vect_close(&OutMap);
175 }
176
177 i = 0;
178 while (old->answers[i]) {
179 in_name = old->answers[i];
180 Vect_set_open_level(1);
181 if (Vect_open_old_head(&InMap, in_name, "") < 0)
182 G_fatal_error(_("Unable to open vector map <%s>"), in_name);
183
184 fi_in = Vect_get_field(&InMap, 1);
185 table_in = NULL;
186 if (fi_in) {
187 dbTable **table;
188
189 driver_in =
190 db_start_driver_open_database(fi_in->driver,
191 fi_in->database);
192 if (!driver_in) {
193 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
194 fi_in->database, fi_in->driver);
195 }
196 db_set_error_handler_driver(driver_in);
197
198 if (!append->answer && i == 0) {
199 table = &table_out;
200 key = G_store(fi_in->key);
201 }
202 else {
203 table = &table_in;
204 }
205
206 db_set_string(&table_name_in, fi_in->table);
207 if (db_describe_table(driver_in, &table_name_in, table)
208 != DB_OK) {
209 G_fatal_error(_("Unable to describe table <%s>"),
210 fi_in->table);
211 }
212 db_close_database_shutdown_driver(driver_in);
213 }
214 else {
215 G_fatal_error(_("Missing attribute table for vector map <%s>"), in_name);
216 }
217
218 /* Get the output table structure */
219 if (i == 0 ) {
220 int ncols, col;
221
222 ncols = db_get_table_number_of_columns(table_out);
223
224 for (col = 0; col < ncols; col++) {
225 dbColumn *column_out;
226
227 column_out = db_get_table_column(table_out, col);
228 if (col == 0)
229 strcpy(colnames, db_get_column_name(column_out));
230 else {
231 char tmpbuf[4096];
232
233 sprintf(tmpbuf, ",%s", db_get_column_name(column_out));
234 strcat(colnames, tmpbuf);
235 }
236 }
237 }
238
239 /* Check the table structure */
240 if (i > 0 || append->answer) {
241 int ncols, col;
242
243 if (!table_in ||
244 (table_out && !table_in) || (!table_out && table_in)) {
245 G_fatal_error(_("Missing table"));
246 }
247
248 if (G_strcasecmp(fi_in->key, key) != 0) {
249 G_fatal_error(_("Key columns differ"));
250 }
251
252 ncols = db_get_table_number_of_columns(table_out);
253
254 if (ncols != db_get_table_number_of_columns(table_in)) {
255 G_fatal_error(_("Number of columns differ"));
256 }
257
258 for (col = 0; col < ncols; col++) {
259 int col2, colmatch;
260 dbColumn *column_out, *column_in;
261 int ctype_in, ctype_out;
262
263 column_out = db_get_table_column(table_out, col);
264 col2 = 0;
265 colmatch = -1;
266 column_in = NULL;
267 /* find column with same name */
268 while (colmatch < 0 && col2 < ncols) {
269 column_in = db_get_table_column(table_in, col2);
270
271 if (G_strcasecmp(db_get_column_name(column_in),
272 db_get_column_name(column_out)) == 0) {
273 colmatch = col2;
274 }
275 col2++;
276 }
277 if (colmatch < 0) {
278 G_fatal_error(_("No column <%s> in input map <%s>"),
279 db_get_column_name(column_out),
280 in_name);
281 }
282
283 ctype_in =
284 db_sqltype_to_Ctype(db_get_column_sqltype(column_in));
285 ctype_out =
286 db_sqltype_to_Ctype(db_get_column_sqltype
287 (column_out));
288 if (ctype_in != ctype_out) {
289 G_fatal_error(_("Column types differ"));
290 }
291 if (ctype_in == DB_C_TYPE_STRING &&
292 db_get_column_length(column_in) !=
293 db_get_column_length(column_out)) {
294 G_fatal_error(_("Length of string columns differ"));
295 }
296 if (G_strcasecmp(key,
297 db_get_column_name(column_out)) == 0) {
298 keycol = col;
299 }
300 }
301 }
302
303 Vect_close(&InMap);
304 i++;
305 }
306
307 if (keycol == -1) {
308 G_fatal_error(_("Key column not found"));
309 }
310 }
311
312 if (append->answer) {
313 if (no_topo->answer)
314 Vect_set_open_level(1);
315
316 if (Vect_open_update(&OutMap, out_name, G_mapset()) < 0)
317 G_fatal_error(_("Unable to open vector map <%s>"), out_name);
318
319 if (out_is_3d == WITH_Z && !Vect_is_3d(&OutMap)) {
320 G_warning(_("The output map is not 3D"));
321 }
322 maxcat = max_cat(&OutMap, 1);
323 }
324 else {
325 if (Vect_open_new(&OutMap, out_name, out_is_3d) < 0)
326 G_fatal_error(_("Unable to create vector map <%s>"), out_name);
327 }
328
329 if (bbox_name) {
330 if (Vect_open_new(&BBoxMap, bbox_name, out_is_3d) < 0) /* TODO 3D */
331 G_fatal_error(_("Unable to create vector map <%s>"), bbox_name);
332 Vect_hist_command(&BBoxMap);
333 }
334
335 Vect_hist_command(&OutMap);
336
337 driver_out = NULL;
338 if (do_table) {
339 if (append->answer) {
340 fi_out = Vect_get_field(&OutMap, 1);
341 }
342 else {
343 fi_out = Vect_default_field_info(&OutMap, 1, NULL, GV_1TABLE);
344 fi_out->key = key;
345 }
346 if (fi_out) {
347 driver_out =
348 db_start_driver_open_database(fi_out->driver,
349 Vect_subst_var(fi_out->database,
350 &OutMap));
351 if (!driver_out) {
352 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
353 fi_out->database, fi_out->driver);
354 }
355 db_set_error_handler_driver(driver_out);
356
357 db_begin_transaction(driver_out);
358 }
359
360 db_set_string(&table_name_out, fi_out->table);
361 db_set_table_name(table_out, fi_out->table);
362
363 if (!append->answer) {
364 if (db_create_table(driver_out, table_out) != DB_OK) {
365 G_fatal_error(_("Unable to create table <%s>"),
366 fi_out->table);
367 }
368
369 /* do not allow duplicate keys */
370 if (db_create_index2(driver_out, fi_out->table, fi_out->key) != DB_OK)
371 G_warning(_("Unable to create index"));
372
373 if (db_grant_on_table
374 (driver_out, fi_out->table, DB_PRIV_SELECT,
375 DB_GROUP | DB_PUBLIC) != DB_OK)
376 G_fatal_error(_("Unable to grant privileges on table <%s>"),
377 fi_out->table);
378
379 Vect_map_add_dblink(&OutMap, 1, NULL, fi_out->table,
380 fi_in->key, fi_out->database, fi_out->driver);
381
382 /* avoid Vect_subst_var() below */
383 fi_out = Vect_get_field(&OutMap, 1);
384 }
385 }
386
387 i = 0;
388 while (old->answers[i]) {
389 int add_cat;
390
391 in_name = old->answers[i++];
392 G_important_message(_("Patching vector map <%s>..."), in_name);
393 if (bbox_name)
394 Vect_set_open_level(2); /* needed for Vect_map_box() */
395 else
396 Vect_set_open_level(1);
397 if (Vect_open_old(&InMap, in_name, "") < 0)
398 G_fatal_error(_("Unable to open vector map <%s>"), in_name);
399
400 /*first time around, copy first in head to out head */
401 if (i == 1)
402 Vect_copy_head_data(&InMap, &OutMap);
403
404 if (do_table) {
405 add_cat = maxcat + 1;
406 }
407 else {
408 add_cat = 0;
409 }
410 G_debug(2, "maxcat = %d add_cat = %d", maxcat, add_cat);
411
412 ret =
413 patch(&InMap, &OutMap, add_cat, &maxcat,
414 bbox_name ? &BBoxMap : NULL);
415 if (ret < 0)
416 G_warning(_("Error reading vector map <%s> - "
417 "some data may not be correct"), in_name);
418
419 if (do_table) {
420 fi_in = Vect_get_field(&InMap, 1);
421 if (fi_in) {
422
423 /* SQLite does not like to have the same database opened twice */
424 if (strcmp(fi_in->driver, fi_out->driver) == 0
425 && strcmp(fi_in->database, fi_out->database) == 0) {
426 G_debug(3, "Use the same driver");
427 driver_in = driver_out;
428 }
429 else {
430 driver_in =
431 db_start_driver_open_database(fi_in->driver,
432 fi_in->database);
433 if (!driver_in) {
434 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
435 fi_in->database, fi_in->driver);
436 }
437 db_set_error_handler_driver(driver_in);
438 }
439
440 db_set_string(&table_name_in, fi_in->table);
441 copy_records(driver_in, &table_name_in,
442 driver_out, &table_name_out,
443 colnames, keycol, add_cat);
444
445 if (driver_in != driver_out)
446 db_close_database_shutdown_driver(driver_in);
447 }
448 }
449
450 Vect_close(&InMap);
451 }
452 n_files = i;
453
454 if (driver_out) {
455 db_commit_transaction(driver_out);
456 db_close_database_shutdown_driver(driver_out);
457 }
458
459 Vect_set_map_name(&OutMap, "Output from v.patch");
460 Vect_set_person(&OutMap, G_whoami());
461
462 if (!no_topo->answer) {
463 Vect_build_partial(&OutMap, GV_BUILD_BASE);
464
465 if (Vect_get_num_primitives(&OutMap, GV_BOUNDARY) > 0) {
466 int nmodif;
467 struct bound_box box;
468 double xmax, ymax, min_snap, max_snap;
469 int exp;
470 char *separator = "-----------------------------------------------------";
471
472 Vect_get_map_box(&OutMap, &box);
473
474 if (abs(box.E) > abs(box.W))
475 xmax = abs(box.E);
476 else
477 xmax = abs(box.W);
478 if (abs(box.N) > abs(box.S))
479 ymax = abs(box.N);
480 else
481 ymax = abs(box.S);
482
483 if (xmax < ymax)
484 xmax = ymax;
485
486 /* double precision ULP */
487 min_snap = frexp(xmax, &exp);
488 exp -= 52;
489 min_snap = ldexp(min_snap, exp);
490 /* human readable */
491 min_snap = log10(min_snap);
492 if (min_snap < 0)
493 min_snap = (int)min_snap;
494 else
495 min_snap = (int)min_snap + 1;
496
497 /* single precision ULP */
498 max_snap = frexp(xmax, &exp);
499 exp -= 23;
500 max_snap = ldexp(max_snap, exp);
501 /* human readable */
502 max_snap = log10(max_snap);
503 if (max_snap < 0)
504 max_snap = (int)max_snap;
505 else
506 max_snap = (int)max_snap + 1;
507
508 snap = (min_snap + max_snap) / 2 - 1.5;
509 snap = pow(10, snap);
510
511 if (snap >= 0) {
512 G_message("%s", separator);
513 G_message(_("Snapping boundaries (threshold = %.3e)..."), snap);
514 Vect_snap_lines(&OutMap, GV_BOUNDARY, snap, NULL);
515 }
516
517 G_message("%s", separator);
518 G_message(_("Breaking polygons..."));
519 Vect_break_polygons(&OutMap, GV_BOUNDARY, NULL);
520
521 G_message("%s", separator);
522 G_message(_("Removing duplicates..."));
523 Vect_remove_duplicates(&OutMap, GV_BOUNDARY, NULL);
524
525 /* in non-pathological cases, the bulk of the cleaning is now done */
526
527 /* Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections
528 * are created. We must call Vect_break_lines(), Vect_remove_duplicates()
529 * and Vect_clean_small_angles_at_nodes() until no more small angles are found */
530 do {
531 G_message("%s", separator);
532 G_message(_("Breaking boundaries..."));
533 Vect_break_lines(&OutMap, GV_BOUNDARY, NULL);
534
535 G_message("%s", separator);
536 G_message(_("Removing duplicates..."));
537 Vect_remove_duplicates(&OutMap, GV_BOUNDARY, NULL);
538
539 G_message("%s", separator);
540 G_message(_("Cleaning boundaries at nodes..."));
541 nmodif =
542 Vect_clean_small_angles_at_nodes(&OutMap, GV_BOUNDARY, NULL);
543 } while (nmodif > 0);
544
545 /* merge boundaries */
546 G_message("%s", separator);
547 G_message(_("Merging boundaries..."));
548 Vect_merge_lines(&OutMap, GV_BOUNDARY, NULL, NULL);
549
550 G_message("%s", separator);
551 G_message(_("Removing dangles..."));
552 Vect_remove_dangles(&OutMap, GV_BOUNDARY, -1.0, NULL);
553
554 G_message("%s", separator);
555 Vect_build_partial(&OutMap, GV_BUILD_ALL);
556
557 G_message(_("Removing bridges..."));
558 Vect_remove_bridges(&OutMap, NULL, &nmodif, NULL);
559
560 /* Boundaries are hopefully clean, build areas */
561 G_message("%s", separator);
562 }
563
564 Vect_build_partial(&OutMap, GV_BUILD_NONE);
565 Vect_build(&OutMap);
566 }
567 Vect_close(&OutMap);
568
569 if (bbox_name) {
570 Vect_set_map_name(&BBoxMap, "Output from v.patch (bounding boxes)");
571 Vect_set_person(&BBoxMap, G_whoami());
572 G_important_message(" ");
573 G_important_message(_("Building topology for vector map <%s>..."),
574 bbox_name);
575 Vect_build(&BBoxMap);
576 Vect_close(&BBoxMap);
577 }
578
579 G_message(_("Intersections at borders will have to be snapped"));
580 G_message(_("Lines common between files will have to be edited"));
581 G_message(_("The header information also may have to be edited"));
582
583 G_done_msg(_("%d vector maps patched"), n_files);
584
585 exit(EXIT_SUCCESS);
586 }
587
588
copy_records(dbDriver * driver_in,dbString * table_name_in,dbDriver * driver_out,dbString * table_name_out,char * colnames,int keycol,int add_cat)589 int copy_records(dbDriver * driver_in, dbString * table_name_in,
590 dbDriver * driver_out, dbString * table_name_out,
591 char *colnames, int keycol, int add_cat)
592 {
593 int ncols, col;
594 dbCursor cursor;
595 dbString value_str, sql;
596 dbTable *table_in;
597 char tmpbuf[4096];
598
599 db_init_string(&value_str);
600 db_init_string(&sql);
601
602 if (colnames && *colnames)
603 sprintf(tmpbuf, "select %s from ", colnames);
604 else
605 sprintf(tmpbuf, "select * from ");
606 db_set_string(&sql, tmpbuf);
607 db_append_string(&sql, db_get_string(table_name_in));
608
609 if (db_open_select_cursor(driver_in, &sql, &cursor, DB_SEQUENTIAL) !=
610 DB_OK) {
611 G_warning(_("Cannot open select cursor: '%s'"), db_get_string(&sql));
612 return 0;
613 }
614 table_in = db_get_cursor_table(&cursor);
615 ncols = db_get_table_number_of_columns(table_in);
616
617 while (1) {
618 int more;
619 char buf[DB_SQL_MAX];
620
621 if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
622 db_close_cursor(&cursor);
623 G_fatal_error(_("Cannot fetch row"));
624 }
625 if (!more)
626 break;
627
628 sprintf(buf, "insert into %s values ( ",
629 db_get_string(table_name_out));
630 db_set_string(&sql, buf);
631
632 for (col = 0; col < ncols; col++) {
633 int ctype, sqltype;
634 dbColumn *column;
635 dbValue *value;
636
637 column = db_get_table_column(table_in, col);
638
639 sqltype = db_get_column_sqltype(column);
640 ctype = db_sqltype_to_Ctype(sqltype);
641 value = db_get_column_value(column);
642
643 if (col > 0)
644 db_append_string(&sql, ", ");
645
646 if (col == keycol) {
647 db_set_value_int(value, db_get_value_int(value) + add_cat);
648 }
649 db_convert_value_to_string(value, sqltype, &value_str);
650
651 switch (ctype) {
652 case DB_C_TYPE_STRING:
653 case DB_C_TYPE_DATETIME:
654 if (db_test_value_isnull(value)) {
655 db_append_string(&sql, "null");
656 }
657 else {
658 db_double_quote_string(&value_str);
659 sprintf(buf, "'%s'", db_get_string(&value_str));
660 db_append_string(&sql, buf);
661 }
662 break;
663 case DB_C_TYPE_INT:
664 case DB_C_TYPE_DOUBLE:
665 if (db_test_value_isnull(value)) {
666 db_append_string(&sql, "null");
667 }
668 else {
669 db_append_string(&sql, db_get_string(&value_str));
670 }
671 break;
672 default:
673 G_fatal_error(_("Unknown column type"));
674 }
675 }
676 db_append_string(&sql, ")");
677
678 G_debug(2, "SQL: %s", db_get_string(&sql));
679
680 if (db_execute_immediate(driver_out, &sql) != DB_OK) {
681 G_fatal_error(_("Cannot insert new record: '%s'"),
682 db_get_string(&sql));
683 }
684 }
685
686 db_close_cursor(&cursor);
687
688 return 1;
689 }
690
patch(struct Map_info * InMap,struct Map_info * OutMap,int add_cat,int * max_cat,struct Map_info * BBoxMap)691 int patch(struct Map_info *InMap, struct Map_info *OutMap, int add_cat,
692 int *max_cat, struct Map_info *BBoxMap)
693 {
694 int type;
695 struct line_pnts *Points;
696 struct line_cats *Cats;
697
698 *max_cat = add_cat;
699
700 Points = Vect_new_line_struct();
701 Cats = Vect_new_cats_struct();
702
703 /* TODO:
704 OutMap->head.orig_scale = GREATER (OutMap->head.orig_scale, InMap->head.orig_scale);
705 OutMap->head.digit_thresh = 0;
706 OutMap->head.map_thresh = GREATER (OutMap->head.map_thresh, InMap->head.map_thresh);
707 */
708
709 while ((type = Vect_read_next_line(InMap, Points, Cats)) > 0) {
710 int i;
711
712 for (i = 0; i < Cats->n_cats; i++) {
713 if (Cats->field[i] == 1) {
714 Cats->cat[i] += add_cat;
715 if (Cats->cat[i] > *max_cat)
716 *max_cat = Cats->cat[i];
717 }
718 }
719
720 Vect_write_line(OutMap, type, Points, Cats);
721 }
722
723 if (BBoxMap) { /* inspired by v.in.region */
724 struct bound_box box;
725 double diff_long, mid_long;
726 static int cat;
727
728 Vect_get_map_box(InMap, &box);
729
730 diff_long = box.E - box.W;
731 mid_long = (box.W + box.E) / 2;
732
733 /* rectangle */
734 Vect_reset_cats(Cats);
735
736 /* write each line, useful for snapping */
737 Vect_reset_line(Points);
738 Vect_append_point(Points, box.W, box.S, 0.0);
739 if (Vect_get_proj(BBoxMap) == PROJECTION_LL && diff_long >= 179) {
740 Vect_append_point(Points, mid_long, box.S, 0.0);
741 }
742 Vect_append_point(Points, box.E, box.S, 0.0);
743 Vect_write_line(BBoxMap, GV_BOUNDARY, Points, Cats);
744
745 Vect_reset_line(Points);
746 Vect_append_point(Points, box.E, box.S, 0.0);
747 Vect_append_point(Points, box.E, box.N, 0.0);
748 Vect_write_line(BBoxMap, GV_BOUNDARY, Points, Cats);
749
750 Vect_reset_line(Points);
751 Vect_append_point(Points, box.E, box.N, 0.0);
752 if (Vect_get_proj(BBoxMap) == PROJECTION_LL && diff_long >= 179) {
753 Vect_append_point(Points, mid_long, box.N, 0.0);
754 }
755 Vect_append_point(Points, box.W, box.N, 0.0);
756 Vect_write_line(BBoxMap, GV_BOUNDARY, Points, Cats);
757
758 Vect_reset_line(Points);
759 Vect_append_point(Points, box.W, box.N, 0.0);
760 Vect_append_point(Points, box.W, box.S, 0.0);
761 Vect_write_line(BBoxMap, GV_BOUNDARY, Points, Cats);
762
763 /* centroid */
764 Vect_reset_line(Points);
765 Vect_cat_set(Cats, 1, ++cat); /* first layer */
766 Vect_append_point(Points, (box.W + box.E) / 2, (box.S + box.N) / 2,
767 0.0);
768
769 Vect_write_line(BBoxMap, GV_CENTROID, Points, Cats);
770 }
771
772 Vect_destroy_line_struct(Points);
773 Vect_destroy_cats_struct(Cats);
774
775 if (type != -2)
776 return -1;
777
778 return 0;
779 }
780
max_cat(struct Map_info * Map,int layer)781 int max_cat(struct Map_info *Map, int layer)
782 {
783 struct line_cats *Cats;
784 int max = 0;
785
786 Cats = Vect_new_cats_struct();
787
788 while (Vect_read_next_line(Map, NULL, Cats) > 0) {
789 int i;
790
791 for (i = 0; i < Cats->n_cats; i++) {
792 if (Cats->field[i] == layer && Cats->cat[i] > max) {
793 max = Cats->cat[i];
794 }
795 }
796 }
797 return max;
798 }
799