~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to vector/v.select/main.c

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/****************************************************************************
3
3
 *
4
 
 * MODULE:       v.select - select features from one map by features in another map.
 
4
 * MODULE:       v.select
5
5
 * AUTHOR(S):    Radim Blazek <radim.blazek gmail.com> (original contributor)
6
 
 *               Glynn Clements <glynn gclements.plus.com>, Markus Neteler <neteler itc.it>
 
6
 *               Glynn Clements <glynn gclements.plus.com>
 
7
 *               Markus Neteler <neteler itc.it>
7
8
 *               Martin Landa <landa.martin gmail.com> (GEOS support)
8
 
 * PURPOSE:      
9
 
 * COPYRIGHT:    (C) 2003-2010 by the GRASS Development Team
 
9
 * PURPOSE:      Select features from one map by features in another map.
 
10
 * COPYRIGHT:    (C) 2003-2014 by the GRASS Development Team
10
11
 *
11
 
 *               This program is free software under the GNU General Public
12
 
 *               License (>=v2). Read the file COPYING that comes with GRASS
13
 
 *               for details.
 
12
 *               This program is free software under the GNU General
 
13
 *               Public License (>=v2). Read the file COPYING that
 
14
 *               comes with GRASS for details.
14
15
 *
15
16
 *****************************************************************************/
16
17
 
17
18
#include <stdlib.h>
18
19
#include <string.h>
19
20
#include <stdio.h>
20
 
#include <grass/config.h>
 
21
 
21
22
#include <grass/gis.h>
22
 
#include <grass/dbmi.h>
23
 
#include <grass/Vect.h>
 
23
#include <grass/vector.h>
24
24
#include <grass/glocale.h>
25
25
 
26
26
#include "proto.h"
27
27
 
28
28
int main(int argc, char *argv[])
29
29
{
30
 
    int i, iopt;
 
30
    int iopt;
31
31
    int operator;
32
 
    int aline, nalines, nskipped;
33
 
    int ltype, itype[2], ifield[2];
34
 
    int **cats, *ncats, nfields, *fields;
35
 
    char *mapset[2], *pre[2];
 
32
    int nskipped[2], native;
 
33
    int itype[2], ifield[2];
 
34
 
 
35
    int *ALines; /* List of lines: 0 do not output, 1 - write to output */
 
36
    int **cats, *ncats, *fields, nfields;
 
37
    
36
38
    struct GModule *module;
37
39
    struct GParm parm;
38
40
    struct GFlag flag;
39
41
    struct Map_info In[2], Out;
40
 
    struct field_info *IFi, *OFi;
41
 
    struct line_pnts *APoints, *BPoints;
42
 
    struct line_cats *ACats, *BCats;
43
 
    int *ALines;                /* List of lines: 0 do not output, 1 - write to output */
44
 
    struct ilist *List, *TmpList, *BoundList;
 
42
    struct field_info *IFi;
45
43
 
46
44
    G_gisinit(argv[0]);
47
45
 
48
 
    pre[0] = "a";
49
 
    pre[1] = "b";
50
 
 
51
46
    module = G_define_module();
52
 
    module->keywords = _("vector, spatial query");
 
47
    G_add_keyword(_("vector"));
 
48
    G_add_keyword(_("geometry"));
 
49
    G_add_keyword(_("spatial query"));
53
50
    module->description =
54
51
        _("Selects features from vector map (A) by features from other vector map (B).");
55
52
 
84
81
    else if (parm.operator->answer[0] == 'r')
85
82
        operator = OP_RELATE;
86
83
    else
87
 
        G_fatal_error(_("Unknown operator"));
 
84
        G_fatal_error(_("Unknown operator '%s'"), parm.operator->answer);
88
85
    
 
86
#ifdef HAVE_GEOS
89
87
    if (operator == OP_RELATE && !parm.relate->answer) {
90
88
        G_fatal_error(_("Required parameter <%s> not set"),
91
89
                      parm.relate->key);
92
90
    }
93
 
    
 
91
#else
 
92
    if (operator != OP_OVERLAP) {
 
93
        G_warning(_("Operator can only be 'overlap'"));
 
94
        operator = OP_OVERLAP;
 
95
    }
 
96
#endif    
94
97
    for (iopt = 0; iopt < 2; iopt++) {
95
98
        itype[iopt] = Vect_option_to_types(parm.type[iopt]);
96
 
        ifield[iopt] = atoi(parm.field[iopt]->answer);
97
99
 
98
100
        Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer,
99
 
                                     GV_FATAL_EXIT);
 
101
                                     G_FATAL_EXIT);
