mirror of https://github.com/apache/lucene.git
LUCENE-9067: Polygon2D#contains is now thread safe (#1040)
Use a byte to handle the logic if a point lies on the boundary.
This commit is contained in:
parent
8485b5a939
commit
14dc678f39
|
@ -145,6 +145,8 @@ Other
|
|||
|
||||
* LUCENE-8983: Add sandbox PhraseWildcardQuery to control multi-terms expansions in a phrase. (Bruno Roustant)
|
||||
|
||||
* LUCENE-9067: Polygon2D#contains() is now thread safe. (Ignacio Vera)
|
||||
|
||||
Build
|
||||
|
||||
* Upgrade forbiddenapis to version 2.7; upgrade Groovy to 2.4.17. (Uwe Schindler)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.apache.lucene.geo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.lucene.geo.GeoUtils.lineCrossesLine;
|
||||
import static org.apache.lucene.geo.GeoUtils.lineCrossesLineWithBoundary;
|
||||
|
@ -38,7 +37,7 @@ import static org.apache.lucene.geo.GeoUtils.orient;
|
|||
*
|
||||
* @lucene.internal
|
||||
*/
|
||||
public class EdgeTree {
|
||||
public class EdgeTree {
|
||||
// lat-lon pair (in original order) of the two vertices
|
||||
final double y1, y2;
|
||||
final double x1, x2;
|
||||
|
@ -50,6 +49,10 @@ public class EdgeTree {
|
|||
EdgeTree left;
|
||||
/** right child edge, or null */
|
||||
EdgeTree right;
|
||||
/** helper bytes to signal if a point is on an edge, it is within the edge tree or disjoint */
|
||||
final private static byte FALSE = 0x00;
|
||||
final private static byte TRUE = 0x01;
|
||||
final private static byte ON_EDGE = 0x02;
|
||||
|
||||
EdgeTree(double x1, double y1, double x2, double y2, double low, double max) {
|
||||
this.y1 = y1;
|
||||
|
@ -61,7 +64,17 @@ public class EdgeTree {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the point crosses this edge subtree an odd number of times
|
||||
* Returns true if the point is on an edge or crosses the edge subtree an odd number
|
||||
* of times.
|
||||
*/
|
||||
protected boolean contains(double x, double y) {
|
||||
return containsPnPoly(x, y) > FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns byte 0x00 if the point crosses this edge subtree an even number of times.
|
||||
* Returns byte 0x01 if the point crosses this edge subtree an odd number of times.
|
||||
* Returns byte 0x02 if the point is on one of the edges.
|
||||
* <p>
|
||||
* See <a href="https://www.ecse.rpi.edu/~wrf/Research/Short_Notes/pnpoly.html">
|
||||
* https://www.ecse.rpi.edu/~wrf/Research/Short_Notes/pnpoly.html</a> for more information.
|
||||
|
@ -90,30 +103,35 @@ public class EdgeTree {
|
|||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
protected boolean contains(double x, double y, AtomicBoolean isOnEdge) {
|
||||
boolean res = false;
|
||||
if (isOnEdge.get() == false && y <= this.max) {
|
||||
private byte containsPnPoly(double x, double y) {
|
||||
byte res = FALSE;
|
||||
if (y <= this.max) {
|
||||
if (y == this.y1 && y == this.y2 ||
|
||||
(y <= this.y1 && y >= this.y2) != (y >= this.y1 && y <= this.y2)) {
|
||||
if ((x == this.x1 && x == this.x2) ||
|
||||
((x <= this.x1 && x >= this.x2) != (x >= this.x1 && x <= this.x2) &&
|
||||
GeoUtils.orient(this.x1, this.y1, this.x2, this.y2, x, y) == 0)) {
|
||||
// if its on the boundary return true
|
||||
isOnEdge.set(true);
|
||||
return true;
|
||||
return ON_EDGE;
|
||||
} else if (this.y1 > y != this.y2 > y) {
|
||||
res = x < (this.x2 - this.x1) * (y - this.y1) / (this.y2 - this.y1) + this.x1;
|
||||
res = x < (this.x2 - this.x1) * (y - this.y1) / (this.y2 - this.y1) + this.x1 ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
if (this.left != null) {
|
||||
res ^= left.contains(x, y, isOnEdge);
|
||||
res ^= left.containsPnPoly(x, y);
|
||||
if ((res & 0x02) == 0x02) {
|
||||
return ON_EDGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.right != null && y >= this.low) {
|
||||
res ^= right.contains(x, y, isOnEdge);
|
||||
res ^= right.containsPnPoly(x, y);
|
||||
if ((res & 0x02) == 0x02) {
|
||||
return ON_EDGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isOnEdge.get() || res;
|
||||
assert res >= FALSE && res <= ON_EDGE;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** returns true if the provided x, y point lies on the line */
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.apache.lucene.geo;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.lucene.index.PointValues.Relation;
|
||||
|
||||
/**
|
||||
|
@ -41,8 +39,6 @@ public class Polygon2D implements Component2D {
|
|||
final protected Component2D holes;
|
||||
/** Edges of the polygon represented as a 2-d interval tree.*/
|
||||
final EdgeTree tree;
|
||||
/** helper boolean for points on boundary */
|
||||
final private AtomicBoolean containsBoundary = new AtomicBoolean(false);
|
||||
|
||||
protected Polygon2D(final double minX, final double maxX, final double minY, final double maxY, double[] x, double[] y, Component2D holes) {
|
||||
this.minY = minY;
|
||||
|
@ -92,8 +88,7 @@ public class Polygon2D implements Component2D {
|
|||
}
|
||||
|
||||
private boolean internalContains(double x, double y) {
|
||||
containsBoundary.set(false);
|
||||
if (tree.contains(x, y, containsBoundary)) {
|
||||
if (tree.contains(x, y)) {
|
||||
if (holes != null && holes.contains(x, y)) {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue