Final submission

This commit is contained in:
Rory Healy 2021-09-15 00:06:04 +10:00
parent 11b8feaa6e
commit d552f37321
21 changed files with 966 additions and 544 deletions

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"files.associations": {
"type_traits": "c"
}
}

View file

@ -1,6 +1,6 @@
# Link command:
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
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o towers.o common.o -lm
# Compilation commands
common.o: common.c

0
README.md Normal file → Executable file
View file

View file

@ -2,9 +2,9 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 9th September 2021
* Last modified 14th September 2021
*
* Contains functions for general use throughout other files.
* Contains functions and headers for general use throughout other files.
*
*/

860
dcel.c
View file

@ -2,10 +2,10 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 13th September 2021
* Last modified 14th September 2021
*
* Contains functions for the DCEL data structure, including initialisation,
* splitting an edge, and identifying towers in faces.
* Contains functions for the DCEL data structure and related data structures
* (including points, intersections, and bisectors).
*
* Contains several functions and structures from Grady Fitzpatrick's Base
* Code on the Ed Discussion Forum.
@ -16,106 +16,29 @@
#include "dcel.h"
#endif
void freePoints(vertex_t **points, int numPoints) {
for (int i = 0; i < numPoints; i++) {
free(points[i]);
}
free(points);
#define INITIALVERTICES 4
#define INITIALEDGES 4
#define INITIALFACES 1
#define NOVERTEX (-1)
#define NOEDGE (-1)
#define DIR_UNDECIDED (0)
#define INSIDE (1)
#define OUTSIDE (-1)
#define NODIAMETER (-1)
/* ----------------------- My points functions start ----------------------- */
vertex_t *newPoint() {
vertex_t *newPoint = malloc(sizeof(*newPoint));
checkNullPointer(newPoint);
return newPoint;
}
void freeBisectors(bisector_t **bisectors, int numBisectors) {
for (int i = 0; i < numBisectors; i++) {
free(bisectors[i]->mid);
free(bisectors[i]);
}
free(bisectors);
}
void freeIntersections(intersection_t **intersections, int numIntersections) {
for (int i = 0; i < numIntersections; i++) {
free(intersections[i]->fromPoint);
free(intersections[i]->toPoint);
free(intersections[i]);
}
free(intersections);
}
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numBisectors) {
for (int i = 0; i < numBisectors; i++) {
bisectors[i] = malloc(sizeof(*bisectors[i]));
bisectors[i]->mid = malloc(sizeof(*bisectors[i]->mid));
/* Calculate midpoint of the two points */
bisectors[i]->mid->x = (points[2 * i]->x + points[2 * i + 1]->x) / 2;
bisectors[i]->mid->y = (points[2 * i]->y + points[2 * i + 1]->y) / 2;
/* Calculating bisector slope according to slope of AB */
if (points[2 * i]->x == points[2 * i + 1]->x) {
/* The line segment AB has an infinite gradient,
* so the orthogonal line will have zero slope.
*/
bisectors[i]->slope = 0;
bisectors[i]->isSlopeInfinite = 0;
} else if (points[2 * i]->y == points[2 * i + 1]->y) {
/* The line segment AB has gradient of zero, so
* the orthogonal line will have an infinite slope.
*/
bisectors[i]->isSlopeInfinite = 1;
/* Not actually zero, just a placeholder to prevent
* accidental errors
*/
bisectors[i]->slope = 0;
} else {
/* The line segment AB has a non-zero and finite gradient,
* so the gradient of the bisector can be calculated.
*/
bisectors[i]->isSlopeInfinite = 0;
bisectors[i]->slope = -1 / \
((points[2 * i + 1]->y - points[2 * i]->y) / \
(points[2 * i + 1]->x - points[2 * i]->x));
}
}
return bisectors;
}
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction) {
vertex_t *returnPoint = malloc(sizeof(*returnPoint));
if (b->isSlopeInfinite) {
/* Vertical line - just add vertical distance */
returnPoint->x = b->mid->x;
returnPoint->y = b->mid->y + (distance * direction);
} else if (b->slope == 0) {
/* Horizontal line - just add horizontal distance */
returnPoint->x = b->mid->x + (distance * direction);
returnPoint->y = b->mid->y;
} else {
/* Not horizontal or vertical - add distance to x, then find
* y-intercept of the bisector, and plug it in to y = mx + c to find
* the corresponding y-value.
*/
double c = b->mid->y - b->slope * b->mid->x;
returnPoint->x = b->mid->x + (distance * direction);
returnPoint->y = b->slope * returnPoint->x + c;
}
return returnPoint;
}
intersection_t *newIntersection() {
intersection_t *intersection = malloc(sizeof(*intersection));
checkNullPointer(intersection);
intersection->fromPoint = malloc(sizeof(*intersection->fromPoint));
checkNullPointer(intersection->fromPoint);
intersection->toPoint = malloc(sizeof(*intersection->toPoint));
checkNullPointer(intersection->toPoint);
return intersection;
vertex_t *getAPoint(double x, double y) {
vertex_t *point = newPoint();
point->x = x;
point->y = y;
return point;
}
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
@ -157,225 +80,303 @@ vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) {
return points;
}
/* Here on out is the base code from Grady, with some alterations from me */
#define INITIALVERTICES 4
#define INITIALEDGES 4
#define INITIALFACES 1
#define NOVERTEX (-1)
#define NOEDGE (-1)
#define DIR_UNDECIDED (0)
#define INSIDE (1)
#define OUTSIDE (-1)
#define NODIAMETER (-1)
/*
This intersection is based on code by Joseph O'Rourke and is provided for use in
COMP20003 Assignment 2.
The approach for intersections is:
- Use the bisector to construct a finite segment and test it against the half-edge.
- Use O'Rourke's segseg intersection
(https://hydra.smith.edu/~jorourke/books/ftp.html)
to check if the values overlap/intersect
Generates a segment with each end at least minLength away in each direction
from the bisector midpoint.
Returns 1 if b intersects the given half-edge on this segment, 0 otherwise.
Sets the intersection point to the given x, y positions.
*/
int areaSign(double sx, double sy, double ex, double ey, double x, double y) {
double areaSq;
/* |AB x AC|^2, squared area */
/* See https://mathworld.wolfram.com/CrossProduct.html */
areaSq = (ex - sx) * (y - sy) -
(x - sx) * (ey - sy);
if (areaSq > 0.0) {
return 1;
} else if (areaSq == 0.0) {
return 0;
} else {
return -1;
void freePoints(vertex_t **points, int numPoints) {
if (!points) {
return;
}
for (int i = 0; i < numPoints; i++) {
if (points[i]) {
free(points[i]);
}
}
free(points);
}
int between(double sx, double sy, double ex, double ey, double x, double y) {
if (sx != ex) {
/* If not vertical, check whether between x. */
if ((sx <= x && x <= ex) || (sx >= x && x >= ex)) {
return 1;
} else {
return 0;
}
} else {
/* Vertical, so can't check _between_ x-values. Check y-axis. */
if ((sy <= y && y <= ey) || (sy >= y && y >= ey)) {
return 1;
} else {
return 0;
}
}
double distPoints(vertex_t *pointA, vertex_t *pointB) {
double a = pointB->x - pointA->x;
double b = pointB->y - pointA->y;
return sqrt(a * a + b * b);
}
int collinear(double sx, double sy, double ex, double ey, double x, double y) {
/* If area of the parallelogram is 0, then the points
* are in the same line.
*/
if (areaSign(sx, sy, ex, ey, x, y) == 0) {
return 1;
/* ------------------------ My points functions end ------------------------ */
/* -------------------- My intersection functions start -------------------- */
intersection_t *newIntersection() {
intersection_t *intersection = malloc(sizeof(*intersection));
checkNullPointer(intersection);
intersection->fromPoint = malloc(sizeof(*intersection->fromPoint));
checkNullPointer(intersection->fromPoint);
intersection->toPoint = malloc(sizeof(*intersection->toPoint));
checkNullPointer(intersection->toPoint);
return intersection;
}
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
bisector_t *bisector, int face, int minLength) {
/* Intersection coordinates */
double x, y;
/* Flag is raised when first intersection is found */
int isIntersectionFound = 0;
halfEdge_t *startHE = (dcel->faces)[face].start;
halfEdge_t *currentHE = startHE;
int startVertex = startHE->startVertex;
int first = 1;
/* Loop through the face until the starting vertex is reached */
while (first || currentHE->startVertex != startVertex) {
enum intersectType typeOfIntersection = \
intersects(currentHE, bisector, dcel, minLength, &x, &y);
switch (typeOfIntersection) {
case INTERSECT:
case SAME_LINE_OVERLAP:
case ENDS_OVERLAP:
if (!isIntersectionFound) {
/* First point of intersection */
isIntersectionFound = 1;
intersection = newIntersection();
intersection->fromPoint->x = x;
intersection->fromPoint->y = y;
intersection->fromEdge = currentHE->edge;
} else {
return 0;
/* Second point of intersection */
intersection->toPoint->x = x;
intersection->toPoint->y = y;
intersection->toEdge = currentHE->edge;
}
break;
case DOESNT_INTERSECT:
default:
break;
}
currentHE = currentHE->next;
first = 0;
}
return intersection;
}
enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \
double bEx, double bEy, double *x, double *y) {
if (!collinear(heSx, heSy, heEx, heEy, bSx, bSy)) {
/* Parallel, no intersection so don't set (x, y) */
return DOESNT_INTERSECT;
}
/* bS between heS and heE */
if (between(heSx, heSy, heEx, heEy, bSx, bSy)) {
*x = bSx;
*y = bSy;
return SAME_LINE_OVERLAP;
}
/* bE between heS and heE */
if (between(heSx, heSy, heEx, heEy, bEx, bEy)) {
*x = bEx;
*y = bEy;
return SAME_LINE_OVERLAP;
}
/* heS between bS and bE */
if (between(bSx, bSy, bEx, bEy, heSx, heSy)) {
*x = heSx;
*y = heSy;
return SAME_LINE_OVERLAP;
}
/* heE between bS and bE */
if (between(bSx, bSy, bEx, bEy, heEx, heEy)) {
*x = heEx;
*y = heEy;
return SAME_LINE_OVERLAP;
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength) {
int maxSizeIntersections = 1;
for (int i = 0; i < numBisectors; i++) {
intersection_t *intersection = NULL;
intersection = getAnIntersection(intersection, dcel, bisectors[i], \
face, minLength);
/* If there is an intersection, add it to the array */
if (intersection != NULL) {
/* Ensure there is enough space in the array */
if (*numIntersections == maxSizeIntersections) {
maxSizeIntersections *= 2;
intersection_t **temp = realloc(intersections, \
maxSizeIntersections * sizeof(*intersections));
checkNullPointer(temp);
intersections = temp;
}
return DOESNT_INTERSECT;
intersections[*numIntersections] = intersection;
*numIntersections += 1;
}
}
return intersections;
}
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y) {
/* Half-edge x, y twin */
double heSx = dcel->vertices[he->startVertex].x;
double heSy = dcel->vertices[he->startVertex].y;
double heEx = dcel->vertices[he->endVertex].x;
double heEy = dcel->vertices[he->endVertex].y;
/* Bisector x, y twin */
vertex_t *startPoint = getBisectorPoint(minLength, b, -1);
vertex_t *endPoint = getBisectorPoint(minLength, b, 1);
double bSx = startPoint->x;
double bSy = startPoint->y;
double bEx = endPoint->x;
double bEy = endPoint->y;
free(startPoint);
free(endPoint);
/* Fill in segment. */
/* Parametric equation parameters */
double t1, t2;
/* Numerators for X and Y coordinate of intersection. */
double numeratorX, numeratorY;
/* Denominators of intersection coordinates. */
double denominator;
/*
See http://www.cs.jhu.edu/~misha/Spring20/15.pdf
for explanation and intuition of the algorithm here.
x_1 = heSx, y_1 = heSy | p_1 = heS
x_2 = heEx, y_2 = heEy | q_1 = heE
x_3 = bSx , y_3 = bSy | p_2 = bS
x_4 = bEx , y_4 = bEy | q_2 = bE
----------------------------------------
So the parameters t1 and t2 are given by:
| t1 | | heEx - heSx bSx - bEx | -1 | bSx - heSx |
| | = | | | |
| t2 | | heEy - heSy bSy - bEy | | bSy - heSy |
Hence:
| t1 | 1 | bSy - bEy bEx - bSx | | bSx - heSx |
| | = --------- | | | |
| t2 | ad - bc | heSy - heEy heEx - heSx | | bSy - heSy |
where
a = heEx - heSx
b = bSx - bEx
c = heEy - heSy
d = bSy - bEy
*/
/* Here we calculate ad - bc */
denominator = heSx * (bEy - bSy) +
heEx * (bSy - bEy) +
bEx * (heEy - heSy) +
bSx * (heSy - heEy);
if (denominator == 0) {
/* In this case the two are parallel */
return parallelIntersects(heSx, heSy, heEx, heEy, \
bSx, bSy, bEx, bEy, x, y);
void freeIntersections(intersection_t **intersections, int numIntersections) {
if (!intersections) {
return;
}
/*
Here we calculate the top row.
| bSy - bEy bEx - bSx | | bSx - heSx |
| | | |
| | | bSy - heSy |
*/
numeratorX = heSx * (bEy - bSy) +
bSx * (heSy - bEy) +
bEx * (bSy - heSy);
for (int i = 0; i < numIntersections; i++) {
if (intersections[i]->fromPoint) {
free(intersections[i]->fromPoint);
}
if (intersections[i]->toPoint) {
free(intersections[i]->toPoint);
}
if (intersections[i]) {
free(intersections[i]);
}
}
free(intersections);
}
/*
Here we calculate the bottom row.
| | | bSx - heSx |
| | | |
| heSy - heEy heEx - heSx | | bSy - heSy |
*/
numeratorY = -(heSx * (bSy - heEy) +
heEx * (heSy - bSy) +
bSx * (heEy - heSy));
/* --------------------- My intersection functions end --------------------- */
/* Use parameters to convert to the intersection point */
t1 = numeratorX/denominator;
t2 = numeratorY/denominator;
*x = heSx + t1 * (heEx - heSx);
*y = heSy + t1 * (heEy - heSy);
/* ---------------------- My bisector functions start ---------------------- */
/* Make final decision - if point is on segments, parameter values will be
between 0, the start of the line segment, and 1, the end of the line segment.
bisector_t *newBisector() {
bisector_t *newBisector = malloc(sizeof(*newBisector));
checkNullPointer(newBisector);
newBisector->mid = malloc(sizeof(*newBisector->mid));
checkNullPointer(newBisector->mid);
return newBisector;
}
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
vertex_t *pointB) {
/* Calculate midpoint of the two points */
bisector->mid->x = (pointA->x + pointB->x) / 2;
bisector->mid->y = (pointA->y + pointB->y) / 2;
/* 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.
*/
if (0.0 < t1 && t1 < 1.0 && 0.0 < t2 && t2 < 1.0) {
return INTERSECT;
} else if (t1 < 0.0 || 1.0 < t1 || t2 < 0.0 || 1.0 < t2) {
/* s or t outside of line segment. */
return DOESNT_INTERSECT;
bisector->slope = 0;
bisector->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.
*/
bisector->isSlopeInfinite = 1;
/* Not actually zero, just a placeholder to prevent
* accidental errors
*/
bisector->slope = 0;
} else {
/*
((numeratorX == 0) || (numeratorY == 0) ||
(numeratorX == denominator) || (numeratorY == denominator))
/* The line segment AB has a non-zero and finite gradient,
* so the gradient of the bisector can be calculated.
*/
return ENDS_OVERLAP;
bisector->isSlopeInfinite = 0;
bisector->slope = -1 / ((pointB->y - pointA->y) / \
(pointB->x - pointA->x));
}
return bisector;
}
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numBisectors) {
for (int i = 0; i < numBisectors; i++) {
bisectors[i] = newBisector();
bisectors[i] = getABisector(bisectors[i], points[2 * i], \
points[2 * i + 1]);
}
return bisectors;
}
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction) {
vertex_t *returnPoint = malloc(sizeof(*returnPoint));
if (b->isSlopeInfinite) {
/* Vertical line - just add vertical distance */
returnPoint->x = b->mid->x;
returnPoint->y = b->mid->y + (distance * direction);
} else if (b->slope == 0) {
/* Horizontal line - just add horizontal distance */
returnPoint->x = b->mid->x + (distance * direction);
returnPoint->y = b->mid->y;
} else {
/* Not horizontal or vertical - add distance to x, then find
* y-intercept of the bisector, and plug it in to y = mx + c to find
* the corresponding y-value.
*/
double c = b->mid->y - b->slope * b->mid->x;
returnPoint->x = b->mid->x + (distance * direction);
returnPoint->y = b->slope * returnPoint->x + c;
}
return returnPoint;
}
void freeBisectors(bisector_t **bisectors, int numBisectors) {
if (!bisectors) {
return;
}
for (int i = 0; i < numBisectors; i++) {
if (bisectors[i]->mid) {
free(bisectors[i]->mid);
}
if (bisectors[i]) {
free(bisectors[i]);
}
}
free(bisectors);
}
/* ----------------------- My bisector functions end ----------------------- */
/* ------------------------ My DCEL functions start ------------------------ */
double getDiameter(DCEL_t *dcel, int faceIndex) {
/* firstHE and firstVertex refer to the first HE/vertex from the face used
* to control when the loop stops
*
* startHE and startVertex refer to the starting point used to
* advance the new starting vertex after a complete cycle
*
* currentHE and currentVertex refer to the current HE/vertex being used to
* compute the diameter
*/
halfEdge_t *firstHE = (dcel->faces)[faceIndex].start;
halfEdge_t *startHE = firstHE;
halfEdge_t *currentHE = startHE;
int firstVertex = firstHE->startVertex;
int startVertex = firstVertex;
int currentVertex = startVertex;
int first = 1;
double currentDiameter = NODIAMETER, maxDiameter = NODIAMETER;
while (first || !(currentHE->startVertex == firstVertex && \
startHE->startVertex == firstVertex)) {
first = 0;
/* Compute currentDiameter, compare to maxDiameter */
currentDiameter = distPoints(&(dcel->vertices)[startVertex], \
&(dcel->vertices)[currentVertex]);
if (currentDiameter >= maxDiameter) {
maxDiameter = currentDiameter;
}
/* Advance current HE, update currentVertex */
currentHE = currentHE->next;
currentVertex = currentHE->startVertex;
/* When the starting vertex is reached, move the startHE to the next HE
* and update the vertices.
*/
if (currentVertex == startVertex) {
startHE = startHE->next;
currentHE = startHE;
startVertex = startHE->startVertex;
currentVertex = startVertex;
}
}
if (currentDiameter == NODIAMETER) {
return NODIAMETER;
}
return maxDiameter;
}
/* ------------------------- My DCEL functions end ------------------------- */
/* ------------------------------------------------------------------------- */
/* */
/* Here onwards are the functions from Grady's base code on Ed */
/* */
/* ------------------------------------------------------------------------- */
DCEL_t *newDCEL() {
/* Setup DCEL. */
DCEL_t *dcel = malloc(sizeof(*dcel));
@ -1011,83 +1012,208 @@ int inFace(DCEL_t *dcel, double x, double y, int faceIndex) {
return 1;
}
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength) {
int maxSizeIntersections = 1;
/* This intersection is based on code by Joseph O'Rourke and is provided for
* use in COMP20003 Assignment 2.
*
* The approach for intersections is:
* - Use the bisector to construct a finite segment and test it against
* the half-edge.
* - Use O'Rourke's segseg intersection
* (https://hydra.smith.edu/~jorourke/books/ftp.html) to check if the values
* overlap/intersect
*
* Generates a segment with each end at least minLength away in each direction
* from the bisector midpoint.
*
* Returns 1 if b intersects the given half-edge on this segment, 0 otherwise.
* Sets the intersection point to the given x, y positions.
*/
for (int i = 0; i < numBisectors; i++) {
intersection_t *currentIntersection = NULL;
int areaSign(double sx, double sy, double ex, double ey, double x, double y) {
double areaSq;
/* |AB x AC|^2, squared area */
/* See https://mathworld.wolfram.com/CrossProduct.html */
areaSq = (ex - sx) * (y - sy) -
(x - sx) * (ey - sy);
/* Intersection coordinates */
double x, y;
/* Flag is raised when first intersection is found */
int isIntersectionFound = 0;
halfEdge_t *startHE = (dcel->faces)[face].start;
halfEdge_t *currentHE = startHE;
int startVertex = startHE->startVertex;
int first = 1;
/* Loop through the face until the starting vertex is reached */
while (first || currentHE->startVertex != startVertex) {
enum intersectType typeOfIntersection = \
intersects(currentHE, bisectors[i], dcel, minLength, &x, &y);
switch (typeOfIntersection) {
case INTERSECT:
case SAME_LINE_OVERLAP:
case ENDS_OVERLAP:
if (!isIntersectionFound) {
/* First point of intersection */
isIntersectionFound = 1;
currentIntersection = newIntersection();
currentIntersection->fromPoint->x = x;
currentIntersection->fromPoint->y = y;
currentIntersection->fromEdge = currentHE->edge;
if (areaSq > 0.0) {
return 1;
} else if (areaSq == 0.0) {
return 0;
} else {
/* Second point of intersection */
currentIntersection->toPoint->x = x;
currentIntersection->toPoint->y = y;
currentIntersection->toEdge = currentHE->edge;
return -1;
}
break;
case DOESNT_INTERSECT:
default:
break;
}
currentHE = currentHE->next;
first = 0;
}
/* If there is an intersection, add it to the array */
if (currentIntersection != NULL) {
/* Ensure there is enough space in the array */
if (*numIntersections == maxSizeIntersections) {
maxSizeIntersections *= 2;
intersection_t **temp = realloc(intersections, maxSizeIntersections * sizeof(*intersections));
checkNullPointer(temp);
intersections = temp;
}
intersections[*numIntersections] = currentIntersection;
*numIntersections += 1;
}
}
return intersections;
}
double getDiameter(DCEL_t *dcel, int faceIndex) {
// FILL IN
printf("in getDiamter(): faceIndex = %d, dcel faces = %d\n", \
faceIndex, dcel->facesAllocated);
return NODIAMETER;
int between(double sx, double sy, double ex, double ey, double x, double y) {
if (sx != ex) {
/* If not vertical, check whether between x. */
if ((sx <= x && x <= ex) || (sx >= x && x >= ex)) {
return 1;
} else {
return 0;
}
} else {
/* Vertical, so can't check _between_ x-values. Check y-axis. */
if ((sy <= y && y <= ey) || (sy >= y && y >= ey)) {
return 1;
} else {
return 0;
}
}
}
void incrementalVoronoi(DCEL_t *dcel, tower_t *tower) {
// FILL IN
printf("In incrementalVoronoi(): tower id = %s, dcel faces = %d\n", \
tower->id, dcel->facesAllocated);
int collinear(double sx, double sy, double ex, double ey, double x, double y) {
/* If area of the parallelogram is 0, then the points
* are in the same line.
*/
if (areaSign(sx, sy, ex, ey, x, y) == 0) {
return 1;
} else {
return 0;
}
}
enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \
double bEx, double bEy, double *x, double *y) {
if (!collinear(heSx, heSy, heEx, heEy, bSx, bSy)) {
/* Parallel, no intersection so don't set (x, y) */
return DOESNT_INTERSECT;
}
/* bS between heS and heE */
if (between(heSx, heSy, heEx, heEy, bSx, bSy)) {
*x = bSx;
*y = bSy;
return SAME_LINE_OVERLAP;
}
/* bE between heS and heE */
if (between(heSx, heSy, heEx, heEy, bEx, bEy)) {
*x = bEx;
*y = bEy;
return SAME_LINE_OVERLAP;
}
/* heS between bS and bE */
if (between(bSx, bSy, bEx, bEy, heSx, heSy)) {
*x = heSx;
*y = heSy;
return SAME_LINE_OVERLAP;
}
/* heE between bS and bE */
if (between(bSx, bSy, bEx, bEy, heEx, heEy)) {
*x = heEx;
*y = heEy;
return SAME_LINE_OVERLAP;
}
return DOESNT_INTERSECT;
}
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y) {
/* Half-edge x, y twin */
double heSx = dcel->vertices[he->startVertex].x;
double heSy = dcel->vertices[he->startVertex].y;
double heEx = dcel->vertices[he->endVertex].x;
double heEy = dcel->vertices[he->endVertex].y;
/* Bisector x, y twin */
vertex_t *startPoint = getBisectorPoint(minLength, b, -1);
vertex_t *endPoint = getBisectorPoint(minLength, b, 1);
double bSx = startPoint->x;
double bSy = startPoint->y;
double bEx = endPoint->x;
double bEy = endPoint->y;
free(startPoint);
free(endPoint);
/* Parametric equation parameters */
double t1, t2;
/* Numerators for X and Y coordinate of intersection. */
double numeratorX, numeratorY;
/* Denominators of intersection coordinates. */
double denominator;
/*
See http://www.cs.jhu.edu/~misha/Spring20/15.pdf
for explanation and intuition of the algorithm here.
x_1 = heSx, y_1 = heSy | p_1 = heS
x_2 = heEx, y_2 = heEy | q_1 = heE
x_3 = bSx , y_3 = bSy | p_2 = bS
x_4 = bEx , y_4 = bEy | q_2 = bE
----------------------------------------
So the parameters t1 and t2 are given by:
| t1 | | heEx - heSx bSx - bEx | -1 | bSx - heSx |
| | = | | | |
| t2 | | heEy - heSy bSy - bEy | | bSy - heSy |
Hence:
| t1 | 1 | bSy - bEy bEx - bSx | | bSx - heSx |
| | = --------- | | | |
| t2 | ad - bc | heSy - heEy heEx - heSx | | bSy - heSy |
where
a = heEx - heSx
b = bSx - bEx
c = heEy - heSy
d = bSy - bEy
*/
/* Here we calculate ad - bc */
denominator = heSx * (bEy - bSy) +
heEx * (bSy - bEy) +
bEx * (heEy - heSy) +
bSx * (heSy - heEy);
if (denominator == 0) {
/* In this case the two are parallel */
return parallelIntersects(heSx, heSy, heEx, heEy, \
bSx, bSy, bEx, bEy, x, y);
}
/*
Here we calculate the top row.
| bSy - bEy bEx - bSx | | bSx - heSx |
| | | |
| | | bSy - heSy |
*/
numeratorX = heSx * (bEy - bSy) +
bSx * (heSy - bEy) +
bEx * (bSy - heSy);
/*
Here we calculate the bottom row.
| | | bSx - heSx |
| | | |
| heSy - heEy heEx - heSx | | bSy - heSy |
*/
numeratorY = -(heSx * (bSy - heEy) +
heEx * (heSy - bSy) +
bSx * (heEy - heSy));
/* Use parameters to convert to the intersection point */
t1 = numeratorX/denominator;
t2 = numeratorY/denominator;
*x = heSx + t1 * (heEx - heSx);
*y = heSy + t1 * (heEy - heSy);
/* Make final decision - if point is on segments, parameter values will be
between 0, the start of the line segment, and 1, the end of the line segment.
*/
if (0.0 < t1 && t1 < 1.0 && 0.0 < t2 && t2 < 1.0) {
return INTERSECT;
} else if (t1 < 0.0 || 1.0 < t1 || t2 < 0.0 || 1.0 < t2) {
/* s or t outside of line segment. */
return DOESNT_INTERSECT;
} else {
/*
((numeratorX == 0) || (numeratorY == 0) ||
(numeratorX == denominator) || (numeratorY == denominator))
*/
return ENDS_OVERLAP;
}
}

224
dcel.h
View file

@ -2,10 +2,23 @@
#include "towers.h"
#endif
#ifndef MATH_HEADER
#include <math.h>
#endif
#ifndef DCEL_HEADER
#define DCEL_HEADER
/* Here is the Base Code from Grady, with some alterations by me */
/* -------- Definitions, enums, and structs from Grady's base code --------- */
/* 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)
enum intersectType {
DOESNT_INTERSECT = 0, // Doesn't intersect
@ -19,12 +32,6 @@ typedef struct vertex {
double y;
} vertex_t;
typedef struct bisector {
vertex_t *mid;
int isSlopeInfinite;
double slope;
} bisector_t;
typedef struct halfEdge {
struct halfEdge *previous;
struct halfEdge *next;
@ -53,13 +60,6 @@ typedef struct split {
vertex_t endPoint;
} split_t;
typedef struct intersection {
int fromEdge;
int toEdge;
vertex_t *fromPoint;
vertex_t *toPoint;
} intersection_t;
typedef struct DCEL {
edge_t *edges;
int edgesUsed;
@ -74,35 +74,114 @@ typedef struct DCEL {
int verticesAllocated;
} DCEL_t;
/* ------------------------------ My structs ------------------------------- */
typedef struct bisector {
vertex_t *mid;
int isSlopeInfinite;
double slope;
} bisector_t;
typedef struct intersection {
int fromEdge;
int toEdge;
vertex_t *fromPoint;
vertex_t *toPoint;
} intersection_t;
/* ----------------------- My points functions start ----------------------- */
/* Creates a new point */
vertex_t *newPoint();
/* Gets a single point from an x-y pair */
vertex_t *getAPoint(double x, double y);
/* Reads a points file and stores the information in the points array */
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
/* Frees an array of points */
void freePoints(vertex_t **points, int numPoints);
/* Returns the distance between two points */
double distPoints(vertex_t *pointA, vertex_t *pointB);
/* ------------------------ My points functions end ------------------------ */
/* -------------------- My intersection functions start -------------------- */
/* Create a new intersection */
intersection_t *newIntersection();
/* Fills in a single intersection structure */
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
bisector_t *bisector, int face, int minLength);
/* Gets the intersection between the given bisector and the given DCEL
* for the given face.
*/
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength);
/* Frees an array of intersections */
void freeIntersections(intersection_t **intersections, int numIntersections);
/* --------------------- My intersection functions end --------------------- */
/* ---------------------- My bisector functions start ---------------------- */
/* Creates a new bisector */
bisector_t *newBisector();
/* Calculates and returns the equation of a bisector of two points */
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
vertex_t *pointB);
/* Returns a list of bisectors built from a list of points */
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numPoints);
/* Returns a point at least distance away from the midpoint of the
* bisector given. If direction is 0, then the point is +distance away in the
* x-direction, otherwise -distance away in the x-direction.
*/
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
/* Frees an array of bisectors */
void freeBisectors(bisector_t **bisectors, int numBisectors);
/* ----------------------- My bisector functions end ----------------------- */
/* ------------------------ My DCEL functions start ------------------------ */
/* Gets the diameter of the given face. */
double getDiameter(DCEL_t *dcel, int faceIndex);
/* ------------------------- My DCEL functions end ------------------------- */
/* ----------------------------------------------------------------------------
* Here on out are the functions from Grady's base code on Ed
* ----------------------------------------------------------------------------
*/
/* 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.
/* 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.
/* 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.
/* Check there's space for another face in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForFace(DCEL_t *dcel);
@ -127,18 +206,6 @@ 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);
/* 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)
/* Applies a given split to the DCEL. */
void applySplit(split_t *split, DCEL_t *dcel);
@ -148,40 +215,37 @@ void freeDCEL(DCEL_t *dcel);
/* Gets the number of faces in the DCEL. */
int getFaceCount(DCEL_t *dcel);
/* 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);
/* 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 intersection between the given bisector and the given DCEL
* for the given face.
/* ------------------- O'Rourke's intersection functions ------------------- */
/* Returns -1, 0 or 1, based on the area enclosed by the three points.
* 0 corresponds to no area enclosed
*/
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength);
/* 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);
/* O'Rourke's intersection 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.
* 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.
* intersecting
*/
enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \
@ -191,38 +255,4 @@ enum intersectType parallelIntersects(double heSx, double heSy, \
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y);
/* 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 **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numPoints);
/* Returns a point at least distance away from the midpoint of the
* bisector given. If direction is 0, then the point is +distance away in the
* x-direction, otherwise -distance away in the x-direction.
*/
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
/* Create a new intersection */
intersection_t *newIntersection();
/* Frees an array of bisectors */
void freeBisectors(bisector_t **bisectors, int numBisectors);
/* Frees an array of points */
void freePoints(vertex_t **points, int numPoints);
/* Frees an array of intersections */
void freeIntersections(intersection_t **intersections, int numIntersections);
/* Reads a points file and stores the information in the points array */
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
#endif

