const char * UsageLines [] = { "Usage: linetopbm (width) (height)", "Reads space-separated points, from standard input, in the form", "\tacross,down", "\twhere across and down are positive or negative integers.", "Writes, to standard output, a P4 PBM image.", "A line one pixel wide will join the points on each input line", "\t(that has at least two points).", "On each input line, everything after # is treated as a comment.", "The leftmost column of pixels is considered - (width)/2 across.", "The topmost row of pixels is considered - (height)/2 down.", "August 26, 2011. Newest is at gopher -p users/julianbr sdf.org", }; const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] ); struct Segment { int across1; int down1; int across2; int down2; struct Segment * next; }; #include <stdlib.h> #include <stdio.h> int ReadSegments (struct Segment * * SegmentsPtr) { struct Segment * * SegmentPtr; unsigned int LineNum; int IsNegative, FoundAcross, across, FoundDown, down; int PreviousAcross, PreviousDown, PreviousPoint; int c, ok; ok = 1; LineNum = 0; SegmentsPtr [0] = NULL; SegmentPtr = SegmentsPtr; c = getchar (); while (c != EOF) { LineNum++; PreviousPoint = 0; while (c != EOF && c != '\n') { while (c == ' ') c = getchar (); /* read across */ IsNegative = 0; if (c == '+') c = getchar (); else if (c == '-') { IsNegative = 1; c = getchar (); } FoundAcross = 0; across = 0; while (c >= '0' && c <= '9') { FoundAcross = 1; across = 10*across + (c - '0'); c = getchar (); } if (IsNegative) across = - across; if (c == ',') c = getchar (); else FoundAcross = 0; /* read down */ IsNegative = 0; if (c == '+') c = getchar (); else if (c == '-') { IsNegative = 1; c = getchar (); } FoundDown = 0; down = 0; while (c >= '0' && c <= '9') { FoundDown = 1; down = 10*down + (c - '0'); c = getchar (); } if (IsNegative) down = - down; if (c != EOF && c != '\n' && c != ' ' && c != '#') { fprintf (stderr, "***linetopbm: Improper"); fprintf (stderr, " '%c'", c); fprintf (stderr, " in line #%u.\n", LineNum); while (c != EOF && c != '\n' && c != ' ' && c != '#') c = getchar (); ok = 0; } else if (FoundAcross && !FoundDown) { fprintf (stderr, "***linetopbm: Incomplete"); fprintf (stderr, " across,down"); fprintf (stderr, " in line #%u.\n", LineNum); ok = 0; } else if (FoundAcross && FoundDown) { if (PreviousPoint) { /* Add segment */; SegmentPtr [0] = malloc ( sizeof (SegmentPtr [0] [0] ) ); if (SegmentPtr [0] == NULL) { fprintf (stderr, "***"); fprintf (stderr, "linetopbm:"); fprintf (stderr, " Not enough"); fprintf (stderr, " memory.\n"); ok = 0; } else { SegmentPtr [0]->across1 = PreviousAcross; SegmentPtr [0]->down1 = PreviousDown; SegmentPtr [0]->across2 = across; SegmentPtr [0]->down2 = down; SegmentPtr [0]->next = NULL; SegmentPtr = & SegmentPtr [0]->next; } } PreviousPoint = 1; PreviousAcross = across; PreviousDown = down; } if (c == '#') { while (c != EOF && c != '\n') c = getchar (); } } if (c != EOF) c = getchar (); } return ok; } int IsOnSegment (int across, int down, struct Segment * Segments) { struct Segment * Segment; int m, n, x, y, temp; Segment = Segments; while (Segment != NULL) { if (Segment->across1 > Segment->across2) { m = Segment->across1 - Segment->across2 + 1; y = Segment->across1 - across; } else { m = Segment->across2 - Segment->across1 + 1; y = across - Segment->across1; } if (Segment->down1 > Segment->down2) { n = Segment->down1 - Segment->down2 + 1; x = Segment->down1 - down; } else { n = Segment->down2 - Segment->down1 + 1; x = down - Segment->down1; } if (m > n) { temp = n; n = m; m = temp; temp = y; y = x; x = temp; } if (x >= 0 && x < n) { if (y == (m/2 + m*x)/n) return 1; } Segment = Segment->next; } return 0; } void WriteSegments ( struct Segment * Segments, int width, int height) { /* int i, j, k, m, LineSize, OutputBuffer, pixel; */ int across, down, OutputWeight, OutputValue; printf ("P4\n%d %d\n", width, height); for (down = - height/2; down < height - height/2; down++) { OutputWeight = 128; OutputValue = 0; for (across = - width/2; across < width - width/2; across++) { if (IsOnSegment (across, down, Segments) ) OutputValue += OutputWeight; OutputWeight /= 2; if (OutputWeight == 0) { putchar (OutputValue); OutputWeight = 128; OutputValue = 0; } } if (OutputWeight < 128) putchar (OutputValue); } } void CloseSegments (struct Segment * Segments) { struct Segment * Segment, * NextSegment; Segment = Segments; while (Segment != NULL) { NextSegment = Segment->next; free (Segment); Segment = NextSegment; } } int main (int argc, char * argv [] ) { struct Segment * Segments; int width, height, i; char c; if (argc < 2) { for (i = 0; i < NumUsageLines; i++) printf ("%s\n", UsageLines [i] ); } else if (argc == 3 && sscanf (argv [1], "%d%c", & width, & c) == 1 && width > 0 && sscanf (argv [2], "%d%c", & height, & c) == 1 && height > 0) { if (ReadSegments (& Segments) ) WriteSegments (Segments, width, height); CloseSegments (Segments); } else { fprintf (stderr, "Usage: linetopbm"); fprintf (stderr, " (width) (height)\n"); } return 0; }