Search in sources :

Example 1 with MultiDimensionalNumericData

use of org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData in project datawave by NationalSecurityAgency.

the class GeoWaveUtils method optimizeByteArrayRange.

/**
 * Optimizes the list of byte array ranges needed to query the desired area. Portions of each range which do not intersect the original query polygon will
 * be pruned out.
 *
 * @param queryGeometry
 *            the original query geometry used to create the list of byte array ranges
 * @param byteArrayRange
 *            a byte array range representing a portion of the query geometry
 * @param rangeSplitThreshold
 *            used to determine the minimum number of segments to break a range into - higher values will take longer to compute, but will yield tighter
 *            ranges
 * @param maxRangeOverlap
 *            the maximum amount of overlap a range is allowed to have compared to the envelope of the query geometry - expressed as a double between 0 and
 *            1.
 * @param longBuffer
 *            a reusable byte buffer of Long.BYTES length
 * @return a list of optimized byte array ranges
 */
public static List<ByteArrayRange> optimizeByteArrayRange(Geometry queryGeometry, ByteArrayRange byteArrayRange, int rangeSplitThreshold, double maxRangeOverlap, ByteBuffer longBuffer) {
    GeometryFactory gf = new GeometryFactory();
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    int tier = decodeTier(byteArrayRange.getStart());
    if (tier == 0) {
        byteArrayRanges.add(byteArrayRange);
    } else {
        longBuffer = initLongBuffer(longBuffer);
        long min = decodePosition(byteArrayRange.getStart(), longBuffer);
        long max = decodePosition(byteArrayRange.getEnd(), longBuffer);
        long range = max - min + 1;
        // as well).
        for (int curTier = 0; curTier <= tier; curTier++) {
            long scale = (long) Math.pow(2.0, 2.0 * (tier - curTier));
            if (range >= scale) {
                long scaledMin = (long) Math.ceil((double) min / scale);
                long scaledMax = max / scale;
                if ((scaledMax - scaledMin + 1) >= rangeSplitThreshold) {
                    boolean simplifiedRanges = false;
                    long subRangeMin = scaledMin * scale;
                    long subRangeMax = Long.MIN_VALUE;
                    for (long scaledPos = scaledMin; scaledPos <= scaledMax; scaledPos++) {
                        long nextSubRangeMax = (scaledPos * scale + scale - 1);
                        if (nextSubRangeMax <= max) {
                            simplifiedRanges = true;
                            subRangeMax = nextSubRangeMax;
                            // make sure that this condensed hash is within the bounds of the map
                            byte[] scaledId = createByteArray(curTier, scaledPos, longBuffer);
                            MultiDimensionalNumericData scaledBounds = GeometryNormalizer.indexStrategy.getRangeForId(null, scaledId);
                            // note: all cells for tiers 0 and 1 are within the bounds of the map
                            if (curTier <= 1 || inBounds(scaledBounds)) {
                                Geometry scaledGeom = boundsToGeometry(gf, scaledBounds);
                                // make sure that the scaled geometry intersects the original query geometry
                                if (scaledGeom.intersects(queryGeometry)) {
                                    byteArrayRanges.add(createByteArrayRange(tier, scaledPos * scale, scaledPos * scale + scale - 1, longBuffer));
                                }
                            }
                        } else {
                            break;
                        }
                    }
                    if (simplifiedRanges) {
                        if (min < subRangeMin && rangeToGeometry(tier, min, subRangeMin - 1).intersects(queryGeometry)) {
                            byteArrayRanges.add(createByteArrayRange(tier, min, subRangeMin - 1, longBuffer));
                        }
                        if (max > subRangeMax && rangeToGeometry(tier, subRangeMax + 1, max).intersects(queryGeometry)) {
                            byteArrayRanges.add(createByteArrayRange(tier, subRangeMax + 1, max, longBuffer));
                        }
                        break;
                    }
                }
            }
        }
        if (byteArrayRanges.isEmpty()) {
            if (rangeToGeometry(tier, min, max).intersects(queryGeometry))
                byteArrayRanges.add(byteArrayRange);
        } else {
            if (byteArrayRanges.size() > 1)
                byteArrayRanges = mergeContiguousRanges(byteArrayRanges, longBuffer);
            if (!byteArrayRanges.isEmpty())
                byteArrayRanges = splitLargeRanges(byteArrayRanges, queryGeometry, maxRangeOverlap, longBuffer);
        }
    }
    return byteArrayRanges;
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) ArrayList(java.util.ArrayList) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange)

