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