GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
plot.c
Go to the documentation of this file.
1 /*!
2  * \file lib/gis/plot.c
3  *
4  * \brief GIS Library - Plotting functions.
5  *
6  * Plot lines and filled polygons. Input space is current
7  * window. Output space and output functions are user
8  * defined. Converts input east,north lines and polygons to output x,y
9  * and calls user supplied line drawing routines to do the plotting.
10  *
11  * Handles global wrap-around for lat-lon locations.
12  *
13  * Does not perform window clipping.
14  * Clipping must be done by the line draw routines supplied by the user.
15  *
16  * Note:
17  * Hopefully, cartographic style projection plotting will be added later.
18  *
19  * (C) 2001-2008, 2013 by the GRASS Development Team
20  *
21  * This program is free software under the GNU General Public License
22  * (>=v2). Read the file COPYING that comes with GRASS for details.
23  *
24  * \author Original author CERL
25  */
26 
27 #include <stdlib.h>
28 #include <math.h>
29 #include <grass/gis.h>
30 
31 static void fastline(double, double, double, double);
32 static void slowline(double, double, double, double);
33 static void plot_line(double, double, double, double,
34  void (*)(double, double, double, double));
35 static double wrap_east(double, double);
36 static int edge(double, double, double, double);
37 static int edge_point(double, int);
38 
39 static int edge_order(const void *, const void *);
40 static void row_solid_fill(int, double, double);
41 static void row_dotted_fill(int, double, double);
42 static int ifloor(double);
43 static int iceil(double);
44 
45 struct point {
46  double x;
47  int y;
48 };
49 
50 #define POINT struct point
51 
52 static struct state {
53  struct Cell_head window;
54  double xconv, yconv;
55  double left, right, top, bottom;
56  int ymin, ymax;
57  int dotted_fill_gap;
58 
59  POINT *P;
60  int np;
61  int npalloc;
62 
63  void (*row_fill)(int, double, double);
64  int (*move)(int, int);
65  int (*cont)(int, int);
66 } state;
67 
68 static struct state *st = &state;
69 
70 #define OK 0
71 #define TOO_FEW_EDGES 2
72 #define NO_MEMORY 1
73 #define OUT_OF_SYNC -1
74 
75 /*!
76  * \brief Initialize plotting routines
77  *
78  * Initializes the plotting capability. This routine must be called
79  * once before calling the G_plot_*() routines described below. The
80  * parameters <i>t, b, l, r</i> are the top, bottom, left, and right
81  * of the output x,y coordinate space. They are not integers, but
82  * doubles to allow for subpixel registration of the input and output
83  * coordinate spaces. The input coordinate space is assumed to be the
84  * current GRASS region, and the routines supports both planimetric
85  * and latitude-longitude coordinate systems.
86 
87  * <b>Move</b> and <b>Cont</b> are subroutines that will draw lines in x,y
88  * space. They will be called as follows:
89  * - Move(x, y) move to x,y (no draw)
90  * - Cont(x, y) draw from previous position to x,y. Cont(~) is responsible for
91  clipping
92  *
93  * \param t,b,l,r top, bottom, left, right
94  * \param move Move function
95  * \param Cont Cont function
96  */
97 void G_setup_plot(double t, double b, double l, double r, int (*Move)(int, int),
98  int (*Cont)(int, int))
99 {
100  G_get_set_window(&st->window);
101 
102  st->left = l;
103  st->right = r;
104  st->top = t;
105  st->bottom = b;
106 
107  st->xconv = (st->right - st->left) / (st->window.east - st->window.west);
108  st->yconv = (st->bottom - st->top) / (st->window.north - st->window.south);
109 
110  if (st->top < st->bottom) {
111  st->ymin = iceil(st->top);
112  st->ymax = ifloor(st->bottom);
113  }
114  else {
115  st->ymin = iceil(st->bottom);
116  st->ymax = ifloor(st->top);
117  }
118 
119  st->move = Move;
120  st->cont = Cont;
121 }
122 
123 /*!
124  * \brief Set row_fill routine to row_solid_fill or row_dotted_fill
125  *
126  * After calling this function, G_plot_polygon() and G_plot_area()
127  * fill shapes with solid or dotted lines. If gap is greater than
128  * zero, this value will be used for row_dotted_fill. Otherwise,
129  * row_solid_fill is used.
130  *
131  * \param gap
132  */
133 void G_setup_fill(int gap)
134 {
135  if (gap > 0) {
136  st->row_fill = row_dotted_fill;
137  st->dotted_fill_gap = gap + 1;
138  }
139  else
140  st->row_fill = row_solid_fill;
141 }
142 
143 #define X(e) (st->left + st->xconv * ((e) - st->window.west))
144 #define Y(n) (st->top + st->yconv * (st->window.north - (n)))
145 
146 #define EAST(x) (st->window.west + ((x) - st->left) / st->xconv)
147 #define NORTH(y) (st->window.north - ((y) - st->top) / st->yconv)
148 
149 /*!
150  * \brief Converts east,north to x,y
151  *
152  * The map coordinates <i>east,north</i> are converted
153  * to pixel coordinates <i>x,y</i>.
154  *
155  * \param east easting
156  * \param north nothing
157  * \param x x coordinate
158  * \param y y coordinate
159  */
160 void G_plot_where_xy(double east, double north, int *x, int *y)
161 {
162  *x = ifloor(X(G_adjust_easting(east, &st->window)) + 0.5);
163  *y = ifloor(Y(north) + 0.5);
164 }
165 
166 /*!
167  * \brief Converts x,y to east,north
168  *
169  * The pixel coordinates <i>x,y</i> are converted to map
170  * coordinates <i>east,north</i>.
171  *
172  * \param x x coordinate
173  * \param y y coordinate
174  * \param east easting
175  * \param north northing
176  */
177 void G_plot_where_en(int x, int y, double *east, double *north)
178 {
179  *east = G_adjust_easting(EAST(x), &st->window);
180  *north = NORTH(y);
181 }
182 
183 /*!
184  \brief Plot point
185 
186  \param east easting
187  \param north northing
188  */
189 void G_plot_point(double east, double north)
190 {
191  int x, y;
192 
193  G_plot_where_xy(east, north, &x, &y);
194  st->move(x, y);
195  st->cont(x, y);
196 }
197 
198 /*!
199  * \brief Plot line between latlon coordinates (fastline)
200  *
201  * A line from <i>east1,north1</i> to <i>east2,north2</i> is plotted
202  * in output x,y coordinates (e.g. pixels for graphics.) This routine
203  * handles global wrap-around for latitude-longitude databases.
204  *
205  * \param east1, north1 first point (start line node)
206  * \param east2, north2 second point (end line node)
207  */
208 void G_plot_line(double east1, double north1, double east2, double north2)
209 {
210  plot_line(east1, north1, east2, north2, fastline);
211 }
212 
213 /*!
214  * \brief Plot line between latlon coordinates (slowline)
215  *
216  * A line from <i>east1,north1</i> to <i>east2,north2</i> is plotted
217  * in output x,y coordinates (e.g. pixels for graphics.) This routine
218  * handles global wrap-around for latitude-longitude databases.
219  *
220  * \param east1, north1 first point (start line node)
221  * \param east2, north2 second point (end line node)
222  */
223 void G_plot_line2(double east1, double north1, double east2, double north2)
224 {
225  plot_line(east1, north1, east2, north2, slowline);
226 }
227 
228 /* fastline converts double rows/cols to ints then plots
229  * this is ok for graphics, but not the best for vector to raster
230  */
231 static void fastline(double x1, double y1, double x2, double y2)
232 {
233  st->move(ifloor(x1 + 0.5), ifloor(y1 + 0.5));
234  st->cont(ifloor(x2 + 0.5), ifloor(y2 + 0.5));
235 }
236 
237 /* NOTE (shapiro):
238  * I think the adding of 0.5 in slowline is not correct
239  * the output window (left, right, top, bottom) should already
240  * be adjusted for this: left=-0.5; right = window.cols-0.5;
241  */
242 static void slowline(double x1, double y1, double x2, double y2)
243 {
244  double dx, dy;
245  double m, b;
246  int xstart, xstop, ystart, ystop;
247 
248  dx = x2 - x1;
249  dy = y2 - y1;
250 
251  if (fabs(dx) > fabs(dy)) {
252  m = dy / dx;
253  b = y1 - m * x1;
254 
255  if (x1 > x2) {
256  xstart = iceil(x2 - 0.5);
257  xstop = ifloor(x1 + 0.5);
258  }
259  else {
260  xstart = iceil(x1 - 0.5);
261  xstop = ifloor(x2 + 0.5);
262  }
263  if (xstart <= xstop) {
264  ystart = ifloor(m * xstart + b + 0.5);
265  st->move(xstart, ystart);
266  while (xstart <= xstop) {
267  st->cont(xstart++, ystart);
268  ystart = ifloor(m * xstart + b + 0.5);
269  }
270  }
271  }
272  else {
273  if (dx == dy) /* they both might be 0 */
274  m = 1.;
275  else
276  m = dx / dy;
277  b = x1 - m * y1;
278 
279  if (y1 > y2) {
280  ystart = iceil(y2 - 0.5);
281  ystop = ifloor(y1 + 0.5);
282  }
283  else {
284  ystart = iceil(y1 - 0.5);
285  ystop = ifloor(y2 + 0.5);
286  }
287  if (ystart <= ystop) {
288  xstart = ifloor(m * ystart + b + 0.5);
289  st->move(xstart, ystart);
290  while (ystart <= ystop) {
291  st->cont(xstart, ystart++);
292  xstart = ifloor(m * ystart + b + 0.5);
293  }
294  }
295  }
296 }
297 
298 static void plot_line(double east1, double north1, double east2, double north2,
299  void (*line)(double, double, double, double))
300 {
301  double x1, x2, y1, y2;
302 
303  y1 = Y(north1);
304  y2 = Y(north2);
305 
306  if (st->window.proj == PROJECTION_LL) {
307  if (east1 > east2)
308  while ((east1 - east2) > 180)
309  east2 += 360;
310  else if (east2 > east1)
311  while ((east2 - east1) > 180)
312  east1 += 360;
313  while (east1 > st->window.east) {
314  east1 -= 360.0;
315  east2 -= 360.0;
316  }
317  while (east1 < st->window.west) {
318  east1 += 360.0;
319  east2 += 360.0;
320  }
321  x1 = X(east1);
322  x2 = X(east2);
323 
324  line(x1, y1, x2, y2);
325 
326  if (east2 > st->window.east || east2 < st->window.west) {
327  while (east2 > st->window.east) {
328  east1 -= 360.0;
329  east2 -= 360.0;
330  }
331  while (east2 < st->window.west) {
332  east1 += 360.0;
333  east2 += 360.0;
334  }
335  x1 = X(east1);
336  x2 = X(east2);
337  line(x1, y1, x2, y2);
338  }
339  }
340  else {
341  x1 = X(east1);
342  x2 = X(east2);
343  line(x1, y1, x2, y2);
344  }
345 }
346 
347 static double wrap_east(double e0, double e1)
348 {
349  while (e0 - e1 > 180)
350  e1 += 360.0;
351  while (e1 - e0 > 180)
352  e1 -= 360.0;
353 
354  return e1;
355 }
356 
357 /*!
358  * \brief Plot filled polygon with n vertices
359  *
360  * The polygon, described by the <i>n</i> vertices
361  * <i>east,north</i>, is plotted in the output x,y space as a filled polygon.
362  *
363  * \param x coordinates of vertices
364  * \param y coordinates of vertices
365  * \param n number of vertices
366  *
367  * \return 0 on success
368  * \return 2 n < 3
369  * \return -1 weird internal error
370  * \return 1 no memory
371  */
372 int G_plot_polygon(const double *x, const double *y, int n)
373 {
374  int i;
375  int pole;
376  double x0, x1;
377  double y0, y1;
378  double shift, E, W = 0L;
379  double e0, e1;
380  int shift1, shift2;
381 
382  if (!st->row_fill)
383  st->row_fill = row_solid_fill;
384 
385  if (n < 3)
386  return TOO_FEW_EDGES;
387 
388  /* traverse the perimeter */
389 
390  st->np = 0;
391  shift1 = 0;
392 
393  /* global wrap-around for lat-lon, part1 */
394  if (st->window.proj == PROJECTION_LL) {
395  /*
396  pole = G_pole_in_polygon(x,y,n);
397  */
398  pole = 0;
399 
400  e0 = x[n - 1];
401  E = W = e0;
402 
403  x0 = X(e0);
404  y0 = Y(y[n - 1]);
405 
406  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
407  return NO_MEMORY;
408 
409  for (i = 0; i < n; i++) {
410  e1 = wrap_east(e0, x[i]);
411  if (e1 > E)
412  E = e1;
413  if (e1 < W)
414  W = e1;
415 
416  x1 = X(e1);
417  y1 = Y(y[i]);
418 
419  if (!edge(x0, y0, x1, y1))
420  return NO_MEMORY;
421 
422  x0 = x1;
423  y0 = y1;
424  e0 = e1;
425  }
426  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
427  return NO_MEMORY;
428 
429  shift = 0; /* shift into window */
430  while (E + shift > st->window.east)
431  shift -= 360.0;
432  while (E + shift < st->window.west)
433  shift += 360.0;
434  shift1 = X(x[n - 1] + shift) - X(x[n - 1]);
435  }
436  else {
437  x0 = X(x[n - 1]);
438  y0 = Y(y[n - 1]);
439 
440  for (i = 0; i < n; i++) {
441  x1 = X(x[i]);
442  y1 = Y(y[i]);
443  if (!edge(x0, y0, x1, y1))
444  return NO_MEMORY;
445  x0 = x1;
446  y0 = y1;
447  }
448  }
449 
450  /* check if perimeter has odd number of points */
451  if (st->np & 1) {
452  G_warning("Weird internal error: perimeter has odd number of points");
453  return OUT_OF_SYNC;
454  }
455 
456  /* sort the edge points by col(x) and then by row(y) */
457  qsort(st->P, st->np, sizeof(POINT), edge_order);
458 
459  /* plot */
460  for (i = 1; i < st->np; i += 2) {
461  if (st->P[i].y != st->P[i - 1].y) {
462  G_warning("Weird internal error: edge leaves row");
463  return OUT_OF_SYNC;
464  }
465  st->row_fill(st->P[i].y, st->P[i - 1].x + shift1, st->P[i].x + shift1);
466  }
467  if (st->window.proj == PROJECTION_LL) { /* now do wrap-around, part 2 */
468  shift = 0;
469  while (W + shift < st->window.west)
470  shift += 360.0;
471  while (W + shift > st->window.east)
472  shift -= 360.0;
473  shift2 = X(x[n - 1] + shift) - X(x[n - 1]);
474  if (shift2 != shift1) {
475  for (i = 1; i < st->np; i += 2) {
476  st->row_fill(st->P[i].y, st->P[i - 1].x + shift2,
477  st->P[i].x + shift2);
478  }
479  }
480  }
481  return OK;
482 }
483 
484 /*!
485  * \brief Plot multiple polygons
486  *
487  * Like G_plot_polygon(), except it takes a set of polygons, each with
488  * npts[<i>i</i>] vertices, where the number of polygons is specified
489  * with the <i>rings</i> argument. It is especially useful for
490  * plotting vector areas with interior islands.
491  *
492  * \param xs pointer to pointer for X's
493  * \param ys pointer to pointer for Y's
494  * \param rpnts array of ints w/ num points per ring
495  * \param rings number of rings
496  *
497  * \return 0 on success
498  * \return 2 n < 3
499  * \return -1 weird internal error
500  * \return 1 no memory
501  */
502 int G_plot_area(double *const *xs, double *const *ys, int *rpnts, int rings)
503 {
504  int i, j, n;
505  int pole;
506  double x0, x1, *x;
507  double y0, y1, *y;
508  double shift, E, W = 0L;
509  double e0, e1;
510  int *shift1 = NULL, shift2;
511 
512  if (!st->row_fill)
513  st->row_fill = row_solid_fill;
514 
515  /* traverse the perimeter */
516 
517  st->np = 0;
518  shift1 = (int *)G_calloc(sizeof(int), rings);
519 
520  for (j = 0; j < rings; j++) {
521  n = rpnts[j];
522 
523  if (n < 3)
524  return TOO_FEW_EDGES;
525 
526  x = xs[j];
527  y = ys[j];
528 
529  /* global wrap-around for lat-lon, part1 */
530  if (st->window.proj == PROJECTION_LL) {
531  /*
532  pole = G_pole_in_polygon(x,y,n);
533  */
534  pole = 0;
535 
536  e0 = x[n - 1];
537  E = W = e0;
538 
539  x0 = X(e0);
540  y0 = Y(y[n - 1]);
541 
542  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
543  return NO_MEMORY;
544 
545  for (i = 0; i < n; i++) {
546  e1 = wrap_east(e0, x[i]);
547  if (e1 > E)
548  E = e1;
549  if (e1 < W)
550  W = e1;
551 
552  x1 = X(e1);
553  y1 = Y(y[i]);
554 
555  if (!edge(x0, y0, x1, y1))
556  return NO_MEMORY;
557 
558  x0 = x1;
559  y0 = y1;
560  e0 = e1;
561  }
562  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
563  return NO_MEMORY;
564 
565  shift = 0; /* shift into window */
566  while (E + shift > st->window.east)
567  shift -= 360.0;
568  while (E + shift < st->window.west)
569  shift += 360.0;
570  shift1[j] = X(x[n - 1] + shift) - X(x[n - 1]);
571  }
572  else {
573  x0 = X(x[n - 1]);
574  y0 = Y(y[n - 1]);
575 
576  for (i = 0; i < n; i++) {
577  x1 = X(x[i]);
578  y1 = Y(y[i]);
579  if (!edge(x0, y0, x1, y1))
580  return NO_MEMORY;
581  x0 = x1;
582  y0 = y1;
583  }
584  }
585  } /* for() */
586 
587  /* check if perimeter has odd number of points */
588  if (st->np & 1) {
589  G_warning("Weird internal error: perimeter has odd number of points");
590  return OUT_OF_SYNC;
591  }
592 
593  /* sort the edge points by col(x) and then by row(y) */
594  qsort(st->P, st->np, sizeof(POINT), &edge_order);
595 
596  /* plot */
597  for (j = 0; j < rings; j++) {
598  for (i = 1; i < st->np; i += 2) {
599  if (st->P[i].y != st->P[i - 1].y) {
600  G_warning("Weird internal error: edge leaves row");
601  return OUT_OF_SYNC;
602  }
603  st->row_fill(st->P[i].y, st->P[i - 1].x + shift1[j],
604  st->P[i].x + shift1[j]);
605  }
606  if (st->window.proj == PROJECTION_LL) { /* now do wrap-around, part 2 */
607  n = rpnts[j];
608  x = xs[j];
609  y = ys[j];
610 
611  shift = 0;
612  while (W + shift < st->window.west)
613  shift += 360.0;
614  while (W + shift > st->window.east)
615  shift -= 360.0;
616  shift2 = X(x[n - 1] + shift) - X(x[n - 1]);
617  if (shift2 != shift1[j]) {
618  for (i = 1; i < st->np; i += 2) {
619  st->row_fill(st->P[i].y, st->P[i - 1].x + shift2,
620  st->P[i].x + shift2);
621  }
622  }
623  }
624  }
625  G_free(shift1);
626  return OK;
627 }
628 
629 static int edge(double x0, double y0, double x1, double y1)
630 {
631  double m, d;
632  double x;
633  int ystart, ystop;
634  int exp;
635 
636  /* tolerance to avoid FPE */
637  d = GRASS_EPSILON;
638  if (y0 != y1) {
639  if (fabs(y0) > fabs(y1))
640  d = fabs(y0);
641  else
642  d = fabs(y1);
643 
644  d = frexp(d, &exp);
645  exp -= 53;
646  d = ldexp(d, exp);
647  }
648 
649  if (fabs(y0 - y1) < d)
650  return 1;
651 
652  if (y0 < y1) {
653  ystart = iceil(y0);
654  ystop = ifloor(y1);
655  if (ystop == y1)
656  ystop--; /* if line stops at row center, don't include point */
657  }
658  else {
659  ystart = iceil(y1);
660  ystop = ifloor(y0);
661  if (ystop == y0)
662  ystop--; /* if line stops at row center, don't include point */
663  }
664 
665  if (ystart > ystop)
666  return 1; /* does not cross center line of row */
667 
668  m = (x0 - x1) / (y0 - y1);
669  x = m * (ystart - y0) + x0;
670  while (ystart <= ystop) {
671  if (!edge_point(x, ystart++))
672  return 0;
673  x += m;
674  }
675 
676  return 1;
677 }
678 
679 static int edge_point(double x, int y)
680 {
681 
682  if (y < st->ymin || y > st->ymax)
683  return 1;
684  if (st->np >= st->npalloc) {
685  if (st->npalloc > 0) {
686  st->npalloc *= 2;
687  st->P = (POINT *)G_realloc(st->P, st->npalloc * sizeof(POINT));
688  }
689  else {
690  st->npalloc = 32;
691  st->P = (POINT *)G_malloc(st->npalloc * sizeof(POINT));
692  }
693  if (st->P == NULL) {
694  st->npalloc = 0;
695  return 0;
696  }
697  }
698  st->P[st->np].x = x;
699  st->P[st->np++].y = y;
700  return 1;
701 }
702 
703 static int edge_order(const void *aa, const void *bb)
704 {
705  const struct point *a = aa, *b = bb;
706 
707  if (a->y < b->y)
708  return (-1);
709  if (a->y > b->y)
710  return (1);
711 
712  if (a->x < b->x)
713  return (-1);
714  if (a->x > b->x)
715  return (1);
716 
717  return (0);
718 }
719 
720 static void row_solid_fill(int y, double x1, double x2)
721 {
722  int i1, i2;
723 
724  i1 = iceil(x1);
725  i2 = ifloor(x2);
726  if (i1 <= i2) {
727  st->move(i1, y);
728  st->cont(i2, y);
729  }
730 }
731 
732 static void row_dotted_fill(int y, double x1, double x2)
733 {
734  int i1, i2, i;
735 
736  if (y != iceil(y / st->dotted_fill_gap) * st->dotted_fill_gap)
737  return;
738 
739  i1 = iceil(x1 / st->dotted_fill_gap) * st->dotted_fill_gap;
740  i2 = ifloor(x2);
741  if (i1 <= i2) {
742  for (i = i1; i <= i2; i += st->dotted_fill_gap) {
743  st->move(i, y);
744  st->cont(i, y);
745  }
746  }
747 }
748 
749 static int ifloor(double x)
750 {
751  int i;
752 
753  i = (int)x;
754  if (i > x)
755  i--;
756  return i;
757 }
758 
759 static int iceil(double x)
760 {
761  int i;
762 
763  i = (int)x;
764  if (i < x)
765  i++;
766  return i;
767 }
768 
769 /*!
770  * \brief Plot f(east1) to f(east2)
771  *
772  * The function <i>f(east)</i> is plotted from <i>east1</i> to
773  * <i>east2</i>. The function <i>f(east)</i> must return the map
774  * northing coordinate associated with east.
775  *
776  * \param f plotting function
777  * \param east1 easting (first point)
778  * \param east2 easting (second point)
779  */
780 void G_plot_fx(double (*f)(double), double east1, double east2)
781 {
782  double east, north, north1;
783  double incr;
784 
785  incr = fabs(1.0 / st->xconv);
786 
787  east = east1;
788  north = f(east1);
789 
790  if (east1 > east2) {
791  while ((east1 -= incr) > east2) {
792  north1 = f(east1);
793  G_plot_line(east, north, east1, north1);
794  north = north1;
795  east = east1;
796  }
797  }
798  else {
799  while ((east1 += incr) < east2) {
800  north1 = f(east1);
801  G_plot_line(east, north, east1, north1);
802  north = north1;
803  east = east1;
804  }
805  }
806 
807  G_plot_line(east, north, east2, f(east2));
808 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:147
#define G_realloc(p, n)
Definition: defs/gis.h:96
#define G_calloc(m, n)
Definition: defs/gis.h:95
void G_warning(const char *,...) __attribute__((format(printf
void G_get_set_window(struct Cell_head *)
Get the current working window (region)
#define G_malloc(n)
Definition: defs/gis.h:94
double G_adjust_easting(double, const struct Cell_head *)
Returns east not smaller than west.
#define GRASS_EPSILON
Definition: gis.h:178
#define PROJECTION_LL
Projection code - Latitude-Longitude.
Definition: gis.h:129
int edge_order(const void *aa, const void *bb)
Determines points order during sorting.
#define W
Definition: ogsf.h:143
struct state state
Definition: parser.c:103
struct state * st
Definition: parser.c:104
int G_plot_area(double *const *xs, double *const *ys, int *rpnts, int rings)
Plot multiple polygons.
Definition: plot.c:502
void G_plot_line2(double east1, double north1, double east2, double north2)
Plot line between latlon coordinates (slowline)
Definition: plot.c:223
int G_plot_polygon(const double *x, const double *y, int n)
Plot filled polygon with n vertices.
Definition: plot.c:372
#define OUT_OF_SYNC
Definition: plot.c:73
void G_plot_where_en(int x, int y, double *east, double *north)
Converts x,y to east,north.
Definition: plot.c:177
#define X(e)
Definition: plot.c:143
#define POINT
Definition: plot.c:50
void G_plot_where_xy(double east, double north, int *x, int *y)
Converts east,north to x,y.
Definition: plot.c:160
void G_setup_fill(int gap)
Set row_fill routine to row_solid_fill or row_dotted_fill.
Definition: plot.c:133
void G_setup_plot(double t, double b, double l, double r, int(*Move)(int, int), int(*Cont)(int, int))
Initialize plotting routines.
Definition: plot.c:97
#define NORTH(y)
Definition: plot.c:147
void G_plot_fx(double(*f)(double), double east1, double east2)
Plot f(east1) to f(east2)
Definition: plot.c:780
void G_plot_line(double east1, double north1, double east2, double north2)
Plot line between latlon coordinates (fastline)
Definition: plot.c:208
#define Y(n)
Definition: plot.c:144
#define NO_MEMORY
Definition: plot.c:72
#define OK
Definition: plot.c:70
void G_plot_point(double east, double north)
Plot point.
Definition: plot.c:189
#define EAST(x)
Definition: plot.c:146
#define TOO_FEW_EDGES
Definition: plot.c:71
double b
Definition: r_raster.c:39
double l
Definition: r_raster.c:39
double t
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
2D/3D raster map header (used also for region)
Definition: gis.h:446
double bottom
Extent coordinates (bottom) - 3D data.
Definition: gis.h:502
double top
Extent coordinates (top) - 3D data.
Definition: gis.h:500
#define x