Example 2 with MultiDimensionalNumericData

use of org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData in project datawave by NationalSecurityAgency.

the class GeoWaveUtilsTest method optimizeByteArrayRangesTest.

@Test
public void optimizeByteArrayRangesTest() throws Exception {
    String wktString = "POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10))";
    Geometry geom = new WKTReader().read(wktString);
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    for (MultiDimensionalNumericData range : GeometryUtils.basicConstraintsFromEnvelope(geom.getEnvelopeInternal()).getIndexConstraints(GeometryNormalizer.index)) {
        byteArrayRanges.addAll(GeometryNormalizer.index.getIndexStrategy().getQueryRanges(range, 8).getCompositeQueryRanges());
    }
    // count the number of cells included in the original ranges
    long numUnoptimizedIndices = byteArrayRanges.stream().map(range -> (GeoWaveUtils.decodePosition(range.getEnd()) - GeoWaveUtils.decodePosition(range.getStart()) + 1)).reduce(0L, Long::sum);
    List<ByteArrayRange> optimizedByteArrayRanges = GeoWaveUtils.optimizeByteArrayRanges(geom, byteArrayRanges, 16, 0.25);
    // count the number of cells included in the optimized ranges
    long numOptimizedIndices = optimizedByteArrayRanges.stream().map(range -> (GeoWaveUtils.decodePosition(range.getEnd()) - GeoWaveUtils.decodePosition(range.getStart()) + 1)).reduce(0L, Long::sum);
    Assert.assertTrue(numOptimizedIndices < numUnoptimizedIndices);
    // check each tier to ensure that it covers the original geometry
    Map<Integer, List<ByteArrayRange>> rangesByTier = optimizedByteArrayRanges.stream().collect(Collectors.groupingBy(x -> GeoWaveUtils.decodeTier(x.getStart())));
    for (Map.Entry<Integer, List<ByteArrayRange>> ranges : rangesByTier.entrySet()) {
        // union can introduce holes in the final geometry due to the level of precision used to
        // represent the geometries, so we need to ensure that we are only keeping the exterior ring
        Geometry tierGeom = new GeometryFactory().createPolygon(((Polygon) ranges.getValue().stream().map(GeoWaveUtils::rangeToGeometry).reduce(Geometry::union).get()).getExteriorRing().getCoordinates());
        Assert.assertTrue(tierGeom.covers(geom));
    }
}
Also used : ByteArray(org.locationtech.geowave.core.index.ByteArray) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) WKTReader(org.locationtech.jts.io.WKTReader) Test(org.junit.Test) GeometryUtils(org.locationtech.geowave.core.geotime.util.GeometryUtils) Collectors(java.util.stream.Collectors) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) ArrayList(java.util.ArrayList) GeometryNormalizer(datawave.data.normalizer.GeometryNormalizer) List(java.util.List) Map(java.util.Map) Polygon(org.locationtech.jts.geom.Polygon) Geometry(org.locationtech.jts.geom.Geometry) PointNormalizer(datawave.data.normalizer.PointNormalizer) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Assert(org.junit.Assert) Collections(java.util.Collections) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) ArrayList(java.util.ArrayList) WKTReader(org.locationtech.jts.io.WKTReader) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) List(java.util.List) Polygon(org.locationtech.jts.geom.Polygon) Map(java.util.Map) Test(org.junit.Test)

Example 3 with MultiDimensionalNumericData

