// Seed triangulation
if(!hullonly) {
tris.add(besttri);
}
// Seed convex hull
hull.add(new IntIntPair(besttri.a, 0));
hull.add(new IntIntPair(besttri.b, 0));
hull.add(new IntIntPair(besttri.c, 0));
if(logger.isDebuggingFinest()) {
debugHull();
}
// Resort from triangle center
Vector center = besttri.m;
for(int i = start; i < len; i++) {
sort[i].first = quadraticEuclidean(center, points.get(sort[i].second));
}
Arrays.sort(sort, start, len);
// Grow hull and triangles
for(int i = start; i < len; i++) {
final int pointId = sort[i].second;
final Vector newpoint = points.get(pointId);
LinkedList<Triangle> newtris = hullonly ? null : new LinkedList<Triangle>();
// We identify edges by their starting point. -1 is invalid.
int hstart = -1, hend = -1;
// Find first and last consecutive visible edge, backwards:
{
Iterator<IntIntPair> iter = hull.descendingIterator();
IntIntPair next = hull.getFirst();
Vector nextV = points.get(next.first);
for(int pos = hull.size() - 1; iter.hasNext(); pos--) {
IntIntPair prev = iter.next();
Vector prevV = points.get(prev.first);
// Not yet visible:
if(hend < 0) {
if(leftOf(prevV, nextV, newpoint)) {
hstart = pos;
hend = pos;
if(!hullonly) {
// Clockwise, A is new point!
Triangle tri = new Triangle(pointId, next.first, prev.first);
assert (tri.isClockwise(points));
assert (prev.second >= 0);
tri.updateCircumcircle(points);
tri.bc = prev.second;
newtris.addFirst(tri);
}
}
}
else {
if(leftOf(prevV, nextV, newpoint)) {
hstart = pos;
// Add triad:
if(!hullonly) {
// Clockwise, A is new point!
Triangle tri = new Triangle(pointId, next.first, prev.first);
assert (tri.isClockwise(points));
assert (prev.second >= 0);
tri.updateCircumcircle(points);
tri.bc = prev.second;
newtris.addFirst(tri);
}
}
else {
break;
}
}
next = prev;
nextV = prevV;
}
}
// If the last edge was visible, we also need to scan forwards:
if(hend == hull.size() - 1) {
Iterator<IntIntPair> iter = hull.iterator();
IntIntPair prev = iter.next();
Vector prevV = points.get(prev.first);
while(iter.hasNext()) {
IntIntPair next = iter.next();
Vector nextV = points.get(next.first);
if(leftOf(prevV, nextV, newpoint)) {
hend++;
// Add triad:
if(!hullonly) {
// Clockwise, A is new point!
Triangle tri = new Triangle(pointId, next.first, prev.first);
assert (tri.isClockwise(points));
assert (prev.second >= 0);
tri.updateCircumcircle(points);
tri.bc = prev.second;
newtris.addLast(tri);
}
}
else {
break;
}
prev = next;
prevV = nextV;
}
}
assert (hstart >= 0 && hend >= hstart);
// Note that hend can be larger than hull.size() now, interpret as
// "hend % hull.size()"
// Update hull, remove points
final int firsttri, lasttri;
if(hullonly) {
firsttri = -1;
lasttri = -1;
}
else {
final int tristart = tris.size();
firsttri = tristart;
lasttri = tristart + newtris.size() - 1;
}
final int hullsize = hull.size();
if(logger.isDebuggingFinest()) {
logger.debugFinest("Size: " + hullsize + " start: " + hstart + " end: " + hend);
}
if(hend < hullsize) {
ListIterator<IntIntPair> iter = hull.listIterator();
int p = 0;
// Skip
for(; p <= hstart; p++) {
iter.next();
}
// Remove
for(; p <= hend; p++) {
iter.next();
iter.remove();
}
// Insert, and update edge->triangle mapping
iter.add(new IntIntPair(pointId, lasttri));
iter.previous();
if(!hullonly) {
if(iter.hasPrevious()) {
iter.previous().second = firsttri;
}
else {
hull.getLast().second = firsttri;
}
}
}
else {
// System.err.println("Case #2 "+pointId+" "+hstart+" "+hend+" "+hullsize);
ListIterator<IntIntPair> iter = hull.listIterator();
// Remove end
int p = hullsize;
for(; p <= hend; p++) {
iter.next();
iter.remove();
}
// Insert
iter.add(new IntIntPair(pointId, lasttri));
// Wrap around
p -= hullsize;
IntIntPair pre = null;
for(; p <= hstart; p++) {
pre = iter.next();
}
assert (pre != null);
pre.second = firsttri;