Search in sources :

Example 1 with Polygon

use of de.lmu.ifi.dbs.elki.data.spatial.Polygon in project elki by elki-project.

the class AlphaShape method compute.

public List<Polygon> compute() {
    // Compute delaunay triangulation:
    delaunay = (new SweepHullDelaunay2D(points)).getDelaunay();
    List<Polygon> polys = new ArrayList<>();
    // Working data
    long[] used = BitsUtil.zero(delaunay.size());
    List<double[]> cur = new ArrayList<>();
    for (int i = 0; /* = used.nextClearBit(0) */
    i < delaunay.size() && i >= 0; i = BitsUtil.nextClearBit(used, i + 1)) {
        if (BitsUtil.get(used, i)) {
            continue;
        }
        BitsUtil.setI(used, i);
        SweepHullDelaunay2D.Triangle tri = delaunay.get(i);
        if (tri.r2 <= alpha2) {
            // Check neighbors
            processNeighbor(cur, used, i, tri.ab, tri.b);
            processNeighbor(cur, used, i, tri.bc, tri.c);
            processNeighbor(cur, used, i, tri.ca, tri.a);
        }
        if (!cur.isEmpty()) {
            polys.add(new Polygon(cur));
            cur = new ArrayList<>();
        }
    }
    return polys;
}
Also used : ArrayList(java.util.ArrayList) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon)

Example 2 with Polygon

use of de.lmu.ifi.dbs.elki.data.spatial.Polygon in project elki by elki-project.

the class KMLOutputHandler method buildHullsRecursively.

/**
 * Recursively step through the clusters to build the hulls.
 *
 * @param clu Current cluster
 * @param hier Clustering hierarchy
 * @param hulls Hull map
 */
private DoubleObjPair<Polygon> buildHullsRecursively(Cluster<Model> clu, Hierarchy<Cluster<Model>> hier, Map<Object, DoubleObjPair<Polygon>> hulls, Relation<? extends NumberVector> coords) {
    final DBIDs ids = clu.getIDs();
    GrahamScanConvexHull2D hull = new GrahamScanConvexHull2D();
    for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
        hull.add(coords.get(iter).toArray());
    }
    double weight = ids.size();
    if (hier != null && hulls != null) {
        final int numc = hier.numChildren(clu);
        if (numc > 0) {
            for (It<Cluster<Model>> iter = hier.iterChildren(clu); iter.valid(); iter.advance()) {
                final Cluster<Model> iclu = iter.get();
                DoubleObjPair<Polygon> poly = hulls.get(iclu);
                if (poly == null) {
                    poly = buildHullsRecursively(iclu, hier, hulls, coords);
                }
                // Add inner convex hull to outer convex hull.
                for (ArrayListIter<double[]> vi = poly.second.iter(); vi.valid(); vi.advance()) {
                    hull.add(vi.get());
                }
                weight += poly.first / numc;
            }
        }
    }
    DoubleObjPair<Polygon> pair = new DoubleObjPair<>(weight, hull.getHull());
    hulls.put(clu, pair);
    return pair;
}
Also used : ArrayModifiableDBIDs(de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs) DBIDs(de.lmu.ifi.dbs.elki.database.ids.DBIDs) Cluster(de.lmu.ifi.dbs.elki.data.Cluster) DBIDIter(de.lmu.ifi.dbs.elki.database.ids.DBIDIter) DoubleObjPair(de.lmu.ifi.dbs.elki.utilities.pairs.DoubleObjPair) GrahamScanConvexHull2D(de.lmu.ifi.dbs.elki.math.geometry.GrahamScanConvexHull2D) Model(de.lmu.ifi.dbs.elki.data.model.Model) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon)

Example 3 with Polygon

use of de.lmu.ifi.dbs.elki.data.spatial.Polygon in project elki by elki-project.

the class AlphaShapeTest method randomConvexHull.

