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
|
# gcc -Wall -Wextra -Werror -pedantic -g -o main.o main.c -c
|
||||||
|
|
||||||
# Link command:
|
# Link command:
|
||||||
voronoi2: common.o geometry.o dcel.o voronoi.o input.o main.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 geometry.o common.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
|
common.o: common.c
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c
|
gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c
|
||||||
|
|
||||||
geometry.o: geometry.c
|
towers.o: towers.c
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o geometry.o geometry.c -c
|
gcc -Wall -Wextra -Werror -pedantic -g -o towers.o towers.c -c
|
||||||
|
|
||||||
dcel.o: dcel.c
|
dcel.o: dcel.c
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c
|
gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c
|
||||||
|
|
7
common.h
7
common.h
|
@ -19,6 +19,13 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MATH_HEADER
|
||||||
|
#define MATH_HEADER
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef COMMON_HEADER
|
#ifndef COMMON_HEADER
|
||||||
#define 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
|
#ifndef TOWERS_HEADER
|
||||||
#include "geometry.h"
|
#include "towers.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STDIO_HEADER
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DCEL_HEADER
|
#ifndef DCEL_HEADER
|
||||||
#define DCEL_HEADER
|
#define DCEL_HEADER
|
||||||
|
|
||||||
typedef struct halfEdge {
|
/* Here is the Base Code from Grady, with some alterations by me */
|
||||||
struct halfEdge *previous;
|
|
||||||
struct halfEdge *next;
|
enum intersectType {
|
||||||
struct halfEdge *twin;
|
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 face;
|
||||||
int edge;
|
int edge;
|
||||||
|
int startVertex;
|
||||||
|
int endVertex;
|
||||||
} halfEdge_t;
|
} halfEdge_t;
|
||||||
|
|
||||||
typedef struct edge {
|
typedef struct edge {
|
||||||
halfEdge_t halfEdge;
|
halfEdge_t *halfEdge;
|
||||||
} edge_t;
|
} edge_t;
|
||||||
|
|
||||||
typedef struct face {
|
typedef struct face {
|
||||||
halfEdge_t start;
|
halfEdge_t *start;
|
||||||
|
tower_t *tower;
|
||||||
} face_t;
|
} 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, \
|
vertex_t **readPolygon(vertex_t **vertices, FILE *polygonFile, \
|
||||||
int *numVertices);
|
int *numVertices);
|
||||||
|
|
||||||
|
/* Frees an array of vertices */
|
||||||
void freeVertices(vertex_t **vertices, int numVertices);
|
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
|
#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 by Rory Healy (healyr@student.unimelb.edu.au)
|
||||||
* Created on 12th August 2021
|
* 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
|
* Contains functions involving the generation of the Voronoi diagram, and
|
||||||
* running each stage of the assignment.
|
* running each stage of the assignment.
|
||||||
|
@ -17,101 +17,9 @@
|
||||||
#include "voronoi.h"
|
#include "voronoi.h"
|
||||||
#endif
|
#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) {
|
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
|
||||||
/* Current length of a single points line */
|
/* Initial size of buffer is 1 as getline() reallocs as needed */
|
||||||
size_t lineBufferSize = 50;
|
size_t lineBufferSize = 1;
|
||||||
|
|
||||||
/* Stores the current line from the points file */
|
/* Stores the current line from the points file */
|
||||||
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
|
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
|
||||||
|
@ -148,6 +56,16 @@ vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
|
||||||
return points;
|
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) {
|
void freePoints(vertex_t **points, int numPoints) {
|
||||||
for (int i = 0; i < numPoints; i++) {
|
for (int i = 0; i < numPoints; i++) {
|
||||||
free(points[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 each pair, calculate and print the bisector to outputFile */
|
||||||
for (int i = 0; i < numPoints; i += 2) {
|
for (int i = 0; i < numPoints; i += 2) {
|
||||||
bisector_t currBisector = getBisector(points[i], points[i + 1]);
|
bisector_t *currBisector = getBisector(points[i], points[i + 1]);
|
||||||
|
stage1PrintBisector(currBisector, outputFile);
|
||||||
/* Cannot print infinite slope, so print only x-intercept */
|
free(currBisector);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
freePoints(points, numPoints);
|
freePoints(points, numPoints);
|
||||||
fclose(pointsFile);
|
fclose(pointsFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
|
@ -190,8 +103,21 @@ void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
|
||||||
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
|
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
|
||||||
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
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(pointsFile);
|
||||||
fclose(polygonFile);
|
fclose(polygonFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
|
@ -205,6 +131,7 @@ void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
fclose(dataFile);
|
fclose(dataFile);
|
||||||
fclose(polygonFile);
|
fclose(polygonFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
|
@ -217,7 +144,8 @@ void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
||||||
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
fclose(dataFile);
|
fclose(dataFile);
|
||||||
fclose(polygonFile);
|
fclose(polygonFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
|
|
21
voronoi.h
21
voronoi.h
|
@ -5,27 +5,12 @@
|
||||||
#ifndef VORONOI_HEADER
|
#ifndef VORONOI_HEADER
|
||||||
#define 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 */
|
/* Reads a points file and stores the information in the points array */
|
||||||
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
|
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 */
|
/* Frees all points from a points array */
|
||||||
void freePoints(vertex_t **points, int numPoints);
|
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