| 1 |
|
|---|
| 2 | /****************************************************************************
|
|---|
| 3 | *
|
|---|
| 4 | * MODULE: v.select
|
|---|
| 5 | * AUTHOR(S): Radim Blazek <radim.blazek gmail.com> (original contributor)
|
|---|
| 6 | * Glynn Clements <glynn gclements.plus.com>
|
|---|
| 7 | * Markus Neteler <neteler itc.it>
|
|---|
| 8 | * Martin Landa <landa.martin gmail.com> (GEOS support)
|
|---|
| 9 | * Huidae Cho <grass4u gmail.com> (reverse flag fix)
|
|---|
| 10 | * PURPOSE: Select features from one map by features in another map.
|
|---|
| 11 | * COPYRIGHT: (C) 2003-2017, 2019 by the GRASS Development Team
|
|---|
| 12 | *
|
|---|
| 13 | * This program is free software under the GNU General
|
|---|
| 14 | * Public License (>=v2). Read the file COPYING that
|
|---|
| 15 | * comes with GRASS for details.
|
|---|
| 16 | *
|
|---|
| 17 | *****************************************************************************/
|
|---|
| 18 |
|
|---|
| 19 | #include <stdlib.h>
|
|---|
| 20 | #include <string.h>
|
|---|
| 21 | #include <stdio.h>
|
|---|
| 22 |
|
|---|
| 23 | #include <grass/gis.h>
|
|---|
| 24 | #include <grass/vector.h>
|
|---|
| 25 | #include <grass/glocale.h>
|
|---|
| 26 |
|
|---|
| 27 | #include "proto.h"
|
|---|
| 28 |
|
|---|
| 29 | int main(int argc, char *argv[])
|
|---|
| 30 | {
|
|---|
| 31 | int iopt;
|
|---|
| 32 | int operator;
|
|---|
| 33 | int nskipped[2], native, nfound;
|
|---|
| 34 | int itype[2], ifield[2];
|
|---|
| 35 |
|
|---|
| 36 | int *ALines; /* List of lines: 0 do not output, 1 - write to output */
|
|---|
| 37 | int *AAreas; /* List of areas: 0 do not output, 1 - write area boundaries to output */
|
|---|
| 38 | int **cats, *ncats, *fields, nfields;
|
|---|
| 39 |
|
|---|
| 40 | struct GModule *module;
|
|---|
| 41 | struct GParm parm;
|
|---|
| 42 | struct GFlag flag;
|
|---|
| 43 | struct Map_info In[2], Out;
|
|---|
| 44 | struct field_info *IFi;
|
|---|
| 45 | int nlines, nareas;
|
|---|
| 46 |
|
|---|
| 47 | G_gisinit(argv[0]);
|
|---|
| 48 |
|
|---|
| 49 | module = G_define_module();
|
|---|
| 50 | G_add_keyword(_("vector"));
|
|---|
| 51 | G_add_keyword(_("geometry"));
|
|---|
| 52 | G_add_keyword(_("spatial query"));
|
|---|
| 53 | module->description =
|
|---|
| 54 | _("Selects features from vector map (A) by features from other vector map (B).");
|
|---|
| 55 |
|
|---|
| 56 | parse_options(&parm, &flag);
|
|---|
| 57 |
|
|---|
| 58 | if (G_parser(argc, argv))
|
|---|
| 59 | exit(EXIT_FAILURE);
|
|---|
| 60 |
|
|---|
| 61 | if (parm.operator->answer[0] == 'e')
|
|---|
| 62 | operator = OP_EQUALS;
|
|---|
| 63 | else if (parm.operator->answer[0] == 'd') {
|
|---|
| 64 | /* operator = OP_DISJOINT; */
|
|---|
| 65 | operator = OP_INTERSECTS;
|
|---|
| 66 | flag.reverse->answer = YES;
|
|---|
| 67 | }
|
|---|
| 68 | else if (parm.operator->answer[0] == 'i')
|
|---|
| 69 | operator = OP_INTERSECTS;
|
|---|
| 70 | else if (parm.operator->answer[0] == 't')
|
|---|
| 71 | operator = OP_TOUCHES;
|
|---|
| 72 | else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'r')
|
|---|
| 73 | operator = OP_CROSSES;
|
|---|
| 74 | else if (parm.operator->answer[0] == 'w')
|
|---|
| 75 | operator = OP_WITHIN;
|
|---|
| 76 | else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'o')
|
|---|
| 77 | operator = OP_CONTAINS;
|
|---|
| 78 | else if (parm.operator->answer[0] == 'o') {
|
|---|
| 79 | if (strcmp(parm.operator->answer, "overlaps") == 0)
|
|---|
| 80 | operator = OP_OVERLAPS;
|
|---|
| 81 | else
|
|---|
| 82 | operator = OP_OVERLAP;
|
|---|
| 83 | }
|
|---|
| 84 | else if (parm.operator->answer[0] == 'r')
|
|---|
| 85 | operator = OP_RELATE;
|
|---|
| 86 | else
|
|---|
| 87 | G_fatal_error(_("Unknown operator '%s'"), parm.operator->answer);
|
|---|
| 88 |
|
|---|
| 89 | #ifdef HAVE_GEOS
|
|---|
| 90 | if (operator == OP_RELATE && !parm.relate->answer) {
|
|---|
| 91 | G_fatal_error(_("Required parameter <%s> not set"),
|
|---|
| 92 | parm.relate->key);
|
|---|
| 93 | }
|
|---|
| 94 | #else
|
|---|
| 95 | if (operator != OP_OVERLAP) {
|
|---|
| 96 | G_warning(_("Operator can only be 'overlap'"));
|
|---|
| 97 | operator = OP_OVERLAP;
|
|---|
| 98 | }
|
|---|
| 99 | #endif
|
|---|
| 100 | for (iopt = 0; iopt < 2; iopt++) {
|
|---|
| 101 | itype[iopt] = Vect_option_to_types(parm.type[iopt]);
|
|---|
| 102 |
|
|---|
| 103 | Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer,
|
|---|
| 104 | G_FATAL_EXIT);
|
|---|
| 105 |
|
|---|
| 106 | Vect_set_open_level(2);
|
|---|
| 107 |
|
|---|
| 108 | if (Vect_open_old2(&(In[iopt]), parm.input[iopt]->answer, "",
|
|---|
| 109 | parm.field[iopt]->answer) < 0)
|
|---|
| 110 | G_fatal_error(_("Unable to open vector map <%s>"),
|
|---|
| 111 | parm.input[iopt]->answer);
|
|---|
| 112 |
|
|---|
| 113 | ifield[iopt] = Vect_get_field_number(&(In[iopt]), parm.field[iopt]->answer);
|
|---|
| 114 | }
|
|---|
| 115 |
|
|---|
| 116 | /* Alloc space for input lines array */
|
|---|
| 117 | nlines = Vect_get_num_lines(&(In[0]));
|
|---|
| 118 | nareas = Vect_get_num_areas(&(In[0]));
|
|---|
| 119 |
|
|---|
| 120 | ALines = (int *)G_calloc(nlines + 1, sizeof(int));
|
|---|
| 121 | AAreas = (int *)G_calloc(nareas + 1, sizeof(int));
|
|---|
| 122 |
|
|---|
| 123 | /* Read field info */
|
|---|
| 124 | IFi = Vect_get_field(&(In[0]), ifield[0]);
|
|---|
| 125 |
|
|---|
| 126 | /* Select features */
|
|---|
| 127 | #ifdef HAVE_GEOS
|
|---|
| 128 | nfound = select_lines(&(In[0]), itype[0], ifield[0],
|
|---|
| 129 | &(In[1]), itype[1], ifield[1],
|
|---|
| 130 | flag.cat->answer ? 1 : 0, operator,
|
|---|
| 131 | parm.relate->answer,
|
|---|
| 132 | ALines, AAreas, nskipped);
|
|---|
| 133 | #else
|
|---|
| 134 | nfound = select_lines(&(In[0]), itype[0], ifield[0],
|
|---|
| 135 | &(In[1]), itype[1], ifield[1],
|
|---|
| 136 | flag.cat->answer ? 1 : 0, operator,
|
|---|
| 137 | NULL,
|
|---|
| 138 | ALines, AAreas, nskipped);
|
|---|
| 139 | #endif
|
|---|
| 140 |
|
|---|
| 141 | #ifdef HAVE_GEOS
|
|---|
| 142 | finishGEOS();
|
|---|
| 143 | #endif
|
|---|
| 144 |
|
|---|
| 145 | if (!flag.reverse->answer) {
|
|---|
| 146 | G_free(AAreas);
|
|---|
| 147 | AAreas = NULL;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 |
|
|---|
| 151 | if ((!flag.reverse->answer && nfound > 0) ||
|
|---|
| 152 | (flag.reverse->answer && nlines + nareas - nfound > 0)) {
|
|---|
| 153 | /* Open output */
|
|---|
| 154 | if (Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0]))) < 0)
|
|---|
| 155 | G_fatal_error(_("Unable to create vector map <%s>"),
|
|---|
| 156 | parm.output->answer);
|
|---|
| 157 |
|
|---|
| 158 | Vect_set_map_name(&Out, _("Output from v.select"));
|
|---|
| 159 | Vect_set_person(&Out, G_whoami());
|
|---|
| 160 | Vect_copy_head_data(&(In[0]), &Out);
|
|---|
| 161 | Vect_hist_copy(&(In[0]), &Out);
|
|---|
| 162 | Vect_hist_command(&Out);
|
|---|
| 163 |
|
|---|
| 164 | native = Vect_maptype(&Out) == GV_FORMAT_NATIVE;
|
|---|
| 165 |
|
|---|
| 166 | nfields = Vect_cidx_get_num_fields(&(In[0]));
|
|---|
| 167 | cats = (int **)G_malloc(nfields * sizeof(int *));
|
|---|
| 168 | ncats = (int *)G_malloc(nfields * sizeof(int));
|
|---|
| 169 | fields = (int *)G_malloc(nfields * sizeof(int));
|
|---|
| 170 |
|
|---|
| 171 | /* Write lines */
|
|---|
| 172 | if (!flag.table->answer && !native) {
|
|---|
| 173 | /* Copy attributes for OGR output */
|
|---|
| 174 | Vect_copy_map_dblinks(&(In[0]), &Out, TRUE);
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | write_lines(&(In[0]), IFi, ALines, AAreas,
|
|---|
| 178 | &Out, flag.table->answer ? 1 : 0, flag.reverse->answer ? 1 : 0,
|
|---|
| 179 | nfields, fields, ncats, cats);
|
|---|
| 180 |
|
|---|
| 181 | /* Copy tables */
|
|---|
| 182 | if (!flag.table->answer && native) {
|
|---|
| 183 | copy_tabs(&(In[0]), &Out,
|
|---|
| 184 | nfields, fields, ncats, cats);
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | /* print info about skipped features & close input maps */
|
|---|
| 188 | for (iopt = 0; iopt < 2; iopt++) {
|
|---|
| 189 | if (nskipped[iopt] > 0) {
|
|---|
| 190 | G_warning(_("%d features from <%s> without category skipped"),
|
|---|
| 191 | nskipped[iopt], Vect_get_full_name(&(In[iopt])));
|
|---|
| 192 | }
|
|---|
| 193 | Vect_set_release_support(&In[iopt]);
|
|---|
| 194 | Vect_close(&(In[iopt]));
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | Vect_build(&Out);
|
|---|
| 198 | nfound = Vect_get_num_lines(&Out);
|
|---|
| 199 | Vect_set_release_support(&Out);
|
|---|
| 200 | Vect_close(&Out);
|
|---|
| 201 |
|
|---|
| 202 | G_done_msg(_("%d features written to output."), nfound);
|
|---|
| 203 | }
|
|---|
| 204 | else {
|
|---|
| 205 | Vect_set_release_support(&In[0]);
|
|---|
| 206 | Vect_set_release_support(&In[1]);
|
|---|
| 207 | Vect_close(&In[0]);
|
|---|
| 208 | Vect_close(&In[1]);
|
|---|
| 209 | G_done_msg(_("No features found !"));
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | exit(EXIT_SUCCESS);
|
|---|
| 213 | }
|
|---|