Update project structure

This commit is contained in:
Rory Healy 2024-06-12 23:50:48 +10:00
parent d552f37321
commit 19e9b90bd8
Signed by: roryhealy
GPG key ID: 0A3CBDE9C2AE672F
50 changed files with 4297 additions and 3389 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.o
build/
voronoi2

46
.vscode/launch.json vendored
View file

@ -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
}
]
}
]
}

View file

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

View file

@ -1,22 +1,15 @@
# Link command:
voronoi2: common.o towers.o dcel.o voronoi.o input.o main.o
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi2 main.o input.o voronoi.o dcel.o towers.o common.o -lm
# Compilation commands
common.o: common.c
gcc -Wall -Wextra -Werror -pedantic -g -o common.o common.c -c
towers.o: towers.c
gcc -Wall -Wextra -Werror -pedantic -g -o towers.o towers.c -c
dcel.o: dcel.c
gcc -Wall -Wextra -Werror -pedantic -g -o dcel.o dcel.c -c
voronoi.o: voronoi.c
gcc -Wall -Wextra -Werror -pedantic -g -o voronoi.o voronoi.c -c
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
BUILDDIR=$(CURDIR)/build
NAME=voronoi2
$(NAME): build/common.o build/towers.o build/dcel.o build/voronoi.o build/input.o build/main.o | $(BUILDDIR)
gcc -Wall -Wextra -Werror -pedantic -g -o $(NAME) $^ -lm
build/%.o: src/%.c
gcc -Wall -Wextra -Werror -pedantic -g -c $< -o $@
$(BUILDDIR):
mkdir -p $(BUILDDIR)
clean:
@rm -rf build
@rm -f $(NAME)

View file

@ -1 +1 @@
## COMP20003 Assignment 2
## COMP20003 Assignment 2 - Voronoi Diagrams

BIN
common.o

Binary file not shown.

BIN
dcel.o

Binary file not shown.

448
docs/SPECIFICATION.md Normal file
View 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 elses 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 doesnt 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

BIN
docs/images/image02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 KiB

BIN
docs/images/image03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
docs/images/image04.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/images/image05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/images/image06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/images/image07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
docs/images/image08.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

BIN
docs/images/image09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

218
docs/intersection.c Normal file
View 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
View 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

Binary file not shown.

BIN
input.o

Binary file not shown.

BIN
main.o

Binary file not shown.

View file

@ -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

View file

@ -1,29 +1,29 @@
/* common.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 14th September 2021
*
* Contains functions and headers for general use throughout other files.
*
*/
#ifndef COMMON_HEADER
#include "common.h"
#endif
void checkNullPointer(void *ptr) {
if (!ptr) {
fputs("Error: Cannot allocate memory.\n", stderr);
exit(EXIT_FAILURE);
}
}
FILE *safeFileOpen(FILE **f, char *fileName, char *mode) {
*f = fopen(fileName, mode);
if (*f == NULL) {
fprintf(stderr, "Error: Unable to open file %s\n", fileName);
exit(EXIT_FAILURE);
}
return *f;
}
/* common.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 14th September 2021
*
* Contains functions and headers for general use throughout other files.
*
*/
#ifndef COMMON_HEADER
#include "common.h"
#endif
void checkNullPointer(void *ptr) {
if (!ptr) {
fputs("Error: Cannot allocate memory.\n", stderr);
exit(EXIT_FAILURE);
}
}
FILE *safeFileOpen(FILE **f, char *fileName, char *mode) {
*f = fopen(fileName, mode);
if (*f == NULL) {
fprintf(stderr, "Error: Unable to open file %s\n", fileName);
exit(EXIT_FAILURE);
}
return *f;
}

View file

