1 /****************************************************************************
2 *
3 * MODULE:       v.transform
4 * AUTHOR(S):    Eric G. Miller <egm2@jps.net>
5 *               Upgrade to 5.7 Radim Blazek
6 *               Column support & OGR support added by Martin Landa (09/2007)
7 *
8 * PURPOSE:      To transform a vector map's coordinates via a set of tie
9 *               points.
10 *
11 * COPYRIGHT:    (C) 2002-2014 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  *History:
20  *- This takes an ascii digit file in one coordinate system and converts
21  *  the map to another coordinate system.
22  *  Uses the transform library:  $(TRANSLIB)
23  *
24  *  Written during the ice age of Illinois, 02/16/90, by the GRASS team, -mh.
25  *
26  *- Modified by Dave Gerdes  1/90  for dig_head stuff
27  *- Modified by Radim Blazek to work on binary files 2002
28  *- Interactive functionality disabled, 2007
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <grass/gis.h>
35 #include <grass/vector.h>
36 #include <grass/dbmi.h>
37 #include <grass/glocale.h>
38 #include "trans.h"
39 #include "local_proto.h"
40 
main(int argc,char * argv[])41 int main(int argc, char *argv[])
42 {
43     struct file_info Current, Trans;
44 
45     struct GModule *module;
46 
47     struct Option *vold, *vnew, *xshift, *yshift, *zshift,
48 	*xscale, *yscale, *zscale, *zrot, *columns, *field_opt;
49     struct Flag *tozero_flag, *no_topo;
50     struct Flag *swap_flag, *swap_xz_flag, *swap_yz_flag, *swap_after_flag;
51 
52     char mon[4], date[40], buf[1000];
53     struct Map_info Old, New;
54     int day, yr;
55     struct bound_box box;
56 
57     double ztozero;
58     double trans_params[7];	/* xshift, ..., xscale, ..., zrot */
59 
60     /* columns */
61     unsigned int i;
62     int idx, out3d;
63     char **tokens;
64     char *columns_name[7];	/* xshift, yshift, zshift, xscale, yscale, zscale, zrot */
65     int field;
66 
67     G_gisinit(argv[0]);
68 
69     module = G_define_module();
70     G_add_keyword(_("vector"));
71     G_add_keyword(_("transformation"));
72     G_add_keyword(_("geometry"));
73     G_add_keyword("GCP");
74     module->description =
75 	_("Performs an affine transformation (shift, scale and rotate) "
76 	  "on vector map.");
77 
78     tozero_flag = G_define_flag();
79     tozero_flag->key = 't';
80     tozero_flag->description = _("Shift all z values to bottom=0");
81 
82     swap_flag = G_define_flag();
83     swap_flag->key = 'w';
84     swap_flag->description =
85 	_("Swap coordinates x, y and then apply other parameters");
86 
87     swap_xz_flag = G_define_flag();
88     swap_xz_flag->key = 'x';
89     swap_xz_flag->description =
90         _("Swap coordinates x, z and then apply other parameters");
91 
92     swap_yz_flag = G_define_flag();
93     swap_yz_flag->key = 'y';
94     swap_yz_flag->description =
95         _("Swap coordinates y, z and then apply other parameters");
96 
97     swap_after_flag = G_define_flag();
98     swap_after_flag->key = 'a';
99     swap_after_flag->description =
100         _("Swap coordinates after the other transformations");
101 
102     no_topo = G_define_flag();
103     no_topo->key = 'b';
104     no_topo->description = _("Do not build topology");
105 
106     vold = G_define_standard_option(G_OPT_V_INPUT);
107 
108     field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
109     field_opt->guisection = _("Custom");
110 
111     vnew = G_define_standard_option(G_OPT_V_OUTPUT);
112 
113     xshift = G_define_option();
114     xshift->key = "xshift";
115     xshift->type = TYPE_DOUBLE;
116     xshift->required = NO;
117     xshift->multiple = NO;
118     xshift->description = _("Shifting value for x coordinates");
119     xshift->answer = "0.0";
120     xshift->guisection = _("Custom");
121 
122     yshift = G_define_option();
123     yshift->key = "yshift";
124     yshift->type = TYPE_DOUBLE;
125     yshift->required = NO;
126     yshift->multiple = NO;
127     yshift->description = _("Shifting value for y coordinates");
128     yshift->answer = "0.0";
129     yshift->guisection = _("Custom");
130 
131     zshift = G_define_option();
132     zshift->key = "zshift";
133     zshift->type = TYPE_DOUBLE;
134     zshift->required = NO;
135     zshift->multiple = NO;
136     zshift->description = _("Shifting value for z coordinates");
137     zshift->answer = "0.0";
138     zshift->guisection = _("Custom");
139 
140     xscale = G_define_option();
141     xscale->key = "xscale";
142     xscale->type = TYPE_DOUBLE;
143     xscale->required = NO;
144     xscale->multiple = NO;
145     xscale->description = _("Scaling factor for x coordinates");
146     xscale->answer = "1.0";
147     xscale->guisection = _("Custom");
148 
149     yscale = G_define_option();
150     yscale->key = "yscale";
151     yscale->type = TYPE_DOUBLE;
152     yscale->required = NO;
153     yscale->multiple = NO;
154     yscale->description = _("Scaling factor for y coordinates");
155     yscale->answer = "1.0";
156     yscale->guisection = _("Custom");
157 
158     zscale = G_define_option();
159     zscale->key = "zscale";
160     zscale->type = TYPE_DOUBLE;
161     zscale->required = NO;
162     zscale->multiple = NO;
163     zscale->description = _("Scaling factor for z coordinates");
164     zscale->answer = "1.0";
165     zscale->guisection = _("Custom");
166 
167     zrot = G_define_option();
168     zrot->key = "zrotation";
169     zrot->type = TYPE_DOUBLE;
170     zrot->required = NO;
171     zrot->multiple = NO;
172     zrot->description =
173 	_("Rotation around z axis in degrees (counter-clockwise)");
174     zrot->answer = "0.0";
175     zrot->guisection = _("Custom");
176 
177     columns = G_define_standard_option(G_OPT_DB_COLUMNS);
178     columns->label =
179 	_("Name of attribute column(s) used as transformation parameters");
180     columns->description =
181 	_("Format: parameter:column, e.g. xshift:xs,yshift:ys,zrot:zr");
182     columns->guisection = _("Custom");
183 
184     /* we don't define order of swapping, so only one can be used safely */
185     G_option_exclusive(swap_flag, swap_xz_flag, swap_yz_flag, NULL);
186 
187     if (G_parser(argc, argv))
188 	exit(EXIT_FAILURE);
189 
190     strcpy(Current.name, vold->answer);
191     strcpy(Trans.name, vnew->answer);
192 
193     Vect_check_input_output_name(vold->answer, vnew->answer, G_FATAL_EXIT);
194 
195     /* open input vector */
196     if (Vect_open_old2(&Old, vold->answer, "", field_opt->answer) < 0)
197 	G_fatal_error(_("Unable to open vector map <%s>"), vold->answer);
198 
199     field = Vect_get_field_number(&Old, field_opt->answer);
200     if (field < 1 && columns->answer) {
201 	G_fatal_error(_("Columns require a valid layer. Please use '%s' parameter."),
202 		      field_opt->key);
203     }
204 
205     out3d = Vect_is_3d(&Old);
206 
207     /* tokenize columns names */
208     for (i = 0; i <= IDX_ZROT; i++) {
209 	columns_name[i] = NULL;
210     }
211     i = 0;
212     if (columns->answer) {
213 	while (columns->answers[i]) {
214 	    tokens = G_tokenize(columns->answers[i], ":");
215 	    if (G_number_of_tokens(tokens) == 2) {
216 		if (strcmp(tokens[0], xshift->key) == 0)
217 		    idx = IDX_XSHIFT;
218 		else if (strcmp(tokens[0], yshift->key) == 0)
219 		    idx = IDX_YSHIFT;
220 		else if (strcmp(tokens[0], zshift->key) == 0)
221 		    idx = IDX_ZSHIFT;
222 		else if (strcmp(tokens[0], xscale->key) == 0)
223 		    idx = IDX_XSCALE;
224 		else if (strcmp(tokens[0], yscale->key) == 0)
225 		    idx = IDX_YSCALE;
226 		else if (strcmp(tokens[0], zscale->key) == 0)
227 		    idx = IDX_ZSCALE;
228 		else if (strcmp(tokens[0], zrot->key) == 0)
229 		    idx = IDX_ZROT;
230 		else {
231 		    G_warning(_("Unknown column parameter '%s'"),
232 		              tokens[0]);
233 		    idx = -1;
234 		}
235 
236 		if (idx != -1)
237 		    columns_name[idx] = G_store(tokens[1]);
238 
239 		G_free_tokens(tokens);
240 	    }
241 	    else {
242 		G_fatal_error(_("Unable to tokenize column string: [%s]"),
243 			      columns->answers[i]);
244 	    }
245 	    i++;
246 	}
247     }
248 
249     /* determine transformation parameters */
250     trans_params[IDX_XSHIFT] = atof(xshift->answer);
251     trans_params[IDX_YSHIFT] = atof(yshift->answer);
252     trans_params[IDX_ZSHIFT] = atof(zshift->answer);
253     trans_params[IDX_XSCALE] = atof(xscale->answer);
254     trans_params[IDX_YSCALE] = atof(yscale->answer);
255     trans_params[IDX_ZSCALE] = atof(zscale->answer);
256     trans_params[IDX_ZROT] = atof(zrot->answer);
257 
258     /* should output be 3D ?
259      * note that z-scale and ztozero have no effect with input 2D */
260     if (trans_params[IDX_ZSHIFT] != 0. || columns_name[IDX_ZSHIFT])
261 	out3d = WITH_Z;
262 
263     /* open output vector */
264     if (Vect_open_new(&New, vnew->answer, out3d) < 0)
265 	G_fatal_error(_("Unable to create vector map <%s>"), vnew->answer);
266 
267     /* copy and set header */
268     Vect_copy_head_data(&Old, &New);
269 
270     Vect_hist_copy(&Old, &New);
271     Vect_hist_command(&New);
272 
273     sprintf(date, "%s", G_date());
274     sscanf(date, "%*s%s%d%*s%d", mon, &day, &yr);
275     sprintf(date, "%s %d %d", mon, day, yr);
276     Vect_set_date(&New, date);
277 
278     Vect_set_person(&New, G_whoami());
279 
280     sprintf(buf, "transformed from %s", vold->answer);
281     Vect_set_map_name(&New, buf);
282 
283     Vect_set_scale(&New, 1);
284     Vect_set_zone(&New, 0);
285     Vect_set_thresh(&New, 0.0);
286 
287     Vect_get_map_box(&Old, &box);
288 
289     /* z to zero */
290     if (tozero_flag->answer)
291 	ztozero = 0 - box.B;
292     else
293 	ztozero = 0;
294 
295     /* do the transformation */
296     G_important_message(_("Transforming features..."));
297     transform_digit_file(&Old, &New, ztozero, swap_flag->answer,
298                          swap_xz_flag->answer, swap_yz_flag->answer,
299                          swap_after_flag->answer, trans_params, columns_name,
300                          field);
301 
302     G_important_message(_("Copying attributes..."));
303     if (Vect_copy_tables(&Old, &New, 0))
304         G_warning(_("Failed to copy attribute table to output map"));
305     Vect_close(&Old);
306     if (!no_topo->answer)
307 	Vect_build(&New);
308 
309     Vect_get_map_box(&New, &box);
310     G_verbose_message(_("New vector map <%s> boundary coordinates:"),
311 		      vnew->answer);
312     G_verbose_message(_(" N: %-10.3f    S: %-10.3f"), box.N, box.S);
313     G_verbose_message(_(" E: %-10.3f    W: %-10.3f"), box.E, box.W);
314     G_verbose_message(_(" B: %6.3f    T: %6.3f"), box.B, box.T);
315 
316     Vect_close(&New);
317 
318     G_done_msg(" ");
319 
320     exit(EXIT_SUCCESS);
321 }
322