locationtech / locationtech/spatial4j

Contains vs Within ambiguity for equal shapes

Open
#39 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
961
Forks
172
PR merge metrics
No merged PRs in 30d

Description

When two shapes are equal, the shape.relate(otherShape) method can ambiguously return either Contains or Within. If the caller wants to know specifically if the relationship is Contains (or Within) it can test to see if they are equal if relate() returns Within (or Contains).

Once we introduce aggregate shapes (e.g. ShapeCollection), the aforementioned equality test isn't good enough because the ShapeCollection.relate() doesn't know if the caller prefers Within or Contains. And that's the problem.

One approach taken in SpatialOpRecursivePrefixTreeTest in Lucene spatial is a ShapePair class that has a boolean bias flag to prefer Contains or Within first. It looks something like this:

    private SpatialRelation relateApprox(Shape other) {
      if (biasContainsThenWithin) {
        if (shape1.relate(other) == CONTAINS || shape1.equals(other)
            || shape2.relate(other) == CONTAINS || shape2.equals(other)) return CONTAINS;

        if (shape1.relate(other) == WITHIN && shape2.relate(other) == WITHIN) return WITHIN;

      } else {
        if ((shape1.relate(other) == WITHIN || shape1.equals(other))
            && (shape2.relate(other) == WITHIN || shape2.equals(other))) return WITHIN;

        if (shape1.relate(other) == CONTAINS || shape2.relate(other) == CONTAINS) return CONTAINS;
      }

      if (shape1.relate(other).intersects() || shape2.relate(other).intersects())
        return INTERSECTS;//might actually be 'CONTAINS' if these 2 are adjacent
      return DISJOINT;
    }

Another possible approach (not mutually exclusive) is to establish a protocol in which the more "complex" shape (defaulting to the current shape, 'this', when both shapes are the same type) will always favor 'Contains'. Then if the caller prefers a bias of Within, it can just flip the who relates to who call. This isn't a complete approach that addresses all theoretical use cases, but known cases in Lucene spatial for example could work with this.

Another possible approach is to add a shape.hasRelation(relation, Shape other):boolean method. This would also give the potential for optimization because the implementation can focus on a yes-no answer instead of returning one of multiple possible enum values. However if the caller needs to know if it's Within OR Intersects OR ... (i.e. multiple conditions) then this optimization rationale evaporates.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Shape.relate and the proposed ShapeCollection behavior, then compare the ShapePair bias logic in SpatialOpRecursivePrefixTreeTest from Lucene spatial. Decide which relation-bias protocol or hasRelation API is required and define the equal-shape and aggregate-shape cases; done means the chosen semantics and scope are resolved for implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.