You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by kw...@apache.org on 2017/09/08 05:58:28 UTC
lucene-solr:branch_7x: LUCENE-7962: Add path support for computing
distance along the path only.
Repository: lucene-solr
Updated Branches:
refs/heads/branch_7x 1155b581d -> ba29cce46
LUCENE-7962: Add path support for computing distance along the path only.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/ba29cce4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/ba29cce4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/ba29cce4
Branch: refs/heads/branch_7x
Commit: ba29cce46e0cc17fa134b062a385bcd7d48ce801
Parents: 1155b58
Author: Karl Wright <Da...@gmail.com>
Authored: Fri Sep 8 01:19:29 2017 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Fri Sep 8 01:58:17 2017 -0400
----------------------------------------------------------------------
.../apache/lucene/spatial3d/geom/GeoPath.java | 30 +++++++
.../lucene/spatial3d/geom/GeoStandardPath.java | 89 ++++++++++++++++++++
.../lucene/spatial3d/geom/GeoPathTest.java | 2 +
3 files changed, 121 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ba29cce4/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
index 48a613b..891c896 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
@@ -22,4 +22,34 @@ package org.apache.lucene.spatial3d.geom;
* @lucene.experimental
*/
public interface GeoPath extends GeoDistanceShape {
+
+ // The following methods compute distances along the path from the shape to a point
+ // that doesn't need to be inside the shape. The perpendicular distance from the path
+ // itself to the point is not included in the calculation.
+
+ /**
+ * Compute the nearest path distance to the GeoPoint.
+ * The path distance will not include the distance from the path itself to the
+ * point, but just the distance along the path to the nearest point on the path.
+ *
+ * @param distanceStyle is the distance style.
+ * @param point is the point to compute the distance to.
+ * @return the distance to the nearest path point.
+ */
+ public default double computeNearestDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+ return computeNearestDistance(distanceStyle, point.x, point.y, point.z);
+ }
+
+ /**
+ * Compute the nearest path distance to the GeoPoint.
+ * The path distance will not include the distance from the path itself to the
+ * point, but just the distance along the path to the nearest point on the path.
+ *
+ * @param x is the point's unit x coordinate (using U.S. convention).
+ * @param y is the point's unit y coordinate (using U.S. convention).
+ * @param z is the point's unit z coordinate (using U.S. convention).
+ * @return the distance to the nearest path point.
+ */
+ public double computeNearestDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ba29cce4/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
index 4db74de..841b981 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
@@ -215,6 +215,34 @@ class GeoStandardPath extends GeoBasePath {
}
@Override
+ public double computeNearestDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+ // Algorithm:
+ // (1) If the point is within any of the segments along the path, return that value.
+ // (2) If the point is within any of the segment end circles along the path, return that value.
+ double currentDistance = 0.0;
+ for (PathSegment segment : segments) {
+ double distance = segment.nearestPathDistance(planetModel, distanceStyle, x,y,z);
+ if (distance != Double.POSITIVE_INFINITY)
+ return distanceStyle.fromAggregationForm(distanceStyle.aggregateDistances(currentDistance, distance));
+ currentDistance = distanceStyle.aggregateDistances(currentDistance, segment.fullPathDistance(distanceStyle));
+ }
+
+ int segmentIndex = 0;
+ currentDistance = 0.0;
+ for (SegmentEndpoint endpoint : endPoints) {
+ double distance = endpoint.nearestPathDistance(distanceStyle, x, y, z);
+ if (distance != Double.POSITIVE_INFINITY) {
+ return distanceStyle.fromAggregationForm(distanceStyle.aggregateDistances(currentDistance, distance));
+ }
+ if (segmentIndex < segments.size()) {
+ currentDistance = distanceStyle.aggregateDistances(currentDistance, segments.get(segmentIndex++).fullPathDistance(distanceStyle));
+ }
+ }
+
+ return Double.POSITIVE_INFINITY;
+ }
+
+ @Override
protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
// Algorithm:
// (1) If the point is within any of the segments along the path, return that value.
@@ -562,6 +590,23 @@ class GeoStandardPath extends GeoBasePath {
return distanceStyle.toAggregationForm(distanceStyle.computeDistance(this.point, x, y, z));
}
+ /** Compute nearest path distance.
+ *@param distanceStyle is the distance style.
+ *@param x is the point x.
+ *@param y is the point y.
+ *@param z is the point z.
+ *@return the distance metric (always value zero), in aggregation form, or POSITIVE_INFINITY
+ * if the point is not within the bounds of the endpoint.
+ */
+ public double nearestPathDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+ for (final Membership m : cutoffPlanes) {
+ if (!m.isWithin(x,y,z)) {
+ return Double.POSITIVE_INFINITY;
+ }
+ }
+ return distanceStyle.toAggregationForm(0.0);
+ }
+
/** Compute external distance.
*@param distanceStyle is the distance style.
*@param x is the point x.
@@ -766,6 +811,50 @@ class GeoStandardPath extends GeoBasePath {
lowerConnectingPlane.isWithin(x, y, z);
}
+ /** Compute nearest path distance.
+ *@param planetModel is the planet model.
+ *@param distanceStyle is the distance style.
+ *@param x is the point x.
+ *@param y is the point y.
+ *@param z is the point z.
+ *@return the distance metric, in aggregation form, or Double.POSITIVE_INFINITY if outside this segment
+ */
+ public double nearestPathDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+ // First, if this point is outside the endplanes of the segment, return POSITIVE_INFINITY.
+ if (!startCutoffPlane.isWithin(x, y, z) || !endCutoffPlane.isWithin(x, y, z)) {
+ return Double.POSITIVE_INFINITY;
+ }
+ // (1) Compute normalizedPerpPlane. If degenerate, then there is no such plane, which means that the point given
+ // is insufficient to distinguish between a family of such planes. This can happen only if the point is one of the
+ // "poles", imagining the normalized plane to be the "equator". In that case, the distance returned should be zero.
+ // Want no allocations or expensive operations! so we do this the hard way
+ final double perpX = normalizedConnectingPlane.y * z - normalizedConnectingPlane.z * y;
+ final double perpY = normalizedConnectingPlane.z * x - normalizedConnectingPlane.x * z;
+ final double perpZ = normalizedConnectingPlane.x * y - normalizedConnectingPlane.y * x;
+ final double magnitude = Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
+ if (Math.abs(magnitude) < Vector.MINIMUM_RESOLUTION)
+ return distanceStyle.toAggregationForm(0.0);
+ final double normFactor = 1.0/magnitude;
+ final Plane normalizedPerpPlane = new Plane(perpX * normFactor, perpY * normFactor, perpZ * normFactor, 0.0);
+
+ final GeoPoint[] intersectionPoints = normalizedConnectingPlane.findIntersections(planetModel, normalizedPerpPlane);
+ GeoPoint thePoint;
+ if (intersectionPoints.length == 0)
+ throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+ else if (intersectionPoints.length == 1)
+ thePoint = intersectionPoints[0];
+ else {
+ if (startCutoffPlane.isWithin(intersectionPoints[0]) && endCutoffPlane.isWithin(intersectionPoints[0]))
+ thePoint = intersectionPoints[0];
+ else if (startCutoffPlane.isWithin(intersectionPoints[1]) && endCutoffPlane.isWithin(intersectionPoints[1]))
+ thePoint = intersectionPoints[1];
+ else
+ throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+ }
+ return distanceStyle.toAggregationForm(distanceStyle.computeDistance(start, thePoint.x, thePoint.y, thePoint.z));
+ }
+
+
/** Compute interior path distance.
*@param planetModel is the planet model.
*@param distanceStyle is the distance style.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ba29cce4/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
index 648854e..3aada9a 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
@@ -56,8 +56,10 @@ public class GeoPathTest {
p.done();
gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+ assertEquals(0.15, p.computeNearestDistance(DistanceStyle.ARC,gp), 0.000001);
gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
assertEquals(0.12, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+ assertEquals(0.12, p.computeNearestDistance(DistanceStyle.ARC,gp), 0.000001);
// Now try a vertical path, and make sure distances are as expected
p = new GeoStandardPath(PlanetModel.SPHERE, 0.1);