CS-PROJECTS / c08_gis_system / GISParse.c
GISParse.c
Raw
#include "arrayList.h"
#include "StringHashTable.h"
#include "nextField.h"
#include "GISParse.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define MAX_LINE_LENGTH 500
#define PI 3.14159265358979323846
#define RADIUS 6371.0088

/**
 * Combines both name and state to create one string in order to
 * pass that new string into a the hastable as a key
 */
char *create_key(char *name, char *state)
{
    char *key = calloc(strlen(name) + strlen(state) + 1, sizeof(char));
    strcpy(key, name);
    strcpy(key + strlen(name), state);

    return key;
}

char *get_name_and_state(char *line)
{
    int i = -1;
    char *name, *state, *temp;

    while (++i < 4)
    {
        switch (i)
        {
        case 0:;
            temp = nextField(line);
            break;
        case 1:;
            name = nextField(NULL);
            break;
        case 3:;
            state = nextField(NULL);
            break;
        default:
            temp = nextField(NULL);
            break;
        }
    }

    free(temp);

    return create_key(name, state);
}

/**
 * Given an array of offsets, this method retrives the
 * first 5 fields of each record at the specified offset
 */
char **get_details_of(FILE *gis, uint32_t offset)
{
    char **details = calloc(9, sizeof(char *)),
         *line = calloc(MAX_LINE_LENGTH + 1, sizeof(char)),
         *f = NULL;

    fseek(gis, offset, SEEK_SET);
    fgets(line, MAX_LINE_LENGTH + 1, gis);
    int x = -1, i = 0;

    while (++x < 11)
    {
        if (x == 0)
            details[i++] = nextField(line);
        else if (x < 4 || x == 5 || x >= 7)
            details[i++] = nextField(NULL);
        else
            f = nextField(NULL);
    }

    free(line);
    free(f);
    return details;
}

/**
 * Gets the longitude and lattitude field of a record at a
 * specified offset
 */
char **get_dec_lat_and_long(uint32_t offset, FILE *gis)
{
    char **lat_and_long = calloc(2, sizeof(char *)),
         *line = calloc(MAX_LINE_LENGTH + 1, sizeof(char)),
         *f = NULL;

    fseek(gis, offset, SEEK_SET);
    fgets(line, MAX_LINE_LENGTH + 1, gis);

    int x = -1, i = 0;
    while (++x < 11)
    {
        if (x == 0)
            f = nextField(line);
        else if (x >= 9)
            lat_and_long[i++] = nextField(NULL);
        else
            f = nextField(NULL);
    }

    free(line);
    free(f);
    return lat_and_long;
}

/**
 * Alters the string of longitude or lattitude
 * found within the GIS file to the desired format
 * as specified within the documentation
 */
char **get_readable_lat_and_long(uint32_t offset, FILE *gis)
{
    char **dms = calloc(10, sizeof(char *)),
         *line = calloc(MAX_LINE_LENGTH + 1, sizeof(char)),
         *f = NULL;

    fseek(gis, offset, SEEK_SET);
    fgets(line, MAX_LINE_LENGTH + 1, gis);

    int x = -1, i = 0;
    while (++x < 11)
    {
        if (x == 0)
            f = nextField(line);
        else if (x == 1 || x == 3)
            dms[i++] = nextField(NULL);
        else if (x == 7)
        {
            f = nextField(NULL);

            char *d = calloc(3, sizeof(char)),
                 *m = calloc(3, sizeof(char)),
                 *s = calloc(3, sizeof(char)),
                 *dir = calloc(6, sizeof(char));

            strncpy(d, f, 2);
            strncpy(m, f + 2, 2);
            strncpy(s, f + 4, 2);
            strncpy(dir, f + 6, 1);

            if (!(strcmp(dir, "N")))
                dir = "North";
            else
                dir = "South";

            dms[2] = d;
            dms[3] = m;
            dms[4] = s;
            dms[5] = dir;
        }
        else if (x == 8)
        {
            f = nextField(NULL);

            char *d = calloc(4, sizeof(char)),
                 *m = calloc(3, sizeof(char)),
                 *s = calloc(3, sizeof(char)),
                 *dir = calloc(5, sizeof(char));

            strncpy(d, f, 3);
            strncpy(m, f + 3, 2);
            strncpy(s, f + 5, 2);
            strncpy(dir, f + 7, 1);

            if (!(strcmp(dir, "W")))
                dir = "West";
            else
                dir = "East";

            dms[6] = d;
            dms[7] = m;
            dms[8] = s;
            dms[9] = dir;
        }
        else
            f = nextField(NULL);
    }

    free(line);
    free(f);
    return dms;
}

/**
 * Calculates the distance between 2 records when
 * given the offset of both records
 */
double find_distance_between(uint32_t offset1, uint32_t offset2, FILE *gis)
{
    char **d1 = get_dec_lat_and_long(offset1, gis),
         **d2 = get_dec_lat_and_long(offset2, gis);

    double lat1 = atof(d1[0]) * (PI / 180.0),
           lat2 = atof(d2[0]) * (PI / 180.0),

           long1 = atof(d1[1]),
           long2 = atof(d2[1]),

           centralAngle = acos((sin(lat1) * sin(lat2)) + (cos(lat1) * cos(lat2) * cos((long2 - long1) * (PI / 180.0)))),
           distance = ((RADIUS * centralAngle));

    free(d1);
    free(d2);

    return distance;
}