@ -1,31 +1,31 @@
#ifndef STDIO_HEADER
#define STDIO_HEADER
#include <stdio.h>
#endif
#ifndef STDLIB_HEADER
#define STDLIB_HEADER
#include <stdlib.h>
#endif
#ifndef STRING_HEADER
#define STRING_HEADER
#include <string.h>
#endif
#ifndef COMMON_HEADER
#define COMMON_HEADER
/* Checks if a pointer assigned through dynamic memory allocation is NULL */
void checkNullPointer(void *ptr);
/* Opens a file and checks if the file is safe to use */
FILE *safeFileOpen(FILE **f, char *fileName, char *mode);
#endif
#ifndef STDIO_HEADER
#define STDIO_HEADER
#include <stdio.h>
#endif
#ifndef STDLIB_HEADER
#define STDLIB_HEADER
#include <stdlib.h>
#endif
#ifndef STRING_HEADER
#define STRING_HEADER
#include <string.h>
#endif
#ifndef COMMON_HEADER
#define COMMON_HEADER
/* Checks if a pointer assigned through dynamic memory allocation is NULL */
void checkNullPointer(void *ptr);
/* Opens a file and checks if the file is safe to use */
FILE *safeFileOpen(FILE **f, char *fileName, char *mode);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,258 +1,258 @@
#ifndef TOWERS_HEADER
#include "towers.h"
#endif
#ifndef MATH_HEADER
#include <math.h>
#endif
#ifndef DCEL_HEADER
#define DCEL_HEADER
/* -------- Definitions, enums, and structs from Grady's base code --------- */
/* Representation of no face */
#define NOFACE (-1)
/* Default face for intersections. */
#define DEFAULT_FACE 0
/* Default minimum length for bisector in each direction */
#define DEFAULTMINLENGTH (200)
enum intersectType {
DOESNT_INTERSECT = 0, // Doesn't intersect
INTERSECT = 1, // Intersects
SAME_LINE_OVERLAP = 2, // Lines are the same
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
};
typedef struct vertex {
double x;
double y;
} vertex_t;
typedef struct halfEdge {
struct halfEdge *previous;
struct halfEdge *next;
struct halfEdge *twin;
int face;
int edge;
int startVertex;
int endVertex;
} halfEdge_t;
typedef struct edge {
halfEdge_t *halfEdge;
tower_t *tower;
} edge_t;
typedef struct face {
halfEdge_t *start;
tower_t *tower;
} face_t;
typedef struct split {
int startEdge;
int endEdge;
int verticesSpecified;
vertex_t startPoint;
vertex_t endPoint;
} split_t;
typedef struct DCEL {
edge_t *edges;
int edgesUsed;
int edgesAllocated;
face_t *faces;
int facesUsed;
int facesAllocated;
vertex_t *vertices;
int verticesUsed;
int verticesAllocated;
} DCEL_t;
/* ------------------------------ My structs ------------------------------- */
typedef struct bisector {
vertex_t *mid;
int isSlopeInfinite;
double slope;
} bisector_t;
typedef struct intersection {
int fromEdge;
int toEdge;
vertex_t *fromPoint;
vertex_t *toPoint;
} intersection_t;
/* ----------------------- My points functions start ----------------------- */
/* Creates a new point */
vertex_t *newPoint();
/* Gets a single point from an x-y pair */
vertex_t *getAPoint(double x, double y);
/* Reads a points file and stores the information in the points array */
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
/* Frees an array of points */
void freePoints(vertex_t **points, int numPoints);
/* Returns the distance between two points */
double distPoints(vertex_t *pointA, vertex_t *pointB);
/* ------------------------ My points functions end ------------------------ */
/* -------------------- My intersection functions start -------------------- */
/* Create a new intersection */
intersection_t *newIntersection();
/* Fills in a single intersection structure */
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
bisector_t *bisector, int face, int minLength);
/* Gets the intersection between the given bisector and the given DCEL
* for the given face.
*/
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength);
/* Frees an array of intersections */
void freeIntersections(intersection_t **intersections, int numIntersections);
/* --------------------- My intersection functions end --------------------- */
/* ---------------------- My bisector functions start ---------------------- */
/* Creates a new bisector */
bisector_t *newBisector();
/* Calculates and returns the equation of a bisector of two points */
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
vertex_t *pointB);
/* Returns a list of bisectors built from a list of points */
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numPoints);
/* Returns a point at least distance away from the midpoint of the
* bisector given. If direction is 0, then the point is +distance away in the
* x-direction, otherwise -distance away in the x-direction.
*/
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
/* Frees an array of bisectors */
void freeBisectors(bisector_t **bisectors, int numBisectors);
/* ----------------------- My bisector functions end ----------------------- */
/* ------------------------ My DCEL functions start ------------------------ */
/* Gets the diameter of the given face. */
double getDiameter(DCEL_t *dcel, int faceIndex);
/* ------------------------- My DCEL functions end ------------------------- */
/* ----------------------------------------------------------------------------
* Here on out are the functions from Grady's base code on Ed
* ----------------------------------------------------------------------------
*/
/* Allocate a new DCEL and return it. */
DCEL_t *newDCEL();
/* Allocate a new halfEdge and return it. */
halfEdge_t *newHalfEdge();
/* Check there's space for another vertex in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForVertex(DCEL_t *dcel);
/* Check there's space for another edge in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForEdge(DCEL_t *dcel);
/* Check there's space for another face in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForFace(DCEL_t *dcel);
/* Add an edge from the startVertex index vertex to the endVertex index.
* Only fills one half-edge as other half-edges will always be added
* through geometry construction.
*/
void addEdge(DCEL_t *dcel, int startVertex, int endVertex);
/* Add a face to the DCEL given using the given halfEdge and sets the face. */
void addFace(DCEL_t *dcel, halfEdge_t *he);
/* Reads the polygon from the given file. */
DCEL_t *readPolygonFile(char *polygonfileName);
/* Reads the next split from the given file. */
split_t *readNextSplit(FILE *splitfile);
/* Frees a given split. */
void freeSplit(split_t *split);
/* Returns 1 if vertices are sufficiently close, 0 otherwise. */
int vertexMatch(vertex_t *v1, vertex_t *v2);
/* Applies a given split to the DCEL. */
void applySplit(split_t *split, DCEL_t *dcel);
/* Frees the given DCEL */
void freeDCEL(DCEL_t *dcel);
/* Gets the number of faces in the DCEL. */
int getFaceCount(DCEL_t *dcel);
/* Returns INSIDE if the points is on the INSIDE of the vector twin by the CW
* winding order, OUTSIDE if it is OUTSIDE by the CW winding order, and
* DIR_UNDECIDED if the point lies on the vector between the points v1 and v2.
*/
int getRelativeDir(double x, double y, vertex_t *v1, vertex_t *v2);
/* Takes an established direction and a new direction, and returns 1 if the
* direction matches the decidedDirection or if the direction is undecided.
*/
int directionOrUndecided(int decidedDirection, int direction);
/* Returns 1 if the given x,y point is inside the given face. */
int inFace(DCEL_t *dcel, double x, double y, int faceIndex);
/* ------------------- O'Rourke's intersection functions ------------------- */
/* Returns -1, 0 or 1, based on the area enclosed by the three points.
* 0 corresponds to no area enclosed
*/
int areaSign(double sx, double sy, double ex, double ey, double x, double y);
/* Returns 1 if point (x, y) is between (sx, sy) and (ex, ey) */
int between(double sx, double sy, double ex, double ey, double x, double y);
/* Returns 1 if the point (x, y) is in the line from s(x, y) to e(x, y),
* 0 otherwise
*/
int collinear(double sx, double sy, double ex, double ey, double x, double y);
/* Tests if the half edge and bisector are parallel and overlapping, or not
* intersecting
*/
enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \
double bEx, double bEy, double *x, double *y);
/* Tests if a half edge and a bisector intersect */
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y);
#endif
#ifndef TOWERS_HEADER
#include "towers.h"
#endif
#ifndef MATH_HEADER
#include <math.h>
#endif
#ifndef DCEL_HEADER
#define DCEL_HEADER
/* -------- Definitions, enums, and structs from Grady's base code --------- */
/* Representation of no face */
#define NOFACE (-1)
/* Default face for intersections. */
#define DEFAULT_FACE 0
/* Default minimum length for bisector in each direction */
#define DEFAULTMINLENGTH (200)
enum intersectType {
DOESNT_INTERSECT = 0, // Doesn't intersect
INTERSECT = 1, // Intersects
SAME_LINE_OVERLAP = 2, // Lines are the same
ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint)
};
typedef struct vertex {
double x;
double y;
} vertex_t;
typedef struct halfEdge {
struct halfEdge *previous;
struct halfEdge *next;
struct halfEdge *twin;
int face;
int edge;
int startVertex;
int endVertex;
} halfEdge_t;
typedef struct edge {
halfEdge_t *halfEdge;
tower_t *tower;
} edge_t;
typedef struct face {
halfEdge_t *start;
tower_t *tower;
} face_t;
typedef struct split {
int startEdge;
int endEdge;
int verticesSpecified;
vertex_t startPoint;
vertex_t endPoint;
} split_t;
typedef struct DCEL {
edge_t *edges;
int edgesUsed;
int edgesAllocated;
face_t *faces;
int facesUsed;
int facesAllocated;
vertex_t *vertices;
int verticesUsed;
int verticesAllocated;
} DCEL_t;
/* ------------------------------ My structs ------------------------------- */
typedef struct bisector {
vertex_t *mid;
int isSlopeInfinite;
double slope;
} bisector_t;
typedef struct intersection {
int fromEdge;
int toEdge;
vertex_t *fromPoint;
vertex_t *toPoint;
} intersection_t;
/* ----------------------- My points functions start ----------------------- */
/* Creates a new point */
vertex_t *newPoint();
/* Gets a single point from an x-y pair */
vertex_t *getAPoint(double x, double y);
/* Reads a points file and stores the information in the points array */
vertex_t **readPoints(vertex_t **points, FILE *pointsFile, int *numPoints);
/* Frees an array of points */
void freePoints(vertex_t **points, int numPoints);
/* Returns the distance between two points */
double distPoints(vertex_t *pointA, vertex_t *pointB);
/* ------------------------ My points functions end ------------------------ */
/* -------------------- My intersection functions start -------------------- */
/* Create a new intersection */
intersection_t *newIntersection();
/* Fills in a single intersection structure */
intersection_t *getAnIntersection(intersection_t *intersection, DCEL_t *dcel, \
bisector_t *bisector, int face, int minLength);
/* Gets the intersection between the given bisector and the given DCEL
* for the given face.
*/
intersection_t **getIntersections(intersection_t **intersections, \
int *numIntersections, bisector_t **bisectors, int numBisectors, \
DCEL_t *dcel, int face, double minLength);
/* Frees an array of intersections */
void freeIntersections(intersection_t **intersections, int numIntersections);
/* --------------------- My intersection functions end --------------------- */
/* ---------------------- My bisector functions start ---------------------- */
/* Creates a new bisector */
bisector_t *newBisector();
/* Calculates and returns the equation of a bisector of two points */
bisector_t *getABisector(bisector_t *bisector, vertex_t *pointA, \
vertex_t *pointB);
/* Returns a list of bisectors built from a list of points */
bisector_t **getBisectors(bisector_t **bisectors, vertex_t **points, \
int numPoints);
/* Returns a point at least distance away from the midpoint of the
* bisector given. If direction is 0, then the point is +distance away in the
* x-direction, otherwise -distance away in the x-direction.
*/
vertex_t *getBisectorPoint(double distance, bisector_t *b, int direction);
/* Frees an array of bisectors */
void freeBisectors(bisector_t **bisectors, int numBisectors);
/* ----------------------- My bisector functions end ----------------------- */
/* ------------------------ My DCEL functions start ------------------------ */
/* Gets the diameter of the given face. */
double getDiameter(DCEL_t *dcel, int faceIndex);
/* ------------------------- My DCEL functions end ------------------------- */
/* ----------------------------------------------------------------------------
* Here on out are the functions from Grady's base code on Ed
* ----------------------------------------------------------------------------
*/
/* Allocate a new DCEL and return it. */
DCEL_t *newDCEL();
/* Allocate a new halfEdge and return it. */
halfEdge_t *newHalfEdge();
/* Check there's space for another vertex in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForVertex(DCEL_t *dcel);
/* Check there's space for another edge in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForEdge(DCEL_t *dcel);
/* Check there's space for another face in the DCEL, or increase the
* allocated space.
*/
void ensureSpaceForFace(DCEL_t *dcel);
/* Add an edge from the startVertex index vertex to the endVertex index.
* Only fills one half-edge as other half-edges will always be added
* through geometry construction.
*/
void addEdge(DCEL_t *dcel, int startVertex, int endVertex);
/* Add a face to the DCEL given using the given halfEdge and sets the face. */
void addFace(DCEL_t *dcel, halfEdge_t *he);
/* Reads the polygon from the given file. */
DCEL_t *readPolygonFile(char *polygonfileName);
/* Reads the next split from the given file. */
split_t *readNextSplit(FILE *splitfile);
/* Frees a given split. */
void freeSplit(split_t *split);
/* Returns 1 if vertices are sufficiently close, 0 otherwise. */
int vertexMatch(vertex_t *v1, vertex_t *v2);
/* Applies a given split to the DCEL. */
void applySplit(split_t *split, DCEL_t *dcel);
/* Frees the given DCEL */
void freeDCEL(DCEL_t *dcel);
/* Gets the number of faces in the DCEL. */
int getFaceCount(DCEL_t *dcel);
/* Returns INSIDE if the points is on the INSIDE of the vector twin by the CW
* winding order, OUTSIDE if it is OUTSIDE by the CW winding order, and
* DIR_UNDECIDED if the point lies on the vector between the points v1 and v2.
*/
int getRelativeDir(double x, double y, vertex_t *v1, vertex_t *v2);
/* Takes an established direction and a new direction, and returns 1 if the
* direction matches the decidedDirection or if the direction is undecided.
*/
int directionOrUndecided(int decidedDirection, int direction);
/* Returns 1 if the given x,y point is inside the given face. */
int inFace(DCEL_t *dcel, double x, double y, int faceIndex);
/* ------------------- O'Rourke's intersection functions ------------------- */
/* Returns -1, 0 or 1, based on the area enclosed by the three points.
* 0 corresponds to no area enclosed
*/
int areaSign(double sx, double sy, double ex, double ey, double x, double y);
/* Returns 1 if point (x, y) is between (sx, sy) and (ex, ey) */
int between(double sx, double sy, double ex, double ey, double x, double y);
/* Returns 1 if the point (x, y) is in the line from s(x, y) to e(x, y),
* 0 otherwise
*/
int collinear(double sx, double sy, double ex, double ey, double x, double y);
/* Tests if the half edge and bisector are parallel and overlapping, or not
* intersecting
*/
enum intersectType parallelIntersects(double heSx, double heSy, \
double heEx, double heEy, double bSx, double bSy, \
double bEx, double bEy, double *x, double *y);
/* Tests if a half edge and a bisector intersect */
enum intersectType intersects(halfEdge_t *he, bisector_t *b, \
DCEL_t *dcel, double minLength, double *x, double *y);
#endif

View file

