You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
4.3 KiB
193 lines
4.3 KiB
import {RedBlackNode} from "./RedBlackTree"; |
|
import {createCell} from "./Cell"; |
|
import {attachCircle, detachCircle} from "./Circle"; |
|
import {createEdge, setEdgeEnd} from "./Edge"; |
|
import {beaches, epsilon} from "./Diagram"; |
|
|
|
var beachPool = []; |
|
|
|
function Beach() { |
|
RedBlackNode(this); |
|
this.edge = |
|
this.site = |
|
this.circle = null; |
|
} |
|
|
|
function createBeach(site) { |
|
var beach = beachPool.pop() || new Beach; |
|
beach.site = site; |
|
return beach; |
|
} |
|
|
|
function detachBeach(beach) { |
|
detachCircle(beach); |
|
beaches.remove(beach); |
|
beachPool.push(beach); |
|
RedBlackNode(beach); |
|
} |
|
|
|
export function removeBeach(beach) { |
|
var circle = beach.circle, |
|
x = circle.x, |
|
y = circle.cy, |
|
vertex = [x, y], |
|
previous = beach.P, |
|
next = beach.N, |
|
disappearing = [beach]; |
|
|
|
detachBeach(beach); |
|
|
|
var lArc = previous; |
|
while (lArc.circle |
|
&& Math.abs(x - lArc.circle.x) < epsilon |
|
&& Math.abs(y - lArc.circle.cy) < epsilon) { |
|
previous = lArc.P; |
|
disappearing.unshift(lArc); |
|
detachBeach(lArc); |
|
lArc = previous; |
|
} |
|
|
|
disappearing.unshift(lArc); |
|
detachCircle(lArc); |
|
|
|
var rArc = next; |
|
while (rArc.circle |
|
&& Math.abs(x - rArc.circle.x) < epsilon |
|
&& Math.abs(y - rArc.circle.cy) < epsilon) { |
|
next = rArc.N; |
|
disappearing.push(rArc); |
|
detachBeach(rArc); |
|
rArc = next; |
|
} |
|
|
|
disappearing.push(rArc); |
|
detachCircle(rArc); |
|
|
|
var nArcs = disappearing.length, |
|
iArc; |
|
for (iArc = 1; iArc < nArcs; ++iArc) { |
|
rArc = disappearing[iArc]; |
|
lArc = disappearing[iArc - 1]; |
|
setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex); |
|
} |
|
|
|
lArc = disappearing[0]; |
|
rArc = disappearing[nArcs - 1]; |
|
rArc.edge = createEdge(lArc.site, rArc.site, null, vertex); |
|
|
|
attachCircle(lArc); |
|
attachCircle(rArc); |
|
} |
|
|
|
export function addBeach(site) { |
|
var x = site[0], |
|
directrix = site[1], |
|
lArc, |
|
rArc, |
|
dxl, |
|
dxr, |
|
node = beaches._; |
|
|
|
while (node) { |
|
dxl = leftBreakPoint(node, directrix) - x; |
|
if (dxl > epsilon) node = node.L; else { |
|
dxr = x - rightBreakPoint(node, directrix); |
|
if (dxr > epsilon) { |
|
if (!node.R) { |
|
lArc = node; |
|
break; |
|
} |
|
node = node.R; |
|
} else { |
|
if (dxl > -epsilon) { |
|
lArc = node.P; |
|
rArc = node; |
|
} else if (dxr > -epsilon) { |
|
lArc = node; |
|
rArc = node.N; |
|
} else { |
|
lArc = rArc = node; |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
createCell(site); |
|
var newArc = createBeach(site); |
|
beaches.insert(lArc, newArc); |
|
|
|
if (!lArc && !rArc) return; |
|
|
|
if (lArc === rArc) { |
|
detachCircle(lArc); |
|
rArc = createBeach(lArc.site); |
|
beaches.insert(newArc, rArc); |
|
newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site); |
|
attachCircle(lArc); |
|
attachCircle(rArc); |
|
return; |
|
} |
|
|
|
if (!rArc) { // && lArc |
|
newArc.edge = createEdge(lArc.site, newArc.site); |
|
return; |
|
} |
|
|
|
// else lArc !== rArc |
|
detachCircle(lArc); |
|
detachCircle(rArc); |
|
|
|
var lSite = lArc.site, |
|
ax = lSite[0], |
|
ay = lSite[1], |
|
bx = site[0] - ax, |
|
by = site[1] - ay, |
|
rSite = rArc.site, |
|
cx = rSite[0] - ax, |
|
cy = rSite[1] - ay, |
|
d = 2 * (bx * cy - by * cx), |
|
hb = bx * bx + by * by, |
|
hc = cx * cx + cy * cy, |
|
vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay]; |
|
|
|
setEdgeEnd(rArc.edge, lSite, rSite, vertex); |
|
newArc.edge = createEdge(lSite, site, null, vertex); |
|
rArc.edge = createEdge(site, rSite, null, vertex); |
|
attachCircle(lArc); |
|
attachCircle(rArc); |
|
} |
|
|
|
function leftBreakPoint(arc, directrix) { |
|
var site = arc.site, |
|
rfocx = site[0], |
|
rfocy = site[1], |
|
pby2 = rfocy - directrix; |
|
|
|
if (!pby2) return rfocx; |
|
|
|
var lArc = arc.P; |
|
if (!lArc) return -Infinity; |
|
|
|
site = lArc.site; |
|
var lfocx = site[0], |
|
lfocy = site[1], |
|
plby2 = lfocy - directrix; |
|
|
|
if (!plby2) return lfocx; |
|
|
|
var hl = lfocx - rfocx, |
|
aby2 = 1 / pby2 - 1 / plby2, |
|
b = hl / plby2; |
|
|
|
if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx; |
|
|
|
return (rfocx + lfocx) / 2; |
|
} |
|
|
|
function rightBreakPoint(arc, directrix) { |
|
var rArc = arc.N; |
|
if (rArc) return leftBreakPoint(rArc, directrix); |
|
var site = arc.site; |
|
return site[1] === directrix ? site[0] : Infinity; |
|
}
|
|
|