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: # Link command:
voronoi2: common.o towers.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 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 # Compilation commands
common.o: common.c 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 by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021 * 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 by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021 * Created on 25th August 2021
* Last modified 13th September 2021 * Last modified 14th September 2021
* *
* Contains functions for the DCEL data structure, including initialisation, * Contains functions for the DCEL data structure and related data structures
* splitting an edge, and identifying towers in faces. * (including points, intersections, and bisectors).
* *
* Contains several functions and structures from Grady Fitzpatrick's Base * Contains several functions and structures from Grady Fitzpatrick's Base
* Code on the Ed Discussion Forum. * Code on the Ed Discussion Forum.
@ -16,106 +16,29 @@
#include "dcel.h" #include "dcel.h"
#endif #endif
void freePoints(vertex_t **points, int numPoints) { #define INITIALVERTICES 4
for (int i = 0; i < numPoints; i++) { #define INITIALEDGES 4
free(points[i]); #define INITIALFACES 1
} #define NOVERTEX (-1)
free(points); #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) { vertex_t *getAPoint(double x, double y) {
for (int i = 0; i < numBisectors; i++) { vertex_t *point = newPoint();
free(bisectors[i]->mid); point->x = x;
free(bisectors[i]); point->y = y;
} return point;
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 **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) { 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; return points;
} }
/* Here on out is the base code from Grady, with some alterations from me */ void freePoints(vertex_t **points, int numPoints) {
if (!points) {
#define INITIALVERTICES 4 return;
#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;
} }
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) { double distPoints(vertex_t *pointA, vertex_t *pointB) {
if (sx != ex) { double a = pointB->x - pointA->x;
/* If not vertical, check whether between x. */ double b = pointB->y - pointA->y;
if ((sx <= x && x <= ex) || (sx >= x && x >= ex)) { return sqrt(a * a + b * b);
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;
}
}
} }
int collinear(double sx, double sy, double ex, double ey, double x, double y) { /* ------------------------ My points functions end ------------------------ */
/* If area of the parallelogram is 0, then the points
* are in the same line. /* -------------------- My intersection functions start -------------------- */
*/
if (areaSign(sx, sy, ex, ey, x, y) == 0) { intersection_t *newIntersection() {
return 1; 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 { } 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, \ intersection_t **getIntersections(intersection_t **intersections, \
double heEx, double heEy, double bSx, double bSy, \ int *numIntersections, bisector_t **bisectors, int numBisectors, \
double bEx, double bEy, double *x, double *y) { DCEL_t *dcel, int face, double minLength) {
if (!collinear(heSx, heSy, heEx, heEy, bSx, bSy)) {
/* Parallel, no intersection so don't set (x, y) */ int maxSizeIntersections = 1;
return DOESNT_INTERSECT;
} for (int i = 0; i < numBisectors; i++) {
/* bS between heS and heE */ intersection_t *intersection = NULL;
if (between(heSx, heSy, heEx, heEy, bSx, bSy)) { intersection = getAnIntersection(intersection, dcel, bisectors[i], \
*x = bSx; face, minLength);
*y = bSy;
return SAME_LINE_OVERLAP; /* If there is an intersection, add it to the array */
} if (intersection != NULL) {
/* bE between heS and heE */ /* Ensure there is enough space in the array */
if (between(heSx, heSy, heEx, heEy, bEx, bEy)) { if (*numIntersections == maxSizeIntersections) {
*x = bEx; maxSizeIntersections *= 2;
*y = bEy; intersection_t **temp = realloc(intersections, \
return SAME_LINE_OVERLAP; maxSizeIntersections * sizeof(*intersections));
} checkNullPointer(temp);
/* heS between bS and bE */ intersections = temp;
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; intersections[*numIntersections] = intersection;
*numIntersections += 1;
}
}
return intersections;
} }
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \ void freeIntersections(intersection_t **intersections, int numIntersections) {
DCEL_t *dcel, double minLength, double *x, double *y) { if (!intersections) {
/* Half-edge x, y twin */ return;
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);
} }
/* for (int i = 0; i < numIntersections; i++) {
Here we calculate the top row. if (intersections[i]->fromPoint) {
| bSy - bEy bEx - bSx | | bSx - heSx | free(intersections[i]->fromPoint);
| | | | }
| | | bSy - heSy | if (intersections[i]->toPoint) {
*/ free(intersections[i]->toPoint);
numeratorX = heSx * (bEy - bSy) + }
bSx * (heSy - bEy) + if (intersections[i]) {
bEx * (bSy - heSy); free(intersections[i]);
}
}
free(intersections);
}
/* /* --------------------- My intersection functions end --------------------- */
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 */ /* ---------------------- My bisector functions start ---------------------- */
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 bisector_t *newBisector() {
between 0, the start of the line segment, and 1, the end of the line segment. 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) { bisector->slope = 0;
return INTERSECT; bisector->isSlopeInfinite = 0;
} else if (t1 < 0.0 || 1.0 < t1 || t2 < 0.0 || 1.0 < t2) { } else if (pointA->y == pointB->y) {
/* s or t outside of line segment. */ /* The line segment AB has gradient of zero, so
return DOESNT_INTERSECT; * 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 { } else {
/* /* The line segment AB has a non-zero and finite gradient,
((numeratorX == 0) || (numeratorY == 0) || * so the gradient of the bisector can be calculated.
(numeratorX == denominator) || (numeratorY == denominator))
*/ */
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() { DCEL_t *newDCEL() {
/* Setup DCEL. */ /* Setup DCEL. */
DCEL_t *dcel = malloc(sizeof(*dcel)); DCEL_t *dcel = malloc(sizeof(*dcel));
@ -1011,83 +1012,208 @@ int inFace(DCEL_t *dcel, double x, double y, int faceIndex) {
return 1; return 1;
} }
intersection_t **getIntersections(intersection_t **intersections, \ /* This intersection is based on code by Joseph O'Rourke and is provided for
int *numIntersections, bisector_t **bisectors, int numBisectors, \ * use in COMP20003 Assignment 2.
DCEL_t *dcel, int face, double minLength) { *
int maxSizeIntersections = 1; * 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++) { int areaSign(double sx, double sy, double ex, double ey, double x, double y) {
intersection_t *currentIntersection = NULL; 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 */ if (areaSq > 0.0) {
double x, y; return 1;
} else if (areaSq == 0.0) {
/* Flag is raised when first intersection is found */ return 0;
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;
} else { } else {
/* Second point of intersection */ return -1;
currentIntersection->toPoint->x = x;
currentIntersection->toPoint->y = y;
currentIntersection->toEdge = currentHE->edge;
} }
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) { int between(double sx, double sy, double ex, double ey, double x, double y) {
// FILL IN if (sx != ex) {
printf("in getDiamter(): faceIndex = %d, dcel faces = %d\n", \ /* If not vertical, check whether between x. */
faceIndex, dcel->facesAllocated); if ((sx <= x && x <= ex) || (sx >= x && x >= ex)) {
return NODIAMETER; 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) { int collinear(double sx, double sy, double ex, double ey, double x, double y) {
// FILL IN /* If area of the parallelogram is 0, then the points
printf("In incrementalVoronoi(): tower id = %s, dcel faces = %d\n", \ * are in the same line.
tower->id, dcel->facesAllocated); */
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" #include "towers.h"
#endif #endif
#ifndef MATH_HEADER
#include <math.h>
#endif
#ifndef DCEL_HEADER #ifndef DCEL_HEADER
#define 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 { enum intersectType {
DOESNT_INTERSECT = 0, // Doesn't intersect DOESNT_INTERSECT = 0, // Doesn't intersect
@ -19,12 +32,6 @@ typedef struct vertex {
double y; double y;
} vertex_t; } vertex_t;
typedef struct bisector {
vertex_t *mid;
int isSlopeInfinite;
double slope;
} bisector_t;
typedef struct halfEdge { typedef struct halfEdge {
struct halfEdge *previous; struct halfEdge *previous;
struct halfEdge *next; struct halfEdge *next;
@ -53,13 +60,6 @@ typedef struct split {
vertex_t endPoint; vertex_t endPoint;
} split_t; } split_t;
typedef struct intersection {
int fromEdge;
int toEdge;
vertex_t *fromPoint;
vertex_t *toPoint;
} intersection_t;
typedef struct DCEL { typedef struct DCEL {
edge_t *edges; edge_t *edges;
int edgesUsed; int edgesUsed;
@ -74,35 +74,114 @@ typedef struct DCEL {
int verticesAllocated; int verticesAllocated;
} DCEL_t; } 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. */ /* Allocate a new DCEL and return it. */
DCEL_t *newDCEL(); DCEL_t *newDCEL();
/* Allocate a new halfEdge and return it. */ /* Allocate a new halfEdge and return it. */
halfEdge_t *newHalfEdge(); halfEdge_t *newHalfEdge();
/* Returns INSIDE if the points is on the INSIDE of the vector twin by the CW /* Check there's space for another vertex in the DCEL, or increase the
* winding order, OUTSIDE if it is OUTSIDE by the CW winding order, and * allocated space.
* 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); void ensureSpaceForVertex(DCEL_t *dcel);
/* Check there's space for another edge in the DCEL, /* Check there's space for another edge in the DCEL, or increase the
* or increase the allocated space. * allocated space.
*/ */
void ensureSpaceForEdge(DCEL_t *dcel); void ensureSpaceForEdge(DCEL_t *dcel);
/* Check there's space for another face in the DCEL, /* Check there's space for another face in the DCEL, or increase the
* or increase the allocated space. * allocated space.
*/ */
void ensureSpaceForFace(DCEL_t *dcel); void ensureSpaceForFace(DCEL_t *dcel);
@ -127,18 +206,6 @@ void freeSplit(split_t *split);
/* Returns 1 if vertices are sufficiently close, 0 otherwise. */ /* Returns 1 if vertices are sufficiently close, 0 otherwise. */
int vertexMatch(vertex_t *v1, vertex_t *v2); 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. */ /* Applies a given split to the DCEL. */
void applySplit(split_t *split, DCEL_t *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. */ /* Gets the number of faces in the DCEL. */
int getFaceCount(DCEL_t *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. */ /* Returns 1 if the given x,y point is inside the given face. */
int inFace(DCEL_t *dcel, double x, double y, int faceIndex); int inFace(DCEL_t *dcel, double x, double y, int faceIndex);
/* Gets the intersection between the given bisector and the given DCEL /* ------------------- O'Rourke's intersection functions ------------------- */
* for the given face.
/* 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); 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) */ /* 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); 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), /* 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); 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 /* Tests if the half edge and bisector are parallel and overlapping, or not
* intersecting. * intersecting
*/ */
enum intersectType parallelIntersects(double heSx, double heSy, \ enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \ 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, \ enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y); 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 #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 by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 8th September 2021 * 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 * Contains functions for ensuring correct input arguments are given for
* each stage of the voronoi2 program. Adapted from Grady's base code on Ed. * each stage of the voronoi2 program. Adapted from Grady's base code on Ed.
@ -13,10 +13,6 @@
#include "input.h" #include "input.h"
#endif #endif
#ifndef COMMON_HEADER
#include "common.h"
#endif
#define STAGE_1_ARG_COUNT 4 #define STAGE_1_ARG_COUNT 4
#define STAGE_2_ARG_COUNT 5 #define STAGE_2_ARG_COUNT 5
#define STAGE_3_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 #ifndef INPUT_HEADER
#define 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 by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021 * 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. * Stage 1: Computes and outputs equations for the bisectors of points
* The polygon can be split using a pair of integers, which represent * Stage 2: Computes and outputs intersection points for bisectors against a
* the edge numbers that should be connected. This comes from stdin. * 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 * To see valid input arguments, run ./voronoi2
* *
@ -25,6 +30,8 @@ int main(int argc, char **argv) {
if (argc == 1) { if (argc == 1) {
printArgError(STAGE_ERROR, "Incorrect usage."); printArgError(STAGE_ERROR, "Incorrect usage.");
} }
/* Get stage, ensure correct input args */
enum stages stage = getStage(argv[1]); enum stages stage = getStage(argv[1]);
int expectedArgs = getExpectedArgs(stage); int expectedArgs = getExpectedArgs(stage);
if (expectedArgs != argc) { 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) 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
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)

View file

@ -2,7 +2,7 @@
* *
* Created by Rory Healy (healyr@student.unimelb.edu.au) * Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 11th September 2021 * 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 * Contains functions for reading a CSV of watchtower information into an
* array of towers. * array of towers.
@ -18,38 +18,7 @@
#define MAX_FIELD_LEN 128 #define MAX_FIELD_LEN 128
#define NUM_CSV_FIELDS 6 #define NUM_CSV_FIELDS 6
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) { void readATower(char *lineBuffer, tower_t *tower) {
/* 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) {
/* Stores the current CSV field for the current line */ /* Stores the current CSV field for the current line */
char *token = strtok(lineBuffer, ","); char *token = strtok(lineBuffer, ",");
size_t tokenLength; size_t tokenLength;
@ -57,11 +26,8 @@ void readCurrentTower(char *lineBuffer, tower_t *tower) {
for (int i = 0; i < NUM_CSV_FIELDS; i++) { for (int i = 0; i < NUM_CSV_FIELDS; i++) {
tokenLength = strlen(token); tokenLength = strlen(token);
switch(i) { switch(i) {
/* Case 0, 1, and 3 deal with strings /* Cases represent each field in the CSV, and as such are handled
* Case 2 deals with an integer * differently.
* Case 4 and 5 deal with doubles
* Each case is handled seperately to fill in the
* tower with no space wasted.
*/ */
case 0: case 0:
tower->id = malloc(sizeof(char) * tokenLength + 1); 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) { void freeTowers(tower_t **towers, int numTowers) {
if (!towers) {
return;
}
for (int i = 0; i < numTowers; i++) { for (int i = 0; i < numTowers; i++) {
if (towers[i]->id) {
free(towers[i]->id); free(towers[i]->id);
}
if (towers[i]->manager) {
free(towers[i]->manager); free(towers[i]->manager);
}
if (towers[i]->postcode) {
free(towers[i]->postcode); free(towers[i]->postcode);
}
if (towers[i]) {
free(towers[i]); free(towers[i]);
} }
}
free(towers); free(towers);
} }

View file

@ -14,12 +14,12 @@ typedef struct tower {
double y; double y;
} tower_t; } 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 */ /* Reads the CSV file and stores the information in the towers array */
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers); 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 */ /* Frees all towers in a towers array */
void freeTowers(tower_t **towers, int numTowers); 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 by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 12th August 2021 * 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 * Contains functions involving the generation of the Voronoi diagram, and
* running each stage of the assignment. * running each stage of the assignment.
@ -30,6 +30,58 @@ void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
intersection->toPoint->x, intersection->toPoint->y); 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) { void stage1(char *pointsFileName, char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL; FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r"); pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
@ -59,7 +111,9 @@ void stage1(char *pointsFileName, char *outputFileName) {
fclose(outputFile); fclose(outputFile);
} }
void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) { void stage2(char *pointsFileName, char *polygonFileName, \
char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL; FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r"); pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w"); outputFile = safeFileOpen(&outputFile, outputFileName, "w");
@ -83,8 +137,8 @@ void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) {
intersection_t **intersections = malloc(sizeof(*intersections)); intersection_t **intersections = malloc(sizeof(*intersections));
checkNullPointer(intersections); checkNullPointer(intersections);
int numIntersections = 0; int numIntersections = 0;
intersections = getIntersections(intersections, &numIntersections, bisectors, numBisectors, dcel, DEFAULT_FACE, \ intersections = getIntersections(intersections, &numIntersections, \
DEFAULTMINLENGTH); bisectors, numBisectors, dcel, DEFAULT_FACE, DEFAULTMINLENGTH);
for (int i = 0; i < numIntersections; i++) { for (int i = 0; i < numIntersections; i++) {
stage2PrintIntersection(intersections[i], outputFile); stage2PrintIntersection(intersections[i], outputFile);
@ -105,9 +159,22 @@ void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r"); polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w"); 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 */ /* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile); fclose(dataFile);
fclose(polygonFile); fclose(polygonFile);
fclose(outputFile); fclose(outputFile);
@ -119,9 +186,22 @@ void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r"); polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w"); 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 */ /* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile); fclose(dataFile);
fclose(polygonFile); fclose(polygonFile);
fclose(outputFile); fclose(outputFile);

View file

@ -11,6 +11,20 @@ void stage1PrintBisector(bisector_t *bisector, FILE *outputFile);
/* Prints intersections to an output file */ /* Prints intersections to an output file */
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile); 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 */ /* Outputs the bisector equations from pointsFile into outputFile */
void stage1(char *pointsFileName, char *outputFileName); void stage1(char *pointsFileName, char *outputFileName);

BIN
voronoi.o

Binary file not shown.

BIN
voronoi2

Binary file not shown.