BIN
dcel.o

Binary file not shown.

156
ed.supp Normal file
View file

@ -0,0 +1,156 @@
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:runtime.adjustframe
fun:runtime.gentraceback
fun:runtime.copystack
fun:runtime.newstack
fun:runtime.morestack
fun:runtime.rt0_go
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:runtime.adjustframe
fun:runtime.gentraceback
fun:runtime.copystack
fun:runtime.newstack
fun:runtime.morestack
fun:runtime.rt0_go
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:runtime.adjustpointer
fun:runtime.adjustframe
fun:runtime.gentraceback
fun:runtime.copystack
fun:runtime.newstack
fun:runtime.morestack
fun:runtime.rt0_go
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:runtime.adjustpointer
fun:runtime.adjustframe
fun:runtime.gentraceback
fun:runtime.copystack
fun:runtime.newstack
fun:runtime.morestack
fun:runtime.rt0_go
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:x_cgo_sys_thread_create
fun:_rt0_amd64_lib
fun:call_init
fun:_dl_init
obj:/usr/lib/ld-2.33.so
obj:*
obj:*
obj:*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:_cgo_sys_thread_start
fun:runtime.asmcgocall
obj:*
fun:runtime.newm
fun:runtime.main.func1
fun:runtime.systemstack
obj:/mnt/share/ed/libX11.so
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:_cgo_sys_thread_start
fun:runtime.asmcgocall
obj:*
fun:runtime.newm
fun:runtime.startm
fun:runtime.newproc1
fun:runtime.newproc.func1
fun:runtime.systemstack
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:_cgo_sys_thread_start
fun:runtime.asmcgocall
obj:*
fun:runtime.newm
fun:runtime.startm
fun:runtime.handoffp
fun:runtime.stoplockedm
fun:runtime.schedule
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:_cgo_sys_thread_start
fun:runtime.asmcgocall
obj:*
fun:runtime.malg.func1
fun:runtime.systemstack
obj:/mnt/share/ed/libX11.so
fun:runtime.rt0_go
}
{
<edstem-suppression>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:x_cgo_sys_thread_create
fun:_rt0_amd64_lib
fun:call_init
fun:_dl_init
obj:/usr/lib/ld-2.33.so
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
fun:_cgo_try_pthread_create
fun:_cgo_sys_thread_start
fun:runtime.asmcgocall
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
}