@ -1,92 +1,92 @@
/* input.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 8th September 2021
* Last modified 14th September 2021
*
* Contains functions for ensuring correct input arguments are given for
* each stage of the voronoi2 program. Adapted from Grady's base code on Ed.
*
*/
#ifndef INPUT_HEADER
#include "input.h"
#endif
#define STAGE_1_ARG_COUNT 4
#define STAGE_2_ARG_COUNT 5
#define STAGE_3_ARG_COUNT 5
#define STAGE_4_ARG_COUNT 5
enum stages getStage(char *stage) {
if (strcmp(stage, "1") == 0){
return STAGE_1;
} else if (strcmp(stage, "2") == 0){
return STAGE_2;
} else if (strcmp(stage, "3") == 0){
return STAGE_3;
} else if (strcmp(stage, "4") == 0){
return STAGE_4;
} else {
return STAGE_ERROR;
}
}
void printArgError(enum stages stage, char *errorMessage) {
fprintf(stderr, "Error: %s\n\n", errorMessage);
/* Stage 1 - Print bisector equations */
if (stage == STAGE_ERROR || stage == STAGE_1) {
fputs("./voronoi2 1 pointsFile outputFile\n"
"\tTo output the bisectors for the given pointsFile to the \n"
"\tgiven outputFile.\n\n", stderr);
}
/* Stage 2 - Print intersections between bisectors and polygon */
if (stage == STAGE_ERROR || stage == STAGE_2) {
fputs("./voronoi2 2 pointsFile polygonFile outputFile\n"
"\tTo output the intersections the given bisectors make with \n"
"\tthe polygon to the given outputFile.\n\n", stderr);
}
/* Stage 3: Print diameter of each face, constructing using
* incremental method
*/
if (stage == STAGE_ERROR || stage == STAGE_3) {
fputs("./voronoi2 3 dataFile polygonFile outputFile\n"
"\tTo generate the initial polygon in polygonFile, layout the \n"
"\twatchtower points in the dataFile on the polygon, generate \n"
"\the voronoi diagram, adding or modifying the polydon so that \n"
"\ta voronoi diagram is constructed, seperating all points \n"
"\tinto their own cell with all tpoints in the cell being \n"
"\tclosest to the watchtower in the cell. The watchtower data \n"
"\tand its diameter is output to the outputFile.\n\n", stderr);
}
/* Stage 4 - Sort by diameter */
if (stage == STAGE_ERROR || stage == STAGE_4) {
fputs("./voronoi2 4 dataFile polygonFile outputFile\n"
"\tSame as stage 3, but output watchtowers are in order of \n"
"\tdiameter, smallest to largest.\n\n", stderr);
}
exit(EXIT_FAILURE);
}
int getExpectedArgs(enum stages stage) {
switch(stage){
case STAGE_1:
return STAGE_1_ARG_COUNT;
case STAGE_2:
return STAGE_2_ARG_COUNT;
case STAGE_3:
return STAGE_3_ARG_COUNT;
case STAGE_4:
return STAGE_4_ARG_COUNT;
case STAGE_ERROR:
default:
printArgError(stage, "Invalid stage number.");
exit(EXIT_FAILURE);
}
return -1;
}
/* input.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 8th September 2021
* Last modified 14th September 2021
*
* Contains functions for ensuring correct input arguments are given for
* each stage of the voronoi2 program. Adapted from Grady's base code on Ed.
*
*/
#ifndef INPUT_HEADER
#include "input.h"
#endif
#define STAGE_1_ARG_COUNT 4
#define STAGE_2_ARG_COUNT 5
#define STAGE_3_ARG_COUNT 5
#define STAGE_4_ARG_COUNT 5
enum stages getStage(char *stage) {
if (strcmp(stage, "1") == 0){
return STAGE_1;
} else if (strcmp(stage, "2") == 0){
return STAGE_2;
} else if (strcmp(stage, "3") == 0){
return STAGE_3;
} else if (strcmp(stage, "4") == 0){
return STAGE_4;
} else {
return STAGE_ERROR;
}
}
void printArgError(enum stages stage, char *errorMessage) {
fprintf(stderr, "Error: %s\n\n", errorMessage);
/* Stage 1 - Print bisector equations */
if (stage == STAGE_ERROR || stage == STAGE_1) {
fputs("./voronoi2 1 pointsFile outputFile\n"
"\tTo output the bisectors for the given pointsFile to the \n"
"\tgiven outputFile.\n\n", stderr);
}
/* Stage 2 - Print intersections between bisectors and polygon */
if (stage == STAGE_ERROR || stage == STAGE_2) {
fputs("./voronoi2 2 pointsFile polygonFile outputFile\n"
"\tTo output the intersections the given bisectors make with \n"
"\tthe polygon to the given outputFile.\n\n", stderr);
}
/* Stage 3: Print diameter of each face, constructing using
* incremental method
*/
if (stage == STAGE_ERROR || stage == STAGE_3) {
fputs("./voronoi2 3 dataFile polygonFile outputFile\n"
"\tTo generate the initial polygon in polygonFile, layout the \n"
"\twatchtower points in the dataFile on the polygon, generate \n"
"\the voronoi diagram, adding or modifying the polydon so that \n"
"\ta voronoi diagram is constructed, seperating all points \n"
"\tinto their own cell with all tpoints in the cell being \n"
"\tclosest to the watchtower in the cell. The watchtower data \n"
"\tand its diameter is output to the outputFile.\n\n", stderr);
}
/* Stage 4 - Sort by diameter */
if (stage == STAGE_ERROR || stage == STAGE_4) {
fputs("./voronoi2 4 dataFile polygonFile outputFile\n"
"\tSame as stage 3, but output watchtowers are in order of \n"
"\tdiameter, smallest to largest.\n\n", stderr);
}
exit(EXIT_FAILURE);
}
int getExpectedArgs(enum stages stage) {
switch(stage){
case STAGE_1:
return STAGE_1_ARG_COUNT;
case STAGE_2:
return STAGE_2_ARG_COUNT;
case STAGE_3:
return STAGE_3_ARG_COUNT;
case STAGE_4:
return STAGE_4_ARG_COUNT;
case STAGE_ERROR:
default:
printArgError(stage, "Invalid stage number.");
exit(EXIT_FAILURE);
}
return -1;
}

View file

@ -1,28 +1,28 @@
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef INPUT_HEADER
#define INPUT_HEADER
enum stages {
STAGE_1 = 1,
STAGE_2 = 2,
STAGE_3 = 3,
STAGE_4 = 4,
STAGE_ERROR = -1
};
/* Gets the current stage from the command-line argument */
enum stages getStage(char *stage);
/* Checks the validity of the command line input arguments */
void checkInputArgs(int argc, char **argv);
/* Gets the expected number of arguments for a given stage */
int getExpectedArgs(enum stages stage);
/* Prints the corresponding usage strings for a given stage */
void printArgError(enum stages stage, char *errorMessage);
#endif
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef INPUT_HEADER
#define INPUT_HEADER
enum stages {
STAGE_1 = 1,
STAGE_2 = 2,
STAGE_3 = 3,
STAGE_4 = 4,
STAGE_ERROR = -1
};
/* Gets the current stage from the command-line argument */
enum stages getStage(char *stage);
/* Checks the validity of the command line input arguments */
void checkInputArgs(int argc, char **argv);
/* Gets the expected number of arguments for a given stage */
int getExpectedArgs(enum stages stage);
/* Prints the corresponding usage strings for a given stage */
void printArgError(enum stages stage, char *errorMessage);
#endif

View file

@ -1,71 +1,71 @@
/* main.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 14th September 2021
*
* Stage 1: Computes and outputs equations for the bisectors of points
* Stage 2: Computes and outputs intersection points for bisectors against a
* given polygon
* Stage 3: Computes a Voronoi diagram using watchtowers as points and a
* polygon as the outer boundary. Outputs diameters of each Voronoi
* cell along with information about each watchtower.
* Stage 4: Same as Stage 4, but the watchtowers are sorted by ascending order
* by diameter.
*
* To see valid input arguments, run ./voronoi2
*
*/
#ifndef VORONOI_HEADER
#include "voronoi.h"
#endif
#ifndef INPUT_HEADER
#include "input.h"
#endif
int main(int argc, char **argv) {
/* Ensure input arguments are correct */
if (argc == 1) {
printArgError(STAGE_ERROR, "Incorrect usage.");
}
/* Get stage, ensure correct input args */
enum stages stage = getStage(argv[1]);
int expectedArgs = getExpectedArgs(stage);
if (expectedArgs != argc) {
printArgError(stage, "Incorrect number of inputs.");
}
/* Then run the program according to the stage given */
switch(stage) {
/* Expected usage: ./voronoi2 1 pointsFile outputFile */
case STAGE_1:
stage1(argv[2], argv[3]);
break;
/* Expected usage: ./voronoi2 2 pointsFile polygonFile outputFile */
case STAGE_2:
stage2(argv[2], argv[3], argv[4]);
break;
/* Expected usage: ./voronoi2 3 dataFile polygonFile outputFile */
case STAGE_3:
stage3(argv[2], argv[3], argv[4]);
break;
/* Expected usage: /voronoi2 4 dataFile polygonFile outputFile */
case STAGE_4:
stage4(argv[2], argv[3], argv[4]);
break;
/* Return error if stage number isn't defined. */
case STAGE_ERROR:
default:
printArgError(stage, "Invalid stage entered.");
exit(EXIT_FAILURE);
}
return 0;
}
/* main.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 25th August 2021
* Last modified 14th September 2021
*
* Stage 1: Computes and outputs equations for the bisectors of points
* Stage 2: Computes and outputs intersection points for bisectors against a
* given polygon
* Stage 3: Computes a Voronoi diagram using watchtowers as points and a
* polygon as the outer boundary. Outputs diameters of each Voronoi
* cell along with information about each watchtower.
* Stage 4: Same as Stage 4, but the watchtowers are sorted by ascending order
* by diameter.
*
* To see valid input arguments, run ./voronoi2
*
*/
#ifndef VORONOI_HEADER
#include "voronoi.h"
#endif
#ifndef INPUT_HEADER
#include "input.h"
#endif
int main(int argc, char **argv) {
/* Ensure input arguments are correct */
if (argc == 1) {
printArgError(STAGE_ERROR, "Incorrect usage.");
}
/* Get stage, ensure correct input args */
enum stages stage = getStage(argv[1]);
int expectedArgs = getExpectedArgs(stage);
if (expectedArgs != argc) {
printArgError(stage, "Incorrect number of inputs.");
}
/* Then run the program according to the stage given */
switch(stage) {
/* Expected usage: ./voronoi2 1 pointsFile outputFile */
case STAGE_1:
stage1(argv[2], argv[3]);
break;
/* Expected usage: ./voronoi2 2 pointsFile polygonFile outputFile */
case STAGE_2:
stage2(argv[2], argv[3], argv[4]);
break;
/* Expected usage: ./voronoi2 3 dataFile polygonFile outputFile */
case STAGE_3:
stage3(argv[2], argv[3], argv[4]);
break;
/* Expected usage: /voronoi2 4 dataFile polygonFile outputFile */
case STAGE_4:
stage4(argv[2], argv[3], argv[4]);
break;
/* Return error if stage number isn't defined. */
case STAGE_ERROR:
default:
printArgError(stage, "Invalid stage entered.");
exit(EXIT_FAILURE);
}
return 0;
}

View file

