import
java.util.*;
public
class
DelaunayTriangulation {
private
static
final
double
EPSILON = 1e-
12
;
static
class
Edge {
int
a, b;
Edge(
int
a,
int
b)
{
this
.a = a;
this
.b = b;
}
}
static
class
Point {
double
x, y;
Point(
double
x,
double
y)
{
this
.x = x;
this
.y = y;
}
}
private
static
double
crossProduct(Point A, Point B)
{
return
A.x * B.y - A.y * B.x;
}
private
static
boolean
insideCircle(Point A, Point B,
Point C, Point P)
{
double
ax = A.x - P.x;
double
ay = A.y - P.y;
double
bx = B.x - P.x;
double
by = B.y - P.y;
double
cx = C.x - P.x;
double
cy = C.y - P.y;
double
a2 = ax * ax + ay * ay;
double
b2 = bx * bx + by * by;
double
c2 = cx * cx + cy * cy;
return
(ax * (by - cy) + bx * (cy - ay)
+ cx * (ay - by))
>= EPSILON;
}
public
static
List<Edge> triangulate(Point[] points)
{
int
n = points.length;
List<Edge> edges =
new
ArrayList<>();
Point[] sorted =
new
Point[n];
for
(
int
i =
0
; i < n; i++) {
sorted[i] = points[i];
}
sorted = sortByX(sorted,
0
, n -
1
);
for
(
int
i =
0
; i < n; i++) {
while
(edges.size() >=
2
) {
int
j = edges.size() -
2
;
int
k = edges.size() -
1
;
Point A = sorted[edges.get(j).a];
Point B = sorted[edges.get(j).b];
Point C = sorted[edges.get(k).b];
if
(crossProduct(
new
Point(B.x - A.x, B.y - A.y),
new
Point(C.x - B.x, C.y - B.y))
>
0
) {
break
;
}
edges.remove(edges.size() -
1
);
}
edges.add(
new
Edge(edges.size(), i));
}
int
lower = edges.size();
for
(
int
i = n -
2
, t = lower +
1
; i >=
0
; i--) {
while
(edges.size() >= t) {
int
j = edges.size() -
2
;
int
k = edges.size() -
1
;
Point A = sorted[edges.get(j).a];
Point B = sorted[edges.get(j).b];
Point C = sorted[edges.get(k).b];
if
(crossProduct(
new
Point(B.x - A.x, B.y - A.y),
new
Point(C.x - B.x, C.y - B.y))
>
0
) {
break
;
}
edges.remove(edges.size() -
1
);
}
edges.add(
new
Edge(i, edges.size()));
}
edges.remove(edges.size() -
1
);
List<Edge> result =
new
ArrayList<>();
for
(
int
i =
0
; i < edges.size(); i++) {
int
a = edges.get(i).a;
int
b = edges.get(i).b;
Point A = sorted[a];
Point B = sorted[b];
boolean
flag =
true
;
for
(
int
j =
0
; j < n; j++) {
if
(j == a || j == b) {
continue
;
}
Point P = sorted[j];
if
(insideCircle(A, B, P,
sorted[a + b >>
1
])) {
flag =
false
;
break
;
}
}
if
(flag) {
result.add(
new
Edge(a, b));
}
}
return
result;
}
private
static
Point[] sortByX(Point[] points,
int
start,
int
end)
{
if
(start >= end) {
return
points;
}
int
pivot = partition(points, start, end);
sortByX(points, start, pivot -
1
);
sortByX(points, pivot +
1
, end);
return
points;
}
private
static
int
partition(Point[] points,
int
start,
int
end)
{
Point pivot = points[end];
int
i = start -
1
;
for
(
int
j = start; j <= end -
1
; j++) {
if
(points[j].x <= pivot.x) {
i++;
Point temp = points[i];
points[i] = points[j];
points[j] = temp;
}
}
Point temp = points[i +
1
];
points[i +
1
] = points[end];
points[end] = temp;
return
i +
1
;
}
public
static
void
main(String[] args)
{
Scanner sc =
new
Scanner(System.in);
System.out.println(
"Enter the no. of coordinates:"
);
int
x, y, n =
0
;
n = sc.nextInt();
Point[] points =
new
Point[n];
for
(
int
i =
0
; i < n; i++) {
System.out.println(
"Enter Coordinate No."
+
" "
+ (i +
1
));
x = sc.nextInt();
y = sc.nextInt();
points[i] =
new
Point(x, y);
}
List<Edge> edges = triangulate(points);
System.out.println(
"Triangulated Edges:"
);
for
(Edge edge : edges) {
System.out.println(edge.a +
" - "
+ edge.b);
}
}
}