Taylor Bockman
5 years ago
commit
60862d95cc
16 changed files with 808 additions and 0 deletions
@ -0,0 +1,15 @@
|
||||
AlignConsecutiveMacros: 'true' |
||||
AlignConsecutiveAssignments: 'true' |
||||
AlignTrailingComments: 'true' |
||||
AllowShortFunctionsOnASingleLine: None |
||||
AllowShortIfStatementsOnASingleLine: Never |
||||
AllowShortLambdasOnASingleLine: None |
||||
AllowShortLoopsOnASingleLine: 'false' |
||||
BreakBeforeBraces: Linux |
||||
ColumnLimit: '80' |
||||
IndentWidth: '4' |
||||
PointerAlignment: Right |
||||
SpaceBeforeParens: ControlStatements |
||||
SpacesInCStyleCastParentheses: 'false' |
||||
TabWidth: '4' |
||||
UseTab: Never |
@ -0,0 +1,117 @@
|
||||
# Prerequisites |
||||
*.d |
||||
|
||||
# Compiled Object files |
||||
*.slo |
||||
*.lo |
||||
*.o |
||||
*.obj |
||||
|
||||
# Precompiled Headers |
||||
*.gch |
||||
*.pch |
||||
|
||||
# Compiled Dynamic libraries |
||||
*.so |
||||
*.dylib |
||||
*.dll |
||||
|
||||
# Fortran module files |
||||
*.mod |
||||
*.smod |
||||
|
||||
# Compiled Static libraries |
||||
*.lai |
||||
*.la |
||||
*.a |
||||
*.lib |
||||
|
||||
# Executables |
||||
*.exe |
||||
*.out |
||||
*.app |
||||
|
||||
CMakeLists.txt.user |
||||
CMakeCache.txt |
||||
CMakeFiles |
||||
CMakeScripts |
||||
Testing |
||||
Makefile |
||||
cmake_install.cmake |
||||
install_manifest.txt |
||||
compile_commands.json |
||||
CTestTestfile.cmake |
||||
_deps |
||||
|
||||
cmake-build-debug |
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm |
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 |
||||
|
||||
# User-specific stuff |
||||
.idea/**/workspace.xml |
||||
.idea/**/tasks.xml |
||||
.idea/**/usage.statistics.xml |
||||
.idea/**/dictionaries |
||||
.idea/**/shelf |
||||
|
||||
# Generated files |
||||
.idea/**/contentModel.xml |
||||
|
||||
# Sensitive or high-churn files |
||||
.idea/**/dataSources/ |
||||
.idea/**/dataSources.ids |
||||
.idea/**/dataSources.local.xml |
||||
.idea/**/sqlDataSources.xml |
||||
.idea/**/dynamic.xml |
||||
.idea/**/uiDesigner.xml |
||||
.idea/**/dbnavigator.xml |
||||
|
||||
# Gradle |
||||
.idea/**/gradle.xml |
||||
.idea/**/libraries |
||||
|
||||
# Gradle and Maven with auto-import |
||||
# When using Gradle or Maven with auto-import, you should exclude module files, |
||||
# since they will be recreated, and may cause churn. Uncomment if using |
||||
# auto-import. |
||||
# .idea/modules.xml |
||||
# .idea/*.iml |
||||
# .idea/modules |
||||
# *.iml |
||||
# *.ipr |
||||
|
||||
# CMake |
||||
cmake-build-*/ |
||||
|
||||
# Mongo Explorer plugin |
||||
.idea/**/mongoSettings.xml |
||||
|
||||
# File-based project format |
||||
*.iws |
||||
|
||||
# IntelliJ |
||||
out/ |
||||
|
||||
# mpeltonen/sbt-idea plugin |
||||
.idea_modules/ |
||||
|
||||
# JIRA plugin |
||||
atlassian-ide-plugin.xml |
||||
|
||||
# Cursive Clojure plugin |
||||
.idea/replstate.xml |
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ) |
||||
com_crashlytics_export_strings.xml |
||||
crashlytics.properties |
||||
crashlytics-build.properties |
||||
fabric.properties |
||||
|
||||
# Editor-based Rest Client |
||||
.idea/httpRequests |
||||
|
||||
# Android studio 3.1+ serialized cache file |
||||
.idea/caches/build_file_checksums.ser |
||||
|
||||
bin/ |
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration"> |
||||
<state> |
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" /> |
||||
</state> |
||||
</component> |
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<module classpath="CMake" type="CPP_MODULE" version="4" /> |
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> |
||||
<component name="CidrRootsConfiguration"> |
||||
<sourceRoots> |
||||
<file path="$PROJECT_DIR$/include" /> |
||||
<file path="$PROJECT_DIR$/src" /> |
||||
</sourceRoots> |
||||
</component> |
||||
<component name="JavaScriptSettings"> |
||||
<option name="languageLevel" value="ES6" /> |
||||
</component> |
||||
</project> |
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="ProjectModuleManager"> |
||||
<modules> |
||||
<module fileurl="file://$PROJECT_DIR$/.idea/compginc.iml" filepath="$PROJECT_DIR$/.idea/compginc.iml" /> |
||||
</modules> |
||||
</component> |
||||
</project> |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="VcsDirectoryMappings"> |
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
||||
</component> |
||||
</project> |
@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.15) |
||||
project(cgc C) |
||||
|
||||
file(GLOB SOURCE "src/*.c") |
||||
file(GLOB INCLUDE "include/*.h") |
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) |
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) |
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) |
||||
|
||||
include_directories("include") |
||||
|
||||
set(CMAKE_C_STANDARD 99) |
||||
|
||||
add_executable(cgc ${SOURCE} ${INCLUDE}) |
@ -0,0 +1,26 @@
|
||||
# Computational Geometry in C, 2nd Edition |
||||
|
||||
This is the project I use for storing all of the code in the book _Computational Geometry in C, 2nd Edition_ by |
||||
Joseph O'Rourke. |
||||
|
||||
Much of the code is copied verbatim, however I took the time to fix a few memory leaks and made other small changes |
||||
to make the code more maintainable across different chapters. In particular, I wrote the code without an assumption |
||||
of a global vertex pointer in order to make debugging functions significantly easier. I also added a few |
||||
freeing functions that were not featured in the book. |
||||
|
||||
## Some Notes |
||||
|
||||
There are a handful of instances where I am using constant pointers or double pointers (pointers to pointers) that |
||||
I need to go back and fix. Additionally, Valgrind does not work on OS X right now (1/26/2020) so I cannot verify |
||||
the code is leak-free. |
||||
|
||||
## Compilation and Running |
||||
|
||||
To compile the code: |
||||
|
||||
```sh |
||||
cd <directory of repository> |
||||
cmake . |
||||
make |
||||
./bin/cgc |
||||
``` |
@ -0,0 +1,6 @@
|
||||
#ifndef _CGC_ERROR_H |
||||
#define _CGC_ERROR_H |
||||
|
||||
#define EXIT_FAILURE 1 |
||||
|
||||
#endif // _CGC_ERROR_H
|
@ -0,0 +1,146 @@
|
||||
#ifndef CGC_MATH_H |
||||
#define CGC_MATH_H |
||||
|
||||
#include "vertex.h" |
||||
#define X 0 |
||||
#define Y 1 |
||||
#define Z 2 |
||||
|
||||
/**
|
||||
* Given 3 vertices, calculates the two dimensional area of the triangle |
||||
* represented by those shapes. |
||||
* |
||||
* Integers are used here for simplicity. Doubles would be nice too but |
||||
* for now the lack of rounding error in integers is sufficient for the |
||||
* purpose. |
||||
* |
||||
* @param a The first vertex. |
||||
* @param b The second vertex. |
||||
* @param c The third vertex. |
||||
* @return The integer area of the polygon. |
||||
*/ |
||||
int area2(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c); |
||||
|
||||
/**
|
||||
* Given the head of a counter-clockwise indexed polygon area_poly_2 |
||||
* calculates the area of the polygon given. |
||||
* |
||||
* @param head The first vertex. |
||||
* @return The area. |
||||
*/ |
||||
int area_poly_2(const struct Vertex *head); |
||||
|
||||
/**
|
||||
* Determines if vertex c is to the left of the line segment ab. Note the |
||||
* area of the shape made by the 3 vertices must have c to the left to have |
||||
* positive area. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @return True if it is to the left, false otherwise. |
||||
*/ |
||||
bool left(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c); |
||||
|
||||
/**
|
||||
* Determines if vertex c is to the left or collinear with the line segment ab. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @return True if it is to the left or collinear, false otherwise. |
||||
*/ |
||||
bool left_on(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c); |
||||
|
||||
/**
|
||||
* Determines if the vertex c is collinear with line segment ab. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @return True if it is collinear with ab, false otherwise. |
||||
*/ |
||||
bool collinear(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c); |
||||
|
||||
/**
|
||||
* Determines if the line segments ab and cd are intersecting properly. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @param d Vertex d. |
||||
* @return True if they intersect properly, false otherwise. |
||||
*/ |
||||
bool intersect_prop(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c, const struct Vertex *d); |
||||
|
||||
/**
|
||||
* Determines the betweenness of c. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @return True if c is between ab. |
||||
*/ |
||||
bool between(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c); |
||||
|
||||
/**
|
||||
* Determines if two line segments, ab and cd, intersect. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @param c Vertex c. |
||||
* @param d Vertex d. |
||||
* @return True if they intersect, false otherwise. |
||||
*/ |
||||
bool intersect(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c, const struct Vertex *d); |
||||
|
||||
/**
|
||||
* Finds a diagonal of line segment ab for the polygon represented by the start |
||||
* vertex `head`. |
||||
* |
||||
* @param head The first vertex of a counter-clockwise labeled polygon. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @return True if ab is a valid diagonal, false otherwise. |
||||
*/ |
||||
bool diagonalie(const struct Vertex *head, const struct Vertex *a, |
||||
const struct Vertex *b); |
||||
|
||||
/**
|
||||
* Determines if one vector b lines inside the cone created by vertices a and |
||||
* b. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @return True if it lies in the cone, false otherwise. |
||||
*/ |
||||
bool in_cone(const struct Vertex *a, const struct Vertex *b); |
||||
|
||||
/**
|
||||
* Determines if ab is a diagonal in the polygon represented by the |
||||
* counter-clockwise ordered vertex list head. |
||||
* |
||||
* @param head The head of the polygon's vertex list. |
||||
* @param a Vertex a. |
||||
* @param b Vertex b. |
||||
* @return True if ab is a diagonal, false otherwise. |
||||
*/ |
||||
bool diagonal(const struct Vertex *head, const struct Vertex *a, |
||||
const struct Vertex *b); |
||||
|
||||
/**
|
||||
* Triangulates a given polygon and prints the results to screen. |
||||
* |
||||
* Note this currently destructively modifies the polygon. Each ear |
||||
* removed is freed as a result of the algorithm pointing around it in |
||||
* the circularly linked list. The book does not talk about memory management |
||||
* and on large polygons this is a massive memory leak. |
||||
* |
||||
* Future versions of the function should operate on copies and/or non |
||||
* destructively produce results. |
||||
* |
||||
* @param head The start vertex of a polygon. |
||||
*/ |
||||
void triangulate(const struct Vertex *head); |
||||
|
||||
#endif // CGC_MATH_H
|
@ -0,0 +1,77 @@
|
||||
#ifndef _CGC_VERTEX_H |
||||
#define _CGC_VERTEX_H |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
struct Vertex { |
||||
int number; |
||||
int coordinates[2]; |
||||
bool ear; |
||||
struct Vertex *next; |
||||
struct Vertex *prev; |
||||
}; |
||||
|
||||
/**
|
||||
* Initializes a new vertex struct. |
||||
* @param number The number of the vertex for identification. |
||||
* @param x X coordinate. |
||||
* @param y Y coordinate. |
||||
* @return An initialized Vertex struct. |
||||
*/ |
||||
struct Vertex *new_vertex(int number, int x, int y); |
||||
|
||||
/**
|
||||
* Adds a vertex to a parent vertex under the assumption the parent vertex |
||||
* is the LAST vertex in the list. The reason this is necessary is because |
||||
* the list of vertices is circular, and as such the last element points |
||||
* back to the head of the list. The list will be modified in place. |
||||
* |
||||
* @param head The head of the polygon's vertex list. |
||||
* @param parent The parent vertex to add the new one to. |
||||
* @param child The child vertex. |
||||
*/ |
||||
void add_vertex(struct Vertex **head, struct Vertex **parent, |
||||
struct Vertex **child); |
||||
|
||||
/**
|
||||
* Frees a single vertex. This does not free it's next and previous pointers. |
||||
* @param vertex The vertex to free. |
||||
*/ |
||||
void free_vertex(struct Vertex *vertex); |
||||
|
||||
/**
|
||||
* Frees an entire polygon given it's head (first) vertex. |
||||
* @param head The start of the counter-clockwise ordered polygon. |
||||
*/ |
||||
void free_polygon(struct Vertex **head); |
||||
|
||||
/**
|
||||
* Pretty prints a vertex. |
||||
* @param vertex The vertex. |
||||
*/ |
||||
void print_vertex(const struct Vertex *vertex); |
||||
|
||||
/**
|
||||
* Pretty prints a polygon. |
||||
* @param head The first point in the polygon. |
||||
*/ |
||||
void print_polygon(const struct Vertex *head); |
||||
|
||||
/**
|
||||
* Traverses the polygon represented by the starting point `head` and |
||||
* sets the ear parameter correctly. |
||||
* |
||||
* @param head |
||||
*/ |
||||
void init_ear(struct Vertex *head); |
||||
|
||||
/**
|
||||
* Counts the number of vertices in a polygon. |
||||
* @param head The start vertex of the polygon. |
||||
* @return The count of vertices. |
||||
*/ |
||||
int vertex_count(const struct Vertex *head); |
||||
|
||||
#endif // _CGC_VERTEX_H
|
@ -0,0 +1,64 @@
|
||||
#include <stdio.h> |
||||
|
||||
#include "vertex.h" |
||||
#include "math.h" |
||||
|
||||
void chapter1() { |
||||
// Initialize our chapter 1 polygon
|
||||
struct Vertex *v0 = new_vertex(0, 0, 0); |
||||
struct Vertex *v1 = new_vertex(1, 10, 7); |
||||
struct Vertex *v2 = new_vertex(2, 12, 3); |
||||
struct Vertex *v3 = new_vertex(3, 20, 8); |
||||
struct Vertex *v4 = new_vertex(4, 13, 17); |
||||
struct Vertex *v5 = new_vertex(5, 10, 12); |
||||
struct Vertex *v6 = new_vertex(6, 12, 14); |
||||
struct Vertex *v7 = new_vertex(7, 14, 9); |
||||
struct Vertex *v8 = new_vertex(8, 8, 10); |
||||
struct Vertex *v9 = new_vertex(9, 6, 14); |
||||
struct Vertex *v10 = new_vertex(10, 10, 15); |
||||
struct Vertex *v11 = new_vertex(11, 7, 18); |
||||
struct Vertex *v12 = new_vertex(12, 0, 16); |
||||
struct Vertex *v13 = new_vertex(13, 1, 13); |
||||
struct Vertex *v14 = new_vertex(14, 3, 15); |
||||
struct Vertex *v15 = new_vertex(15, 5, 8); |
||||
struct Vertex *v16 = new_vertex(16, -2, 9); |
||||
struct Vertex *v17 = new_vertex(17, 5, 5); |
||||
|
||||
// TODO: You may be able to change this back to normal as long as you're
|
||||
// using -> to set the value on the struct. This is interpreted
|
||||
// as (*thing).xyz so you are doing too much work on pointers
|
||||
// in this.
|
||||
add_vertex(&v0, &v0, &v1); |
||||
add_vertex(&v0, &v1, &v2); |
||||
add_vertex(&v0, &v2, &v3); |
||||
add_vertex(&v0, &v3, &v4); |
||||
add_vertex(&v0, &v4, &v5); |
||||
add_vertex(&v0, &v5, &v6); |
||||
add_vertex(&v0, &v6, &v7); |
||||
add_vertex(&v0, &v7, &v8); |
||||
add_vertex(&v0, &v8, &v9); |
||||
add_vertex(&v0, &v9, &v10); |
||||
add_vertex(&v0, &v10, &v11); |
||||
add_vertex(&v0, &v11, &v12); |
||||
add_vertex(&v0, &v12, &v13); |
||||
add_vertex(&v0, &v13, &v14); |
||||
add_vertex(&v0, &v14, &v15); |
||||
add_vertex(&v0, &v15, &v16); |
||||
add_vertex(&v0, &v16, &v17); |
||||
|
||||
init_ear(v0); |
||||
|
||||
print_polygon(v0); |
||||
|
||||
triangulate(v0); |
||||
|
||||
//print_polygon(v0);
|
||||
|
||||
free_polygon(&v0); |
||||
} |
||||
|
||||
int main() |
||||
{ |
||||
chapter1(); |
||||
return 0; |
||||
} |
@ -0,0 +1,206 @@
|
||||
#include "math.h" |
||||
#include <vertex.h> |
||||
|
||||
int area2(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c) |
||||
{ |
||||
return ((b->coordinates[X] - a->coordinates[X]) * |
||||
(c->coordinates[Y] - a->coordinates[Y])) - |
||||
((c->coordinates[X] - a->coordinates[X]) * |
||||
(b->coordinates[Y] - a->coordinates[Y])); |
||||
} |
||||
|
||||
int area_poly_2(const struct Vertex *head) |
||||
{ |
||||
int sum = 0; |
||||
struct Vertex *a = head->next; |
||||
|
||||
do { |
||||
sum += area2(head, a, a->next); |
||||
a = a->next; |
||||
} while (a->next != head); |
||||
|
||||
return sum; |
||||
} |
||||
|
||||
bool left(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c) |
||||
{ |
||||
return area2(a, b, c) > 0; |
||||
} |
||||
|
||||
bool left_on(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c) |
||||
{ |
||||
return area2(a, b, c) >= 0; |
||||
} |
||||
|
||||
bool collinear(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c) |
||||
{ |
||||
return area2(a, b, c) == 0; |
||||
} |
||||
|
||||
bool intersect_prop(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c, const struct Vertex *d) |
||||
{ |
||||
if (collinear(a, b, c) || collinear(a, b, d) || collinear(c, d, a) || |
||||
collinear(c, d, b)) { |
||||
return false; |
||||
} |
||||
|
||||
// The arguments are negated to insure they are 0/1
|
||||
return !left(a, b, c) ^ !left(a, b, d) && !left(c, d, a) ^ !left(c, d, b); |
||||
} |
||||
|
||||
bool between(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c) |
||||
{ |
||||
if (!collinear(a, b, c)) { |
||||
return false; |
||||
} |
||||
|
||||
// if ab is not vertical, check betweenness on x, else on y.
|
||||
if (a->coordinates[X] != b->coordinates[X]) { |
||||
return ((a->coordinates[X] <= c->coordinates[X]) && |
||||
(c->coordinates[X] <= b->coordinates[X])) || |
||||
((a->coordinates[X] >= c->coordinates[X]) && |
||||
(c->coordinates[X] >= b->coordinates[X])); |
||||
} else { |
||||
return ((a->coordinates[Y] <= c->coordinates[Y]) && |
||||
(c->coordinates[Y] <= b->coordinates[Y])) || |
||||
((a->coordinates[Y] >= c->coordinates[Y]) && |
||||
(c->coordinates[Y] >= b->coordinates[Y])); |
||||
} |
||||
} |
||||
|
||||
bool intersect(const struct Vertex *a, const struct Vertex *b, |
||||
const struct Vertex *c, const struct Vertex *d) |
||||
{ |
||||
// First check for proper intersection - the intersection that you
|
||||
// normally think of (two lines forming a kind of cross).
|
||||
if (intersect_prop(a, b, c, d)) { |
||||
return true; |
||||
} else if (between(a, b, c) || between(a, b, d) || between(c, d, a) || |
||||
between(c, d, b)) { |
||||
|
||||
// Improper intersection - where an endpoint of one line
|
||||
// segment is intersected on another line segment.
|
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool diagonalie(const struct Vertex *head, const struct Vertex *a, |
||||
const struct Vertex *b) |
||||
{ |
||||
struct Vertex *c; |
||||
struct Vertex *c1; |
||||
|
||||
c = head; |
||||
|
||||
// For each edge (c, c1) of the polygon represented by head
|
||||
do { |
||||
c1 = c->next; |
||||
|
||||
/* Skip the edge (c, c1) if it is incident with (a, b).
|
||||
In this case we are testing first to make sure the chosen points |
||||
aren't the same points as our test edge ab (trivial case of |
||||
incidence) and then testing to make sure there is no intersection |
||||
(normal idea of incidence of two line segments). |
||||
*/ |
||||
if ((c != a) && (c1 != a) && (c != b) && (c1 != b) && |
||||
intersect(a, b, c, c1)) { |
||||
return false; |
||||
} |
||||
|
||||
c = c->next; |
||||
} while (c != head); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool in_cone(const struct Vertex *a, const struct Vertex *b) |
||||
{ |
||||
struct Vertex *a0; |
||||
struct Vertex *a1; |
||||
|
||||
a1 = a->next; |
||||
a0 = a->prev; |
||||
|
||||
// If a is a convex vertex...
|
||||
if (left_on(a, a1, a0)) { |
||||
return left(a, b, a0) && left(b, a, a1); |
||||
} |
||||
|
||||
// Otherwise a is reflex...
|
||||
// The result is a0 and a1 will be "further outside" of a, so the
|
||||
// diagonal formed by a0a1 is external to the cone.
|
||||
return !(left_on(a, b, a1) && left_on(b, a, a0)); |
||||
} |
||||
|
||||
bool diagonal(const struct Vertex *head, const struct Vertex *a, |
||||
const struct Vertex *b) |
||||
{ |
||||
// Performance wise in_cone is called first because it is a constant
|
||||
// time operation that, when it fails, prevents a call to the more
|
||||
// potentially performance heavy looping in diagonalie.
|
||||
return in_cone(a, b) && in_cone(b, a) && diagonalie(head, a, b); |
||||
} |
||||
|
||||
void triangulate(const struct Vertex *head) |
||||
{ |
||||
// 5 consecutive vertices
|
||||
struct Vertex *v0; |
||||
struct Vertex *v1; |
||||
struct Vertex *v2; |
||||
struct Vertex *v3; |
||||
struct Vertex *v4; |
||||
|
||||
int n = vertex_count(head); |
||||
|
||||
// Each step of the outer loop removes one ear
|
||||
while (n > 3) { |
||||
// Inner loop searches for an ear.
|
||||
v2 = head; |
||||
do { |
||||
if (v2->ear) { |
||||
// Found an ear, fill the variables
|
||||
v3 = v2->next; |
||||
v4 = v3->next; |
||||
v1 = v2->prev; |
||||
v0 = v1->prev; |
||||
|
||||
// Print the diagonal
|
||||
printf("DIAGONAL: (%d, %d)\n", v1->number, v3->number); |
||||
|
||||
// Update the earity of the remaining diagonal endpoints
|
||||
v1->ear = diagonal(head, v0, v3); |
||||
v3->ear = diagonal(head, v1, v4); |
||||
|
||||
// Cut off the ear v2.
|
||||
v1->next = v3; |
||||
v3->prev = v1; |
||||
head = v3; |
||||
n--; |
||||
|
||||
break; |
||||
} |
||||
|
||||
if(v2 -> ear) { |
||||
struct Vertex *temp = v2->next; |
||||
|
||||
// Since we have pointed around v2 (ear removal) there is no
|
||||
// way to reach it anymore. As a result a free call is necessary
|
||||
// to clean it up.
|
||||
free_vertex(v2); |
||||
|
||||
v2 = temp; |
||||
} else { |
||||
v2 = v2->next; |
||||
} |
||||
|
||||
} while (v2 != head); |
||||
} |
||||
} |
@ -0,0 +1,101 @@
|
||||
#include "vertex.h" |
||||
#include "math.h" |
||||
|
||||
struct Vertex *new_vertex(int number, int x, int y) |
||||
{ |
||||
struct Vertex *newv = (struct Vertex *)malloc(sizeof(struct Vertex)); |
||||
|
||||
if (newv == NULL) { |
||||
printf("Out of memory"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
newv->number = number; |
||||
newv->coordinates[0] = x; |
||||
newv->coordinates[1] = y; |
||||
newv->ear = false; |
||||
|
||||
return newv; |
||||
} |
||||
|
||||
void add_vertex(struct Vertex **head, struct Vertex **parent, |
||||
struct Vertex **child) |
||||
{ |
||||
(*parent)->next = *child; |
||||
(*child)->prev = *parent; |
||||
(*child)->next = *head; |
||||
(*head)->prev = *child; |
||||
}; |
||||
|
||||
void free_vertex(struct Vertex *vertex) |
||||
{ |
||||
if (vertex != NULL) { |
||||
free(vertex); |
||||
} |
||||
} |
||||
|
||||
void free_polygon(struct Vertex **head) |
||||
{ |
||||
if(head == NULL) { |
||||
return; |
||||
} |
||||
|
||||
while(*head != NULL) { |
||||
struct Vertex **temp = head; |
||||
(*head) = (*head)->next; |
||||
free(*temp); |
||||
*temp = NULL; |
||||
} |
||||
} |
||||
|
||||
void print_vertex(const struct Vertex *vertex) |
||||
{ |
||||
printf("VERTEX {number: %d x: %d y: %d ear: %d}\n", vertex->number, |
||||
vertex->coordinates[X], vertex->coordinates[Y], vertex->ear); |
||||
} |
||||
|
||||
void print_polygon(const struct Vertex *head) { |
||||
const struct Vertex *v = head->next; |
||||
|
||||
printf("-------"); |
||||
while(v != head) { |
||||
print_vertex(v); |
||||
v = v->next; |
||||
} |
||||
} |
||||
|
||||
void init_ear(struct Vertex *head) |
||||
{ |
||||
// 3 consecutive vertices
|
||||
struct Vertex *v0; |
||||
struct Vertex *v1; |
||||
struct Vertex *v2; |
||||
|
||||
// Initialize v1->ear for all vertices
|
||||
v1 = head; |
||||
|
||||
do { |
||||
v2 = v1->next; |
||||
v0 = v1->prev; |
||||
|
||||
// If v0v2 is a diagonal, v1 is an ear by definition.
|
||||
v1->ear = diagonal(head, v0, v2); |
||||
|
||||
// Move one point over and run it again.
|
||||
v1 = v1->next; |
||||
} while (v1 != head); |
||||
} |
||||
|
||||
|
||||
int vertex_count(const struct Vertex *head) |
||||
{ |
||||
int sum = 1; |
||||
const struct Vertex *v = head->next; |
||||
|
||||
while(v != head) { |
||||
sum++; |
||||
v = v->next; |
||||
} |
||||
|
||||
return sum; |
||||
} |
Loading…
Reference in new issue