100
102
 
101
 
        if ((mapset[iopt] =
102
 
             G_find_vector2(parm.input[iopt]->answer, NULL)) == NULL) {
103
 
            G_fatal_error(_("Vector map <%s> not found"),
104
 
                          parm.input[iopt]->answer);
105
 
        }
106
 
        
107
103
        Vect_set_open_level(2);
108
 
        Vect_open_old(&(In[iopt]), parm.input[iopt]->answer, mapset[iopt]);
 
104
 
 
105
        if (Vect_open_old2(&(In[iopt]), parm.input[iopt]->answer, "",
 
106
                                parm.field[iopt]->answer) < 0)
 
107
            G_fatal_error(_("Unable to open vector map <%s>"),
 
108
                            parm.input[iopt]->answer);
 
109
 
 
110
        ifield[iopt] = Vect_get_field_number(&(In[iopt]), parm.field[iopt]->answer);
109
111
    }
110
 
    
 
112
 
 
113
    /* Alloc space for input lines array */
 
114
    ALines = (int *)G_calloc(Vect_get_num_lines(&(In[0])) + 1, sizeof(int));
 
115
 
111
116
    /* Read field info */
112
117
    IFi = Vect_get_field(&(In[0]), ifield[0]);
113
118
 
114
 
    APoints = Vect_new_line_struct();
115
 
    BPoints = Vect_new_line_struct();
116
 
    ACats = Vect_new_cats_struct();
117
 
    BCats = Vect_new_cats_struct();
118
 
    List = Vect_new_list();
119
 
    TmpList = Vect_new_list();
120
 
    BoundList = Vect_new_list();
121
 
 
122
119
    /* Open output */
123
 
    Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0])));
 
120
    if (Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0]))) < 0)
 
121
        G_fatal_error(_("Unable to create vector map <%s>"),
 
122
                        parm.output->answer);
 
123
 
124
124
    Vect_set_map_name(&Out, _("Output from v.select"));
125
125
    Vect_set_person(&Out, G_whoami());
126
126
    Vect_copy_head_data(&(In[0]), &Out);
127
127
    Vect_hist_copy(&(In[0]), &Out);
128
128
    Vect_hist_command(&Out);
129
 
 
130
 
    nskipped = 0;
131
 
    nalines = Vect_get_num_lines(&(In[0]));
132
 
 
 
129
    
 
130
    /* Select features */
133
131
#ifdef HAVE_GEOS
134
 
    initGEOS(G_message, G_fatal_error);
135
 
    GEOSGeometry *AGeom = NULL;
 
132
    select_lines(&(In[0]), itype[0], ifield[0],
 
133
                 &(In[1]), itype[1], ifield[1],
 
134
                 flag.cat->answer ? 1 : 0, operator,
 
135
                 parm.relate->answer,
 
136
                 ALines, nskipped);
136
137
#else
137
 
    void *AGeom = NULL;
138
 
#endif
139
 
 
140
 
    /* Alloc space for input lines array */
141
 
    ALines = (int *)G_calloc(nalines + 1, sizeof(int));
142
 
 
143
 
    G_message(_("Building spatial index..."));
144
 
    Vect_build_spatial_index(&In[0]);
145
 
    Vect_build_spatial_index(&In[1]);
146
 
    
147
 
    /* Lines in A. Go through all lines and mark those that meets condition */
