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