use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.
the class TestGeo3DDocValues method checkPointEncoding.
void checkPointEncoding(final double latitude, final double longitude) {
final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
long pointValue = Geo3DDocValuesField.encodePoint(point);
final double x = Geo3DDocValuesField.decodeXValue(pointValue);
final double y = Geo3DDocValuesField.decodeYValue(pointValue);
final double z = Geo3DDocValuesField.decodeZValue(pointValue);
final GeoPoint pointR = new GeoPoint(x, y, z);
// Check whether stable
pointValue = Geo3DDocValuesField.encodePoint(x, y, z);
assertEquals(x, Geo3DDocValuesField.decodeXValue(pointValue), 0.0);
assertEquals(y, Geo3DDocValuesField.decodeYValue(pointValue), 0.0);
assertEquals(z, Geo3DDocValuesField.decodeZValue(pointValue), 0.0);
// Check whether has some relationship with original point
assertEquals(0.0, point.arcDistance(pointR), 0.02);
}
use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.
the class TestGeo3DPoint method verifyPolygon.
protected static boolean verifyPolygon(final PlanetModel pm, final Polygon polygon, final GeoPolygon outsidePolygon) {
// Each point in the new poly should be inside the outside poly, and each edge should not intersect the outside poly edge
final double[] lats = polygon.getPolyLats();
final double[] lons = polygon.getPolyLons();
final List<GeoPoint> polyPoints = new ArrayList<>(lats.length - 1);
for (int i = 0; i < lats.length - 1; i++) {
final GeoPoint newPoint = new GeoPoint(pm, toRadians(lats[i]), toRadians(lons[i]));
if (!outsidePolygon.isWithin(newPoint)) {
return false;
}
polyPoints.add(newPoint);
}
// We don't need to construct the world to find intersections -- just the bordering planes.
for (int planeIndex = 0; planeIndex < polyPoints.size(); planeIndex++) {
final GeoPoint startPoint = polyPoints.get(planeIndex);
final GeoPoint endPoint = polyPoints.get(legalIndex(planeIndex + 1, polyPoints.size()));
final GeoPoint beforeStartPoint = polyPoints.get(legalIndex(planeIndex - 1, polyPoints.size()));
final GeoPoint afterEndPoint = polyPoints.get(legalIndex(planeIndex + 2, polyPoints.size()));
final SidedPlane beforePlane = new SidedPlane(endPoint, beforeStartPoint, startPoint);
final SidedPlane afterPlane = new SidedPlane(startPoint, endPoint, afterEndPoint);
final Plane plane = new Plane(startPoint, endPoint);
// Check for intersections!!
if (outsidePolygon.intersects(plane, null, beforePlane, afterPlane)) {
return false;
}
}
return true;
}
use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.
the class TestGeo3DPoint method makePoly.
/** Cook up a random Polygon that makes sense, with possible nested polygon within.
* This is part of testing more complex polygons with nested holes. Picking random points
* doesn't do it because it's almost impossible to come up with nested ones of the proper
* clockwise/counterclockwise rotation that way.
*/
protected static Polygon makePoly(final PlanetModel pm, final GeoPoint pole, final boolean clockwiseDesired, final boolean createHoles) {
// Polygon edges will be arranged around the provided pole, and holes will each have a pole selected within the parent
// polygon.
final int pointCount = TestUtil.nextInt(random(), 3, 10);
// The point angles we pick next. The only requirement is that they are not all on one side of the pole.
// We arrange that by picking the next point within what's left of the remaining angle, but never more than 180 degrees,
// and never less than what is needed to insure that the remaining point choices are less than 180 degrees always.
// These are all picked in the context of the pole,
final double[] angles = new double[pointCount];
final double[] arcDistance = new double[pointCount];
// Pick a set of points
while (true) {
double accumulatedAngle = 0.0;
for (int i = 0; i < pointCount; i++) {
final int remainingEdgeCount = pointCount - i;
final double remainingAngle = 2.0 * Math.PI - accumulatedAngle;
if (remainingEdgeCount == 1) {
angles[i] = remainingAngle;
} else {
// The maximum angle is 180 degrees, or what's left when you give a minimal amount to each edge.
double maximumAngle = remainingAngle - (remainingEdgeCount - 1) * MINIMUM_EDGE_ANGLE;
if (maximumAngle > Math.PI) {
maximumAngle = Math.PI;
}
// The minimum angle is MINIMUM_EDGE_ANGLE, or enough to be sure nobody afterwards needs more than
// 180 degrees. And since we have three points to start with, we already know that.
final double minimumAngle = MINIMUM_EDGE_ANGLE;
// Pick the angle
final double angle = random().nextDouble() * (maximumAngle - minimumAngle) + minimumAngle;
angles[i] = angle;
accumulatedAngle += angle;
}
// Pick the arc distance randomly; not quite the full range though
arcDistance[i] = random().nextDouble() * (Math.PI * 0.5 - MINIMUM_ARC_ANGLE) + MINIMUM_ARC_ANGLE;
}
if (clockwiseDesired) {
// Reverse the signs
for (int i = 0; i < pointCount; i++) {
angles[i] = -angles[i];
}
}
// Now, use the pole's information plus angles and arcs to create GeoPoints in the right order.
final List<GeoPoint> polyPoints = convertToPoints(pm, pole, angles, arcDistance);
// Next, do some holes. No more than 2 of these. The poles for holes must always be within the polygon, so we're
// going to use Geo3D to help us select those given the points we just made.
final int holeCount = createHoles ? TestUtil.nextInt(random(), 0, 2) : 0;
final List<Polygon> holeList = new ArrayList<>();
/* Hole logic is broken and needs rethinking
// Create the geo3d polygon, so we can test out our poles.
final GeoPolygon poly;
try {
poly = GeoPolygonFactory.makeGeoPolygon(pm, polyPoints, null);
} catch (IllegalArgumentException e) {
// This is what happens when three adjacent points are colinear, so try again.
continue;
}
for (int i = 0; i < holeCount; i++) {
// Choose a pole. The poly has to be within the polygon, but it also cannot be on the polygon edge.
// If we can't find a good pole we have to give it up and not do the hole.
for (int k = 0; k < 500; k++) {
final GeoPoint poleChoice = new GeoPoint(pm, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
if (!poly.isWithin(poleChoice)) {
continue;
}
// We have a pole within the polygon. Now try 100 times to build a polygon that does not intersect the outside ring.
// After that we give up and pick a new pole.
boolean foundOne = false;
for (int j = 0; j < 100; j++) {
final Polygon insidePoly = makePoly(pm, poleChoice, !clockwiseDesired, false);
// Verify that the inside polygon is OK. If not, discard and repeat.
if (!verifyPolygon(pm, insidePoly, poly)) {
continue;
}
holeList.add(insidePoly);
foundOne = true;
}
if (foundOne) {
break;
}
}
}
*/
final Polygon[] holes = holeList.toArray(new Polygon[0]);
// Finally, build the polygon and return it
final double[] lats = new double[polyPoints.size() + 1];
final double[] lons = new double[polyPoints.size() + 1];
for (int i = 0; i < polyPoints.size(); i++) {
lats[i] = polyPoints.get(i).getLatitude() * 180.0 / Math.PI;
lons[i] = polyPoints.get(i).getLongitude() * 180.0 / Math.PI;
}
lats[polyPoints.size()] = lats[0];
lons[polyPoints.size()] = lons[0];
return new Polygon(lats, lons, holes);
}
}
use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.
the class TestGeo3DPoint method verify.
private static void verify(double[] lats, double[] lons) throws Exception {
IndexWriterConfig iwc = newIndexWriterConfig();
GeoPoint[] points = new GeoPoint[lats.length];
GeoPoint[] unquantizedPoints = new GeoPoint[lats.length];
// Pre-quantize all lat/lons:
for (int i = 0; i < lats.length; i++) {
if (Double.isNaN(lats[i]) == false) {
//System.out.println("lats[" + i + "] = " + lats[i]);
unquantizedPoints[i] = new GeoPoint(PlanetModel.WGS84, toRadians(lats[i]), toRadians(lons[i]));
points[i] = quantize(unquantizedPoints[i]);
}
}
// Else we can get O(N^2) merging:
int mbd = iwc.getMaxBufferedDocs();
if (mbd != -1 && mbd < points.length / 100) {
iwc.setMaxBufferedDocs(points.length / 100);
}
iwc.setCodec(getCodec());
Directory dir;
if (points.length > 100000) {
dir = newFSDirectory(createTempDir("TestBKDTree"));
} else {
dir = getDirectory();
}
Set<Integer> deleted = new HashSet<>();
// RandomIndexWriter is too slow here:
IndexWriter w = new IndexWriter(dir, iwc);
for (int id = 0; id < points.length; id++) {
Document doc = new Document();
doc.add(newStringField("id", "" + id, Field.Store.NO));
doc.add(new NumericDocValuesField("id", id));
GeoPoint point = points[id];
if (point != null) {
doc.add(new Geo3DPoint("point", point.x, point.y, point.z));
}
w.addDocument(doc);
if (id > 0 && random().nextInt(100) == 42) {
int idToDelete = random().nextInt(id);
w.deleteDocuments(new Term("id", "" + idToDelete));
deleted.add(idToDelete);
if (VERBOSE) {
System.err.println(" delete id=" + idToDelete);
}
}
}
if (random().nextBoolean()) {
w.forceMerge(1);
}
final IndexReader r = DirectoryReader.open(w);
if (VERBOSE) {
System.out.println("TEST: using reader " + r);
}
w.close();
// We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
IndexSearcher s = newSearcher(r, false);
final int iters = atLeast(100);
for (int iter = 0; iter < iters; iter++) {
/*
GeoShape shape = randomShape();
if (VERBOSE) {
System.err.println("\nTEST: iter=" + iter + " shape="+shape);
}
*/
// Geo3DPoint.newShapeQuery("point", shape);
Query query = random3DQuery("point");
if (VERBOSE) {
System.err.println(" using query: " + query);
}
final FixedBitSet hits = new FixedBitSet(r.maxDoc());
s.search(query, new SimpleCollector() {
private int docBase;
@Override
public boolean needsScores() {
return false;
}
@Override
protected void doSetNextReader(LeafReaderContext context) throws IOException {
docBase = context.docBase;
}
@Override
public void collect(int doc) {
hits.set(docBase + doc);
}
});
if (VERBOSE) {
System.err.println(" hitCount: " + hits.cardinality());
}
NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
for (int docID = 0; docID < r.maxDoc(); docID++) {
assertEquals(docID, docIDToID.nextDoc());
int id = (int) docIDToID.longValue();
GeoPoint point = points[id];
GeoPoint unquantizedPoint = unquantizedPoints[id];
if (point != null && unquantizedPoint != null) {
GeoShape shape = ((PointInGeo3DShapeQuery) query).getShape();
XYZBounds bounds = new XYZBounds();
shape.getBounds(bounds);
XYZSolid solid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, bounds.getMinimumX(), bounds.getMaximumX(), bounds.getMinimumY(), bounds.getMaximumY(), bounds.getMinimumZ(), bounds.getMaximumZ());
boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point));
if (hits.get(docID) != expected) {
StringBuilder b = new StringBuilder();
if (expected) {
b.append("FAIL: id=" + id + " should have matched but did not\n");
} else {
b.append("FAIL: id=" + id + " should not have matched but did\n");
}
b.append(" shape=" + shape + "\n");
b.append(" bounds=" + bounds + "\n");
b.append(" world bounds=(" + " minX=" + PlanetModel.WGS84.getMinimumXValue() + " maxX=" + PlanetModel.WGS84.getMaximumXValue() + " minY=" + PlanetModel.WGS84.getMinimumYValue() + " maxY=" + PlanetModel.WGS84.getMaximumYValue() + " minZ=" + PlanetModel.WGS84.getMinimumZValue() + " maxZ=" + PlanetModel.WGS84.getMaximumZValue() + "\n");
b.append(" quantized point=" + point + " within shape? " + shape.isWithin(point) + " within bounds? " + solid.isWithin(point) + "\n");
b.append(" unquantized point=" + unquantizedPoint + " within shape? " + shape.isWithin(unquantizedPoint) + " within bounds? " + solid.isWithin(unquantizedPoint) + "\n");
b.append(" docID=" + docID + " deleted?=" + deleted.contains(id) + "\n");
b.append(" query=" + query + "\n");
b.append(" explanation:\n " + explain("point", shape, point, unquantizedPoint, r, docID).replace("\n", "\n "));
fail(b.toString());
}
} else {
assertFalse(hits.get(docID));
}
}
}
IOUtils.close(r, dir);
}
use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.
the class Geo3DUtil method convertToDescription.
/**
* Convert a list of polygons to a list of polygon descriptions.
* @param polygons is the list of polygons to convert.
* @return the list of polygon descriptions.
*/
private static List<GeoPolygonFactory.PolygonDescription> convertToDescription(final Polygon... polygons) {
final List<GeoPolygonFactory.PolygonDescription> descriptions = new ArrayList<>(polygons.length);
for (final Polygon polygon : polygons) {
final Polygon[] theHoles = polygon.getHoles();
final List<GeoPolygonFactory.PolygonDescription> holes = convertToDescription(theHoles);
// Now do the polygon itself
final double[] polyLats = polygon.getPolyLats();
final double[] polyLons = polygon.getPolyLons();
// I presume the arguments have already been checked
final List<GeoPoint> points = new ArrayList<>(polyLats.length - 1);
// We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
for (int i = 0; i < polyLats.length - 1; i++) {
final int index = polyLats.length - 2 - i;
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
}
descriptions.add(new GeoPolygonFactory.PolygonDescription(points, holes));
}
return descriptions;
}
Aggregations