main.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /* r.resamp.rst - flexible, normalized segmented processing surface analysis
  2. * program with tension and smoothing.
  3. *
  4. * Written by H. Mitasova, I. Kosinovsky, D. Gerdes Summer 1993
  5. * University of Illinois
  6. * US Army Construction Engineering Research Lab
  7. * Copyright 1993, H. Mitasova (University of Illinois),
  8. * I. Kosinovsky, (USA-CERL), and D.Gerdes (USA-CERL)
  9. *
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. *
  26. * modified by McCauley in August 1995
  27. * modified by Mitasova in August 1995
  28. * modified by Mitasova in November 1999
  29. *
  30. */
  31. #include <stdio.h>
  32. #include <math.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <grass/dbmi.h>
  36. #include <grass/gis.h>
  37. #include <grass/raster.h>
  38. #include <grass/linkm.h>
  39. #include <grass/bitmap.h>
  40. #include "surf.h"
  41. #include <grass/interpf.h>
  42. #include <grass/glocale.h>
  43. #include <grass/gmath.h>
  44. static double /* pargr */ ns_res, ew_res, inp_ew_res, inp_ns_res;
  45. static int inp_rows, inp_cols;
  46. static double inp_x_orig, inp_y_orig;
  47. static double dmin, ertre, deltx, delty;
  48. static int nsizr, nsizc;
  49. static double /* datgr */ *az, *adx, *ady, *adxx, *adyy, *adxy;
  50. static double /* error */ ertot, ertre, zminac, zmaxac, zmult;
  51. static int NPOINT;
  52. static int deriv, overlap, cursegm, dtens;
  53. static double fi;
  54. static int cond1, cond2;
  55. static double fstar2, tfsta2, xmin, xmax, ymin, ymax, zmin, zmax, gmin, gmax,
  56. c1min, c1max, c2min, c2max;
  57. static double dnorm;
  58. static double smc;
  59. static double theta, scalex;
  60. static FCELL *zero_array_cell;
  61. static struct interp_params params;
  62. static FILE *fd4; /* unused? */
  63. static int fdinp, fdsmooth = -1;
  64. /*
  65. * x,y,z - input data npoint - number of input data fi - tension parameter
  66. * b - coef. of int. function a - matrix of system of linear equations az-
  67. * interpolated values z for output grid adx,ady, ... - estimation of
  68. * derivatives for output grid nsizr,nsizc - number of rows and columns
  69. * for output grid xmin ... - coordinates of corners of output grid
  70. *
  71. * subroutines input_data - input of data x,y,z (test function or measured
  72. * data) iterpolate - interpolation of z-values and derivatives to grid
  73. * secpar_loop- computation of secondary(morphometric) parameters output -
  74. * output of gridded data and derivatives/sec.parameters check_at_points -
  75. * interpolation of z-values to given point x,y
  76. */
  77. static char *input;
  78. static char *smooth;
  79. static char *elev;
  80. static char *slope;
  81. static char *aspect;
  82. static char *pcurv;
  83. static char *tcurv;
  84. static char *mcurv;
  85. static char *maskmap;
  86. static off_t sdisk, disk;
  87. static char *Tmp_file_z;
  88. static char *Tmp_file_dx;
  89. static char *Tmp_file_dy;
  90. static char *Tmp_file_xx;
  91. static char *Tmp_file_yy;
  92. static char *Tmp_file_xy;
  93. static FILE *Tmp_fd_z;
  94. static FILE *Tmp_fd_dx;
  95. static FILE *Tmp_fd_dy;
  96. static FILE *Tmp_fd_xx;
  97. static FILE *Tmp_fd_yy;
  98. static FILE *Tmp_fd_xy;
  99. static FILE *Tmp_fd_z;
  100. static struct BM *bitmask;
  101. static struct Cell_head winhd;
  102. static struct Cell_head inphd;
  103. static struct Cell_head outhd;
  104. static struct Cell_head smhd;
  105. static void create_temp_files(void);
  106. static void clean(void);
  107. int main(int argc, char *argv[])
  108. {
  109. int m1;
  110. struct FPRange range;
  111. DCELL cellmin, cellmax;
  112. FCELL *cellrow, fcellmin;
  113. struct GModule *module;
  114. struct
  115. {
  116. struct Option *input, *elev, *slope, *aspect, *pcurv, *tcurv, *mcurv,
  117. *smooth, *maskmap, *zmult, *fi, *segmax, *npmin, *res_ew, *res_ns,
  118. *overlap, *theta, *scalex;
  119. } parm;
  120. struct
  121. {
  122. struct Flag *deriv, *cprght;
  123. } flag;
  124. G_gisinit(argv[0]);
  125. module = G_define_module();
  126. G_add_keyword(_("raster"));
  127. G_add_keyword(_("resample"));
  128. module->description =
  129. _("Reinterpolates and optionally computes topographic analysis from "
  130. "input raster map to a new raster map (possibly with "
  131. "different resolution) using regularized spline with "
  132. "tension and smoothing.");
  133. parm.input = G_define_standard_option(G_OPT_R_INPUT);
  134. parm.res_ew = G_define_option();
  135. parm.res_ew->key = "ew_res";
  136. parm.res_ew->type = TYPE_DOUBLE;
  137. parm.res_ew->required = YES;
  138. parm.res_ew->description = _("Desired east-west resolution");
  139. parm.res_ns = G_define_option();
  140. parm.res_ns->key = "ns_res";
  141. parm.res_ns->type = TYPE_DOUBLE;
  142. parm.res_ns->required = YES;
  143. parm.res_ns->description = _("Desired north-south resolution");
  144. parm.elev = G_define_standard_option(G_OPT_R_ELEV);
  145. parm.elev->required = NO;
  146. parm.elev->gisprompt = "new,cell,raster";
  147. parm.elev->description = _("Name for output elevation raster map");
  148. parm.elev->guisection = _("Output");
  149. parm.slope = G_define_standard_option(G_OPT_R_OUTPUT);
  150. parm.slope->key = "slope";
  151. parm.slope->required = NO;
  152. parm.slope->description = _("Name for output slope map (or fx)");
  153. parm.slope->guisection = _("Output");
  154. parm.aspect = G_define_standard_option(G_OPT_R_OUTPUT);
  155. parm.aspect->key = "aspect";
  156. parm.aspect->required = NO;
  157. parm.aspect->description = _("Name for output aspect map (or fy)");
  158. parm.aspect->guisection = _("Output");
  159. parm.pcurv = G_define_standard_option(G_OPT_R_OUTPUT);
  160. parm.pcurv->key = "pcurvature";
  161. parm.pcurv->required = NO;
  162. parm.pcurv->description = _("Name for output profile curvature map (or fxx)");
  163. parm.pcurv->guisection = _("Output");
  164. parm.tcurv = G_define_standard_option(G_OPT_R_OUTPUT);
  165. parm.tcurv->key = "tcurvature";
  166. parm.tcurv->required = NO;
  167. parm.tcurv->description = _("Name for output tangential curvature map (or fyy)");
  168. parm.tcurv->guisection = _("Output");
  169. parm.mcurv = G_define_standard_option(G_OPT_R_OUTPUT);
  170. parm.mcurv->key = "mcurvature";
  171. parm.mcurv->required = NO;
  172. parm.mcurv->description = _("Name for output mean curvature map (or fxy)");
  173. parm.mcurv->guisection = _("Output");
  174. parm.smooth = G_define_standard_option(G_OPT_R_INPUT);
  175. parm.smooth->key = "smooth";
  176. parm.smooth->required = NO;
  177. parm.smooth->description = _("Name of input raster map containing smoothing");
  178. parm.smooth->guisection = _("Settings");
  179. parm.maskmap = G_define_standard_option(G_OPT_R_INPUT);
  180. parm.maskmap->key = "maskmap";
  181. parm.maskmap->required = NO;
  182. parm.maskmap->description = _("Name of input raster map to be used as mask");
  183. parm.maskmap->guisection = _("Settings");
  184. parm.overlap = G_define_option();
  185. parm.overlap->key = "overlap";
  186. parm.overlap->type = TYPE_INTEGER;
  187. parm.overlap->required = NO;
  188. parm.overlap->answer = OVERLAP;
  189. parm.overlap->description = _("Rows/columns overlap for segmentation");
  190. parm.overlap->guisection = _("Settings");
  191. parm.zmult = G_define_option();
  192. parm.zmult->key = "zscale";
  193. parm.zmult->type = TYPE_DOUBLE;
  194. parm.zmult->answer = ZMULT;
  195. parm.zmult->required = NO;
  196. parm.zmult->description = _("Multiplier for z-values");
  197. parm.zmult->guisection = _("Settings");
  198. parm.fi = G_define_option();
  199. parm.fi->key = "tension";
  200. parm.fi->type = TYPE_DOUBLE;
  201. parm.fi->answer = TENSION;
  202. parm.fi->required = NO;
  203. parm.fi->description = _("Spline tension value");
  204. parm.fi->guisection = _("Settings");
  205. parm.theta = G_define_option();
  206. parm.theta->key = "theta";
  207. parm.theta->type = TYPE_DOUBLE;
  208. parm.theta->required = NO;
  209. parm.theta->description = _("Anisotropy angle (in degrees counterclockwise from East)");
  210. parm.theta->guisection = _("Anisotropy");
  211. parm.scalex = G_define_option();
  212. parm.scalex->key = "scalex";
  213. parm.scalex->type = TYPE_DOUBLE;
  214. parm.scalex->required = NO;
  215. parm.scalex->description = _("Anisotropy scaling factor");
  216. parm.scalex->guisection = _("Anisotropy");
  217. flag.cprght = G_define_flag();
  218. flag.cprght->key = 't';
  219. flag.cprght->description = _("Use dnorm independent tension");
  220. flag.deriv = G_define_flag();
  221. flag.deriv->key = 'd';
  222. flag.deriv->description =
  223. _("Output partial derivatives instead of topographic parameters");
  224. flag.deriv->guisection = _("Output");
  225. if (G_parser(argc, argv))
  226. exit(EXIT_FAILURE);
  227. G_get_set_window(&winhd);
  228. inp_ew_res = winhd.ew_res;
  229. inp_ns_res = winhd.ns_res;
  230. inp_cols = winhd.cols;
  231. inp_rows = winhd.rows;
  232. inp_x_orig = winhd.west;
  233. inp_y_orig = winhd.south;
  234. input = parm.input->answer;
  235. smooth = parm.smooth->answer;
  236. maskmap = parm.maskmap->answer;
  237. elev = parm.elev->answer;
  238. slope = parm.slope->answer;
  239. aspect = parm.aspect->answer;
  240. pcurv = parm.pcurv->answer;
  241. tcurv = parm.tcurv->answer;
  242. mcurv = parm.mcurv->answer;
  243. cond2 = ((pcurv != NULL) || (tcurv != NULL) || (mcurv != NULL));
  244. cond1 = ((slope != NULL) || (aspect != NULL) || cond2);
  245. deriv = flag.deriv->answer;
  246. dtens = flag.cprght->answer;
  247. ertre = 0.1;
  248. if (!G_scan_resolution(parm.res_ew->answer, &ew_res, winhd.proj))
  249. G_fatal_error(_("Unable to read ew_res value"));
  250. if (!G_scan_resolution(parm.res_ns->answer, &ns_res, winhd.proj))
  251. G_fatal_error(_("Unable to read ns_res value"));
  252. if (sscanf(parm.fi->answer, "%lf", &fi) != 1)
  253. G_fatal_error(_("Invalid value for tension"));
  254. if (sscanf(parm.zmult->answer, "%lf", &zmult) != 1)
  255. G_fatal_error(_("Invalid value for zmult"));
  256. if (sscanf(parm.overlap->answer, "%d", &overlap) != 1)
  257. G_fatal_error(_("Invalid value for overlap"));
  258. if (parm.theta->answer) {
  259. if (sscanf(parm.theta->answer, "%lf", &theta) != 1)
  260. G_fatal_error(_("Invalid value for theta"));
  261. }
  262. if (parm.scalex->answer) {
  263. if (sscanf(parm.scalex->answer, "%lf", &scalex) != 1)
  264. G_fatal_error(_("Invalid value for scalex"));
  265. if (!parm.theta->answer)
  266. G_fatal_error(_("When using anisotropy both theta and scalex must be specified"));
  267. }
  268. /*
  269. * G_set_embedded_null_value_mode(1);
  270. */
  271. outhd.ew_res = ew_res;
  272. outhd.ns_res = ns_res;
  273. outhd.east = winhd.east;
  274. outhd.west = winhd.west;
  275. outhd.north = winhd.north;
  276. outhd.south = winhd.south;
  277. outhd.proj = winhd.proj;
  278. outhd.zone = winhd.zone;
  279. G_adjust_Cell_head(&outhd, 0, 0);
  280. ew_res = outhd.ew_res;
  281. ns_res = outhd.ns_res;
  282. nsizc = outhd.cols;
  283. nsizr = outhd.rows;
  284. disk = (off_t)nsizc * nsizr * sizeof(int);
  285. az = G_alloc_vector(nsizc + 1);
  286. if (cond1) {
  287. adx = G_alloc_vector(nsizc + 1);
  288. ady = G_alloc_vector(nsizc + 1);
  289. if (cond2) {
  290. adxx = G_alloc_vector(nsizc + 1);
  291. adyy = G_alloc_vector(nsizc + 1);
  292. adxy = G_alloc_vector(nsizc + 1);
  293. }
  294. }
  295. if (smooth != NULL) {
  296. Rast_get_cellhd(smooth, "", &smhd);
  297. if ((winhd.ew_res != smhd.ew_res) || (winhd.ns_res != smhd.ns_res))
  298. G_fatal_error(_("Map <%s> is the wrong resolution"), smooth);
  299. if (Rast_read_fp_range(smooth, "", &range) >= 0)
  300. Rast_get_fp_range_min_max(&range, &cellmin, &cellmax);
  301. fcellmin = (float)cellmin;
  302. if (Rast_is_f_null_value(&fcellmin) || fcellmin < 0.0)
  303. G_fatal_error(_("Smoothing values can not be negative or NULL"));
  304. }
  305. Rast_get_cellhd(input, "", &inphd);
  306. if ((winhd.ew_res != inphd.ew_res) || (winhd.ns_res != inphd.ns_res))
  307. G_fatal_error(_("Input map resolution differs from current region resolution!"));
  308. sdisk = 0;
  309. if (elev != NULL)
  310. sdisk += disk;
  311. if (slope != NULL)
  312. sdisk += disk;
  313. if (aspect != NULL)
  314. sdisk += disk;
  315. if (pcurv != NULL)
  316. sdisk += disk;
  317. if (tcurv != NULL)
  318. sdisk += disk;
  319. if (mcurv != NULL)
  320. sdisk += disk;
  321. G_message(_("Processing all selected output files will require"));
  322. if (sdisk > 1024) {
  323. if (sdisk > 1024 * 1024) {
  324. if (sdisk > 1024 * 1024 * 1024) {
  325. G_message(_("%.2f GB of disk space for temp files."), sdisk / (1024. * 1024. * 1024.));
  326. }
  327. else
  328. G_message(_("%.2f MB of disk space for temp files."), sdisk / (1024. * 1024.));
  329. }
  330. else
  331. G_message(_("%.2f KB of disk space for temp files."), sdisk / 1024.);
  332. }
  333. else
  334. G_message(n_("%d byte of disk space for temp files.",
  335. "%d bytes of disk space for temp files.", (int)sdisk), (int)sdisk);
  336. fstar2 = fi * fi / 4.;
  337. tfsta2 = fstar2 + fstar2;
  338. deltx = winhd.east - winhd.west;
  339. delty = winhd.north - winhd.south;
  340. xmin = winhd.west;
  341. xmax = winhd.east;
  342. ymin = winhd.south;
  343. ymax = winhd.north;
  344. if (smooth != NULL)
  345. smc = -9999;
  346. else
  347. smc = 0.01;
  348. if (Rast_read_fp_range(input, "", &range) >= 0) {
  349. Rast_get_fp_range_min_max(&range, &cellmin, &cellmax);
  350. }
  351. else {
  352. fdinp = Rast_open_old(input, "");
  353. cellrow = Rast_allocate_f_buf();
  354. for (m1 = 0; m1 < inp_rows; m1++) {
  355. Rast_get_f_row(fdinp, cellrow, m1);
  356. Rast_row_update_fp_range(cellrow, m1, &range, FCELL_TYPE);
  357. }
  358. Rast_get_fp_range_min_max(&range, &cellmin, &cellmax);
  359. Rast_close(fdinp);
  360. }
  361. fcellmin = (float)cellmin;
  362. if (Rast_is_f_null_value(&fcellmin))
  363. G_fatal_error(_("Maximum value of a raster map is NULL."));
  364. zmin = (double)cellmin *zmult;
  365. zmax = (double)cellmax *zmult;
  366. G_debug(1, "zmin=%f, zmax=%f", zmin, zmax);
  367. if (fd4 != NULL)
  368. fprintf(fd4, "deltx,delty %f %f \n", deltx, delty);
  369. create_temp_files();
  370. IL_init_params_2d(&params, NULL, 1, 1, zmult, KMIN, KMAX, maskmap,
  371. outhd.rows, outhd.cols, az, adx, ady, adxx, adyy, adxy,
  372. fi, MAXPOINTS, SCIK1, SCIK2, SCIK3, smc, elev, slope,
  373. aspect, pcurv, tcurv, mcurv, dmin, inp_x_orig,
  374. inp_y_orig, deriv, theta, scalex, Tmp_fd_z, Tmp_fd_dx,
  375. Tmp_fd_dy, Tmp_fd_xx, Tmp_fd_yy, Tmp_fd_xy, NULL, NULL,
  376. 0, NULL);
  377. /* In the above line, the penultimate argument is supposed to be a
  378. * deviations file pointer. None is obvious, so I used NULL. */
  379. /* The 3rd and 4th argument are int-s, elatt and smatt (from the function
  380. * definition. The value 1 seemed like a good placeholder... or not. */
  381. IL_init_func_2d(&params, IL_grid_calc_2d, IL_matrix_create,
  382. IL_check_at_points_2d,
  383. IL_secpar_loop_2d, IL_crst, IL_crstg, IL_write_temp_2d);
  384. G_message(_("Temporarily changing the region to desired resolution ..."));
  385. Rast_set_window(&outhd);
  386. bitmask = IL_create_bitmask(&params);
  387. /* change region to initial region */
  388. G_message(_("Changing back to the original region ..."));
  389. Rast_set_window(&winhd);
  390. fdinp = Rast_open_old(input, "");
  391. if (smooth != NULL)
  392. fdsmooth = Rast_open_old(smooth, "");
  393. ertot = 0.;
  394. cursegm = 0;
  395. G_message(_("Percent complete: "));
  396. NPOINT =
  397. IL_resample_interp_segments_2d(&params, bitmask, zmin, zmax, &zminac,
  398. &zmaxac, &gmin, &gmax, &c1min, &c1max,
  399. &c2min, &c2max, &ertot, nsizc, &dnorm,
  400. overlap, inp_rows, inp_cols, fdsmooth,
  401. fdinp, ns_res, ew_res, inp_ns_res,
  402. inp_ew_res, dtens);
  403. G_message(_("dnorm in mainc after grid before out1= %f"), dnorm);
  404. if (NPOINT < 0) {
  405. clean();
  406. G_fatal_error(_("split_and_interpolate() failed"));
  407. }
  408. if (fd4 != NULL)
  409. fprintf(fd4, "max. error found = %f \n", ertot);
  410. G_free_vector(az);
  411. if (cond1) {
  412. G_free_vector(adx);
  413. G_free_vector(ady);
  414. if (cond2) {
  415. G_free_vector(adxx);
  416. G_free_vector(adyy);
  417. G_free_vector(adxy);
  418. }
  419. }
  420. G_message(_("dnorm in mainc after grid before out2= %f"), dnorm);
  421. if (IL_resample_output_2d(&params, zmin, zmax, zminac, zmaxac, c1min,
  422. c1max, c2min, c2max, gmin, gmax, ertot, input,
  423. &dnorm, &outhd, &winhd, smooth, NPOINT) < 0) {
  424. clean();
  425. G_fatal_error(_("Unable to write raster maps -- try increasing cell size"));
  426. }
  427. G_free(zero_array_cell);
  428. clean();
  429. if (fd4)
  430. fclose(fd4);
  431. Rast_close(fdinp);
  432. if (smooth != NULL)
  433. Rast_close(fdsmooth);
  434. G_done_msg(" ");
  435. exit(EXIT_SUCCESS);
  436. }
  437. static FILE *create_temp_file(const char *name, char **tmpname)
  438. {
  439. FILE *fp;
  440. char *tmp;
  441. int i;
  442. if (!name)
  443. return NULL;
  444. *tmpname = tmp = G_tempfile();
  445. fp = fopen(tmp, "w+");
  446. if (!fp)
  447. G_fatal_error(_("Unable to open temporary file <%s>"), *tmpname);
  448. for (i = 0; i < nsizr; i++) {
  449. if (fwrite(zero_array_cell, sizeof(FCELL), nsizc, fp) != nsizc) {
  450. clean();
  451. G_fatal_error(_("Error writing temporary file <%s>"), *tmpname);
  452. }
  453. }
  454. return fp;
  455. }
  456. static void create_temp_files(void)
  457. {
  458. zero_array_cell = (FCELL *) G_calloc(nsizc, sizeof(FCELL));
  459. Tmp_fd_z = create_temp_file(elev, &Tmp_file_z );
  460. Tmp_fd_dx = create_temp_file(slope, &Tmp_file_dx);
  461. Tmp_fd_dy = create_temp_file(aspect, &Tmp_file_dy);
  462. Tmp_fd_xx = create_temp_file(pcurv, &Tmp_file_xx);
  463. Tmp_fd_yy = create_temp_file(tcurv, &Tmp_file_yy);
  464. Tmp_fd_xy = create_temp_file(mcurv, &Tmp_file_xy);
  465. }
  466. static void clean(void)
  467. {
  468. if (Tmp_fd_z) fclose(Tmp_fd_z);
  469. if (Tmp_fd_dx) fclose(Tmp_fd_dx);
  470. if (Tmp_fd_dy) fclose(Tmp_fd_dy);
  471. if (Tmp_fd_xx) fclose(Tmp_fd_xx);
  472. if (Tmp_fd_yy) fclose(Tmp_fd_yy);
  473. if (Tmp_fd_xy) fclose(Tmp_fd_xy);
  474. if (Tmp_file_z) unlink(Tmp_file_z);
  475. if (Tmp_file_dx) unlink(Tmp_file_dx);
  476. if (Tmp_file_dy) unlink(Tmp_file_dy);
  477. if (Tmp_file_xx) unlink(Tmp_file_xx);
  478. if (Tmp_file_yy) unlink(Tmp_file_yy);
  479. if (Tmp_file_xy) unlink(Tmp_file_xy);
  480. }