class Event {
constructor(x, y, isLeft, index) {
this.x = x;
this.y = y;
this.isLeft = isLeft;
this.index = index;
}
// Order events by y-coordinate, then by x-coordinate
compareTo(e) {
if (this.y === e.y)
return this.x - e.x;
return this.y - e.y;
}
}
function onSegment(p, q, r) {
// Given three collinear points p, q, r
// the function checks if point
// q lies on line segment 'pr'
if (q[0] <= Math.max(p[0], r[0]) && q[0] >= Math.min(p[0], r[0]) &&
q[1] <= Math.max(p[1], r[1]) && q[1] >= Math.min(p[1], r[1]))
return true;
return false;
}
function orientation(p, q, r) {
// To find orientation of ordered triplet (p, q, r).
// Returns 0 if collinear, 1 if clockwise, 2 if counterclockwise.
let val = (q[1] - p[1]) * (r[0] - q[0]) -
(q[0] - p[0]) * (r[1] - q[1]);
// collinear
if (val === 0)
return 0;
// clock- or counterclockwise
return (val > 0) ? 1 : 2;
}
function doIntersect(s1, s2) {
// to fin dif two segments intersect
let p1 = s1[0], q1 = s1[1], p2 = s2[0], q2 = s2[1];
let o1 = orientation(p1, q1, p2);
let o2 = orientation(p1, q1, q2);
let o3 = orientation(p2, q2, p1);
let o4 = orientation(p2, q2, q1);
// General case
if (o1 !== o2 && o3 !== o4)
return true;
// Special cases
if (o1 === 0 && onSegment(p1, p2, q1)) return true;
if (o2 === 0 && onSegment(p1, q2, q1)) return true;
if (o3 === 0 && onSegment(p2, p1, q2)) return true;
if (o4 === 0 && onSegment(p2, q1, q2)) return true;
return false;
}
function pred(arr, pos) {
// Returns the predecessor iterator in set s.
return pos > 0 ? arr[pos - 1] : null;
}
function succ(arr, pos) {
// Returns the successor iterator in set s.
return (pos + 1 < arr.length) ? arr[pos + 1] : null;
}
function lowerBound(arr, elem) {
// Binary search to find the first element not less than elem.
let low = 0, high = arr.length;
while (low < high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid].compareTo(elem) < 0)
low = mid + 1;
else
high = mid;
}
return low;
}
function findIndex(arr, elem) {
// Finds index of elem in arr.
for (let i = 0; i < arr.length; i++) {
if (arr[i].x === elem.x && arr[i].y === elem.y && arr[i].isLeft === elem.isLeft && arr[i].index === elem.index)
return i;
}
return -1;
}
function isIntersect(lines) {
// Returns the number of intersections found between segments.
// To avoid duplicate intersection reports.
let mp = {};
let events = [];
let n = lines.length;
for (let i = 0; i < n; ++i) {
// Create events for the left and right endpoints.
events.push(new Event(lines[i][0][0], lines[i][0][1], true, i));
events.push(new Event(lines[i][1][0], lines[i][1][1], false, i));
}
// Sort events according to x-coordinate.
events.sort((e1, e2) => e1.x - e2.x);
// Set for storing active segments.
let active = [];
let ans = 0;
// Process all events.
for (let i = 0; i < 2 * n; i++) {
let curr = events[i];
let index = curr.index;
if (curr.isLeft) {
// For the left endpoint, get neighbors in the active set.
let pos = lowerBound(active, curr);
let next = pos < active.length ? active[pos] : null;
let prev = pred(active, pos);
// Check for intersection with the next segment.
if (next !== null && doIntersect(lines[next.index], lines[index])) {
let key = (next.index + 1).toString() + " " + (index + 1).toString();
if (!(key in mp)) {
mp[key] = 1;
ans++;
}
}
// Check for intersection with the previous segment.
if (prev !== null && doIntersect(lines[prev.index], lines[index])) {
let key = (prev.index + 1).toString() + " " + (index + 1).toString();
if (!(key in mp)) {
mp[key] = 1;
ans++;
}
}
// To avoid counting duplicates if the same segment is both neighbor.
if (prev !== null && next !== null && next.index === prev.index)
ans--;
active.splice(lowerBound(active, curr), 0, curr);
}
else {
// For the right endpoint, find the matching left endpoint in the active set.
let temp = new Event(lines[index][0][0], lines[index][0][1], true, index);
let pos = findIndex(active, temp);
let next = succ(active, pos);
let prev = pred(active, pos);
// If both neighbors exist, check if they intersect.
if (next !== null && prev !== null) {
let key1 = (next.index + 1).toString() + " " + (prev.index + 1).toString();
let key2 = (prev.index + 1).toString() + " " + (next.index + 1).toString();
if (!(key1 in mp) && !(key2 in mp) && doIntersect(lines[prev.index], lines[next.index]))
ans++;
mp[key1] = 1;
}
active.splice(pos, 1);
}
}
for (let key in mp) {
console.log("Line: " + key);
}
return ans;
}
let lines = [
[ [1, 5], [4, 5] ],
[ [2, 5], [10, 1] ],
[ [3, 2], [10, 3] ],
[ [6, 4], [9, 4] ],
[ [7, 1], [8, 1] ]
];
console.log(isIntersect(lines));