Loading...
Searching...
No Matches
gv_quick.c
Go to the documentation of this file.
/*!
\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 <landa.martin gmail.com> (May 2008)
*/
#include <stdio.h>
#include <stdlib.h>
#include <grass/gis.h>
#include <grass/ogsf.h>
#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);
}
NULL
#define NULL
Definition ccmath.h:32
G_debug
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
GS_distance
float GS_distance(float *from, float *to)
Calculate distance.
Definition gs_util.c:141
GS_P2distance
float GS_P2distance(float *from, float *to)
Calculate distance in plane.
Definition gs_util.c:160
TFAST_PTS
#define TFAST_PTS
target number of desired points to represent entire file
Definition gv_quick.c:33
MFAST_LNS
#define MFAST_LNS
max number of lines desired
Definition gv_quick.c:38
gv_line_length
float gv_line_length(geoline *gln)
Get line width.
Definition gv_quick.c:173
gln_num_points
int gln_num_points(geoline *gln)
Get number of line vertices.
Definition gv_quick.c:197
gv_num_points
int gv_num_points(geovect *gv)
Get number of points in vector.
Definition gv_quick.c:216
gv_decimate_lines
int gv_decimate_lines(geovect *gv)
Decimate line.
Definition gv_quick.c:231
rowcol.h
X
#define X(j)
Y
#define Y(j)