use of de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair in project elki by elki-project.
the class Parallel3DRenderer method drawParallelPlot.
protected void drawParallelPlot(GLAutoDrawable drawable, GL2 gl) {
// Sort axes by sq. distance from camera, front-to-back:
sortAxes();
// Sort edges by the maximum (foreground) index.
IntIntPair[] edgesort = sortEdges(dindex);
if (textures != null) {
gl.glShadeModel(GL2.GL_FLAT);
// Render spider web:
// outside glBegin!
gl.glLineWidth(shared.settings.linewidth);
gl.glBegin(GL.GL_LINES);
gl.glColor4f(0f, 0f, 0f, 1f);
for (Layout.Edge edge : shared.layout.edges) {
Node n1 = shared.layout.getNode(edge.dim1), n2 = shared.layout.getNode(edge.dim2);
gl.glVertex3d(n1.getX(), n1.getY(), 0f);
gl.glVertex3d(n2.getX(), n2.getY(), 0f);
}
gl.glEnd();
// Draw axes and 3DPC:
for (int i = 0; i < shared.dim; i++) {
final int d = axes[i].second;
final Node node1 = shared.layout.getNode(d);
// Draw edge textures
for (IntIntPair pair : edgesort) {
// Not yet available?
if (pair.second >= completedTextures) {
continue;
}
// Other axis must have a smaller index.
if (pair.first >= i) {
continue;
}
Layout.Edge edge = shared.layout.edges.get(pair.second);
// Must involve the current axis.
if (edge.dim1 != d && edge.dim2 != d) {
continue;
}
int od = axes[pair.first].second;
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glColor4f(1f, 1f, 1f, 1f);
final Node node2 = shared.layout.getNode(od);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[pair.second]);
gl.glBegin(GL2.GL_QUADS);
gl.glTexCoord2d((edge.dim1 == d) ? 0f : 1f, 0f);
gl.glVertex3d(node1.getX(), node1.getY(), 0f);
gl.glTexCoord2d((edge.dim1 == d) ? 0f : 1f, 1f);
gl.glVertex3d(node1.getX(), node1.getY(), 1f);
gl.glTexCoord2d((edge.dim1 != d) ? 0f : 1f, 1f);
gl.glVertex3d(node2.getX(), node2.getY(), 1f);
gl.glTexCoord2d((edge.dim1 != d) ? 0f : 1f, 0f);
gl.glVertex3d(node2.getX(), node2.getY(), 0f);
gl.glEnd();
gl.glDisable(GL.GL_TEXTURE_2D);
}
// Draw axis
// outside glBegin!
gl.glLineWidth(shared.settings.linewidth);
gl.glBegin(GL.GL_LINES);
gl.glColor4f(0f, 0f, 0f, 1f);
gl.glVertex3d(node1.getX(), node1.getY(), 0f);
gl.glVertex3d(node1.getX(), node1.getY(), 1f);
gl.glEnd();
// Draw ticks.
LinearScale scale = shared.proj.getAxisScale(d);
gl.glPointSize(shared.settings.linewidth * 2f);
gl.glBegin(GL.GL_POINTS);
for (double tick = scale.getMin(); tick <= scale.getMax() + scale.getRes() / 10; tick += scale.getRes()) {
gl.glVertex3d(node1.getX(), node1.getY(), scale.getScaled(tick));
}
gl.glEnd();
}
}
// Render labels
renderLabels(gl, edgesort);
}
use of de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair in project elki by elki-project.
the class SweepHullDelaunay2D method findSmallest.
/**
* @param seedid First seed point
* @param seed2id Second seed point
* @param sorti Points
* @param len Number of points
* @return Best triangle
*/
public Triangle findSmallest(int seedid, int seed2id, double[] sortd, int[] sorti, int len) {
Triangle besttri = new Triangle(seedid, seed2id, -1);
besttri.r2 = Double.MAX_VALUE;
Triangle testtri = new Triangle(seedid, seed2id, -1);
int besti = -1;
for (int i = 1; i < len; i++) {
// Update test triad
testtri.c = sorti[i];
if (!testtri.updateCircumcircle(points)) {
// Degenerated.
continue;
}
assert (testtri.r2 > 0.);
if (testtri.r2 < besttri.r2) {
besttri.copyFrom(testtri);
besti = i;
} else if (besttri.r2 * 4. < sortd[i]) {
// Stop early, points are too far away from seed.
break;
}
}
if (besti == -1) {
// Degenerated result, everything is colinear.
hull.add(new IntIntPair(0, sorti[len - 1]));
return null;
}
assert (besti >= 1);
// Rearrange - remove third seed point.
if (besti > 1) {
// Note: we do NOT update the distances, they will be overwritten next.
int i = sorti[besti];
System.arraycopy(sorti, 1, sorti, 2, besti - 1);
sorti[1] = i;
}
return besttri;
}
use of de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair in project elki by elki-project.
the class SweepHullDelaunay2D method run.
/**
* Run the actual algorithm
*
* @param hullonly
*/
void run(boolean hullonly) {
if (points.size() < 3) {
throw new UnsupportedOperationException("There is no delaunay triangulation for less than three objects!");
}
int len = points.size() - 1;
hull = new LinkedList<>();
tris = hullonly ? null : new ArrayList<Triangle>(len);
// 1. Seed point x_0
final double[] seed;
final int seedid = 0;
final double[] sortd = new double[len];
final int[] sorti = new int[len];
// To cause errors
Arrays.fill(sorti, -42);
// TODO: remove duplicates.
// 2. sort by squared Euclidean distance
{
Iterator<double[]> iter = points.iterator();
seed = iter.next();
for (int i = 0, j = 1; iter.hasNext(); j++, i++) {
double dist = quadraticEuclidean(seed, iter.next());
if (dist <= 0.) {
// Duplicate.
// Decrease candidate set size
--len;
// Increase j, but not i.
--i;
continue;
}
sortd[i] = dist;
sorti[i] = j;
}
DoubleIntegerArrayQuickSort.sort(sortd, sorti, len);
}
// Detect some degenerate situations:
if (len < 2) {
hull.add(new IntIntPair(seedid, -1));
if (len == 1) {
hull.add(new IntIntPair(sorti[0], -1));
}
return;
}
assert (sortd[0] > 0);
// final double[] seed2 = points.get(sort[0].second);
final int seed2id = sorti[0];
// 3. Find minimal triangle for these two points:
Triangle besttri = findSmallest(seedid, seed2id, sortd, sorti, len);
if (besttri == null) {
// Degenerate
hull.add(new IntIntPair(seedid, -1));
hull.add(new IntIntPair(seed2id, -1));
return;
}
// Note: sortd no longer accurate, recompute below!
// First two points have already been processed.
int start = 2;
// 5. Make right-handed:
besttri.makeClockwise(points);
// Seed triangulation
if (!hullonly) {
tris.add(besttri);
}
// Seed convex hull (point, triangle)
hull.add(new IntIntPair(besttri.a, 0));
hull.add(new IntIntPair(besttri.b, 0));
hull.add(new IntIntPair(besttri.c, 0));
if (LOG.isDebuggingFinest()) {
debugHull();
}
// 6. Resort from triangle circumcircle center
double[] center = besttri.m;
for (int i = start; i < len; i++) {
sortd[i] = quadraticEuclidean(center, points.get(sorti[i]));
}
DoubleIntegerArrayQuickSort.sort(sortd, sorti, start, len);
// Grow hull and triangles
for (int i = start; i < len; i++) {
final int pointId = sorti[i];
final double[] 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();
double[] nextV = points.get(next.first);
for (int pos = hull.size() - 1; iter.hasNext(); pos--) {
IntIntPair prev = iter.next();
double[] 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();
double[] prevV = points.get(prev.first);
while (iter.hasNext()) {
IntIntPair next = iter.next();
double[] 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 (LOG.isDebuggingFinest()) {
LOG.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;
// Remove remainder
while (iter.hasNext()) {
iter.next();
iter.remove();
}
}
if (LOG.isDebuggingFinest()) {
debugHull();
}
if (!hullonly) {
final int tristart = tris.size();
// Connect triads (they are ordered)
Iterator<Triangle> iter = newtris.iterator();
for (int o = 0; iter.hasNext(); o++) {
// This triangle has num tristart + o.
Triangle cur = iter.next();
if (o > 0) {
// previously added triangle
cur.ca = tristart + o - 1;
} else {
// outside
cur.ca = -1;
}
if (iter.hasNext()) {
// next triangle
cur.ab = tristart + o + 1;
} else {
// outside
cur.ab = -1;
}
// cur.bc was set upon creation
assert (cur.bc >= 0);
Triangle other = tris.get(cur.bc);
Orientation orient = cur.findOrientation(other);
assert (orient != null) : "Inconsistent triangles: " + cur + " " + other;
switch(orient) {
case ORIENT_BC_BA:
assert (other.ab == -1) : "Inconsistent triangles: " + cur + " " + other;
other.ab = tristart + o;
break;
case ORIENT_BC_CB:
assert (other.bc == -1) : "Inconsistent triangles: " + cur + " " + other;
other.bc = tristart + o;
break;
case ORIENT_BC_AC:
assert (other.ca == -1) : "Inconsistent triangles: " + cur + " " + other;
other.ca = tristart + o;
break;
default:
assert (cur.isClockwise(points));
assert (other.isClockwise(points));
throw new RuntimeException("Inconsistent triangles: " + cur + " " + other + " size:" + tris.size());
}
tris.add(cur);
}
assert (tris.size() == lasttri + 1);
}
}
// Now check for triangles that need flipping.
if (!hullonly) {
final int size = tris.size();
long[] flippedA = BitsUtil.zero(size), flippedB = BitsUtil.zero(size);
// Initial flip
if (flipTriangles(flippedA) > 0) {
for (int iterations = 1; iterations < 1000; iterations += 2) {
if (LOG.isDebuggingFinest()) {
debugHull();
}
if (flipTriangles(flippedA, flippedB) == 0) {
break;
}
if (LOG.isDebuggingFinest()) {
debugHull();
}
if (flipTriangles(flippedB, flippedA) == 0) {
break;
}
}
}
}
}
use of de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair in project elki by elki-project.
the class SweepHullDelaunay2D method getHull.
/**
* Get the convex hull only.
*
* Note: if you also want the Delaunay Triangulation, you should get that
* first!
*
* @return Convex hull
*/
public Polygon getHull() {
if (hull == null) {
run(true);
}
DoubleMinMax minmaxX = new DoubleMinMax();
DoubleMinMax minmaxY = new DoubleMinMax();
List<double[]> hullp = new ArrayList<>(hull.size());
for (IntIntPair pair : hull) {
double[] v = points.get(pair.first);
hullp.add(v);
minmaxX.put(v[0]);
minmaxY.put(v[1]);
}
return new Polygon(hullp, minmaxX.getMin(), minmaxX.getMax(), minmaxY.getMin(), minmaxY.getMax());
}
Aggregations