|
@@ -0,0 +1,116 @@
|
|
|
+/*
|
|
|
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
|
+ * or more contributor license agreements. Licensed under the Elastic License
|
|
|
+ * 2.0; you may not use this file except in compliance with the Elastic License
|
|
|
+ * 2.0.
|
|
|
+ */
|
|
|
+
|
|
|
+package org.elasticsearch.xpack.spatial.index.fielddata;
|
|
|
+
|
|
|
+import org.apache.lucene.geo.Component2D;
|
|
|
+import org.apache.lucene.geo.LatLonGeometry;
|
|
|
+import org.apache.lucene.index.PointValues;
|
|
|
+
|
|
|
+/**
|
|
|
+ * A reusable tree reader visitor for a previous serialized {@link org.elasticsearch.geometry.Geometry} using
|
|
|
+ * {@link TriangleTreeWriter}.
|
|
|
+ *
|
|
|
+ * This class supports checking {@link LatLonGeometry} relations against a serialized triangle tree.
|
|
|
+ * It does not support bounding boxes crossing the dateline.
|
|
|
+ *
|
|
|
+ */
|
|
|
+class LatLonGeometryRelationVisitor extends TriangleTreeReader.DecodedVisitor {
|
|
|
+
|
|
|
+ private GeoRelation relation;
|
|
|
+ private Component2D component2D;
|
|
|
+
|
|
|
+ LatLonGeometryRelationVisitor(CoordinateEncoder encoder) {
|
|
|
+ super(encoder);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void reset(LatLonGeometry latLonGeometry) {
|
|
|
+ component2D = LatLonGeometry.create(latLonGeometry);
|
|
|
+ relation = GeoRelation.QUERY_DISJOINT;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * return the computed relation.
|
|
|
+ */
|
|
|
+ public GeoRelation relation() {
|
|
|
+ return relation;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ void visitDecodedPoint(double x, double y) {
|
|
|
+ if (component2D.contains(x, y)) {
|
|
|
+ if (component2D.withinPoint(x, y) == Component2D.WithinRelation.CANDIDATE) {
|
|
|
+ relation = GeoRelation.QUERY_INSIDE;
|
|
|
+ } else {
|
|
|
+ relation = GeoRelation.QUERY_CROSSES;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ void visitDecodedLine(double aX, double aY, double bX, double bY, byte metadata) {
|
|
|
+ if (component2D.intersectsLine(aX, aY, bX, bY)) {
|
|
|
+ final boolean ab = (metadata & 1 << 4) == 1 << 4;
|
|
|
+ if (component2D.withinLine(aX, aY, ab, bX, bY) == Component2D.WithinRelation.CANDIDATE) {
|
|
|
+ relation = GeoRelation.QUERY_INSIDE;
|
|
|
+ } else {
|
|
|
+ relation = GeoRelation.QUERY_CROSSES;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ void visitDecodedTriangle(double aX, double aY, double bX, double bY, double cX, double cY, byte metadata) {
|
|
|
+ if (component2D.intersectsTriangle(aX, aY, bX, bY, cX, cY)) {
|
|
|
+ boolean ab = (metadata & 1 << 4) == 1 << 4;
|
|
|
+ boolean bc = (metadata & 1 << 5) == 1 << 5;
|
|
|
+ boolean ca = (metadata & 1 << 6) == 1 << 6;
|
|
|
+ if (component2D.withinTriangle(aX, aY, ab, bX, bY, bc, cX, cY, ca) == Component2D.WithinRelation.CANDIDATE) {
|
|
|
+ relation = GeoRelation.QUERY_INSIDE;
|
|
|
+ } else {
|
|
|
+ relation = GeoRelation.QUERY_CROSSES;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean push() {
|
|
|
+ return relation != GeoRelation.QUERY_CROSSES;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean pushDecodedX(double minX) {
|
|
|
+ return component2D.getMaxX() >= minX;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean pushDecodedY(double minY) {
|
|
|
+ return component2D.getMaxY() >= minY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean pushDecoded(double maxX, double maxY) {
|
|
|
+ return component2D.getMinY() <= maxY && component2D.getMinX() <= maxX;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @SuppressWarnings("HiddenField")
|
|
|
+ public boolean pushDecoded(double minX, double minY, double maxX, double maxY) {
|
|
|
+ PointValues.Relation rel = component2D.relate(minX, maxX, minY, maxY);
|
|
|
+ if (rel == PointValues.Relation.CELL_OUTSIDE_QUERY) {
|
|
|
+ // shapes are disjoint
|
|
|
+ relation = GeoRelation.QUERY_DISJOINT;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (rel == PointValues.Relation.CELL_INSIDE_QUERY) {
|
|
|
+ // the rectangle fully contains the shape
|
|
|
+ relation = GeoRelation.QUERY_CROSSES;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|