@Test
public void randomConvexHull() {
    ArrayList<double[]> t = new ArrayList<>();
    Random r = new Random(0L);
    for (int i = 0; i < 1000; i++) {
        t.add(new double[] { r.nextDouble(), r.nextDouble() });
    }
    List<Polygon> polys = new AlphaShape(t, 100.).compute();
    assertEquals("Too many polys.", 1, polys.size());
    assertEquals("Hull size not as expected.", 21, polys.get(0).size());
}
Also used : Random(java.util.Random) ArrayList(java.util.ArrayList) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon) Test(org.junit.Test)

Example 4 with Polygon

use of de.lmu.ifi.dbs.elki.data.spatial.Polygon in project elki by elki-project.

the class KMLOutputHandler method writeOutlierResult.

private void writeOutlierResult(XMLStreamWriter xmlw, OutlierResult outlierResult, Database database) throws XMLStreamException {
    Relation<PolygonsObject> polys = database.getRelation(TypeUtil.POLYGON_TYPE);
    Relation<String> labels = DatabaseUtil.guessObjectLabelRepresentation(database);
    xmlw.writeStartDocument();
    xmlw.writeCharacters("\n");
    xmlw.writeStartElement("kml");
    xmlw.writeDefaultNamespace("http://earth.google.com/kml/2.2");
    xmlw.writeStartElement("Document");
    {
        // TODO: can we automatically generate more helpful data here?
        xmlw.writeStartElement("name");
        xmlw.writeCharacters("ELKI KML output for " + outlierResult.getLongName());
        // name
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
        // TODO: e.g. list the settings in the description?
        xmlw.writeStartElement("description");
        xmlw.writeCharacters("ELKI KML output for " + outlierResult.getLongName());
        // description
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
    }
    {
        // TODO: generate styles from color scheme
        for (int i = 0; i < NUMSTYLES; i++) {
            Color col = getColorForValue(i / (NUMSTYLES - 1.0));
            xmlw.writeStartElement("Style");
            xmlw.writeAttribute("id", "s" + i);
            writeNewlineOnDebug(xmlw);
            {
                xmlw.writeStartElement("LineStyle");
                xmlw.writeStartElement("width");
                xmlw.writeCharacters("0");
                // width
                xmlw.writeEndElement();
                // LineStyle
                xmlw.writeEndElement();
            }
            writeNewlineOnDebug(xmlw);
            {
                xmlw.writeStartElement("PolyStyle");
                xmlw.writeStartElement("color");
                // KML uses AABBGGRR format!
                xmlw.writeCharacters(String.format("%02x%02x%02x%02x", col.getAlpha(), col.getBlue(), col.getGreen(), col.getRed()));
                // color
                xmlw.writeEndElement();
                // out.writeStartElement("fill");
                // out.writeCharacters("1"); // Default 1
                // out.writeEndElement(); // fill
                xmlw.writeStartElement("outline");
                xmlw.writeCharacters("0");
                // outline
                xmlw.writeEndElement();
                // PolyStyle
                xmlw.writeEndElement();
            }
            writeNewlineOnDebug(xmlw);
            // Style
            xmlw.writeEndElement();
            writeNewlineOnDebug(xmlw);
        }
    }
    DoubleRelation scores = outlierResult.getScores();
    Collection<Relation<?>> otherrel = new LinkedList<>(database.getRelations());
    otherrel.remove(scores);
    otherrel.remove(polys);
    otherrel.remove(labels);
    otherrel.remove(database.getRelation(TypeUtil.DBID));
    ArrayModifiableDBIDs ids = DBIDUtil.newArray(scores.getDBIDs());
    scaling.prepare(outlierResult);
    for (DBIDIter iter = outlierResult.getOrdering().order(ids).iter(); iter.valid(); iter.advance()) {
        double score = scores.doubleValue(iter);
        PolygonsObject poly = polys.get(iter);
        String label = labels.get(iter);
        if (Double.isNaN(score)) {
            LOG.warning("No score for object " + DBIDUtil.toString(iter));
        }
        if (poly == null) {
            LOG.warning("No polygon for object " + DBIDUtil.toString(iter) + " - skipping.");
            continue;
        }
        xmlw.writeStartElement("Placemark");
        {
            xmlw.writeStartElement("name");
            xmlw.writeCharacters(score + " " + label);
            // name
            xmlw.writeEndElement();
            StringBuilder buf = makeDescription(otherrel, iter);
            xmlw.writeStartElement("description");
            xmlw.writeCData("<div>" + buf.toString() + "</div>");
            // description
            xmlw.writeEndElement();
            xmlw.writeStartElement("styleUrl");
            int style = (int) (scaling.getScaled(score) * NUMSTYLES);
            style = Math.max(0, Math.min(style, NUMSTYLES - 1));
            xmlw.writeCharacters("#s" + style);
            // styleUrl
            xmlw.writeEndElement();
        }
        {
            xmlw.writeStartElement("Polygon");
            writeNewlineOnDebug(xmlw);
            if (compat) {
                xmlw.writeStartElement("altitudeMode");
                xmlw.writeCharacters("relativeToGround");
                // close altitude mode
                xmlw.writeEndElement();
                writeNewlineOnDebug(xmlw);
            }
            // First polygon clockwise?
            boolean first = true;
            for (Polygon p : poly.getPolygons()) {
                if (first) {
                    xmlw.writeStartElement("outerBoundaryIs");
                } else {
                    xmlw.writeStartElement("innerBoundaryIs");
                }
                xmlw.writeStartElement("LinearRing");
                xmlw.writeStartElement("coordinates");
                // Reverse anti-clockwise polygons.
                boolean reverse = (p.testClockwise() >= 0);
                ArrayListIter<double[]> it = p.iter();
                if (reverse) {
                    it.seek(p.size() - 1);
                }
                while (it.valid()) {
                    double[] v = it.get();
                    xmlw.writeCharacters(FormatUtil.format(v, ","));
                    if (compat && (v.length == 2)) {
                        xmlw.writeCharacters(",50");
                    }
                    xmlw.writeCharacters(" ");
                    if (!reverse) {
                        it.advance();
                    } else {
                        it.retract();
                    }
                }
                // close coordinates
                xmlw.writeEndElement();
                // close LinearRing
                xmlw.writeEndElement();
                // close *BoundaryIs
                xmlw.writeEndElement();
                first = false;
            }
            writeNewlineOnDebug(xmlw);
            // Polygon
            xmlw.writeEndElement();
        }
        // Placemark
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
    }
    // Document
    xmlw.writeEndElement();
    // kml
    xmlw.writeEndElement();
    xmlw.writeEndDocument();
}
Also used : ArrayListIter(de.lmu.ifi.dbs.elki.utilities.datastructures.iterator.ArrayListIter) Color(java.awt.Color) PolygonsObject(de.lmu.ifi.dbs.elki.data.spatial.PolygonsObject) DoubleRelation(de.lmu.ifi.dbs.elki.database.relation.DoubleRelation) LinkedList(java.util.LinkedList) DBIDIter(de.lmu.ifi.dbs.elki.database.ids.DBIDIter) DoubleRelation(de.lmu.ifi.dbs.elki.database.relation.DoubleRelation) Relation(de.lmu.ifi.dbs.elki.database.relation.Relation) ArrayModifiableDBIDs(de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon)