View file

@ -2,7 +2,7 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 8th September 2021
* Last modified 9th September 2021
* Last modified 14th September 2021
*
* Contains functions for ensuring correct input arguments are given for
* each stage of the voronoi2 program. Adapted from Grady's base code on Ed.
@ -13,10 +13,6 @@
#include "input.h"
#endif
#ifndef COMMON_HEADER
#include "common.h"
#endif
#define STAGE_1_ARG_COUNT 4
#define STAGE_2_ARG_COUNT 5
#define STAGE_3_ARG_COUNT 5

View file

@ -1,3 +1,7 @@
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef INPUT_HEADER
#define INPUT_HEADER

BIN
input.o

Binary file not shown.

15
main.c
View file

@ -2,11 +2,16 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 9th September 2021
* Last modified 14th September 2021
*
* Lists the watchtowers that are in each face of the polygon.
* The polygon can be split using a pair of integers, which represent
* the edge numbers that should be connected. This comes from stdin.
* Stage 1: Computes and outputs equations for the bisectors of points
* Stage 2: Computes and outputs intersection points for bisectors against a
* given polygon
* Stage 3: Computes a Voronoi diagram using watchtowers as points and a
* polygon as the outer boundary. Outputs diameters of each Voronoi
* cell along with information about each watchtower.
* Stage 4: Same as Stage 4, but the watchtowers are sorted by ascending order
* by diameter.
*
* To see valid input arguments, run ./voronoi2
*
@ -25,6 +30,8 @@ int main(int argc, char **argv) {
if (argc == 1) {
printArgError(STAGE_ERROR, "Incorrect usage.");
}
/* Get stage, ensure correct input args */
enum stages stage = getStage(argv[1]);
int expectedArgs = getExpectedArgs(stage);
if (expectedArgs != argc) {

BIN
main.o

Binary file not shown.

View file

@ -1,6 +1 @@
From Edge 0 (140.900000, -34.700000) to Edge 2 (150.000000, -34.700000)
From Edge 0 (140.900000, -35.200000) to Edge 2 (150.000000, -35.200000)
From Edge 1 (147.100000, -33.900000) to Edge 3 (147.100000, -39.200000)
From Edge 1 (147.100000, -33.900000) to Edge 3 (147.100000, -39.200000)
From Edge 1 (147.600000, -33.900000) to Edge 3 (147.600000, -39.200000)
From Edge 1 (146.900000, -33.900000) to Edge 3 (141.600000, -39.200000)
Watchtower ID: WT3765SHSPB, Postcode: 3765, Population Served: 3380, Watchtower Point of Contact Name: Eilene Horner, x: 145.362014, y: -37.818943, Diameter of Cell: 10.000000

View file

@ -2,7 +2,7 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 11th September 2021
* Last modified 13th September 2021
* Last modified 14th September 2021
*
* Contains functions for reading a CSV of watchtower information into an
* array of towers.
@ -18,38 +18,7 @@
#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 (+1 for null char in string) */
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) {
/* Ensure there is 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) {
void readATower(char *lineBuffer, tower_t *tower) {
/* Stores the current CSV field for the current line */
char *token = strtok(lineBuffer, ",");
size_t tokenLength;
@ -57,11 +26,8 @@ void readCurrentTower(char *lineBuffer, tower_t *tower) {
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.
/* Cases represent each field in the CSV, and as such are handled
* differently.
*/
case 0:
tower->id = malloc(sizeof(char) * tokenLength + 1);
@ -95,12 +61,55 @@ void readCurrentTower(char *lineBuffer, tower_t *tower) {
}
}
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
/* Maximum length of a single CSV line (+1 for null char in string) */
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) {
/* Ensure there is 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]));
readATower(lineBuffer, towers[*numTowers]);
*numTowers += 1;
}
free(lineBuffer);
return towers;
}
void freeTowers(tower_t **towers, int numTowers) {
if (!towers) {
return;
}
for (int i = 0; i < numTowers; i++) {
if (towers[i]->id) {
free(towers[i]->id);
}
if (towers[i]->manager) {
free(towers[i]->manager);
}
if (towers[i]->postcode) {
free(towers[i]->postcode);
}
if (towers[i]) {
free(towers[i]);
}
}
free(towers);
}

View file

@ -14,12 +14,12 @@ typedef struct tower {
double y;
} tower_t;
/* Reads the current row from the CSV and converts it into a new tower */
void readATower(char *lineBuffer, tower_t *tower);
/* 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);

BIN
towers.o

Binary file not shown.

View file

@ -2,7 +2,7 @@
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 12th August 2021
* Last modified 13th September 2021
* Last modified 14th September 2021
*
* Contains functions involving the generation of the Voronoi diagram, and
* running each stage of the assignment.
@ -30,6 +30,58 @@ void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
intersection->toPoint->x, intersection->toPoint->y);
}
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter) {
fprintf(outputFile, "Watchtower ID: %s, Postcode: %s, Population " \
"Served: %d, Watchtower Point of Contact Name: %s, x: %lf, y: %lf, " \
"Diameter of Cell: %lf\n", tower->id, tower->postcode, \
tower->population, tower->manager, tower->x, tower->y, diameter);
}
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower) {
for (int i = 0; i < getFaceCount(dcel); i++) {
if (inFace(dcel, tower->x, tower->y, i)) {
return i;
}
}
return -1;
}
void incrementalVoronoi(DCEL_t *voronoi, tower_t *tower) {
int faceTowerIsIn = getFaceTowerIsIn(voronoi, tower);
if (faceTowerIsIn == -1) {
fprintf(stderr, "Error: Watchtower %s is outside the polygon.\n", \
tower->id);
exit(EXIT_FAILURE);
}
}
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB) {
/* Get vertices from towers */
vertex_t *pointA = getAPoint(towerA->x, towerA->y);
vertex_t *pointB = getAPoint(towerB->x, towerB->y);
/* Create first bisector */
bisector_t *bisector = newBisector();
bisector = getABisector(bisector, pointA, pointB);
/* Get intersection of bisector with the polygon */
intersection_t *intersection = NULL;
intersection = getAnIntersection(intersection, voronoi, bisector, \
DEFAULT_FACE, DEFAULTMINLENGTH);
if (intersection) {
free(intersection->fromPoint);
free(intersection->toPoint);
free(intersection);
}
free(bisector->mid);
free(bisector);
free(pointA);
free(pointB);
return voronoi;
}
void stage1(char *pointsFileName, char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
@ -59,7 +111,9 @@ void stage1(char *pointsFileName, char *outputFileName) {
fclose(outputFile);
}
void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
void stage2(char *pointsFileName, char *polygonFileName, \
char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
@ -83,8 +137,8 @@ void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
intersection_t **intersections = malloc(sizeof(*intersections));
checkNullPointer(intersections);
int numIntersections = 0;
intersections = getIntersections(intersections, &numIntersections, bisectors, numBisectors, dcel, DEFAULT_FACE, \
DEFAULTMINLENGTH);
intersections = getIntersections(intersections, &numIntersections, \
bisectors, numBisectors, dcel, DEFAULT_FACE, DEFAULTMINLENGTH);
for (int i = 0; i < numIntersections; i++) {
stage2PrintIntersection(intersections[i], outputFile);
@ -105,9 +159,22 @@ void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
@ -119,9 +186,22 @@ void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and sort, then output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);

View file

@ -11,6 +11,20 @@ void stage1PrintBisector(bisector_t *bisector, FILE *outputFile);
/* Prints intersections to an output file */
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile);
/* Prints the watchtower information to an output file */
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter);
/* Returns the face a tower is in */
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower);
/* 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 *voronoi, tower_t *tower);
/* Creates a new Voronoi structure */
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB);
/* Outputs the bisector equations from pointsFile into outputFile */
void stage1(char *pointsFileName, char *outputFileName);

BIN
voronoi.o

Binary file not shown.

BIN
voronoi2

Binary file not shown.