summaryrefslogtreecommitdiff
path: root/core/math/triangulator.h
blob: b6dd7e82364bde2f2d533ce72d1dff88d766cf89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
//Copyright (C) 2011 by Ivan Fratric
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.

#ifndef TRIANGULATOR_H
#define TRIANGULATOR_H

#include "math_2d.h"
#include "list.h"
#include "set.h"
//2D point structure


#define TRIANGULATOR_CCW 1
#define TRIANGULATOR_CW -1
//Polygon implemented as an array of points with a 'hole' flag
class TriangulatorPoly {
protected:



	Vector2 *points;
	long numpoints;
	bool hole;

public:

	//constructors/destructors
	TriangulatorPoly();
	~TriangulatorPoly();

	TriangulatorPoly(const TriangulatorPoly &src);
	TriangulatorPoly& operator=(const TriangulatorPoly &src);

	//getters and setters
	long GetNumPoints() {
		return numpoints;
	}

	bool IsHole() {
		return hole;
	}

	void SetHole(bool hole) {
		this->hole = hole;
	}

	Vector2 &GetPoint(long i) {
		return points[i];
	}

	Vector2 *GetPoints() {
		return points;
	}

	Vector2& operator[] (int i) {
		return points[i];
	}

	//clears the polygon points
	void Clear();

	//inits the polygon with numpoints vertices
	void Init(long numpoints);

	//creates a triangle with points p1,p2,p3
	void Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3);

	//inverts the orfer of vertices
	void Invert();

	//returns the orientation of the polygon
	//possible values:
	//   Triangulator_CCW : polygon vertices are in counter-clockwise order
	//   Triangulator_CW : polygon vertices are in clockwise order
	//       0 : the polygon has no (measurable) area
	int GetOrientation();

	//sets the polygon orientation
	//orientation can be
	//   Triangulator_CCW : sets vertices in counter-clockwise order
	//   Triangulator_CW : sets vertices in clockwise order
	void SetOrientation(int orientation);
};

class TriangulatorPartition {
protected:
	struct PartitionVertex {
		bool isActive;
		bool isConvex;
		bool isEar;

		Vector2 p;
		real_t angle;
		PartitionVertex *previous;
		PartitionVertex *next;
	};

	struct MonotoneVertex {
		Vector2 p;
		long previous;
		long next;
	};

	struct VertexSorter{
		mutable MonotoneVertex *vertices;
		bool operator() (long index1, long index2) const;
	};

	struct Diagonal {
		long index1;
		long index2;
	};

	//dynamic programming state for minimum-weight triangulation
	struct DPState {
		bool visible;
		real_t weight;
		long bestvertex;
	};

	//dynamic programming state for convex partitioning
	struct DPState2 {
		bool visible;
		long weight;
		List<Diagonal> pairs;
	};

	//edge that intersects the scanline
	struct ScanLineEdge {
		mutable long index;
		Vector2 p1;
		Vector2 p2;

		//determines if the edge is to the left of another edge
		bool operator< (const ScanLineEdge & other) const;

		bool IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const;
	};

	//standard helper functions
	bool IsConvex(Vector2& p1, Vector2& p2, Vector2& p3);
	bool IsReflex(Vector2& p1, Vector2& p2, Vector2& p3);
	bool IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p);

	bool InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p);
	bool InCone(PartitionVertex *v, Vector2 &p);

	int Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22);

	Vector2 Normalize(const Vector2 &p);
	real_t Distance(const Vector2 &p1, const Vector2 &p2);

	//helper functions for Triangulate_EC
	void UpdateVertexReflexity(PartitionVertex *v);
	void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);

	//helper functions for ConvexPartition_OPT
	void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
	void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
	void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);

	//helper functions for MonotonePartition
	bool Below(Vector2 &p1, Vector2 &p2);
	void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
			 char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators,
			 Set<ScanLineEdge> *edgeTree, long *helpers);

	//triangulates a monotone polygon, used in Triangulate_MONO
	int TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles);

