├── .gitignore
├── BOUNDARY_CONTOURS.png
├── README.md
├── TRIANGLES.png
├── exsample
└── gdi
│ ├── console.sln
│ ├── console.vcxproj
│ ├── console.vcxproj.user
│ ├── main.cpp
│ ├── window.cpp
│ └── window.h
└── tesselator
├── detail
├── cdt.inl
├── dict.hpp
├── geometry.hpp
├── mesh.hpp
├── mono.hpp
├── normal.inl
├── public.h
├── sweep.hpp
└── sweep.inl
└── tesselator.hpp
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
--------------------------------------------------------------------------------
/BOUNDARY_CONTOURS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/BOUNDARY_CONTOURS.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tesselator
2 |
3 | https://github.com/sdragonx/libtess
4 |
5 | this is refactored version of the original libtess which comes with the GLU reference implementation.
6 | this is C++ version(c++98), Using STL as memory pool.
7 | Independent version without any third-party libraries, header files only.
8 |
9 | 重构版本的 gluTesselation 库,C++98 版本,使用了 STL 容器做内存缓存。
10 | 不依赖任何三方库,独立版本,只需要引用头文件就能使用。
11 |
12 | 琢磨了几个月,这次心血来潮,重构了代码,用了十来天时间(记不清了)。
13 | 原版本是个C库,到处是跳转和 #define,要把这些分散的函数封装成类,难度颇大,改动一处错误百出。
14 | libtess2 作者对原代码重构过一次,但还是 C 版本,而且整体结构变动不大。
15 | 这次重构,看着 libtess2 的代码,又看着原版代码,为了查找错误,前后对照了几遍!吐血!
16 | 这次重构成 C++ 版本,是第一步,之后会进行后续优化。
17 |
18 | 也很纳闷,这么多年了,没有人重做一个OpenGL的三角形分解库,一直是 SGI 的这个 libtess。
19 | GPC 简单易用,但是开源协议不友好;poly2tri 比 libtess快,但效果不如 libtess 好,有时候很不稳定。
20 | 希望我这个代码做个好的开头,有人能构建出更好更快的库,同时开源协议要友好。
21 |
22 | For OpenGL, For Open source !!!
23 |
24 | # main class:
25 |
26 | class Tesselator
27 | {
28 | int init();
29 | void dispose();
30 | int add_contour( int size, const void* pointer, int stride, int count );
31 | int tesselate( TessWindingRule windingRule, TessElementType elementType, int polySize = 3);
32 | };
33 |
34 | # Exsample:
35 |
36 |
37 | #define LIBTESS_USE_VEC2
38 |
39 | #include
40 | #include
41 |
42 | struct vec2f
43 | {
44 | float x, y;
45 | };
46 |
47 | //tesselate polygons
48 | libtess::Tesselator tess;
49 | tess.init();
50 |
51 | std::vector points;
52 | //points.push_back(...)//add some points
53 | tess.add_contour( 2, &points[0], sizeof(Vec2), points.size() );
54 | //tess.AddContour( ... );
55 | tess.Tesselate( libtess::TESS_WINDING_ODD, libtess::TESS_TRIANGLES );
56 |
57 | //OpenGL drawing:
58 | void draw_elements(int shape, const Vec2* vs, const int* indices, int size)
59 | {
60 | #ifdef LIBTESS_HIGH_PRECISION
61 | glVertexPointer(2, GL_DOUBLE, sizeof(Vec2), vs);
62 | #else
63 | glVertexPointer(2, GL_FLOAT, sizeof(Vec2), vs);
64 | #endif
65 | glEnableClientState(GL_VERTEX_ARRAY);
66 | glDrawElements(shape, size, GL_UNSIGNED_INT, indices);
67 | glDisableClientState(GL_VERTEX_ARRAY);
68 | }
69 |
70 | draw_elements(CGL_TRIANGLES, &tess.vertices[0], &tess.elements[0], tess.elements.size());
71 |
72 |
73 | TESS_TRIANGLES执行结果:
74 | 
75 | TESS_BOUNDARY_CONTOURS执行结果:
76 | 
77 |
78 |
--------------------------------------------------------------------------------
/TRIANGLES.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/TRIANGLES.png
--------------------------------------------------------------------------------
/exsample/gdi/console.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26228.4
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "console.vcxproj", "{ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Debug|x64.ActiveCfg = Debug|x64
17 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Debug|x64.Build.0 = Debug|x64
18 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Debug|x86.ActiveCfg = Debug|Win32
19 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Debug|x86.Build.0 = Debug|Win32
20 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Release|x64.ActiveCfg = Release|x64
21 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Release|x64.Build.0 = Release|x64
22 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Release|x86.ActiveCfg = Release|Win32
23 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/exsample/gdi/console.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {ED3F6BC6-BDE5-47C7-9B13-239EBB5B6D4A}
24 | Win32Proj
25 | ConsoleApplication1
26 | 10.0.14393.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v141
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v141
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v141
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v141
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 | bin\$(Platform)\
76 | $(ExecutablePath)
77 | include;$(IncludePath)
78 | lib;$(LibraryPath)
79 | obj\$(Platform)\
80 |
81 |
82 | true
83 | bin\$(Platform)\
84 | $(ExecutablePath)
85 | include;$(IncludePath)
86 | lib;$(LibraryPath)
87 | obj\$(Platform)\
88 |
89 |
90 | false
91 | $(ExecutablePath)
92 | include;$(IncludePath)
93 | lib;$(LibraryPath)
94 | bin\$(Platform)\
95 | obj\$(Platform)\
96 |
97 |
98 | false
99 | $(ExecutablePath)
100 | include;$(IncludePath)
101 | lib;$(LibraryPath)
102 | bin\$(Platform)\
103 | obj\$(Platform)\
104 |
105 |
106 |
107 | NotUsing
108 | Level3
109 | Disabled
110 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE
111 |
112 |
113 | Console
114 |
115 |
116 |
117 |
118 | NotUsing
119 | Level3
120 | Disabled
121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE
122 |
123 |
124 | Console
125 |
126 |
127 |
128 |
129 | Level3
130 | NotUsing
131 | MaxSpeed
132 | true
133 | true
134 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE
135 |
136 |
137 | Console
138 | true
139 | true
140 |
141 |
142 |
143 |
144 | Level3
145 | NotUsing
146 | MaxSpeed
147 | true
148 | true
149 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE
150 |
151 |
152 | Console
153 | true
154 | true
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/exsample/gdi/console.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(TargetDir)
5 | WindowsLocalDebugger
6 |
7 |
8 | $(TargetDir)
9 | WindowsLocalDebugger
10 |
11 |
12 | $(TargetDir)
13 | WindowsLocalDebugger
14 |
15 |
16 | $(TargetDir)
17 | WindowsLocalDebugger
18 |
19 |
--------------------------------------------------------------------------------
/exsample/gdi/main.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/exsample/gdi/main.cpp
--------------------------------------------------------------------------------
/exsample/gdi/window.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 |
3 | #include "Window.h"
4 |
5 | static HWND hWindow; // 主窗口
6 | static UINT uTimerID = 0; // 计时器 ID
7 | static HDC hMemDC; // 绘图设备
8 | static HBITMAP hBackBuffer; // 背景缓冲图片
9 | static HFONT hFont; // 字体
10 |
11 | // 主消息处理函数
12 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
13 |
14 | // 初始化函数
15 | void OnWMCreate(HWND hWnd);
16 |
17 | // 释放函数
18 | void OnWMDestroy(HWND hWnd);
19 |
20 | // 窗口大小改变
21 | void OnWMResize(HWND hWnd, int width, int height);
22 |
23 | // 内部绘制函数
24 | void OnWMPaint(HWND hWnd);
25 |
26 | // 返回窗口句柄
27 | HWND Window()
28 | {
29 | return hWindow;
30 | }
31 |
32 | // 窗口创建函数
33 | HWND InitWindow(LPCTSTR title, int width, int height, bool scalable)
34 | {
35 | HWND hWnd;
36 | HINSTANCE hInstance = GetModuleHandle(NULL);
37 |
38 | WNDCLASSEX wc = { 0 };
39 | wc.cbSize = sizeof(WNDCLASSEX);
40 | wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
41 | wc.lpfnWndProc = WindowProc;
42 | wc.hInstance = hInstance;
43 | wc.hIcon = LoadIconW(hInstance, L"ICO_MAIN");
44 | wc.hCursor = LoadCursor(NULL, IDC_ARROW);
45 | wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
46 | wc.lpszMenuName = NULL;
47 | wc.lpszClassName = CLASSNAME;
48 | wc.hIconSm = LoadIconW(hInstance, L"ICO_MAIN");
49 |
50 | if (!RegisterClassEx(&wc)) {
51 | return NULL;
52 | }
53 |
54 | DWORD style;
55 | if (scalable) {
56 | // 窗口可以缩放
57 | style = WS_OVERLAPPEDWINDOW;
58 | }
59 | else {
60 | // 固定大小窗口
61 | style = WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION;
62 | }
63 |
64 | RECT rect = { 0, 0, static_cast(width), static_cast(height) };
65 | AdjustWindowRectEx(&rect, style, FALSE, WS_EX_CLIENTEDGE);
66 | width = static_cast(rect.right - rect.left);
67 | height = static_cast(rect.bottom - rect.top);
68 |
69 | hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, CLASSNAME, title, style,
70 | CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL);
71 |
72 | if (hWnd) {
73 | ShowWindow(hWnd, SW_SHOW);
74 | }
75 |
76 | return hWnd;
77 | }
78 |
79 | // 主消息处理函数
80 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
81 | {
82 | switch (Message) {
83 | case WM_CREATE:
84 | OnWMCreate(hWnd);
85 | break;
86 | case WM_DESTROY:
87 | OnWMDestroy(hWnd);
88 | break;
89 | case WM_CLOSE:
90 | //OutputDebugStringA("WM_CLOSE\n");
91 | PostQuitMessage(0);
92 | break;
93 | case WM_QUIT:
94 | //OutputDebugStringA("WM_QUIT\n");
95 | break;
96 | case WM_ERASEBKGND:// 不擦除背景
97 | return TRUE;
98 | case WM_SIZE:// 窗口大小改变
99 | OnWMResize(hWnd, LOWORD(lParam), HIWORD(lParam));
100 | break;
101 | case WM_PAINT:// 窗口绘制事件
102 | OnWMPaint(hWnd);
103 | break;
104 | case WM_TIMER:// 计时器事件
105 | OnTimer();
106 | Repaint(hWnd);
107 | break;
108 |
109 | case WM_KEYDOWN:
110 | if (wParam == VK_ESCAPE)PostQuitMessage(0);
111 | if (OnKeyDown)OnKeyDown(int(wParam));
112 | break;
113 | case WM_KEYUP:
114 | if (OnKeyUp)OnKeyUp(int(wParam));
115 | break;
116 |
117 | case WM_MOUSEMOVE:
118 | OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
119 | break;
120 | case WM_LBUTTONDOWN:
121 | OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), VK_LBUTTON);
122 | break;
123 | case WM_LBUTTONUP:
124 | OnMouseUp(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), VK_LBUTTON);
125 | break;
126 | case WM_RBUTTONDOWN:
127 | OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), VK_RBUTTON);
128 | break;
129 | case WM_RBUTTONUP:
130 | OnMouseUp(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), VK_RBUTTON);
131 | break;
132 |
133 | default:
134 | break;
135 | }
136 | return DefWindowProc(hWnd, Message, wParam, lParam);
137 | }
138 |
139 | // 重绘窗口
140 | void Repaint(HWND hwnd)
141 | {
142 | RECT rect;
143 | GetClientRect(hwnd, &rect);
144 | RedrawWindow(hwnd, &rect, 0, RDW_INVALIDATE | RDW_NOERASE | RDW_UPDATENOW);
145 | }
146 |
147 | // 执行消息循环
148 | void DoEvents()
149 | {
150 | MSG msg;
151 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
152 | if (!TranslateAccelerator(msg.hwnd, NULL, &msg)) {
153 | TranslateMessage(&msg);
154 | DispatchMessage(&msg);
155 | }
156 | }
157 | }
158 |
159 | // 判断程序是否运行
160 | bool Running()
161 | {
162 | return hWindow != NULL;
163 | }
164 |
165 | // 运行 APP
166 | int RunApp()
167 | {
168 | MSG msg;
169 |
170 | // 主消息循环:
171 | while (GetMessage(&msg, NULL, 0, 0)) {
172 | if (!TranslateAccelerator(msg.hwnd, NULL, &msg)) {
173 | TranslateMessage(&msg);
174 | DispatchMessage(&msg);
175 | }
176 | }
177 | return 0;
178 | }
179 |
180 | // 初始化函数
181 | void OnWMCreate(HWND hWnd)
182 | {
183 | hWindow = hWnd;
184 |
185 | // 获取窗口客户区大小
186 | RECT rect;
187 | GetClientRect(hWnd, &rect);
188 |
189 | // 创建内存 DC 和背景缓冲位图
190 | hMemDC = CreateCompatibleDC(NULL);
191 | hBackBuffer = CreateBitmap(rect.right - rect.left, rect.bottom - rect.top, 1, 32, NULL);
192 | SelectObject(hMemDC, hBackBuffer);
193 |
194 | // 创建字体
195 | hFont = CreateFont(32, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET, 0, 0, 0, DEFAULT_PITCH, TEXT("msyh"));
196 |
197 | // 选择字体
198 | SelectObject(hMemDC, hFont);
199 |
200 | // 字体透明
201 | SetBkMode(hMemDC, TRANSPARENT);
202 |
203 | // 设置计时器
204 | uTimerID = SetTimer(hWnd, 0, 40, NULL);
205 | }
206 |
207 | // 释放函数
208 | void OnWMDestroy(HWND hWnd)
209 | {
210 | if (uTimerID) {
211 | KillTimer(hWnd, uTimerID);
212 | uTimerID = 0;
213 | }
214 |
215 | // 删除双缓冲
216 | DeleteObject(hBackBuffer);
217 | DeleteDC(hMemDC);
218 | // 删除字体
219 | DeleteObject(hFont);
220 |
221 | // 退出消息
222 | //PostQuitMessage(0);
223 |
224 | hWindow = NULL;
225 | }
226 |
227 | // 窗口大小改变
228 | void OnWMResize(HWND hWnd, int width, int height)
229 | {
230 | // 重建绘图缓冲区
231 | RECT rect;
232 | GetClientRect(hWnd, &rect);
233 |
234 | // 创建内存 DC 和背景缓冲位图
235 | if (hBackBuffer) {
236 | DeleteObject(hBackBuffer);
237 | }
238 | hBackBuffer = CreateBitmap(rect.right - rect.left, rect.bottom - rect.top, 1, 32, NULL);
239 | SelectObject(hMemDC, hBackBuffer);
240 | }
241 |
242 | // 内部绘制函数
243 | void OnWMPaint(HWND hWnd)
244 | {
245 | PAINTSTRUCT ps;
246 | HDC hdc = BeginPaint(hWnd, &ps);
247 | RECT rect;
248 |
249 | // 获取窗口内部区域大小
250 | GetClientRect(hWnd, &rect);
251 |
252 | // 创建背景画刷
253 | HBRUSH brush = CreateSolidBrush(0xFF8000);
254 |
255 | // 填充背景
256 | FillRect(hMemDC, &rect, brush);
257 |
258 | // 删除画刷
259 | DeleteObject(brush);
260 |
261 | // 绘制游戏,用背景缓冲的 HDC
262 | OnPaint(hMemDC, rect);
263 |
264 | // 背景缓冲绘制到窗口 dc
265 | BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hMemDC, 0, 0, SRCCOPY);
266 |
267 | // 释放窗口 dc
268 | ReleaseDC(hWnd, hdc);
269 |
270 | EndPaint(hWnd, &ps);
271 | }
272 |
273 | // 显示消息对话框
274 | void msgbox(PCTSTR param, ...)
275 | {
276 | TCHAR buf[1024] = {};
277 | va_list body;
278 | va_start(body, param);
279 | _vsntprintf(buf, 1024, param, body);
280 | va_end(body);
281 |
282 | MessageBox(hWindow, buf, TEXT("消息"), MB_OK);
283 | }
284 |
--------------------------------------------------------------------------------
/exsample/gdi/window.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 |
3 | #ifndef WIN32_WINDOW_H
4 | #define WIN32_WINDOW_H
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #define CLASSNAME TEXT("win32.window")
12 |
13 | // 返回窗口句柄
14 | HWND Window();
15 |
16 | // 窗口创建函数
17 | HWND InitWindow(LPCTSTR title, int width, int height, bool scalable = true);
18 |
19 | // 重绘窗口
20 | void Repaint(HWND hWnd);
21 |
22 | // 判断程序是否运行
23 | bool Running();
24 |
25 | // 执行消息循环
26 | void DoEvents();
27 |
28 | // 运行 APP
29 | int RunApp();
30 |
31 | //
32 | // 窗口事件
33 | //
34 |
35 | // 窗口大小改变
36 | void OnSize(int width, int height);
37 |
38 | // 按键按下
39 | void OnKeyDown(int key);
40 |
41 | // 按键弹起
42 | void OnKeyUp(int key);
43 |
44 | // 鼠标按下
45 | void OnMouseDown(int x, int y, int button);
46 |
47 | // 鼠标弹起
48 | void OnMouseUp(int x, int y, int button);
49 |
50 | // 鼠标移动
51 | void OnMouseMove(int x, int y);
52 |
53 | // 计时器事件
54 | void OnTimer();
55 |
56 | // 窗口绘制事件
57 | void OnPaint(HDC hdc, const RECT& rect);
58 |
59 | //
60 | // 辅助函数
61 | //
62 |
63 | // 显示消息对话框
64 | void msgbox(PCTSTR param, ...);
65 |
66 | //---------------------------------------------------------------------------
67 | #endif //WIN32_WINDOW_H
68 |
--------------------------------------------------------------------------------
/tesselator/detail/cdt.inl:
--------------------------------------------------------------------------------
1 | #ifndef LIBTESS_CDT_HPP
2 | #define LIBTESS_CDT_HPP
3 |
4 | #include "mesh.hpp"
5 |
6 | namespace libtess {
7 |
8 | /* Starting with a valid triangulation, uses the Edge Flip algorithm to
9 | * refine the triangulation into a Constrained Delaunay Triangulation.
10 | */
11 | LIBTESS_INLINE void Tesselator::MeshRefineDelaunay(Mesh *mesh)
12 | {
13 | /* At this point, we have a valid, but not optimal, triangulation.
14 | * We refine the triangulation using the Edge Flip algorithm
15 | *
16 | * 1) Find all internal edges
17 | * 2) Mark all dual edges
18 | * 3) insert all dual edges into a queue
19 | */
20 |
21 | Face *f;
22 | std::stack stack;
23 | HalfEdge *e;
24 | int maxFaces = 0, maxIter = 0, iter = 0;
25 |
26 | for (f = mesh->m_faceHead.next; f != &mesh->m_faceHead; f = f->next) {
27 | if (f->inside) {
28 | e = f->edge;
29 | do {
30 | e->mark = EdgeIsInternal(e); // Mark internal edges
31 | if (e->mark && !e->mirror->mark) stack.push(e); // Insert into queue
32 | e = e->Lnext;
33 | } while (e != f->edge);
34 | maxFaces++;
35 | }
36 | }
37 |
38 | /* The algorithm should converge on O(n^2), since the predicate is not robust,
39 | * we'll save guard against infinite loop.
40 | */
41 | maxIter = maxFaces * maxFaces;
42 |
43 | /* Pop stack until we find a reversed edge
44 | * Flip the reversed edge, and insert any of the four opposite edges
45 | * which are internal and not already in the stack (!marked)
46 | */
47 | while (!stack.empty() && iter < maxIter) {
48 | e = stack.top();
49 | stack.pop();
50 | e->mark = e->mirror->mark = 0;
51 | if (!EdgeIsLocallyDelaunay(e)) {
52 | HalfEdge *edges[4];
53 | int i;
54 | mesh->FlipEdge(e);
55 | // for each opposite edge
56 | edges[0] = e->Lnext;
57 | edges[1] = e->Onext->mirror;
58 | edges[2] = e->mirror->Lnext;
59 | edges[3] = e->mirror->Onext->mirror;
60 | for (i = 0; i < 4; i++) {
61 | if (!edges[i]->mark && EdgeIsInternal(edges[i])) {
62 | edges[i]->mark = edges[i]->mirror->mark = 1;
63 | stack.push(edges[i]);
64 | }
65 | }
66 | }
67 | iter++;
68 | }
69 | }
70 |
71 | #if 0
72 |
73 | Index Tesselator::GetNeighbourFace(HalfEdge* edge)
74 | {
75 | if (!edge->mirror->Lface)
76 | return INVALID_INDEX;
77 | if (!edge->mirror->Lface->inside)
78 | return INVALID_INDEX;
79 | return edge->mirror->Lface->n;
80 | }
81 |
82 | int Tesselator::OutputPolymesh(int elementType, int polySize)
83 | {
84 | Vertex* v = 0;
85 | Face* f = 0;
86 | HalfEdge* edge = 0;
87 | int maxFaceCount = 0;
88 | int maxVertexCount = 0;
89 | int faceVerts, i;
90 | Index *elements = 0;
91 |
92 | /* Assume that the input data is triangles now.
93 | * Try to merge as many polygons as possible
94 | */
95 | if (polySize > 3) {
96 | if (!mesh.MergeConvexFaces(polySize)) {
97 | return LIBTESS_ERROR;
98 | }
99 | }
100 |
101 | // Mark unused
102 | for (v = mesh.m_vtxHead.next; v != &mesh.m_vtxHead; v = v->next)
103 | v->n = INVALID_INDEX;
104 |
105 | // Create unique IDs for all vertices and faces.
106 | for (f = mesh.m_faceHead.next; f != &mesh.m_faceHead; f = f->next) {
107 | f->n = INVALID_INDEX;
108 | if (!f->inside) continue;
109 |
110 | edge = f->edge;
111 | faceVerts = 0;
112 | do {
113 | v = edge->vertex;
114 | if (v->n == INVALID_INDEX) {
115 | v->n = maxVertexCount;
116 | maxVertexCount++;
117 | }
118 | faceVerts++;
119 | edge = edge->Lnext;
120 | } while (edge != f->edge);
121 |
122 | assert(faceVerts <= polySize);
123 |
124 | f->n = maxFaceCount;
125 | ++maxFaceCount;
126 | }
127 |
128 | //int elementCount = maxFaceCount;
129 | if (elementType == TESS_CONNECTED_POLYGONS)
130 | maxFaceCount *= 2;
131 | //tess->elements = (Index*)tess->alloc.memalloc( tess->alloc.userData,sizeof(Index) * maxFaceCount * polySize );
132 | this->elements.resize(maxFaceCount * polySize);
133 |
134 |
135 | int vertexCount = maxVertexCount;
136 | //tess->vertices = (TESSreal*)tess->alloc.memalloc( tess->alloc.userData, sizeof(TESSreal) * tess->vertexCount * vertexSize );
137 | this->vertices.resize(vertexCount);
138 |
139 | //tess->vertexIndices = (Index*)tess->alloc.memalloc( tess->alloc.userData, sizeof(Index) * tess->vertexCount );
140 | this->indices.resize(vertexCount);
141 |
142 | // Output vertices.
143 | for (v = mesh.m_vtxHead.next; v != &mesh.m_vtxHead; v = v->next) {
144 | if (v->n != INVALID_INDEX) {
145 | // Store coordinate
146 | #ifdef LIBTESS_USE_VEC3
147 | this->vertices[v->n].x = v->coords.x;
148 | this->vertices[v->n].y = v->coords.y;
149 | this->vertices[v->n].z = v->coords.z;
150 | #else
151 | this->vertices[v->n].x = v->coords.x;
152 | this->vertices[v->n].y = v->coords.y;
153 | #endif
154 |
155 | // Store vertex index.
156 | this->indices[v->n] = v->idx;
157 | }
158 | }
159 |
160 | // Output indices.
161 | elements = &this->elements[0];
162 | for (f = mesh.m_faceHead.next; f != &mesh.m_faceHead; f = f->next) {
163 | if (!f->inside) continue;
164 |
165 | // Store polygon
166 | edge = f->edge;
167 | faceVerts = 0;
168 | do {
169 | v = edge->vertex;
170 | *elements++ = v->n;
171 | faceVerts++;
172 | edge = edge->Lnext;
173 | } while (edge != f->edge);
174 |
175 | // Fill unused.
176 | for (i = faceVerts; i < polySize; ++i) {
177 | *elements++ = INVALID_INDEX;
178 | }
179 |
180 | // Store polygon connectivity
181 | if (elementType == TESS_CONNECTED_POLYGONS) {
182 | edge = f->edge;
183 | do {
184 | *elements++ = GetNeighbourFace(edge);
185 | edge = edge->Lnext;
186 | } while (edge != f->edge);
187 | // Fill unused.
188 | for (i = faceVerts; i < polySize; ++i) {
189 | *elements++ = INVALID_INDEX;
190 | }
191 | }
192 | }
193 |
194 | return LIBTESS_OK;
195 | }
196 |
197 | #endif
198 |
199 | }// end namespace libtess
200 |
201 | #endif //LIBTESS_CDT_HPP
202 |
--------------------------------------------------------------------------------
/tesselator/detail/dict.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 | * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a
6 | * copy of this software and associated documentation files (the "Software"),
7 | * to deal in the Software without restriction, including without limitation
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | * and/or sell copies of the Software, and to permit persons to whom the
10 | * Software is furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice including the dates of first publication and
13 | * either this permission notice or a reference to
14 | * http://oss.sgi.com/projects/FreeB/
15 | * shall be included in all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 | * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | *
25 | * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 | * shall not be used in advertising or otherwise to promote the sale, use or
27 | * other dealings in this Software without prior written authorization from
28 | * Silicon Graphics, Inc.
29 | */
30 | /*
31 | ** Author: Eric Veach, July 1994.
32 | **
33 | */
34 |
35 | #ifndef LIBTESS_DICT_HPP
36 | #define LIBTESS_DICT_HPP
37 |
38 | #include "public.h"
39 |
40 | namespace libtess {
41 |
42 | //
43 | // Dist
44 | //
45 |
46 | typedef void *DictKey;
47 |
48 | typedef int (*PFN_DICTKEY_COMPARE)(void *frame, DictKey key1, DictKey key2);
49 |
50 | struct DictNode
51 | {
52 | DictKey key;
53 | DictNode *next;
54 | DictNode *prev;
55 |
56 | DictNode() : key(), next(), prev() {}
57 | };
58 |
59 | class Dict
60 | {
61 | protected:
62 | //head.next == first node;
63 | //head.prev == last node
64 | DictNode head;
65 | void *frame;
66 | PFN_DICTKEY_COMPARE comp;
67 |
68 | pool poolbuf;
69 |
70 | public:
71 | Dict();
72 | ~Dict();
73 |
74 | void init(void *_frame, PFN_DICTKEY_COMPARE pfn);
75 | void dispose();
76 |
77 | DictNode* insert(DictNode *node, DictKey key);
78 | DictNode* insert(DictKey key) { return this->insert(&head, key); }
79 | void erase(DictNode *node);
80 | DictNode* find(DictKey key);
81 | DictNode* min();
82 | DictNode* max();
83 |
84 | protected:
85 | DictNode* allocate()
86 | {
87 | #ifdef LIBTESS_USE_POOL
88 | return poolbuf.allocate();
89 | #else
90 | return new DictNode;
91 | #endif
92 | }
93 |
94 | void deallocate(DictNode* n)
95 | {
96 | #ifdef LIBTESS_USE_POOL
97 | poolbuf.deallocate(n);
98 | #else
99 | delete n;
100 | #endif
101 | }
102 | };
103 |
104 | //
105 | // source
106 | //
107 |
108 | // DictKey
109 |
110 | LIBTESS_INLINE DictKey dictKey(DictNode* n)
111 | {
112 | return n->key;
113 | }
114 |
115 | // Dict
116 |
117 | LIBTESS_INLINE Dict::Dict() : head(), frame(), comp()
118 | {
119 |
120 | }
121 |
122 | LIBTESS_INLINE Dict::~Dict()
123 | {
124 | this->dispose();
125 | }
126 |
127 | LIBTESS_INLINE void Dict::init(void *_frame, PFN_DICTKEY_COMPARE pfn)
128 | {
129 | head.key = NULL;
130 | head.next = &head;
131 | head.prev = &head;
132 |
133 | frame = _frame;
134 | comp = pfn;
135 | }
136 |
137 | LIBTESS_INLINE void Dict::dispose()
138 | {
139 | #ifdef LIBTESS_USE_POOL
140 | poolbuf.dispose();
141 | #else
142 | DictNode* node = head.next;
143 | DictNode* next;
144 | while (node && node != &head) {
145 | next = node->next;
146 | delete node;
147 | node = next;
148 | }
149 | #endif
150 | }
151 |
152 | LIBTESS_INLINE DictNode * Dict::insert(DictNode *node, DictKey key)
153 | {
154 | DictNode *newNode;
155 |
156 | do {
157 | node = node->prev;
158 | } while (node->key != NULL && !(*comp)(frame, node->key, key));
159 |
160 | newNode = this->allocate();
161 | if (newNode == NULL) return NULL;
162 |
163 | newNode->key = key;
164 | newNode->next = node->next;
165 | node->next->prev = newNode;
166 | newNode->prev = node;
167 | node->next = newNode;
168 |
169 | return newNode;
170 | }
171 |
172 | LIBTESS_INLINE void Dict::erase(DictNode *node)
173 | {
174 | node->next->prev = node->prev;
175 | node->prev->next = node->next;
176 | this->deallocate(node);
177 | }
178 |
179 | LIBTESS_INLINE DictNode * Dict::find(DictKey key)
180 | {
181 | DictNode *node = &head;
182 |
183 | do {
184 | node = node->next;
185 | } while (node->key != NULL && !(*comp)(frame, key, node->key));
186 |
187 | return node;
188 | }
189 |
190 | LIBTESS_INLINE DictNode* Dict::min()
191 | {
192 | return head.next;
193 | }
194 |
195 | LIBTESS_INLINE DictNode* Dict::max()
196 | {
197 | return head.prev;
198 | }
199 |
200 | }// end namespace libtess
201 |
202 | #endif// LIBTESS_DICT_HPP
203 |
--------------------------------------------------------------------------------
/tesselator/detail/geometry.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/geometry.hpp
--------------------------------------------------------------------------------
/tesselator/detail/mesh.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/mesh.hpp
--------------------------------------------------------------------------------
/tesselator/detail/mono.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/mono.hpp
--------------------------------------------------------------------------------
/tesselator/detail/normal.inl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/normal.inl
--------------------------------------------------------------------------------
/tesselator/detail/public.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/public.h
--------------------------------------------------------------------------------
/tesselator/detail/sweep.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/sweep.hpp
--------------------------------------------------------------------------------
/tesselator/detail/sweep.inl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/detail/sweep.inl
--------------------------------------------------------------------------------
/tesselator/tesselator.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdragonx/tesselator/a3f856ee70ada515dd621c59614478d63f3886c6/tesselator/tesselator.hpp
--------------------------------------------------------------------------------