diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..884d5dd --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Voronoi2 - 1", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/voronoi2", + "args": ["1", "pp_inside.txt", "output.txt"], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "Voronoi2 - 2", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/voronoi2", + "args": ["2", "pp_inside.txt", "polygon_square.txt", "output.txt"], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} diff --git a/Makefile b/Makefile index e725bfa..a96ce28 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,8 @@ -# Link command: -#voronoi1: common.o dcel.o voronoi.o main.o -# gcc -Wall -Wextra -Werror -pedantic -g -o voronoi1 main.o voronoi.o dcel.o common.o - -# Compilation commands: -#common.o: common.c -# gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c -# -#dcel.o: dcel.c -# gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c -# -#voronoi.o: voronoi.c -# gcc -Wall -Wextra -Werror -pedantic -g -o voronoi.o voronoi.c -c -# -#main.o: main.c -# gcc -Wall -Wextra -Werror -pedantic -g -o main.o main.c -c - # 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 -lm + gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o towers.o common.o +# Compilation commands common.o: common.c gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c @@ -31,8 +15,8 @@ dcel.o: dcel.c voronoi.o: voronoi.c gcc -Wall -Wextra -Werror -pedantic -g -o voronoi.o voronoi.c -c -main.o: main.c - gcc -Wall -Wextra -Werror -pedantic -g -o main.o main.c -c - input.o: input.c gcc -Wall -Wextra -Werror -pedantic -g -o input.o input.c -c + +main.o: main.c + gcc -Wall -Wextra -Werror -pedantic -g -o main.o main.c -c diff --git a/common.h b/common.h index 8527956..7709843 100644 --- a/common.h +++ b/common.h @@ -19,13 +19,6 @@ #endif -#ifndef MATH_HEADER -#define MATH_HEADER - -#include - -#endif - #ifndef COMMON_HEADER #define COMMON_HEADER diff --git a/common.o b/common.o index d255b40..734d90f 100644 Binary files a/common.o and b/common.o differ diff --git a/dcel.c b/dcel.c index 9ba0348..bc785a0 100644 --- a/dcel.c +++ b/dcel.c @@ -2,7 +2,7 @@ * * Created by Rory Healy (healyr@student.unimelb.edu.au) * Created on 25th August 2021 - * Last modified 11th September 2021 + * Last modified 13th September 2021 * * Contains functions for the DCEL data structure, including initialisation, * splitting an edge, and identifying towers in faces. @@ -16,74 +16,145 @@ #include "dcel.h" #endif -/* Deprecated by Grady's sample solution */ -vertex_t **readPolygon(vertex_t **vertices, FILE *polygonFile, \ - int *numVertices) { - double currentX, currentY; - int maxSizeVertices = 1; - while ((fscanf(polygonFile, "%lf %lf", ¤tX, ¤tY)) != EOF) { - /* Check if there enough space in the towers array */ - if (*numVertices == maxSizeVertices) { - maxSizeVertices *= 2; - vertex_t **temp = realloc(vertices, \ - maxSizeVertices * sizeof(*vertices)); +void freePoints(vertex_t **points, int numPoints) { + for (int i = 0; i < numPoints; i++) { + free(points[i]); + } + free(points); +} + +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 **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) { + /* Initial size of buffer is 1 as getline() reallocs as needed */ + size_t lineBufferSize = 1; + + /* Stores the current line from the points file */ + char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer)); + checkNullPointer(lineBuffer); + + /* Assuming that pointsFile is valid, there must be at least two points */ + int maxSizePoints = 2; + + while (getline(&lineBuffer, &lineBufferSize, pointsFile) > 0) { + /* Ensure there is enough space in the points array */ + if (*numPoints == maxSizePoints) { + maxSizePoints *= 2; + vertex_t **temp = realloc(points, maxSizePoints * sizeof(*points)); checkNullPointer(temp); - vertices = temp; + points = temp; } - /* The current vertex being filled in with information */ - vertices[*numVertices] = malloc(sizeof(*vertices[*numVertices])); - vertices[*numVertices]->x = currentX; - vertices[*numVertices]->y = currentY; - *numVertices += 1; - } - return vertices; -} + double xCoordinateA, yCoordinateA, xCoordinateB, yCoordinateB; + sscanf(lineBuffer, "%lf %lf %lf %lf", &xCoordinateA, &yCoordinateA, \ + &xCoordinateB, &yCoordinateB); + + points[*numPoints] = malloc(sizeof(*points[*numPoints])); + points[*numPoints]->x = xCoordinateA; + points[*numPoints]->y = yCoordinateA; + *numPoints += 1; -void freeVertices(vertex_t **vertices, int numVertices) { - for (int i = 0; i < numVertices; i++) { - free(vertices[i]); - } - free(vertices); -} - -bisector_t *getBisector(vertex_t *pointA, vertex_t *pointB) { - bisector_t *newBisector = malloc(sizeof(*newBisector)); - checkNullPointer(newBisector); - - double midpointX = (pointA->x + pointB->x) / 2; - double midpointY = (pointA->y + pointB->y) / 2; - - newBisector->midX = midpointX; - newBisector->midY = midpointY; - - /* Calculating bisector slope according to slope of AB */ - if (pointA->x == pointB->x) { - /* The line segment AB has an infinite gradient, - * so the orthogonal line will have zero slope. - */ - newBisector->slope = 0; - newBisector->isSlopeInfinite = 0; - } else if (pointA->y == pointB->y) { - /* The line segment AB has gradient of zero, so - * the orthogonal line will have an infinite slope. - */ - newBisector->isSlopeInfinite = 1; - - /* Not actually zero, just a placeholder to prevent - * accidental errors - */ - newBisector->slope = 0; - } else { - /* The line segment AB has a non-zero and finite gradient, - * so the gradient of the bisector can be calculated. - */ - newBisector->isSlopeInfinite = 0; - newBisector->slope = -1 / \ - ((pointB->y - pointA->y) / (pointB->x - pointA->x)); + points[*numPoints] = malloc(sizeof(*points[*numPoints])); + points[*numPoints]->x = xCoordinateB; + points[*numPoints]->y = yCoordinateB; + *numPoints += 1; } - return newBisector; + free(lineBuffer); + return points; } /* Here on out is the base code from Grady, with some alterations from me */ @@ -99,48 +170,6 @@ bisector_t *getBisector(vertex_t *pointA, vertex_t *pointB) { #define OUTSIDE (-1) #define NODIAMETER (-1) -double dist_2D(double x1, double y1, double x2, double y2) { - return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); -} - -double inv_dist_2D(double x1, double y1, double m, double c1, double d) { - /* Solve sqrt((y - y1)^2 + (x - x1)^2) = d^2 for x by substituting - * y = mx + c1, which gives an equation for x - * Using this, you can find a point that lies on the line y = mx + c1 - * that is of distance d away from (x1, y1). - */ - double a = m * m + 1; - double b = 2 * c1 * m - 2 * x1 - 2 * m * y1; - double c = c1 * c1 + x1 * x1 + y1 * y1 - 2 * c1 * y1 - d * d; - return (-b + sqrt(b * b - 4 * a * c)) / (2 * a); -} - -vertex_t *getBisectorPoint(double distance, bisector_t *b) { - vertex_t *returnPoint = malloc(sizeof(*returnPoint)); - if (b->isSlopeInfinite) { - returnPoint->x = b->midX; - returnPoint->y = b->midY + distance; - } else if (b->slope == 0) { - returnPoint->x = b->midX + distance; - returnPoint->y = b->midY; - } else { - /* Find the y-intercept of the bisector, use it to find the general - * form of the bisector in the form of y = mx + c - */ - double c = b->midY - b->slope * b->midX; - returnPoint->x = inv_dist_2D(b->midX, b->midY, b->slope, c, distance); - returnPoint->y = b->slope * returnPoint->x + c; - } - - /* Due to floating-point precision, there may be a situation where the - * distance between the bisector midpoint and returnPoint is slightly less - * than distance, but unless getBisectorPoint needs to guarentee that this - * distance is greater than distance, it shouldn't be an issue. - */ - - return returnPoint; -} - /* This intersection is based on code by Joseph O'Rourke and is provided for use in COMP20003 Assignment 2. @@ -246,15 +275,18 @@ enum intersectType intersects(halfEdge_t *he, bisector_t *b, \ double heEy = dcel->vertices[he->endVertex].y; /* Bisector x, y twin */ - double bSx = b->startX; - double bSy = b->startY; - double bEx = b->endX; - double bEy = b->endY; + 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. */ - // min-length not used here? - printf("In intersets(): minlength = %lf\n", minLength); - + /* Parametric equation parameters */ double t1, t2; @@ -344,53 +376,6 @@ enum intersectType intersects(halfEdge_t *he, bisector_t *b, \ } } -char *getIntersectionString(intersection_t *intersection) { - /* - - - - FILL IN - - - - */ - if (!intersection) { - return NULL; - } - char *returnString = NULL; - if (0 <= 0) { - /* Find out memory needed. */ - int stringLength = snprintf(returnString, 0, - "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)", - 0, 0.0, 0.0, - 0, 0.0, 0.0); - returnString = malloc(sizeof(*returnString) * (stringLength + 1)); - checkNullPointer(returnString); - sprintf(returnString, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)", - 0, 0.0, 0.0, - 0, 0.0, 0.0); - } else { - /* Find out memory needed. */ - int stringLength = snprintf(returnString, 0, - "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)", - 0, 0.0, 0.0, - 0, 0.0, 0.0); - returnString = malloc(sizeof(*returnString) * (stringLength + 1)); - checkNullPointer(returnString); - sprintf(returnString, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)", - 0, 0.0, 0.0, - 0, 0.0, 0.0); - } - return returnString; -} - -void freeIntersection(intersection_t *intersection) { - if (!intersection) { - return; - } - free(intersection); -} - DCEL_t *newDCEL() { /* Setup DCEL. */ DCEL_t *dcel = malloc(sizeof(*dcel)); @@ -1026,82 +1011,72 @@ int inFace(DCEL_t *dcel, double x, double y, int faceIndex) { return 1; } -int getDCELPointCount(DCEL_t *dcel) { - if (!dcel) { - return 0; +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 *currentIntersection = NULL; + + /* 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; + } else { + /* Second point of intersection */ + 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 dcel->verticesUsed; -} -double getDCELVertexX(DCEL_t *dcel, int vertex) { - return (dcel->vertices)[vertex].x; -} - -double getDCELVertexY(DCEL_t *dcel, int vertex) { - return (dcel->vertices)[vertex].y; -} - -int getDCELEdgeCount(DCEL_t *dcel) { - if (!dcel) { - return 0; - } - return dcel->edgesUsed; -} - -int getDCELEdgeVertexStart(DCEL_t *dcel, int edge) { - if (!dcel) { - return 0; - } - return (dcel->edges)[edge].halfEdge->startVertex; -} - -int getDCELEdgeVertexEnd(DCEL_t *dcel, int edge) { - if (!dcel) { - return 0; - } - return (dcel->edges)[edge].halfEdge->endVertex; -} - -int getDCELEdgeVertexPairStart(DCEL_t *dcel, int edge) { - if (!dcel) { - return 0; - } - return (dcel->edges)[edge].halfEdge->twin->startVertex; -} - -int getDCELEdgeVertexPairEnd(DCEL_t *dcel, int edge) { - if (!dcel) { - return 0; - } - return (dcel->edges)[edge].halfEdge->twin->endVertex; -} - -int DCELhasEdge(DCEL_t *dcel, int edge) { - if ((dcel->edges)[edge].halfEdge->face != NOFACE) { - return 1; - } else { - return 0; - } -} - -int DCELhasEdgePair(DCEL_t *dcel, int edge) { - if ((dcel->edges)[edge].halfEdge->face == NOFACE) { - return 0; - } - if ((dcel->edges)[edge].halfEdge->twin) { - return 1; - } else { - return 0; - } -} - -intersection_t *getIntersection(bisector_t *b, DCEL_t *dcel, int face, - double minLength) { - // FILL IN - printf("In getIntersection(): bisector start: %lf, dcel numfaces = %d" \ - "face = %d, minLength = %lf\n", b->startX, dcel->facesAllocated, \ - face, minLength); - return NULL; + return intersections; } double getDiameter(DCEL_t *dcel, int faceIndex) { diff --git a/dcel.h b/dcel.h index d13827a..25672ae 100644 --- a/dcel.h +++ b/dcel.h @@ -20,25 +20,15 @@ typedef struct vertex { } vertex_t; typedef struct bisector { - double startX; - double startY; - double endX; - double endY; - - /* This refers to the midpoint of the line segment AB, not the midpoint - * of the bisector itself. - */ - double midX; - double midY; - + vertex_t *mid; int isSlopeInfinite; double slope; } bisector_t; -typedef struct halfEdgeLabel { - struct halfEdgeLabel *previous; - struct halfEdgeLabel *next; - struct halfEdgeLabel *twin; +typedef struct halfEdge { + struct halfEdge *previous; + struct halfEdge *next; + struct halfEdge *twin; int face; int edge; int startVertex; @@ -47,6 +37,7 @@ typedef struct halfEdgeLabel { typedef struct edge { halfEdge_t *halfEdge; + tower_t *tower; } edge_t; typedef struct face { @@ -63,7 +54,10 @@ typedef struct split { } split_t; typedef struct intersection { - vertex_t intersectionPoint; + int fromEdge; + int toEdge; + vertex_t *fromPoint; + vertex_t *toPoint; } intersection_t; typedef struct DCEL { @@ -136,9 +130,6 @@ int vertexMatch(vertex_t *v1, vertex_t *v2); /* Gets the string for the given bisector equation. */ char *getBisectorEquation(bisector_t *b); -/* Frees the given bisector. */ -void freeBisector(bisector_t *bisector); - /* Representation of no face */ #define NOFACE (-1) @@ -148,18 +139,6 @@ void freeBisector(bisector_t *bisector); /* Default minimum length for bisector in each direction */ #define DEFAULTMINLENGTH (200) -/* Gets the intersection between the given bisector and the given DCEL - * for the given face. - */ -intersection_t *getIntersection(bisector_t *b, DCEL_t *dcel, \ - int face, double minLength); - -/* Gets the string for the given intersection. */ -char *getIntersectionString(intersection_t *intersection); - -/* Frees a given intersection. */ -void freeIntersection(intersection_t *intersection); - /* Applies a given split to the DCEL. */ void applySplit(split_t *split, DCEL_t *dcel); @@ -172,6 +151,13 @@ int getFaceCount(DCEL_t *dcel); /* Returns 1 if the given x,y point is inside the given face. */ int inFace(DCEL_t *dcel, double x, double y, int faceIndex); +/* Gets the 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); + /* Gets the diameter of the given face. */ double getDiameter(DCEL_t *dcel, int faceIndex); @@ -180,60 +166,7 @@ double getDiameter(DCEL_t *dcel, int faceIndex); */ void incrementalVoronoi(DCEL_t *dcel, tower_t *watchTower); -/* Returns the number of vertices in the DCEL. */ -int getDCELPointCount(DCEL_t *dcel); - -/* Get x value of given vertex in DCEL. */ -double getDCELVertexX(DCEL_t *dcel, int vertex); - -/* Get y value of given vertex in DCEL. */ -double getDCELVertexY(DCEL_t *dcel, int vertex); - -/* Returns the number of edges in the DCEL. */ -int getDCELEdgeCount(DCEL_t *dcel); - -/* Get start vertex of given edge in DCEL. */ -int getDCELEdgeVertexStart(DCEL_t *dcel, int edge); - -/* Get end vertex of given edge in DCEL. */ -int getDCELEdgeVertexEnd(DCEL_t *dcel, int edge); - -/* Get start vertex of paired given edge in DCEL. */ -int getDCELEdgeVertexPairStart(DCEL_t *dcel, int edge); - -/* Get end vertex of paired given edge in DCEL. */ -int getDCELEdgeVertexPairEnd(DCEL_t *dcel, int edge); - -/* Check if the DCEL has the given edge. */ -int DCELhasEdge(DCEL_t *dcel, int edge); - -/* Check if the DCEL has a pair for the given edge. */ -int DCELhasEdgePair(DCEL_t *dcel, int edge); - -/* My own functions */ - -/* Reads the polygon file and stores the information in the vertices array */ -vertex_t **readPolygon(vertex_t **vertices, FILE *polygonFile, \ - int *numVertices); - -/* Frees an array of vertices */ -void freeVertices(vertex_t **vertices, int numVertices); - -/* Calculates and returns the equation of a bisector of two points */ -bisector_t *getBisector(vertex_t *pointA, vertex_t *pointB); - -/* Euclidian distance between two 2D points */ -double dist_2D(double x1, double y1, double x2, double y2); - -/* Returns a value for x that ensures the point (x, y) is at least d (distance) - * away from (x1, y1) whilst ensuring (x, y) is on the line y = mx + c1. - */ -double inv_dist_2D(double x1, double y1, double m, double c, double d); - -/* Returns a point at least distance away from the midpoint of the bisector given */ -vertex_t *getBisectorPoint(double distance, bisector_t *b); - -/* O'Rourke's functions */ +/* 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. */ @@ -254,8 +187,42 @@ enum intersectType parallelIntersects(double heSx, double heSy, \ double heEx, double heEy, double bSx, double bSy, \ double bEx, double bEy, double *x, double *y); -/* Tests if */ +/* Tests if a half edge and a bisector intersect */ 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 diff --git a/dcel.o b/dcel.o index aca2613..78c1473 100644 Binary files a/dcel.o and b/dcel.o differ diff --git a/input.c b/input.c index bfae7eb..1bec771 100644 --- a/input.c +++ b/input.c @@ -5,7 +5,7 @@ * Last modified 9th September 2021 * * Contains functions for ensuring correct input arguments are given for - * each stage of the voronoi2 program. + * each stage of the voronoi2 program. Adapted from Grady's base code on Ed. * */ diff --git a/input.o b/input.o index a46796f..325dbb4 100644 Binary files a/input.o and b/input.o differ diff --git a/main.c b/main.c index 24d23a2..1a0c4f0 100644 --- a/main.c +++ b/main.c @@ -12,14 +12,6 @@ * */ -#ifndef DCEL_HEADER -#include "dcel.h" -#endif - -#ifndef COMMON_HEADER -#include "common.h" -#endif - #ifndef VORONOI_HEADER #include "voronoi.h" #endif @@ -28,38 +20,6 @@ #include "input.h" #endif -// int main(int argc, char **argv) { -// /* Input and output files */ -// FILE *datasetFile = NULL, *polygonFile = NULL, *outputFile = NULL; -// checkInputArgs(argc, argv, &datasetFile, &polygonFile, &outputFile); - -// /* Stores information about the towers given in dataset file */ -// tower_t **towers = malloc(sizeof(*towers)); -// checkNullPointer(towers); -// int numTowers = 0; -// towers = readTowers(towers, datasetFile, &numTowers); - -// /* Stores information about the vertices in the polygon file */ -// vertex_t **vertices = malloc(sizeof(*vertices)); -// checkNullPointer(vertices); -// int numVertices = 0; -// vertices = readPolygon(vertices, polygonFile, &numVertices); - -// /* Create DCEL structure from vertices */ - -// /* Check for splits, split the polygon if needed */ - -// /* Counts towers in each polygon, outputs to outputFile */ - -// /* Cleaning up data */ -// freeTowers(towers, numTowers); -// freeVertices(vertices, numVertices); -// fclose(datasetFile); -// fclose(polygonFile); -// fclose(outputFile); -// return 0; -// } - int main(int argc, char **argv) { /* Ensure input arguments are correct */ if (argc == 1) { @@ -96,7 +56,7 @@ int main(int argc, char **argv) { /* Return error if stage number isn't defined. */ case STAGE_ERROR: default: - fprintf(stderr, "Stage was not handled ENUM value (%d)\n", stage); + printArgError(stage, "Invalid stage entered."); exit(EXIT_FAILURE); } diff --git a/main.o b/main.o index d5ba5ac..4cceff8 100644 Binary files a/main.o and b/main.o differ diff --git a/output.txt b/output.txt index e69de29..5080ec9 100644 --- a/output.txt +++ b/output.txt @@ -0,0 +1,6 @@ +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) diff --git a/towers.c b/towers.c index 0d66bcb..e9dc503 100644 --- a/towers.c +++ b/towers.c @@ -1,4 +1,13 @@ - +/* voronoi.c + * + * Created by Rory Healy (healyr@student.unimelb.edu.au) + * Created on 11th September 2021 + * Last modified 13th September 2021 + * + * Contains functions for reading a CSV of watchtower information into an + * array of towers. + * + */ #ifndef TOWERS_HEADER #include "towers.h" @@ -10,7 +19,7 @@ #define NUM_CSV_FIELDS 6 tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) { - /* Maximum length of a single CSV line */ + /* 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 */ @@ -22,7 +31,7 @@ tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) { /* Discard the header line, then read the rest of the CSV */ getline(&lineBuffer, &lineBufferSize, datasetFile); while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) { - /* Check if there enough space in the towers array */ + /* Ensure there is enough space in the towers array */ if (*numTowers == maxSizetowers) { maxSizetowers *= 2; tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers)); @@ -34,7 +43,7 @@ tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) { towers[*numTowers] = malloc(sizeof(*towers[*numTowers])); readCurrentTower(lineBuffer, towers[*numTowers]); - *numTowers += 1; + *numTowers += 1; } free(lineBuffer); return towers; diff --git a/towers.o b/towers.o index 04f55ab..32c15bb 100644 Binary files a/towers.o and b/towers.o differ diff --git a/voronoi.c b/voronoi.c index 78ef41f..abeedd6 100644 --- a/voronoi.c +++ b/voronoi.c @@ -2,75 +2,32 @@ * * Created by Rory Healy (healyr@student.unimelb.edu.au) * Created on 12th August 2021 - * Last modified 11th September 2021 + * Last modified 13th September 2021 * * Contains functions involving the generation of the Voronoi diagram, and * running each stage of the assignment. * */ -#ifndef COMMON_HEADER -#include "common.h" -#endif - #ifndef VORONOI_HEADER #include "voronoi.h" #endif -vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints) { - /* Initial size of buffer is 1 as getline() reallocs as needed */ - size_t lineBufferSize = 1; - - /* Stores the current line from the points file */ - char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer)); - checkNullPointer(lineBuffer); - - /* Assuming that pointsFile is valid, there must be at least two points */ - int maxSizePoints = 2; - - while (getline(&lineBuffer, &lineBufferSize, pointsFile) > 0) { - /* Check if there is enough space in the points array */ - if (*numPoints == maxSizePoints) { - maxSizePoints *= 2; - vertex_t **temp = realloc(points, maxSizePoints * sizeof(*points)); - checkNullPointer(temp); - points = temp; - } - - double xCoordinateA, yCoordinateA, xCoordinateB, yCoordinateB; - sscanf(lineBuffer, "%lf %lf %lf %lf", &xCoordinateA, &yCoordinateA, \ - &xCoordinateB, &yCoordinateB); - - points[*numPoints] = malloc(sizeof(*points[*numPoints])); - points[*numPoints]->x = xCoordinateA; - points[*numPoints]->y = yCoordinateA; - *numPoints += 1; - - points[*numPoints] = malloc(sizeof(*points[*numPoints])); - points[*numPoints]->x = xCoordinateB; - points[*numPoints]->y = yCoordinateB; - *numPoints += 1; - } - - free(lineBuffer); - return points; -} - void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) { if (bisector->isSlopeInfinite) { /* Cannot print infinite slope, so print only x-intercept */ - fprintf(outputFile, "x = %lf\n", bisector->midX); + fprintf(outputFile, "x = %lf\n", bisector->mid->x); } else { fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \ - bisector->slope, bisector->midX, bisector->midY); + bisector->slope, bisector->mid->x, bisector->mid->y); } } -void freePoints(vertex_t **points, int numPoints) { - for (int i = 0; i < numPoints; i++) { - free(points[i]); - } - free(points); +void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) { + fprintf(outputFile, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)\n", \ + intersection->fromEdge, intersection->fromPoint->x, \ + intersection->fromPoint->y, intersection->toEdge, \ + intersection->toPoint->x, intersection->toPoint->y); } void stage1(char *pointsFileName, char *outputFileName) { @@ -84,23 +41,27 @@ void stage1(char *pointsFileName, char *outputFileName) { int numPoints = 0; points = readPoints(points, pointsFile, &numPoints); + /* There are half as many bisectors as points */ + int numBisectors = numPoints / 2; + bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors); + checkNullPointer(bisectors); + bisectors = getBisectors(bisectors, points, numBisectors); + /* For each pair, calculate and print the bisector to outputFile */ - for (int i = 0; i < numPoints; i += 2) { - bisector_t *currBisector = getBisector(points[i], points[i + 1]); - stage1PrintBisector(currBisector, outputFile); - free(currBisector); + for (int i = 0; i < numBisectors; i++) { + stage1PrintBisector(bisectors[i], outputFile); } /* Clean up */ freePoints(points, numPoints); + freeBisectors(bisectors, numBisectors); fclose(pointsFile); fclose(outputFile); } void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) { - FILE *pointsFile = NULL, *polygonFile = NULL, *outputFile = NULL; + FILE *pointsFile = NULL, *outputFile = NULL; pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r"); - polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r"); outputFile = safeFileOpen(&outputFile, outputFileName, "w"); /* Points are given as pairs, so initialise 2 points */ @@ -109,17 +70,32 @@ void stage2(char *pointsFileName, char *polygonFileName, char *outputFileName) { int numPoints = 0; points = readPoints(points, pointsFile, &numPoints); + /* There are half as many bisectors as points */ + int numBisectors = numPoints / 2; + bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors); + checkNullPointer(bisectors); + bisectors = getBisectors(bisectors, points, numBisectors); + /* Construct the DCEL from the polygon file */ DCEL_t *dcel = readPolygonFile(polygonFileName); /* Calculate and print intersections to the output file */ - + intersection_t **intersections = malloc(sizeof(*intersections)); + checkNullPointer(intersections); + int numIntersections = 0; + intersections = getIntersections(intersections, &numIntersections, bisectors, numBisectors, dcel, DEFAULT_FACE, \ + DEFAULTMINLENGTH); + + for (int i = 0; i < numIntersections; i++) { + stage2PrintIntersection(intersections[i], outputFile); + } /* Clean up */ freePoints(points, numPoints); + freeBisectors(bisectors, numBisectors); + freeIntersections(intersections, numIntersections); freeDCEL(dcel); fclose(pointsFile); - fclose(polygonFile); fclose(outputFile); } diff --git a/voronoi.h b/voronoi.h index 8f059ac..7088143 100644 --- a/voronoi.h +++ b/voronoi.h @@ -5,14 +5,11 @@ #ifndef VORONOI_HEADER #define VORONOI_HEADER -/* Reads a points file and stores the information in the points array */ -vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints); - /* Prints bisectors to an output file */ void stage1PrintBisector(bisector_t *bisector, FILE *outputFile); -/* Frees all points from a points array */ -void freePoints(vertex_t **points, int numPoints); +/* Prints intersections to an output file */ +void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile); /* Outputs the bisector equations from pointsFile into outputFile */ void stage1(char *pointsFileName, char *outputFileName); diff --git a/voronoi.o b/voronoi.o index 4b32af2..bd23345 100644 Binary files a/voronoi.o and b/voronoi.o differ diff --git a/voronoi2 b/voronoi2 index a1adcbe..ed784ff 100755 Binary files a/voronoi2 and b/voronoi2 differ