/*! \file lib/ogsf/gv_quick.c \brief OGSF library - GRASS OpenGL gsurf OGSF Library Trying some stuff to draw a quick version of a vector map, to represent it when doing interactive translations. (C) 1999-2008 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. \author Bill Brown, USACERL (December 1993) \author Doxygenized by Martin Landa (May 2008) */ #include #include #include #include #include "rowcol.h" /*! \brief target number of desired points to represent entire file */ #define TFAST_PTS 800 /*! \brief max number of lines desired */ #define MFAST_LNS 400 static geoline *copy_line(geoline *); static geoline *thin_line(geoline *, float); /*! \brief Copy line \param gln source line (geoline) \return pointer to geoline struct \return on failure */ static geoline *copy_line(geoline * gln) { geoline *newln; int i, np; newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */ if (!newln) { return (NULL); } np = newln->npts = gln->npts; if (2 == (newln->dims = gln->dims)) { newln->p2 = (Point2 *) G_calloc(np, sizeof(Point2)); /* G_fatal_error */ if (!newln->p2) { return (NULL); } for (i = 0; i < np; i++) { newln->p2[i][X] = gln->p2[i][X]; newln->p2[i][Y] = gln->p2[i][Y]; } } else { newln->p3 = (Point3 *) G_calloc(np, sizeof(Point3)); /* G_fatal_error */ if (!newln->p3) { return (NULL); } for (i = 0; i < np; i++) { newln->p3[i][X] = gln->p3[i][X]; newln->p3[i][Y] = gln->p3[i][Y]; newln->p3[i][Z] = gln->p3[i][Z]; } } newln->next = NULL; return (newln); } /*! \brief Thin line For now, just eliminate points at regular interval \param gln line (geoline) \param factor \return pointer to geoline struct \return NULL on failure */ static geoline *thin_line(geoline * gln, float factor) { geoline *newln; int i, nextp, targp; newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */ if (!newln) { return (NULL); } targp = (int)(gln->npts / factor); if (targp < 2) { targp = 2; } newln->npts = targp; if (2 == (newln->dims = gln->dims)) { newln->p2 = (Point2 *) G_calloc(targp, sizeof(Point2)); /* G_fatal_error */ if (!newln->p2) { return (NULL); } for (i = 0; i < targp; i++) { if (i == targp - 1) { nextp = gln->npts - 1; /* avoid rounding error */ } else { nextp = (int)((i * (gln->npts - 1)) / (targp - 1)); } newln->p2[i][X] = gln->p2[nextp][X]; newln->p2[i][Y] = gln->p2[nextp][Y]; } } else { newln->p3 = (Point3 *) G_calloc(targp, sizeof(Point3)); /* G_fatal_error */ if (!newln->p3) { return (NULL); } for (i = 0; i < targp; i++) { if (i == targp - 1) { nextp = gln->npts - 1; /* avoid rounding error */ } else { nextp = (int)((i * (gln->npts - 1)) / (targp - 1)); } newln->p3[i][X] = gln->p3[nextp][X]; newln->p3[i][Y] = gln->p3[nextp][Y]; newln->p3[i][Z] = gln->p3[nextp][Z]; } } newln->next = NULL; return (newln); } /*! \brief Get line width \param gln line (geoline) \return line width */ float gv_line_length(geoline * gln) { int n; float length = 0.0; for (n = 0; n < gln->npts - 1; n++) { if (gln->p2) { length += GS_P2distance(gln->p2[n + 1], gln->p2[n]); } else { length += GS_distance(gln->p3[n + 1], gln->p3[n]); } } return (length); } /*! \brief Get number of line vertices \param gln line (geoline) \return number of vertices */ int gln_num_points(geoline * gln) { int np = 0; geoline *tln; for (tln = gln; tln; tln = tln->next) { np += tln->npts; } return (np); } /*! \brief Get number of points in vector \param gv vector (geovect) \return number of points */ int gv_num_points(geovect * gv) { return (gln_num_points(gv->lines)); } /*! \brief Decimate line strategy here: if line has more than average number of points, decimate by eliminating points, otherwise decimate by eliminating shorter lines \param gv vector (geovect) \return */ int gv_decimate_lines(geovect * gv) { int T_pts, A_ppl, N_s; float decim_factor, slength[MFAST_LNS], T_slength, A_slength; geoline *gln, *prev; /* should check if already exists & free if != gv->lines */ if (TFAST_PTS > (T_pts = gv_num_points(gv))) { gv->fastlines = gv->lines; return (1); } N_s = 0; T_slength = 0.0; decim_factor = T_pts / TFAST_PTS; A_ppl = T_pts / gv->n_lines; /* (int) Average points per line */ prev = NULL; for (gln = gv->lines; gln; gln = gln->next) { if (gln->npts > A_ppl) { if (prev) { prev->next = thin_line(gln, decim_factor); prev = prev->next; } else { prev = gv->fastlines = thin_line(gln, decim_factor); } } else if (N_s < MFAST_LNS) { T_slength += slength[N_s++] = gv_line_length(gln); } } A_slength = T_slength / N_s; N_s = 0; for (gln = gv->lines; gln; gln = gln->next) { if (gln->npts <= A_ppl) { if (N_s < MFAST_LNS) { if (slength[N_s++] > A_slength) { if (prev) { prev->next = copy_line(gln); prev = prev->next; } else { prev = gv->fastlines = copy_line(gln); } } } } } G_debug(3, "Decimated lines have %d points.", gln_num_points(gv->fastlines)); return (1); }