Search in sources :

Example 6 with IntIntPair

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);
}
Also used : LinearScale(de.lmu.ifi.dbs.elki.math.scales.LinearScale) Layout(de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout) Node(de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout.Node) IntIntPair(de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)

Example 7 with IntIntPair

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;
}
Also used : IntIntPair(de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)

Example 8 with IntIntPair

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;
                }
            }
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Iterator(java.util.Iterator) ListIterator(java.util.ListIterator) IntIntPair(de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)

Example 9 with IntIntPair

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());
}
Also used : DoubleMinMax(de.lmu.ifi.dbs.elki.math.DoubleMinMax) ArrayList(java.util.ArrayList) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon) IntIntPair(de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)

Aggregations

IntIntPair (de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)9 Layout (de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout)3 ArrayList (java.util.ArrayList)3 DoubleMinMax (de.lmu.ifi.dbs.elki.math.DoubleMinMax)2 Node (de.lmu.ifi.dbs.elki.visualization.parallel3d.layout.Layout.Node)2 Polygon (de.lmu.ifi.dbs.elki.data.spatial.Polygon)1 WritableDoubleDataStore (de.lmu.ifi.dbs.elki.database.datastore.WritableDoubleDataStore)1 DBIDIter (de.lmu.ifi.dbs.elki.database.ids.DBIDIter)1 DBIDs (de.lmu.ifi.dbs.elki.database.ids.DBIDs)1 DoubleRelation (de.lmu.ifi.dbs.elki.database.relation.DoubleRelation)1 MaterializedDoubleRelation (de.lmu.ifi.dbs.elki.database.relation.MaterializedDoubleRelation)1 LinearScale (de.lmu.ifi.dbs.elki.math.scales.LinearScale)1 InvertedOutlierScoreMeta (de.lmu.ifi.dbs.elki.result.outlier.InvertedOutlierScoreMeta)1 OutlierResult (de.lmu.ifi.dbs.elki.result.outlier.OutlierResult)1 OutlierScoreMeta (de.lmu.ifi.dbs.elki.result.outlier.OutlierScoreMeta)1 Rectangle2D (java.awt.geom.Rectangle2D)1 Iterator (java.util.Iterator)1 ListIterator (java.util.ListIterator)1