blob: 760ae4e4c5d806678b49ea07f56ad5b780044477 [file] [log] [blame]
using Spatial4n.Core.Shapes;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Lucene.Net.Spatial.Queries
{
/*
* 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.
*/
/// <summary>
/// A clause that compares a stored geometry to a supplied geometry. For more
/// explanation of each operation, consider looking at the source implementation
/// of <see cref="Evaluate(IShape, IShape)"/>.
/// <para>
/// See <a href="http://edndoc.esri.com/arcsde/9.1/general_topics/understand_spatial_relations.htm">
/// ESRIs docs on spatial relations</a>
/// </para>
/// @lucene.experimental
/// </summary>
#if FEATURE_SERIALIZABLE
[Serializable]
#endif
public abstract class SpatialOperation
{
// Private registry
private static readonly IDictionary<string, SpatialOperation> registry = new Dictionary<string, SpatialOperation>();
private static readonly IList<SpatialOperation> list = new List<SpatialOperation>();
// Geometry Operations
/// <summary>
/// Bounding box of the *indexed* shape.
/// </summary>
public static readonly SpatialOperation BBoxIntersects = new BBoxIntersectsSpatialOperation();
private sealed class BBoxIntersectsSpatialOperation : SpatialOperation
{
internal BBoxIntersectsSpatialOperation()
: base("BBoxIntersects", true, false, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return indexedShape.BoundingBox.Relate(queryShape).Intersects();
}
}
/// <summary>
/// Bounding box of the *indexed* shape.
/// </summary>
public static readonly SpatialOperation BBoxWithin = new BBoxWithinSpatialOperation();
private sealed class BBoxWithinSpatialOperation : SpatialOperation
{
internal BBoxWithinSpatialOperation()
: base("BBoxWithin", true, false, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
IRectangle bbox = indexedShape.BoundingBox;
return bbox.Relate(queryShape) == SpatialRelation.WITHIN || bbox.Equals(queryShape);
}
}
public static readonly SpatialOperation Contains = new ContainsSpatialOperation();
private sealed class ContainsSpatialOperation : SpatialOperation
{
internal ContainsSpatialOperation()
: base("Contains", true, true, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return indexedShape.HasArea && indexedShape.Relate(queryShape) == SpatialRelation.CONTAINS || indexedShape.Equals(queryShape);
}
}
public static readonly SpatialOperation Intersects = new IntersectsSpatialOperation();
private sealed class IntersectsSpatialOperation : SpatialOperation
{
internal IntersectsSpatialOperation()
: base("Intersects", true, false, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return indexedShape.Relate(queryShape).Intersects();
}
}
public static readonly SpatialOperation IsEqualTo = new IsEqualToSpatialOperation();
private sealed class IsEqualToSpatialOperation : SpatialOperation
{
internal IsEqualToSpatialOperation()
: base("IsEqualTo", false, false, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return indexedShape.Equals(queryShape);
}
}
public static readonly SpatialOperation IsDisjointTo = new IsDisjointToSpatialOperation();
private sealed class IsDisjointToSpatialOperation : SpatialOperation
{
internal IsDisjointToSpatialOperation()
: base("IsDisjointTo", false, false, false)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return !indexedShape.Relate(queryShape).Intersects();
}
}
public static readonly SpatialOperation IsWithin = new IsWithinSpatialOperation();
private sealed class IsWithinSpatialOperation : SpatialOperation
{
internal IsWithinSpatialOperation()
: base("IsWithin", true, false, true)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return queryShape.HasArea && (indexedShape.Relate(queryShape) == SpatialRelation.WITHIN || indexedShape.Equals(queryShape));
}
}
public static readonly SpatialOperation Overlaps = new OverlapsSpatialOperation();
private sealed class OverlapsSpatialOperation : SpatialOperation
{
internal OverlapsSpatialOperation()
: base("Overlaps", true, false, true)
{ }
public override bool Evaluate(IShape indexedShape, IShape queryShape)
{
return queryShape.HasArea && indexedShape.Relate(queryShape).Intersects();
}
}
// Member variables
private readonly bool scoreIsMeaningful;
private readonly bool sourceNeedsArea;
private readonly bool targetNeedsArea;
private readonly string name;
protected SpatialOperation(string name, bool scoreIsMeaningful, bool sourceNeedsArea, bool targetNeedsArea)
{
this.name = name;
this.scoreIsMeaningful = scoreIsMeaningful;
this.sourceNeedsArea = sourceNeedsArea;
this.targetNeedsArea = targetNeedsArea;
registry[name] = this;
registry[CultureInfo.InvariantCulture.TextInfo.ToUpper(name)] = this;
list.Add(this);
}
public static SpatialOperation Get(string v)
{
if (!registry.TryGetValue(v, out SpatialOperation op) || op == null)
{
if (!registry.TryGetValue(CultureInfo.InvariantCulture.TextInfo.ToUpper(v), out op) || op == null)
throw new ArgumentException($"Unknown Operation: {v}", nameof(v));
}
return op;
}
public static IList<SpatialOperation> Values => list;
public static bool Is(SpatialOperation op, params SpatialOperation[] tst)
{
foreach (SpatialOperation t in tst)
{
if (op == t)
return true;
}
return false;
}
/// <summary>
/// Returns whether the relationship between <paramref name="indexedShape"/> and <paramref name="queryShape"/> is
/// satisfied by this operation.
/// </summary>
public abstract bool Evaluate(IShape indexedShape, IShape queryShape);
// ================================================= Getters / Setters =============================================
public virtual bool IsScoreMeaningful => scoreIsMeaningful;
public virtual bool SourceNeedsArea => sourceNeedsArea;
public virtual bool IsTargetNeedsArea => targetNeedsArea;
public virtual string Name => name;
public override string ToString()
{
return name;
}
}
}