/**************************************************************************** * * MODULE: r.out.vrml * AUTHOR(S): Bill Brown (CERL/UIUC GMSL Laboratory) (original contributor), * Hamish Bowman , * Jachym Cepicky , * Markus Neteler * PURPOSE: This module exports a GRASS raster map to the Virtual Reality * Modeling Language (VRML) format for 3D visualization. * COPYRIGHT: (C) 2006-2006 by the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS * for details. * *****************************************************************************/ #include #include #include #include #include #include "pv.h" struct Cell_head W; int main(int argc, char *argv[]) { struct Option *rast_el, *rast_co, *out; struct Option *exag_opt; int elevfd = 0, colorfd = 0; FILE *vout = NULL; struct Colors colr; char outfile[GPATH_MAX]; int shh, color_ok; double exag, min, max; struct GModule *module; G_gisinit(argv[0]); shh = color_ok = 0; module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("export")); G_add_keyword(_("VRML")); module->description = _("Exports a raster map to the Virtual Reality Modeling Language (VRML)."); rast_el = G_define_standard_option(G_OPT_R_ELEV); rast_co = G_define_standard_option(G_OPT_R_INPUT); rast_co->key = "color"; rast_co->required = NO; rast_co->description = _("Name of input color map"); exag_opt = G_define_option(); exag_opt->key = "exaggeration"; exag_opt->type = TYPE_DOUBLE; exag_opt->required = NO; exag_opt->answer = "1.0"; exag_opt->description = _("Vertical exaggeration"); out = G_define_standard_option(G_OPT_F_OUTPUT); out->required = YES; out->description = _("Name for output VRML file"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); G_get_set_window(&W); elevfd = Rast_open_old(rast_el->answer, ""); { CELL cmin, cmax; struct Range range; int is_fp; DCELL dmin, dmax; struct FPRange fp_range; is_fp = Rast_map_is_fp(rast_el->answer, ""); if (is_fp) { if (Rast_read_fp_range(rast_el->answer, "", &fp_range) != 1) { G_fatal_error(_("Range info for [%s] not available (run r.support)"), rast_el->answer); } Rast_get_fp_range_min_max(&fp_range, &dmin, &dmax); min = dmin; max = dmax; } else { if (Rast_read_range(rast_el->answer, "", &range) == -1) { G_fatal_error(_("Range info for <%s> not available (run r.support)"), rast_el->answer); } Rast_get_range_min_max(&range, &cmin, &cmax); min = cmin; max = cmax; } } if (rast_co->answer) { colorfd = Rast_open_old(rast_co->answer, ""); Rast_read_colors(rast_co->answer, "", &colr); color_ok = 1; } /* TODO: if file exists, just append new objects */ if (out->answer) { char *p; /* look for .wrl suffix, add if not found */ if (NULL == (p = strrchr(out->answer, '.'))) { /* no suffix */ strcpy(outfile, out->answer); strcat(outfile, ".wrl"); } else if (strncmp(p + 1, "wrl", 4)) { /* some other extension */ strcpy(outfile, out->answer); strcat(outfile, ".wrl"); } else strcpy(outfile, out->answer); /* open file for writing VRML */ G_message(_("Opening %s for writing... "), outfile); if (NULL == (vout = fopen(outfile, "w"))) { G_fatal_error(_("Unable to open output file <%s>"), outfile); } } exag = 1.0; if (exag_opt->answer) { sscanf(exag_opt->answer, "%lf", &exag); } init_coordcnv(exag, &W, min, max); vrml_begin(vout); /* vrml_put_view(vout, NULL); */ vrml_put_grid(vout, &W, elevfd, colorfd, &colr, color_ok, W.rows, W.cols, shh); vrml_end(vout); Rast_close(elevfd); if (color_ok) Rast_close(colorfd); return (EXIT_SUCCESS); } static double scaleXZ, scaleY; static double transX, transY, transZ; static double Xrange, Yrange, Zrange; /* REMEMBER - * Y is HEIGHT * Z is northing-W.south * X is adjusted easting-W.west */ /* * This could be entered as a vrml scale to preserve real * geographic coords, but I'm not sure how good the average * vrml viewer is at setting appropriate z-depths, so testing * first like this. */ /* TODO: * change scale & use G_distance for latlon to preserve meter units */ int init_coordcnv(double exag, struct Cell_head *w, double min, double max) { Yrange = (max - min) * exag; Zrange = (w->rows - 1) * w->ns_res; Xrange = (w->cols - 1) * w->ew_res; transX = -(Rast_col_to_easting(0.5, w)); transZ = -(Rast_row_to_northing(0.5, w)); transY = -min; if (Zrange >= Xrange && Zrange >= Yrange) { /* northing biggest */ scaleXZ = 1.0 / Zrange; scaleY = exag * scaleXZ; } else if (Xrange >= Zrange && Xrange >= Yrange) { /* easting biggest */ scaleXZ = 1.0 / Xrange; scaleY = exag * scaleXZ; } else /* depth biggest */ scaleY = scaleXZ = 1.0 / Yrange; return 0; } int do_coordcnv(double *dval, int axis) { double dret = 0.0; switch (axis) { case 'x': case 'X': dret = (*dval + transX) * scaleXZ; break; case 'z': case 'Z': dret = (Zrange - (*dval + transZ)) * scaleXZ; break; case 'y': case 'Y': dret = (*dval + transY) * scaleY; break; default: G_fatal_error("invalid axis: %c", axis); break; } *dval = dret; return 0; }