comp20003-project02/voronoi.c
2021-09-09 21:23:53 +10:00

224 lines
7.2 KiB
C

/* voronoi.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 12th August 2021
* Last modified 9th September 2021
*
* Contains functions involving the generation of the Voronoi diagram, and
* running each stage of the assignment.
*
*/
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef VORONOI_HEADER
#include "voronoi.h"
#endif
#define BASE_10 10
#define MAX_CSV_ENTRY_LEN 512
#define MAX_FIELD_LEN 128
#define NUM_CSV_FIELDS 6
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
/* Maximum length of a single CSV line */
size_t lineBufferSize = MAX_CSV_ENTRY_LEN + 1;
/* Stores the current line from the CSV */
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
checkNullPointer(lineBuffer);
int maxSizetowers = 1;
/* Discard the header line, then read the rest of the CSV */
getline(&lineBuffer, &lineBufferSize, datasetFile);
while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) {
/* Check if there enough space in the towers array */
if (*numTowers == maxSizetowers) {
maxSizetowers *= 2;
tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers));
checkNullPointer(temp);
towers = temp;
}
/* The current tower being filled in with information */
towers[*numTowers] = malloc(sizeof(*towers[*numTowers]));
readCurrentTower(lineBuffer, towers[*numTowers]);
*numTowers += 1;
}
free(lineBuffer);
return towers;
}
void readCurrentTower(char *lineBuffer, tower_t *tower) {
/* Stores the current CSV field for the current line */
char *token = strtok(lineBuffer, ",");
size_t tokenLength;
for (int i = 0; i < NUM_CSV_FIELDS; i++) {
tokenLength = strlen(token);
switch(i) {
/* Case 0, 1, and 3 deal with strings
* Case 2 deals with an integer
* Case 4 and 5 deal with doubles
* Each case is handled seperately to fill in the
* tower with no space wasted.
*/
case 0:
tower->id = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->id);
strcpy(tower->id, token);
tower->id[tokenLength] = '\0';
break;
case 1:
tower->postcode = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->postcode);
strcpy(tower->postcode, token);
tower->postcode[tokenLength] = '\0';
break;
case 2:
tower->population = strtol(token, NULL, BASE_10);
break;
case 3:
tower->manager = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->manager);
strcpy(tower->manager, token);
tower->manager[tokenLength] = '\0';
break;
case 4:
tower->x = strtod(token, NULL);
break;
case 5:
tower->y = strtod(token, NULL);
break;
}
token = strtok(NULL, ",");
}
}
void freeTowers(tower_t **towers, int numTowers) {
for (int i = 0; i < numTowers; i++) {
free(towers[i]->id);
free(towers[i]->manager);
free(towers[i]->postcode);
free(towers[i]);
}
free(towers);
}
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
/* Current length of a single points line */
size_t lineBufferSize = 50;
/* Stores the current line from the points file */
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
checkNullPointer(lineBuffer);
/* Assuming that pointsFile is valid, there must be at least two points */
int maxSizePoints = 2;
while (getline(&lineBuffer, &lineBufferSize, pointsFile) > 0) {
/* Check if there is enough space in the points array */
if (*numPoints == maxSizePoints) {
maxSizePoints *= 2;
vertex_t **temp = realloc(points, maxSizePoints * sizeof(*points));
checkNullPointer(temp);
points = temp;
}
double xCoordinateA, yCoordinateA, xCoordinateB, yCoordinateB;
sscanf(lineBuffer, "%lf %lf %lf %lf", &xCoordinateA, &yCoordinateA, \
&xCoordinateB, &yCoordinateB);
points[*numPoints] = malloc(sizeof(*points[*numPoints]));
points[*numPoints]->x = xCoordinateA;
points[*numPoints]->y = yCoordinateA;
*numPoints += 1;
points[*numPoints] = malloc(sizeof(*points[*numPoints]));
points[*numPoints]->x = xCoordinateB;
points[*numPoints]->y = yCoordinateB;
*numPoints += 1;
}
free(lineBuffer);
return points;
}
void freePoints(vertex_t **points, int numPoints) {
for (int i = 0; i < numPoints; i++) {
free(points[i]);
}
free(points);
}
void stage1(char *pointsFileName, char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Points are given as pairs, so initialise 2 points */
vertex_t **points = malloc(sizeof(*points) * 2);
checkNullPointer(points);
int numPoints = 0;
points = readPoints(points, pointsFile, &numPoints);
/* For each pair, calculate and print the bisector to outputFile */
for (int i = 0; i < numPoints; i += 2) {
bisector_t currBisector = getBisector(points[i], points[i + 1]);
/* Cannot print infinite slope, so print only x-intercept */
if (currBisector.isSlopeInfinite) {
fprintf(outputFile, "x = %lf\n", currBisector.x);
} else {
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
currBisector.slope, currBisector.x, currBisector.y);
}
}
freePoints(points, numPoints);
fclose(pointsFile);
fclose(outputFile);
}
void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
FILE *pointsFile = NULL, *polygonFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
fclose(pointsFile);
fclose(polygonFile);
fclose(outputFile);
}
void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}
void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}