GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-602118adcc
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 
178 void G_plot_where_en(int x, int y, double *east, double *north)
179 {
180  *east = G_adjust_easting(EAST(x), &st->window);
181  *north = NORTH(y);
182 }
183 
184 /*!
185  \brief Plot point
186 
187  \param east easting
188  \param north northing
189  */
190 void G_plot_point(double east, double north)
191 {
192  int x, y;
193 
194  G_plot_where_xy(east, north, &x, &y);
195  st->move(x, y);
196  st->cont(x, y);
197 }
198 
199 /*!
200  * \brief Plot line between latlon coordinates (fastline)
201  *
202  * A line from <i>east1,north1</i> to <i>east2,north2</i> is plotted
203  * in output x,y coordinates (e.g. pixels for graphics.) This routine
204  * handles global wrap-around for latitude-longitude databases.
205  *
206  * \param east1, north1 first point (start line node)
207  * \param east2, north2 second point (end line node)
208  */
209 void G_plot_line(double east1, double north1, double east2, double north2)
210 {
211  plot_line(east1, north1, east2, north2, fastline);
212 }
213 
214 /*!
215  * \brief Plot line between latlon coordinates (slowline)
216  *
217  * A line from <i>east1,north1</i> to <i>east2,north2</i> is plotted
218  * in output x,y coordinates (e.g. pixels for graphics.) This routine
219  * handles global wrap-around for latitude-longitude databases.
220  *
221  * \param east1, north1 first point (start line node)
222  * \param east2, north2 second point (end line node)
223  */
224 void G_plot_line2(double east1, double north1, double east2, double north2)
225 {
226  plot_line(east1, north1, east2, north2, slowline);
227 }
228 
229 /* fastline converts double rows/cols to ints then plots
230  * this is ok for graphics, but not the best for vector to raster
231  */
232 static void fastline(double x1, double y1, double x2, double y2)
233 {
234  st->move(ifloor(x1 + 0.5), ifloor(y1 + 0.5));
235  st->cont(ifloor(x2 + 0.5), ifloor(y2 + 0.5));
236 }
237 
238 /* NOTE (shapiro):
239  * I think the adding of 0.5 in slowline is not correct
240  * the output window (left, right, top, bottom) should already
241  * be adjusted for this: left=-0.5; right = window.cols-0.5;
242  */
243 
244 static void slowline(double x1, double y1, double x2, double y2)
245 {
246  double dx, dy;
247  double m, b;
248  int xstart, xstop, ystart, ystop;
249 
250  dx = x2 - x1;
251  dy = y2 - y1;
252 
253  if (fabs(dx) > fabs(dy)) {
254  m = dy / dx;
255  b = y1 - m * x1;
256 
257  if (x1 > x2) {
258  xstart = iceil(x2 - 0.5);
259  xstop = ifloor(x1 + 0.5);
260  }
261  else {
262  xstart = iceil(x1 - 0.5);
263  xstop = ifloor(x2 + 0.5);
264  }
265  if (xstart <= xstop) {
266  ystart = ifloor(m * xstart + b + 0.5);
267  st->move(xstart, ystart);
268  while (xstart <= xstop) {
269  st->cont(xstart++, ystart);
270  ystart = ifloor(m * xstart + b + 0.5);
271  }
272  }
273  }
274  else {
275  if (dx == dy) /* they both might be 0 */
276  m = 1.;
277  else
278  m = dx / dy;
279  b = x1 - m * y1;
280 
281  if (y1 > y2) {
282  ystart = iceil(y2 - 0.5);
283  ystop = ifloor(y1 + 0.5);
284  }
285  else {
286  ystart = iceil(y1 - 0.5);
287  ystop = ifloor(y2 + 0.5);
288  }
289  if (ystart <= ystop) {
290  xstart = ifloor(m * ystart + b + 0.5);
291  st->move(xstart, ystart);
292  while (ystart <= ystop) {
293  st->cont(xstart, ystart++);
294  xstart = ifloor(m * ystart + b + 0.5);
295  }
296  }
297  }
298 }
299 
300 static void plot_line(double east1, double north1, double east2, double north2,
301  void (*line)(double, double, double, double))
302 {
303  double x1, x2, y1, y2;
304 
305  y1 = Y(north1);
306  y2 = Y(north2);
307 
308  if (st->window.proj == PROJECTION_LL) {
309  if (east1 > east2)
310  while ((east1 - east2) > 180)
311  east2 += 360;
312  else if (east2 > east1)
313  while ((east2 - east1) > 180)
314  east1 += 360;
315  while (east1 > st->window.east) {
316  east1 -= 360.0;
317  east2 -= 360.0;
318  }
319  while (east1 < st->window.west) {
320  east1 += 360.0;
321  east2 += 360.0;
322  }
323  x1 = X(east1);
324  x2 = X(east2);
325 
326  line(x1, y1, x2, y2);
327 
328  if (east2 > st->window.east || east2 < st->window.west) {
329  while (east2 > st->window.east) {
330  east1 -= 360.0;
331  east2 -= 360.0;
332  }
333  while (east2 < st->window.west) {
334  east1 += 360.0;
335  east2 += 360.0;
336  }
337  x1 = X(east1);
338  x2 = X(east2);
339  line(x1, y1, x2, y2);
340  }
341  }
342  else {
343  x1 = X(east1);
344  x2 = X(east2);
345  line(x1, y1, x2, y2);
346  }
347 }
348 
349 static double wrap_east(double e0, double e1)
350 {
351  while (e0 - e1 > 180)
352  e1 += 360.0;
353  while (e1 - e0 > 180)
354  e1 -= 360.0;
355 
356  return e1;
357 }
358 
359 /*!
360  * \brief Plot filled polygon with n vertices
361  *
362  * The polygon, described by the <i>n</i> vertices
363  * <i>east,north</i>, is plotted in the output x,y space as a filled polygon.
364  *
365  * \param x coordinates of vertices
366  * \param y coordinates of vertices
367  * \param n number of vertices
368  *
369  * \return 0 on success
370  * \return 2 n < 3
371  * \return -1 weird internal error
372  * \return 1 no memory
373  */
374 int G_plot_polygon(const double *x, const double *y, int n)
375 {
376  int i;
377  int pole;
378  double x0, x1;
379  double y0, y1;
380  double shift, E, W = 0L;
381  double e0, e1;
382  int shift1, shift2;
383 
384  if (!st->row_fill)
385  st->row_fill = row_solid_fill;
386 
387  if (n < 3)
388  return TOO_FEW_EDGES;
389 
390  /* traverse the perimeter */
391 
392  st->np = 0;
393  shift1 = 0;
394 
395  /* global wrap-around for lat-lon, part1 */
396  if (st->window.proj == PROJECTION_LL) {
397  /*
398  pole = G_pole_in_polygon(x,y,n);
399  */
400  pole = 0;
401 
402  e0 = x[n - 1];
403  E = W = e0;
404 
405  x0 = X(e0);
406  y0 = Y(y[n - 1]);
407 
408  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
409  return NO_MEMORY;
410 
411  for (i = 0; i < n; i++) {
412  e1 = wrap_east(e0, x[i]);
413  if (e1 > E)
414  E = e1;
415  if (e1 < W)
416  W = e1;
417 
418  x1 = X(e1);
419  y1 = Y(y[i]);
420 
421  if (!edge(x0, y0, x1, y1))
422  return NO_MEMORY;
423 
424  x0 = x1;
425  y0 = y1;
426  e0 = e1;
427  }
428  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
429  return NO_MEMORY;
430 
431  shift = 0; /* shift into window */
432  while (E + shift > st->window.east)
433  shift -= 360.0;
434  while (E + shift < st->window.west)
435  shift += 360.0;
436  shift1 = X(x[n - 1] + shift) - X(x[n - 1]);
437  }
438  else {
439  x0 = X(x[n - 1]);
440  y0 = Y(y[n - 1]);
441 
442  for (i = 0; i < n; i++) {
443  x1 = X(x[i]);
444  y1 = Y(y[i]);
445  if (!edge(x0, y0, x1, y1))
446  return NO_MEMORY;
447  x0 = x1;
448  y0 = y1;
449  }
450  }
451 
452  /* check if perimeter has odd number of points */
453  if (st->np & 1) {
454  G_warning("Weird internal error: perimeter has odd number of points");
455  return OUT_OF_SYNC;
456  }
457 
458  /* sort the edge points by col(x) and then by row(y) */
459  qsort(st->P, st->np, sizeof(POINT), edge_order);
460 
461  /* plot */
462  for (i = 1; i < st->np; i += 2) {
463  if (st->P[i].y != st->P[i - 1].y) {
464  G_warning("Weird internal error: edge leaves row");
465  return OUT_OF_SYNC;
466  }
467  st->row_fill(st->P[i].y, st->P[i - 1].x + shift1, st->P[i].x + shift1);
468  }
469  if (st->window.proj == PROJECTION_LL) { /* now do wrap-around, part 2 */
470  shift = 0;
471  while (W + shift < st->window.west)
472  shift += 360.0;
473  while (W + shift > st->window.east)
474  shift -= 360.0;
475  shift2 = X(x[n - 1] + shift) - X(x[n - 1]);
476  if (shift2 != shift1) {
477  for (i = 1; i < st->np; i += 2) {
478  st->row_fill(st->P[i].y, st->P[i - 1].x + shift2,
479  st->P[i].x + shift2);
480  }
481  }
482  }
483  return OK;
484 }
485 
486 /*!
487  * \brief Plot multiple polygons
488  *
489  * Like G_plot_polygon(), except it takes a set of polygons, each with
490  * npts[<i>i</i>] vertices, where the number of polygons is specified
491  * with the <i>rings</i> argument. It is especially useful for
492  * plotting vector areas with interior islands.
493  *
494  * \param xs pointer to pointer for X's
495  * \param ys pointer to pointer for Y's
496  * \param rpnts array of ints w/ num points per ring
497  * \param rings number of rings
498  *
499  * \return 0 on success
500  * \return 2 n < 3
501  * \return -1 weird internal error
502  * \return 1 no memory
503  */
504 int G_plot_area(double *const *xs, double *const *ys, int *rpnts, int rings)
505 {
506  int i, j, n;
507  int pole;
508  double x0, x1, *x;
509  double y0, y1, *y;
510  double shift, E, W = 0L;
511  double e0, e1;
512  int *shift1 = NULL, shift2;
513 
514  if (!st->row_fill)
515  st->row_fill = row_solid_fill;
516 
517  /* traverse the perimeter */
518 
519  st->np = 0;
520  shift1 = (int *)G_calloc(sizeof(int), rings);
521 
522  for (j = 0; j < rings; j++) {
523  n = rpnts[j];
524 
525  if (n < 3)
526  return TOO_FEW_EDGES;
527 
528  x = xs[j];
529  y = ys[j];
530 
531  /* global wrap-around for lat-lon, part1 */
532  if (st->window.proj == PROJECTION_LL) {
533  /*
534  pole = G_pole_in_polygon(x,y,n);
535  */
536  pole = 0;
537 
538  e0 = x[n - 1];
539  E = W = e0;
540 
541  x0 = X(e0);
542  y0 = Y(y[n - 1]);
543 
544  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
545  return NO_MEMORY;
546 
547  for (i = 0; i < n; i++) {
548  e1 = wrap_east(e0, x[i]);
549  if (e1 > E)
550  E = e1;
551  if (e1 < W)
552  W = e1;
553 
554  x1 = X(e1);
555  y1 = Y(y[i]);
556 
557  if (!edge(x0, y0, x1, y1))
558  return NO_MEMORY;
559 
560  x0 = x1;
561  y0 = y1;
562  e0 = e1;
563  }
564  if (pole && !edge(x0, y0, x0, Y(90.0 * pole)))
565  return NO_MEMORY;
566 
567  shift = 0; /* shift into window */
568  while (E + shift > st->window.east)
569  shift -= 360.0;
570  while (E + shift < st->window.west)
571  shift += 360.0;
572  shift1[j] = X(x[n - 1] + shift) - X(x[n - 1]);
573  }
574  else {
575  x0 = X(x[n - 1]);
576  y0 = Y(y[n - 1]);
577 
578  for (i = 0; i < n; i++) {
579  x1 = X(x[i]);
580  y1 = Y(y[i]);
581  if (!edge(x0, y0, x1, y1))
582  return NO_MEMORY;
583  x0 = x1;
584  y0 = y1;
585  }
586  }
587  } /* for() */
588 
589  /* check if perimeter has odd number of points */
590  if (st->np & 1) {
591  G_warning("Weird internal error: perimeter has odd number of points");
592  return OUT_OF_SYNC;
593  }
594 
595  /* sort the edge points by col(x) and then by row(y) */
596  qsort(st->P, st->np, sizeof(POINT), &edge_order);
597 
598  /* plot */
599  for (j = 0; j < rings; j++) {
600  for (i = 1; i < st->np; i += 2) {
601  if (st->P[i].y != st->P[i - 1].y) {
602  G_warning("Weird internal error: edge leaves row");
603  return OUT_OF_SYNC;
604  }
605  st->row_fill(st->P[i].y, st->P[i - 1].x + shift1[j],
606  st->P[i].x + shift1[j]);
607  }
608  if (st->window.proj == PROJECTION_LL) { /* now do wrap-around, part 2 */
609  n = rpnts[j];
610  x = xs[j];
611  y = ys[j];
612 
613  shift = 0;
614  while (W + shift < st->window.west)
615  shift += 360.0;
616  while (W + shift > st->window.east)
617  shift -= 360.0;
618  shift2 = X(x[n - 1] + shift) - X(x[n - 1]);
619  if (shift2 != shift1[j]) {
620  for (i = 1; i < st->np; i += 2) {
621  st->row_fill(st->P[i].y, st->P[i - 1].x + shift2,
622  st->P[i].x + shift2);
623  }
624  }
625  }
626  }
627  G_free(shift1);
628  return OK;
629 }
630 
631 static int edge(double x0, double y0, double x1, double y1)
632 {
633  double m, d;
634  double x;
635  int ystart, ystop;
636  int exp;
637 
638  /* tolerance to avoid FPE */
639  d = GRASS_EPSILON;
640  if (y0 != y1) {
641  if (fabs(y0) > fabs(y1))
642  d = fabs(y0);
643  else
644  d = fabs(y1);
645 
646  d = frexp(d, &exp);
647  exp -= 53;
648  d = ldexp(d, exp);
649  }
650 
651  if (fabs(y0 - y1) < d)
652  return 1;
653 
654  if (y0 < y1) {
655  ystart = iceil(y0);
656  ystop = ifloor(y1);
657  if (ystop == y1)
658  ystop--; /* if line stops at row center, don't include point */
659  }
660  else {
661  ystart = iceil(y1);
662  ystop = ifloor(y0);
663  if (ystop == y0)
664  ystop--; /* if line stops at row center, don't include point */
665  }
666 
667  if (ystart > ystop)
668  return 1; /* does not cross center line of row */
669 
670  m = (x0 - x1) / (y0 - y1);
671  x = m * (ystart - y0) + x0;
672  while (ystart <= ystop) {
673  if (!edge_point(x, ystart++))
674  return 0;
675  x += m;
676  }
677 
678  return 1;
679 }
680 
681 static int edge_point(double x, int y)
682 {
683 
684  if (y < st->ymin || y > st->ymax)
685  return 1;
686  if (st->np >= st->npalloc) {
687  if (st->npalloc > 0) {
688  st->npalloc *= 2;
689  st->P = (POINT *)G_realloc(st->P, st->npalloc * sizeof(POINT));
690  }
691  else {
692  st->npalloc = 32;
693  st->P = (POINT *)G_malloc(st->npalloc * sizeof(POINT));
694  }
695  if (st->P == NULL) {
696  st->npalloc = 0;
697  return 0;
698  }
699  }
700  st->P[st->np].x = x;
701  st->P[st->np++].y = y;
702  return 1;
703 }
704 
705 static int edge_order(const void *aa, const void *bb)
706 {
707  const struct point *a = aa, *b = bb;
708 
709  if (a->y < b->y)
710  return (-1);
711  if (a->y > b->y)
712  return (1);
713 
714  if (a->x < b->x)
715  return (-1);
716  if (a->x > b->x)
717  return (1);
718 
719  return (0);
720 }
721 
722 static void row_solid_fill(int y, double x1, double x2)
723 {
724  int i1, i2;
725 
726  i1 = iceil(x1);
727  i2 = ifloor(x2);
728  if (i1 <= i2) {
729  st->move(i1, y);
730  st->cont(i2, y);
731  }
732 }
733 
734 static void row_dotted_fill(int y, double x1, double x2)
735 {
736  int i1, i2, i;
737 
738  if (y != iceil(y / st->dotted_fill_gap) * st->dotted_fill_gap)
739  return;
740 
741  i1 = iceil(x1 / st->dotted_fill_gap) * st->dotted_fill_gap;
742  i2 = ifloor(x2);
743  if (i1 <= i2) {
744  for (i = i1; i <= i2; i += st->dotted_fill_gap) {
745  st->move(i, y);
746  st->cont(i, y);
747  }
748  }
749 }
750 
751 static int ifloor(double x)
752 {
753  int i;
754 
755  i = (int)x;
756  if (i > x)
757  i--;
758  return i;
759 }
760 
761 static int iceil(double x)
762 {
763  int i;
764 
765  i = (int)x;
766  if (i < x)
767  i++;
768  return i;
769 }
770 
771 /*!
772  * \brief Plot f(east1) to f(east2)
773  *
774  * The function <i>f(east)</i> is plotted from <i>east1</i> to
775  * <i>east2</i>. The function <i>f(east)</i> must return the map
776  * northing coordinate associated with east.
777  *
778  * \param f plotting function
779  * \param east1 easting (first point)
780  * \param east2 easting (second point)
781  */
782 void G_plot_fx(double (*f)(double), double east1, double east2)
783 {
784  double east, north, north1;
785  double incr;
786 
787  incr = fabs(1.0 / st->xconv);
788 
789  east = east1;
790  north = f(east1);
791 
792  if (east1 > east2) {
793  while ((east1 -= incr) > east2) {
794  north1 = f(east1);
795  G_plot_line(east, north, east1, north1);
796  north = north1;
797  east = east1;
798  }
799  }
800  else {
801  while ((east1 += incr) < east2) {
802  north1 = f(east1);
803  G_plot_line(east, north, east1, north1);
804  north = north1;
805  east = east1;
806  }
807  }
808 
809  G_plot_line(east, north, east2, f(east2));
810 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#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:173
#define PROJECTION_LL
Projection code - Latitude-Longitude.
Definition: gis.h:130
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:504
void G_plot_line2(double east1, double north1, double east2, double north2)
Plot line between latlon coordinates (slowline)
Definition: plot.c:224
int G_plot_polygon(const double *x, const double *y, int n)
Plot filled polygon with n vertices.
Definition: plot.c:374
#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:178
#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:782
void G_plot_line(double east1, double north1, double east2, double north2)
Plot line between latlon coordinates (fastline)
Definition: plot.c:209
#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:190
#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:440
double bottom
Extent coordinates (bottom) - 3D data.
Definition: gis.h:496
double top
Extent coordinates (top) - 3D data.
Definition: gis.h:494
#define x