/* Ppm Generate tide graphs in raw 8 bit PPM format. Last modified 1997-04-26 Copyright (C) 1997 David Flater. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "everythi.h" #include "glyphs.h" /* These are the colors. */ static int BGR = 135; static int BGG = 206; static int BGB = 235; static int FGR = 0; static int FGG = 0; static int FGB = 255; static int EBR = 46; static int EBG = 139; static int EBB = 87; static int TXR = 0; static int TXG = 0; static int TXB = 0; static int MKR = 255; static int MKG = 0; static int MKB = 0; static int MDR = 255; static int MDG = 255; static int MDB = 0; static int MLR = 255; static int MLG = 255; static int MLB = 255; /* margin -- same as before. */ /* linewidth -- applies to linegraph (nofill) only. */ #define margin 0.05 #define linewidth 2.0 /* pixmap -- for building of the ppm */ /* pixmap16 -- extra work area for linegraph */ static unsigned char *pixmap; static unsigned short *pixmap16; /* Colors must be specified in the form rgb:hh/hh/hh, where hh is a 2-byte hexidecimal number. */ static void p_parsecolor (int *r, int *g, int *b, char *col) { if (col) { if (sscanf (col, "rgb:%x/%x/%x", r, g, b) != 3) barf (BADCOLORSPEC); } if (!((*r >= 0 && *r <= 255)&&(*g >= 0 && *g <= 255)&& (*b >= 0 && *b <= 255))) barf (BADCOLORSPEC); } static void p_parseallcolors () { p_parsecolor (&FGR, &FGG, &FGB, fgrise_color_arg); p_parsecolor (&EBR, &EBG, &EBB, fgfall_color_arg); p_parsecolor (&TXR, &TXG, &TXB, fgtext_color_arg); p_parsecolor (&MKR, &MKG, &MKB, fgmark_color_arg); p_parsecolor (&MLR, &MLG, &MLB, fgmllw_color_arg); p_parsecolor (&MDR, &MDG, &MDB, fgmiddle_color_arg); p_parsecolor (&BGR, &BGG, &BGB, bg_color_arg); } /* Set a color value in the pixmap */ static void p_setval (int x, int y, int c, int val) { if (x < 0 || y < -12 || x >= PPMWIDTH || y >= PPMHEIGHT) return; pixmap[((y+12)*PPMWIDTH+x)*3+c] = (unsigned char)val; } /* Get a color value from the pixmap */ static int p_getval (int x, int y, int c) { if (x < 0 || y < -12 || x >= PPMWIDTH || y >= PPMHEIGHT) return 0; return (int) (pixmap[((y+12)*PPMWIDTH+x)*3+c]); } /* Set a pixel (all 3 colors) in the pixmap) */ static void p_setpix (int x, int y, int r, int g, int b) { p_setval (x, y, 0, r); p_setval (x, y, 1, g); p_setval (x, y, 2, b); } /* Set a pixel in the linegraph work area */ static void p_setpix16 (double x, double y) { int xx, yy, zz, x1, y1, z1; xx = (int)x; yy = (int)y; if (x < 0 || y < 0 || x >= PPMWIDTH || y >= PPMHEIGHT) return; zz = yy * PPMWIDTH + xx; x -= (double)xx; y -= (double)yy; x1 = (int)(x*4.0); y1 = (int)(y*4.0); assert (x1 < 4 && x1 >= 0); assert (y1 < 4 && y1 >= 0); z1 = y1 * 4 + x1; pixmap16[zz] |= 1 << z1; } /* Support function for p_circle16 */ static int circlep (double x, double y, double xx, double yy, double r) { double x2, y2; r /= 2.0; x2 = x - xx; x2 *= x2; y2 = y - yy; y2 *= y2; if (x2 + y2 < r*r+0.25) return 1; return 0; } /* Draw and fill a circle in the linegraph work area. */ static void p_circle16 (double x, double y, double r) { double xx, yy; for (yy=y-r;yy<=y+r;yy+=0.25) for (xx=x-r;xx<=x+r;xx+=0.25) if (circlep (x, y, xx, yy, r)) p_setpix16 (xx, yy); } /* Support function for p_line16_primary */ static void p_line16_secondary (double x2, double y2, double w, double slope, int sflag) { double x, y, x1, y1, d; /* p_setpix16 (x2, y2); return; */ d = sqrt (w*w / (slope*slope + 1.0)) / 2.0; if (sflag) { y1 = y2 - d; x1 = x2 - d * slope; } else { x1 = x2 - d; y1 = y2 - d * slope; } if (sflag) { for (y=y1;y fabs(dx)) { slope = dx / dy; if (y1 > y2) { x = x1; x1 = x2; x2 = x; y = y1; y1 = y2; y2 = y; } for (y=y1;y x2) { x = x1; x1 = x2; x2 = x; y = y1; y1 = y2; y2 = y; } for (x=x1;x= PPMWIDTH || y >= PPMHEIGHT) return 0; zz = yy * PPMWIDTH + xx; x -= (double)xx; y -= (double)yy; x1 = (int)(x*4.0); y1 = (int)(y*4.0); assert (x1 < 4 && x1 >= 0); assert (y1 < 4 && y1 >= 0); z1 = y1 * 4 + x1; if (pixmap16[zz] & (1 << z1)) return 1; return 0; } static void writepbm () { double x, y; printf ("P1\n%d %d\n", PPMWIDTH*4, PPMHEIGHT*4); for (y=0;y= 0 && base < 95); base *= 7; for (yl=0;yl<11;yl++) for (xl=0;xl<7;xl++) if (glyphs[yl][base+xl]) p_setpix (x+xl, y+yl, TXR, TXG, TXB); } /* Scrawl a string on the pixmap. */ static void p_putstr (int x, int y, char *s) { int a; for (a=0;a<(int)(strlen(s));a++) p_putglyph (x+a*7, y, s[a]); } /* Center a string in the pixmap. */ static void p_center_text (int x, int y, char *text) { int l = strlen (text); p_putstr (x - 7 * l / 2, y, text); } /* More drawing functions. */ static void p_write_high_tide (int x) { p_center_text (x, 1, next_ht_date); p_center_text (x, 13, next_ht_text); } static void p_write_trans_time (int x) { int bottom = PPMHEIGHT - 19; if (tinc) bottom -= 12; p_center_text (x, bottom-12, next_ht_date); p_center_text (x, bottom, next_ht_text); } static void p_draw_depth_lines (int *tmax, int *tmin) { int a, x, y, firstflag = 1; if (lines) { *tmin = 30; *tmax = PPMHEIGHT - 14; if (mark) *tmax -= 24; if (tinc) *tmax -= 12; *tmin = (int) (p_wl2tide (*tmin) * fakeamplitude + fakedatum); *tmax = (int) (ceil (p_wl2tide (*tmax) * fakeamplitude + fakedatum)); for (a=*tmin;a>=*tmax;a--) { if (fakeamplitude > 30.0 && (a % 10)) continue; y = (int) p_tide2wl (((double)a - fakedatum) / fakeamplitude); if (hinc) { if (!(a % hinc)) { char temp[20+MAXARGLEN]; int l; make_depth_caption (&firstflag, a, temp); l = strlen (temp); for (x=0;x midwl)) || ((!iscurrent) && hairy && (yy > prev_g_tide))) { TR = EBR; TG = EBG; TB = EBB; } else { TR = FGR; TG = FGG; TB = FGB; } p_semi_setpix (x, y, TR, TG, TB, 1.0 - bitcount); } faketime += tstep; prev_g_tide = yy; } } else { prev_g_tide = p_tide2wl (time2secondary (faketime-1)); for (x=0;x(int)yy;y--) p_setpix (x, y, FGR, FGG, FGB); p_semi_setpix (x, (int)yy, FGR, FGG, FGB, yy - floor (yy)); } else { for (y=midwl+1;y<=(int)yy;y++) p_setpix (x, y, EBR, EBG, EBB); p_semi_setpix (x, (int)yy+1, EBR, EBG, EBB, 1.0 - (yy - floor (yy))); } } else { if (!hairy || yy < prev_g_tide) { TR = FGR; TG = FGG; TB = FGB; } else { TR = EBR; TG = EBG; TB = EBB; } for (y=PPMHEIGHT-1;y>(int)yy;y--) p_setpix (x, y, TR, TG, TB); p_semi_setpix (x, (int)yy, TR, TG, TB, yy - floor (yy)); } faketime += tstep; prev_g_tide = yy; } } if (toplines) p_draw_depth_lines (&tmax, &tmin); /* Label unit lines */ if (hinc) { for (a=tmin;a>=tmax;a--) { if (fakeamplitude > 30.0 && (a % 10)) continue; if (!(a % hinc)) { char temp[20+MAXARGLEN]; int l; y = (int) p_tide2wl (((double)a - fakedatum) / fakeamplitude); make_depth_caption (&firstflag, a, temp); l = strlen (temp); p_putstr (PPMWIDTH - 7 * l, y-4, temp); } } } /* Extra lines */ if (mark) { y = (int) p_tide2wl ((marklev - fakedatum) / fakeamplitude); for (x=0;xPPMHEIGHT-8;y--) p_setpix (x, y, TXR, TXG, TXB); if (tinc) { struct tm *foo; foo = tmtime (hour); if (!((foo->tm_hour) % tinc)) { char buf[20]; do_timestamp (buf, foo); if (buf[1] == ':') buf[1] = '\0'; else buf[2] = '\0'; p_center_text (x, PPMHEIGHT-19, buf); } } } for (hour=prev_day(start);hour<=start+PPMWIDTH*tstep+HOURSECONDS; hour=increment_day(hour)) { x = (hour - start) / tstep; for (y=PPMHEIGHT-1;y>PPMHEIGHT-8;y--) { p_setpix (x-1, y, TXR, TXG, TXB); p_setpix (x, y, TXR, TXG, TXB); p_setpix (x+1, y, TXR, TXG, TXB); } } } if (now) { int looper; /* X marks the spot */ x = (int)((this_time - start) / tstep); y = (int) p_tide2wl (time2secondary (this_time)); for (looper=-4;looper<=4;looper++) { p_setpix (x+looper, y, TXR, TXG, TXB); p_setpix (x, y+looper, TXR, TXG, TXB); } } /* Scrawl timestamps */ next_ht = start - MAX(abs(httimeoff),abs(lttimeoff)); finish = start + PPMWIDTH*tstep + MAX(abs(httimeoff),abs(lttimeoff)); event_type = update_high_tide (); while (next_ht < finish) { x = (int)((next_ht_adj - start) / tstep); if (event_type & 3) p_write_high_tide (x); if (event_type & 12) { p_write_trans_time (x); for (y=PPMHEIGHT-1;y>=PPMHEIGHT-7;y--) p_setpix (x, y, MKR, MKG, MKB); } event_type = update_high_tide (); } /* Identify the pixmap */ p_center_text (PPMWIDTH>>1, -11, location); /* Write output. */ if (strcmp (outfile, "-")) { #ifdef OS2 if (!(fp = fopen (outfile, "wb"))) #else if (!(fp = fopen (outfile, "w"))) #endif barf (CANTOPENFILE); } else fp = stdout; fprintf (fp, "P6\n%d %d\n255\n", PPMWIDTH, PPMHEIGHT+12); fwrite (pixmap, 3, PPMWIDTH*(PPMHEIGHT+12), fp); fclose (fp); free (pixmap); if (linegraph) free (pixmap16); }