-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonotone.cpp
More file actions
553 lines (512 loc) · 16.7 KB
/
Copy pathmonotone.cpp
File metadata and controls
553 lines (512 loc) · 16.7 KB
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
/*
Name: Altaf Ahmad ; Roll no : 18MA20005
This is an implementation of the Plane-Sweep Monotone Transformation for Polygon Triangulation. The worst case run time is O(n logn ). The entire implementation is not complete yet. It identitfies the split and merge vertices now and tries to convert into monotone polygons
Our approach is based on a two-step process (although
with a little cleverness, both steps could be combined into one algorithm).
First, the simple polygon is decomposed into a collection of simpler polygons, called
monotone polygons. This step takes O(n log n) time. - this is almost complete for our case
Second, each of the monotone polygons is triangulated separately, and the result are
combined. This step takes O(n) time. - this step has not been implemented yet
A polygonal curve C is monotone with respect to ` if each line that is orthogonal to ` intersects
C in a single connected component. (It may intersect, not at all, at a single point, or along
a single line segment.) A polygonal curve C is said to be strictly monotone with respect to
a given line `, if any line that is orthogonal to ` intersects C in at most one point.
We begin with the assumption that the vertices of the polygon have been sorted in increasing , which will be done by us later one=
order of their y-coordinates. (For simplicity we assume no duplicate x-coordinates. Otherwise,
break ties between the upper and lower chains arbitrarily, and within a chain break ties so
that the chain order is preserved.) We can simply extract the upper and lower chain, and merge them (as done in MergeSort) in O(n)
In order to run the above triangulation algorithm, we rst need to
subdivide an arbitrary simple polygon P into monotone polygons. This is also done by a plane-sweep approach.
Based on certain properties, we subdivide the vertices into 4 classes if they are special :
• Start Vertex - its two neighbors lie below it
and the interior angle < 180°
• End Vertex - its two neighbors lie above it and
the interior angle < 180°
• Split Vertex - its two neighbors lie below it and
the interior angle > 180°
• Merge Vertex - its two neighbors lie above it
and the interior angle > 180°
we need to maintain a vertex that is visible to any split
vertex that may arise between ea and eb. To do this, imagine a sweeping a vertical segment
between ea and eb to the left until it hits a vertex. Called this helper(ea) - Another way to visualize the helper is to imagine sweeping out a trapezoid to the left from
the sweep line. The top side of the trapezoid lies on ea, the bottom side lies on eb, the right
side lies on the sweep line, and the left side is sweeps as far as it can until hitting a vertex
helper(ea) is dened with respect to the current location of the sweep line. As
the sweep line moves, its value changes. The helper is dened only for those edges intersected
by the sweep line. Our approach will be to join each split vertex to helper(ea), where ea is
the edge of P immediately above the split vertex. (
whenever we see a split vertex, we add a diagonal to the helper of
the edge immediately above it. We defer adding diagonals to merge vertices until the
next opportunity arises.
Similarly, we can do the same for merge vertices i.e, attach them to the nearest helper function.
In this way, our monotone polygon will be generated
Now, we have to triangulize a particular monotone polygon. This can be done in O(n) time using our
hypothesis.
We dene a reflex vertex to be a vertex of the polygon whose interior angle is at least pi, and
otherwise the vertex is nonreflex. We dene a reflex chain to be a sequence of one or more
consecutive reflex vertices along the polygon's boundary.
The idea behind the triangulation algorithm is quite simple: Try to triangulate everything you
can to the left of the current vertex by adding diagonals, and then remove the triangulated
region from further consideration. The trickiest aspect of implementing this idea is nding a
clean invariant that characterizes the untriangulated region that lies to the left of the sweep
line. Ideally, this structure will be simple enough to allow us to determine in
constant time whether it is possible to add another diagonal. And in general we can add each
additional diagonal in constant time. Since any triangulation consists of n3 diagonals, the
process runs in O(n) total time.
*/
#include <iostream>
#include <graphics.h> // this is for the graphical visualization, if you don't want this, then comment out this part and the drawPolygon function and wherever it is used
using namespace std;
struct Link // a doubly linked list structure that helps in storing current polygon
{
int data;
struct Link *next, *prev;
};
struct Link *head = NULL;
struct Side
{
int val;
double x, y;
int type; // 0 for start, 1 for merge , 2 for split and 3 for end and 5 for not any
};
void merge(Side arr[], int l, int m, int r)
{
int n1 = m - l + 1;
int n2 = r - m;
// Create temp arrays
Side L[n1], R[n2];
// Copy data to temp arrays L[] and R[]
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// Merge the temp arrays back into arr[l..r]
// Initial index of first subarray
int i = 0;
// Initial index of second subarray
int j = 0;
// Initial index of merged subarray
int k = l;
while (i < n1 && j < n2)
{
if (L[i].y <= R[j].y)
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of
// L[], if there are any
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
// Copy the remaining elements of
// R[], if there are any
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
// l is for left index and r is
// right index of the sub-array
// of arr to be sorted */
void mergeSort(Side arr[], int l, int r)
{
if (l < r)
{
// Same as (l+r)/2, but avoids
// overflow for large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
void mergex(Side arr[], int l, int m, int r)
{
int n1 = m - l + 1;
int n2 = r - m;
// Create temp arrays
Side L[n1], R[n2];
// Copy data to temp arrays L[] and R[]
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// Merge the temp arrays back into arr[l..r]
// Initial index of first subarray
int i = 0;
// Initial index of second subarray
int j = 0;
// Initial index of merged subarray
int k = l;
while (i < n1 && j < n2)
{
if (L[i].x <= R[j].x)
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of
// L[], if there are any
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
// Copy the remaining elements of
// R[], if there are any
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
// l is for left index and r is
// right index of the sub-array
// of arr to be sorted */
void mergeSortx(Side arr[], int l, int r)
{
if (l < r)
{
// Same as (l+r)/2, but avoids
// overflow for large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSortx(arr, l, m);
mergeSortx(arr, m + 1, r);
mergex(arr, l, m, r);
}
}
void insertList(int new_data) //function that adds data to the end of the linked list. This creates a queue type of structure that helps us in printing the tree
{
struct Link *new_node = (struct Link *)malloc(sizeof(struct Link));
new_node->data = new_data;
new_node->next = NULL;
if (head == NULL) // if the list is empty it adds the first element to the list
{
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
head = new_node;
}
else // if the list is not empty, then
{
if (head->next == NULL)
{
Link *temp = new Link;
temp = head;
temp->prev = new_node;
temp->next = new_node;
new_node->next = head;
new_node->prev = head;
}
else
{
Link *temp = new Link;
temp = head;
new_node->next = head;
new_node->prev = head->prev;
temp->prev->next = new_node;
head->prev = new_node;
}
}
}
void deleteList(int datapt) // function to clip or delete the edges of a polygon
{
Link *temp = new Link;
temp = head;
int i = 0;
while (temp->data != datapt)
{
if ((i++) > 100)
{
//cout<<"You have entered a wrong number\n";
break;
}
temp = temp->next;
}
if (temp->data == datapt)
{
//cout<<"Link is deleted\n";
//delete this node;
Link *pre, *nex;
pre = temp->prev;
nex = temp->next;
pre->next = nex;
nex->prev = pre;
}
}
bool pntSameSide(double a, double b, double c, double x1, double y1)
{
double fx1 = a * x1 + b * y1 + c;
if (fx1 * c > 0.0)
{
return true;
}
return false;
}
bool isVisible(Side ar[], int start, int end)
{
double a, b, c;
a = ar[end].y - ar[start].y;
b = ar[start].x - ar[end].x;
c = ar[start].y * ar[end].x - ar[end].y * ar[start].x;
bool am = pntSameSide(a,b,c,ar[start+1].x,ar[start+1].y);
for (int i = start + 2; i < end; i++)// if all are on the same side of the line
{
if(pntSameSide(a,b,c,ar[i].x,ar[i].y) != am)
{
return false;
}
}
for (int i = start + 1; i < end; i++) // if the values are between start and end, i.e., no extra edge is there from the opposite side
{
if(ar[i].val<ar[start].val || ar[i].val>ar[end].val )
{
return false;
}
}
return true;
}
void drawPolygon(double ar[][2], int tr[][2], int n, int trcnt) // graphical visualization of the triangulation of the polygon using graphics.h library void drawPolygon(double ar[][2], int tr[][2], int n)
{
int i, j;
int gd = DETECT, gm;
initgraph(&gd, &gm, "");
for (i = 0; i < (n - 1); i++) // here, the axes are mirrored over the X axis. So, the polygon visualized will also be a mirrored version
{
setcolor(1);
line(50 * ar[i][0] + 10, 50 * ar[i][1] + 10, 50 * ar[i + 1][0] + 10, 50 * ar[i + 1][1] + 10);
}
line(50 * ar[i][0] + 10, 50 * ar[i][1] + 10, 50 * ar[0][0] + 10, 50 * ar[0][1] + 10);
setcolor(2);
for (i = 0; i < trcnt; i++)
{
line(50 * ar[tr[i][0]][0] + 10, 50 * ar[tr[i][0]][1] + 10, 50 * ar[tr[i][1]][0] + 10, 50 * ar[tr[i][1]][1] + 10);
}
getch(); // also, if the points get out of the boundary, for eg if it is negative or some very large value, then it cannot visualise it properly
closegraph();
}
double angle_degree(double x1, double y1, double x2, double y2, double x3, double y3) // calculates the angle between the three points. This is one of the tests for ear checking
{
double r8_pi = 3.141592653589793;
double value;
double x;
double y;
x = (x3 - x2) * (x1 - x2) + (y3 - y2) * (y1 - y2);
y = (x3 - x2) * (y1 - y2) - (y3 - y2) * (x1 - x2);
if (x == 0.0 && y == 0.0)
{
value = 0.0;
}
else
{
value = atan2(y, x);
if (value < 0.0)
{
value = value + 2.0 * r8_pi;
}
value = 180.0 * value / r8_pi;
}
return value;
}
double areaTrap(double x1, double y1, double x2, double y2)
{
double h = x1 - x2;
double area = (h * (y1 + y2)) / 2.0;
return area;
}
double areaPoly(double ar[][2], int n)
{
double area = 0;
for (int i = 0; i < n; i++)
{
area += areaTrap(ar[i][0], ar[i][1], ar[(i + 1) % n][0], ar[(i + 1) % n][1]);
}
return area;
}
int main()
{
int n;
cout << "Enter the Number of Edges of the polygon: ";
cin >> n;
Side sd[n], sdx[n];
double ar[n][2];
int tr[n - 3][2], trcnt = 0,isdx[n],isd[n];
cout << "Enter the coordinates of the polygon one by one and by adjacent sides: ";
for (int i = 0; i < n; i++)
{
cin >> ar[i][0] >> ar[i][1];
insertList(i);
}
double a[n][2];
if (areaPoly(ar, n) > 0)
{
//everything is fine and we can use ar itself
for (int i = 0; i < n; i++)
{
a[i][0] = ar[i][0];
a[i][1] = ar[i][1];
sd[i].val = i;
sd[i].x = ar[i][0];
sd[i].y = ar[i][1];
sd[i].type = 5;
sdx[i].val = i;
sdx[i].x = ar[i][0];
sdx[i].y = ar[i][1];
sdx[i].type = 5;
}
}
else
{
//cout<<"Red alert";
/* We have to reverse the polygon as it has been entered in an anticlockwise way*/
for (int i = 0; i < n; i++)
{
a[i][0] = ar[(n - i) % n][0];
a[i][1] = ar[(n - i) % n][1];
sd[i].val = i;
sd[i].x = a[i][0];
sd[i].y = a[i][1];
sd[i].type = 5;
sdx[i].val = i;
sdx[i].x = ar[i][0];
sdx[i].y = ar[i][1];
sdx[i].type = 5;
}
}
cout << "Area of the given Polygon is :" << areaPoly(a, n) << "\n";
for (int i = 0; i < n; i++)
{
Side prev, next;
if (i == 0)
{
prev = sd[n - 1];
next = sd[1];
}
else if (i == n - 1)
{
prev = sd[i - 1];
next = sd[0];
}
else
{
prev = sd[i - 1];
next = sd[i + 1];
}
double angl = angle_degree(prev.x, prev.y, sd[i].x, sd[i].y, next.x, next.y);
if (angl > 180.0)
{
//Split Vertex - its two neighbors lie below it and the interior angle > 180° - 2
if (sd[i].y > prev.y && sd[i].y > next.y)
{
sd[i].type = 2;
}
//Merge Vertex - its two neighbors lie above it and the interior angle > 180° - 3
else if (sd[i].y < prev.y && sd[i].y < next.y)
{
sd[i].type = 3;
}
}
else
{
//Start Vertex - its two neighbors lie below it and the interior angle < 180° - 0
if (sd[i].y > prev.y && sd[i].y > next.y)
{
sd[i].type = 0;
}
//End Vertex - its two neighbors lie above it and the interior angle < 180° - 1
else if (sd[i].y < prev.y && sd[i].y < next.y)
{
sd[i].type = 1;
}
}
}
mergeSort(sd, 0, n - 1);
mergeSortx(sdx,0,n-1);
int j;
j=0;
int start,end;
for (int i = 0; i < n; i++)
{
isdx[sdx[i].val] = i;
isd[sd[i].val] = i;
}
for (int i = n - 1; i >= 0; i--)
{
cout << sd[i].val << " Has the coordinates :" << sd[i].x << " ," << sd[i].y;
switch (sd[i].type)
{
case 0:
cout << " and it is a Start Vertex\n";
break;
case 1:
cout << " and it is an End Vertex\n";
break;
case 2:
cout << " and it is a Split Vertex\n";
j=0;
start =isdx[sd[i].val];
end = isdx[sd[i-1].val];
while(isVisible(sdx,start,end)!=true)
{
j++;
end = isdx[sd[i-1-j].val];
}
tr[trcnt][0] = sd[i].val;
tr[trcnt][1] = sd[i - 1-j].val;
cout << "Join " << sd[i].val << " with " << sd[i - j- 1].val << " and it is not a split anymore\n";
trcnt++;
if (sd[i - 1].type == 2)
{
sd[i - 1].type = 5;
}
break;
case 3:
cout << " and it is a Merge Vertex\n";
j=0;
start =isdx[sd[i].val];
end = isdx[sd[i-1].val];
while(isVisible(sdx,start,end)!=true)
{
j++;
end = isdx[sd[i-1-j].val];
}
tr[trcnt][0] = sd[i].val;
tr[trcnt][1] = sd[i - 1-j].val;
trcnt++;
cout << "Join " << sd[i].val << " with " << sd[i - 1-j].val << " and it is not a Merge anymore\n";
if (sd[i - 1].type == 2)
{
sd[i - 1].type = 5;
}
break;
default:
cout << "\n";
break;
}
}
drawPolygon(a, tr, n, trcnt);
}