const char * UsageLines [] = { "Usage: llfind (latitude) (longitude)... < (input file)" "", "Finds points inside a perimeter containing straight line segments", "oriented E-W which are specified by latitude, and straight line", "segments oriented N-S which are specified by longitude.", "Input must contain lines beginning with:", "\t(latitude),(longitude)", "", "Outputs points that are inside (or on) the borders specified.", "Rounds input and borders to and displays output at 4 decimal places.", "Displays area in \"GeoAres\": a GeoAre is a rectangle whose", "sides are .0001 degree latitude, and .0001 degree longitude apart.", "(1 sq km = 8100 GeoAres at the equator,", " 1 sq km = 12600 GeoAres at 50 degrees latitude.)", "", "March 10, 2013", "Latest version can be found at:", " gopher -p users/julianbr sdf.org", "or: gopher://sdf.org/1/users/julianbr", }; const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] ); #include #include #define NumDecimalPlaces 4 int ReadLocation ( long int * northPtr, long int * eastPtr, int * endOfInputLinePtr, int * endOfInputPtr) { char sign; int decimalPosition, LatitudeAndLongitudeOk, c; LatitudeAndLongitudeOk = 0; endOfInputLinePtr [0] = 0; c = getchar (); sign = '+'; if (c == '-' || c == '+') { sign = c; c = getchar (); } northPtr [0] = 0; while (c >= '0' && c <= '9') { northPtr [0] = 10*northPtr [0] + (c - '0'); c = getchar (); } decimalPosition = 0; if (c == '.') { c = getchar (); while (c >= '0' && c <= '9') { if (decimalPosition == NumDecimalPlaces) { if (c > '4') northPtr [0]++; } else if (decimalPosition < NumDecimalPlaces) northPtr [0] = 10*northPtr [0] + (c - '0'); decimalPosition++; c = getchar (); } } while (decimalPosition < NumDecimalPlaces) { northPtr [0] = 10*northPtr [0]; decimalPosition++; } if (sign == '-') northPtr [0] = - northPtr [0]; if (c == ',') { c = getchar (); sign = '+'; if (c == '-' || c == '+') { sign = c; c = getchar (); } eastPtr [0] = 0; while (c >= '0' && c <= '9') { eastPtr [0] = 10*eastPtr [0] + (c - '0'); c = getchar (); } decimalPosition = 0; if (c == '.') { c = getchar (); while (c >= '0' && c <= '9') { if (decimalPosition == NumDecimalPlaces) { if (c > '4') eastPtr [0]++; } else if (decimalPosition < NumDecimalPlaces) eastPtr [0] = 10*eastPtr [0] + (c - '0'); decimalPosition++; c = getchar (); } } while (decimalPosition < NumDecimalPlaces) { eastPtr [0] = 10*eastPtr [0]; decimalPosition++; } if (sign == '-') eastPtr [0] = - eastPtr [0]; LatitudeAndLongitudeOk = 1; } if (c != EOF && c != '\n' && c != ' ') { fprintf (stderr, "***llfind: Improper '%c'", c); LatitudeAndLongitudeOk = 0; } else if (c != EOF && !LatitudeAndLongitudeOk) fprintf (stderr, "***llfind: Comma not found"); if (c == EOF) { endOfInputLinePtr [0] = 1; endOfInputPtr [0] = 1; } if (c == '\n') endOfInputLinePtr [0] = 1; return LatitudeAndLongitudeOk; } long int ReadBoundary (char * Boundary) { long int boundaryValue; int decimalPosition; char sign, * ptr; ptr = Boundary; sign = '+'; if (ptr [0] == '-' || ptr [0] == '+') { sign = ptr [0]; ptr++; } boundaryValue = 0; while (ptr [0] >= '0' && ptr [0] <= '9') { boundaryValue = 10*boundaryValue + (ptr [0] - '0'); ptr++; } decimalPosition = 0; if (ptr [0] == '.') { ptr++; while (ptr [0] >= '0' && ptr [0] <= '9') { if (decimalPosition == NumDecimalPlaces) { if (ptr [0] > '4') boundaryValue++; } else if (decimalPosition < NumDecimalPlaces) boundaryValue = 10*boundaryValue + (ptr [0] - '0'); decimalPosition++; ptr++; } } while (decimalPosition < NumDecimalPlaces) { boundaryValue = 10*boundaryValue; decimalPosition++; } if (sign == '-') boundaryValue = - boundaryValue; return boundaryValue; } void FindAreaInsideBoundaries ( int numBoundaries, char * * Boundaries) { long int cwArea, east; int i; cwArea = 0; east = 0; for (i = 1; i < numBoundaries; i += 2) { east += ReadBoundary (Boundaries [i] ); } east /= numBoundaries/2; for (i = 1; i < numBoundaries; i += 2) { cwArea += (ReadBoundary (Boundaries [(i + 1)%numBoundaries] ) - ReadBoundary (Boundaries [i - 1] ) ) *(east - ReadBoundary (Boundaries [i] ) ); } if (cwArea < 0) cwArea = - cwArea; fprintf (stderr, "llfind: %ld GeoAres", cwArea); fprintf (stderr, " inside specified boundaries.\n"); } int IsInsideOrOnBoundaries ( long int north, long int east, int numBoundaries, char * * Boundaries) { long int north1, east2, north3, east4; int numCrossings, i; numCrossings = 0; for (i = 0; i < numBoundaries/2; i++) { north1 = ReadBoundary ( Boundaries [(i + i + 0)%numBoundaries] ); east2 = ReadBoundary ( Boundaries [(i + i + 1)%numBoundaries] ); north3 = ReadBoundary ( Boundaries [(i + i + 2)%numBoundaries] ); east4 = ReadBoundary ( Boundaries [(i + i + 3)%numBoundaries] ); if (east == east2 && !(north < north1 && north < north3) && !(north > north1 && north > north3) ) return 1; else if (north == north3 && !(east < east2 && east < east4) && !(east > east2 && east > east4) ) return 1; else if (north >= north1 && north < north3) { if (east >= east2) numCrossings++; } else if (north >= north3 && north < north1) { if (east >= east2) numCrossings--; } } if (numCrossings == 0) return 0; return 1; } int BoundaryOk (char * Boundary) { char * ptr; ptr = Boundary; if (ptr [0] == '-' || ptr [0] == '+') ptr++; while (ptr [0] >= '0' && ptr [0] <= '9') ptr++; if (ptr [0] == '.') ptr++; while (ptr [0] >= '0' && ptr [0] <= '9') ptr++; if (ptr [0] == '\0') return 1; return 0; } int BoundariesOk (int numBoundaries, char * * Boundaries) { int i, ok; ok = 1; for (i = 0; i < numBoundaries; i++) { if (!BoundaryOk (Boundaries [i] ) ) { fprintf (stderr, "***llfind: Improper boundary:"); fprintf (stderr, " \"%s\".\n", Boundaries [i] ); ok = 0; } } return ok; } void WriteLocation ( long int north, long int east, int endOfInputLine, int * endOfInputPtr) { unsigned long int value, factor; int i, c; if (north < 0) { putchar ('-'); value = - north; } else { putchar ('+'); value = north; } factor = 1; for (i = 0; i < NumDecimalPlaces + 2; i++) factor *= 10; for (i = 0; i < 2; i++) { factor /= 10; putchar ('0' + value/factor%10); } putchar ('.'); for (i = 0; i < NumDecimalPlaces; i++) { factor /= 10; putchar ('0' + value/factor%10); } putchar (','); if (east < 0) { putchar ('-'); value = - east; } else { putchar ('+'); value = east; } factor = 1; for (i = 0; i < NumDecimalPlaces + 3; i++) factor *= 10; for (i = 0; i < 3; i++) { factor /= 10; putchar ('0' + value/factor%10); } putchar ('.'); for (i = 0; i < NumDecimalPlaces; i++) { factor /= 10; putchar ('0' + value/factor%10); } if (!endOfInputLine) { putchar (' '); c = getchar (); while (c != EOF && c != '\n') { putchar (c); c = getchar (); } if (c == EOF) endOfInputPtr [0] = 1; } putchar ('\n'); } void FindLocationsOnOrInsideBoundaries ( int numBoundaries, char * * Boundaries) { unsigned long int all, inside, lineNum; long int north, east; int endOfInputLine, endOfInput, ok, c; ok = 1; all = 0; inside = 0; lineNum = 0; endOfInput = 0; while (!endOfInput) { lineNum++; if (ReadLocation ( & north, & east, & endOfInputLine, & endOfInput) ) { all++; if (IsInsideOrOnBoundaries ( north, east, numBoundaries, Boundaries) ) { inside++; WriteLocation ( north, east, endOfInputLine, & endOfInput); } else if (!endOfInputLine) { c = getchar (); while (c != EOF && c != '\n') c = getchar (); if (c == EOF) endOfInput = 1; } } else if (!endOfInput) { ok = 0; fprintf (stderr, " in line #%lu.\n", lineNum); if (!endOfInputLine) { c = getchar (); while (c != EOF && c != '\n') c = getchar (); if (c == EOF) endOfInput = 1; } } } if (ok) { fprintf (stderr, "llfind: Found %lu inside or", inside); fprintf (stderr, " on boundaries out of %lu total.\n", all); } } int main (int argc, char * argv [] ) { int i; if (argc < 2) { for (i = 0; i < NumUsageLines; i++) printf ("%s\n", UsageLines [i] ); } else if ((argc - 1)%2 == 1) printf ("***llfind: must specify number pairs.\n"); else if ((argc - 1) > 0 && BoundariesOk (argc - 1, argv + 1) ) { FindAreaInsideBoundaries (argc - 1, argv + 1); FindLocationsOnOrInsideBoundaries (argc - 1, argv + 1); } return 0; }