use of org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData in project datawave by NationalSecurityAgency.

the class GeoWaveUtils method rangeToGeometry.

/**
 * Given a range at a given tier, this will generate a Geometry which represents that range.
 *
 * @param tier
 * @param start
 * @param end
 * @param longBuffer
 *            a reusable byte buffer of Long.BYTES length
 * @return
 */
public static Geometry rangeToGeometry(int tier, long start, long end, ByteBuffer longBuffer) {
    longBuffer = initLongBuffer(longBuffer);
    GeometryFactory gf = new GeometryFactory();
    List<byte[]> byteArrays = decomposeRange(tier, start, end, longBuffer);
    List<Geometry> geometries = new ArrayList<>(byteArrays.size());
    for (byte[] byteArray : byteArrays) {
        MultiDimensionalNumericData bounds = GeometryNormalizer.indexStrategy.getRangeForId(null, byteArray);
        if (decodeTier(byteArray) <= 1 || inBounds(bounds)) {
            geometries.add(boundsToGeometry(gf, bounds));
        }
    }
    // union can introduce holes in the final geometry due to the level of precision used to
    // represent the geometries, so we need to ensure that we are only keeping the exterior ring
    Geometry unionedGeometry = new GeometryCollection(geometries.toArray(new Geometry[0]), gf).union();
    if (unionedGeometry instanceof Polygon && ((Polygon) unionedGeometry).getNumInteriorRing() > 0) {
        return gf.createPolygon(((Polygon) unionedGeometry).getExteriorRing().getCoordinates());
    } else {
        return unionedGeometry;
    }
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) GeometryCollection(org.locationtech.jts.geom.GeometryCollection) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) ArrayList(java.util.ArrayList) Polygon(org.locationtech.jts.geom.Polygon)

Example 4 with MultiDimensionalNumericData

use of org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData in project datawave by NationalSecurityAgency.

the class GeoWaveUtilsTest method optimizeSinglePointTest.

@Test
public void optimizeSinglePointTest() throws Exception {
    String wktString = "POINT(12.34567890123 9.87654321098)";
    Geometry geom = new WKTReader().read(wktString);
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    for (MultiDimensionalNumericData range : GeometryUtils.basicConstraintsFromEnvelope(geom.getEnvelopeInternal()).getIndexConstraints(PointNormalizer.index)) {
        byteArrayRanges.addAll(PointNormalizer.index.getIndexStrategy().getQueryRanges(range, 32).getCompositeQueryRanges());
    }
    List<ByteArrayRange> optimizedByteArrayRanges = GeoWaveUtils.optimizeByteArrayRanges(geom, byteArrayRanges, 16, 0.25);
    Assert.assertEquals(1, optimizedByteArrayRanges.size());
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) ArrayList(java.util.ArrayList) WKTReader(org.locationtech.jts.io.WKTReader) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Test(org.junit.Test)

Aggregations

ArrayList (java.util.ArrayList)4 MultiDimensionalNumericData (org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData)4 Geometry (org.locationtech.jts.geom.Geometry)4 ByteArrayRange (org.locationtech.geowave.core.index.ByteArrayRange)3 GeometryFactory (org.locationtech.jts.geom.GeometryFactory)3 Test (org.junit.Test)2 Polygon (org.locationtech.jts.geom.Polygon)2 WKTReader (org.locationtech.jts.io.WKTReader)2 GeometryNormalizer (datawave.data.normalizer.GeometryNormalizer)1 PointNormalizer (datawave.data.normalizer.PointNormalizer)1 Collections (java.util.Collections)1 List (java.util.List)1 Map (java.util.Map)1 Collectors (java.util.stream.Collectors)1 Assert (org.junit.Assert)1 GeometryUtils (org.locationtech.geowave.core.geotime.util.GeometryUtils)1 ByteArray (org.locationtech.geowave.core.index.ByteArray)1 GeometryCollection (org.locationtech.jts.geom.GeometryCollection)1