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