Example 5 with Polygon

use of de.lmu.ifi.dbs.elki.data.spatial.Polygon in project elki by elki-project.

the class KMLOutputHandler method writeClusteringResult.

private void writeClusteringResult(XMLStreamWriter xmlw, Clustering<Model> clustering, Database database) throws XMLStreamException {
    xmlw.writeStartDocument();
    xmlw.writeCharacters("\n");
    xmlw.writeStartElement("kml");
    xmlw.writeDefaultNamespace("http://earth.google.com/kml/2.2");
    xmlw.writeStartElement("Document");
    {
        // TODO: can we automatically generate more helpful data here?
        xmlw.writeStartElement("name");
        xmlw.writeCharacters("ELKI KML output for " + clustering.getLongName());
        // name
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
        // TODO: e.g. list the settings in the description?
        xmlw.writeStartElement("description");
        xmlw.writeCharacters("ELKI KML output for " + clustering.getLongName());
        // description
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
    }
    List<Cluster<Model>> clusters = clustering.getAllClusters();
    Relation<NumberVector> coords = database.getRelation(TypeUtil.NUMBER_VECTOR_FIELD_2D);
    List<Cluster<Model>> topc = clustering.getToplevelClusters();
    Hierarchy<Cluster<Model>> hier = clustering.getClusterHierarchy();
    Map<Object, DoubleObjPair<Polygon>> hullmap = new HashMap<>();
    for (Cluster<Model> clu : topc) {
        buildHullsRecursively(clu, hier, hullmap, coords);
    }
    {
        final double projarea = 360. * 180. * .01;
        // TODO: generate styles from color scheme
        Iterator<Cluster<Model>> it = clusters.iterator();
        for (int i = 0; it.hasNext(); i++) {
            Cluster<Model> clus = it.next();
            // This is a prime based magic number, to produce a colorful output
            Color col = Color.getHSBColor(i / 4.294967291f, 1.f, .5f);
            DoubleObjPair<Polygon> pair = hullmap.get(clus);
            // Approximate area (using bounding box)
            double hullarea = SpatialUtil.volume(pair.second);
            final double relativeArea = Math.max(1. - (hullarea / projarea), 0.);
            // final double relativeSize = pair.first / coords.size();
            final double opacity = .65 * FastMath.sqrt(relativeArea) + .1;
            xmlw.writeStartElement("Style");
            xmlw.writeAttribute("id", "s" + i);
            writeNewlineOnDebug(xmlw);
            {
                xmlw.writeStartElement("LineStyle");
                xmlw.writeStartElement("width");
                xmlw.writeCharacters("0");
                // width
                xmlw.writeEndElement();
                // LineStyle
                xmlw.writeEndElement();
            }
            writeNewlineOnDebug(xmlw);
            {
                xmlw.writeStartElement("PolyStyle");
                xmlw.writeStartElement("color");
                // KML uses AABBGGRR format!
                xmlw.writeCharacters(String.format("%02x%02x%02x%02x", (int) (255 * Math.min(.75, opacity)), col.getBlue(), col.getGreen(), col.getRed()));
                // color
                xmlw.writeEndElement();
                // out.writeStartElement("fill");
                // out.writeCharacters("1"); // Default 1
                // out.writeEndElement(); // fill
                xmlw.writeStartElement("outline");
                xmlw.writeCharacters("0");
                // outline
                xmlw.writeEndElement();
                // PolyStyle
                xmlw.writeEndElement();
            }
            writeNewlineOnDebug(xmlw);
            // Style
            xmlw.writeEndElement();
            writeNewlineOnDebug(xmlw);
        }
    }
    Cluster<?> ignore = topc.size() == 1 ? topc.get(0) : null;
    Iterator<Cluster<Model>> it = clusters.iterator();
    for (int cnum = 0; it.hasNext(); cnum++) {
        Cluster<?> c = it.next();
        // Ignore sole toplevel cluster (usually: noise)
        if (c == ignore) {
            continue;
        }
        Polygon p = hullmap.get(c).second;
        xmlw.writeStartElement("Placemark");
        {
            xmlw.writeStartElement("name");
            xmlw.writeCharacters(c.getNameAutomatic());
            // name
            xmlw.writeEndElement();
            xmlw.writeStartElement("description");
            xmlw.writeCData(makeDescription(c).toString());
            // description
            xmlw.writeEndElement();
            xmlw.writeStartElement("styleUrl");
            xmlw.writeCharacters("#s" + cnum);
            // styleUrl
            xmlw.writeEndElement();
        }
        {
            xmlw.writeStartElement("Polygon");
            writeNewlineOnDebug(xmlw);
            if (compat) {
                xmlw.writeStartElement("altitudeMode");
                xmlw.writeCharacters("relativeToGround");
                // close altitude mode
                xmlw.writeEndElement();
                writeNewlineOnDebug(xmlw);
            }
            {
                xmlw.writeStartElement("outerBoundaryIs");
                xmlw.writeStartElement("LinearRing");
                xmlw.writeStartElement("coordinates");
                // Reverse anti-clockwise polygons.
                boolean reverse = (p.testClockwise() >= 0);
                ArrayListIter<double[]> itp = p.iter();
                if (reverse) {
                    itp.seek(p.size() - 1);
                }
                while (itp.valid()) {
                    double[] v = itp.get();
                    xmlw.writeCharacters(FormatUtil.format(v, ","));
                    if (compat && (v.length == 2)) {
                        xmlw.writeCharacters(",100");
                    }
                    xmlw.writeCharacters(" ");
                    if (!reverse) {
                        itp.advance();
                    } else {
                        itp.retract();
                    }
                }
                // close coordinates
                xmlw.writeEndElement();
                // close LinearRing
                xmlw.writeEndElement();
                // close *BoundaryIs
                xmlw.writeEndElement();
            }
            writeNewlineOnDebug(xmlw);
            // Polygon
            xmlw.writeEndElement();
        }
        // Placemark
        xmlw.writeEndElement();
        writeNewlineOnDebug(xmlw);
    }
    // Document
    xmlw.writeEndElement();
    // kml
    xmlw.writeEndElement();
    xmlw.writeEndDocument();
}
Also used : HashMap(java.util.HashMap) Color(java.awt.Color) Cluster(de.lmu.ifi.dbs.elki.data.Cluster) DoubleObjPair(de.lmu.ifi.dbs.elki.utilities.pairs.DoubleObjPair) NumberVector(de.lmu.ifi.dbs.elki.data.NumberVector) Model(de.lmu.ifi.dbs.elki.data.model.Model) Iterator(java.util.Iterator) PolygonsObject(de.lmu.ifi.dbs.elki.data.spatial.PolygonsObject) Polygon(de.lmu.ifi.dbs.elki.data.spatial.Polygon)