@ -1,115 +1,115 @@
/* voronoi.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 11th September 2021
* Last modified 14th September 2021
*
* Contains functions for reading a CSV of watchtower information into an
* array of towers.
*
*/
#ifndef TOWERS_HEADER
#include "towers.h"
#endif
#define BASE_10 10
#define MAX_CSV_ENTRY_LEN 512
#define MAX_FIELD_LEN 128
#define NUM_CSV_FIELDS 6
void readATower(char *lineBuffer, tower_t *tower) {
/* Stores the current CSV field for the current line */
char *token = strtok(lineBuffer, ",");
size_t tokenLength;
for (int i = 0; i < NUM_CSV_FIELDS; i++) {
tokenLength = strlen(token);
switch(i) {
/* Cases represent each field in the CSV, and as such are handled
* differently.
*/
case 0:
tower->id = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->id);
strcpy(tower->id, token);
tower->id[tokenLength] = '\0';
break;
case 1:
tower->postcode = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->postcode);
strcpy(tower->postcode, token);
tower->postcode[tokenLength] = '\0';
break;
case 2:
tower->population = strtol(token, NULL, BASE_10);
break;
case 3:
tower->manager = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->manager);
strcpy(tower->manager, token);
tower->manager[tokenLength] = '\0';
break;
case 4:
tower->x = strtod(token, NULL);
break;
case 5:
tower->y = strtod(token, NULL);
break;
}
token = strtok(NULL, ",");
}
}
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
/* Maximum length of a single CSV line (+1 for null char in string) */
size_t lineBufferSize = MAX_CSV_ENTRY_LEN + 1;
/* Stores the current line from the CSV */
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
checkNullPointer(lineBuffer);
int maxSizetowers = 1;
/* Discard the header line, then read the rest of the CSV */
getline(&lineBuffer, &lineBufferSize, datasetFile);
while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) {
/* Ensure there is enough space in the towers array */
if (*numTowers == maxSizetowers) {
maxSizetowers *= 2;
tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers));
checkNullPointer(temp);
towers = temp;
}
/* The current tower being filled in with information */
towers[*numTowers] = malloc(sizeof(*towers[*numTowers]));
readATower(lineBuffer, towers[*numTowers]);
*numTowers += 1;
}
free(lineBuffer);
return towers;
}
void freeTowers(tower_t **towers, int numTowers) {
if (!towers) {
return;
}
for (int i = 0; i < numTowers; i++) {
if (towers[i]->id) {
free(towers[i]->id);
}
if (towers[i]->manager) {
free(towers[i]->manager);
}
if (towers[i]->postcode) {
free(towers[i]->postcode);
}
if (towers[i]) {
free(towers[i]);
}
}
free(towers);
}
/* voronoi.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 11th September 2021
* Last modified 14th September 2021
*
* Contains functions for reading a CSV of watchtower information into an
* array of towers.
*
*/
#ifndef TOWERS_HEADER
#include "towers.h"
#endif
#define BASE_10 10
#define MAX_CSV_ENTRY_LEN 512
#define MAX_FIELD_LEN 128
#define NUM_CSV_FIELDS 6
void readATower(char *lineBuffer, tower_t *tower) {
/* Stores the current CSV field for the current line */
char *token = strtok(lineBuffer, ",");
size_t tokenLength;
for (int i = 0; i < NUM_CSV_FIELDS; i++) {
tokenLength = strlen(token);
switch(i) {
/* Cases represent each field in the CSV, and as such are handled
* differently.
*/
case 0:
tower->id = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->id);
strcpy(tower->id, token);
tower->id[tokenLength] = '\0';
break;
case 1:
tower->postcode = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->postcode);
strcpy(tower->postcode, token);
tower->postcode[tokenLength] = '\0';
break;
case 2:
tower->population = strtol(token, NULL, BASE_10);
break;
case 3:
tower->manager = malloc(sizeof(char) * tokenLength + 1);
checkNullPointer(tower->manager);
strcpy(tower->manager, token);
tower->manager[tokenLength] = '\0';
break;
case 4:
tower->x = strtod(token, NULL);
break;
case 5:
tower->y = strtod(token, NULL);
break;
}
token = strtok(NULL, ",");
}
}
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers) {
/* Maximum length of a single CSV line (+1 for null char in string) */
size_t lineBufferSize = MAX_CSV_ENTRY_LEN + 1;
/* Stores the current line from the CSV */
char *lineBuffer = malloc(lineBufferSize * sizeof(*lineBuffer));
checkNullPointer(lineBuffer);
int maxSizetowers = 1;
/* Discard the header line, then read the rest of the CSV */
getline(&lineBuffer, &lineBufferSize, datasetFile);
while (getline(&lineBuffer, &lineBufferSize, datasetFile) > 0) {
/* Ensure there is enough space in the towers array */
if (*numTowers == maxSizetowers) {
maxSizetowers *= 2;
tower_t **temp = realloc(towers, maxSizetowers * sizeof(*towers));
checkNullPointer(temp);
towers = temp;
}
/* The current tower being filled in with information */
towers[*numTowers] = malloc(sizeof(*towers[*numTowers]));
readATower(lineBuffer, towers[*numTowers]);
*numTowers += 1;
}
free(lineBuffer);
return towers;
}
void freeTowers(tower_t **towers, int numTowers) {
if (!towers) {
return;
}
for (int i = 0; i < numTowers; i++) {
if (towers[i]->id) {
free(towers[i]->id);
}
if (towers[i]->manager) {
free(towers[i]->manager);
}
if (towers[i]->postcode) {
free(towers[i]->postcode);
}
if (towers[i]) {
free(towers[i]);
}
}
free(towers);
}

View file

@ -1,26 +1,26 @@
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef TOWERS_HEADER
#define TOWERS_HEADER
typedef struct tower {
char *id;
char *postcode;
char *manager;
int population;
double x;
double y;
} tower_t;
/* Reads the current row from the CSV and converts it into a new tower */
void readATower(char *lineBuffer, tower_t *tower);
/* Reads the CSV file and stores the information in the towers array */
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers);
/* Frees all towers in a towers array */
void freeTowers(tower_t **towers, int numTowers);
#endif
#ifndef COMMON_HEADER
#include "common.h"
#endif
#ifndef TOWERS_HEADER
#define TOWERS_HEADER
typedef struct tower {
char *id;
char *postcode;
char *manager;
int population;
double x;
double y;
} tower_t;
/* Reads the current row from the CSV and converts it into a new tower */
void readATower(char *lineBuffer, tower_t *tower);
/* Reads the CSV file and stores the information in the towers array */
tower_t **readTowers(tower_t **towers, FILE *datasetFile, int *numTowers);
/* Frees all towers in a towers array */
void freeTowers(tower_t **towers, int numTowers);
#endif

View file