148
 
    if (itype[0] & (GV_POINTS | GV_LINES)) {
149
 
        G_message(_("Processing features..."));
150
 
        
151
 
        for (aline = 1; aline <= nalines; aline++) {
152
 
            BOUND_BOX abox;
153
 
 
154
 
            G_debug(3, "aline = %d", aline);
155
 
            G_percent(aline, nalines, 2);       /* must be before any continue */
156
 
 
157
 
            /* Check category */
158
 
            if (!flag.cat->answer && Vect_get_line_cat(&(In[0]), aline, ifield[0]) < 0) {
159
 
                nskipped++;
160
 
                continue;
161
 
            }
162
 
 
163
 
            /* Read line and check type */
164
 
            if (operator != OP_OVERLAP) {
165
 
#ifdef HAVE_GEOS
166
 
                AGeom = Vect_read_line_geos(&(In[0]), aline, &ltype);
167
 
#endif
168
 
                if (!(ltype & (GV_POINT | GV_LINE)))
169
 
                    continue;
170
 
 
171
 
                if (!AGeom)
172
 
                    G_fatal_error(_("Unable to read line id %d from vector map <%s>"),
173
 
                                  aline, Vect_get_full_name(&(In[0])));
174
 
            }
175
 
            else {
176
 
                ltype = Vect_read_line(&(In[0]), APoints, NULL, aline);
177
 
            }
178
 
            
179
 
            if (!(ltype & itype[0]))
180
 
                continue;
181
 
            
182
 
            Vect_get_line_box(&(In[0]), aline, &abox);
183
 
            abox.T = PORT_DOUBLE_MAX;
184
 
            abox.B = -PORT_DOUBLE_MAX;
185
 
 
186
 
            /* Check if this line overlaps any feature in B */
187
 
            /* x Lines in B */
188
 
            if (itype[1] & (GV_POINTS | GV_LINES)) {
189
 
                int i;
190
 
                int found = 0;
191
 
                
192
 
                /* Lines */
193
 
                Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);
194
 
                for (i = 0; i < List->n_values; i++) {
195
 
                    int bline;
196
 
                    
197
 
                    bline = List->value[i];
198
 
                    G_debug(3, "  bline = %d", bline);
199
 
                    
200
 
                    /* Check category */
201
 
                    if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
202
 
                        nskipped++;
203
 
                        continue;
204
 
                    }
205
 
                    
206
 
                    if (operator != OP_OVERLAP) {
207
 
#ifdef HAVE_GEOS
208
 
                        if(line_relate_geos(&(In[1]), AGeom,
209
 
                                            bline, operator, parm.relate->answer)) {
210
 
 
211
 
                            found = 1;
212
 
                            break;
213
 
                        }
214
 
#endif
215
 
                    }
216
 
                    else {
217
 
                        Vect_read_line(&(In[1]), BPoints, NULL, bline);
218
 
 
219
 
                        if (Vect_line_check_intersection(APoints, BPoints, 0)) {
220
 
                            found = 1;
221
 
                            break;
222
 
                        }
223
 
                    }
224
 
                }
225
 
                
226
 
                if (found) {
227
 
                    ALines[aline] = 1;
228
 
                    continue;   /* Go to next A line */
229
 
                }
230
 
            }
231
 
            
232
 
            /* x Areas in B. */
233
 
            if (itype[1] & GV_AREA) {
234
 
                int i;
235
 
                
236
 
                Vect_select_areas_by_box(&(In[1]), &abox, List);
237
 
                for (i = 0; i < List->n_values; i++) {
238
 
                    int barea;
239
 
                    
240
 
                    barea = List->value[i];
241
 
                    G_debug(3, "  barea = %d", barea);
242
 
                    
243
 
                    if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
244
 
                        nskipped++;
245
 
                        continue;
246
 
                    }
247
 
 
248
 
                    if (operator != OP_OVERLAP) {
249
 
#ifdef HAVE_GEOS
250
 
                        if(area_relate_geos(&(In[1]), AGeom,
251
 
                                            barea, operator, parm.relate->answer)) {
252
 
                            ALines[aline] = 1;
253
 
                            break;
254
 
                        }
255
 
#endif
256
 
                    }
257
 
                    else {
258
 
                        if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) {
259
 
                            ALines[aline] = 1;
260
 
                            break;
261
 
                        }
262
 
                    }
263
 
                }
264
 
            }
265
 
            if (operator != OP_OVERLAP) {
266
 
#ifdef HAVE_GEOS
267
 
                GEOSGeom_destroy(AGeom);
268
 
#endif
269
 
                AGeom = NULL;
270
 
            }
