├── .gitignore ├── sample.data ├── DECL.hpp ├── LICENSE ├── README.md ├── .vscode └── launch.json ├── .clang-format └── DECL.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | -------------------------------------------------------------------------------- /sample.data: -------------------------------------------------------------------------------- 1 | 3 2 | 3 3 | 0 0 4 | 4 4 5 | 3 2 6 | 0 1 7 | 1 2 8 | 2 0 9 | 3 10 | 1 2 11 | -------------------------------------------------------------------------------- /DECL.hpp: -------------------------------------------------------------------------------- 1 | 2 | class vertex 3 | { 4 | public: 5 | /* data */ 6 | int key; 7 | float x, y; 8 | }; 9 | 10 | class half_edge 11 | { 12 | public: 13 | int origin_v, end_v; 14 | class vertex *origin, *end; 15 | class half_edge *twin; 16 | }; 17 | 18 | class face 19 | { 20 | public: 21 | int key = -1; 22 | }; 23 | 24 | class vertex_table 25 | { 26 | public: 27 | class vertex *v; 28 | class half_edge *e; 29 | }; 30 | 31 | class face_table 32 | { 33 | public: 34 | class face *face = NULL; 35 | vector inner_components; 36 | class half_edge *outer_component = NULL; 37 | float area = -1; 38 | }; 39 | 40 | class half_edge_table 41 | { 42 | public: 43 | class half_edge *half_edge, *next, *prev; 44 | class face *incident_face = NULL; 45 | }; 46 | 47 | #define INF 10000 48 | 49 | struct Point 50 | { 51 | float x; 52 | float y; 53 | }; 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ankur Jaiswal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # DCEL 3 | 4 | ===== 5 | 6 | [![License : MIT](https://img.shields.io/npm/l/express.svg)](https://ankur.mit-license.org/) 7 | ![CPP: 11](https://img.shields.io/badge/CPP-11-red.svg) 8 | 9 | **The doubly connected edge list (DCEL)**, also known as half-edge data structure, is a data structure to represent an embedding of a planar graph in the plane, and polytopes in 3D. 10 | This data structure provides efficient manipulation of the topological information associated with the objects in question (vertices, edges, faces). 11 | It is used in many algorithms of computational geometry to handle polygonal subdivisions of the plane, commonly called planar straight-line graphs (PSLG). 12 | For example, a Voronoi diagram is commonly represented by a DCEL inside a bounding box. 13 | 14 | ## INPUT FORMAT: is that of Adjacency list 15 | 16 | 1st line specifies number of vertices, v 17 | 2nd line number of edges, e 18 | Subsequent 'v' lines specifies vertices as space separated cordinate points. 19 | Subsequent 'e' lines specifies edges as space separated verice name which they are connecting. 20 | 21 | ## DEMO 22 | 23 | Use the sample data in the sample.data file to test it out! 24 | 25 | bash> ./a.out < sample.data 26 | 27 | ## Contributing 28 | 29 | Feel free to submit a pull request or an issue. Sugest new features on issue tracker. 30 | **OR** 31 | You can [tweet me](https://twitter.com/ItsAnkurJ) if library helps. 32 | 33 | ## License 34 | 35 | Built with ♥ by Ankur Jaiswal under [MIT License](https://ankur.mit-license.org/) 36 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "(gdb) Attach", 10 | "type": "cppdbg", 11 | "request": "attach", 12 | "program": "enter program name, for example ${workspaceFolder}/a.exe", 13 | "processId": "${command:pickProcess}", 14 | "MIMode": "gdb", 15 | "miDebuggerPath": "/path/to/gdb", 16 | "setupCommands": [ 17 | { 18 | "description": "Enable pretty-printing for gdb", 19 | "text": "-enable-pretty-printing", 20 | "ignoreFailures": true 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "(gdb) Launch", 26 | "type": "cppdbg", 27 | "request": "launch", 28 | "program": "enter program name, for example ${workspaceFolder}/a.exe", 29 | "args": [], 30 | "stopAtEntry": false, 31 | "cwd": "${fileDirname}", 32 | "environment": [], 33 | "externalConsole": false, 34 | "MIMode": "gdb", 35 | "miDebuggerPath": "/path/to/gdb", 36 | "setupCommands": [ 37 | { 38 | "description": "Enable pretty-printing for gdb", 39 | "text": "-enable-pretty-printing", 40 | "ignoreFailures": true 41 | } 42 | ] 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: false 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: All 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: MultiLine 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Attach 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 80 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | ExperimentalAutoDetectBinPacking: false 63 | FixNamespaceComments: true 64 | ForEachMacros: 65 | - foreach 66 | - Q_FOREACH 67 | - BOOST_FOREACH 68 | IncludeBlocks: Preserve 69 | IncludeCategories: 70 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 71 | Priority: 2 72 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 73 | Priority: 3 74 | - Regex: '.*' 75 | Priority: 1 76 | IncludeIsMainRegex: '(Test)?$' 77 | IndentCaseLabels: false 78 | IndentPPDirectives: None 79 | IndentWidth: 2 80 | IndentWrappedFunctionNames: false 81 | JavaScriptQuotes: Leave 82 | JavaScriptWrapImports: true 83 | KeepEmptyLinesAtTheStartOfBlocks: true 84 | MacroBlockBegin: '' 85 | MacroBlockEnd: '' 86 | MaxEmptyLinesToKeep: 1 87 | NamespaceIndentation: None 88 | ObjCBinPackProtocolList: Auto 89 | ObjCBlockIndentWidth: 2 90 | ObjCSpaceAfterProperty: false 91 | ObjCSpaceBeforeProtocolList: true 92 | PenaltyBreakAssignment: 2 93 | PenaltyBreakBeforeFirstCallParameter: 19 94 | PenaltyBreakComment: 300 95 | PenaltyBreakFirstLessLess: 120 96 | PenaltyBreakString: 1000 97 | PenaltyBreakTemplateDeclaration: 10 98 | PenaltyExcessCharacter: 1000000 99 | PenaltyReturnTypeOnItsOwnLine: 60 100 | PointerAlignment: Right 101 | ReflowComments: true 102 | SortIncludes: true 103 | SortUsingDeclarations: true 104 | SpaceAfterCStyleCast: false 105 | SpaceAfterLogicalNot: false 106 | SpaceAfterTemplateKeyword: true 107 | SpaceBeforeAssignmentOperators: true 108 | SpaceBeforeCpp11BracedList: false 109 | SpaceBeforeCtorInitializerColon: true 110 | SpaceBeforeInheritanceColon: true 111 | SpaceBeforeParens: ControlStatements 112 | SpaceBeforeRangeBasedForLoopColon: true 113 | SpaceInEmptyParentheses: false 114 | SpacesBeforeTrailingComments: 1 115 | SpacesInAngles: false 116 | SpacesInContainerLiterals: true 117 | SpacesInCStyleCastParentheses: false 118 | SpacesInParentheses: false 119 | SpacesInSquareBrackets: false 120 | Standard: Cpp11 121 | StatementMacros: 122 | - Q_UNUSED 123 | - QT_REQUIRE_VERSION 124 | TabWidth: 4 125 | UseTab: Never 126 | ... 127 | 128 | -------------------------------------------------------------------------------- /DECL.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #include "DECL.hpp" 5 | 6 | // Given three colinear points p, q, r, the function checks if 7 | // point q lies on line segment 'pr' 8 | bool onSegment(Point p, Point q, Point r) { 9 | if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) && q.y <= max(p.y, r.y) && 10 | q.y >= min(p.y, r.y)) 11 | return true; 12 | return false; 13 | } 14 | 15 | // To find orientation of ordered triplet (p, q, r). 16 | // The function returns following values 17 | // 0 --> p, q and r are colinear 18 | // 1 --> Clockwise 19 | // 2 --> Counterclockwise 20 | int orientation(Point p, Point q, Point r) { 21 | float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); 22 | 23 | if (val == 0) 24 | return 0; // colinear 25 | return (val > 0) ? 1 : 2; // clock or counterclock wise 26 | } 27 | 28 | // The function that returns true if line segment 'p1q1' 29 | // and 'p2q2' intersect. 30 | bool doIntersect(Point p1, Point q1, Point p2, Point q2) { 31 | // Find the four orientations needed for general and 32 | // special cases 33 | float o1 = orientation(p1, q1, p2); 34 | float o2 = orientation(p1, q1, q2); 35 | float o3 = orientation(p2, q2, p1); 36 | float o4 = orientation(p2, q2, q1); 37 | 38 | // General case 39 | if (o1 != o2 && o3 != o4) 40 | return true; 41 | 42 | // Special Cases 43 | // p1, q1 and p2 are colinear and p2 lies on segment p1q1 44 | if (o1 == 0 && onSegment(p1, p2, q1)) 45 | return true; 46 | 47 | // p1, q1 and p2 are colinear and q2 lies on segment p1q1 48 | if (o2 == 0 && onSegment(p1, q2, q1)) 49 | return true; 50 | 51 | // p2, q2 and p1 are colinear and p1 lies on segment p2q2 52 | if (o3 == 0 && onSegment(p2, p1, q2)) 53 | return true; 54 | 55 | // p2, q2 and q1 are colinear and q1 lies on segment p2q2 56 | if (o4 == 0 && onSegment(p2, q1, q2)) 57 | return true; 58 | 59 | return false; // Doesn't fall in any of the above cases 60 | } 61 | 62 | // Returns true if the point p lies inside the polygon[] with n vertices 63 | bool isInside(Point polygon[], int n, Point p) { 64 | // There must be at least 3 vertices in polygon[] 65 | if (n < 3) 66 | return false; 67 | 68 | // Create a point for line segment from p to infinite 69 | Point extreme = {INF, p.y}; 70 | 71 | // Count intersections of the above line with sides of polygon 72 | int count = 0, i = 0; 73 | do { 74 | int next = (i + 1) % n; 75 | 76 | // Check if the line segment from 'p' to 'extreme' intersects 77 | // with the line segment from 'polygon[i]' to 'polygon[next]' 78 | if (doIntersect(polygon[i], polygon[next], p, extreme)) { 79 | // If the point 'p' is colinear with line segment 'i-next', 80 | // then check if it lies on segment. If it lies, return true, 81 | // otherwise false 82 | if (orientation(polygon[i], p, polygon[next]) == 0) 83 | return onSegment(polygon[i], p, polygon[next]); 84 | 85 | count++; 86 | } 87 | i = next; 88 | } while (i != 0); 89 | 90 | // Return true if count is odd, false otherwise 91 | return count & 1; // Same as (count%2 == 1) 92 | } 93 | 94 | void print_half_edge(vector &a, vector &v, int l) { 95 | for (int i = 0; i < l; i++) { 96 | int s, e; 97 | half_edge *temp; 98 | s = a[i].origin_v; 99 | e = a[i].end_v; 100 | temp = a[i].twin; 101 | cout << "edge :" << s << "-" << e << " "; 102 | cout << "coordinates : (" << v[s].x << " , " << v[s].y << ") , (" << v[e].x 103 | << " , " << v[e].y << ") "; 104 | cout << "Twin edge :" << temp->origin_v << "-" << temp->end_v << "\n"; 105 | } 106 | } 107 | 108 | int search_half_edge(int s, int e, vector &h) { 109 | int l = h.size(); 110 | for (int i = 0; i < l; i++) { 111 | if (h[i].origin_v == s && h[i].end_v == e) { 112 | return i; 113 | } 114 | } 115 | cout << "Error in serching half edge" 116 | << "\n"; 117 | return -1; 118 | } 119 | 120 | int search_half_edge_table(half_edge *half_edge, 121 | vector half_edge_table) { 122 | int l = half_edge_table.size(); 123 | for (int i = 0; i < l; i++) { 124 | if (half_edge_table[i].half_edge == half_edge) 125 | return i; 126 | } 127 | return 0; 128 | } 129 | 130 | void fill_vertex_table(vector &ver_tab, int l, 131 | vector> adj, vector &h, 132 | vector &v) { 133 | for (int i = 0; i < l; i++) { 134 | int s = v[i].key; 135 | int e = adj[s][0]; // Assuming no stand alone vertex 136 | ver_tab[i].v = &v[i]; 137 | ver_tab[i].e = &h[search_half_edge(s, e, h)]; 138 | } 139 | } 140 | 141 | float angle(float x1, float y1, float x2, float y2, float x3, float y3) { 142 | x1 = x1 - x2; 143 | y1 = y1 - y2; 144 | x3 = x3 - x2; 145 | y3 = y3 - y2; 146 | float dot = x1 * x3 + y1 * y3; 147 | float det = x1 * y3 - y1 * x3; 148 | float result = atan2(det, dot); 149 | return ((result < 0) ? (result * 180 / 3.141592) + 360 150 | : (result * 180 / 3.141592)); 151 | } 152 | 153 | int next_half_edge(int current, vector> adj, 154 | vector vertex, vector &half_edge) { 155 | int s, e; 156 | float max_angle = 0, temp_angle; 157 | int next_vertex; 158 | s = half_edge[current].origin_v; 159 | e = half_edge[current].end_v; 160 | float x1, x2, y1, y2; 161 | next_vertex = s; 162 | x1 = vertex[s].x; 163 | y1 = vertex[s].y; 164 | x2 = vertex[e].x; 165 | y2 = vertex[e].y; 166 | for (auto k : adj[e]) { 167 | if (k == e) 168 | continue; 169 | else { 170 | temp_angle = angle(x1, y1, x2, y2, vertex[k].x, vertex[k].y); 171 | if (max_angle < temp_angle) { 172 | max_angle = temp_angle; 173 | next_vertex = k; 174 | } 175 | } 176 | } 177 | return search_half_edge(e, next_vertex, half_edge); 178 | } 179 | 180 | float area_poly(vector key, vector vertex) { 181 | float x2, y2; 182 | float signedArea = 0; 183 | int l = key.size(); 184 | for (int i = 0; i < l; i++) { 185 | float x1 = vertex[key[i]].x; 186 | float y1 = vertex[key[i]].y; 187 | if (i == l - 1) { 188 | x2 = vertex[key[0]].x; 189 | y2 = vertex[key[0]].y; 190 | signedArea += (x1 * y2 - x2 * y1); 191 | } else { 192 | x2 = vertex[key[i + 1]].x; 193 | y2 = vertex[key[i + 1]].y; 194 | signedArea += (x1 * y2 - x2 * y1); 195 | } 196 | } 197 | return abs(signedArea / 2); 198 | } 199 | 200 | void fill_half_edge_face(vector &half_edge_table, 201 | vector &face, vector vertex, 202 | vector &face_table) { 203 | int l = half_edge_table.size(); 204 | int face_key = 0; 205 | int head = 0; 206 | float x2, y2; 207 | float signedArea = 0; 208 | for (int i = 0; i < l; i++) { 209 | float x1 = vertex[half_edge_table[i].half_edge->origin_v].x; 210 | float y1 = vertex[half_edge_table[i].half_edge->origin_v].y; 211 | if (half_edge_table[i].next == half_edge_table[head].half_edge) { 212 | x2 = vertex[half_edge_table[head].half_edge->origin_v].x; 213 | y2 = vertex[half_edge_table[head].half_edge->origin_v].y; 214 | signedArea += (x1 * y2 - x2 * y1); 215 | if (signedArea > 0) // Assuming no standalone edge 216 | { 217 | face_table[face_key].area = abs(signedArea / 2); 218 | face[face_key].key = face_key; 219 | face_table[face_key].face = &face[face_key]; 220 | face_table[face_key].outer_component = half_edge_table[head].half_edge; 221 | for (int j = head; j <= i; j++) 222 | half_edge_table[j].incident_face = &face[face_key]; 223 | face_key++; 224 | } 225 | signedArea = 0; 226 | head = i + 1; 227 | } else { 228 | x2 = vertex[half_edge_table[i].half_edge->end_v].x; 229 | y2 = vertex[half_edge_table[i].half_edge->end_v].y; 230 | signedArea += (x1 * y2 - x2 * y1); 231 | } 232 | } 233 | face[face_key].key = -1; 234 | face_table[face_key].face = &face[face_key]; 235 | } 236 | 237 | void fill_half_edge_table(vector &half_edge_table, 238 | vector &half_edge, 239 | vector &unvisited_half_edge, 240 | vector vertex, vector> adj, 241 | vector &face, vector &face_table) { 242 | int l = unvisited_half_edge.size(); 243 | int current, next, previous; 244 | int head, j = 0, head_index; 245 | for (int i = 0; i < l; i++) { 246 | if (unvisited_half_edge[i] == 0) { 247 | unvisited_half_edge[i] = 1; 248 | head = i; 249 | head_index = j; 250 | half_edge_table[j].half_edge = &half_edge[i]; 251 | next = next_half_edge(i, adj, vertex, half_edge); 252 | half_edge_table[j].next = &half_edge[next]; 253 | j++; 254 | previous = i; 255 | current = next; 256 | while (1) { 257 | unvisited_half_edge[current] = 1; 258 | half_edge_table[j].half_edge = &half_edge[current]; 259 | next = next_half_edge(current, adj, vertex, half_edge); 260 | half_edge_table[j].next = &half_edge[next]; 261 | half_edge_table[j].prev = &half_edge[previous]; 262 | j++; 263 | previous = current; 264 | current = next; 265 | if (next == head) { 266 | break; 267 | } 268 | } 269 | half_edge_table[head_index].prev = &half_edge[previous]; 270 | } 271 | } 272 | fill_half_edge_face(half_edge_table, face, vertex, face_table); 273 | } 274 | 275 | bool check_if_point_is_inside(int ver, vector key, 276 | vector &vertex) { 277 | float x, y; 278 | int n = key.size(); 279 | Point polygon1[n]; 280 | for (int i = 0; i < n; i++) { 281 | polygon1[i] = {vertex[key[i]].x, vertex[key[i]].y}; 282 | } 283 | Point p = {vertex[ver].x, vertex[ver].y}; 284 | return isInside(polygon1, n, p); 285 | } 286 | 287 | int check_if_inside(vector &face_table, vector &vertex, 288 | vector key, vector face, 289 | vector half_edge_table) { 290 | int face_index = -1; 291 | float self_area; 292 | int l = face_table.size(); 293 | class face_table temp; 294 | class half_edge *half_edge, *temp2, *head; 295 | float min_area = 100021.1; 296 | self_area = area_poly(key, vertex); 297 | for (int i = 0; i < l; i++) { 298 | if (face_table[i].face == NULL) 299 | break; 300 | temp = face_table[i]; 301 | half_edge = temp.outer_component; 302 | int index = search_half_edge_table(half_edge, half_edge_table); 303 | temp2 = half_edge_table[index].half_edge; 304 | head = temp2; 305 | vector key2; 306 | while (1) { 307 | key2.push_back(temp2->origin_v); 308 | temp2 = half_edge_table[index].next; 309 | if (head == temp2) 310 | break; 311 | index++; 312 | } 313 | bool flag = 1; 314 | for (int k = 0; k < key.size(); k++) { 315 | flag = flag & check_if_point_is_inside(key[k], key2, vertex); 316 | if (flag == 0) 317 | break; 318 | } 319 | if (flag) { 320 | float a = area_poly(key2, vertex); 321 | if (min_area > a && self_area != a && self_area < a) { 322 | min_area = a; 323 | face_index = i; 324 | } 325 | } 326 | } 327 | return face_index; 328 | } 329 | 330 | int search_outer_face(vector face) { 331 | for (int i = 0; i < face.size(); i++) { 332 | if (face[i].key == -1) 333 | return i; 334 | } 335 | return 0; 336 | } 337 | 338 | void fill_face_table_inner_components(vector &face_table, 339 | vector &half_edge, 340 | vector &half_edge_table, 341 | vector &face, 342 | vector vertex) { 343 | int face_index; 344 | int l = half_edge_table.size(); 345 | class half_edge *temp, *head; 346 | for (int i = 0; i < l; i++) { 347 | if (half_edge_table[i].incident_face != NULL) 348 | continue; 349 | temp = half_edge_table[i].half_edge; 350 | head = temp; 351 | vector key; 352 | while (1) { 353 | key.push_back(temp->origin_v); 354 | temp = half_edge_table[i].next; 355 | if (head == temp) { 356 | face_index = 357 | check_if_inside(face_table, vertex, key, face, half_edge_table); 358 | if (face_index != -1) { 359 | int index = search_half_edge_table(temp, half_edge_table); 360 | face_table[face_index].inner_components.push_back( 361 | half_edge_table[index].half_edge); 362 | while (1) { 363 | half_edge_table[index].incident_face = &face[face_index]; 364 | temp = half_edge_table[index].next; 365 | if (temp == head) 366 | break; 367 | index++; 368 | } 369 | } else { 370 | face_index = search_outer_face(face); 371 | int index = search_half_edge_table(temp, half_edge_table); 372 | face_table[face_index].inner_components.push_back( 373 | half_edge_table[index].half_edge); 374 | while (1) { 375 | half_edge_table[index].incident_face = &face[face_index]; 376 | temp = half_edge_table[index].next; 377 | if (temp == head) 378 | break; 379 | index++; 380 | } 381 | } 382 | 383 | break; 384 | } 385 | i++; 386 | } 387 | key.clear(); 388 | } 389 | } 390 | 391 | void print_vertex_table(vector &ver_tab, int l) { 392 | vertex *temp_v; 393 | half_edge *temp_e; 394 | cout << "\n" 395 | << "********** Vertex Table ***********" 396 | << "\n"; 397 | cout << "vertex " 398 | << " Coordinates " 399 | << "Incident Edge " 400 | << "\n"; 401 | for (int i = 0; i < l; i++) { 402 | temp_v = ver_tab[i].v; 403 | temp_e = ver_tab[i].e; 404 | cout << temp_v->key << "\t(" << temp_v->x << " , " << temp_v->y << ") "; 405 | cout << "\t" << temp_e->origin_v << "-" << temp_e->end_v << "\n"; 406 | } 407 | } 408 | 409 | void print_half_edge_table(vector &half_edge_table, 410 | vector &half_edge) { 411 | int l = half_edge_table.size(); 412 | class half_edge_table temp; 413 | cout << "\n" 414 | << "********** Half Edge Table **********" 415 | << "\n"; 416 | cout << "Half-edge " 417 | << "Origin " 418 | << "Twin Incident_Face Next Previous" 419 | << "\n"; 420 | for (int i = 0; i < l; i++) { 421 | temp = half_edge_table[i]; 422 | cout << temp.half_edge->origin_v << "-" << temp.half_edge->end_v << "\t "; 423 | cout << temp.half_edge->origin_v << "\t"; 424 | cout << temp.half_edge->twin->origin_v << "-" << temp.half_edge->twin->end_v 425 | << "\t"; 426 | if (temp.incident_face != NULL) 427 | cout << " F" << temp.incident_face->key << "\t "; 428 | else 429 | cout << " NULL" 430 | << " "; 431 | cout << temp.next->origin_v << "-" << temp.next->end_v << " "; 432 | cout << temp.prev->origin_v << "-" << temp.prev->end_v << "\n"; 433 | } 434 | } 435 | 436 | void print_face_table(vector face_table) { 437 | int l = face_table.size(); 438 | class face_table temp; 439 | cout << "*************** Face_Table **************" 440 | << "\n"; 441 | cout << "Face Outer_component" 442 | << " Inner_Components" 443 | << "\n"; 444 | for (int i = 0; i < l; i++) { 445 | temp = face_table[i]; 446 | if (temp.face == NULL) 447 | break; 448 | if (temp.outer_component == NULL) { 449 | cout << "Finf" << setw(3) << "|" << setw(8) << "NULL" << setw(9) << "|" 450 | << setw(5); 451 | int n = temp.inner_components.size(); 452 | for (int j = 0; j < n; j++) 453 | cout << temp.inner_components[j]->origin_v << "-" 454 | << temp.inner_components[j]->end_v << " "; 455 | if (n == 0) 456 | cout << setw(5) << "NULL\t"; 457 | cout << "\n"; 458 | } else { 459 | cout << "F" << temp.face->key << setw(5) << "|" << setw(5) 460 | << temp.outer_component->origin_v << "-" 461 | << temp.outer_component->end_v; 462 | cout << setw(10) << "|" << setw(5); 463 | int n = temp.inner_components.size(); 464 | for (int j = 0; j < n; j++) 465 | cout << temp.inner_components[j]->origin_v << "-" 466 | << temp.inner_components[j]->end_v << "\t"; 467 | if (n == 0) 468 | cout << " NULL"; 469 | cout << "\n"; 470 | } 471 | } 472 | } 473 | 474 | int search_face_table(int key, vector &face_table) { 475 | for (int i = 0; i < face_table.size(); i++) { 476 | if (face_table[i].face->key == key) 477 | return i; 478 | } 479 | 480 | cout << "Error in search_face_table" << endl; 481 | return -1; 482 | } 483 | 484 | void print_faces_with_area_lessthan_threshhold( 485 | float threshhold_area, vector &face_table, 486 | vector half_edge_table, 487 | vector vertex) { 488 | class face_table temp = face_table[0]; 489 | int i = 0; 490 | // cout<<"*****Area of faces******"< inner_edges = temp.inner_components; 496 | float area = temp.area; 497 | for (int i = 0; i < inner_edges.size(); i++) { 498 | int index = search_half_edge_table(inner_edges[i], half_edge_table); 499 | class half_edge *temp2 = half_edge_table[index].half_edge, *head; 500 | head = temp2; 501 | vector key; 502 | 503 | while (1) { 504 | key.push_back(temp2->origin_v); 505 | temp2 = half_edge_table[index].next; 506 | 507 | if (head == temp2) 508 | break; 509 | index++; 510 | } 511 | area -= area_poly(key, vertex); 512 | } 513 | 514 | // cout<<"F "<key<<" "< 0) 517 | cout << "F" << temp.face->key << ", less than threshhold.\n"; 518 | i++; 519 | temp = face_table[i]; 520 | } 521 | } 522 | 523 | void print_neighbouring_faces(float x, float y, 524 | vector &half_edge_vector, 525 | vector &half_edge_table, 526 | vector &face_table) { 527 | class half_edge *half_edge, *head, *temp; 528 | map m; 529 | int index = search_half_edge(x, y, half_edge_vector); 530 | half_edge = &half_edge_vector[index]; 531 | index = search_half_edge_table(half_edge, half_edge_table); 532 | int stored_index = index; 533 | int original_face = half_edge_table[stored_index].incident_face->key; 534 | if (original_face == -1) // For handling Outer boundary 535 | { 536 | int face_table_index = search_face_table(original_face, face_table); 537 | vector outer_component = 538 | face_table[face_table_index].inner_components; 539 | int index_inner; 540 | for (int k = 0; k < outer_component.size(); k++) { 541 | int outer_component_index = 542 | search_half_edge_table(outer_component[k], half_edge_table); 543 | index = outer_component_index; 544 | head = half_edge_table[outer_component_index].half_edge; 545 | temp = head; 546 | while (1) { 547 | temp = half_edge_table[outer_component_index].next; 548 | index_inner = search_half_edge_table(temp->twin, half_edge_table); 549 | m[half_edge_table[index_inner].incident_face->key] = 1; 550 | outer_component_index++; 551 | if (temp == head) 552 | break; 553 | } 554 | } 555 | for (auto j : m) { 556 | cout << "F" << j.first << endl; 557 | } 558 | return; 559 | } 560 | int face_table_index = search_face_table(original_face, face_table); 561 | class half_edge *outer_component = 562 | face_table[face_table_index].outer_component; 563 | int outer_component_index = 564 | search_half_edge_table(outer_component, half_edge_table); 565 | index = outer_component_index; 566 | head = half_edge_table[outer_component_index].half_edge; 567 | temp = head; 568 | bool flag = 0; 569 | while (1) { 570 | temp = half_edge_table[outer_component_index].half_edge; 571 | if (temp == half_edge_table[stored_index].half_edge) { 572 | flag = 1; 573 | break; 574 | } 575 | outer_component_index++; 576 | if (temp == head) 577 | break; 578 | } 579 | // cout << flag <<"\n"; 580 | int indext; 581 | if (flag) { // For handaling outer edge 582 | head = half_edge_table[index].half_edge; 583 | temp = head; 584 | while (1) { 585 | indext = search_half_edge_table(temp->twin, half_edge_table); 586 | m[half_edge_table[indext].incident_face->key] = 1; 587 | temp = half_edge_table[index].next; 588 | if (temp == head) 589 | break; 590 | index++; 591 | } 592 | vector inner_components = 593 | face_table[face_table_index].inner_components; 594 | 595 | for (int i = 0; i < inner_components.size(); i++) { 596 | index = 597 | search_half_edge_table(inner_components[i]->twin, half_edge_table); 598 | m[half_edge_table[index].incident_face->key] = 1; 599 | } 600 | for (auto j : m) { 601 | cout << "F" << j.first << endl; 602 | } 603 | } else { 604 | print_neighbouring_faces(outer_component->origin_v, outer_component->end_v, 605 | half_edge_vector, half_edge_table, face_table); 606 | } 607 | } 608 | 609 | int main() { 610 | int edges, nodes; 611 | float x, y; 612 | cout << "No. of vertices : "; 613 | cin >> nodes; 614 | cout << "No. of edges : "; 615 | cin >> edges; 616 | vector vertex(nodes); 617 | vector h(2 * edges); 618 | vector ver_tab(nodes); 619 | vector half_edge_table(2 * edges); 620 | vector> adj(nodes); 621 | vector unvisited_half_edge(2 * edges); 622 | vector face(nodes); 623 | vector face_table(nodes); 624 | 625 | for (int i = 0; i < nodes; i++) { 626 | cout << "Coordinates of " << i << " vertex : "; 627 | cin >> x >> y; 628 | vertex[i].key = i; 629 | vertex[i].x = x; 630 | vertex[i].y = y; 631 | } 632 | for (int i = 0; i < edges; i++) { 633 | cin >> x >> y; 634 | adj[x].push_back(y); 635 | adj[y].push_back(x); 636 | h[2 * i].origin_v = x; 637 | h[2 * i].end_v = y; 638 | h[2 * i].origin = &vertex[x]; 639 | h[2 * i].end = &vertex[y]; 640 | h[2 * i + 1].origin_v = y; 641 | h[2 * i + 1].end_v = x; 642 | h[2 * i + 1].origin = &vertex[y]; 643 | h[2 * i + 1].end = &vertex[x]; 644 | h[2 * i].twin = &h[2 * i + 1]; 645 | h[2 * i + 1].twin = &h[2 * i]; 646 | } 647 | fill_vertex_table(ver_tab, nodes, adj, h, vertex); 648 | fill_half_edge_table(half_edge_table, h, unvisited_half_edge, vertex, adj, 649 | face, face_table); 650 | fill_face_table_inner_components(face_table, h, half_edge_table, face, 651 | vertex); 652 | // print_half_edge(h , vertex , 2*edges); 653 | print_vertex_table(ver_tab, nodes); 654 | print_half_edge_table(half_edge_table, h); 655 | print_face_table(face_table); 656 | 657 | cout << "Enter the thresh hold area: "; 658 | float threshold_area; 659 | cin >> threshold_area; 660 | print_faces_with_area_lessthan_threshhold(threshold_area, face_table, 661 | half_edge_table, vertex); 662 | 663 | cout << "Enter the name of Half Edge: "; 664 | cin >> x >> y; 665 | print_neighbouring_faces(x, y, h, half_edge_table, face_table); 666 | return 0; 667 | } 668 | --------------------------------------------------------------------------------