public:

	//simple heuristic procedure for removing holes from a list of polygons
	//works by creating a diagonal from the rightmost hole vertex to some visible vertex
	//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
	//space complexity: O(n)
	//params:
	//   inpolys : a list of polygons that can contain holes
	//             vertices of all non-hole polys have to be in counter-clockwise order
	//             vertices of all hole polys have to be in clockwise order
	//   outpolys : a list of polygons without holes
	//returns 1 on success, 0 on failure
	int RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys);

	//triangulates a polygon by ear clipping
	//time complexity O(n^2), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   poly : an input polygon to be triangulated
	//          vertices have to be in counter-clockwise order
	//   triangles : a list of triangles (result)
	//returns 1 on success, 0 on failure
	int Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);

	//triangulates a list of polygons that may contain holes by ear clipping algorithm
	//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
	//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
	//space complexity: O(n)
	//params:
	//   inpolys : a list of polygons to be triangulated (can contain holes)
	//             vertices of all non-hole polys have to be in counter-clockwise order
	//             vertices of all hole polys have to be in clockwise order
	//   triangles : a list of triangles (result)
	//returns 1 on success, 0 on failure
	int Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);

	//creates an optimal polygon triangulation in terms of minimal edge length
	//time complexity: O(n^3), n is the number of vertices
	//space complexity: O(n^2)
	//params:
	//   poly : an input polygon to be triangulated
	//          vertices have to be in counter-clockwise order
	//   triangles : a list of triangles (result)
	//returns 1 on success, 0 on failure
	int Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);

	//triangulates a polygons by firstly partitioning it into monotone polygons
	//time complexity: O(n*log(n)), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   poly : an input polygon to be triangulated
	//          vertices have to be in counter-clockwise order
	//   triangles : a list of triangles (result)
	//returns 1 on success, 0 on failure
	int Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);

	//triangulates a list of polygons by firstly partitioning them into monotone polygons
	//time complexity: O(n*log(n)), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   inpolys : a list of polygons to be triangulated (can contain holes)
	//             vertices of all non-hole polys have to be in counter-clockwise order
	//             vertices of all hole polys have to be in clockwise order
	//   triangles : a list of triangles (result)
	//returns 1 on success, 0 on failure
	int Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);

	//creates a monotone partition of a list of polygons that can contain holes
	//time complexity: O(n*log(n)), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   inpolys : a list of polygons to be triangulated (can contain holes)
	//             vertices of all non-hole polys have to be in counter-clockwise order
	//             vertices of all hole polys have to be in clockwise order
	//   monotonePolys : a list of monotone polygons (result)
	//returns 1 on success, 0 on failure
	int MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys);

	//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
	//the algorithm gives at most four times the number of parts as the optimal algorithm
	//however, in practice it works much better than that and often gives optimal partition
	//uses triangulation obtained by ear clipping as intermediate result
	//time complexity O(n^2), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   poly : an input polygon to be partitioned
	//          vertices have to be in counter-clockwise order
	//   parts : resulting list of convex polygons
	//returns 1 on success, 0 on failure
	int ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);

	//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
	//the algorithm gives at most four times the number of parts as the optimal algorithm
	//however, in practice it works much better than that and often gives optimal partition
	//uses triangulation obtained by ear clipping as intermediate result
	//time complexity O(n^2), n is the number of vertices
	//space complexity: O(n)
	//params:
	//   inpolys : an input list of polygons to be partitioned
	//             vertices of all non-hole polys have to be in counter-clockwise order
	//             vertices of all hole polys have to be in clockwise order
	//   parts : resulting list of convex polygons
	//returns 1 on success, 0 on failure
	int ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts);

	//optimal convex partitioning (in terms of number of resulting convex polygons)
	//using the Keil-Snoeyink algorithm
	//M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
	//time complexity O(n^3), n is the number of vertices
	//space complexity: O(n^3)
	//   poly : an input polygon to be partitioned
	//          vertices have to be in counter-clockwise order
	//   parts : resulting list of convex polygons
	//returns 1 on success, 0 on failure
	int ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
};


#endif