271
 
        }
272
 
    }
273
 
    
274
 
    /* Areas in A. */
275
 
    if (itype[0] & GV_AREA) {
276
 
        int aarea, naareas;
277
 
 
278
 
        G_message(_("Processing areas..."));
279
 
        
280
 
        naareas = Vect_get_num_areas(&(In[0]));
281
 
 
282
 
        for (aarea = 1; aarea <= naareas; aarea++) {
283
 
            BOUND_BOX abox;
284
 
 
285
 
            G_percent(aarea, naareas, 2);       /* must be before any continue */
286
 
 
287
 
            if (Vect_get_area_cat(&(In[0]), aarea, ifield[0]) < 0) {
288
 
                nskipped++;
289
 
                continue;
290
 
            }
291
 
        
292
 
            Vect_get_area_box(&(In[0]), aarea, &abox);
293
 
            abox.T = PORT_DOUBLE_MAX;
294
 
            abox.B = -PORT_DOUBLE_MAX;
295
 
 
296
 
            if (operator != OP_OVERLAP) {
297
 
#ifdef HAVE_GEOS
298
 
                AGeom = Vect_read_area_geos(&(In[0]), aarea);
299
 
#endif
300
 
                if (!AGeom)
301
 
                    G_fatal_error(_("Unable to read area id %d from vector map <%s>"),
302
 
                                  aline, Vect_get_full_name(&(In[0])));
303
 
            }
304
 
 
305
 
            /* x Lines in B */
306
 
            if (itype[1] & (GV_POINTS | GV_LINES)) {
307
 
                Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);
308
 
 
309
 
                for (i = 0; i < List->n_values; i++) {
310
 
                    int bline;
311
 
 
312
 
                    bline = List->value[i];
313
 
 
314
 
                    if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
315
 
                        nskipped++;
316
 
                        continue;
317
 
                    }
318
 
                    
319
 
                    if (operator != OP_OVERLAP) {
320
 
#ifdef HAVE_GEOS
321
 
                        if(line_relate_geos(&(In[1]), AGeom,
322
 
                                            bline, operator, parm.relate->answer)) {
323
 
                            add_aarea(&(In[0]), aarea, ALines);
324
 
                            break;
325
 
                        }
326
 
#endif
327
 
                    }
328
 
                    else {
329
 
                        if (line_overlap_area(&(In[1]), bline, &(In[0]), aarea)) {
330
 
                            add_aarea(&(In[0]), aarea, ALines);
331
 
                            continue;
332
 
                        }
333
 
                    }
334
 
                }
335
 
            }
336
 
 
337
 
            /* x Areas in B */
