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;
}
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));
}
}
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;
}
}
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());
}
Aggregations