@ -1,208 +1,208 @@
/* voronoi.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 12th August 2021
* Last modified 14th September 2021
*
* Contains functions involving the generation of the Voronoi diagram, and
* running each stage of the assignment.
*
*/
#ifndef VORONOI_HEADER
#include "voronoi.h"
#endif
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) {
if (bisector->isSlopeInfinite) {
/* Cannot print infinite slope, so print only x-intercept */
fprintf(outputFile, "x = %lf\n", bisector->mid->x);
} else {
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
bisector->slope, bisector->mid->x, bisector->mid->y);
}
}
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
fprintf(outputFile, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)\n", \
intersection->fromEdge, intersection->fromPoint->x, \
intersection->fromPoint->y, intersection->toEdge, \
intersection->toPoint->x, intersection->toPoint->y);
}
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter) {
fprintf(outputFile, "Watchtower ID: %s, Postcode: %s, Population " \
"Served: %d, Watchtower Point of Contact Name: %s, x: %lf, y: %lf, " \
"Diameter of Cell: %lf\n", tower->id, tower->postcode, \
tower->population, tower->manager, tower->x, tower->y, diameter);
}
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower) {
for (int i = 0; i < getFaceCount(dcel); i++) {
if (inFace(dcel, tower->x, tower->y, i)) {
return i;
}
}
return -1;
}
void incrementalVoronoi(DCEL_t *voronoi, tower_t *tower) {
int faceTowerIsIn = getFaceTowerIsIn(voronoi, tower);
if (faceTowerIsIn == -1) {
fprintf(stderr, "Error: Watchtower %s is outside the polygon.\n", \
tower->id);
exit(EXIT_FAILURE);
}
}
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB) {
/* Get vertices from towers */
vertex_t *pointA = getAPoint(towerA->x, towerA->y);
vertex_t *pointB = getAPoint(towerB->x, towerB->y);
/* Create first bisector */
bisector_t *bisector = newBisector();
bisector = getABisector(bisector, pointA, pointB);
/* Get intersection of bisector with the polygon */
intersection_t *intersection = NULL;
intersection = getAnIntersection(intersection, voronoi, bisector, \
DEFAULT_FACE, DEFAULTMINLENGTH);
if (intersection) {
free(intersection->fromPoint);
free(intersection->toPoint);
free(intersection);
}
free(bisector->mid);
free(bisector);
free(pointA);
free(pointB);
return voronoi;
}
void stage1(char *pointsFileName, char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Points are given as pairs, so initialise 2 points */
vertex_t **points = malloc(sizeof(*points) * 2);
checkNullPointer(points);
int numPoints = 0;
points = readPoints(points, pointsFile, &numPoints);
/* There are half as many bisectors as points */
int numBisectors = numPoints / 2;
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
checkNullPointer(bisectors);
bisectors = getBisectors(bisectors, points, numBisectors);
/* For each pair, calculate and print the bisector to outputFile */
for (int i = 0; i < numBisectors; i++) {
stage1PrintBisector(bisectors[i], outputFile);
}
/* Clean up */
freePoints(points, numPoints);
freeBisectors(bisectors, numBisectors);
fclose(pointsFile);
fclose(outputFile);
}
void stage2(char *pointsFileName, char *polygonFileName, \
char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Points are given as pairs, so initialise 2 points */
vertex_t **points = malloc(sizeof(*points) * 2);
checkNullPointer(points);
int numPoints = 0;
points = readPoints(points, pointsFile, &numPoints);
/* There are half as many bisectors as points */
int numBisectors = numPoints / 2;
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
checkNullPointer(bisectors);
bisectors = getBisectors(bisectors, points, numBisectors);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Calculate and print intersections to the output file */
intersection_t **intersections = malloc(sizeof(*intersections));
checkNullPointer(intersections);
int numIntersections = 0;
intersections = getIntersections(intersections, &numIntersections, \
bisectors, numBisectors, dcel, DEFAULT_FACE, DEFAULTMINLENGTH);
for (int i = 0; i < numIntersections; i++) {
stage2PrintIntersection(intersections[i], outputFile);
}
/* Clean up */
freePoints(points, numPoints);
freeBisectors(bisectors, numBisectors);
freeIntersections(intersections, numIntersections);
freeDCEL(dcel);
fclose(pointsFile);
fclose(outputFile);
}
void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}
void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and sort, then output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}
/* voronoi.c
*
* Created by Rory Healy (healyr@student.unimelb.edu.au)
* Created on 12th August 2021
* Last modified 14th September 2021
*
* Contains functions involving the generation of the Voronoi diagram, and
* running each stage of the assignment.
*
*/
#ifndef VORONOI_HEADER
#include "voronoi.h"
#endif
void stage1PrintBisector(bisector_t *bisector, FILE *outputFile) {
if (bisector->isSlopeInfinite) {
/* Cannot print infinite slope, so print only x-intercept */
fprintf(outputFile, "x = %lf\n", bisector->mid->x);
} else {
fprintf(outputFile, "y = %lf * (x - %lf) + %lf\n", \
bisector->slope, bisector->mid->x, bisector->mid->y);
}
}
void stage2PrintIntersection(intersection_t *intersection, FILE *outputFile) {
fprintf(outputFile, "From Edge %d (%lf, %lf) to Edge %d (%lf, %lf)\n", \
intersection->fromEdge, intersection->fromPoint->x, \
intersection->fromPoint->y, intersection->toEdge, \
intersection->toPoint->x, intersection->toPoint->y);
}
void stage34PrintTowers(tower_t *tower, FILE *outputFile, double diameter) {
fprintf(outputFile, "Watchtower ID: %s, Postcode: %s, Population " \
"Served: %d, Watchtower Point of Contact Name: %s, x: %lf, y: %lf, " \
"Diameter of Cell: %lf\n", tower->id, tower->postcode, \
tower->population, tower->manager, tower->x, tower->y, diameter);
}
int getFaceTowerIsIn(DCEL_t *dcel, tower_t *tower) {
for (int i = 0; i < getFaceCount(dcel); i++) {
if (inFace(dcel, tower->x, tower->y, i)) {
return i;
}
}
return -1;
}
void incrementalVoronoi(DCEL_t *voronoi, tower_t *tower) {
int faceTowerIsIn = getFaceTowerIsIn(voronoi, tower);
if (faceTowerIsIn == -1) {
fprintf(stderr, "Error: Watchtower %s is outside the polygon.\n", \
tower->id);
exit(EXIT_FAILURE);
}
}
DCEL_t *newVoronoi(DCEL_t *voronoi, tower_t *towerA, tower_t *towerB) {
/* Get vertices from towers */
vertex_t *pointA = getAPoint(towerA->x, towerA->y);
vertex_t *pointB = getAPoint(towerB->x, towerB->y);
/* Create first bisector */
bisector_t *bisector = newBisector();
bisector = getABisector(bisector, pointA, pointB);
/* Get intersection of bisector with the polygon */
intersection_t *intersection = NULL;
intersection = getAnIntersection(intersection, voronoi, bisector, \
DEFAULT_FACE, DEFAULTMINLENGTH);
if (intersection) {
free(intersection->fromPoint);
free(intersection->toPoint);
free(intersection);
}
free(bisector->mid);
free(bisector);
free(pointA);
free(pointB);
return voronoi;
}
void stage1(char *pointsFileName, char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Points are given as pairs, so initialise 2 points */
vertex_t **points = malloc(sizeof(*points) * 2);
checkNullPointer(points);
int numPoints = 0;
points = readPoints(points, pointsFile, &numPoints);
/* There are half as many bisectors as points */
int numBisectors = numPoints / 2;
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
checkNullPointer(bisectors);
bisectors = getBisectors(bisectors, points, numBisectors);
/* For each pair, calculate and print the bisector to outputFile */
for (int i = 0; i < numBisectors; i++) {
stage1PrintBisector(bisectors[i], outputFile);
}
/* Clean up */
freePoints(points, numPoints);
freeBisectors(bisectors, numBisectors);
fclose(pointsFile);
fclose(outputFile);
}
void stage2(char *pointsFileName, char *polygonFileName, \
char *outputFileName) {
FILE *pointsFile = NULL, *outputFile = NULL;
pointsFile = safeFileOpen(&pointsFile, pointsFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Points are given as pairs, so initialise 2 points */
vertex_t **points = malloc(sizeof(*points) * 2);
checkNullPointer(points);
int numPoints = 0;
points = readPoints(points, pointsFile, &numPoints);
/* There are half as many bisectors as points */
int numBisectors = numPoints / 2;
bisector_t **bisectors = malloc(sizeof(*bisectors) * numBisectors);
checkNullPointer(bisectors);
bisectors = getBisectors(bisectors, points, numBisectors);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Calculate and print intersections to the output file */
intersection_t **intersections = malloc(sizeof(*intersections));
checkNullPointer(intersections);
int numIntersections = 0;
intersections = getIntersections(intersections, &numIntersections, \
bisectors, numBisectors, dcel, DEFAULT_FACE, DEFAULTMINLENGTH);
for (int i = 0; i < numIntersections; i++) {
stage2PrintIntersection(intersections[i], outputFile);
}
/* Clean up */
freePoints(points, numPoints);
freeBisectors(bisectors, numBisectors);
freeIntersections(intersections, numIntersections);
freeDCEL(dcel);
fclose(pointsFile);
fclose(outputFile);
}
void stage3(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}
void stage4(char *dataFileName, char *polygonFileName, char *outputFileName) {
FILE *dataFile = NULL, *polygonFile = NULL, *outputFile = NULL;
dataFile = safeFileOpen(&dataFile, dataFileName, "r");
polygonFile = safeFileOpen(&polygonFile, polygonFileName, "r");
outputFile = safeFileOpen(&outputFile, outputFileName, "w");
/* Read towers from the data file */
tower_t **towers = malloc(sizeof(*towers));
checkNullPointer(towers);
int numTowers = 0;
towers = readTowers(towers, dataFile, &numTowers);
/* Construct the DCEL from the polygon file */
DCEL_t *dcel = readPolygonFile(polygonFileName);
/* Add each tower to the Voronoi DCEL */
/* Get diameters and sort, then output to outputFile */
/* Clean up */
freeDCEL(dcel);
freeTowers(towers, numTowers);
fclose(dataFile);
fclose(polygonFile);
fclose(outputFile);
}

View file

@ -1,12 +1,12 @@
1.0 1.0 2.0 1.0
1.0 1.0 3.0 1.0
1.0 1.0 4.0 1.0
1.0 1.0 5.0 1.0
0.0 1.0 1.0 1.0
0.0 1.0 2.0 1.0
0.0 1.0 3.0 1.0
0.0 1.0 4.0 1.0
0.0 2.0 4.0 2.0
0.0 3.0 4.0 3.0
0.0 4.0 4.0 4.0
1.0 1.0 2.0 1.0
1.0 1.0 3.0 1.0
1.0 1.0 4.0 1.0
1.0 1.0 5.0 1.0
0.0 1.0 1.0 1.0
0.0 1.0 2.0 1.0
0.0 1.0 3.0 1.0
0.0 1.0 4.0 1.0
0.0 2.0 4.0 2.0
0.0 3.0 4.0 3.0
0.0 4.0 4.0 4.0
0.0 0.0 4.0 0.0

View file

@ -1,6 +1,6 @@
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
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

View file

@ -1,6 +1,6 @@
0.0 0.0 0.0 1.0
0.0 0.0 0.0 2.0
0.0 1.0 0.0 2.0
1.0 1.0 1.0 2.0
2.0 1.0 2.0 2.0
0.0 0.0 0.0 1.0
0.0 0.0 0.0 2.0
0.0 1.0 0.0 2.0
1.0 1.0 1.0 2.0
2.0 1.0 2.0 2.0
3.0 1.0 3.0 2.0

View file

@ -1,8 +1,8 @@
142.993000 -33.122900
147.597600 -33.221400
150.054600 -36.590100
150.400400 -39.229900
147.779600 -40.333100
144.412600 -40.195200
140.736200 -39.289000
142.993000 -33.122900
147.597600 -33.221400
150.054600 -36.590100
150.400400 -39.229900
147.779600 -40.333100
144.412600 -40.195200
140.736200 -39.289000
140.335800 -37.476600

View file

@ -1,4 +1,4 @@
140.9 -39.2
140.9 -33.9
150.0 -33.9
140.9 -39.2
140.9 -33.9
150.0 -33.9
150.0 -39.2

View file

@ -1,11 +1,11 @@
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
1 Watchtower ID Postcode Population Served Watchtower Point of Contact Name x y
2 WT3106HTUYW 3106 2374 David Bryan 145.14493956217032 -37.74550312585378
3 WT3151ANFQX 3151 3424 Daniel Davis 145.16632131582105 -37.84908719684687
4 WT3953SGAEI 3953 1571 Ofelia Kadlec 145.77800174296402 -38.55984015166651
5 WT3765SHSPB 3765 3380 Eilene Horner 145.36201379669092 -37.81894302945288
6 WT3227LRSVA 3227 4819 Joan Cox 144.38837299987338 -38.22664848840161
7 WT3370XRAHI 3370 356 Tammy Compton 143.76050524940354 -37.17889378247109
8 WT3525YPKBW 3525 433 Denise Roberts 143.32090727836928 -36.14524876420747
9 WT3701KWYIQ 3701 269 Martha Moore 147.39302957919313 -36.254894160169314
10 WT3779NULEK 3779 197 Aida Kuhnle 146.11080887018696 -37.67951918079387
11 WT3530RJWDT 3530 63 Troy Clark 143.0834668479817 -35.79299394885817

View file

@ -1,101 +1,101 @@
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
WT3023QBQJF,3023,12794,Sandra Jaynes,144.7116868675065,-37.79835253004884
WT3037YAKEI,3037,25577,Paul Watson,144.7404381965215,-37.71057606210163
WT3810RRMDP,3810,47894,Shirl Bays,145.54377380709113,-38.11642115246884
WT3550ANADF,3550,10084,Virginia Lumpkins,144.25225555806287,-36.7583657822827
WT3754SXJZI,3754,6292,Henriette Mitchell,145.1619799395555,-37.61057382984485
WT3754WSOKP,3754,6292,James Lopez,145.11378037030943,-37.60927638542337
WT3046ADKBS,3046,8515,Morris Pring,144.94317380188164,-37.71659755462475
WT3178BQAJG,3178,5612,Malka Smith,145.26959423333145,-37.918875236595035
WT3130PLSQY,3130,8043,Jose Hayes,145.13764760079675,-37.828083908584475
WT3032PWVMB,3032,7362,William Mackiewicz,144.87559681642185,-37.79083145310446
WT3173JKIEY,3173,5157,Teddy Mccauley,145.18948448769126,-37.992844271467284
WT3122GVRSM,3122,11755,William Bell,145.0366394627393,-37.810997917513916
WT3171BGAEJ,3171,7238,Lila Levy,145.1337946019459,-37.92898751855743
WT3128AQDRS,3128,6609,Sarah Kauffman,145.1295813912443,-37.82078823368618
WT3219MZCMM,3219,4928,Charlie Gerber,144.37942394090373,-38.19362930153523
WT3170XJVWP,3170,9684,Lucy Lahay,145.17553159514887,-37.936150181976984
WT3031DMFGC,3031,6177,Caroline Luckenbach,144.90707048527796,-37.78767901585732
WT3015PKLER,3015,8736,Bill Kilbane,144.8979183219914,-37.82580808335247
WT3106WQFPR,3106,2374,Mary Bass,145.14274097499288,-37.731835101044354
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
WT3352KHBBN,3352,15996,Richard Askew,143.60419898610786,-37.722432808576656
WT3079QORWG,3079,5329,Jerry Somogyi,145.05361972090736,-37.76092644646485
WT3850WPPZJ,3850,14779,Scott Buggie,146.99670975934802,-38.11120375121315
WT3400BOZRI,3400,14543,Tom Davis,142.2056868163526,-36.700923449995635
WT3123YZTIF,3123,7160,Paul Earwood,145.05955004240124,-37.82771644759941
WT3224OGJJN,3224,1773,Shirley Hall,144.42849521054393,-38.218027859101916
WT3137PJCVG,3137,1541,Yolanda Stern,145.32887887734955,-37.830025027117365
WT3305NMFYC,3305,3204,Larry Witter,141.29643421841453,-38.11167114301085
WT3305KWOFD,3305,3204,Judith Figueroa,141.25644777166127,-38.24079323443777
WT3025UXSIE,3025,2430,Willie Laigo,144.79429337101448,-37.82881778367748
WT3437KHBPL,3437,3479,Charlotte Green,144.59696365066134,-37.48113208398435
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
WT3019ASCJP,3019,3065,Charlotte Coutermarsh,144.85492421197495,-37.772589492919515
WT3019JIKGX,3019,3065,Vincent January,144.85730316799982,-37.7718018219131
WT3764MKCUE,3764,4582,Alejandrina Salazar,144.970506104261,-37.15854276662507
WT3730UTUPX,3730,2944,Curtis Johnson,145.8390200963087,-36.01276678240247
WT3054SQEQA,3054,8428,Eugene Salano,144.95861592679725,-37.783412869711185
WT3620DPAMB,3620,4120,Ben Oneil,144.96824098896346,-36.398921729744224
WT3804OQOOF,3804,2023,Jackie Smith,145.35298253700518,-37.98426462189473
WT3909HFRJQ,3909,2633,Maria Rhodus,147.90601975805444,-37.764598529015366
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
WT3953NPQQN,3953,1571,Peter Willer,146.04193592469497,-38.44633595871089
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
WT3027FZKQC,3027,3323,Angelo Hard,144.73167189283603,-37.85646049026309
WT3996ZMYGL,3996,1846,Jennifer Adkins,145.7771574897382,-38.67107249698782
WT3984UBSFJ,3984,1041,Ned Johnson,145.61381415852048,-38.3660140349184
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
WT3950WWFHI,3950,2400,Donald Neil,145.789697571232,-38.44829776894874
WT3842LLUAZ,3842,2391,Justin Butcher,146.43738290720543,-38.33409319136186
WT3225ZWRKT,3225,1352,Sierra Zelaya,144.63248453729392,-38.273920927385454
WT3797JXEYZ,3797,1738,Wade Seay,145.59525777895735,-37.85187937890587
WT3980CXZJX,3980,1675,Marianne Gulledge,145.38407991603268,-38.234540388656654
WT3862WPONG,3862,1578,Anthony Dawkins,147.33271058732282,-37.491238739170896
WT3202IDOPR,3202,1453,Shannon Bello,145.07561474247163,-37.947828524869706
WT3304LTOER,3304,681,James Broadway,141.91304296053238,-38.08286392590754
WT3478NOSNX,3478,614,Mary Wooster,143.190083774406,-36.70864776402552
WT3373ZJBZG,3373,573,Helen Hu,143.40004730403342,-37.327257624451846
WT3373FDEUM,3373,573,Phyllis Hegyi,143.19424925274458,-37.38771716562931
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
WT3673HXZDV,3673,346,June Matteson,145.99560167654946,-36.51826050506983
WT3943FFEHH,3943,398,Floyd Mcfaul,144.7219219690698,-38.32665967904324
WT3937YBAGH,3937,762,Tyesha Evans,145.0385876851752,-38.37262744294901
WT3786QKGRU,3786,506,Joe Pulaski,145.33261178176102,-37.876147897332174
WT3321FSNXX,3321,759,James Mcintosh,144.00220559674338,-38.10453080180178
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
WT3231VKTTU,3231,418,Karl Evans,143.99174248566703,-38.47241568127852
WT3231YSKOO,3231,418,Leontine Mcghee,144.07128861030645,-38.416049306559025
WT3766LYICC,3766,619,Gary Evans,145.3953639008541,-37.81880414343826
WT3381FUDIA,3381,151,Penny Carrier,142.7602629758581,-37.02897861269415
WT3232GSLYH,3232,1114,Joshua Sickafoose,143.96111969797116,-38.544885004427805
WT3933UXXXP,3933,549,Shaun Guffey,145.11706009902144,-38.26228415412558
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
WT3701TPSEH,3701,269,Grant Kennedy,147.41241338695838,-36.74234154193107
WT3312BCEJQ,3312,1031,Alexandra Ratzlaff,141.38649875710092,-37.85213620536482
WT3332VSYVL,3332,338,Charles Koons,144.08742265383532,-37.906318691909874
WT3623CXKIC,3623,224,Rebecca Lara,144.90863570166192,-36.44103547317975
WT3289ZSWDS,3289,378,Kim Hall,142.1760506248015,-37.83343114690931
WT3728YZARW,3728,318,Heather Cummings,145.8168813215635,-36.115027477064245
WT3633WGRXB,3633,201,John Miller,145.48023893751045,-36.2875408553956
WT3633UVHAO,3633,201,Michael Price,145.51505172180683,-36.31027112244356
WT3637KIERO,3637,198,Robert Dow,145.25553090556156,-36.0980796504903
WT3063WZIQE,3063,114,James Miller,144.81061694155076,-37.553501843305575
WT3334GGKOS,3334,141,Elizabet Benson,144.1621690362788,-37.67891238372265
WT3251FUJSG,3251,522,Lisa Voegele,143.5797389397756,-38.1623931117428
WT3649NJHAF,3649,86,Catherine Ortiz,145.70444412227315,-36.12591041370753
WT3287NEKVB,3287,216,Joel Simmons,142.26305043381535,-37.983480961999916
WT3407PYOAR,3407,420,Gale Martin,141.83324586447986,-37.2859635851256
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
WT3719TVVJM,3719,122,Brent Bautista,145.6864773045679,-37.03188286944955
WT3719HLABD,3719,122,Alfred Too,145.52985920519603,-36.964844896202216
WT3573DPVGU,3573,111,Wiley Palmer,144.15009214850954,-36.12318035418112
WT3254RXAVL,3254,310,Amy Pugh,143.54387071993327,-38.308515316326016
WT3832NHOOV,3832,247,Bryan Warren,146.0154412945935,-37.93424551655733
WT3238BOTYW,3238,72,Bernard Jackson,143.567776369521,-38.625836774939955
WT3238MCUPV,3238,72,Nellie Banks,143.56196753560545,-38.82942446565583
WT3375LAJLR,3375,104,Emma Boatwright,143.2980117885972,-37.372200644973155
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
WT3596HBEUF,3596,47,Jose Robertson,143.15095468769667,-35.190473662123345
WT3293SQKBY,3293,100,Shawn Clark,142.64808203542347,-37.82556647618436
WT3887NLNSJ,3887,342,Lorene Anderson,147.96080438424718,-37.76269836557282
Watchtower ID,Postcode,Population Served,Watchtower Point of Contact Name,x,y
WT3023QBQJF,3023,12794,Sandra Jaynes,144.7116868675065,-37.79835253004884
WT3037YAKEI,3037,25577,Paul Watson,144.7404381965215,-37.71057606210163
WT3810RRMDP,3810,47894,Shirl Bays,145.54377380709113,-38.11642115246884
WT3550ANADF,3550,10084,Virginia Lumpkins,144.25225555806287,-36.7583657822827
WT3754SXJZI,3754,6292,Henriette Mitchell,145.1619799395555,-37.61057382984485
WT3754WSOKP,3754,6292,James Lopez,145.11378037030943,-37.60927638542337
WT3046ADKBS,3046,8515,Morris Pring,144.94317380188164,-37.71659755462475
WT3178BQAJG,3178,5612,Malka Smith,145.26959423333145,-37.918875236595035
WT3130PLSQY,3130,8043,Jose Hayes,145.13764760079675,-37.828083908584475
WT3032PWVMB,3032,7362,William Mackiewicz,144.87559681642185,-37.79083145310446
WT3173JKIEY,3173,5157,Teddy Mccauley,145.18948448769126,-37.992844271467284
WT3122GVRSM,3122,11755,William Bell,145.0366394627393,-37.810997917513916
WT3171BGAEJ,3171,7238,Lila Levy,145.1337946019459,-37.92898751855743
WT3128AQDRS,3128,6609,Sarah Kauffman,145.1295813912443,-37.82078823368618
WT3219MZCMM,3219,4928,Charlie Gerber,144.37942394090373,-38.19362930153523
WT3170XJVWP,3170,9684,Lucy Lahay,145.17553159514887,-37.936150181976984
WT3031DMFGC,3031,6177,Caroline Luckenbach,144.90707048527796,-37.78767901585732
WT3015PKLER,3015,8736,Bill Kilbane,144.8979183219914,-37.82580808335247
WT3106WQFPR,3106,2374,Mary Bass,145.14274097499288,-37.731835101044354
WT3106HTUYW,3106,2374,David Bryan,145.14493956217032,-37.74550312585378
WT3352KHBBN,3352,15996,Richard Askew,143.60419898610786,-37.722432808576656
WT3079QORWG,3079,5329,Jerry Somogyi,145.05361972090736,-37.76092644646485
WT3850WPPZJ,3850,14779,Scott Buggie,146.99670975934802,-38.11120375121315
WT3400BOZRI,3400,14543,Tom Davis,142.2056868163526,-36.700923449995635
WT3123YZTIF,3123,7160,Paul Earwood,145.05955004240124,-37.82771644759941
WT3224OGJJN,3224,1773,Shirley Hall,144.42849521054393,-38.218027859101916
WT3137PJCVG,3137,1541,Yolanda Stern,145.32887887734955,-37.830025027117365
WT3305NMFYC,3305,3204,Larry Witter,141.29643421841453,-38.11167114301085
WT3305KWOFD,3305,3204,Judith Figueroa,141.25644777166127,-38.24079323443777
WT3025UXSIE,3025,2430,Willie Laigo,144.79429337101448,-37.82881778367748
WT3437KHBPL,3437,3479,Charlotte Green,144.59696365066134,-37.48113208398435
WT3151ANFQX,3151,3424,Daniel Davis,145.16632131582105,-37.84908719684687
WT3019ASCJP,3019,3065,Charlotte Coutermarsh,144.85492421197495,-37.772589492919515
WT3019JIKGX,3019,3065,Vincent January,144.85730316799982,-37.7718018219131
WT3764MKCUE,3764,4582,Alejandrina Salazar,144.970506104261,-37.15854276662507
WT3730UTUPX,3730,2944,Curtis Johnson,145.8390200963087,-36.01276678240247
WT3054SQEQA,3054,8428,Eugene Salano,144.95861592679725,-37.783412869711185
WT3620DPAMB,3620,4120,Ben Oneil,144.96824098896346,-36.398921729744224
WT3804OQOOF,3804,2023,Jackie Smith,145.35298253700518,-37.98426462189473
WT3909HFRJQ,3909,2633,Maria Rhodus,147.90601975805444,-37.764598529015366
WT3953SGAEI,3953,1571,Ofelia Kadlec,145.77800174296402,-38.55984015166651
WT3953NPQQN,3953,1571,Peter Willer,146.04193592469497,-38.44633595871089
WT3765SHSPB,3765,3380,Eilene Horner,145.36201379669092,-37.81894302945288
WT3027FZKQC,3027,3323,Angelo Hard,144.73167189283603,-37.85646049026309
WT3996ZMYGL,3996,1846,Jennifer Adkins,145.7771574897382,-38.67107249698782
WT3984UBSFJ,3984,1041,Ned Johnson,145.61381415852048,-38.3660140349184
WT3227LRSVA,3227,4819,Joan Cox,144.38837299987338,-38.22664848840161
WT3950WWFHI,3950,2400,Donald Neil,145.789697571232,-38.44829776894874
WT3842LLUAZ,3842,2391,Justin Butcher,146.43738290720543,-38.33409319136186
WT3225ZWRKT,3225,1352,Sierra Zelaya,144.63248453729392,-38.273920927385454
WT3797JXEYZ,3797,1738,Wade Seay,145.59525777895735,-37.85187937890587
WT3980CXZJX,3980,1675,Marianne Gulledge,145.38407991603268,-38.234540388656654
WT3862WPONG,3862,1578,Anthony Dawkins,147.33271058732282,-37.491238739170896
WT3202IDOPR,3202,1453,Shannon Bello,145.07561474247163,-37.947828524869706
WT3304LTOER,3304,681,James Broadway,141.91304296053238,-38.08286392590754
WT3478NOSNX,3478,614,Mary Wooster,143.190083774406,-36.70864776402552
WT3373ZJBZG,3373,573,Helen Hu,143.40004730403342,-37.327257624451846
WT3373FDEUM,3373,573,Phyllis Hegyi,143.19424925274458,-37.38771716562931
WT3370XRAHI,3370,356,Tammy Compton,143.76050524940354,-37.17889378247109
WT3673HXZDV,3673,346,June Matteson,145.99560167654946,-36.51826050506983
WT3943FFEHH,3943,398,Floyd Mcfaul,144.7219219690698,-38.32665967904324
WT3937YBAGH,3937,762,Tyesha Evans,145.0385876851752,-38.37262744294901
WT3786QKGRU,3786,506,Joe Pulaski,145.33261178176102,-37.876147897332174
WT3321FSNXX,3321,759,James Mcintosh,144.00220559674338,-38.10453080180178
WT3525YPKBW,3525,433,Denise Roberts,143.32090727836928,-36.14524876420747
WT3231VKTTU,3231,418,Karl Evans,143.99174248566703,-38.47241568127852
WT3231YSKOO,3231,418,Leontine Mcghee,144.07128861030645,-38.416049306559025
WT3766LYICC,3766,619,Gary Evans,145.3953639008541,-37.81880414343826
WT3381FUDIA,3381,151,Penny Carrier,142.7602629758581,-37.02897861269415
WT3232GSLYH,3232,1114,Joshua Sickafoose,143.96111969797116,-38.544885004427805
WT3933UXXXP,3933,549,Shaun Guffey,145.11706009902144,-38.26228415412558
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
WT3701TPSEH,3701,269,Grant Kennedy,147.41241338695838,-36.74234154193107
WT3312BCEJQ,3312,1031,Alexandra Ratzlaff,141.38649875710092,-37.85213620536482
WT3332VSYVL,3332,338,Charles Koons,144.08742265383532,-37.906318691909874
WT3623CXKIC,3623,224,Rebecca Lara,144.90863570166192,-36.44103547317975
WT3289ZSWDS,3289,378,Kim Hall,142.1760506248015,-37.83343114690931
WT3728YZARW,3728,318,Heather Cummings,145.8168813215635,-36.115027477064245
WT3633WGRXB,3633,201,John Miller,145.48023893751045,-36.2875408553956
WT3633UVHAO,3633,201,Michael Price,145.51505172180683,-36.31027112244356
WT3637KIERO,3637,198,Robert Dow,145.25553090556156,-36.0980796504903
WT3063WZIQE,3063,114,James Miller,144.81061694155076,-37.553501843305575
WT3334GGKOS,3334,141,Elizabet Benson,144.1621690362788,-37.67891238372265
WT3251FUJSG,3251,522,Lisa Voegele,143.5797389397756,-38.1623931117428
WT3649NJHAF,3649,86,Catherine Ortiz,145.70444412227315,-36.12591041370753
WT3287NEKVB,3287,216,Joel Simmons,142.26305043381535,-37.983480961999916
WT3407PYOAR,3407,420,Gale Martin,141.83324586447986,-37.2859635851256
WT3779NULEK,3779,197,Aida Kuhnle,146.11080887018696,-37.67951918079387
WT3719TVVJM,3719,122,Brent Bautista,145.6864773045679,-37.03188286944955
WT3719HLABD,3719,122,Alfred Too,145.52985920519603,-36.964844896202216
WT3573DPVGU,3573,111,Wiley Palmer,144.15009214850954,-36.12318035418112
WT3254RXAVL,3254,310,Amy Pugh,143.54387071993327,-38.308515316326016
WT3832NHOOV,3832,247,Bryan Warren,146.0154412945935,-37.93424551655733
WT3238BOTYW,3238,72,Bernard Jackson,143.567776369521,-38.625836774939955
WT3238MCUPV,3238,72,Nellie Banks,143.56196753560545,-38.82942446565583
WT3375LAJLR,3375,104,Emma Boatwright,143.2980117885972,-37.372200644973155
WT3530RJWDT,3530,63,Troy Clark,143.0834668479817,-35.79299394885817
WT3596HBEUF,3596,47,Jose Robertson,143.15095468769667,-35.190473662123345
WT3293SQKBY,3293,100,Shawn Clark,142.64808203542347,-37.82556647618436
WT3887NLNSJ,3887,342,Lorene Anderson,147.96080438424718,-37.76269836557282
1 Watchtower ID Postcode Population Served Watchtower Point of Contact Name x y
2 WT3023QBQJF 3023 12794 Sandra Jaynes 144.7116868675065 -37.79835253004884
3 WT3037YAKEI 3037 25577 Paul Watson 144.7404381965215 -37.71057606210163
4 WT3810RRMDP 3810 47894 Shirl Bays 145.54377380709113 -38.11642115246884
5 WT3550ANADF 3550 10084 Virginia Lumpkins 144.25225555806287 -36.7583657822827
6 WT3754SXJZI 3754 6292 Henriette Mitchell 145.1619799395555 -37.61057382984485
7 WT3754WSOKP 3754 6292 James Lopez 145.11378037030943 -37.60927638542337
8 WT3046ADKBS 3046 8515 Morris Pring 144.94317380188164 -37.71659755462475
9 WT3178BQAJG 3178 5612 Malka Smith 145.26959423333145 -37.918875236595035
10 WT3130PLSQY 3130 8043 Jose Hayes 145.13764760079675 -37.828083908584475
11 WT3032PWVMB 3032 7362 William Mackiewicz 144.87559681642185 -37.79083145310446
12 WT3173JKIEY 3173 5157 Teddy Mccauley 145.18948448769126 -37.992844271467284
13 WT3122GVRSM 3122 11755 William Bell 145.0366394627393 -37.810997917513916
14 WT3171BGAEJ 3171 7238 Lila Levy 145.1337946019459 -37.92898751855743
15 WT3128AQDRS 3128 6609 Sarah Kauffman 145.1295813912443 -37.82078823368618
16 WT3219MZCMM 3219 4928 Charlie Gerber 144.37942394090373 -38.19362930153523
17 WT3170XJVWP 3170 9684 Lucy Lahay 145.17553159514887 -37.936150181976984
18 WT3031DMFGC 3031 6177 Caroline Luckenbach 144.90707048527796 -37.78767901585732
19 WT3015PKLER 3015 8736 Bill Kilbane 144.8979183219914 -37.82580808335247
20 WT3106WQFPR 3106 2374 Mary Bass 145.14274097499288 -37.731835101044354
21 WT3106HTUYW 3106 2374 David Bryan 145.14493956217032 -37.74550312585378
22 WT3352KHBBN 3352 15996 Richard Askew 143.60419898610786 -37.722432808576656
23 WT3079QORWG 3079 5329 Jerry Somogyi 145.05361972090736 -37.76092644646485
24 WT3850WPPZJ 3850 14779 Scott Buggie 146.99670975934802 -38.11120375121315
25 WT3400BOZRI 3400 14543 Tom Davis 142.2056868163526 -36.700923449995635
26 WT3123YZTIF 3123 7160 Paul Earwood 145.05955004240124 -37.82771644759941
27 WT3224OGJJN 3224 1773 Shirley Hall 144.42849521054393 -38.218027859101916
28 WT3137PJCVG 3137 1541 Yolanda Stern 145.32887887734955 -37.830025027117365
29 WT3305NMFYC 3305 3204 Larry Witter 141.29643421841453 -38.11167114301085
30 WT3305KWOFD 3305 3204 Judith Figueroa 141.25644777166127 -38.24079323443777
31 WT3025UXSIE 3025 2430 Willie Laigo 144.79429337101448 -37.82881778367748
32 WT3437KHBPL 3437 3479 Charlotte Green 144.59696365066134 -37.48113208398435
33 WT3151ANFQX 3151 3424 Daniel Davis 145.16632131582105 -37.84908719684687
34 WT3019ASCJP 3019 3065 Charlotte Coutermarsh 144.85492421197495 -37.772589492919515
35 WT3019JIKGX 3019 3065 Vincent January 144.85730316799982 -37.7718018219131
36 WT3764MKCUE 3764 4582 Alejandrina Salazar 144.970506104261 -37.15854276662507
37 WT3730UTUPX 3730 2944 Curtis Johnson 145.8390200963087 -36.01276678240247
38 WT3054SQEQA 3054 8428 Eugene Salano 144.95861592679725 -37.783412869711185
39 WT3620DPAMB 3620 4120 Ben Oneil 144.96824098896346 -36.398921729744224
40 WT3804OQOOF 3804 2023 Jackie Smith 145.35298253700518 -37.98426462189473
41 WT3909HFRJQ 3909 2633 Maria Rhodus 147.90601975805444 -37.764598529015366
42 WT3953SGAEI 3953 1571 Ofelia Kadlec 145.77800174296402 -38.55984015166651
43 WT3953NPQQN 3953 1571 Peter Willer 146.04193592469497 -38.44633595871089
44 WT3765SHSPB 3765 3380 Eilene Horner 145.36201379669092 -37.81894302945288
45 WT3027FZKQC 3027 3323 Angelo Hard 144.73167189283603 -37.85646049026309
46 WT3996ZMYGL 3996 1846 Jennifer Adkins 145.7771574897382 -38.67107249698782
47 WT3984UBSFJ 3984 1041 Ned Johnson 145.61381415852048 -38.3660140349184
48 WT3227LRSVA 3227 4819 Joan Cox 144.38837299987338 -38.22664848840161
49 WT3950WWFHI 3950 2400 Donald Neil 145.789697571232 -38.44829776894874
50 WT3842LLUAZ 3842 2391 Justin Butcher 146.43738290720543 -38.33409319136186
51 WT3225ZWRKT 3225 1352 Sierra Zelaya 144.63248453729392 -38.273920927385454
52 WT3797JXEYZ 3797 1738 Wade Seay 145.59525777895735 -37.85187937890587
53 WT3980CXZJX 3980 1675 Marianne Gulledge 145.38407991603268 -38.234540388656654
54 WT3862WPONG 3862 1578 Anthony Dawkins 147.33271058732282 -37.491238739170896
55 WT3202IDOPR 3202 1453 Shannon Bello 145.07561474247163 -37.947828524869706
56 WT3304LTOER 3304 681 James Broadway 141.91304296053238 -38.08286392590754
57 WT3478NOSNX 3478 614 Mary Wooster 143.190083774406 -36.70864776402552
58 WT3373ZJBZG 3373 573 Helen Hu 143.40004730403342 -37.327257624451846
59 WT3373FDEUM 3373 573 Phyllis Hegyi 143.19424925274458 -37.38771716562931
60 WT3370XRAHI 3370 356 Tammy Compton 143.76050524940354 -37.17889378247109
61 WT3673HXZDV 3673 346 June Matteson 145.99560167654946 -36.51826050506983
62 WT3943FFEHH 3943 398 Floyd Mcfaul 144.7219219690698 -38.32665967904324
63 WT3937YBAGH 3937 762 Tyesha Evans 145.0385876851752 -38.37262744294901
64 WT3786QKGRU 3786 506 Joe Pulaski 145.33261178176102 -37.876147897332174
65 WT3321FSNXX 3321 759 James Mcintosh 144.00220559674338 -38.10453080180178
66 WT3525YPKBW 3525 433 Denise Roberts 143.32090727836928 -36.14524876420747
67 WT3231VKTTU 3231 418 Karl Evans 143.99174248566703 -38.47241568127852
68 WT3231YSKOO 3231 418 Leontine Mcghee 144.07128861030645 -38.416049306559025
69 WT3766LYICC 3766 619 Gary Evans 145.3953639008541 -37.81880414343826
70 WT3381FUDIA 3381 151 Penny Carrier 142.7602629758581 -37.02897861269415
71 WT3232GSLYH 3232 1114 Joshua Sickafoose 143.96111969797116 -38.544885004427805
72 WT3933UXXXP 3933 549 Shaun Guffey 145.11706009902144 -38.26228415412558
73 WT3701KWYIQ 3701 269 Martha Moore 147.39302957919313 -36.254894160169314
74 WT3701TPSEH 3701 269 Grant Kennedy 147.41241338695838 -36.74234154193107
75 WT3312BCEJQ 3312 1031 Alexandra Ratzlaff 141.38649875710092 -37.85213620536482
76 WT3332VSYVL 3332 338 Charles Koons 144.08742265383532 -37.906318691909874
77 WT3623CXKIC 3623 224 Rebecca Lara 144.90863570166192 -36.44103547317975
78 WT3289ZSWDS 3289 378 Kim Hall 142.1760506248015 -37.83343114690931
79 WT3728YZARW 3728 318 Heather Cummings 145.8168813215635 -36.115027477064245
80 WT3633WGRXB 3633 201 John Miller 145.48023893751045 -36.2875408553956
81 WT3633UVHAO 3633 201 Michael Price 145.51505172180683 -36.31027112244356
82 WT3637KIERO 3637 198 Robert Dow 145.25553090556156 -36.0980796504903
83 WT3063WZIQE 3063 114 James Miller 144.81061694155076 -37.553501843305575
84 WT3334GGKOS 3334 141 Elizabet Benson 144.1621690362788 -37.67891238372265
85 WT3251FUJSG 3251 522 Lisa Voegele 143.5797389397756 -38.1623931117428
86 WT3649NJHAF 3649 86 Catherine Ortiz 145.70444412227315 -36.12591041370753
87 WT3287NEKVB 3287 216 Joel Simmons 142.26305043381535 -37.983480961999916
88 WT3407PYOAR 3407 420 Gale Martin 141.83324586447986 -37.2859635851256
89 WT3779NULEK 3779 197 Aida Kuhnle 146.11080887018696 -37.67951918079387
90 WT3719TVVJM 3719 122 Brent Bautista 145.6864773045679 -37.03188286944955
91 WT3719HLABD 3719 122 Alfred Too 145.52985920519603 -36.964844896202216
92 WT3573DPVGU 3573 111 Wiley Palmer 144.15009214850954 -36.12318035418112
93 WT3254RXAVL 3254 310 Amy Pugh 143.54387071993327 -38.308515316326016
94 WT3832NHOOV 3832 247 Bryan Warren 146.0154412945935 -37.93424551655733
95 WT3238BOTYW 3238 72 Bernard Jackson 143.567776369521 -38.625836774939955
96 WT3238MCUPV 3238 72 Nellie Banks 143.56196753560545 -38.82942446565583
97 WT3375LAJLR 3375 104 Emma Boatwright 143.2980117885972 -37.372200644973155
98 WT3530RJWDT 3530 63 Troy Clark 143.0834668479817 -35.79299394885817
99 WT3596HBEUF 3596 47 Jose Robertson 143.15095468769667 -35.190473662123345
100 WT3293SQKBY 3293 100 Shawn Clark 142.64808203542347 -37.82556647618436
101 WT3887NLNSJ 3887 342 Lorene Anderson 147.96080438424718 -37.76269836557282

View file

@ -1,3 +1,3 @@
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
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
1 Watchtower ID Postcode Population Served Watchtower Point of Contact Name x y
2 WT3953SGAEI 3953 1571 Ofelia Kadlec 145.77800174296402 -38.55984015166651
3 WT3765SHSPB 3765 3380 Eilene Horner 145.36201379669092 -37.81894302945288

View file

@ -1,4 +1,4 @@
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
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
1 Watchtower ID Postcode Population Served Watchtower Point of Contact Name x y
2 WT3953SGAEI 3953 1571 Ofelia Kadlec 145.77800174296402 -38.55984015166651
3 WT3765SHSPB 3765 3380 Eilene Horner 145.36201379669092 -37.81894302945288
4 WT3530RJWDT 3530 63 Troy Clark 143.0834668479817 -35.79299394885817

View file

@ -1,5 +1,5 @@
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
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
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
WT3701KWYIQ,3701,269,Martha Moore,147.39302957919313,-36.254894160169314
1 Watchtower ID Postcode Population Served Watchtower Point of Contact Name x y
2 WT3953SGAEI 3953 1571 Ofelia Kadlec 145.77800174296402 -38.55984015166651
3 WT3765SHSPB 3765 3380 Eilene Horner 145.36201379669092 -37.81894302945288
4 WT3530RJWDT 3530 63 Troy Clark 143.0834668479817 -35.79299394885817
5 WT3701KWYIQ 3701 269 Martha Moore 147.39302957919313 -36.254894160169314

File diff suppressed because it is too large Load diff

BIN
towers.o

Binary file not shown.

BIN
voronoi.o

Binary file not shown.

BIN
voronoi2

Binary file not shown.