338
 
            if (itype[1] & GV_AREA) {
339
 
                int naisles;
340
 
                int found = 0;
341
 
 
342
 
                /* List of areas B */
343
 
 
344
 
                /* Make a list of features forming area A */
345
 
                Vect_reset_list(List);
346
 
 
347
 
                Vect_get_area_boundaries(&(In[0]), aarea, BoundList);
348
 
                for (i = 0; i < BoundList->n_values; i++) {
349
 
                    Vect_list_append(List, abs(BoundList->value[i]));
350
 
                }
351
 
 
352
 
                naisles = Vect_get_area_num_isles(&(In[0]), aarea);
353
 
 
354
 
                for (i = 0; i < naisles; i++) {
355
 
                    int j, aisle;
356
 
 
357
 
                    aisle = Vect_get_area_isle(&(In[0]), aarea, i);
358
 
 
359
 
                    Vect_get_isle_boundaries(&(In[0]), aisle, BoundList);
360
 
                    for (j = 0; j < BoundList->n_values; j++) {
361
 
                        Vect_list_append(List, BoundList->value[j]);
362
 
                    }
363
 
                }
364
 
 
365
 
                Vect_select_areas_by_box(&(In[1]), &abox, TmpList);
366
 
 
367
 
                for (i = 0; i < List->n_values; i++) {
368
 
                    int j, aline;
369
 
 
370
 
                    aline = abs(List->value[i]);
371
 
 
372
 
                    for (j = 0; j < TmpList->n_values; j++) {
373
 
                        int barea, bcentroid;
374
 
 
375
 
                        barea = TmpList->value[j];
376
 
                        G_debug(3, "  barea = %d", barea);
377
 
 
378
 
                        if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
379
 
                            nskipped++;
380
 
                            continue;
381
 
                        }
382
 
 
383
 
                        /* Check if any centroid of area B is in area A.
384
 
                         * This test is important in if area B is completely within area A */
385
 
                        bcentroid = Vect_get_area_centroid(&(In[1]), barea);
386
 
                        Vect_read_line(&(In[1]), BPoints, NULL, bcentroid);
387
 
 
388
 
                        if (operator != OP_OVERLAP) {
389
 
#ifdef HAVE_GEOS
390
 
                            if(area_relate_geos(&(In[1]), AGeom,
391
 
                                                barea, operator, parm.relate->answer)) {
392
 
                                found = 1;
393
 
                                break;
394
 
                            }
395
 
#endif
396
 
                        }
397
 
                        else {
398
 
                            if (Vect_point_in_area(&(In[0]), aarea,
399
 
                                                   BPoints->x[0], BPoints->y[0])) {
400
 
                                found = 1;
401
 
                                break;
402
 
                            }
403
 
                            
404
 
                            /* Check intersectin of lines from List with area B */
405
 
                            if (line_overlap_area(&(In[0]), aline,
406
 
                                                  &(In[1]), barea)) {
407
 
                                found = 1;
408
 
                                break;
409
 
                            }
410
 
                        }
411
 
                    }
412
 
                    if (found) {
413
 
                        add_aarea(&(In[0]), aarea, ALines);
414
 
                        break;
415
 
                    }
416
 
                }
417
 
            }
418
 
            if (operator != OP_OVERLAP) {
419
 
#ifdef HAVE_GEOS
420
 
                GEOSGeom_destroy(AGeom);
421
 
#endif
422
 
                AGeom = NULL;
423
 
            }
424
 
        }
425
 
    }
426
 
    
427
 
    Vect_close(&(In[1]));
428
 
 
 
138
    select_lines(&(In[0]), itype[0], ifield[0],
 
139
                 &(In[1]), itype[1], ifield[1],
 
140
                 flag.cat->answer ? 1 : 0, operator,
 
141
                 NULL,
 
142
                 ALines, nskipped);
 
143
#endif
 
144
    
429
145
#ifdef HAVE_GEOS
430
146
    finishGEOS();
431
147
#endif
432
148
 
433
 
    /* Write lines */
 
149
    native = Vect_maptype(&Out) == GV_FORMAT_NATIVE;
 
150
 
434
151
    nfields = Vect_cidx_get_num_fields(&(In[0]));
435
152
    cats = (int **)G_malloc(nfields * sizeof(int *));
436
153
    ncats = (int *)G_malloc(nfields * sizeof(int));
437
154
    fields = (int *)G_malloc(nfields * sizeof(int));
438
 
    for (i = 0; i < nfields; i++) {
439
 
        ncats[i] = 0;
440
 
        cats[i] =
441
 
            (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&(In[0]), i) *
442
 
                            sizeof(int));
443
 
        fields[i] = Vect_cidx_get_field_number(&(In[0]), i);
444
 
    }
445
 
 
446
 
    G_message(_("Writing selected features..."));
447
 
    for (aline = 1; aline <= nalines; aline++) {
448
 
        int atype;
449
 
 
450
 
        G_debug(4, "aline = %d ALines[aline] = %d", aline, ALines[aline]);
451
 
        G_percent(aline, nalines, 2);
452
 
        
453
 
        if ((!flag.reverse->answer && !(ALines[aline])) ||
454
 
            (flag.reverse->answer && ALines[aline]))
455
 
            continue;
456
 
 
457
 
        atype = Vect_read_line(&(In[0]), APoints, ACats, aline);
458
 
        Vect_write_line(&Out, atype, APoints, ACats);
459
 
 
460
 
        if (!(flag.table->answer) && (IFi != NULL)) {
461
 
            for (i = 0; i < ACats->n_cats; i++) {
462
 
                int f, j;
463
 
 
464
 
                for (j = 0; j < nfields; j++) { /* find field */
465
 
                    if (fields[j] == ACats->field[i]) {
466
 
                        f = j;
467
 
                        break;
468
 
                    }
469
 
                }
470
 
                cats[f][ncats[f]] = ACats->cat[i];
471
 
                ncats[f]++;
472
 
            }
473
 
        }
474
 
    }
 
