Update project structure
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.o
|
||||||
|
build/
|
||||||
|
voronoi2
|
46
.vscode/launch.json
vendored
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
5
.vscode/settings.json
vendored
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"type_traits": "c"
|
|
||||||
}
|
|
||||||
}
|
|
37
Makefile
|
@ -1,22 +1,15 @@
|
||||||
# Link command:
|
BUILDDIR=$(CURDIR)/build
|
||||||
voronoi2: common.o towers.o dcel.o voronoi.o input.o main.o
|
NAME=voronoi2
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o towers.o common.o -lm
|
|
||||||
|
$(NAME): build/common.o build/towers.o build/dcel.o build/voronoi.o build/input.o build/main.o | $(BUILDDIR)
|
||||||
# Compilation commands
|
gcc -Wall -Wextra -Werror -pedantic -g -o $(NAME) $^ -lm
|
||||||
common.o: common.c
|
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c
|
build/%.o: src/%.c
|
||||||
|
gcc -Wall -Wextra -Werror -pedantic -g -c $< -o $@
|
||||||
towers.o: towers.c
|
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o towers.o towers.c -c
|
$(BUILDDIR):
|
||||||
|
mkdir -p $(BUILDDIR)
|
||||||
dcel.o: dcel.c
|
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c
|
clean:
|
||||||
|
@rm -rf build
|
||||||
voronoi.o: voronoi.c
|
@rm -f $(NAME)
|
||||||
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi.o voronoi.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
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
## COMP20003 Assignment 2
|
## COMP20003 Assignment 2 - Voronoi Diagrams
|
||||||
|
|
BIN
common.o
BIN
dcel.o
448
docs/SPECIFICATION.md
Normal file
|
@ -0,0 +1,448 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Assignment Specification
|
||||||
|
|
||||||
|
Below is the assignment specification, in full, slightly edited for context and appearence.
|
||||||
|
|
||||||
|
## Voronoi Diagram: The Fundamentals
|
||||||
|
|
||||||
|
In the [first assignment](https://git.roryhealy.dev/unimelb-projects/comp20003-project01), the DCEL was implemented. We used it to store the regions each watchtower was responsible for. However, if you are given a point location, how do you find the nearest watchtower? An obvious solution is to compute the distance to all watchtowers and to select afterward the closest one (pick one randomly if there is more than one). This works fine if you have a single query but the cost is of course $O(mn)$ for $m$ queries if there are $n$ watchtowers.
|
||||||
|
|
||||||
|
An alternative approach is to precompute the region of all points that is closer to a watchtower than to all other watchtowers. This region is called the *Voronoi region* or *Voronoi cell* of that watchtower. If we computed the Voronoi cell for each watchtower (note that this region is unique), then we could simply lookup the region that contains our location and know the responsible watchtower. The planar subdivision of all Voronoi cells is called the ***Voronoi*** ***diagram***.
|
||||||
|
|
||||||
|
### Bisector
|
||||||
|
|
||||||
|
An important concept for Voronoi diagrams is the bisector of two points. The bisector is orthogonal to the line segment connecting the two points and is equidistant to both points. If you had a compass, you would simply center the compass on each site, draw a circle (it does not have to have the other site on its circumference but the circles need to overlap to generate at least one intersection). Of course, for an implementation, we need an actual formula. The point $S_m$ is easy to compute as it is just the midpoint of $S_1$ and $S_2$, which is calculated as:
|
||||||
|
|
||||||
|
$$
|
||||||
|
S_m = \bigg(\frac{S_{1x} + S_{2x}}{2}, \frac{S_{1y} + S_{2y}}{2}\bigg)
|
||||||
|
$$
|
||||||
|
|
||||||
|
The actual bisector is just a usual straight line and its formula is:
|
||||||
|
|
||||||
|
$$
|
||||||
|
y = -\frac{S_{2x} - S_{1x}}{S_{2y} - S_{1y}} \times (x - S_{mx}) + S_{my}
|
||||||
|
$$
|
||||||
|
|
||||||
|
![](./images/image01.png)
|
||||||
|
|
||||||
|
Note that every point on the bisector is equidistant to the sites $S_1$ and $S_2$. In particular, it divides the line segment $\overline{S1S2}$ into two equal halves at point $S_m$. Finally, the line segment $\overline{S1S2}$ is orthogonal to the bisector $b_{12}$.
|
||||||
|
|
||||||
|
### Voronoi cell
|
||||||
|
|
||||||
|
In this assignment, we will use the DCEL to store the Voronoi diagram. More formally, in general we have $n$ sites $S_1, \dots, S_n$ (our watchtowers), then the ***Voronoi cell*** of a site $S_i$ for a given region $R$ (say Victoria) is defined as the set of points $P$ in the given region $R$ that fulfil the following condition:
|
||||||
|
|
||||||
|
```math
|
||||||
|
VC(S_i) = \{P \in R\ |\ dist(P, S_i) \lt dist(P, S_j)\ \forall\ S_j,\ j \neq i \}
|
||||||
|
```
|
||||||
|
|
||||||
|
$dist(\sdot,\ \sdot)$ is the usual Euclidean distance between two points.
|
||||||
|
|
||||||
|
### Voronoi edges and Voronoi vertices
|
||||||
|
|
||||||
|
A shared edge between two Voronoi cells is called a ***Voronoi edge***. If $S_i$ and $S_j$ are two sites whose Voronoi cells share an edge $e_{ij}$, then all the points on $e_{ij}$ are equidistant to $S_i$ and $S_j$. This means that a Voronoi edge is part of the perpendicular bisector between two sites $S_i$ and $S_j$. Voronoi cells can share at most one Voronoi edge. In the figure the sites $S_0$ and $S_4$ share edge $e_{04}$.
|
||||||
|
|
||||||
|
A point at which the edges of three (or more) Voronoi cells meet is called a ***Voronoi vertex***. If $S_i$, $S_j$ and $S_k$ are three sites with shared Voronoi edges $e_{ij}$, $e_{ik}$, and $e_{jk}$ that meet in $V_{ijk}$, then the Voronoi vertex is the circumcentre of the triangle with vertices $S_i$, $S_j$ and $S_k$, because the points $S_i$, $S_j$ and $S_k$ are all equidistant to $V_{ijk}$.
|
||||||
|
|
||||||
|
For example, the vertex $V_{234}$ is shared by the edges $e_{23}$, $e_{24}$ and $e_{34}$ in the figure below:
|
||||||
|
|
||||||
|
![](./images/image02.png)
|
||||||
|
|
||||||
|
Usually, there are two types of Voronoi edges: those that connect two Voronoi vertices and those start from a single vertex and are unbounded (i.e., are infinite). We will assume a (convex) polygon around our Voronoi sites, which clips all infinite edges. This means you can assume that all Voronoi edges are bounded and you use for the second point on the edge simply the intersection points of the polygon with the Voronoi edges.
|
||||||
|
|
||||||
|
In the figure above, the Polygon is defined by the points $A$ to $P$ and the unbounded Voronoi edges $e_{01}$, $e_{02}$, $e_{23}$, $e_{13}$ are described as line segments $\overline{V_{014}P_{01}}$, $\overline{V_{024}P_{02}}$, $\overline{V_{234}P_{23}}$, $\overline{V_{134}P_{13}}$, respectively.
|
||||||
|
|
||||||
|
By the way: there are as many Voronoi cells as we have sites, and if we have $n$ sites, then there are $O(n)$ vertices and edges.
|
||||||
|
|
||||||
|
If we had two sites $S_1$ and $S_2$, what would the Voronoi diagram look like assuming a bounding rectangle as a polygon? Here is an example:
|
||||||
|
|
||||||
|
![](./images/image03.png)
|
||||||
|
|
||||||
|
The two Voronoi cells are simply the result of inserting the bisector between those two sites. All the points in the green cell are closer to the left site, and all the points in the purple cell are closer to right site. In the next figure, we have inserted a third site. Since we have three sites, we get exactly one Voronoi vertex.
|
||||||
|
|
||||||
|
![](./images/image04.png)
|
||||||
|
|
||||||
|
We insert another site and obtain four Voronoi cells
|
||||||
|
|
||||||
|
![](./images/image05.png)
|
||||||
|
|
||||||
|
After inserting another site, we get the first Voronoi cell that has no infinite edges (the brown cell).
|
||||||
|
|
||||||
|
![](./images/image06.png)
|
||||||
|
|
||||||
|
This is the Voronoi diagram after inserting 20 more sites (25 in total):
|
||||||
|
|
||||||
|
![](./images/image07.png)
|
||||||
|
|
||||||
|
[Here](./videos/voronoi.mp4) is a video that shows that the insertion of another site only impacts a few selected Voronoi cells in its neighborhood.
|
||||||
|
|
||||||
|
A final note: finding the Voronoi cell for a given point location can be achieved in $O(\log n)$ time given $n$ sites. The reason is that every Voronoi cell is convex. However, we will not implement this algorithm here but it shows that the original problem of locating $m$ points - stated in the introduction above - can be done in $O(m\log n)$.
|
||||||
|
|
||||||
|
## Task 1: Compute and output equations for bisectors
|
||||||
|
|
||||||
|
The description above motivated the use of an incremental algorithm to compute the Voronoi diagram. We first build the Voronoi diagram for 3 sites through the use of bisectors. Bisectors were described in the previous entry. Your task is to compute and output equations for bisectors given pairs of points in a file.
|
||||||
|
|
||||||
|
Your implementation will receive three arguments, one for the stage and two filenames. The first filename argument is a file that will contain a list of point pairs, one pair per line where the $x$ and $y$ coordinates are separated by a blank. The second filename argument is an output file that contains the equations for all bisectors.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
The point pairs file [pp_inside.txt](../test/data/point-pairs/pp_inside.txt) contains the following point pairs:
|
||||||
|
|
||||||
|
```
|
||||||
|
145.6 -34.2 145.6 -35.2
|
||||||
|
145.6 -34.2 145.6 -36.2
|
||||||
|
145.6 -35.2 148.6 -35.2
|
||||||
|
147.6 -35.2 146.6 -35.2
|
||||||
|
148.6 -35.2 146.6 -35.2
|
||||||
|
148.6 -34.2 146.6 -32.2
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `./voronoi2 1 pp_inside.txt 1-outfile-inside.txt` the contents of `1-outfile-inside.txt` would be:
|
||||||
|
|
||||||
|
```
|
||||||
|
y = 0.000000 * (x - 145.600000) + -34.700000
|
||||||
|
y = 0.000000 * (x - 145.600000) + -35.200000
|
||||||
|
x = 147.100000
|
||||||
|
x = 147.100000
|
||||||
|
x = 147.600000
|
||||||
|
y = 1.000000 * (x - 147.600000) + -33.200000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task 2: Compute and output intersection points for bisectors against a given polygon
|
||||||
|
|
||||||
|
In this task you will output the intersections between bisectors and a given polygon. Your implementation will receive four arguments, one representing the task number and three filenames. The first filename argument is a file that will contain a list of point pairs, one pair per line where the $x$ and $y$ coordinates are separated by a blank. The second argument is a file that will contain the initial polygon to be stored as a DCEL. The third argument is an output file that contains all intersections of the bisectors with the provided polygon. These will specify which edge in the DCEL the bisectors intersected, and the points these occurred at.
|
||||||
|
|
||||||
|
### Provided intersection code
|
||||||
|
|
||||||
|
[This](./intersection.c) provided intersection code is non-trivial, and even a single error is difficult to spot visually. We have provided this code for you here, you are welcome to treat it as a magic black box - the areas to fill in are `...`. You just need to add in your half-edges start and end, and bisector segment start and end. This gives a more detailed diagnosis, but it is sufficient to check if it `DOESNT_INTERSECT` to determine intersection.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
The point pairs file [pp_inside.txt](../test/data/point-pairs/pp_inside.txt) contains the following point pairs:
|
||||||
|
|
||||||
|
```
|
||||||
|
145.6 -34.2 145.6 -35.2
|
||||||
|
145.6 -34.2 145.6 -36.2
|
||||||
|
145.6 -35.2 148.6 -35.2
|
||||||
|
147.6 -35.2 146.6 -35.2
|
||||||
|
148.6 -35.2 146.6 -35.2
|
||||||
|
148.6 -34.2 146.6 -32.2
|
||||||
|
```
|
||||||
|
|
||||||
|
The polygon file [polygon_square.txt](../tests/data/polygons/polygon_square.txt) contains the following coordinates:
|
||||||
|
|
||||||
|
```
|
||||||
|
140.9 -39.2
|
||||||
|
140.9 -33.9
|
||||||
|
150.0 -33.9
|
||||||
|
150.0 -39.2
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `./voronoi2 2 pp_inside.txt polygon_square.txt 2-outfile.txt` the contents of `2-outfile.txt` would be:
|
||||||
|
|
||||||
|
```
|
||||||
|
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)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task 3: Computation of the Voronoi Diagram
|
||||||
|
|
||||||
|
### An incremental algorithm to compute the Voronoi diagram
|
||||||
|
|
||||||
|
How do we enhance our algorithm to work with $n \gt 3$ sites assuming we have a Voronoi diagram for 3 sites already? The algorithm works as follows: assume a new site $S_m$ (see the figure below) is inserted into a Voronoi diagram that has already $k$ sites. The Voronoi cell of $S_m$ is then created as follows:
|
||||||
|
|
||||||
|
- Find the Voronoi cell $VC(S_i)$ that contains $S_m$.
|
||||||
|
|
||||||
|
- Compute the bisector $b_{im}$ of $S_i$ and $S_m$.
|
||||||
|
|
||||||
|
- The bisector $b_{im}$ intersects two edges of $V(S_i)$, say $e_{i_0}$ and $e_{i_1}$ in counter-clockwise direction.
|
||||||
|
|
||||||
|
- If both edges are Voronoi edges (i.e., have a twin (opposite, pair) edge), then the algorithm proceeds as follows:
|
||||||
|
|
||||||
|
- Store the new Voronoi edge of $VC(S_m)$ that connects $e_{i_0}$ and $e_{i_1}$ at their intersection points.
|
||||||
|
|
||||||
|
- Retrieve the Voronoi site using the DCEL of the edge $e_{i_1}$, say $S_{i_1}$.
|
||||||
|
|
||||||
|
- Process the second edge intersection (in counter-clockwise direction) compute the second edge of $S_{i_0}$ that intersects $b_{{i_1}m}$, say $e_{i_2}$.
|
||||||
|
|
||||||
|
- If the next edge is also a Voronoi edge, retrieve the Voronoi site using the DCEL of the edge $e_{i_2}$, say $S_{i_2}$. If every encountered edge is a Voronoi edge, repeat the algorithm until $e_{i_j} = e_{i_0}$.
|
||||||
|
|
||||||
|
- If the algorithm intersects at any stage an edge that is not a Voronoi edge, i.e., an edge of the enclosing polygon, it terminates this search for further Voronoi edges. *Note that could happen even at the beginning and we will have only Voronoi vertex because the Voronoi cell would be unbounded if we did not assume an initial polygon.*
|
||||||
|
|
||||||
|
- Instead, the algorithm may intersect a non-Voronoi edge and continue its search along the initial polygon and terminates its search until it visits $e_{i_0}$ again.
|
||||||
|
|
||||||
|
### Incrementally updating the DCEL
|
||||||
|
|
||||||
|
Of course you need to update all edges in the DCEL, whenever you compute an edge for $S_m$. You will also need to delete all old Voronoi vertices that are enclosed by the new Voronoi cell $VC(S_m)$. There are basically two cases that will happen:
|
||||||
|
|
||||||
|
- The bisector intersects two edges that are adjacent, i.e., share a single vertex. Then you need to delete the shared vertex, split the intersected edges and store the updated edges for the Voronoi cell that is intersected by the bisector.
|
||||||
|
|
||||||
|
- The bisector intersects two non-adjacent edges. Then you need to traverse all edges -- starting from the second intersected edges -- in clockwise order using the *.next* operation until you encounter the first intersected edge. All edges and their shared vertices have to removed. Then you need to split the intersected edges as before and and store the updated edges for the Voronoi cell that is intersected by the bisector.
|
||||||
|
|
||||||
|
Finally, you need to insert the new site into the DCEL including the new edges and their start points.
|
||||||
|
|
||||||
|
### Manual example
|
||||||
|
|
||||||
|
In the example below we have already 5 existing sites $S_0, \dots, S_4$ and wish to insert site $S_5$.
|
||||||
|
|
||||||
|
- In the first step we compute that $S_5$ is in $VC(S_4)$ and compute the bisector of $S_5$ and $S_4$, which intersects the edges $e_{24}$ and $e_{14}$ in counter-clockwise order.
|
||||||
|
|
||||||
|
- Since $e_{14}$ is the edge between $S_4$ and $S_1$, we compute the bisector between $S_1$ and $S_5$, which intersects edge $e_{13}$. This implies that the next site is $S_3$.
|
||||||
|
|
||||||
|
- We then apply the algorithm and compute the next intersection of the bisector of $S_5$ and $S_3$, which is the edge $e_{23}$. Thus, the next site is $S_2$ and the intersection of the bisector $S_5$ and $S_2$ is the edge $e_{24}$.
|
||||||
|
|
||||||
|
- Since we have discovered the edge $e_{24}$ before, the algorithm terminates.
|
||||||
|
|
||||||
|
We now have to update all purple edges (and vertices), and have to insert the new edges, highlighted as dashed edges.
|
||||||
|
|
||||||
|
- This means that we have to delete the vertices $V_{134}$ and $V_{234}$.
|
||||||
|
|
||||||
|
- We also have to delete the edge $e_{34}$ connecting $V_{134}$ and $V_{234}$.
|
||||||
|
|
||||||
|
- Finally, we have to apply the corresponding split operations you have studied in assignment 1 on $e_{24}$, $e_{34}$ and $e_{14}$.
|
||||||
|
|
||||||
|
- Finally, we insert the new dashed edges $e_{45}$, $e_{25}$, $e_{35}$ and $e_{15}$ into the DCEL for the Voronoi cell $VC(S_5)$.
|
||||||
|
|
||||||
|
![](./images/image08.png)
|
||||||
|
|
||||||
|
### The diameter of a Voronoi cell
|
||||||
|
|
||||||
|
You will need to retrieve all Voronoi cells from the DCEL and compute their diameter. The ***diameter*** of a set $S$ is the least upper bound of all distances between point pairs in $S$. Fortunately, all Voronoi cells are convex polygons (remember that a set is convex if for every point pair the segment connecting the points is also in the set). This means that the diameter is easy to compute:
|
||||||
|
|
||||||
|
You just need to compute the distances of all pairs of vertices of a Voronoi cell and select the largest distance.
|
||||||
|
|
||||||
|
It is clear that this algorithm has quadratic complexity in the number of vertices of a Voronoi cell and we have n Voronoi cells for n sites.
|
||||||
|
|
||||||
|
If you are curious: there are faster ways to compute the diameter of a Voronoi cell (or in fact any convex polygon) that are based on the concept of supporting lines. However, this proved to be more difficult than initially thought and a few incorrect algorithms have been published as a consequence! This shows again how important it is to verify the correctness of your algorithms. You can find more information about this [here](http://cgm.cs.mcgill.ca/~athens/cs507/Projects/2000/MS/diameter/node4.html).
|
||||||
|
|
||||||
|
### Your task
|
||||||
|
|
||||||
|
Your task is to compute the Voronoi diagram iteratively. In addition to the argument specifying your program should run task 3, your implementation will receive three filenames as an arguments and will build the Voronoi diagram reading from the first two files and outputting the site/watchtower data and the diameter of each Voronoi cell to the output file.
|
||||||
|
|
||||||
|
- The first file contains all Voronoi sites, i.e., the watchtower from the first assignment, again stored in csv format, one per line, representing the fields associated with each site. Again, your program must read in the records line by line.
|
||||||
|
|
||||||
|
- The second file will contain a list of $(x, y)$ coordinates that describe the vertices of a region $R$ (such as the state of Victoria) as a polygon. Each vertex $(x, y)$ of the region's boundary is stored on a separate line. The coordinates are separated by a space on each line.
|
||||||
|
|
||||||
|
- After processing the second input file, a Voronoi diagram is constructed, separating all points into their own cell with all points in the cell being closest to the site/watchtower in the cell. The site/watchtower data and its diameter(s) are written to the output file.
|
||||||
|
|
||||||
|
#### Note
|
||||||
|
|
||||||
|
The algorithm described above makes a few assumptions to avoid dealing with special cases:
|
||||||
|
|
||||||
|
- Not three watchtowers are collinear.
|
||||||
|
|
||||||
|
- No Voronoi vertex has more than three Voronoi edges.
|
||||||
|
|
||||||
|
- The initial polygon is large enough to contain all Voronoi vertices.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
When run with the number 3 as the first argument, your program should take four arguments. The first argument is this task indicator. The other three arguments are files with the same meaning as the first assignment. The second argument will be the filename of a csv-format list of watchtowers with the same structure as the first assignment, the third argument will be a list of points, one per line, with each coordinate separated by a single space. The fourth argument will be the file to output to.
|
||||||
|
|
||||||
|
The watchtower file [dataset_3.csv](../tests/data/watchtowers/dataset_3.csv) contains the following information:
|
||||||
|
|
||||||
|
```csv
|
||||||
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
||||||
|
```
|
||||||
|
|
||||||
|
The polygon file [polygon_square.txt](../tests/data/polygons/polygon_square.txt) contains the following coordinates:
|
||||||
|
|
||||||
|
```
|
||||||
|
140.9 -39.2
|
||||||
|
140.9 -33.9
|
||||||
|
150.0 -33.9
|
||||||
|
150.0 -39.2
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `./voronoi2 3 dataset_3.csv polygon_square.txt 3-outfile.txt` the contents of `3-outfile.txt` would be:
|
||||||
|
|
||||||
|
```
|
||||||
|
Watchtower ID: WT3953SGAEI, Postcode: 3953, Population Served: 1571, Watchtower Point of Contact Name: Ofelia Kadlec, x: 145.778002, y: -38.559840, Diameter of Cell: 7.144748
|
||||||
|
Watchtower ID: WT3765SHSPB, Postcode: 3765, Population Served: 3380, Watchtower Point of Contact Name: Eilene Horner, x: 145.362014, y: -37.818943, Diameter of Cell: 9.518041
|
||||||
|
Watchtower ID: WT3530RJWDT, Postcode: 3530, Population Served: 63, Watchtower Point of Contact Name: Troy Clark, x: 143.083467, y: -35.792994, Diameter of Cell: 7.935830
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the addition of the **Diameter of Cell** field.
|
||||||
|
|
||||||
|
## Task 4: Computing the diameter of all Voronoi cells and sort them in ascending order by diameter
|
||||||
|
|
||||||
|
Your task has the same input and output files as Task 3 but this time you need to output the sites/watchtowers in order of the length of the diameter of their corresponding Voronoi cell in ascending order, i.e., smallest to largest. Your sorting algorithm has to be stable, which means that for two sites with equal diameter the one with a smaller ID is stored first.
|
||||||
|
|
||||||
|
To sort the Voronoi cells by diameter, you will implement *Insertion Sort*. Here is its pseudocode (note that the ⟵ sign is used to assign values to a variable):
|
||||||
|
|
||||||
|
```
|
||||||
|
InsertionSort(A[0..n - 1])
|
||||||
|
|
||||||
|
for i ⟵ 1 to n - 1 do
|
||||||
|
|
||||||
|
v ⟵ A[i]
|
||||||
|
j ⟵ i – 1
|
||||||
|
|
||||||
|
while j >= 0 and A[j] > v do
|
||||||
|
A[j + 1] ⟵ A[j]
|
||||||
|
j ⟵ j - 1
|
||||||
|
|
||||||
|
A[j + 1] ⟵ v
|
||||||
|
```
|
||||||
|
|
||||||
|
The idea of *Insertion Sort* is that we assume that a smaller problem of sorting the array `A[0..k - 2]` has already been solved. We take advantage of that and simply insert a new element `A[k - 1]` at the appropriate position so that the array `A[0..k − 1]` is now sorted. Note that the basic operation is the key comparison `A[j] > v`. Please convince yourself that this algorithm is indeed stable.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
The watchtower file [dataset_3.csv](../tests/data/watchtowers/dataset_3.csv) contains the following information:
|
||||||
|
|
||||||
|
```csv
|
||||||
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
||||||
|
```
|
||||||
|
|
||||||
|
The polygon file [polygon_square.txt](../tests/data/polygons/polygon_square.txt) contains the following coordinates:
|
||||||
|
|
||||||
|
```
|
||||||
|
140.9 -39.2
|
||||||
|
140.9 -33.9
|
||||||
|
150.0 -33.9
|
||||||
|
150.0 -39.2
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `./voronoi2 4 dataset_3.csv polygon_square.txt 4-outfile.txt` the contents of `4-outfile.txt` would be:
|
||||||
|
|
||||||
|
```
|
||||||
|
Watchtower ID: WT3953SGAEI, Postcode: 3953, Population Served: 1571, Watchtower Point of Contact Name: Ofelia Kadlec, x: 145.778002, y: -38.559840, Diameter of Cell: 7.144748
|
||||||
|
Watchtower ID: WT3530RJWDT, Postcode: 3530, Population Served: 63, Watchtower Point of Contact Name: Troy Clark, x: 143.083467, y: -35.792994, Diameter of Cell: 7.935830
|
||||||
|
Watchtower ID: WT3765SHSPB, Postcode: 3765, Population Served: 3380, Watchtower Point of Contact Name: Eilene Horner, x: 145.362014, y: -37.818943, Diameter of Cell: 9.518041
|
||||||
|
```
|
||||||
|
|
||||||
|
## Plagarism
|
||||||
|
|
||||||
|
This is an individual assignment. The work must be your own.
|
||||||
|
|
||||||
|
While you may discuss your program development, coding problems and experimentation with your classmates, you must not share files, as this is considered plagiarism.
|
||||||
|
|
||||||
|
If you refer to published work in the discussion of your experiments, be sure to include a citation to the publication or the web link.
|
||||||
|
|
||||||
|
“Borrowing” of someone else’s code without acknowledgment is plagiarism. Plagiarism is considered a serious offense at the University of Melbourne. You should read the University code on Academic integrity and details on plagiarism. Make sure you are not plagiarizing, intentionally or unintentionally.
|
||||||
|
|
||||||
|
You are also advised that there will be a C programming component (on paper, not on a computer) in the final examination. Students who do not program their own assignments will be at a disadvantage for this part of the examination.
|
||||||
|
|
||||||
|
## Late Policy
|
||||||
|
|
||||||
|
The late penalty is 10% of the available marks for that project for each day (or part thereof) overdue. Requests for extensions on medical grounds will need to be supported by a medical certificate. Any request received less than 48 hours before the assessment date (or after the date!) will generally not be accepted except in the most extreme circumstances. In general, extensions will not be granted if the interruption covers less than 10% of the project duration. Remember that departmental servers are often heavily loaded near project deadlines, and unexpected outages can occur; these will not be considered as grounds for an extension.
|
||||||
|
|
||||||
|
Students who experience difficulties due to personal circumstances are encouraged to make use of the appropriate University student support services, and to contact the lecturer, at the earliest opportunity.
|
||||||
|
|
||||||
|
Finally, we are here to help! There is information about getting help in this subject on the LMS. Frequently asked questions about the project will be answered on Ed.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
The following implementation requirements must be adhered to:
|
||||||
|
|
||||||
|
- You must write your implementation in the C programming language.
|
||||||
|
|
||||||
|
- You must write your code in a modular way, so that your implementation could be used in another program without extensive rewriting or copying. This means that the Doubly Connected Edge List operations are kept together in a separate .c file, with its own header (.h) file, separate from the main program.
|
||||||
|
|
||||||
|
- Your implementation must read the input file once only.
|
||||||
|
|
||||||
|
- Your program should store strings in a space-efficient manner. If you are using malloc() to create the space for a string, remember to allow space for the final end of string ‘\0’ (NULL).
|
||||||
|
|
||||||
|
- A full Makefile is not provided for you. The Makefile should direct the compilation of your program. To use the Makefile, make sure it is in the same directory as your code, and type `make voronoi2` to make the dictionary. You must submit your makefile with your assignment.
|
||||||
|
|
||||||
|
- Comments should be present in your code and aim to be useful for the target audience of your code, so should be in English, and can assume functional understanding of C and its library functions.
|
||||||
|
|
||||||
|
Hint: If make doesn’t work, read the error messages carefully. A common problem in compiling multifile executables is in the included header files. Note also that the whitespace before the command is a tab, and not multiple spaces. It is not a good idea to code your program as a single file and then try to break it down into multiple files. Start by using multiple files, with minimal content, and make sure they are communicating with each other before starting more serious coding.
|
||||||
|
|
||||||
|
## Hints
|
||||||
|
|
||||||
|
### Starting Voronoi diagrams
|
||||||
|
|
||||||
|
The first three steps in creating the Voronoi diagram are simple enough, but may need careful care:
|
||||||
|
|
||||||
|
1. For the first tower (or Voronoi site), can simply be stored in the face (and the reverse).
|
||||||
|
|
||||||
|
2. For the second tower (or Voronoi site), we have a special case, as the fact that there is only a single face doesn't alone determine whether we are inserting the first or second tower, so you'll need to check.
|
||||||
|
|
||||||
|
3. After inserting the first two towers, the third and beyond can simply check the number of faces.
|
||||||
|
|
||||||
|
### Splits
|
||||||
|
|
||||||
|
If you used a mid-point vertex, you can use the split process from Assignment 1 to perform your splitting, simply set the position of these vertices to the location of the splits instead of the midpoint, the rest of the logic will work out.
|
||||||
|
|
||||||
|
### Constructing new faces for Voronoi cells
|
||||||
|
|
||||||
|
The face you construct following the algorithm must be connected together, a few parts of the process can significantly simplify this process.
|
||||||
|
|
||||||
|
- When using splits to construct the geometry, order the start and end edges in the split such that the watchtower is *outside the half-edge by the half-plane test*. This allows you to record the number of faces initially, perform all the splits, and then you know every face which will ultimately form the new face.
|
||||||
|
|
||||||
|
- Because of recommended choices during the previous assignment, each new face created will have a pointer to its half-edge in the DCEL, this means you can connect these directly.
|
||||||
|
|
||||||
|
### Cleaning contained geometry
|
||||||
|
|
||||||
|
After incremental Voronoi algorithm has completed, there will be edges in your DCEL which go unused, these don't do any harm, but may cause confusion if you want to visualise your progress. A simple process for cleaning up the contained geometry also allows us to connect all faces in the Voronoi cell.
|
||||||
|
|
||||||
|
- For each of the new faces, traverse all half-edges until you reach the original half-edge, update as you traverse with the following rules:
|
||||||
|
|
||||||
|
- (Pink Half-Edge) If a half-edge's pair/twin/opposite half-edge is in a face which is one of the new faces created, or has been assigned to be not in any face (e.g. `NOFACE` in the sample solution), and its following half-edge's pair/twin/opposite is `NULL` (one of the polygon initial half-edges, in green without pair), or joins to a face which is not one of the new faces (one of the joining half-edges, marked in green with black pair), then connect the *previous* pointer of the following edge (green) to the pair (orange)'s preceding half-edge (green in the other face). Set the face of the half-edge to not in any face.
|
||||||
|
|
||||||
|
- (Orange Half-Edge) If a half-edge's pair/twin/opposite half-edge is in a face which is one of the new faces created, or has been assigned to be not in any face (e.g. `NOFACE` in the sample solution), and its preceeding half-edge's pair/twin/opposite is `NULL` (one of the polygon initial half-edges, in green without pair), or joins to a face which is not one of the new faces (one of the joining half-edges, marked in green with black pair), then connect the *next* pointer of the preceding half-edge (green) to the pair (pink)'s following half-edge (green in the other face). Set the face of the half-edge to not in any face.
|
||||||
|
|
||||||
|
- (Blue and Light Blue Half-Edges) If the half-edge's pair/twin/opposite is in a face which is one of the new faces, set this half-edge's face to not in any face.
|
||||||
|
|
||||||
|
- (Green Half-Edges) Otherwise, set the half-edge's face to the stored new face value.
|
||||||
|
|
||||||
|
![](./images/image09.png)
|
||||||
|
|
||||||
|
- After the traversal is complete, set the deleted faces to longer point to their half-edges.
|
||||||
|
|
||||||
|
### Helper functions
|
||||||
|
|
||||||
|
You may find functions to make traversing the DCEL easier useful, e.g. find next face, find next half-edge, etc.
|
||||||
|
|
||||||
|
## Programming Style
|
||||||
|
|
||||||
|
[This](./programming-style.c) is a style guide which assignments are evaluated against. For this subject, the 80 character limit is a guideline rather than a rule - if your code exceeds this limit, you should consider whether your code would be more readable if you instead rearranged it.
|
||||||
|
|
||||||
|
Some automatic evaluations of your code style may be performed where they are reliable. As determining whether these style-related issues are occurring sometimes involves non-trivial (and sometimes even undecidable) calculations, a simpler and more error-prone (but highly successful) solution is used. You may need to add a comment to identify these cases, so check any failing test outputs for instructions on how to resolve incorrectly flagged issues.
|
||||||
|
|
||||||
|
## Additional Support
|
||||||
|
|
||||||
|
Your tutors will be available to help with your assignment during the scheduled workshop times. Questions related to the assignment may be posted on the Ed discussion forum, using the folder tag Assignments for new posts. You should feel free to answer other students’ questions if you are confident of your skills.
|
||||||
|
|
||||||
|
A tutor will check the discussion forum regularly, and answer some questions, but be aware that for some questions you will just need to use your judgment and document your thinking. For example, a question like, “How much data should I use for the experiments?”, will not be answered; you must try out different data and see what makes sense.
|
||||||
|
|
||||||
|
If you have questions about your code specifically which you feel would reveal too much of the assignment, feel free to post a private question on the discussion forum.
|
||||||
|
|
||||||
|
## Submission
|
||||||
|
|
||||||
|
Your C code files (including your Makefile and any other files needed to run your code) should be submitted through Ed to this assignment. Your programs must compile and run correctly on Ed. You may have developed your program in another environment, but it still must run on Ed at submission time. For this reason, and because there are often small, but significant, differences between compilers, it is suggested that if you are working in a different environment, you upload and test your code on Ed at reasonably frequent intervals.
|
||||||
|
|
||||||
|
A common reason for programs not to compile is that a file has been inadvertently omitted from the submission. Please check your submission, and resubmit all files if necessary.
|
||||||
|
|
||||||
|
## Assessment
|
||||||
|
|
||||||
|
There are a total of 15 marks given for this assignment.
|
||||||
|
|
||||||
|
Your C program will be marked on the basis of accuracy, readability, and good C programming structure, safety and style, including documentation (1 mark). Safety refers to checking whether opening a file returns something, whether mallocs do their job, etc. The documentation should explain all major design decisions, and should be formatted so that it does not interfere with reading the code. As much as possible, try to make your code self-documenting, by choosing descriptive variable names. The remainder of the marks will be based on the correct functioning of your submission.
|
||||||
|
|
||||||
|
Note that these correct functioning-related marks will be based on passing various tests. If your program passes these tests without addressing the learning outcomes (e.g. if you fully hard-code solutions or otherwise deliberately exploit the test cases), you may receive less marks than is suggested but your marks will otherwise be determined by test cases.
|
||||||
|
|
||||||
|
| Marks | Task |
|
||||||
|
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| 4 | Compute and output equations for bisectors given pairs of points in a file. |
|
||||||
|
| 2 | Compute and output intersection points for bisectors against a given polygon. |
|
||||||
|
| 6 | Implement the incremental voronoi algorithm and output the diameter of each voronoi cell with its associated information in the original output order. |
|
||||||
|
| 2 | Sort the watchtowers by the diameter of those cells. |
|
||||||
|
| 1 | Program style consistent with Programming Style slide. Memory allocations and file opens checked. |
|
||||||
|
|
||||||
|
Note that code style will be manually marked in order to provide you
|
||||||
|
with the most meaningful feedback for the second assignment.
|
BIN
docs/images/image01.png
Normal file
After Width: | Height: | Size: 594 KiB |
BIN
docs/images/image02.png
Normal file
After Width: | Height: | Size: 743 KiB |
BIN
docs/images/image03.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
docs/images/image04.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/images/image05.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
docs/images/image06.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
docs/images/image07.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
docs/images/image08.png
Normal file
After Width: | Height: | Size: 481 KiB |
BIN
docs/images/image09.png
Normal file
After Width: | Height: | Size: 45 KiB |
218
docs/intersection.c
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
enum intersectType;
|
||||||
|
|
||||||
|
enum intersectType {
|
||||||
|
DOESNT_INTERSECT = 0, // Doesn't intersect
|
||||||
|
INTERSECT = 1, // Intersects
|
||||||
|
SAME_LINE_OVERLAP = 2, // Lines are the same
|
||||||
|
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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 the point (x, y) is in the line from s(x, y) to e(x, y), 0 otherwise. */
|
||||||
|
int collinear(double sx, double sy, double ex, double ey, double x, double y);
|
||||||
|
|
||||||
|
int collinear(double sx, double sy, double ex, double ey, double x, double y){
|
||||||
|
/* Work out area of parallelogram - if it's 0, points are in the same line. */
|
||||||
|
if (areaSign(sx, sy, ex, ey, x, y) == 0){
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 1 if point (x, y) is between (sx, sy) and (se, se) */
|
||||||
|
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){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum intersectType parallelIntersects(double heSx, double heSy, double heEx, double heEy,
|
||||||
|
double bSx, double bSy, double bEx, double bEy, double *x, double *y);
|
||||||
|
|
||||||
|
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( ... , double *x, double *y);
|
||||||
|
|
||||||
|
enum intersectType intersects( ... , double *x, double *y){
|
||||||
|
/* Half-edge x, y pair */
|
||||||
|
double heSx = ...;
|
||||||
|
double heSy = ...;
|
||||||
|
double heEx = ...;
|
||||||
|
double heEy = ...;
|
||||||
|
|
||||||
|
/* Bisector x, y pair */
|
||||||
|
double bSx = ...;
|
||||||
|
double bSy = ...;
|
||||||
|
double bEx = ...;
|
||||||
|
double bEy = ...;
|
||||||
|
|
||||||
|
/* Parametric equation parameters */
|
||||||
|
double t1;
|
||||||
|
double t2;
|
||||||
|
/* Numerators for X and Y coordinate of intersection. */
|
||||||
|
double numeratorX;
|
||||||
|
double 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;
|
||||||
|
}
|
||||||
|
}
|
298
docs/programming-style.c
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
/** ***********************
|
||||||
|
* C Programming Style for Engineering Computation
|
||||||
|
* Created by Aidan Nagorcka-Smith (aidann@student.unimelb.edu.au) 13/03/2011
|
||||||
|
* Definitions and includes
|
||||||
|
* Definitions are in UPPER_CASE
|
||||||
|
* Includes go before definitions
|
||||||
|
* Space between includes, definitions and the main function.
|
||||||
|
* Use definitions for any constants in your program, do not just write them
|
||||||
|
* in.
|
||||||
|
*
|
||||||
|
* Tabs may be set to 4-spaces or 8-spaces, depending on your editor. The code
|
||||||
|
* Below is ``gnu'' style. If your editor has ``bsd'' it will follow the 8-space
|
||||||
|
* style. Both are very standard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define MAX_STRING_SIZE 1000
|
||||||
|
#define DEBUG 0
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Definitions and includes are mixed up */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define MAX_STING_SIZE 1000
|
||||||
|
/* Definitions are given names like variables */
|
||||||
|
#define debug 0
|
||||||
|
#include <stdio.h>
|
||||||
|
/* No spacing between includes, definitions and main function*/
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
...
|
||||||
|
|
||||||
|
/** *****************************
|
||||||
|
* Variables
|
||||||
|
* Give them useful lower_case names or camelCase. Either is fine,
|
||||||
|
* as long as you are consistent and apply always the same style.
|
||||||
|
* Initialise them to something that makes sense.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD: lower_case
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int num_fifties = 0;
|
||||||
|
int num_twenties = 0;
|
||||||
|
int num_tens = 0;
|
||||||
|
|
||||||
|
...
|
||||||
|
/**
|
||||||
|
* GOOD: camelCase
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int numFifties = 0;
|
||||||
|
int numTwenties = 0;
|
||||||
|
int numTens = 0;
|
||||||
|
|
||||||
|
...
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
/* Variable not initialised - causes a bug because we didn't remember to
|
||||||
|
* set it before the loop */
|
||||||
|
int i;
|
||||||
|
/* Variable in all caps - we'll get confused between this and constants
|
||||||
|
*/
|
||||||
|
int NUM_FIFTIES = 0;
|
||||||
|
/* Overly abbreviated variable names make things hard. */
|
||||||
|
int nt = 0
|
||||||
|
|
||||||
|
while (i < 10) {
|
||||||
|
...
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/** ********************
|
||||||
|
* Spacing:
|
||||||
|
* Space intelligently, vertically to group blocks of code that are doing a
|
||||||
|
* specific operation, or to separate variable declarations from other code.
|
||||||
|
* One tab of indentation within either a function or a loop.
|
||||||
|
* Spaces after commas.
|
||||||
|
* Space between ) and {.
|
||||||
|
* No space between the ** and the argv in the definition of the main
|
||||||
|
* function.
|
||||||
|
* When declaring a pointer variable or argument, you may place the asterisk
|
||||||
|
* adjacent to either the type or to the variable name.
|
||||||
|
* Lines at most 80 characters long.
|
||||||
|
* Closing brace goes on its own line
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for(i = 100; i >= 0; i--) {
|
||||||
|
if (i > 0) {
|
||||||
|
printf("%d bottles of beer, take one down and pass it around,"
|
||||||
|
" %d bottles of beer.\n", i, i - 1);
|
||||||
|
} else {
|
||||||
|
printf("%d bottles of beer, take one down and pass it around."
|
||||||
|
" We're empty.\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* No space after commas
|
||||||
|
* Space between the ** and argv in the main function definition
|
||||||
|
* No space between the ) and { at the start of a function */
|
||||||
|
int main(int argc,char ** argv){
|
||||||
|
int i = 0;
|
||||||
|
/* No space between variable declarations and the rest of the function.
|
||||||
|
* No spaces around the boolean operators */
|
||||||
|
for(i=100;i>=0;i--) {
|
||||||
|
/* No indentation */
|
||||||
|
if (i > 0) {
|
||||||
|
/* Line too long */
|
||||||
|
printf("%d bottles of beer, take one down and pass it around, %d
|
||||||
|
bottles of beer.\n", i, i - 1);
|
||||||
|
} else {
|
||||||
|
/* Spacing for no good reason. */
|
||||||
|
|
||||||
|
printf("%d bottles of beer, take one down and pass it around."
|
||||||
|
" We're empty.\n", i);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Closing brace not on its own line */
|
||||||
|
return 0;}
|
||||||
|
|
||||||
|
/** ****************
|
||||||
|
* Braces:
|
||||||
|
* Opening braces go on the same line as the loop or function name
|
||||||
|
* Closing braces go on their own line
|
||||||
|
* Closing braces go at the same indentation level as the thing they are
|
||||||
|
* closing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
for(...) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/* Opening brace on a different line to the for loop open */
|
||||||
|
for(...)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
/* Closing brace at a different indentation to the thing it's
|
||||||
|
closing
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closing brace not on its own line. */
|
||||||
|
return 0;}
|
||||||
|
|
||||||
|
/** **************
|
||||||
|
* Commenting:
|
||||||
|
* Each program should have a comment explaining what it does and who created
|
||||||
|
* it.
|
||||||
|
* Also comment how to run the program, including optional command line
|
||||||
|
* parameters.
|
||||||
|
* Any interesting code should have a comment to explain itself.
|
||||||
|
* We should not comment obvious things - write code that documents itself
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* change.c
|
||||||
|
*
|
||||||
|
* Created by Aidan Nagorcka-Smith (aidann@student.unimelb.edu.au)
|
||||||
|
13/03/2011
|
||||||
|
*
|
||||||
|
* Print the number of each coin that would be needed to make up some
|
||||||
|
change
|
||||||
|
* that is input by the user
|
||||||
|
*
|
||||||
|
* To run the program type:
|
||||||
|
* ./coins --num_coins 5 --shape_coins trapezoid --output blabla.txt
|
||||||
|
*
|
||||||
|
* To see all the input parameters, type:
|
||||||
|
* ./coins --help
|
||||||
|
* Options::
|
||||||
|
* --help Show help message
|
||||||
|
* --num_coins arg Input number of coins
|
||||||
|
* --shape_coins arg Input coins shape
|
||||||
|
* --bound arg (=1) Max bound on xxx, default value 1
|
||||||
|
* --output arg Output solution file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int input_change = 0;
|
||||||
|
|
||||||
|
printf("Please input the value of the change (0-99 cents
|
||||||
|
inclusive):\n");
|
||||||
|
scanf("%d", &input_change);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Valid change values are 0-99 inclusive.
|
||||||
|
if(input_change < 0 || input_change > 99) {
|
||||||
|
printf("Input not in the range 0-99.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* No explanation of what the program is doing */
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
/* Commenting obvious things */
|
||||||
|
/* Create a int variable called input_change to store the input from
|
||||||
|
the
|
||||||
|
* user. */
|
||||||
|
int input_change;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/** ****************
|
||||||
|
* Code structure:
|
||||||
|
* Fail fast - input checks should happen first, then do the computation.
|
||||||
|
* Structure the code so that all error handling happens in an easy to read
|
||||||
|
* location
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GOOD:
|
||||||
|
*/
|
||||||
|
if (input_is_bad) {
|
||||||
|
printf("Error: Input was not valid. Exiting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do computations here */
|
||||||
|
...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BAD:
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (input_is_good) {
|
||||||
|
/* lots of computation here, pushing the else part off the screen.
|
||||||
|
*/
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: Input was not valid. Exiting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
BIN
docs/videos/voronoi.mp4
Normal file
BIN
input.o
BIN
main.o
|
@ -1 +0,0 @@
|
||||||
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
|
|
|
@ -1,29 +1,29 @@
|
||||||
/* common.c
|
/* common.c
|
||||||
*
|
*
|
||||||
* 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 14th September 2021
|
* Last modified 14th September 2021
|
||||||
*
|
*
|
||||||
* Contains functions and headers for general use throughout other files.
|
* Contains functions and headers for general use throughout other files.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COMMON_HEADER
|
#ifndef COMMON_HEADER
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void checkNullPointer(void *ptr) {
|
void checkNullPointer(void *ptr) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
fputs("Error: Cannot allocate memory.\n", stderr);
|
fputs("Error: Cannot allocate memory.\n", stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *safeFileOpen(FILE **f, char *fileName, char *mode) {
|
FILE *safeFileOpen(FILE **f, char *fileName, char *mode) {
|
||||||
*f = fopen(fileName, mode);
|
*f = fopen(fileName, mode);
|
||||||
if (*f == NULL) {
|
if (*f == NULL) {
|
||||||
fprintf(stderr, "Error: Unable to open file %s\n", fileName);
|
fprintf(stderr, "Error: Unable to open file %s\n", fileName);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
return *f;
|
return *f;
|
||||||
}
|
}
|
|
@ -1,31 +1,31 @@
|
||||||
#ifndef STDIO_HEADER
|
#ifndef STDIO_HEADER
|
||||||
#define STDIO_HEADER
|
#define STDIO_HEADER
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STDLIB_HEADER
|
#ifndef STDLIB_HEADER
|
||||||
#define STDLIB_HEADER
|
#define STDLIB_HEADER
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STRING_HEADER
|
#ifndef STRING_HEADER
|
||||||
#define STRING_HEADER
|
#define STRING_HEADER
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef COMMON_HEADER
|
#ifndef COMMON_HEADER
|
||||||
#define COMMON_HEADER
|
#define COMMON_HEADER
|
||||||
|
|
||||||
/* Checks if a pointer assigned through dynamic memory allocation is NULL */
|
/* Checks if a pointer assigned through dynamic memory allocation is NULL */
|
||||||
void checkNullPointer(void *ptr);
|
void checkNullPointer(void *ptr);
|
||||||
|
|
||||||
/* Opens a file and checks if the file is safe to use */
|
/* Opens a file and checks if the file is safe to use */
|
||||||
FILE *safeFileOpen(FILE **f, char *fileName, char *mode);
|
FILE *safeFileOpen(FILE **f, char *fileName, char *mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
2438
dcel.c → src/dcel.c
|
@ -1,258 +1,258 @@
|
||||||
#ifndef TOWERS_HEADER
|
#ifndef TOWERS_HEADER
|
||||||
#include "towers.h"
|
#include "towers.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MATH_HEADER
|
#ifndef MATH_HEADER
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DCEL_HEADER
|
#ifndef DCEL_HEADER
|
||||||
#define DCEL_HEADER
|
#define DCEL_HEADER
|
||||||
|
|
||||||
/* -------- Definitions, enums, and structs from Grady's base code --------- */
|
/* -------- Definitions, enums, and structs from Grady's base code --------- */
|
||||||
|
|
||||||
/* Representation of no face */
|
/* Representation of no face */
|
||||||
#define NOFACE (-1)
|
#define NOFACE (-1)
|
||||||
|
|
||||||
/* Default face for intersections. */
|
/* Default face for intersections. */
|
||||||
#define DEFAULT_FACE 0
|
#define DEFAULT_FACE 0
|
||||||
|
|
||||||
/* Default minimum length for bisector in each direction */
|
/* Default minimum length for bisector in each direction */
|
||||||
#define DEFAULTMINLENGTH (200)
|
#define DEFAULTMINLENGTH (200)
|
||||||
|
|
||||||
enum intersectType {
|
enum intersectType {
|
||||||
DOESNT_INTERSECT = 0, // Doesn't intersect
|
DOESNT_INTERSECT = 0, // Doesn't intersect
|
||||||
INTERSECT = 1, // Intersects
|
INTERSECT = 1, // Intersects
|
||||||
SAME_LINE_OVERLAP = 2, // Lines are the same
|
SAME_LINE_OVERLAP = 2, // Lines are the same
|
||||||
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
|
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct vertex {
|
typedef struct vertex {
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
} vertex_t;
|
} vertex_t;
|
||||||
|
|
||||||
typedef struct halfEdge {
|
typedef struct halfEdge {
|
||||||
struct halfEdge *previous;
|
struct halfEdge *previous;
|
||||||
struct halfEdge *next;
|
struct halfEdge *next;
|
||||||
struct halfEdge *twin;
|
struct halfEdge *twin;
|
||||||
int face;
|
int face;
|
||||||
int edge;
|
int edge;
|
||||||
int startVertex;
|
int startVertex;
|
||||||
int endVertex;
|
int endVertex;
|
||||||
} halfEdge_t;
|
} halfEdge_t;
|
||||||
|
|
||||||
typedef struct edge {
|
typedef struct edge {
|
||||||
halfEdge_t *halfEdge;
|
halfEdge_t *halfEdge;
|
||||||
tower_t *tower;
|
tower_t *tower;
|
||||||
} edge_t;
|
} edge_t;
|
||||||
|
|
||||||
typedef struct face {
|
typedef struct face {
|
||||||
halfEdge_t *start;
|
halfEdge_t *start;
|
||||||
tower_t *tower;
|
tower_t *tower;
|
||||||
} face_t;
|
} face_t;
|
||||||
|
|
||||||
typedef struct split {
|
typedef struct split {
|
||||||
int startEdge;
|
int startEdge;
|
||||||
int endEdge;
|
int endEdge;
|
||||||
int verticesSpecified;
|
int verticesSpecified;
|
||||||
vertex_t startPoint;
|
vertex_t startPoint;
|
||||||
vertex_t endPoint;
|
vertex_t endPoint;
|
||||||
} split_t;
|
} split_t;
|
||||||
|
|
||||||
typedef struct DCEL {
|
typedef struct DCEL {
|
||||||
edge_t *edges;
|
edge_t *edges;
|
||||||
int edgesUsed;
|
int edgesUsed;
|
||||||
int edgesAllocated;
|
int edgesAllocated;
|
||||||
|
|
||||||
face_t *faces;
|
face_t *faces;
|
||||||
int facesUsed;
|
int facesUsed;
|
||||||
int facesAllocated;
|
int facesAllocated;
|
||||||
|
|
||||||
vertex_t *vertices;
|
vertex_t *vertices;
|
||||||
int verticesUsed;
|
int verticesUsed;
|
||||||
int verticesAllocated;
|
int verticesAllocated;
|
||||||
} DCEL_t;
|
} DCEL_t;
|
||||||
|
|
||||||
/* ------------------------------ My structs ------------------------------- */
|
/* ------------------------------ My structs ------------------------------- */
|
||||||
|
|
||||||
typedef struct bisector {
|
typedef struct bisector {
|
||||||
vertex_t *mid;
|
vertex_t *mid;
|
||||||
int isSlopeInfinite;
|
int isSlopeInfinite;
|
||||||
double slope;
|
double slope;
|
||||||
} bisector_t;
|
} bisector_t;
|
||||||
|
|
||||||
typedef struct intersection {
|
typedef struct intersection {
|
||||||
int fromEdge;
|
int fromEdge;
|
||||||
int toEdge;
|
int toEdge;
|
||||||
vertex_t *fromPoint;
|
vertex_t *fromPoint;
|
||||||
vertex_t *toPoint;
|
vertex_t *toPoint;
|
||||||
} intersection_t;
|
} intersection_t;
|
||||||
|
|
||||||
/* ----------------------- My points functions start ----------------------- */
|
/* ----------------------- My points functions start ----------------------- */
|
||||||
|
|
||||||
/* Creates a new point */
|
/* Creates a new point */
|
||||||
vertex_t *newPoint();
|
vertex_t *newPoint();
|
||||||
|
|
||||||
/* Gets a single point from an x-y pair */
|
/* Gets a single point from an x-y pair */
|
||||||
vertex_t *getAPoint(double x, double y);
|
vertex_t *getAPoint(double x, double y);
|
||||||
|
|
||||||
/* Reads a points file and stores the information in the points array */
|
/* Reads a points file and stores the information in the points array */
|
||||||
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
|
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
|
||||||
|
|
||||||
/* Frees an array of points */
|
/* Frees an array of points */
|
||||||
void freePoints(vertex_t **points, int numPoints);
|
void freePoints(vertex_t **points, int numPoints);
|
||||||
|
|
||||||
/* Returns the distance between two points */
|
/* Returns the distance between two points */
|
||||||
double distPoints(vertex_t *pointA, vertex_t *pointB);
|
double distPoints(vertex_t *pointA, vertex_t *pointB);
|
||||||
|
|
||||||
/* ------------------------ My points functions end ------------------------ */
|
/* ------------------------ My points functions end ------------------------ */
|
||||||
|
|
||||||
/* -------------------- My intersection functions start -------------------- */
|
/* -------------------- My intersection functions start -------------------- */
|
||||||
|
|
||||||
/* Create a new intersection */
|
/* Create a new intersection */
|
||||||
intersection_t *newIntersection();
|
intersection_t *newIntersection();
|
||||||
|
|
||||||
/* Fills in a single intersection structure */
|
/* Fills in a single intersection structure */
|
||||||
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
|
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
|
||||||
bisector_t *bisector, int face, int minLength);
|
bisector_t *bisector, int face, int minLength);
|
||||||
|
|
||||||
/* Gets the intersection between the given bisector and the given DCEL
|
/* Gets the intersection between the given bisector and the given DCEL
|
||||||
* for the given face.
|
* for the given face.
|
||||||
*/
|
*/
|
||||||
intersection_t **getIntersections(intersection_t **intersections, \
|
intersection_t **getIntersections(intersection_t **intersections, \
|
||||||
int *numIntersections, bisector_t **bisectors, int numBisectors, \
|
int *numIntersections, bisector_t **bisectors, int numBisectors, \
|
||||||
DCEL_t *dcel, int face, double minLength);
|
DCEL_t *dcel, int face, double minLength);
|
||||||
|
|
||||||
/* Frees an array of intersections */
|
/* Frees an array of intersections */
|
||||||
void freeIntersections(intersection_t **intersections, int numIntersections);
|
void freeIntersections(intersection_t **intersections, int numIntersections);
|
||||||
|
|
||||||
/* --------------------- My intersection functions end --------------------- */
|
/* --------------------- My intersection functions end --------------------- */
|
||||||
|
|
||||||
/* ---------------------- My bisector functions start ---------------------- */
|
/* ---------------------- My bisector functions start ---------------------- */
|
||||||
|
|
||||||
/* Creates a new bisector */
|
/* Creates a new bisector */
|
||||||
bisector_t *newBisector();
|
bisector_t *newBisector();
|
||||||
|
|
||||||
/* Calculates and returns the equation of a bisector of two points */
|
/* Calculates and returns the equation of a bisector of two points */
|
||||||
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
|
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
|
||||||
vertex_t *pointB);
|
vertex_t *pointB);
|
||||||
|
|
||||||
/* Returns a list of bisectors built from a list of points */
|
/* Returns a list of bisectors built from a list of points */
|
||||||
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
|
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
|
||||||
int numPoints);
|
int numPoints);
|
||||||
/* Returns a point at least distance away from the midpoint of the
|
/* 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
|
* bisector given. If direction is 0, then the point is +distance away in the
|
||||||
* x-direction, otherwise -distance away in the x-direction.
|
* x-direction, otherwise -distance away in the x-direction.
|
||||||
*/
|
*/
|
||||||
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
|
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
|
||||||
|
|
||||||
/* Frees an array of bisectors */
|
/* Frees an array of bisectors */
|
||||||
void freeBisectors(bisector_t **bisectors, int numBisectors);
|
void freeBisectors(bisector_t **bisectors, int numBisectors);
|
||||||
|
|
||||||
/* ----------------------- My bisector functions end ----------------------- */
|
/* ----------------------- My bisector functions end ----------------------- */
|
||||||
|
|
||||||
/* ------------------------ My DCEL functions start ------------------------ */
|
/* ------------------------ My DCEL functions start ------------------------ */
|
||||||
|
|
||||||
/* Gets the diameter of the given face. */
|
/* Gets the diameter of the given face. */
|
||||||
double getDiameter(DCEL_t *dcel, int faceIndex);
|
double getDiameter(DCEL_t *dcel, int faceIndex);
|
||||||
|
|
||||||
/* ------------------------- My DCEL functions end ------------------------- */
|
/* ------------------------- My DCEL functions end ------------------------- */
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Here on out are the functions from Grady's base code on Ed
|
* 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();
|
||||||
|
|
||||||
/* Check there's space for another vertex in the DCEL, or increase the
|
/* Check there's space for another vertex in the DCEL, or increase the
|
||||||
* allocated space.
|
* allocated space.
|
||||||
*/
|
*/
|
||||||
void ensureSpaceForVertex(DCEL_t *dcel);
|
void ensureSpaceForVertex(DCEL_t *dcel);
|
||||||
|
|
||||||
/* Check there's space for another edge in the DCEL, or increase the
|
/* Check there's space for another edge in the DCEL, 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, or increase the
|
/* Check there's space for another face in the DCEL, or increase the
|
||||||
* allocated space.
|
* allocated space.
|
||||||
*/
|
*/
|
||||||
void ensureSpaceForFace(DCEL_t *dcel);
|
void ensureSpaceForFace(DCEL_t *dcel);
|
||||||
|
|
||||||
/* Add an edge from the startVertex index vertex to the endVertex index.
|
/* Add an edge from the startVertex index vertex to the endVertex index.
|
||||||
* Only fills one half-edge as other half-edges will always be added
|
* Only fills one half-edge as other half-edges will always be added
|
||||||
* through geometry construction.
|
* through geometry construction.
|
||||||
*/
|
*/
|
||||||
void addEdge(DCEL_t *dcel, int startVertex, int endVertex);
|
void addEdge(DCEL_t *dcel, int startVertex, int endVertex);
|
||||||
|
|
||||||
/* Add a face to the DCEL given using the given halfEdge and sets the face. */
|
/* Add a face to the DCEL given using the given halfEdge and sets the face. */
|
||||||
void addFace(DCEL_t *dcel, halfEdge_t *he);
|
void addFace(DCEL_t *dcel, halfEdge_t *he);
|
||||||
|
|
||||||
/* Reads the polygon from the given file. */
|
/* Reads the polygon from the given file. */
|
||||||
DCEL_t *readPolygonFile(char *polygonfileName);
|
DCEL_t *readPolygonFile(char *polygonfileName);
|
||||||
|
|
||||||
/* Reads the next split from the given file. */
|
/* Reads the next split from the given file. */
|
||||||
split_t *readNextSplit(FILE *splitfile);
|
split_t *readNextSplit(FILE *splitfile);
|
||||||
|
|
||||||
/* Frees a given split. */
|
/* Frees a given split. */
|
||||||
void freeSplit(split_t *split);
|
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);
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
||||||
/* Frees the given DCEL */
|
/* Frees the given DCEL */
|
||||||
void freeDCEL(DCEL_t *dcel);
|
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
|
/* 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
|
* 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.
|
* 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);
|
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
|
/* Takes an established direction and a new direction, and returns 1 if the
|
||||||
* direction matches the decidedDirection or if the direction is undecided.
|
* direction matches the decidedDirection or if the direction is undecided.
|
||||||
*/
|
*/
|
||||||
int directionOrUndecided(int decidedDirection, int direction);
|
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);
|
||||||
|
|
||||||
/* ------------------- O'Rourke's intersection functions ------------------- */
|
/* ------------------- O'Rourke's intersection functions ------------------- */
|
||||||
|
|
||||||
/* Returns -1, 0 or 1, based on the area enclosed by the three points.
|
/* Returns -1, 0 or 1, based on the area enclosed by the three points.
|
||||||
* 0 corresponds to no area enclosed
|
* 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, \
|
||||||
double bEx, double bEy, double *x, double *y);
|
double bEx, double bEy, double *x, double *y);
|
||||||
|
|
||||||
/* Tests if a half edge and a bisector intersect */
|
/* Tests if a half edge and a bisector intersect */
|
||||||
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,92 +1,92 @@
|
||||||
/* input.c
|
/* input.c
|
||||||
*
|
*
|
||||||
* 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 14th 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.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INPUT_HEADER
|
#ifndef INPUT_HEADER
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#endif
|
#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
|
||||||
#define STAGE_4_ARG_COUNT 5
|
#define STAGE_4_ARG_COUNT 5
|
||||||
|
|
||||||
enum stages getStage(char *stage) {
|
enum stages getStage(char *stage) {
|
||||||
if (strcmp(stage, "1") == 0){
|
if (strcmp(stage, "1") == 0){
|
||||||
return STAGE_1;
|
return STAGE_1;
|
||||||
} else if (strcmp(stage, "2") == 0){
|
} else if (strcmp(stage, "2") == 0){
|
||||||
return STAGE_2;
|
return STAGE_2;
|
||||||
} else if (strcmp(stage, "3") == 0){
|
} else if (strcmp(stage, "3") == 0){
|
||||||
return STAGE_3;
|
return STAGE_3;
|
||||||
} else if (strcmp(stage, "4") == 0){
|
} else if (strcmp(stage, "4") == 0){
|
||||||
return STAGE_4;
|
return STAGE_4;
|
||||||
} else {
|
} else {
|
||||||
return STAGE_ERROR;
|
return STAGE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printArgError(enum stages stage, char *errorMessage) {
|
void printArgError(enum stages stage, char *errorMessage) {
|
||||||
fprintf(stderr, "Error: %s\n\n", errorMessage);
|
fprintf(stderr, "Error: %s\n\n", errorMessage);
|
||||||
|
|
||||||
/* Stage 1 - Print bisector equations */
|
/* Stage 1 - Print bisector equations */
|
||||||
if (stage == STAGE_ERROR || stage == STAGE_1) {
|
if (stage == STAGE_ERROR || stage == STAGE_1) {
|
||||||
fputs("./voronoi2 1 pointsFile outputFile\n"
|
fputs("./voronoi2 1 pointsFile outputFile\n"
|
||||||
"\tTo output the bisectors for the given pointsFile to the \n"
|
"\tTo output the bisectors for the given pointsFile to the \n"
|
||||||
"\tgiven outputFile.\n\n", stderr);
|
"\tgiven outputFile.\n\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stage 2 - Print intersections between bisectors and polygon */
|
/* Stage 2 - Print intersections between bisectors and polygon */
|
||||||
if (stage == STAGE_ERROR || stage == STAGE_2) {
|
if (stage == STAGE_ERROR || stage == STAGE_2) {
|
||||||
fputs("./voronoi2 2 pointsFile polygonFile outputFile\n"
|
fputs("./voronoi2 2 pointsFile polygonFile outputFile\n"
|
||||||
"\tTo output the intersections the given bisectors make with \n"
|
"\tTo output the intersections the given bisectors make with \n"
|
||||||
"\tthe polygon to the given outputFile.\n\n", stderr);
|
"\tthe polygon to the given outputFile.\n\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stage 3: Print diameter of each face, constructing using
|
/* Stage 3: Print diameter of each face, constructing using
|
||||||
* incremental method
|
* incremental method
|
||||||
*/
|
*/
|
||||||
if (stage == STAGE_ERROR || stage == STAGE_3) {
|
if (stage == STAGE_ERROR || stage == STAGE_3) {
|
||||||
fputs("./voronoi2 3 dataFile polygonFile outputFile\n"
|
fputs("./voronoi2 3 dataFile polygonFile outputFile\n"
|
||||||
"\tTo generate the initial polygon in polygonFile, layout the \n"
|
"\tTo generate the initial polygon in polygonFile, layout the \n"
|
||||||
"\twatchtower points in the dataFile on the polygon, generate \n"
|
"\twatchtower points in the dataFile on the polygon, generate \n"
|
||||||
"\the voronoi diagram, adding or modifying the polydon so that \n"
|
"\the voronoi diagram, adding or modifying the polydon so that \n"
|
||||||
"\ta voronoi diagram is constructed, seperating all points \n"
|
"\ta voronoi diagram is constructed, seperating all points \n"
|
||||||
"\tinto their own cell with all tpoints in the cell being \n"
|
"\tinto their own cell with all tpoints in the cell being \n"
|
||||||
"\tclosest to the watchtower in the cell. The watchtower data \n"
|
"\tclosest to the watchtower in the cell. The watchtower data \n"
|
||||||
"\tand its diameter is output to the outputFile.\n\n", stderr);
|
"\tand its diameter is output to the outputFile.\n\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stage 4 - Sort by diameter */
|
/* Stage 4 - Sort by diameter */
|
||||||
if (stage == STAGE_ERROR || stage == STAGE_4) {
|
if (stage == STAGE_ERROR || stage == STAGE_4) {
|
||||||
fputs("./voronoi2 4 dataFile polygonFile outputFile\n"
|
fputs("./voronoi2 4 dataFile polygonFile outputFile\n"
|
||||||
"\tSame as stage 3, but output watchtowers are in order of \n"
|
"\tSame as stage 3, but output watchtowers are in order of \n"
|
||||||
"\tdiameter, smallest to largest.\n\n", stderr);
|
"\tdiameter, smallest to largest.\n\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getExpectedArgs(enum stages stage) {
|
int getExpectedArgs(enum stages stage) {
|
||||||
switch(stage){
|
switch(stage){
|
||||||
case STAGE_1:
|
case STAGE_1:
|
||||||
return STAGE_1_ARG_COUNT;
|
return STAGE_1_ARG_COUNT;
|
||||||
case STAGE_2:
|
case STAGE_2:
|
||||||
return STAGE_2_ARG_COUNT;
|
return STAGE_2_ARG_COUNT;
|
||||||
case STAGE_3:
|
case STAGE_3:
|
||||||
return STAGE_3_ARG_COUNT;
|
return STAGE_3_ARG_COUNT;
|
||||||
case STAGE_4:
|
case STAGE_4:
|
||||||
return STAGE_4_ARG_COUNT;
|
return STAGE_4_ARG_COUNT;
|
||||||
case STAGE_ERROR:
|
case STAGE_ERROR:
|
||||||
default:
|
default:
|
||||||
printArgError(stage, "Invalid stage number.");
|
printArgError(stage, "Invalid stage number.");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
|
@ -1,28 +1,28 @@
|
||||||
#ifndef COMMON_HEADER
|
#ifndef COMMON_HEADER
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef INPUT_HEADER
|
#ifndef INPUT_HEADER
|
||||||
#define INPUT_HEADER
|
#define INPUT_HEADER
|
||||||
|
|
||||||
enum stages {
|
enum stages {
|
||||||
STAGE_1 = 1,
|
STAGE_1 = 1,
|
||||||
STAGE_2 = 2,
|
STAGE_2 = 2,
|
||||||
STAGE_3 = 3,
|
STAGE_3 = 3,
|
||||||
STAGE_4 = 4,
|
STAGE_4 = 4,
|
||||||
STAGE_ERROR = -1
|
STAGE_ERROR = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Gets the current stage from the command-line argument */
|
/* Gets the current stage from the command-line argument */
|
||||||
enum stages getStage(char *stage);
|
enum stages getStage(char *stage);
|
||||||
|
|
||||||
/* Checks the validity of the command line input arguments */
|
/* Checks the validity of the command line input arguments */
|
||||||
void checkInputArgs(int argc, char **argv);
|
void checkInputArgs(int argc, char **argv);
|
||||||
|
|
||||||
/* Gets the expected number of arguments for a given stage */
|
/* Gets the expected number of arguments for a given stage */
|
||||||
int getExpectedArgs(enum stages stage);
|
int getExpectedArgs(enum stages stage);
|
||||||
|
|
||||||
/* Prints the corresponding usage strings for a given stage */
|
/* Prints the corresponding usage strings for a given stage */
|
||||||
void printArgError(enum stages stage, char *errorMessage);
|
void printArgError(enum stages stage, char *errorMessage);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,71 +1,71 @@
|
||||||
/* main.c
|
/* main.c
|
||||||
*
|
*
|
||||||
* 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 14th September 2021
|
* Last modified 14th September 2021
|
||||||
*
|
*
|
||||||
* Stage 1: Computes and outputs equations for the bisectors of points
|
* Stage 1: Computes and outputs equations for the bisectors of points
|
||||||
* Stage 2: Computes and outputs intersection points for bisectors against a
|
* Stage 2: Computes and outputs intersection points for bisectors against a
|
||||||
* given polygon
|
* given polygon
|
||||||
* Stage 3: Computes a Voronoi diagram using watchtowers as points and a
|
* Stage 3: Computes a Voronoi diagram using watchtowers as points and a
|
||||||
* polygon as the outer boundary. Outputs diameters of each Voronoi
|
* polygon as the outer boundary. Outputs diameters of each Voronoi
|
||||||
* cell along with information about each watchtower.
|
* cell along with information about each watchtower.
|
||||||
* Stage 4: Same as Stage 4, but the watchtowers are sorted by ascending order
|
* Stage 4: Same as Stage 4, but the watchtowers are sorted by ascending order
|
||||||
* by diameter.
|
* by diameter.
|
||||||
*
|
*
|
||||||
* To see valid input arguments, run ./voronoi2
|
* To see valid input arguments, run ./voronoi2
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VORONOI_HEADER
|
#ifndef VORONOI_HEADER
|
||||||
#include "voronoi.h"
|
#include "voronoi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef INPUT_HEADER
|
#ifndef INPUT_HEADER
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
/* Ensure input arguments are correct */
|
/* Ensure input arguments are correct */
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
printArgError(STAGE_ERROR, "Incorrect usage.");
|
printArgError(STAGE_ERROR, "Incorrect usage.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get stage, ensure correct input args */
|
/* 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) {
|
||||||
printArgError(stage, "Incorrect number of inputs.");
|
printArgError(stage, "Incorrect number of inputs.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then run the program according to the stage given */
|
/* Then run the program according to the stage given */
|
||||||
switch(stage) {
|
switch(stage) {
|
||||||
/* Expected usage: ./voronoi2 1 pointsFile outputFile */
|
/* Expected usage: ./voronoi2 1 pointsFile outputFile */
|
||||||
case STAGE_1:
|
case STAGE_1:
|
||||||
stage1(argv[2], argv[3]);
|
stage1(argv[2], argv[3]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Expected usage: ./voronoi2 2 pointsFile polygonFile outputFile */
|
/* Expected usage: ./voronoi2 2 pointsFile polygonFile outputFile */
|
||||||
case STAGE_2:
|
case STAGE_2:
|
||||||
stage2(argv[2], argv[3], argv[4]);
|
stage2(argv[2], argv[3], argv[4]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Expected usage: ./voronoi2 3 dataFile polygonFile outputFile */
|
/* Expected usage: ./voronoi2 3 dataFile polygonFile outputFile */
|
||||||
case STAGE_3:
|
case STAGE_3:
|
||||||
stage3(argv[2], argv[3], argv[4]);
|
stage3(argv[2], argv[3], argv[4]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Expected usage: /voronoi2 4 dataFile polygonFile outputFile */
|
/* Expected usage: /voronoi2 4 dataFile polygonFile outputFile */
|
||||||
case STAGE_4:
|
case STAGE_4:
|
||||||
stage4(argv[2], argv[3], argv[4]);
|
stage4(argv[2], argv[3], argv[4]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Return error if stage number isn't defined. */
|
/* Return error if stage number isn't defined. */
|
||||||
case STAGE_ERROR:
|
case STAGE_ERROR:
|
||||||
default:
|
default:
|
||||||
printArgError(stage, "Invalid stage entered.");
|
printArgError(stage, "Invalid stage entered.");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,115 +1,115 @@
|
||||||
/* voronoi.c
|
/* voronoi.c
|
||||||
*
|
*
|
||||||
* 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 14th 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.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TOWERS_HEADER
|
#ifndef TOWERS_HEADER
|
||||||
#include "towers.h"
|
#include "towers.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BASE_10 10
|
#define BASE_10 10
|
||||||
#define MAX_CSV_ENTRY_LEN 512
|
#define MAX_CSV_ENTRY_LEN 512
|
||||||
#define MAX_FIELD_LEN 128
|
#define MAX_FIELD_LEN 128
|
||||||
#define NUM_CSV_FIELDS 6
|
#define NUM_CSV_FIELDS 6
|
||||||
|
|
||||||
void readATower(char *lineBuffer, tower_t *tower) {
|
void readATower(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;
|
||||||
|
|
||||||
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) {
|
||||||
/* Cases represent each field in the CSV, and as such are handled
|
/* Cases represent each field in the CSV, and as such are handled
|
||||||
* differently.
|
* differently.
|
||||||
*/
|
*/
|
||||||
case 0:
|
case 0:
|
||||||
tower->id = malloc(sizeof(char) * tokenLength + 1);
|
tower->id = malloc(sizeof(char) * tokenLength + 1);
|
||||||
checkNullPointer(tower->id);
|
checkNullPointer(tower->id);
|
||||||
strcpy(tower->id, token);
|
strcpy(tower->id, token);
|
||||||
tower->id[tokenLength] = '\0';
|
tower->id[tokenLength] = '\0';
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
tower->postcode = malloc(sizeof(char) * tokenLength + 1);
|
tower->postcode = malloc(sizeof(char) * tokenLength + 1);
|
||||||
checkNullPointer(tower->postcode);
|
checkNullPointer(tower->postcode);
|
||||||
strcpy(tower->postcode, token);
|
strcpy(tower->postcode, token);
|
||||||
tower->postcode[tokenLength] = '\0';
|
tower->postcode[tokenLength] = '\0';
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
tower->population = strtol(token, NULL, BASE_10);
|
tower->population = strtol(token, NULL, BASE_10);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
tower->manager = malloc(sizeof(char) * tokenLength + 1);
|
tower->manager = malloc(sizeof(char) * tokenLength + 1);
|
||||||
checkNullPointer(tower->manager);
|
checkNullPointer(tower->manager);
|
||||||
strcpy(tower->manager, token);
|
strcpy(tower->manager, token);
|
||||||
tower->manager[tokenLength] = '\0';
|
tower->manager[tokenLength] = '\0';
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
tower->x = strtod(token, NULL);
|
tower->x = strtod(token, NULL);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
tower->y = strtod(token, NULL);
|
tower->y = strtod(token, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
token = strtok(NULL, ",");
|
token = strtok(NULL, ",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
|
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
|
||||||
/* Maximum length of a single CSV line (+1 for null char in string) */
|
/* Maximum length of a single CSV line (+1 for null char in string) */
|
||||||
size_t lineBufferSize = MAX_CSV_ENTRY_LEN + 1;
|
size_t lineBufferSize = MAX_CSV_ENTRY_LEN + 1;
|
||||||
|
|
||||||
/* Stores the current line from the CSV */
|
/* Stores the current line from the CSV */
|
||||||
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
|
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
|
||||||
checkNullPointer(lineBuffer);
|
checkNullPointer(lineBuffer);
|
||||||
|
|
||||||
int maxSizetowers = 1;
|
int maxSizetowers = 1;
|
||||||
|
|
||||||
/* Discard the header line, then read the rest of the CSV */
|
/* Discard the header line, then read the rest of the CSV */
|
||||||
getline(&lineBuffer, &lineBufferSize, datasetFile);
|
getline(&lineBuffer, &lineBufferSize, datasetFile);
|
||||||
while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) {
|
while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) {
|
||||||
/* Ensure there is enough space in the towers array */
|
/* Ensure there is enough space in the towers array */
|
||||||
if (*numTowers == maxSizetowers) {
|
if (*numTowers == maxSizetowers) {
|
||||||
maxSizetowers *= 2;
|
maxSizetowers *= 2;
|
||||||
tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers));
|
tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers));
|
||||||
checkNullPointer(temp);
|
checkNullPointer(temp);
|
||||||
towers = temp;
|
towers = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The current tower being filled in with information */
|
/* The current tower being filled in with information */
|
||||||
towers[*numTowers] = malloc(sizeof(*towers[*numTowers]));
|
towers[*numTowers] = malloc(sizeof(*towers[*numTowers]));
|
||||||
|
|
||||||
readATower(lineBuffer, towers[*numTowers]);
|
readATower(lineBuffer, towers[*numTowers]);
|
||||||
*numTowers += 1;
|
*numTowers += 1;
|
||||||
}
|
}
|
||||||
free(lineBuffer);
|
free(lineBuffer);
|
||||||
return towers;
|
return towers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeTowers(tower_t **towers, int numTowers) {
|
void freeTowers(tower_t **towers, int numTowers) {
|
||||||
if (!towers) {
|
if (!towers) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < numTowers; i++) {
|
for (int i = 0; i < numTowers; i++) {
|
||||||
if (towers[i]->id) {
|
if (towers[i]->id) {
|
||||||
free(towers[i]->id);
|
free(towers[i]->id);
|
||||||
}
|
}
|
||||||
if (towers[i]->manager) {
|
if (towers[i]->manager) {
|
||||||
free(towers[i]->manager);
|
free(towers[i]->manager);
|
||||||
}
|
}
|
||||||
if (towers[i]->postcode) {
|
if (towers[i]->postcode) {
|
||||||
free(towers[i]->postcode);
|
free(towers[i]->postcode);
|
||||||
}
|
}
|
||||||
if (towers[i]) {
|
if (towers[i]) {
|
||||||
free(towers[i]);
|
free(towers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(towers);
|
free(towers);
|
||||||
}
|
}
|
|
@ -1,26 +1,26 @@
|
||||||
#ifndef COMMON_HEADER
|
#ifndef COMMON_HEADER
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TOWERS_HEADER
|
#ifndef TOWERS_HEADER
|
||||||
#define TOWERS_HEADER
|
#define TOWERS_HEADER
|
||||||
|
|
||||||
typedef struct tower {
|
typedef struct tower {
|
||||||
char *id;
|
char *id;
|
||||||
char *postcode;
|
char *postcode;
|
||||||
char *manager;
|
char *manager;
|
||||||
int population;
|
int population;
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
} tower_t;
|
} tower_t;
|
||||||
|
|
||||||
/* Reads the current row from the CSV and converts it into a new tower */
|
/* Reads the current row from the CSV and converts it into a new tower */
|
||||||
void readATower(char *lineBuffer, tower_t *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);
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,208 +1,208 @@
|
||||||
/* voronoi.c
|
/* voronoi.c
|
||||||
*
|
*
|
||||||
* 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 14th 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.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VORONOI_HEADER
|
#ifndef VORONOI_HEADER
|
||||||
#include "voronoi.h"
|
#include "voronoi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) {
|
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) {
|
||||||
if (bisector->isSlopeInfinite) {
|
if (bisector->isSlopeInfinite) {
|
||||||
/* Cannot print infinite slope, so print only x-intercept */
|
/* Cannot print infinite slope, so print only x-intercept */
|
||||||
fprintf(outputFile, "x = %lf\n", bisector->mid->x);
|
fprintf(outputFile, "x = %lf\n", bisector->mid->x);
|
||||||
} else {
|
} else {
|
||||||
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
|
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
|
||||||
bisector->slope, bisector->mid->x, bisector->mid->y);
|
bisector->slope, bisector->mid->x, bisector->mid->y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
|
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
|
||||||
fprintf(outputFile, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)\n", \
|
fprintf(outputFile, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)\n", \
|
||||||
intersection->fromEdge, intersection->fromPoint->x, \
|
intersection->fromEdge, intersection->fromPoint->x, \
|
||||||
intersection->fromPoint->y, intersection->toEdge, \
|
intersection->fromPoint->y, intersection->toEdge, \
|
||||||
intersection->toPoint->x, intersection->toPoint->y);
|
intersection->toPoint->x, intersection->toPoint->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter) {
|
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter) {
|
||||||
fprintf(outputFile, "Watchtower ID: %s, Postcode: %s, Population " \
|
fprintf(outputFile, "Watchtower ID: %s, Postcode: %s, Population " \
|
||||||
"Served: %d, Watchtower Point of Contact Name: %s, x: %lf, y: %lf, " \
|
"Served: %d, Watchtower Point of Contact Name: %s, x: %lf, y: %lf, " \
|
||||||
"Diameter of Cell: %lf\n", tower->id, tower->postcode, \
|
"Diameter of Cell: %lf\n", tower->id, tower->postcode, \
|
||||||
tower->population, tower->manager, tower->x, tower->y, diameter);
|
tower->population, tower->manager, tower->x, tower->y, diameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower) {
|
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower) {
|
||||||
for (int i = 0; i < getFaceCount(dcel); i++) {
|
for (int i = 0; i < getFaceCount(dcel); i++) {
|
||||||
if (inFace(dcel, tower->x, tower->y, i)) {
|
if (inFace(dcel, tower->x, tower->y, i)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void incrementalVoronoi(DCEL_t *voronoi, tower_t *tower) {
|
void incrementalVoronoi(DCEL_t *voronoi, tower_t *tower) {
|
||||||
int faceTowerIsIn = getFaceTowerIsIn(voronoi, tower);
|
int faceTowerIsIn = getFaceTowerIsIn(voronoi, tower);
|
||||||
if (faceTowerIsIn == -1) {
|
if (faceTowerIsIn == -1) {
|
||||||
fprintf(stderr, "Error: Watchtower %s is outside the polygon.\n", \
|
fprintf(stderr, "Error: Watchtower %s is outside the polygon.\n", \
|
||||||
tower->id);
|
tower->id);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB) {
|
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB) {
|
||||||
/* Get vertices from towers */
|
/* Get vertices from towers */
|
||||||
vertex_t *pointA = getAPoint(towerA->x, towerA->y);
|
vertex_t *pointA = getAPoint(towerA->x, towerA->y);
|
||||||
vertex_t *pointB = getAPoint(towerB->x, towerB->y);
|
vertex_t *pointB = getAPoint(towerB->x, towerB->y);
|
||||||
|
|
||||||
/* Create first bisector */
|
/* Create first bisector */
|
||||||
bisector_t *bisector = newBisector();
|
bisector_t *bisector = newBisector();
|
||||||
bisector = getABisector(bisector, pointA, pointB);
|
bisector = getABisector(bisector, pointA, pointB);
|
||||||
|
|
||||||
/* Get intersection of bisector with the polygon */
|
/* Get intersection of bisector with the polygon */
|
||||||
intersection_t *intersection = NULL;
|
intersection_t *intersection = NULL;
|
||||||
intersection = getAnIntersection(intersection, voronoi, bisector, \
|
intersection = getAnIntersection(intersection, voronoi, bisector, \
|
||||||
DEFAULT_FACE, DEFAULTMINLENGTH);
|
DEFAULT_FACE, DEFAULTMINLENGTH);
|
||||||
|
|
||||||
if (intersection) {
|
if (intersection) {
|
||||||
free(intersection->fromPoint);
|
free(intersection->fromPoint);
|
||||||
free(intersection->toPoint);
|
free(intersection->toPoint);
|
||||||
free(intersection);
|
free(intersection);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(bisector->mid);
|
free(bisector->mid);
|
||||||
free(bisector);
|
free(bisector);
|
||||||
free(pointA);
|
free(pointA);
|
||||||
free(pointB);
|
free(pointB);
|
||||||
return voronoi;
|
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");
|
||||||
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
|
||||||
|
|
||||||
/* Points are given as pairs, so initialise 2 points */
|
/* Points are given as pairs, so initialise 2 points */
|
||||||
vertex_t **points = malloc(sizeof(*points) * 2);
|
vertex_t **points = malloc(sizeof(*points) * 2);
|
||||||
checkNullPointer(points);
|
checkNullPointer(points);
|
||||||
int numPoints = 0;
|
int numPoints = 0;
|
||||||
points = readPoints(points, pointsFile, &numPoints);
|
points = readPoints(points, pointsFile, &numPoints);
|
||||||
|
|
||||||
/* There are half as many bisectors as points */
|
/* There are half as many bisectors as points */
|
||||||
int numBisectors = numPoints / 2;
|
int numBisectors = numPoints / 2;
|
||||||
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
|
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
|
||||||
checkNullPointer(bisectors);
|
checkNullPointer(bisectors);
|
||||||
bisectors = getBisectors(bisectors, points, numBisectors);
|
bisectors = getBisectors(bisectors, points, numBisectors);
|
||||||
|
|
||||||
/* For each pair, calculate and print the bisector to outputFile */
|
/* For each pair, calculate and print the bisector to outputFile */
|
||||||
for (int i = 0; i < numBisectors; i++) {
|
for (int i = 0; i < numBisectors; i++) {
|
||||||
stage1PrintBisector(bisectors[i], outputFile);
|
stage1PrintBisector(bisectors[i], outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
freePoints(points, numPoints);
|
freePoints(points, numPoints);
|
||||||
freeBisectors(bisectors, numBisectors);
|
freeBisectors(bisectors, numBisectors);
|
||||||
fclose(pointsFile);
|
fclose(pointsFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage2(char *pointsFileName, char *polygonFileName, \
|
void stage2(char *pointsFileName, char *polygonFileName, \
|
||||||
char *outputFileName) {
|
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");
|
||||||
|
|
||||||
/* Points are given as pairs, so initialise 2 points */
|
/* Points are given as pairs, so initialise 2 points */
|
||||||
vertex_t **points = malloc(sizeof(*points) * 2);
|
vertex_t **points = malloc(sizeof(*points) * 2);
|
||||||
checkNullPointer(points);
|
checkNullPointer(points);
|
||||||
int numPoints = 0;
|
int numPoints = 0;
|
||||||
points = readPoints(points, pointsFile, &numPoints);
|
points = readPoints(points, pointsFile, &numPoints);
|
||||||
|
|
||||||
/* There are half as many bisectors as points */
|
/* There are half as many bisectors as points */
|
||||||
int numBisectors = numPoints / 2;
|
int numBisectors = numPoints / 2;
|
||||||
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
|
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
|
||||||
checkNullPointer(bisectors);
|
checkNullPointer(bisectors);
|
||||||
bisectors = getBisectors(bisectors, points, numBisectors);
|
bisectors = getBisectors(bisectors, points, numBisectors);
|
||||||
|
|
||||||
/* Construct the DCEL from the polygon file */
|
/* Construct the DCEL from the polygon file */
|
||||||
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
||||||
|
|
||||||
/* Calculate and print intersections to the output file */
|
/* Calculate and print intersections to the output file */
|
||||||
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, \
|
intersections = getIntersections(intersections, &numIntersections, \
|
||||||
bisectors, numBisectors, dcel, DEFAULT_FACE, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
freePoints(points, numPoints);
|
freePoints(points, numPoints);
|
||||||
freeBisectors(bisectors, numBisectors);
|
freeBisectors(bisectors, numBisectors);
|
||||||
freeIntersections(intersections, numIntersections);
|
freeIntersections(intersections, numIntersections);
|
||||||
freeDCEL(dcel);
|
freeDCEL(dcel);
|
||||||
fclose(pointsFile);
|
fclose(pointsFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
||||||
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
|
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
|
||||||
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
|
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
|
||||||
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 */
|
/* Read towers from the data file */
|
||||||
tower_t **towers = malloc(sizeof(*towers));
|
tower_t **towers = malloc(sizeof(*towers));
|
||||||
checkNullPointer(towers);
|
checkNullPointer(towers);
|
||||||
int numTowers = 0;
|
int numTowers = 0;
|
||||||
towers = readTowers(towers, dataFile, &numTowers);
|
towers = readTowers(towers, dataFile, &numTowers);
|
||||||
|
|
||||||
/* Construct the DCEL from the polygon file */
|
/* Construct the DCEL from the polygon file */
|
||||||
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
||||||
|
|
||||||
/* Add each tower to the Voronoi DCEL */
|
/* Add each tower to the Voronoi DCEL */
|
||||||
|
|
||||||
/* Get diameters and output to outputFile */
|
/* Get diameters and output to outputFile */
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
freeDCEL(dcel);
|
freeDCEL(dcel);
|
||||||
freeTowers(towers, numTowers);
|
freeTowers(towers, numTowers);
|
||||||
fclose(dataFile);
|
fclose(dataFile);
|
||||||
fclose(polygonFile);
|
fclose(polygonFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
|
||||||
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
|
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
|
||||||
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
|
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
|
||||||
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 */
|
/* Read towers from the data file */
|
||||||
tower_t **towers = malloc(sizeof(*towers));
|
tower_t **towers = malloc(sizeof(*towers));
|
||||||
checkNullPointer(towers);
|
checkNullPointer(towers);
|
||||||
int numTowers = 0;
|
int numTowers = 0;
|
||||||
towers = readTowers(towers, dataFile, &numTowers);
|
towers = readTowers(towers, dataFile, &numTowers);
|
||||||
|
|
||||||
/* Construct the DCEL from the polygon file */
|
/* Construct the DCEL from the polygon file */
|
||||||
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
DCEL_t *dcel = readPolygonFile(polygonFileName);
|
||||||
|
|
||||||
/* Add each tower to the Voronoi DCEL */
|
/* Add each tower to the Voronoi DCEL */
|
||||||
|
|
||||||
/* Get diameters and sort, then output to outputFile */
|
/* Get diameters and sort, then output to outputFile */
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
freeDCEL(dcel);
|
freeDCEL(dcel);
|
||||||
freeTowers(towers, numTowers);
|
freeTowers(towers, numTowers);
|
||||||
fclose(dataFile);
|
fclose(dataFile);
|
||||||
fclose(polygonFile);
|
fclose(polygonFile);
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
1.0 1.0 2.0 1.0
|
1.0 1.0 2.0 1.0
|
||||||
1.0 1.0 3.0 1.0
|
1.0 1.0 3.0 1.0
|
||||||
1.0 1.0 4.0 1.0
|
1.0 1.0 4.0 1.0
|
||||||
1.0 1.0 5.0 1.0
|
1.0 1.0 5.0 1.0
|
||||||
0.0 1.0 1.0 1.0
|
0.0 1.0 1.0 1.0
|
||||||
0.0 1.0 2.0 1.0
|
0.0 1.0 2.0 1.0
|
||||||
0.0 1.0 3.0 1.0
|
0.0 1.0 3.0 1.0
|
||||||
0.0 1.0 4.0 1.0
|
0.0 1.0 4.0 1.0
|
||||||
0.0 2.0 4.0 2.0
|
0.0 2.0 4.0 2.0
|
||||||
0.0 3.0 4.0 3.0
|
0.0 3.0 4.0 3.0
|
||||||
0.0 4.0 4.0 4.0
|
0.0 4.0 4.0 4.0
|
||||||
0.0 0.0 4.0 0.0
|
0.0 0.0 4.0 0.0
|
|
@ -1,6 +1,6 @@
|
||||||
145.6 -34.2 145.6 -35.2
|
145.6 -34.2 145.6 -35.2
|
||||||
145.6 -34.2 145.6 -36.2
|
145.6 -34.2 145.6 -36.2
|
||||||
145.6 -35.2 148.6 -35.2
|
145.6 -35.2 148.6 -35.2
|
||||||
147.6 -35.2 146.6 -35.2
|
147.6 -35.2 146.6 -35.2
|
||||||
148.6 -35.2 146.6 -35.2
|
148.6 -35.2 146.6 -35.2
|
||||||
148.6 -34.2 146.6 -32.2
|
148.6 -34.2 146.6 -32.2
|
|
@ -1,6 +1,6 @@
|
||||||
0.0 0.0 0.0 1.0
|
0.0 0.0 0.0 1.0
|
||||||
0.0 0.0 0.0 2.0
|
0.0 0.0 0.0 2.0
|
||||||
0.0 1.0 0.0 2.0
|
0.0 1.0 0.0 2.0
|
||||||
1.0 1.0 1.0 2.0
|
1.0 1.0 1.0 2.0
|
||||||
2.0 1.0 2.0 2.0
|
2.0 1.0 2.0 2.0
|
||||||
3.0 1.0 3.0 2.0
|
3.0 1.0 3.0 2.0
|
|
@ -1,8 +1,8 @@
|
||||||
142.993000 -33.122900
|
142.993000 -33.122900
|
||||||
147.597600 -33.221400
|
147.597600 -33.221400
|
||||||
150.054600 -36.590100
|
150.054600 -36.590100
|
||||||
150.400400 -39.229900
|
150.400400 -39.229900
|
||||||
147.779600 -40.333100
|
147.779600 -40.333100
|
||||||
144.412600 -40.195200
|
144.412600 -40.195200
|
||||||
140.736200 -39.289000
|
140.736200 -39.289000
|
||||||
140.335800 -37.476600
|
140.335800 -37.476600
|
|
@ -1,4 +1,4 @@
|
||||||
140.9 -39.2
|
140.9 -39.2
|
||||||
140.9 -33.9
|
140.9 -33.9
|
||||||
150.0 -33.9
|
150.0 -33.9
|
||||||
150.0 -39.2
|
150.0 -39.2
|
|
@ -1,11 +1,11 @@
|
||||||
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
|
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
|
||||||
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
|
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
|
||||||
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
|
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
|
||||||
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
|
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
|
||||||
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
|
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
|
||||||
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
||||||
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
|
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
|
||||||
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
|
|
@ -1,101 +1,101 @@
|
||||||
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
WT3023QBQJF,3023,12794,Sandra Jaynes,144.7116868675065,-37.79835253004884
|
WT3023QBQJF,3023,12794,Sandra Jaynes,144.7116868675065,-37.79835253004884
|
||||||
WT3037YAKEI,3037,25577,Paul Watson,144.7404381965215,-37.71057606210163
|
WT3037YAKEI,3037,25577,Paul Watson,144.7404381965215,-37.71057606210163
|
||||||
WT3810RRMDP,3810,47894,Shirl Bays,145.54377380709113,-38.11642115246884
|
WT3810RRMDP,3810,47894,Shirl Bays,145.54377380709113,-38.11642115246884
|
||||||
WT3550ANADF,3550,10084,Virginia Lumpkins,144.25225555806287,-36.7583657822827
|
WT3550ANADF,3550,10084,Virginia Lumpkins,144.25225555806287,-36.7583657822827
|
||||||
WT3754SXJZI,3754,6292,Henriette Mitchell,145.1619799395555,-37.61057382984485
|
WT3754SXJZI,3754,6292,Henriette Mitchell,145.1619799395555,-37.61057382984485
|
||||||
WT3754WSOKP,3754,6292,James Lopez,145.11378037030943,-37.60927638542337
|
WT3754WSOKP,3754,6292,James Lopez,145.11378037030943,-37.60927638542337
|
||||||
WT3046ADKBS,3046,8515,Morris Pring,144.94317380188164,-37.71659755462475
|
WT3046ADKBS,3046,8515,Morris Pring,144.94317380188164,-37.71659755462475
|
||||||
WT3178BQAJG,3178,5612,Malka Smith,145.26959423333145,-37.918875236595035
|
WT3178BQAJG,3178,5612,Malka Smith,145.26959423333145,-37.918875236595035
|
||||||
WT3130PLSQY,3130,8043,Jose Hayes,145.13764760079675,-37.828083908584475
|
WT3130PLSQY,3130,8043,Jose Hayes,145.13764760079675,-37.828083908584475
|
||||||
WT3032PWVMB,3032,7362,William Mackiewicz,144.87559681642185,-37.79083145310446
|
WT3032PWVMB,3032,7362,William Mackiewicz,144.87559681642185,-37.79083145310446
|
||||||
WT3173JKIEY,3173,5157,Teddy Mccauley,145.18948448769126,-37.992844271467284
|
WT3173JKIEY,3173,5157,Teddy Mccauley,145.18948448769126,-37.992844271467284
|
||||||
WT3122GVRSM,3122,11755,William Bell,145.0366394627393,-37.810997917513916
|
WT3122GVRSM,3122,11755,William Bell,145.0366394627393,-37.810997917513916
|
||||||
WT3171BGAEJ,3171,7238,Lila Levy,145.1337946019459,-37.92898751855743
|
WT3171BGAEJ,3171,7238,Lila Levy,145.1337946019459,-37.92898751855743
|
||||||
WT3128AQDRS,3128,6609,Sarah Kauffman,145.1295813912443,-37.82078823368618
|
WT3128AQDRS,3128,6609,Sarah Kauffman,145.1295813912443,-37.82078823368618
|
||||||
WT3219MZCMM,3219,4928,Charlie Gerber,144.37942394090373,-38.19362930153523
|
WT3219MZCMM,3219,4928,Charlie Gerber,144.37942394090373,-38.19362930153523
|
||||||
WT3170XJVWP,3170,9684,Lucy Lahay,145.17553159514887,-37.936150181976984
|
WT3170XJVWP,3170,9684,Lucy Lahay,145.17553159514887,-37.936150181976984
|
||||||
WT3031DMFGC,3031,6177,Caroline Luckenbach,144.90707048527796,-37.78767901585732
|
WT3031DMFGC,3031,6177,Caroline Luckenbach,144.90707048527796,-37.78767901585732
|
||||||
WT3015PKLER,3015,8736,Bill Kilbane,144.8979183219914,-37.82580808335247
|
WT3015PKLER,3015,8736,Bill Kilbane,144.8979183219914,-37.82580808335247
|
||||||
WT3106WQFPR,3106,2374,Mary Bass,145.14274097499288,-37.731835101044354
|
WT3106WQFPR,3106,2374,Mary Bass,145.14274097499288,-37.731835101044354
|
||||||
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
|
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
|
||||||
WT3352KHBBN,3352,15996,Richard Askew,143.60419898610786,-37.722432808576656
|
WT3352KHBBN,3352,15996,Richard Askew,143.60419898610786,-37.722432808576656
|
||||||
WT3079QORWG,3079,5329,Jerry Somogyi,145.05361972090736,-37.76092644646485
|
WT3079QORWG,3079,5329,Jerry Somogyi,145.05361972090736,-37.76092644646485
|
||||||
WT3850WPPZJ,3850,14779,Scott Buggie,146.99670975934802,-38.11120375121315
|
WT3850WPPZJ,3850,14779,Scott Buggie,146.99670975934802,-38.11120375121315
|
||||||
WT3400BOZRI,3400,14543,Tom Davis,142.2056868163526,-36.700923449995635
|
WT3400BOZRI,3400,14543,Tom Davis,142.2056868163526,-36.700923449995635
|
||||||
WT3123YZTIF,3123,7160,Paul Earwood,145.05955004240124,-37.82771644759941
|
WT3123YZTIF,3123,7160,Paul Earwood,145.05955004240124,-37.82771644759941
|
||||||
WT3224OGJJN,3224,1773,Shirley Hall,144.42849521054393,-38.218027859101916
|
WT3224OGJJN,3224,1773,Shirley Hall,144.42849521054393,-38.218027859101916
|
||||||
WT3137PJCVG,3137,1541,Yolanda Stern,145.32887887734955,-37.830025027117365
|
WT3137PJCVG,3137,1541,Yolanda Stern,145.32887887734955,-37.830025027117365
|
||||||
WT3305NMFYC,3305,3204,Larry Witter,141.29643421841453,-38.11167114301085
|
WT3305NMFYC,3305,3204,Larry Witter,141.29643421841453,-38.11167114301085
|
||||||
WT3305KWOFD,3305,3204,Judith Figueroa,141.25644777166127,-38.24079323443777
|
WT3305KWOFD,3305,3204,Judith Figueroa,141.25644777166127,-38.24079323443777
|
||||||
WT3025UXSIE,3025,2430,Willie Laigo,144.79429337101448,-37.82881778367748
|
WT3025UXSIE,3025,2430,Willie Laigo,144.79429337101448,-37.82881778367748
|
||||||
WT3437KHBPL,3437,3479,Charlotte Green,144.59696365066134,-37.48113208398435
|
WT3437KHBPL,3437,3479,Charlotte Green,144.59696365066134,-37.48113208398435
|
||||||
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
|
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
|
||||||
WT3019ASCJP,3019,3065,Charlotte Coutermarsh,144.85492421197495,-37.772589492919515
|
WT3019ASCJP,3019,3065,Charlotte Coutermarsh,144.85492421197495,-37.772589492919515
|
||||||
WT3019JIKGX,3019,3065,Vincent January,144.85730316799982,-37.7718018219131
|
WT3019JIKGX,3019,3065,Vincent January,144.85730316799982,-37.7718018219131
|
||||||
WT3764MKCUE,3764,4582,Alejandrina Salazar,144.970506104261,-37.15854276662507
|
WT3764MKCUE,3764,4582,Alejandrina Salazar,144.970506104261,-37.15854276662507
|
||||||
WT3730UTUPX,3730,2944,Curtis Johnson,145.8390200963087,-36.01276678240247
|
WT3730UTUPX,3730,2944,Curtis Johnson,145.8390200963087,-36.01276678240247
|
||||||
WT3054SQEQA,3054,8428,Eugene Salano,144.95861592679725,-37.783412869711185
|
WT3054SQEQA,3054,8428,Eugene Salano,144.95861592679725,-37.783412869711185
|
||||||
WT3620DPAMB,3620,4120,Ben Oneil,144.96824098896346,-36.398921729744224
|
WT3620DPAMB,3620,4120,Ben Oneil,144.96824098896346,-36.398921729744224
|
||||||
WT3804OQOOF,3804,2023,Jackie Smith,145.35298253700518,-37.98426462189473
|
WT3804OQOOF,3804,2023,Jackie Smith,145.35298253700518,-37.98426462189473
|
||||||
WT3909HFRJQ,3909,2633,Maria Rhodus,147.90601975805444,-37.764598529015366
|
WT3909HFRJQ,3909,2633,Maria Rhodus,147.90601975805444,-37.764598529015366
|
||||||
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
WT3953NPQQN,3953,1571,Peter Willer,146.04193592469497,-38.44633595871089
|
WT3953NPQQN,3953,1571,Peter Willer,146.04193592469497,-38.44633595871089
|
||||||
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
WT3027FZKQC,3027,3323,Angelo Hard,144.73167189283603,-37.85646049026309
|
WT3027FZKQC,3027,3323,Angelo Hard,144.73167189283603,-37.85646049026309
|
||||||
WT3996ZMYGL,3996,1846,Jennifer Adkins,145.7771574897382,-38.67107249698782
|
WT3996ZMYGL,3996,1846,Jennifer Adkins,145.7771574897382,-38.67107249698782
|
||||||
WT3984UBSFJ,3984,1041,Ned Johnson,145.61381415852048,-38.3660140349184
|
WT3984UBSFJ,3984,1041,Ned Johnson,145.61381415852048,-38.3660140349184
|
||||||
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
|
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
|
||||||
WT3950WWFHI,3950,2400,Donald Neil,145.789697571232,-38.44829776894874
|
WT3950WWFHI,3950,2400,Donald Neil,145.789697571232,-38.44829776894874
|
||||||
WT3842LLUAZ,3842,2391,Justin Butcher,146.43738290720543,-38.33409319136186
|
WT3842LLUAZ,3842,2391,Justin Butcher,146.43738290720543,-38.33409319136186
|
||||||
WT3225ZWRKT,3225,1352,Sierra Zelaya,144.63248453729392,-38.273920927385454
|
WT3225ZWRKT,3225,1352,Sierra Zelaya,144.63248453729392,-38.273920927385454
|
||||||
WT3797JXEYZ,3797,1738,Wade Seay,145.59525777895735,-37.85187937890587
|
WT3797JXEYZ,3797,1738,Wade Seay,145.59525777895735,-37.85187937890587
|
||||||
WT3980CXZJX,3980,1675,Marianne Gulledge,145.38407991603268,-38.234540388656654
|
WT3980CXZJX,3980,1675,Marianne Gulledge,145.38407991603268,-38.234540388656654
|
||||||
WT3862WPONG,3862,1578,Anthony Dawkins,147.33271058732282,-37.491238739170896
|
WT3862WPONG,3862,1578,Anthony Dawkins,147.33271058732282,-37.491238739170896
|
||||||
WT3202IDOPR,3202,1453,Shannon Bello,145.07561474247163,-37.947828524869706
|
WT3202IDOPR,3202,1453,Shannon Bello,145.07561474247163,-37.947828524869706
|
||||||
WT3304LTOER,3304,681,James Broadway,141.91304296053238,-38.08286392590754
|
WT3304LTOER,3304,681,James Broadway,141.91304296053238,-38.08286392590754
|
||||||
WT3478NOSNX,3478,614,Mary Wooster,143.190083774406,-36.70864776402552
|
WT3478NOSNX,3478,614,Mary Wooster,143.190083774406,-36.70864776402552
|
||||||
WT3373ZJBZG,3373,573,Helen Hu,143.40004730403342,-37.327257624451846
|
WT3373ZJBZG,3373,573,Helen Hu,143.40004730403342,-37.327257624451846
|
||||||
WT3373FDEUM,3373,573,Phyllis Hegyi,143.19424925274458,-37.38771716562931
|
WT3373FDEUM,3373,573,Phyllis Hegyi,143.19424925274458,-37.38771716562931
|
||||||
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
|
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
|
||||||
WT3673HXZDV,3673,346,June Matteson,145.99560167654946,-36.51826050506983
|
WT3673HXZDV,3673,346,June Matteson,145.99560167654946,-36.51826050506983
|
||||||
WT3943FFEHH,3943,398,Floyd Mcfaul,144.7219219690698,-38.32665967904324
|
WT3943FFEHH,3943,398,Floyd Mcfaul,144.7219219690698,-38.32665967904324
|
||||||
WT3937YBAGH,3937,762,Tyesha Evans,145.0385876851752,-38.37262744294901
|
WT3937YBAGH,3937,762,Tyesha Evans,145.0385876851752,-38.37262744294901
|
||||||
WT3786QKGRU,3786,506,Joe Pulaski,145.33261178176102,-37.876147897332174
|
WT3786QKGRU,3786,506,Joe Pulaski,145.33261178176102,-37.876147897332174
|
||||||
WT3321FSNXX,3321,759,James Mcintosh,144.00220559674338,-38.10453080180178
|
WT3321FSNXX,3321,759,James Mcintosh,144.00220559674338,-38.10453080180178
|
||||||
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
|
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
|
||||||
WT3231VKTTU,3231,418,Karl Evans,143.99174248566703,-38.47241568127852
|
WT3231VKTTU,3231,418,Karl Evans,143.99174248566703,-38.47241568127852
|
||||||
WT3231YSKOO,3231,418,Leontine Mcghee,144.07128861030645,-38.416049306559025
|
WT3231YSKOO,3231,418,Leontine Mcghee,144.07128861030645,-38.416049306559025
|
||||||
WT3766LYICC,3766,619,Gary Evans,145.3953639008541,-37.81880414343826
|
WT3766LYICC,3766,619,Gary Evans,145.3953639008541,-37.81880414343826
|
||||||
WT3381FUDIA,3381,151,Penny Carrier,142.7602629758581,-37.02897861269415
|
WT3381FUDIA,3381,151,Penny Carrier,142.7602629758581,-37.02897861269415
|
||||||
WT3232GSLYH,3232,1114,Joshua Sickafoose,143.96111969797116,-38.544885004427805
|
WT3232GSLYH,3232,1114,Joshua Sickafoose,143.96111969797116,-38.544885004427805
|
||||||
WT3933UXXXP,3933,549,Shaun Guffey,145.11706009902144,-38.26228415412558
|
WT3933UXXXP,3933,549,Shaun Guffey,145.11706009902144,-38.26228415412558
|
||||||
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
||||||
WT3701TPSEH,3701,269,Grant Kennedy,147.41241338695838,-36.74234154193107
|
WT3701TPSEH,3701,269,Grant Kennedy,147.41241338695838,-36.74234154193107
|
||||||
WT3312BCEJQ,3312,1031,Alexandra Ratzlaff,141.38649875710092,-37.85213620536482
|
WT3312BCEJQ,3312,1031,Alexandra Ratzlaff,141.38649875710092,-37.85213620536482
|
||||||
WT3332VSYVL,3332,338,Charles Koons,144.08742265383532,-37.906318691909874
|
WT3332VSYVL,3332,338,Charles Koons,144.08742265383532,-37.906318691909874
|
||||||
WT3623CXKIC,3623,224,Rebecca Lara,144.90863570166192,-36.44103547317975
|
WT3623CXKIC,3623,224,Rebecca Lara,144.90863570166192,-36.44103547317975
|
||||||
WT3289ZSWDS,3289,378,Kim Hall,142.1760506248015,-37.83343114690931
|
WT3289ZSWDS,3289,378,Kim Hall,142.1760506248015,-37.83343114690931
|
||||||
WT3728YZARW,3728,318,Heather Cummings,145.8168813215635,-36.115027477064245
|
WT3728YZARW,3728,318,Heather Cummings,145.8168813215635,-36.115027477064245
|
||||||
WT3633WGRXB,3633,201,John Miller,145.48023893751045,-36.2875408553956
|
WT3633WGRXB,3633,201,John Miller,145.48023893751045,-36.2875408553956
|
||||||
WT3633UVHAO,3633,201,Michael Price,145.51505172180683,-36.31027112244356
|
WT3633UVHAO,3633,201,Michael Price,145.51505172180683,-36.31027112244356
|
||||||
WT3637KIERO,3637,198,Robert Dow,145.25553090556156,-36.0980796504903
|
WT3637KIERO,3637,198,Robert Dow,145.25553090556156,-36.0980796504903
|
||||||
WT3063WZIQE,3063,114,James Miller,144.81061694155076,-37.553501843305575
|
WT3063WZIQE,3063,114,James Miller,144.81061694155076,-37.553501843305575
|
||||||
WT3334GGKOS,3334,141,Elizabet Benson,144.1621690362788,-37.67891238372265
|
WT3334GGKOS,3334,141,Elizabet Benson,144.1621690362788,-37.67891238372265
|
||||||
WT3251FUJSG,3251,522,Lisa Voegele,143.5797389397756,-38.1623931117428
|
WT3251FUJSG,3251,522,Lisa Voegele,143.5797389397756,-38.1623931117428
|
||||||
WT3649NJHAF,3649,86,Catherine Ortiz,145.70444412227315,-36.12591041370753
|
WT3649NJHAF,3649,86,Catherine Ortiz,145.70444412227315,-36.12591041370753
|
||||||
WT3287NEKVB,3287,216,Joel Simmons,142.26305043381535,-37.983480961999916
|
WT3287NEKVB,3287,216,Joel Simmons,142.26305043381535,-37.983480961999916
|
||||||
WT3407PYOAR,3407,420,Gale Martin,141.83324586447986,-37.2859635851256
|
WT3407PYOAR,3407,420,Gale Martin,141.83324586447986,-37.2859635851256
|
||||||
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
|
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
|
||||||
WT3719TVVJM,3719,122,Brent Bautista,145.6864773045679,-37.03188286944955
|
WT3719TVVJM,3719,122,Brent Bautista,145.6864773045679,-37.03188286944955
|
||||||
WT3719HLABD,3719,122,Alfred Too,145.52985920519603,-36.964844896202216
|
WT3719HLABD,3719,122,Alfred Too,145.52985920519603,-36.964844896202216
|
||||||
WT3573DPVGU,3573,111,Wiley Palmer,144.15009214850954,-36.12318035418112
|
WT3573DPVGU,3573,111,Wiley Palmer,144.15009214850954,-36.12318035418112
|
||||||
WT3254RXAVL,3254,310,Amy Pugh,143.54387071993327,-38.308515316326016
|
WT3254RXAVL,3254,310,Amy Pugh,143.54387071993327,-38.308515316326016
|
||||||
WT3832NHOOV,3832,247,Bryan Warren,146.0154412945935,-37.93424551655733
|
WT3832NHOOV,3832,247,Bryan Warren,146.0154412945935,-37.93424551655733
|
||||||
WT3238BOTYW,3238,72,Bernard Jackson,143.567776369521,-38.625836774939955
|
WT3238BOTYW,3238,72,Bernard Jackson,143.567776369521,-38.625836774939955
|
||||||
WT3238MCUPV,3238,72,Nellie Banks,143.56196753560545,-38.82942446565583
|
WT3238MCUPV,3238,72,Nellie Banks,143.56196753560545,-38.82942446565583
|
||||||
WT3375LAJLR,3375,104,Emma Boatwright,143.2980117885972,-37.372200644973155
|
WT3375LAJLR,3375,104,Emma Boatwright,143.2980117885972,-37.372200644973155
|
||||||
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
||||||
WT3596HBEUF,3596,47,Jose Robertson,143.15095468769667,-35.190473662123345
|
WT3596HBEUF,3596,47,Jose Robertson,143.15095468769667,-35.190473662123345
|
||||||
WT3293SQKBY,3293,100,Shawn Clark,142.64808203542347,-37.82556647618436
|
WT3293SQKBY,3293,100,Shawn Clark,142.64808203542347,-37.82556647618436
|
||||||
WT3887NLNSJ,3887,342,Lorene Anderson,147.96080438424718,-37.76269836557282
|
WT3887NLNSJ,3887,342,Lorene Anderson,147.96080438424718,-37.76269836557282
|
|
|
@ -1,3 +1,3 @@
|
||||||
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
|
|
@ -1,4 +1,4 @@
|
||||||
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
|
|
@ -1,5 +1,5 @@
|
||||||
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
|
||||||
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
|
||||||
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
|
||||||
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
|
||||||
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
|
|