Aggregations

Polygon (de.lmu.ifi.dbs.elki.data.spatial.Polygon)7 ArrayList (java.util.ArrayList)4 PolygonsObject (de.lmu.ifi.dbs.elki.data.spatial.PolygonsObject)3 Cluster (de.lmu.ifi.dbs.elki.data.Cluster)2 Model (de.lmu.ifi.dbs.elki.data.model.Model)2 ArrayModifiableDBIDs (de.lmu.ifi.dbs.elki.database.ids.ArrayModifiableDBIDs)2 DBIDIter (de.lmu.ifi.dbs.elki.database.ids.DBIDIter)2 DoubleObjPair (de.lmu.ifi.dbs.elki.utilities.pairs.DoubleObjPair)2 Color (java.awt.Color)2 ExternalID (de.lmu.ifi.dbs.elki.data.ExternalID)1 NumberVector (de.lmu.ifi.dbs.elki.data.NumberVector)1 DBIDs (de.lmu.ifi.dbs.elki.database.ids.DBIDs)1 DoubleRelation (de.lmu.ifi.dbs.elki.database.relation.DoubleRelation)1 Relation (de.lmu.ifi.dbs.elki.database.relation.Relation)1 DoubleMinMax (de.lmu.ifi.dbs.elki.math.DoubleMinMax)1 GrahamScanConvexHull2D (de.lmu.ifi.dbs.elki.math.geometry.GrahamScanConvexHull2D)1 ArrayListIter (de.lmu.ifi.dbs.elki.utilities.datastructures.iterator.ArrayListIter)1 IntIntPair (de.lmu.ifi.dbs.elki.utilities.pairs.IntIntPair)1 HashMap (java.util.HashMap)1 Iterator (java.util.Iterator)1