155
 
 
156
    /* Write lines */
 
157
    if (!flag.table->answer && !native) {
 
158
        /* Copy attributes for OGR output */
 
159
        Vect_copy_map_dblinks(&(In[0]), &Out, TRUE);
 
160
    }
 
161
    
 
162
    write_lines(&(In[0]), IFi, ALines,
 
163
                &Out, flag.table->answer ? 1 : 0, flag.reverse->answer ? 1 : 0,
 
164
                nfields, fields, ncats, cats);
475
165
 
476
166
    /* Copy tables */
477
 
    if (!(flag.table->answer)) {
478
 
        int ttype, ntabs = 0;
479
 
 
480
 
        G_message(_("Writing attributes..."));
481
 
 
482
 
        /* Number of output tabs */
483
 
        for (i = 0; i < Vect_get_num_dblinks(&(In[0])); i++) {
484
 
            int f, j;
485
 
 
486
 
            IFi = Vect_get_dblink(&(In[0]), i);
487
 
 
488
 
            for (j = 0; j < nfields; j++) {     /* find field */
489
 
                if (fields[j] == IFi->number) {
490
 
                    f = j;
491
 
                    break;
492
 
                }
493
 
            }
494
 
            if (ncats[f] > 0)
495
 
                ntabs++;
496
 
        }
497
 
 
498
 
        if (ntabs > 1)
499
 
            ttype = GV_MTABLE;
500
 
        else
501
 
            ttype = GV_1TABLE;
502
 
 
503
 
        for (i = 0; i < nfields; i++) {
504
 
            int ret;
505
 
 
506
 
            if (fields[i] == 0)
507
 
                continue;
508
 
 
509
 
            /* Make a list of categories */
510
 
            IFi = Vect_get_field(&(In[0]), fields[i]);
511
 
            if (!IFi) {         /* no table */
512
 
                G_warning(_("Layer %d - no table"), fields[i]);
513
 
                continue;
514
 
            }
515
 
 
516
 
            OFi =
517
 
                Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);
518
 
 
519
 
            ret =
520
 
                db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
521
 
                                      OFi->driver,
522
 
                                      Vect_subst_var(OFi->database, &Out),
523
 
                                      OFi->table, IFi->key, cats[i],
524
 
                                      ncats[i]);
525
 
 
526
 
            if (ret == DB_FAILED) {
527
 
                G_warning(_("Layer %d - unable to copy table"), fields[i]);
528
 
            }
529
 
            else {
530
 
                Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
531
 
                                    IFi->key, OFi->database, OFi->driver);
532
 
            }
533
 
        }
534
 
    }
535
 
 
536
 
    Vect_close(&(In[0]));
 
167
    if (!flag.table->answer && native) {
 
168
        copy_tabs(&(In[0]), &Out,
 
169
                  nfields, fields, ncats, cats);
 
170
    }
 
171
 
 
172
    /* print info about skipped features & close input maps */
 
173
    for (iopt = 0; iopt < 2; iopt++) {
 
174
        if (nskipped[iopt] > 0) {
 
175
            G_warning(_("%d features from <%s> without category skipped"),
 
176
                      nskipped[iopt], Vect_get_full_name(&(In[iopt])));
 
177
        }
 
178
        Vect_close(&(In[iopt]));
 
179
    }
537
180
 
538
181
    Vect_build(&Out);
539
182
    Vect_close(&Out);
540
183
 
541
 
    if (nskipped > 0) {
542
 
      G_warning(_("%d features without category skipped"), nskipped);
543
 
    }
544
 
 
545
184
    G_done_msg(_("%d features written to output."), Vect_get_num_lines(&Out));
546
185
 
547
186
    exit(EXIT_SUCCESS);