Refactored code, integrated base code (DCEL)
This commit is contained in:
parent
aa2690dbd3
commit
b1697a0c30
19 changed files with 1487 additions and 227 deletions
8
Makefile
8
Makefile
|
@ -16,14 +16,14 @@
|
|||
# gcc -Wall -Wextra -Werror -pedantic -g -o main.o main.c -c
|
||||
|
||||
# Link command:
|
||||
voronoi2: common.o geometry.o dcel.o voronoi.o input.o main.o
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o geometry.o common.o
|
||||
voronoi2: common.o towers.o dcel.o voronoi.o input.o main.o
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o towers.o common.o -lm
|
||||
|
||||
common.o: common.c
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c
|
||||
|
||||
geometry.o: geometry.c
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o geometry.o geometry.c -c
|
||||
towers.o: towers.c
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o towers.o towers.c -c
|
||||
|
||||
dcel.o: dcel.c
|
||||
gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c
|
||||
|
|
7
common.h
7
common.h
|
@ -19,6 +19,13 @@
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef MATH_HEADER
|
||||
#define MATH_HEADER
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef COMMON_HEADER
|
||||
#define COMMON_HEADER
|
||||
|
||||
|
|
BIN
common.o
BIN
common.o
Binary file not shown.
253
dcel.h
253
dcel.h
|
@ -1,32 +1,261 @@
|
|||
#ifndef GEOMETRY_HEADER
|
||||
#include "geometry.h"
|
||||
#endif
|
||||
|
||||
#ifndef STDIO_HEADER
|
||||
#include <stdio.h>
|
||||
#ifndef TOWERS_HEADER
|
||||
#include "towers.h"
|
||||
#endif
|
||||
|
||||
#ifndef DCEL_HEADER
|
||||
#define DCEL_HEADER
|
||||
|
||||
typedef struct halfEdge {
|
||||
struct halfEdge *previous;
|
||||
struct halfEdge *next;
|
||||
struct halfEdge *twin;
|
||||
/* Here is the Base Code from Grady, with some alterations by me */
|
||||
|
||||
enum intersectType {
|
||||
DOESNT_INTERSECT = 0, // Doesn't intersect
|
||||
INTERSECT = 1, // Intersects
|
||||
SAME_LINE_OVERLAP = 2, // Lines are the same
|
||||
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
|
||||
};
|
||||
|
||||
typedef struct vertex {
|
||||
double x;
|
||||
double y;
|
||||
} vertex_t;
|
||||
|
||||
typedef struct bisector {
|
||||
double startX;
|
||||
double startY;
|
||||
double endX;
|
||||
double endY;
|
||||
|
||||
/* This refers to the midpoint of the line segment AB, not the midpoint
|
||||
* of the bisector itself.
|
||||
*/
|
||||
double midX;
|
||||
double midY;
|
||||
|
||||
int isSlopeInfinite;
|
||||
double slope;
|
||||
} bisector_t;
|
||||
|
||||
typedef struct halfEdgeLabel {
|
||||
struct halfEdgeLabel *previous;
|
||||
struct halfEdgeLabel *next;
|
||||
struct halfEdgeLabel *twin;
|
||||
int face;
|
||||
int edge;
|
||||
int startVertex;
|
||||
int endVertex;
|
||||
} halfEdge_t;
|
||||
|
||||
typedef struct edge {
|
||||
halfEdge_t halfEdge;
|
||||
halfEdge_t *halfEdge;
|
||||
} edge_t;
|
||||
|
||||
typedef struct face {
|
||||
halfEdge_t start;
|
||||
halfEdge_t *start;
|
||||
tower_t *tower;
|
||||
} face_t;
|
||||
|
||||
typedef struct split {
|
||||
int startEdge;
|
||||
int endEdge;
|
||||
int verticesSpecified;
|
||||
vertex_t startPoint;
|
||||
vertex_t endPoint;
|
||||
} split_t;
|
||||
|
||||
typedef struct intersection {
|
||||
vertex_t intersectionPoint;
|
||||
} intersection_t;
|
||||
|
||||
typedef struct DCEL {
|
||||
edge_t *edges;
|
||||
int edgesUsed;
|
||||
int edgesAllocated;
|
||||
|
||||
face_t *faces;
|
||||
int facesUsed;
|
||||
int facesAllocated;
|
||||
|
||||
vertex_t *vertices;
|
||||
int verticesUsed;
|
||||
int verticesAllocated;
|
||||
} DCEL_t;
|
||||
|
||||
/* Allocate a new DCEL and return it. */
|
||||
DCEL_t *newDCEL();
|
||||
|
||||
/* Allocate a new halfEdge and return it. */
|
||||
halfEdge_t *newHalfEdge();
|
||||
|
||||
/* Returns INSIDE if the points is on the INSIDE of the vector twin by the CW
|
||||
* winding order, OUTSIDE if it is OUTSIDE by the CW winding order, and
|
||||
* DIR_UNDECIDED if the point lies on the vector between the points v1 and v2.
|
||||
*/
|
||||
int getRelativeDir(double x, double y, vertex_t *v1, vertex_t *v2);
|
||||
|
||||
/* Takes an established direction and a new direction, and returns 1 if the
|
||||
* direction matches the decidedDirection or if the direction is undecided.
|
||||
*/
|
||||
int directionOrUndecided(int decidedDirection, int direction);
|
||||
|
||||
/* Check there's space for another vertex in the DCEL,
|
||||
* or increase the allocated space.
|
||||
*/
|
||||
void ensureSpaceForVertex(DCEL_t *dcel);
|
||||
|
||||
/* Check there's space for another edge in the DCEL,
|
||||
* or increase the allocated space.
|
||||
*/
|
||||
void ensureSpaceForEdge(DCEL_t *dcel);
|
||||
|
||||
/* Check there's space for another face in the DCEL,
|
||||
* or increase the allocated space.
|
||||
*/
|
||||
void ensureSpaceForFace(DCEL_t *dcel);
|
||||
|
||||
/* Add an edge from the startVertex index vertex to the endVertex index.
|
||||
* Only fills one half-edge as other half-edges will always be added
|
||||
* through geometry construction.
|
||||
*/
|
||||
void addEdge(DCEL_t *dcel, int startVertex, int endVertex);
|
||||
|
||||
/* Add a face to the DCEL given using the given halfEdge and sets the face. */
|
||||
void addFace(DCEL_t *dcel, halfEdge_t *he);
|
||||
|
||||
/* Reads the polygon from the given file. */
|
||||
DCEL_t *readPolygonFile(char *polygonfileName);
|
||||
|
||||
/* Reads the next split from the given file. */
|
||||
split_t *readNextSplit(FILE *splitfile);
|
||||
|
||||
/* Frees a given split. */
|
||||
void freeSplit(split_t *split);
|
||||
|
||||
/* Returns 1 if vertices are sufficiently close, 0 otherwise. */
|
||||
int vertexMatch(vertex_t *v1, vertex_t *v2);
|
||||
|
||||
/* Gets the string for the given bisector equation. */
|
||||
char *getBisectorEquation(bisector_t *b);
|
||||
|
||||
/* Frees the given bisector. */
|
||||
void freeBisector(bisector_t *bisector);
|
||||
|
||||
/* Representation of no face */
|
||||
#define NOFACE (-1)
|
||||
|
||||
/* Default face for intersections. */
|
||||
#define DEFAULT_FACE 0
|
||||
|
||||
/* Default minimum length for bisector in each direction */
|
||||
#define DEFAULTMINLENGTH (200)
|
||||
|
||||
/* Gets the intersection between the given bisector and the given DCEL
|
||||
* for the given face.
|
||||
*/
|
||||
intersection_t *getIntersection(bisector_t *b, DCEL_t *dcel, \
|
||||
int face, double minLength);
|
||||
|
||||
/* Gets the string for the given intersection. */
|
||||
char *getIntersectionString(intersection_t *intersection);
|
||||
|
||||
/* Frees a given intersection. */
|
||||
void freeIntersection(intersection_t *intersection);
|
||||
|
||||
/* Applies a given split to the DCEL. */
|
||||
void applySplit(split_t *split, DCEL_t *dcel);
|
||||
|
||||
/* Frees the given DCEL */
|
||||
void freeDCEL(DCEL_t *dcel);
|
||||
|
||||
/* Gets the number of faces in the DCEL. */
|
||||
int getFaceCount(DCEL_t *dcel);
|
||||
|
||||
/* Returns 1 if the given x,y point is inside the given face. */
|
||||
int inFace(DCEL_t *dcel, double x, double y, int faceIndex);
|
||||
|
||||
/* Gets the diameter of the given face. */
|
||||
double getDiameter(DCEL_t *dcel, int faceIndex);
|
||||
|
||||
/* Adds the watchtower to the Voronoi diagram represented by the given DCEL,
|
||||
* applying required splits and setting the watchtower as required.
|
||||
*/
|
||||
void incrementalVoronoi(DCEL_t *dcel, tower_t *watchTower);
|
||||
|
||||
/* Returns the number of vertices in the DCEL. */
|
||||
int getDCELPointCount(DCEL_t *dcel);
|
||||
|
||||
/* Get x value of given vertex in DCEL. */
|
||||
double getDCELVertexX(DCEL_t *dcel, int vertex);
|
||||
|
||||
/* Get y value of given vertex in DCEL. */
|
||||
double getDCELVertexY(DCEL_t *dcel, int vertex);
|
||||
|
||||
/* Returns the number of edges in the DCEL. */
|
||||
int getDCELEdgeCount(DCEL_t *dcel);
|
||||
|
||||
/* Get start vertex of given edge in DCEL. */
|
||||
int getDCELEdgeVertexStart(DCEL_t *dcel, int edge);
|
||||
|
||||
/* Get end vertex of given edge in DCEL. */
|
||||
int getDCELEdgeVertexEnd(DCEL_t *dcel, int edge);
|
||||
|
||||
/* Get start vertex of paired given edge in DCEL. */
|
||||
int getDCELEdgeVertexPairStart(DCEL_t *dcel, int edge);
|
||||
|
||||
/* Get end vertex of paired given edge in DCEL. */
|
||||
int getDCELEdgeVertexPairEnd(DCEL_t *dcel, int edge);
|
||||
|
||||
/* Check if the DCEL has the given edge. */
|
||||
int DCELhasEdge(DCEL_t *dcel, int edge);
|
||||
|
||||
/* Check if the DCEL has a pair for the given edge. */
|
||||
int DCELhasEdgePair(DCEL_t *dcel, int edge);
|
||||
|
||||
/* My own functions */
|
||||
|
||||
/* Reads the polygon file and stores the information in the vertices array */
|
||||
vertex_t **readPolygon(vertex_t **vertices, FILE *polygonFile, \
|
||||
int *numVertices);
|
||||
|
||||
/* Frees an array of vertices */
|
||||
void freeVertices(vertex_t **vertices, int numVertices);
|
||||
|
||||
/* Calculates and returns the equation of a bisector of two points */
|
||||
bisector_t *getBisector(vertex_t *pointA, vertex_t *pointB);
|
||||
|
||||
/* Euclidian distance between two 2D points */
|
||||
double dist_2D(double x1, double y1, double x2, double y2);
|
||||
|
||||
/* Returns a value for x that ensures the point (x, y) is at least d (distance)
|
||||
* away from (x1, y1) whilst ensuring (x, y) is on the line y = mx + c1.
|
||||
*/
|
||||
double inv_dist_2D(double x1, double y1, double m, double c, double d);
|
||||
|
||||
/* Returns a point at least distance away from the midpoint of the bisector given */
|
||||
vertex_t *getBisectorPoint(double distance, bisector_t *b);
|
||||
|
||||
/* O'Rourke's functions */
|
||||
/* Returns -1, 0 or 1, based on the area enclosed by the three points. 0 corresponds
|
||||
to no area enclosed.
|
||||
*/
|
||||
int areaSign(double sx, double sy, double ex, double ey, double x, double y);
|
||||
|
||||
/* Returns 1 if point (x, y) is between (sx, sy) and (ex, ey) */
|
||||
int between(double sx, double sy, double ex, double ey, double x, double y);
|
||||
|
||||
/* Returns 1 if the point (x, y) is in the line from s(x, y) to e(x, y),
|
||||
* 0 otherwise.
|
||||
*/
|
||||
int collinear(double sx, double sy, double ex, double ey, double x, double y);
|
||||
|
||||
/* Tests if the half edge and bisector are parallel and overlapping, or not
|
||||
* intersecting.
|
||||
*/
|
||||
enum intersectType parallelIntersects(double heSx, double heSy, \
|
||||
double heEx, double heEy, double bSx, double bSy, \
|
||||
double bEx, double bEy, double *x, double *y);
|
||||
|
||||
/* Tests if */
|
||||
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
|
||||
DCEL_t *dcel, double minLength, double *x, double *y);
|
||||
|
||||
#endif
|
||||
|
|
BIN
dcel.o
BIN
dcel.o
Binary file not shown.
56
geometry.c
56
geometry.c
|
@ -1,56 +0,0 @@
|
|||
/* geometry.c
|
||||
*
|
||||
* Created by Rory Healy (healyr@student.unimelb.edu.au)
|
||||
* Created on 9th September 2021
|
||||
* Last modified 9th September 2021
|
||||
*
|
||||
* A small library of functions used in the geometric construction of a
|
||||
* Voronoi diagram.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_HEADER
|
||||
#include "geometry.h"
|
||||
#endif
|
||||
|
||||
#ifndef COMMON_HEADER
|
||||
#include "common.h"
|
||||
#endif
|
||||
|
||||
bisector_t getBisector(vertex_t *pointA, vertex_t *pointB) {
|
||||
bisector_t newBisector;
|
||||
double midpointX = (pointA->x + pointB->x) / 2;
|
||||
double midpointY = (pointA->y + pointB->y) / 2;
|
||||
|
||||
newBisector.x = midpointX;
|
||||
newBisector.y = midpointY;
|
||||
|
||||
/* Calculating bisector slope according to slope of AB */
|
||||
if (pointA->x == pointB->x) {
|
||||
/* The line segment AB has an infinite gradient,
|
||||
* so the orthogonal line will have zero slope.
|
||||
*/
|
||||
newBisector.slope = 0;
|
||||
newBisector.isSlopeInfinite = 0;
|
||||
} else if (pointA->y == pointB->y) {
|
||||
/* The line segment AB has gradient of zero, so
|
||||
* the orthogonal line will have an infinite slope.
|
||||
*/
|
||||
newBisector.isSlopeInfinite = 1;
|
||||
|
||||
/* Not actually zero, just a placeholder to prevent
|
||||
* accidental errors
|
||||
*/
|
||||
newBisector.slope = 0;
|
||||
} else {
|
||||
/* Slope of the line segment AB */
|
||||
double segmentSlope = \
|
||||
(pointB->y - pointA->y) / (pointB->x - pointA->x);
|
||||
|
||||
/* Calculate orthogonal slope */
|
||||
newBisector.isSlopeInfinite = 0;
|
||||
newBisector.slope = -1 / segmentSlope;
|
||||
}
|
||||
|
||||
return newBisector;
|
||||
}
|
19
geometry.h
19
geometry.h
|
@ -1,19 +0,0 @@
|
|||
#ifndef GEOMETRY_HEADER
|
||||
#define GEOMETRY_HEADER
|
||||
|
||||
typedef struct vertex {
|
||||
double x;
|
||||
double y;
|
||||
} vertex_t;
|
||||
|
||||
typedef struct bisector {
|
||||
int isSlopeInfinite;
|
||||
double slope;
|
||||
double x;
|
||||
double y;
|
||||
} bisector_t;
|
||||
|
||||
/* Calculates and returns the equation of a bisector of two points */
|
||||
bisector_t getBisector(vertex_t *vertexA, vertex_t *vertexB);
|
||||
|
||||
#endif
|
BIN
geometry.o
BIN
geometry.o
Binary file not shown.
BIN
input.o
BIN
input.o
Binary file not shown.
BIN
main.o
BIN
main.o
Binary file not shown.
|
@ -1,6 +0,0 @@
|
|||
y = 0.000000 * (x - 145.600000) + -34.700000
|
||||
y = 0.000000 * (x - 145.600000) + -35.200000
|
||||
x = 147.100000
|
||||
x = 147.100000
|
||||
x = 147.600000
|
||||
y = 1.000000 * (x - 147.600000) + -33.200000
|
97
towers.c
Normal file
97
towers.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
|
||||
|
||||
#ifndef TOWERS_HEADER
|
||||
#include "towers.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);
|
||||
}
|
26
towers.h
Normal file
26
towers.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COMMON_HEADER
|
||||
#include "common.h"
|
||||
#endif
|
||||
|
||||
#ifndef TOWERS_HEADER
|
||||
#define TOWERS_HEADER
|
||||
|
||||
typedef struct tower {
|
||||
char *id;
|
||||
char *postcode;
|
||||
char *manager;
|
||||
int population;
|
||||
double x;
|
||||
double y;
|
||||
} tower_t;
|
||||
|
||||
/* Reads the CSV file and stores the information in the towers array */
|
||||
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers);
|
||||
|
||||
/* Reads the current row from the CSV and converts it into a new tower */
|
||||
void readCurrentTower(char *lineBuffer, tower_t *tower);
|
||||
|
||||
/* Frees all towers in a towers array */
|
||||
void freeTowers(tower_t **towers, int numTowers);
|
||||
|
||||
#endif
|
BIN
towers.o
Normal file
BIN
towers.o
Normal file
Binary file not shown.
138
voronoi.c
138
voronoi.c
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Created by Rory Healy (healyr@student.unimelb.edu.au)
|
||||
* Created on 12th August 2021
|
||||
* Last modified 9th September 2021
|
||||
* Last modified 11th September 2021
|
||||
*
|
||||
* Contains functions involving the generation of the Voronoi diagram, and
|
||||
* running each stage of the assignment.
|
||||
|
@ -17,101 +17,9 @@
|
|||
#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;
|
||||
/* Initial size of buffer is 1 as getline() reallocs as needed */
|
||||
size_t lineBufferSize = 1;
|
||||
|
||||
/* Stores the current line from the points file */
|
||||
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
|
||||
|
@ -148,6 +56,16 @@ vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
|
|||
return points;
|
||||
}
|
||||
|
||||
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) {
|
||||
if (bisector->isSlopeInfinite) {
|
||||
/* Cannot print infinite slope, so print only x-intercept */
|
||||
fprintf(outputFile, "x = %lf\n", bisector->midX);
|
||||
} else {
|
||||
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
|
||||
bisector->slope, bisector->midX, bisector->midY);
|
||||
}
|
||||
}
|
||||
|
||||
void freePoints(vertex_t **points, int numPoints) {
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
free(points[i]);
|
||||
|
@ -168,17 +86,12 @@ void stage1(char *pointsFileName, char *outputFileName) {
|
|||
|
||||
/* 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);
|
||||
}
|
||||
bisector_t *currBisector = getBisector(points[i], points[i + 1]);
|
||||
stage1PrintBisector(currBisector, outputFile);
|
||||
free(currBisector);
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
freePoints(points, numPoints);
|
||||
fclose(pointsFile);
|
||||
fclose(outputFile);
|
||||
|
@ -190,8 +103,21 @@ void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
|
|||
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "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);
|
||||
|
||||
/* Construct the DCEL from the polygon file */
|
||||
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
||||
|
||||
/* Calculate and print intersections to the output file */
|
||||
|
||||
|
||||
/* Clean up */
|
||||
freePoints(points, numPoints);
|
||||
freeDCEL(dcel);
|
||||
fclose(pointsFile);
|
||||
fclose(polygonFile);
|
||||
fclose(outputFile);
|
||||
|
@ -205,6 +131,7 @@ void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
|||
|
||||
|
||||
|
||||
/* Clean up */
|
||||
fclose(dataFile);
|
||||
fclose(polygonFile);
|
||||
fclose(outputFile);
|
||||
|
@ -217,7 +144,8 @@ void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
|||
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
||||
|
||||
|
||||
|
||||
|
||||
/* Clean up */
|
||||
fclose(dataFile);
|
||||
fclose(polygonFile);
|
||||
fclose(outputFile);
|
||||
|
|
21
voronoi.h
21
voronoi.h
|
@ -5,27 +5,12 @@
|
|||
#ifndef VORONOI_HEADER
|
||||
#define VORONOI_HEADER
|
||||
|
||||
typedef struct tower {
|
||||
char *id;
|
||||
char *postcode;
|
||||
char *manager;
|
||||
int population;
|
||||
double x;
|
||||
double y;
|
||||
} tower_t;
|
||||
|
||||
/* Reads the CSV file and stores the information in the towers array */
|
||||
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers);
|
||||
|
||||
/* Reads the current row from the CSV and converts it into a new tower */
|
||||
void readCurrentTower(char *lineBuffer, tower_t *tower);
|
||||
|
||||
/* Frees all towers in a towers array */
|
||||
void freeTowers(tower_t **towers, int numTowers);
|
||||
|
||||
/* Reads a points file and stores the information in the points array */
|
||||
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
|
||||
|
||||
/* Prints bisectors to an output file */
|
||||
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile);
|
||||
|
||||
/* Frees all points from a points array */
|
||||
void freePoints(vertex_t **points, int numPoints);
|
||||
|
||||
|
|
BIN
voronoi.o
BIN
voronoi.o
Binary file not shown.
BIN
voronoi2
BIN
voronoi2
Binary file not shown.
Loading…
Reference in a new issue