blob: 44c293f55cb860f8abdc91ed65c28a9eeed0774b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.document;
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
import org.apache.lucene.document.ShapeField.QueryRelation;
import org.apache.lucene.geo.Circle;
import org.apache.lucene.geo.Component2D;
import org.apache.lucene.geo.GeoEncodingUtils;
import org.apache.lucene.geo.GeoTestUtil;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.geo.LatLonGeometry;
import org.apache.lucene.geo.Line;
import org.apache.lucene.geo.Point;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.Tessellator;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.SerialMergeScheduler;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
import org.junit.Ignore;
import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
/** Test case for indexing polygons and querying by bounding box */
public class TestLatLonShape extends LuceneTestCase {
protected static String FIELDNAME = "field";
/** quantizes a latitude value to be consistent with index encoding */
protected static double quantizeLat(double rawLat) {
return decodeLatitude(encodeLatitude(rawLat));
}
/** quantizes a longitude value to be consistent with index encoding */
protected static double quantizeLon(double rawLon) {
return decodeLongitude(encodeLongitude(rawLon));
}
protected void addPolygonsToDoc(String field, Document doc, Polygon polygon) {
Field[] fields = LatLonShape.createIndexableFields(field, polygon);
for (Field f : fields) {
doc.add(f);
}
}
protected void addLineToDoc(String field, Document doc, Line line) {
Field[] fields = LatLonShape.createIndexableFields(field, line);
for (Field f : fields) {
doc.add(f);
}
}
protected Query newRectQuery(String field, double minLat, double maxLat, double minLon, double maxLon) {
return LatLonShape.newBoxQuery(field, QueryRelation.INTERSECTS, minLat, maxLat, minLon, maxLon);
}
@Ignore
public void testRandomPolygons() throws Exception {
int numVertices;
int numPolys = RandomNumbers.randomIntBetween(random(), 10, 20);
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Polygon polygon;
Document document;
for (int i = 0; i < numPolys;) {
document = new Document();
numVertices = TestUtil.nextInt(random(), 100000, 200000);
polygon = GeoTestUtil.createRegularPolygon(0, 0, atLeast(1000000), numVertices);
addPolygonsToDoc(FIELDNAME, document, polygon);
writer.addDocument(document);
}
// search and verify we found our doc
IndexReader reader = writer.getReader();
IndexSearcher searcher = newSearcher(reader);
assertEquals(0, searcher.count(newRectQuery("field", -89.9, -89.8, -179.9, -179.8d)));
reader.close();
writer.close();
dir.close();
}
/** test we can search for a point with a standard number of vertices*/
public void testBasicIntersects() throws Exception {
int numVertices = TestUtil.nextInt(random(), 50, 100);
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
// add a random polygon document
Polygon p = GeoTestUtil.createRegularPolygon(0, 90, atLeast(1000000), numVertices);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, p);
writer.addDocument(document);
// add a line document
document = new Document();
// add a line string
double lats[] = new double[p.numPoints() - 1];
double lons[] = new double[p.numPoints() - 1];
for (int i = 0; i < lats.length; ++i) {
lats[i] = p.getPolyLat(i);
lons[i] = p.getPolyLon(i);
}
Line l = new Line(lats, lons);
addLineToDoc(FIELDNAME, document, l);
writer.addDocument(document);
////// search /////
// search an intersecting bbox
IndexReader reader = writer.getReader();
writer.close();
IndexSearcher searcher = newSearcher(reader);
double minLat = Math.min(lats[0], lats[1]);
double minLon = Math.min(lons[0], lons[1]);
double maxLat = Math.max(lats[0], lats[1]);
double maxLon = Math.max(lons[0], lons[1]);
Query q = newRectQuery(FIELDNAME, minLat, maxLat, minLon, maxLon);
assertEquals(2, searcher.count(q));
// search a disjoint bbox
q = newRectQuery(FIELDNAME, p.minLat-1d, p.minLat+1, p.minLon-1d, p.minLon+1d);
assertEquals(0, searcher.count(q));
IOUtils.close(reader, dir);
}
public void testBasicContains() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
// add a random polygon document
double[] polyLats = new double[] {-10, -10, 10, 10, -10};
double[] polyLons = new double[] {-10, 10, 10, -10, -10};
Polygon p = new Polygon(polyLats, polyLons);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, p);
writer.addDocument(document);
// add a line document
document = new Document();
// add a line string
double lats[] = new double[p.numPoints() - 1];
double lons[] = new double[p.numPoints() - 1];
for (int i = 0; i < lats.length; ++i) {
lats[i] = p.getPolyLat(i);
lons[i] = p.getPolyLon(i);
}
Line l = new Line(lats, lons);
addLineToDoc(FIELDNAME, document, l);
writer.addDocument(document);
////// search /////
// search a Polygon
IndexReader reader = writer.getReader();
writer.close();
IndexSearcher searcher = newSearcher(reader);
polyLats = new double[] {-5, -5, 5, 5, -5};
polyLons = new double[] {-5, 5, 5, -5, -5};
Polygon query = new Polygon(polyLats, polyLons);
Query q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.CONTAINS, query);
assertEquals(1, searcher.count(q));
// search a bounding box
searcher = newSearcher(reader);
q = LatLonShape.newBoxQuery(FIELDNAME, QueryRelation.CONTAINS,0, 0, 0, 0);
assertEquals(1, searcher.count(q));
IOUtils.close(reader, dir);
}
/** test random polygons with a single hole */
public void testPolygonWithHole() throws Exception {
int numVertices = TestUtil.nextInt(random(), 50, 100);
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
// add a random polygon with a hole
Polygon inner = new Polygon(new double[] {-1d, -1d, 1d, 1d, -1d},
new double[] {-91d, -89d, -89d, -91.0, -91.0});
Polygon outer = GeoTestUtil.createRegularPolygon(0, -90, atLeast(1000000), numVertices);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, new Polygon(outer.getPolyLats(), outer.getPolyLons(), inner));
writer.addDocument(document);
///// search //////
IndexReader reader = writer.getReader();
writer.close();
IndexSearcher searcher = newSearcher(reader);
// search a bbox in the hole
Query q = newRectQuery(FIELDNAME, inner.minLat + 1e-6, inner.maxLat - 1e-6, inner.minLon + 1e-6, inner.maxLon - 1e-6);
assertEquals(0, searcher.count(q));
IOUtils.close(reader, dir);
}
/** test we can search for a point with a large number of vertices*/
public void testLargeVertexPolygon() throws Exception {
int numVertices = TEST_NIGHTLY ? TestUtil.nextInt(random(), 200000, 500000) : TestUtil.nextInt(random(), 20000, 50000);
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setMergeScheduler(new SerialMergeScheduler());
int mbd = iwc.getMaxBufferedDocs();
if (mbd != -1 && mbd < numVertices/100) {
iwc.setMaxBufferedDocs(numVertices/100);
}
Directory dir = newFSDirectory(createTempDir(getClass().getSimpleName()));
IndexWriter writer = new IndexWriter(dir, iwc);
// add a random polygon without a hole
Polygon p = GeoTestUtil.createRegularPolygon(0, 90, atLeast(1000000), numVertices);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, p);
writer.addDocument(document);
// add a random polygon with a hole
Polygon inner = new Polygon(new double[] {-1d, -1d, 1d, 1d, -1d},
new double[] {-91d, -89d, -89d, -91.0, -91.0});
Polygon outer = GeoTestUtil.createRegularPolygon(0, -90, atLeast(1000000), numVertices);
document = new Document();
addPolygonsToDoc(FIELDNAME, document, new Polygon(outer.getPolyLats(), outer.getPolyLons(), inner));
writer.addDocument(document);
////// search /////
// search an intersecting bbox
IndexReader reader = DirectoryReader.open(writer);
writer.close();
IndexSearcher searcher = newSearcher(reader);
Query q = newRectQuery(FIELDNAME, -1d, 1d, p.minLon, p.maxLon);
assertEquals(1, searcher.count(q));
// search a disjoint bbox
q = newRectQuery(FIELDNAME, p.minLat-1d, p.minLat+1, p.minLon-1d, p.minLon+1d);
assertEquals(0, searcher.count(q));
// search a bbox in the hole
q = newRectQuery(FIELDNAME, inner.minLat + 1e-6, inner.maxLat - 1e-6, inner.minLon + 1e-6, inner.maxLon - 1e-6);
assertEquals(0, searcher.count(q));
IOUtils.close(reader, dir);
}
public void testWithinDateLine() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
Document doc = new Document();
Polygon indexPoly1 = new Polygon(
new double[] {-7.5d, 15d, 15d, 0d, -7.5d},
new double[] {-180d, -180d, -176d, -176d, -180d}
);
Polygon indexPoly2 = new Polygon(
new double[] {15d, -7.5d, -15d, -10d, 15d, 15d},
new double[] {180d, 180d, 176d, 174d, 176d, 180d}
);
Field[] fields = LatLonShape.createIndexableFields("test", indexPoly1);
for (Field f : fields) {
doc.add(f);
}
fields = LatLonShape.createIndexableFields("test", indexPoly2);
for (Field f : fields) {
doc.add(f);
}
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
Polygon[] searchPoly = new Polygon[] {
new Polygon(new double[] {-20d, 20d, 20d, -20d, -20d},
new double[] {-180d, -180d, -170d, -170d, -180d}),
new Polygon(new double[] {20d, -20d, -20d, 20d, 20d},
new double[] {180d, 180d, 170d, 170d, 180d})
};
Query q = LatLonShape.newPolygonQuery("test", QueryRelation.WITHIN, searchPoly);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.INTERSECTS, searchPoly);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.DISJOINT, searchPoly);
assertEquals(0, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.CONTAINS, searchPoly);
assertEquals(0, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.WITHIN, -20, 20, 170, -170);
assertEquals(1, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.INTERSECTS, -20, 20, 170, -170);
assertEquals(1, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.DISJOINT, -20, 20, 170, -170);
assertEquals(0, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.CONTAINS, -20, 20, 170, -170);
assertEquals(0, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testContainsDateLine() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
Document doc = new Document();
Polygon indexPoly1 = new Polygon(
new double[] {-2d, -2d, 2d, 2d, -2d},
new double[] {178d, 180d, 180d, 178d, 178d}
);
Polygon indexPoly2 = new Polygon(
new double[] {-2d, -2d, 2d, 2d, -2d},
new double[] {-180d, -178d, -178d, -180d, -180d}
);
Field[] fields = LatLonShape.createIndexableFields("test", indexPoly1);
for (Field f : fields) {
doc.add(f);
}
fields = LatLonShape.createIndexableFields("test", indexPoly2);
for (Field f : fields) {
doc.add(f);
}
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
Polygon[] searchPoly = new Polygon[] {
new Polygon(new double[] {-1d, -1d, 1d, 1d, -1d},
new double[] {179d, 180d, 180d, 179d, 179d}),
new Polygon(new double[] {-1d, -1d, 1d, 1d, -1d},
new double[] {-180d, -179d, -179d, -180d, -180d})
};
Query q;
// Not supported due to encoding
//Query q = LatLonShape.newPolygonQuery("test", QueryRelation.CONTAINS, searchPoly);
//assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.INTERSECTS, searchPoly);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.DISJOINT, searchPoly);
assertEquals(0, searcher.count(q));
q = LatLonShape.newPolygonQuery("test", QueryRelation.WITHIN, searchPoly);
assertEquals(0, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.INTERSECTS, -1, 1, 179, -179);
assertEquals(1, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.WITHIN, -1, 1, 179, -179);
assertEquals(0, searcher.count(q));
q = LatLonShape.newBoxQuery("test", QueryRelation.DISJOINT, -1, 1, 179, -179);
assertEquals(0, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testLUCENE8454() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Polygon poly = new Polygon(new double[] {-1.490648725633769E-132d, 90d, 90d, -1.490648725633769E-132d},
new double[] {0d, 0d, 180d, 0d});
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, poly);
writer.addDocument(document);
///// search //////
IndexReader reader = writer.getReader();
writer.close();
IndexSearcher searcher = newSearcher(reader);
// search a bbox in the hole
Query q = LatLonShape.newBoxQuery(FIELDNAME, QueryRelation.DISJOINT,-29.46555603761226d, 0.0d, 8.381903171539307E-8d, 0.9999999403953552d);
assertEquals(1, searcher.count(q));
IOUtils.close(reader, dir);
}
public void testPointIndexAndQuery() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document document = new Document();
Point p = GeoTestUtil.nextPoint();
double qLat = GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(p.getLat()));
double qLon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(p.getLon()));
p = new Point(qLat, qLon);
Field[] fields = LatLonShape.createIndexableFields(FIELDNAME, p.getLat(), p.getLon());
for (Field f : fields) {
document.add(f);
}
writer.addDocument(document);
//// search
IndexReader r = writer.getReader();
writer.close();
IndexSearcher s = newSearcher(r);
// search by same point
Query q = LatLonShape.newPointQuery(FIELDNAME, QueryRelation.INTERSECTS, new double[] {p.getLat(), p.getLon()});
assertEquals(1, s.count(q));
IOUtils.close(r, dir);
}
public void testLUCENE8669() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
Document doc = new Document();
Polygon indexPoly1 = new Polygon(
new double[] {-7.5d, 15d, 15d, 0d, -7.5d},
new double[] {-180d, -180d, -176d, -176d, -180d}
);
Polygon indexPoly2 = new Polygon(
new double[] {15d, -7.5d, -15d, -10d, 15d, 15d},
new double[] {180d, 180d, 176d, 174d, 176d, 180d}
);
addPolygonsToDoc(FIELDNAME, doc, indexPoly1);
addPolygonsToDoc(FIELDNAME, doc, indexPoly2);
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
Polygon[] searchPoly = new Polygon[] {
new Polygon(new double[] {-20d, 20d, 20d, -20d, -20d},
new double[] {-180d, -180d, -170d, -170d, -180d}),
new Polygon(new double[] {20d, -20d, -20d, 20d, 20d},
new double[] {180d, 180d, 170d, 170d, 180d})
};
Query q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.WITHIN, searchPoly);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.INTERSECTS, searchPoly);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.DISJOINT, searchPoly);
assertEquals(0, searcher.count(q));
q = LatLonShape.newBoxQuery(FIELDNAME, QueryRelation.WITHIN, -20, 20, 170, -170);
assertEquals(1, searcher.count(q));
q = LatLonShape.newBoxQuery(FIELDNAME, QueryRelation.INTERSECTS, -20, 20, 170, -170);
assertEquals(1, searcher.count(q));
q = LatLonShape.newBoxQuery(FIELDNAME, QueryRelation.DISJOINT, -20, 20, 170, -170);
assertEquals(0, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testLUCENE8679() {
double alat = 1.401298464324817E-45;
double alon = 24.76789767911785;
double blat = 34.26468306870807;
double blon = -52.67048754768767;
Polygon polygon = new Polygon(new double[] {-14.448264200949083, 0, 0, -14.448264200949083, -14.448264200949083},
new double[] {0.9999999403953552, 0.9999999403953552, 124.50086371762484, 124.50086371762484, 0.9999999403953552});
Component2D polygon2D = LatLonGeometry.create(polygon);
boolean intersects = polygon2D.intersectsTriangle(
quantizeLon(alon), quantizeLat(blat),
quantizeLon(blon), quantizeLat(blat),
quantizeLon(alon), quantizeLat(alat));
assertTrue(intersects);
intersects = polygon2D.intersectsTriangle(
quantizeLon(alon), quantizeLat(blat),
quantizeLon(alon), quantizeLat(alat),
quantizeLon(blon), quantizeLat(blat));
assertTrue(intersects);
}
public void testTriangleTouchingEdges() {
Polygon p = new Polygon(new double[] {0, 0, 1, 1, 0}, new double[] {0, 1, 1, 0, 0});
Component2D polygon2D = LatLonGeometry.create(p);
//3 shared points
boolean containsTriangle = polygon2D.containsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(1), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(1));
boolean intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(1), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(1));
assertTrue(intersectsTriangle);
assertTrue(containsTriangle);
//2 shared points
containsTriangle = polygon2D.containsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(1), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(0.75));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(1), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(0.75));
assertTrue(intersectsTriangle);
assertTrue(containsTriangle);
//1 shared point
containsTriangle = polygon2D.containsTriangle(
quantizeLon(0.5), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(0),
quantizeLon(0.75), quantizeLat(0.75));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(1), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(0.75));
assertTrue(intersectsTriangle);
assertTrue(containsTriangle);
// 1 shared point but out
containsTriangle = polygon2D.containsTriangle(
quantizeLon(1), quantizeLat(0.5),
quantizeLon(2), quantizeLat(0),
quantizeLon(2), quantizeLat(2));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(1), quantizeLat(0.5),
quantizeLon(2), quantizeLat(0),
quantizeLon(2), quantizeLat(2));
assertTrue(intersectsTriangle);
assertFalse(containsTriangle);
// 1 shared point but crossing
containsTriangle = polygon2D.containsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(2), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(1));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0.5), quantizeLat(0),
quantizeLon(2), quantizeLat(0.5),
quantizeLon(0.5), quantizeLat(1));
assertTrue(intersectsTriangle);
assertFalse(containsTriangle);
//share one edge
containsTriangle = polygon2D.containsTriangle(
quantizeLon(0), quantizeLat(0),
quantizeLon(0), quantizeLat(1),
quantizeLon(0.5), quantizeLat(0.5));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0), quantizeLat(0),
quantizeLon(0), quantizeLat(1),
quantizeLon(0.5), quantizeLat(0.5));
assertTrue(intersectsTriangle);
assertTrue(containsTriangle);
//share one edge outside
containsTriangle = polygon2D.containsTriangle(
quantizeLon(0), quantizeLat(1),
quantizeLon(1.5), quantizeLat(1.5),
quantizeLon(1), quantizeLat(1));
intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(0), quantizeLat(1),
quantizeLon(1.5), quantizeLat(1.5),
quantizeLon(1), quantizeLat(1));
assertTrue(intersectsTriangle);
assertFalse(containsTriangle);
}
public void testLUCENE8736() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
// test polygons:
Polygon indexPoly1 = new Polygon(
new double[] {4d, 4d, 3d, 3d, 4d},
new double[] {3d, 4d, 4d, 3d, 3d}
);
Polygon indexPoly2 = new Polygon(
new double[] {2d, 2d, 1d, 1d, 2d},
new double[] {6d, 7d, 7d, 6d, 6d}
);
Polygon indexPoly3 = new Polygon(
new double[] {1d, 1d, 0d, 0d, 1d},
new double[] {3d, 4d, 4d, 3d, 3d}
);
Polygon indexPoly4 = new Polygon(
new double[] {2d, 2d, 1d, 1d, 2d},
new double[] {0d, 1d, 1d, 0d, 0d}
);
// index polygons:
Document doc;
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly1);
w.addDocument(doc);
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly2);
w.addDocument(doc);
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly3);
w.addDocument(doc);
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly4);
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
Polygon[] searchPoly = new Polygon[] {
new Polygon(new double[] {4d, 4d, 0d, 0d, 4d},
new double[] {0d, 7d, 7d, 0d, 0d})
};
Query q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.WITHIN, searchPoly);
assertEquals(4, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testTriangleCrossingPolygonVertices() {
Polygon p = new Polygon(new double[] {0, 0, -5, -10, -5, 0}, new double[] {-1, 1, 5, 0, -5, -1});
Component2D polygon2D = LatLonGeometry.create(p);
boolean intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(-5), quantizeLat(0),
quantizeLon(10), quantizeLat(0),
quantizeLon(-5), quantizeLat(-15));
assertTrue(intersectsTriangle);
}
public void testLineCrossingPolygonVertices() {
Polygon p = new Polygon(new double[] {0, -1, 0, 1, 0}, new double[] {-1, 0, 1, 0, -1});
Component2D polygon2D = LatLonGeometry.create(p);
boolean intersectsTriangle = polygon2D.intersectsTriangle(
quantizeLon(-1.5), quantizeLat(0),
quantizeLon(1.5), quantizeLat(0),
quantizeLon(-1.5), quantizeLat(0));
assertTrue(intersectsTriangle);
}
public void testLineSharedLine() {
Line l = new Line(new double[] {0, 0, 0, 0}, new double[] {-2, -1, 0, 1});
Component2D l2d = LatLonGeometry.create(l);
boolean intersectsLine = l2d.intersectsLine(
quantizeLon(-5), quantizeLat(0),
quantizeLon(5), quantizeLat(0));
assertTrue(intersectsLine);
}
public void testLUCENE9055() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
// test polygons:
//[5, 5], [10, 6], [10, 10], [5, 10], [5, 5] ]
Polygon indexPoly1 = new Polygon(
new double[] {5d, 6d, 10d, 10d, 5d},
new double[] {5d, 10d, 10d, 5d, 5d}
);
// [ [6, 6], [9, 6], [9, 9], [6, 9], [6, 6] ]
Polygon indexPoly2 = new Polygon(
new double[] {6d, 6d, 9d, 9d, 6d},
new double[] {6d, 9d, 9d, 6d, 6d}
);
// index polygons:
Document doc;
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly1);
w.addDocument(doc);
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly2);
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
// [ [0, 0], [5, 5], [7, 7] ]
Line searchLine = new Line(new double[] {0, 5, 7}, new double[] {0, 5, 7});
Query q = LatLonShape.newLineQuery(FIELDNAME, QueryRelation.INTERSECTS, searchLine);
assertEquals(2, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testIndexAndQuerySamePolygon() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
Document doc = new Document();
Polygon polygon;
while(true) {
try {
polygon = GeoTestUtil.nextPolygon();
// quantize the polygon
double[] lats = new double[polygon.numPoints()];
double[] lons = new double[polygon.numPoints()];
for (int i = 0; i < polygon.numPoints(); i++) {
lats[i] = GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(polygon.getPolyLat(i)));
lons[i] = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(polygon.getPolyLon(i)));
}
polygon = new Polygon(lats, lons);
Tessellator.tessellate(polygon);
break;
} catch (Exception e) {
// invalid polygon, try a new one
}
}
addPolygonsToDoc(FIELDNAME, doc, polygon);
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
Query q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.WITHIN, polygon);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.INTERSECTS, polygon);
assertEquals(1, searcher.count(q));
q = LatLonShape.newPolygonQuery(FIELDNAME, QueryRelation.DISJOINT, polygon);
assertEquals(0, searcher.count(q));
IOUtils.close(w, reader, dir);
}
public void testPointIndexAndDistanceQuery() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document document = new Document();
Point p = GeoTestUtil.nextPoint();
Field[] fields = LatLonShape.createIndexableFields(FIELDNAME, p.getLat(), p.getLon());
for (Field f : fields) {
document.add(f);
}
writer.addDocument(document);
//// search
IndexReader r = writer.getReader();
writer.close();
IndexSearcher s = newSearcher(r);
double lat = GeoTestUtil.nextLatitude();
double lon = GeoTestUtil.nextLongitude();
final double radiusMeters = random().nextDouble() * GeoUtils.EARTH_MEAN_RADIUS_METERS * Math.PI / 2.0 + 1.0;
Circle circle = new Circle(lat, lon, radiusMeters);
Component2D circle2D = LatLonGeometry.create(circle);
int expected;
int expectedDisjoint;
if (circle2D.contains(p.getLon(), p.getLat())) {
expected = 1;
expectedDisjoint = 0;
} else {
expected = 0;
expectedDisjoint = 1;
}
Query q = LatLonShape.newDistanceQuery(FIELDNAME, QueryRelation.INTERSECTS, circle);
assertEquals(expected, s.count(q));
q = LatLonShape.newDistanceQuery(FIELDNAME, QueryRelation.WITHIN, circle);
assertEquals(expected, s.count(q));
q = LatLonShape.newDistanceQuery(FIELDNAME, QueryRelation.DISJOINT, circle);
assertEquals(expectedDisjoint, s.count(q));
IOUtils.close(r, dir);
}
public void testLucene9239() throws Exception {
double[] lats = new double[] {-22.350172194105966, 90.0, 90.0, -22.350172194105966, -22.350172194105966};
double[] lons = new double[] {49.931598911327825, 49.931598911327825,51.40819689137876, 51.408196891378765, 49.931598911327825};
Polygon polygon = new Polygon(lats, lons);
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, polygon);
writer.addDocument(document);
//// search
IndexReader r = writer.getReader();
writer.close();
IndexSearcher s = newSearcher(r);
Circle circle = new Circle(78.01086555431775, 0.9513280497489234, 1097753.4254892308);
// Circle is not within the polygon
Query q = LatLonShape.newDistanceQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
assertEquals(0, s.count(q));
IOUtils.close(r, dir);
}
public void testContainsWrappingBooleanQuery() throws Exception {
double[] lats = new double[] {-30, -30, 30, 30, -30};
double[] lons = new double[] {-30, 30, 30, -30, -30};
Polygon polygon = new Polygon(lats, lons);
Directory dir = newDirectory();
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
Document document = new Document();
addPolygonsToDoc(FIELDNAME, document, polygon);
writer.addDocument(document);
//// search
IndexReader r = writer.getReader();
writer.close();
IndexSearcher s = newSearcher(r);
LatLonGeometry[] geometries = new LatLonGeometry[] { new Rectangle(0, 1, 0, 1), new Point(4, 4) };
// geometries within the polygon
Query q = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, geometries);
TopDocs topDocs = s.search(q, 1);
assertEquals(1, topDocs.scoreDocs.length);
assertEquals(1.0, topDocs.scoreDocs[0].score, 0.0);
IOUtils.close(r, dir);
}
public void testContainsIndexedGeometryCollection() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
Polygon polygon = new Polygon(new double[] {-64, -64, 64, 64, -64}, new double[] {-132, 132, 132, -132, -132});
Field[] polygonFields = LatLonShape.createIndexableFields(FIELDNAME, polygon);
// POINT(5, 5) inside the indexed polygon
Field[] pointFields = LatLonShape.createIndexableFields(FIELDNAME, 5, 5);
int numDocs = random().nextInt(1000);
// index the same multi geometry many times
for (int i = 0; i < numDocs; i++) {
Document doc = new Document();
for (Field f : polygonFields) {
doc.add(f);
}
for(int j = 0; j < 10; j++) {
for (Field f : pointFields) {
doc.add(f);
}
}
w.addDocument(doc);
}
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
// Contains is only true if the query geometry is inside a geometry and does not intersect with any other geometry
// belonging to the same document. In this case the query geometry contains the indexed polygon but the point is
// inside the query as well, hence the result is 0.
Polygon polygonQuery = new Polygon(new double[] {4, 4, 6, 6, 4}, new double[] {4, 6, 6, 4, 4});
Query query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, polygonQuery);
assertEquals(0, searcher.count(query));
Rectangle rectangle = new Rectangle(4.0, 6.0, 4.0, 6.0);
query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, rectangle);
assertEquals(0, searcher.count(query));
Circle circle = new Circle(5, 5, 10000);
query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
assertEquals(0, searcher.count(query));
IOUtils.close(w, reader, dir);
}
}