lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From synhers...@apache.org
Subject [6/6] lucenenet git commit: Moving the 3.0 spatial module to serve as a basis to Lucene.Net.Spatial
Date Mon, 09 Feb 2015 01:27:56 GMT
Moving the 3.0 spatial module to serve as a basis to Lucene.Net.Spatial


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/c9f901b2
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/c9f901b2
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/c9f901b2

Branch: refs/heads/master
Commit: c9f901b24237da82dbb137f709eaa5f0e2398192
Parents: 150651b
Author: Itamar Syn-Hershko <itamar@code972.com>
Authored: Mon Feb 9 03:25:27 2015 +0200
Committer: Itamar Syn-Hershko <itamar@code972.com>
Committed: Mon Feb 9 03:25:27 2015 +0200

----------------------------------------------------------------------
 src/Lucene.Net.Spatial/BBox/AreaSimilarity.cs   | 231 +++++++++
 src/Lucene.Net.Spatial/BBox/BBoxSimilarity.cs   |  30 ++
 .../BBox/BBoxSimilarityValueSource.cs           | 122 +++++
 src/Lucene.Net.Spatial/BBox/BBoxStrategy.cs     | 485 +++++++++++++++++++
 .../BBox/DistanceSimilarity.cs                  |  63 +++
 .../Contrib.Spatial.NTS.csproj                  | 202 ++++++++
 src/Lucene.Net.Spatial/Contrib.Spatial.csproj   | 202 ++++++++
 src/Lucene.Net.Spatial/Overview.html            |  41 ++
 .../Prefix/PointPrefixTreeFieldCacheProvider.cs |  51 ++
 .../Prefix/PrefixTreeStrategy.cs                | 176 +++++++
 .../Prefix/RecursivePrefixTreeFilter.cs         | 189 ++++++++
 .../Prefix/RecursivePrefixTreeStrategy.cs       |  62 +++
 .../Prefix/TermQueryPrefixTreeStrategy.cs       |  56 +++
 .../Prefix/Tree/GeohashPrefixTree.cs            | 158 ++++++
 src/Lucene.Net.Spatial/Prefix/Tree/Node.cs      | 222 +++++++++
 .../Prefix/Tree/QuadPrefixTree.cs               | 323 ++++++++++++
 .../Prefix/Tree/SpatialPrefixTree.cs            | 276 +++++++++++
 .../Prefix/Tree/SpatialPrefixTreeFactory.cs     | 102 ++++
 .../Properties/AssemblyInfo.cs                  |  63 +++
 src/Lucene.Net.Spatial/Queries/SpatialArgs.cs   | 142 ++++++
 .../Queries/SpatialArgsParser.cs                | 140 ++++++
 .../Queries/SpatialOperation.cs                 | 116 +++++
 .../Queries/UnsupportedSpatialOperation.cs      |  29 ++
 src/Lucene.Net.Spatial/SpatialStrategy.cs       | 150 ++++++
 src/Lucene.Net.Spatial/Util/Bits.cs             |  92 ++++
 .../Util/CachingDoubleValueSource.cs            | 101 ++++
 .../Util/CompatibilityExtensions.cs             | 296 +++++++++++
 src/Lucene.Net.Spatial/Util/FixedBitSet.cs      | 454 +++++++++++++++++
 src/Lucene.Net.Spatial/Util/FunctionQuery.cs    | 215 ++++++++
 .../Util/ReciprocalFloatFunction.cs             | 100 ++++
 src/Lucene.Net.Spatial/Util/ShapeFieldCache.cs  |  55 +++
 .../Util/ShapeFieldCacheDistanceValueSource.cs  | 116 +++++
 .../Util/ShapeFieldCacheProvider.cs             | 105 ++++
 .../Util/TermsEnumCompatibility.cs              | 140 ++++++
 src/Lucene.Net.Spatial/Util/TermsFilter.cs      | 117 +++++
 .../Util/ValueSourceFilter.cs                   |  72 +++
 .../Vector/DistanceValueSource.cs               | 118 +++++
 .../Vector/PointVectorStrategy.cs               | 260 ++++++++++
 src/contrib/Spatial/BBox/AreaSimilarity.cs      | 231 ---------
 src/contrib/Spatial/BBox/BBoxSimilarity.cs      |  30 --
 .../Spatial/BBox/BBoxSimilarityValueSource.cs   | 122 -----
 src/contrib/Spatial/BBox/BBoxStrategy.cs        | 485 -------------------
 src/contrib/Spatial/BBox/DistanceSimilarity.cs  |  63 ---
 src/contrib/Spatial/Contrib.Spatial.NTS.csproj  | 202 --------
 src/contrib/Spatial/Contrib.Spatial.csproj      | 202 --------
 src/contrib/Spatial/Overview.html               |  41 --
 .../Prefix/PointPrefixTreeFieldCacheProvider.cs |  51 --
 .../Spatial/Prefix/PrefixTreeStrategy.cs        | 176 -------
 .../Spatial/Prefix/RecursivePrefixTreeFilter.cs | 189 --------
 .../Prefix/RecursivePrefixTreeStrategy.cs       |  62 ---
 .../Prefix/TermQueryPrefixTreeStrategy.cs       |  56 ---
 .../Spatial/Prefix/Tree/GeohashPrefixTree.cs    | 158 ------
 src/contrib/Spatial/Prefix/Tree/Node.cs         | 222 ---------
 .../Spatial/Prefix/Tree/QuadPrefixTree.cs       | 323 ------------
 .../Spatial/Prefix/Tree/SpatialPrefixTree.cs    | 276 -----------
 .../Prefix/Tree/SpatialPrefixTreeFactory.cs     | 102 ----
 src/contrib/Spatial/Properties/AssemblyInfo.cs  |  63 ---
 src/contrib/Spatial/Queries/SpatialArgs.cs      | 142 ------
 .../Spatial/Queries/SpatialArgsParser.cs        | 140 ------
 src/contrib/Spatial/Queries/SpatialOperation.cs | 116 -----
 .../Queries/UnsupportedSpatialOperation.cs      |  29 --
 src/contrib/Spatial/SpatialStrategy.cs          | 150 ------
 src/contrib/Spatial/Util/Bits.cs                |  92 ----
 .../Spatial/Util/CachingDoubleValueSource.cs    | 101 ----
 .../Spatial/Util/CompatibilityExtensions.cs     | 296 -----------
 src/contrib/Spatial/Util/FixedBitSet.cs         | 454 -----------------
 src/contrib/Spatial/Util/FunctionQuery.cs       | 215 --------
 .../Spatial/Util/ReciprocalFloatFunction.cs     | 100 ----
 src/contrib/Spatial/Util/ShapeFieldCache.cs     |  55 ---
 .../Util/ShapeFieldCacheDistanceValueSource.cs  | 116 -----
 .../Spatial/Util/ShapeFieldCacheProvider.cs     | 105 ----
 .../Spatial/Util/TermsEnumCompatibility.cs      | 140 ------
 src/contrib/Spatial/Util/TermsFilter.cs         | 117 -----
 src/contrib/Spatial/Util/ValueSourceFilter.cs   |  72 ---
 .../Spatial/Vector/DistanceValueSource.cs       | 118 -----
 .../Spatial/Vector/PointVectorStrategy.cs       | 260 ----------
 76 files changed, 5872 insertions(+), 5872 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/BBox/AreaSimilarity.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/BBox/AreaSimilarity.cs b/src/Lucene.Net.Spatial/BBox/AreaSimilarity.cs
new file mode 100644
index 0000000..fde6e10
--- /dev/null
+++ b/src/Lucene.Net.Spatial/BBox/AreaSimilarity.cs
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+using System;
+using Lucene.Net.Search;
+using Spatial4n.Core.Context;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.BBox
+{
+    /// <summary>
+    /// The algorithm is implemented as envelope on envelope overlays rather than
+    /// complex polygon on complex polygon overlays.
+    /// <p/>
+    /// <p/>
+    /// Spatial relevance scoring algorithm:
+    /// <p/>
+    /// <br/>  queryArea = the area of the input query envelope
+    /// <br/>  targetArea = the area of the target envelope (per Lucene document)
+    /// <br/>  intersectionArea = the area of the intersection for the query/target envelopes
+    /// <br/>  queryPower = the weighting power associated with the query envelope (default = 1.0)
+    /// <br/>  targetPower =  the weighting power associated with the target envelope (default = 1.0)
+    /// <p/>
+    /// <br/>  queryRatio  = intersectionArea / queryArea;
+    /// <br/>  targetRatio = intersectionArea / targetArea;
+    /// <br/>  queryFactor  = Math.pow(queryRatio,queryPower);
+    /// <br/>  targetFactor = Math.pow(targetRatio,targetPower);
+    /// <br/>  score = queryFactor /// targetFactor;
+    /// <p/>
+    /// Based on Geoportal's
+    /// <a href="http://geoportal.svn.sourceforge.net/svnroot/geoportal/Geoportal/trunk/src/com/esri/gpt/catalog/lucene/SpatialRankingValueSource.java">
+    ///   SpatialRankingValueSource</a>.
+    ///
+    /// @lucene.experimental
+    /// </summary>
+    public class AreaSimilarity : BBoxSimilarity
+    {
+       /*
+        * Properties associated with the query envelope
+        */
+        private readonly Rectangle queryExtent;
+        private readonly double queryArea;
+
+        private readonly double targetPower;
+        private readonly double queryPower;
+
+        public AreaSimilarity(Rectangle queryExtent, double queryPower, double targetPower)
+        {
+            this.queryExtent = queryExtent;
+            this.queryArea = queryExtent.GetArea(null);
+
+            this.queryPower = queryPower;
+            this.targetPower = targetPower;
+
+            //  if (this.qryMinX > queryExtent.getMaxX()) {
+            //    this.qryCrossedDateline = true;
+            //    this.qryArea = Math.abs(qryMaxX + 360.0 - qryMinX) * Math.abs(qryMaxY - qryMinY);
+            //  } else {
+            //    this.qryArea = Math.abs(qryMaxX - qryMinX) * Math.abs(qryMaxY - qryMinY);
+            //  }
+        }
+
+        public AreaSimilarity(Rectangle queryExtent)
+            : this(queryExtent, 2.0, 0.5)
+        {
+        }
+
+        public String GetDelimiterQueryParameters()
+        {
+            return queryExtent + ";" + queryPower + ";" + targetPower;
+        }
+
+        public double Score(Rectangle target, Explanation exp)
+        {
+            if (target == null || queryArea <= 0)
+            {
+                return 0;
+            }
+            double targetArea = target.GetArea(null);
+            if (targetArea <= 0)
+            {
+                return 0;
+            }
+            double score = 0;
+
+            double top = Math.Min(queryExtent.GetMaxY(), target.GetMaxY());
+            double bottom = Math.Max(queryExtent.GetMinY(), target.GetMinY());
+            double height = top - bottom;
+            double width = 0;
+
+            // queries that cross the date line
+            if (queryExtent.GetCrossesDateLine())
+            {
+                // documents that cross the date line
+                if (target.GetCrossesDateLine())
+                {
+                    double left = Math.Max(queryExtent.GetMinX(), target.GetMinX());
+                    double right = Math.Min(queryExtent.GetMaxX(), target.GetMaxX());
+                    width = right + 360.0 - left;
+                }
+                else
+                {
+                    double qryWestLeft = Math.Max(queryExtent.GetMinX(), target.GetMaxX());
+                    double qryWestRight = Math.Min(target.GetMaxX(), 180.0);
+                    double qryWestWidth = qryWestRight - qryWestLeft;
+                    if (qryWestWidth > 0)
+                    {
+                        width = qryWestWidth;
+                    }
+                    else
+                    {
+                        double qryEastLeft = Math.Max(target.GetMaxX(), -180.0);
+                        double qryEastRight = Math.Min(queryExtent.GetMaxX(), target.GetMaxX());
+                        double qryEastWidth = qryEastRight - qryEastLeft;
+                        if (qryEastWidth > 0)
+                        {
+                            width = qryEastWidth;
+                        }
+                    }
+                }
+            }
+            else
+            { // queries that do not cross the date line
+
+                if (target.GetCrossesDateLine())
+                {
+                    double tgtWestLeft = Math.Max(queryExtent.GetMinX(), target.GetMinX());
+                    double tgtWestRight = Math.Min(queryExtent.GetMaxX(), 180.0);
+                    double tgtWestWidth = tgtWestRight - tgtWestLeft;
+                    if (tgtWestWidth > 0)
+                    {
+                        width = tgtWestWidth;
+                    }
+                    else
+                    {
+                        double tgtEastLeft = Math.Max(queryExtent.GetMinX(), -180.0);
+                        double tgtEastRight = Math.Min(queryExtent.GetMaxX(), target.GetMaxX());
+                        double tgtEastWidth = tgtEastRight - tgtEastLeft;
+                        if (tgtEastWidth > 0)
+                        {
+                            width = tgtEastWidth;
+                        }
+                    }
+                }
+                else
+                {
+                    double left = Math.Max(queryExtent.GetMinX(), target.GetMinX());
+                    double right = Math.Min(queryExtent.GetMaxX(), target.GetMaxX());
+                    width = right - left;
+                }
+            }
+
+
+            // calculate the score
+            if ((width > 0) && (height > 0))
+            {
+                double intersectionArea = width * height;
+                double queryRatio = intersectionArea / queryArea;
+                double targetRatio = intersectionArea / targetArea;
+                double queryFactor = Math.Pow(queryRatio, queryPower);
+                double targetFactor = Math.Pow(targetRatio, targetPower);
+                score = queryFactor * targetFactor * 10000.0;
+
+                if (exp != null)
+                {
+                    //        StringBuilder sb = new StringBuilder();
+                    //        sb.append("\nscore=").append(score);
+                    //        sb.append("\n  query=").append();
+                    //        sb.append("\n  target=").append(target.toString());
+                    //        sb.append("\n  intersectionArea=").append(intersectionArea);
+                    //        
+                    //        sb.append(" queryArea=").append(queryArea).append(" targetArea=").append(targetArea);
+                    //        sb.append("\n  queryRatio=").append(queryRatio).append(" targetRatio=").append(targetRatio);
+                    //        sb.append("\n  queryFactor=").append(queryFactor).append(" targetFactor=").append(targetFactor);
+                    //        sb.append(" (queryPower=").append(queryPower).append(" targetPower=").append(targetPower).append(")");
+
+                    exp.Value = (float) score;
+                    exp.Description = GetType().Name;
+
+                    Explanation e = null;
+
+                    exp.AddDetail(e = new Explanation((float)intersectionArea, "IntersectionArea"));
+                    e.AddDetail(new Explanation((float)width, "width; Query: " + queryExtent));
+                    e.AddDetail(new Explanation((float)height, "height; Target: " + target));
+
+                    exp.AddDetail(e = new Explanation((float)queryFactor, "Query"));
+                    e.AddDetail(new Explanation((float)queryArea, "area"));
+                    e.AddDetail(new Explanation((float)queryRatio, "ratio"));
+                    e.AddDetail(new Explanation((float)queryPower, "power"));
+
+                    exp.AddDetail(e = new Explanation((float)targetFactor, "Target"));
+                    e.AddDetail(new Explanation((float)targetArea, "area"));
+                    e.AddDetail(new Explanation((float)targetRatio, "ratio"));
+                    e.AddDetail(new Explanation((float)targetPower, "power"));
+                }
+            }
+            else if (exp != null)
+            {
+                exp.Value = 0;
+                exp.Description = "Shape does not intersect";
+            }
+            return score;
+        }
+
+        public override bool Equals(object obj)
+        {
+            var other = obj as AreaSimilarity;
+            if (other == null) return false;
+            return GetDelimiterQueryParameters().Equals(other.GetDelimiterQueryParameters());
+        }
+
+        public override int GetHashCode()
+        {
+            return GetDelimiterQueryParameters().GetHashCode();
+        } 
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/BBox/BBoxSimilarity.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/BBox/BBoxSimilarity.cs b/src/Lucene.Net.Spatial/BBox/BBoxSimilarity.cs
new file mode 100644
index 0000000..a18baa4
--- /dev/null
+++ b/src/Lucene.Net.Spatial/BBox/BBoxSimilarity.cs
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+using Lucene.Net.Search;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.BBox
+{
+    /// <summary>
+    /// Abstraction of the calculation used to determine how similar two Bounding Boxes are.
+    /// </summary>
+    public interface BBoxSimilarity
+    {
+        double Score(Rectangle extent, Explanation exp);
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/BBox/BBoxSimilarityValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/BBox/BBoxSimilarityValueSource.cs b/src/Lucene.Net.Spatial/BBox/BBoxSimilarityValueSource.cs
new file mode 100644
index 0000000..6939274
--- /dev/null
+++ b/src/Lucene.Net.Spatial/BBox/BBoxSimilarityValueSource.cs
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Search.Function;
+using Lucene.Net.Spatial.Util;
+using Spatial4n.Core.Shapes;
+using Spatial4n.Core.Shapes.Impl;
+
+namespace Lucene.Net.Spatial.BBox
+{
+    public class BBoxSimilarityValueSource : ValueSource
+    {
+        private readonly BBoxStrategy strategy;
+        private readonly BBoxSimilarity similarity;
+
+        public BBoxSimilarityValueSource(BBoxStrategy strategy, BBoxSimilarity similarity)
+        {
+            this.strategy = strategy;
+            this.similarity = similarity;
+        }
+
+        private class BBoxSimilarityValueSourceDocValues : DocValues
+        {
+            private readonly BBoxSimilarityValueSource _enclosingInstance;
+            private readonly Rectangle rect;
+            private readonly double[] minX;
+            private readonly double[] minY;
+            private readonly double[] maxX;
+            private readonly double[] maxY;
+
+            private readonly IBits validMinX, validMaxX;
+
+            public BBoxSimilarityValueSourceDocValues(IndexReader reader, BBoxSimilarityValueSource enclosingInstance)
+            {
+                _enclosingInstance = enclosingInstance;
+                rect = _enclosingInstance.strategy.GetSpatialContext().MakeRectangle(0, 0, 0, 0); //reused
+
+                minX = FieldCache_Fields.DEFAULT.GetDoubles(reader, enclosingInstance.strategy.field_minX/*, true*/);
+                minY = FieldCache_Fields.DEFAULT.GetDoubles(reader, enclosingInstance.strategy.field_minY/*, true*/);
+                maxX = FieldCache_Fields.DEFAULT.GetDoubles(reader, enclosingInstance.strategy.field_maxX/*, true*/);
+                maxY = FieldCache_Fields.DEFAULT.GetDoubles(reader, enclosingInstance.strategy.field_maxY/*, true*/);
+
+                validMinX = FieldCache_Fields.DEFAULT.GetDocsWithField(reader, enclosingInstance.strategy.field_minX);
+                validMaxX = FieldCache_Fields.DEFAULT.GetDocsWithField(reader, enclosingInstance.strategy.field_maxX);
+            }
+
+            public override float FloatVal(int doc)
+            {
+                // make sure it has minX and area
+                if (validMinX.Get(doc) && validMaxX.Get(doc))
+                {
+                    rect.Reset(
+                        minX[doc], maxX[doc],
+                        minY[doc], maxY[doc]);
+                    return (float) _enclosingInstance.similarity.Score(rect, null);
+                }
+                else
+                {
+                    return (float) _enclosingInstance.similarity.Score(null, null);
+                }
+            }
+
+            public override Explanation Explain(int doc)
+            {
+                // make sure it has minX and area
+                if (validMinX.Get(doc) && validMaxX.Get(doc))
+                {
+                    rect.Reset(
+                        minX[doc], maxX[doc],
+                        minY[doc], maxY[doc]);
+                    var exp = new Explanation();
+                    _enclosingInstance.similarity.Score(rect, exp);
+                    return exp;
+                }
+                return new Explanation(0, "No BBox");
+            }
+
+            public override string ToString(int doc)
+            {
+                return _enclosingInstance.Description() + "=" + FloatVal(doc);
+            }
+        }
+
+        public override DocValues GetValues(IndexReader reader)
+        {
+            return new BBoxSimilarityValueSourceDocValues(reader, this);
+        }
+
+        public override string Description()
+        {
+            return "BBoxSimilarityValueSource(" + similarity + ")";
+        }
+
+        public override bool Equals(object o)
+        {
+            var other = o as BBoxSimilarityValueSource;
+            if (other == null) return false;
+            return similarity.Equals(other.similarity);
+        }
+
+        public override int GetHashCode()
+        {
+            return typeof(BBoxSimilarityValueSource).GetHashCode() + similarity.GetHashCode();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/BBox/BBoxStrategy.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/BBox/BBoxStrategy.cs b/src/Lucene.Net.Spatial/BBox/BBoxStrategy.cs
new file mode 100644
index 0000000..f14af08
--- /dev/null
+++ b/src/Lucene.Net.Spatial/BBox/BBoxStrategy.cs
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+using System;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Search.Function;
+using Lucene.Net.Spatial.Queries;
+using Lucene.Net.Spatial.Util;
+using Spatial4n.Core.Context;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.BBox
+{
+    public class BBoxStrategy : SpatialStrategy
+    {
+        public static String SUFFIX_MINX = "__minX";
+        public static String SUFFIX_MAXX = "__maxX";
+        public static String SUFFIX_MINY = "__minY";
+        public static String SUFFIX_MAXY = "__maxY";
+        public static String SUFFIX_XDL = "__xdl";
+
+        /*
+         * The Bounding Box gets stored as four fields for x/y min/max and a flag
+         * that says if the box crosses the dateline (xdl).
+         */
+        public readonly String field_bbox;
+        public readonly String field_minX;
+        public readonly String field_minY;
+        public readonly String field_maxX;
+        public readonly String field_maxY;
+        public readonly String field_xdl; // crosses dateline
+
+        public readonly double queryPower = 1.0;
+        public readonly double targetPower = 1.0f;
+        public int precisionStep = 8; // same as solr default
+
+        public BBoxStrategy(SpatialContext ctx, String fieldNamePrefix)
+            : base(ctx, fieldNamePrefix)
+        {
+            field_bbox = fieldNamePrefix;
+            field_minX = fieldNamePrefix + SUFFIX_MINX;
+            field_maxX = fieldNamePrefix + SUFFIX_MAXX;
+            field_minY = fieldNamePrefix + SUFFIX_MINY;
+            field_maxY = fieldNamePrefix + SUFFIX_MAXY;
+            field_xdl = fieldNamePrefix + SUFFIX_XDL;
+        }
+
+        public void SetPrecisionStep(int p)
+        {
+            precisionStep = p;
+            if (precisionStep <= 0 || precisionStep >= 64)
+                precisionStep = int.MaxValue;
+        }
+
+        //---------------------------------
+        // Indexing
+        //---------------------------------
+
+        public override AbstractField[] CreateIndexableFields(Shape shape)
+        {
+            var rect = shape as Rectangle;
+            if (rect != null)
+                return CreateIndexableFields(rect);
+            throw new InvalidOperationException("Can only index Rectangle, not " + shape);
+        }
+
+        public AbstractField[] CreateIndexableFields(Rectangle bbox)
+        {
+            var fields = new AbstractField[5];
+            fields[0] = DoubleField(field_minX, bbox.GetMinX());
+            fields[1] = DoubleField(field_maxX, bbox.GetMaxX());
+            fields[2] = DoubleField(field_minY, bbox.GetMinY());
+            fields[3] = DoubleField(field_maxY, bbox.GetMaxY());
+            fields[4] = new Field(field_xdl, bbox.GetCrossesDateLine() ? "T" : "F", Field.Store.NO,
+                                  Field.Index.NOT_ANALYZED_NO_NORMS) {OmitNorms = true, OmitTermFreqAndPositions = true};
+            return fields;
+        }
+
+        private AbstractField DoubleField(string field, double value)
+        {
+            var f = new NumericField(field, precisionStep, Field.Store.NO, true)
+                        {OmitNorms = true, OmitTermFreqAndPositions = true};
+            f.SetDoubleValue(value);
+            return f;
+        }
+
+        public override ValueSource MakeDistanceValueSource(Point queryPoint)
+        {
+            return new BBoxSimilarityValueSource(this, new DistanceSimilarity(this.GetSpatialContext(), queryPoint));
+        }
+
+        public ValueSource MakeBBoxAreaSimilarityValueSource(Rectangle queryBox)
+        {
+            return new BBoxSimilarityValueSource(
+                this, new AreaSimilarity(queryBox, queryPower, targetPower));
+        }
+
+        public override ConstantScoreQuery MakeQuery(SpatialArgs args)
+        {
+            return new ConstantScoreQuery(new QueryWrapperFilter(MakeSpatialQuery(args)));
+        }
+
+        public Query MakeQueryWithValueSource(SpatialArgs args, ValueSource valueSource)
+        {
+
+            var bq = new BooleanQuery();
+            var spatial = MakeFilter(args);
+            bq.Add(new ConstantScoreQuery(spatial), Occur.MUST);
+
+            // This part does the scoring
+            Query spatialRankingQuery = new FunctionQuery(valueSource);
+            bq.Add(spatialRankingQuery, Occur.MUST);
+            return bq;
+        }
+
+        public override Filter MakeFilter(SpatialArgs args)
+        {
+            return new QueryWrapperFilter(MakeSpatialQuery(args));
+        }
+
+        private Query MakeSpatialQuery(SpatialArgs args)
+        {
+            var bbox = args.Shape as Rectangle;
+            if (bbox == null)
+                throw new InvalidOperationException("Can only query by Rectangle, not " + args.Shape);
+
+            Query spatial = null;
+
+            // Useful for understanding Relations:
+            // http://edndoc.esri.com/arcsde/9.1/general_topics/understand_spatial_relations.htm
+            SpatialOperation op = args.Operation;
+            if (op == SpatialOperation.BBoxIntersects) spatial = MakeIntersects(bbox);
+            else if (op == SpatialOperation.BBoxWithin) spatial = MakeWithin(bbox);
+            else if (op == SpatialOperation.Contains) spatial = MakeContains(bbox);
+            else if (op == SpatialOperation.Intersects) spatial = MakeIntersects(bbox);
+            else if (op == SpatialOperation.IsEqualTo) spatial = MakeEquals(bbox);
+            else if (op == SpatialOperation.IsDisjointTo) spatial = MakeDisjoint(bbox);
+            else if (op == SpatialOperation.IsWithin) spatial = MakeWithin(bbox);
+            else if (op == SpatialOperation.Overlaps) spatial = MakeIntersects(bbox);
+            else
+            {
+                throw new UnsupportedSpatialOperation(op);
+            }
+            return spatial;
+        }
+
+        //-------------------------------------------------------------------------------
+        //
+        //-------------------------------------------------------------------------------
+
+        /// <summary>
+        /// Constructs a query to retrieve documents that fully contain the input envelope.
+        /// </summary>
+        /// <param name="bbox"></param>
+        /// <returns>The spatial query</returns>
+        protected Query MakeContains(Rectangle bbox)
+        {
+
+            // general case
+            // docMinX <= queryExtent.GetMinX() AND docMinY <= queryExtent.GetMinY() AND docMaxX >= queryExtent.GetMaxX() AND docMaxY >= queryExtent.GetMaxY()
+
+            // Y conditions
+            // docMinY <= queryExtent.GetMinY() AND docMaxY >= queryExtent.GetMaxY()
+            Query qMinY = NumericRangeQuery.NewDoubleRange(field_minY, precisionStep, null, bbox.GetMinY(), false, true);
+            Query qMaxY = NumericRangeQuery.NewDoubleRange(field_maxY, precisionStep, bbox.GetMaxY(), null, true, false);
+            Query yConditions = this.MakeQuery(new Query[] { qMinY, qMaxY }, Occur.MUST);
+
+            // X conditions
+            Query xConditions = null;
+
+            // queries that do not cross the date line
+            if (!bbox.GetCrossesDateLine())
+            {
+
+                // X Conditions for documents that do not cross the date line,
+                // documents that contain the min X and max X of the query envelope,
+                // docMinX <= queryExtent.GetMinX() AND docMaxX >= queryExtent.GetMaxX()
+                Query qMinX = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, null, bbox.GetMinX(), false, true);
+                Query qMaxX = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, bbox.GetMaxX(), null, true, false);
+                Query qMinMax = this.MakeQuery(new Query[] { qMinX, qMaxX }, Occur.MUST);
+                Query qNonXDL = this.MakeXDL(false, qMinMax);
+
+                // X Conditions for documents that cross the date line,
+                // the left portion of the document contains the min X of the query
+                // OR the right portion of the document contains the max X of the query,
+                // docMinXLeft <= queryExtent.GetMinX() OR docMaxXRight >= queryExtent.GetMaxX()
+                Query qXDLLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, null, bbox.GetMinX(), false, true);
+                Query qXDLRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, bbox.GetMaxX(), null, true, false);
+                Query qXDLLeftRight = this.MakeQuery(new Query[] { qXDLLeft, qXDLRight }, Occur.SHOULD);
+                Query qXDL = this.MakeXDL(true, qXDLLeftRight);
+
+                // apply the non-XDL and XDL conditions
+                xConditions = this.MakeQuery(new Query[] { qNonXDL, qXDL }, Occur.SHOULD);
+
+                // queries that cross the date line
+            }
+            else
+            {
+
+                // No need to search for documents that do not cross the date line
+
+                // X Conditions for documents that cross the date line,
+                // the left portion of the document contains the min X of the query
+                // AND the right portion of the document contains the max X of the query,
+                // docMinXLeft <= queryExtent.GetMinX() AND docMaxXRight >= queryExtent.GetMaxX()
+                Query qXDLLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, null, bbox.GetMinX(), false, true);
+                Query qXDLRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, bbox.GetMaxX(), null, true, false);
+                Query qXDLLeftRight = this.MakeQuery(new Query[] { qXDLLeft, qXDLRight }, Occur.MUST);
+
+                xConditions = this.MakeXDL(true, qXDLLeftRight);
+            }
+
+            // both X and Y conditions must occur
+            return this.MakeQuery(new Query[] { xConditions, yConditions }, Occur.MUST);
+        }
+
+        /// <summary>
+        /// Constructs a query to retrieve documents that are disjoint to the input envelope.
+        /// </summary>
+        /// <param name="bbox"></param>
+        /// <returns>the spatial query</returns>
+        Query MakeDisjoint(Rectangle bbox)
+        {
+
+            // general case
+            // docMinX > queryExtent.GetMaxX() OR docMaxX < queryExtent.GetMinX() OR docMinY > queryExtent.GetMaxY() OR docMaxY < queryExtent.GetMinY()
+
+            // Y conditions
+            // docMinY > queryExtent.GetMaxY() OR docMaxY < queryExtent.GetMinY()
+            Query qMinY = NumericRangeQuery.NewDoubleRange(field_minY, precisionStep, bbox.GetMaxY(), null, false, false);
+            Query qMaxY = NumericRangeQuery.NewDoubleRange(field_maxY, precisionStep, null, bbox.GetMinY(), false, false);
+            Query yConditions = this.MakeQuery(new Query[] { qMinY, qMaxY }, Occur.SHOULD);
+
+            // X conditions
+            Query xConditions = null;
+
+            // queries that do not cross the date line
+            if (!bbox.GetCrossesDateLine())
+            {
+
+                // X Conditions for documents that do not cross the date line,
+                // docMinX > queryExtent.GetMaxX() OR docMaxX < queryExtent.GetMinX()
+                Query qMinX = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMaxX(), null, false, false);
+                Query qMaxX = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMinX(), false, false);
+                Query qMinMax = this.MakeQuery(new Query[] { qMinX, qMaxX }, Occur.SHOULD);
+                Query qNonXDL = this.MakeXDL(false, qMinMax);
+
+                // X Conditions for documents that cross the date line,
+                // both the left and right portions of the document must be disjoint to the query
+                // (docMinXLeft > queryExtent.GetMaxX() OR docMaxXLeft < queryExtent.GetMinX()) AND
+                // (docMinXRight > queryExtent.GetMaxX() OR docMaxXRight < queryExtent.GetMinX())
+                // where: docMaxXLeft = 180.0, docMinXRight = -180.0
+                // (docMaxXLeft  < queryExtent.GetMinX()) equates to (180.0  < queryExtent.GetMinX()) and is ignored
+                // (docMinXRight > queryExtent.GetMaxX()) equates to (-180.0 > queryExtent.GetMaxX()) and is ignored
+                Query qMinXLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMaxX(), null, false, false);
+                Query qMaxXRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMinX(), false, false);
+                Query qLeftRight = this.MakeQuery(new Query[] { qMinXLeft, qMaxXRight }, Occur.MUST);
+                Query qXDL = this.MakeXDL(true, qLeftRight);
+
+                // apply the non-XDL and XDL conditions
+                xConditions = this.MakeQuery(new Query[] { qNonXDL, qXDL }, Occur.SHOULD);
+
+                // queries that cross the date line
+            }
+            else
+            {
+
+                // X Conditions for documents that do not cross the date line,
+                // the document must be disjoint to both the left and right query portions
+                // (docMinX > queryExtent.GetMaxX()Left OR docMaxX < queryExtent.GetMinX()) AND (docMinX > queryExtent.GetMaxX() OR docMaxX < queryExtent.GetMinX()Left)
+                // where: queryExtent.GetMaxX()Left = 180.0, queryExtent.GetMinX()Left = -180.0
+                Query qMinXLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, 180.0, null, false, false);
+                Query qMaxXLeft = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMinX(), false, false);
+                Query qMinXRight = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMaxX(), null, false, false);
+                Query qMaxXRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, -180.0, false, false);
+                Query qLeft = this.MakeQuery(new Query[] { qMinXLeft, qMaxXLeft }, Occur.SHOULD);
+                Query qRight = this.MakeQuery(new Query[] { qMinXRight, qMaxXRight }, Occur.SHOULD);
+                Query qLeftRight = this.MakeQuery(new Query[] { qLeft, qRight }, Occur.MUST);
+
+                // No need to search for documents that do not cross the date line
+
+                xConditions = this.MakeXDL(false, qLeftRight);
+            }
+
+            // either X or Y conditions should occur
+            return this.MakeQuery(new Query[] { xConditions, yConditions }, Occur.SHOULD);
+        }
+
+        /*
+         * Constructs a query to retrieve documents that equal the input envelope.
+         *
+         * @return the spatial query
+         */
+        public Query MakeEquals(Rectangle bbox)
+        {
+
+            // docMinX = queryExtent.GetMinX() AND docMinY = queryExtent.GetMinY() AND docMaxX = queryExtent.GetMaxX() AND docMaxY = queryExtent.GetMaxY()
+            Query qMinX = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMinX(), bbox.GetMinX(), true, true);
+            Query qMinY = NumericRangeQuery.NewDoubleRange(field_minY, precisionStep, bbox.GetMinY(), bbox.GetMinY(), true, true);
+            Query qMaxX = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, bbox.GetMaxX(), bbox.GetMaxX(), true, true);
+            Query qMaxY = NumericRangeQuery.NewDoubleRange(field_maxY, precisionStep, bbox.GetMaxY(), bbox.GetMaxY(), true, true);
+            
+            var bq = new BooleanQuery
+                         {
+                             {qMinX, Occur.MUST},
+                             {qMinY, Occur.MUST},
+                             {qMaxX, Occur.MUST},
+                             {qMaxY, Occur.MUST}
+                         };
+            return bq;
+        }
+
+        /// <summary>
+        /// Constructs a query to retrieve documents that intersect the input envelope.
+        /// </summary>
+        /// <param name="bbox"></param>
+        /// <returns>the spatial query</returns>
+        Query MakeIntersects(Rectangle bbox)
+        {
+
+            // the original intersects query does not work for envelopes that cross the date line,
+            // switch to a NOT Disjoint query
+
+            // MUST_NOT causes a problem when it's the only clause type within a BooleanQuery,
+            // to get round it we add all documents as a SHOULD
+
+            // there must be an envelope, it must not be disjoint
+            Query qDisjoint = MakeDisjoint(bbox);
+            Query qIsNonXDL = this.MakeXDL(false);
+            Query qIsXDL = this.MakeXDL(true);
+            Query qHasEnv = this.MakeQuery(new Query[] { qIsNonXDL, qIsXDL }, Occur.SHOULD);
+            var qNotDisjoint = new BooleanQuery {{qHasEnv, Occur.MUST}, {qDisjoint, Occur.MUST_NOT}};
+
+            //Query qDisjoint = makeDisjoint();
+            //BooleanQuery qNotDisjoint = new BooleanQuery();
+            //qNotDisjoint.add(new MatchAllDocsQuery(),BooleanClause.Occur.SHOULD);
+            //qNotDisjoint.add(qDisjoint,BooleanClause.Occur.MUST_NOT);
+            return qNotDisjoint;
+        }
+
+        /*
+         * Makes a boolean query based upon a collection of queries and a logical operator.
+         *
+         * @param queries the query collection
+         * @param occur the logical operator
+         * @return the query
+         */
+        BooleanQuery MakeQuery(Query[] queries, Occur occur)
+        {
+            var bq = new BooleanQuery();
+            foreach (Query query in queries)
+            {
+                bq.Add(query, occur);
+            }
+            return bq;
+        }
+
+        /*
+         * Constructs a query to retrieve documents are fully within the input envelope.
+         *
+         * @return the spatial query
+         */
+        Query MakeWithin(Rectangle bbox)
+        {
+
+            // general case
+            // docMinX >= queryExtent.GetMinX() AND docMinY >= queryExtent.GetMinY() AND docMaxX <= queryExtent.GetMaxX() AND docMaxY <= queryExtent.GetMaxY()
+
+            // Y conditions
+            // docMinY >= queryExtent.GetMinY() AND docMaxY <= queryExtent.GetMaxY()
+            Query qMinY = NumericRangeQuery.NewDoubleRange(field_minY, precisionStep, bbox.GetMinY(), null, true, false);
+            Query qMaxY = NumericRangeQuery.NewDoubleRange(field_maxY, precisionStep, null, bbox.GetMaxY(), false, true);
+            Query yConditions = this.MakeQuery(new Query[] { qMinY, qMaxY }, Occur.MUST);
+
+            // X conditions
+            Query xConditions = null;
+
+            // X Conditions for documents that cross the date line,
+            // the left portion of the document must be within the left portion of the query,
+            // AND the right portion of the document must be within the right portion of the query
+            // docMinXLeft >= queryExtent.GetMinX() AND docMaxXLeft <= 180.0
+            // AND docMinXRight >= -180.0 AND docMaxXRight <= queryExtent.GetMaxX()
+            Query qXDLLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMinX(), null, true, false);
+            Query qXDLRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMaxX(), false, true);
+            Query qXDLLeftRight = this.MakeQuery(new Query[] { qXDLLeft, qXDLRight }, Occur.MUST);
+            Query qXDL = this.MakeXDL(true, qXDLLeftRight);
+
+            // queries that do not cross the date line
+            if (!bbox.GetCrossesDateLine())
+            {
+
+                // X Conditions for documents that do not cross the date line,
+                // docMinX >= queryExtent.GetMinX() AND docMaxX <= queryExtent.GetMaxX()
+                Query qMinX = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMinX(), null, true, false);
+                Query qMaxX = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMaxX(), false, true);
+                Query qMinMax = this.MakeQuery(new Query[] { qMinX, qMaxX }, Occur.MUST);
+                Query qNonXDL = this.MakeXDL(false, qMinMax);
+
+                // apply the non-XDL or XDL X conditions
+                if ((bbox.GetMinX() <= -180.0) && bbox.GetMaxX() >= 180.0)
+                {
+                    xConditions = this.MakeQuery(new Query[] { qNonXDL, qXDL }, Occur.SHOULD);
+                }
+                else
+                {
+                    xConditions = qNonXDL;
+                }
+
+                // queries that cross the date line
+            }
+            else
+            {
+
+                // X Conditions for documents that do not cross the date line
+
+                // the document should be within the left portion of the query
+                // docMinX >= queryExtent.GetMinX() AND docMaxX <= 180.0
+                Query qMinXLeft = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, bbox.GetMinX(), null, true, false);
+                Query qMaxXLeft = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, 180.0, false, true);
+                Query qLeft = this.MakeQuery(new Query[] { qMinXLeft, qMaxXLeft }, Occur.MUST);
+
+                // the document should be within the right portion of the query
+                // docMinX >= -180.0 AND docMaxX <= queryExtent.GetMaxX()
+                Query qMinXRight = NumericRangeQuery.NewDoubleRange(field_minX, precisionStep, -180.0, null, true, false);
+                Query qMaxXRight = NumericRangeQuery.NewDoubleRange(field_maxX, precisionStep, null, bbox.GetMaxX(), false, true);
+                Query qRight = this.MakeQuery(new Query[] { qMinXRight, qMaxXRight }, Occur.MUST);
+
+                // either left or right conditions should occur,
+                // apply the left and right conditions to documents that do not cross the date line
+                Query qLeftRight = this.MakeQuery(new Query[] { qLeft, qRight }, Occur.SHOULD);
+                Query qNonXDL = this.MakeXDL(false, qLeftRight);
+
+                // apply the non-XDL and XDL conditions
+                xConditions = this.MakeQuery(new Query[] { qNonXDL, qXDL }, Occur.SHOULD);
+            }
+
+            // both X and Y conditions must occur
+            return this.MakeQuery(new Query[] { xConditions, yConditions }, Occur.MUST);
+        }
+
+        /*
+         * Constructs a query to retrieve documents that do or do not cross the date line.
+         *
+         *
+         * @param crossedDateLine <code>true</true> for documents that cross the date line
+         * @return the query
+         */
+        public Query MakeXDL(bool crossedDateLine)
+        {
+            // The 'T' and 'F' values match solr fields
+            return new TermQuery(new Term(field_xdl, crossedDateLine ? "T" : "F"));
+        }
+
+        /*
+         * Constructs a query to retrieve documents that do or do not cross the date line
+         * and match the supplied spatial query.
+         *
+         * @param crossedDateLine <code>true</true> for documents that cross the date line
+         * @param query the spatial query
+         * @return the query
+         */
+        public Query MakeXDL(bool crossedDateLine, Query query)
+        {
+            var bq = new BooleanQuery
+                         {{this.MakeXDL(crossedDateLine), Occur.MUST}, {query, Occur.MUST}};
+            return bq;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/BBox/DistanceSimilarity.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/BBox/DistanceSimilarity.cs b/src/Lucene.Net.Spatial/BBox/DistanceSimilarity.cs
new file mode 100644
index 0000000..9b7c88b
--- /dev/null
+++ b/src/Lucene.Net.Spatial/BBox/DistanceSimilarity.cs
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+using Lucene.Net.Search;
+using Spatial4n.Core.Context;
+using Spatial4n.Core.Distance;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.BBox
+{
+    /// <summary>
+    /// Returns the distance between the center of the indexed rectangle and the
+    /// query shape.
+    /// </summary>
+    public class DistanceSimilarity : BBoxSimilarity
+    {
+        private readonly Point queryPoint;
+        private readonly DistanceCalculator distCalc;
+        private readonly double nullValue;
+
+        public DistanceSimilarity(SpatialContext ctx, Point queryPoint)
+        {
+            this.queryPoint = queryPoint;
+            this.distCalc = ctx.GetDistCalc();
+            this.nullValue = (ctx.IsGeo() ? 180 : double.MaxValue);
+        }
+
+        public double Score(Rectangle indexRect, Explanation exp)
+        {
+            double score;
+            if (indexRect == null)
+            {
+                score = nullValue;
+            }
+            else
+            {
+                score = distCalc.Distance(queryPoint, indexRect.GetCenter());
+            }
+            if (exp != null)
+            {
+                exp.Value = (float) score;
+                exp.Description = GetType().Name;
+                exp.AddDetail(new Explanation(-1f, "" + queryPoint));
+                exp.AddDetail(new Explanation(-1f, "" + indexRect));
+            }
+            return score;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/Contrib.Spatial.NTS.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Contrib.Spatial.NTS.csproj b/src/Lucene.Net.Spatial/Contrib.Spatial.NTS.csproj
new file mode 100644
index 0000000..fc4e1b3
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Contrib.Spatial.NTS.csproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{02D030D0-C7B5-4561-8BDD-41408B2E2F41}</ProjectGuid>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Spatial</RootNamespace>
+    <AssemblyName>Lucene.Net.Contrib.Spatial.NTS</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial.NTS\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug35|AnyCPU' ">
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial.NTS\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial.NTS\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\..\build\bin\contrib\Spatial.NTS\Release\NET40\Lucene.Net.Contrib.Spatial.NTS.xml</DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release35|AnyCPU' ">
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial.NTS\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\..\build\bin\contrib\Spatial.NTS\Release\NET35\Lucene.Net.Contrib.Spatial.NTS.xml</DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>Lucene.Net.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Spatial4n.Core.NTS">
+      <HintPath>..\..\..\lib\Spatial4n\$(Framework)\Spatial4n.Core.NTS.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Condition="'$(Framework)' == 'NET35'" Include="System.Core" />
+    <Reference Include="System.Data" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BBox\AreaSimilarity.cs" />
+    <Compile Include="BBox\BBoxSimilarity.cs" />
+    <Compile Include="BBox\BBoxSimilarityValueSource.cs" />
+    <Compile Include="BBox\BBoxStrategy.cs" />
+    <Compile Include="BBox\DistanceSimilarity.cs" />
+    <Compile Include="Prefix\PointPrefixTreeFieldCacheProvider.cs" />
+    <Compile Include="Prefix\PrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\RecursivePrefixTreeFilter.cs" />
+    <Compile Include="Prefix\RecursivePrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\TermQueryPrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\Tree\GeohashPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\Node.cs" />
+    <Compile Include="Prefix\Tree\QuadPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\SpatialPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\SpatialPrefixTreeFactory.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Queries\SpatialArgs.cs" />
+    <Compile Include="Queries\SpatialArgsParser.cs" />
+    <Compile Include="Queries\SpatialOperation.cs" />
+    <Compile Include="Queries\UnsupportedSpatialOperation.cs" />
+    <Compile Include="SpatialStrategy.cs" />
+    <Compile Include="Util\Bits.cs" />
+    <Compile Include="Util\ReciprocalFloatFunction.cs" />
+    <Compile Include="Util\ShapeFieldCacheDistanceValueSource.cs" />
+    <Compile Include="Util\CachingDoubleValueSource.cs" />
+    <Compile Include="Util\CompatibilityExtensions.cs" />
+    <Compile Include="Util\FixedBitSet.cs" />
+    <Compile Include="Util\FunctionQuery.cs" />
+    <Compile Include="Util\ShapeFieldCache.cs" />
+    <Compile Include="Util\ShapeFieldCacheProvider.cs" />
+    <Compile Include="Util\TermsEnumCompatibility.cs" />
+    <Compile Include="Util\TermsFilter.cs" />
+    <Compile Include="Util\ValueSourceFilter.cs" />
+    <Compile Include="Vector\DistanceValueSource.cs" />
+    <Compile Include="Vector\PointVectorStrategy.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\core\Lucene.Net.csproj">
+      <Project>{5D4AD9BE-1FFB-41AB-9943-25737971BF57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.0">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Lucene.Net.snk" />
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/Contrib.Spatial.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Contrib.Spatial.csproj b/src/Lucene.Net.Spatial/Contrib.Spatial.csproj
new file mode 100644
index 0000000..ff13d0c
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Contrib.Spatial.csproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{35C347F4-24B2-4BE5-8117-A0E3001551CE}</ProjectGuid>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Spatial</RootNamespace>
+    <AssemblyName>Lucene.Net.Contrib.Spatial</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug35|AnyCPU' ">
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\Lucene.Net.Contrib.Spatial.XML</DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release35|AnyCPU' ">
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <Framework>$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</Framework>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\</OutputPath>
+    <DefineConstants>TRACE;$(Framework)</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\..\build\bin\contrib\Spatial\$(Configuration.Replace("35", ""))\$(Framework)\Lucene.Net.Contrib.Spatial.XML</DocumentationFile>
+    <NoWarn>618</NoWarn>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>Lucene.Net.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Spatial4n.Core">
+      <HintPath>..\..\..\lib\Spatial4n\$(Framework)\Spatial4n.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Condition="'$(Framework)' == 'NET35'" Include="System.Core" />
+    <Reference Include="System.Data" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BBox\AreaSimilarity.cs" />
+    <Compile Include="BBox\BBoxSimilarity.cs" />
+    <Compile Include="BBox\BBoxSimilarityValueSource.cs" />
+    <Compile Include="BBox\BBoxStrategy.cs" />
+    <Compile Include="BBox\DistanceSimilarity.cs" />
+    <Compile Include="Prefix\PointPrefixTreeFieldCacheProvider.cs" />
+    <Compile Include="Prefix\PrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\RecursivePrefixTreeFilter.cs" />
+    <Compile Include="Prefix\RecursivePrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\TermQueryPrefixTreeStrategy.cs" />
+    <Compile Include="Prefix\Tree\GeohashPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\Node.cs" />
+    <Compile Include="Prefix\Tree\QuadPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\SpatialPrefixTree.cs" />
+    <Compile Include="Prefix\Tree\SpatialPrefixTreeFactory.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Queries\SpatialArgs.cs" />
+    <Compile Include="Queries\SpatialArgsParser.cs" />
+    <Compile Include="Queries\SpatialOperation.cs" />
+    <Compile Include="Queries\UnsupportedSpatialOperation.cs" />
+    <Compile Include="SpatialStrategy.cs" />
+    <Compile Include="Util\Bits.cs" />
+    <Compile Include="Util\ReciprocalFloatFunction.cs" />
+    <Compile Include="Util\ShapeFieldCacheDistanceValueSource.cs" />
+    <Compile Include="Util\CachingDoubleValueSource.cs" />
+    <Compile Include="Util\CompatibilityExtensions.cs" />
+    <Compile Include="Util\FixedBitSet.cs" />
+    <Compile Include="Util\FunctionQuery.cs" />
+    <Compile Include="Util\ShapeFieldCache.cs" />
+    <Compile Include="Util\ShapeFieldCacheProvider.cs" />
+    <Compile Include="Util\TermsEnumCompatibility.cs" />
+    <Compile Include="Util\TermsFilter.cs" />
+    <Compile Include="Util\ValueSourceFilter.cs" />
+    <Compile Include="Vector\DistanceValueSource.cs" />
+    <Compile Include="Vector\PointVectorStrategy.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\core\Lucene.Net.csproj">
+      <Project>{5D4AD9BE-1FFB-41AB-9943-25737971BF57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.0">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Lucene.Net.snk" />
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/Overview.html
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Overview.html b/src/Lucene.Net.Spatial/Overview.html
new file mode 100644
index 0000000..536c2f2
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Overview.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<!--
+ 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.
+-->
+
+<html>
+	<head>
+		<title>Geographical filtering & sorting with Lucene</title>
+	</head>
+	<body>
+		<p>
+			This package makes it possible to filter and sort according to
+			geographical constraints.  For example, filter to include only
+			restaurants within 2 miles of a specified latitude/longitude, sorting
+			by distance ascending.
+		</p>
+		<p>
+			See <a href="http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html">here</a>
+			for details on the technical approach.
+		</p>
+		<p>
+			Unfortunately, this package is still very new, and has little to no
+			documentation.  It's best to look at the unit tests included in
+			the source distribution.
+		</p>
+	</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs b/src/Lucene.Net.Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
new file mode 100644
index 0000000..5a7c554
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+using System;
+using Lucene.Net.Index;
+using Lucene.Net.Spatial.Prefix.Tree;
+using Lucene.Net.Spatial.Util;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.Prefix
+{
+    /// <summary>
+    /// Implementation of {@link ShapeFieldCacheProvider} designed for {@link PrefixTreeStrategy}s.
+    /// 
+    /// Note, due to the fragmented representation of Shapes in these Strategies, this implementation
+    /// can only retrieve the central {@link Point} of the original Shapes.
+    /// </summary>
+    public class PointPrefixTreeFieldCacheProvider : ShapeFieldCacheProvider<Point>
+    {
+        readonly SpatialPrefixTree grid; //
+
+        public PointPrefixTreeFieldCacheProvider(SpatialPrefixTree grid, String shapeField, int defaultSize)
+            : base(shapeField, defaultSize)
+        {
+            this.grid = grid;
+        }
+
+        //A kluge that this is a field
+        private Node scanCell = null;
+
+        protected override Point ReadShape(Term term)
+        {
+            scanCell = grid.GetNode(term.Text, scanCell);
+            return scanCell.IsLeaf() ? scanCell.GetShape().GetCenter() : null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c9f901b2/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs b/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs
new file mode 100644
index 0000000..e15f6cd
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+using System;
+#if !NET35
+using System.Collections.Concurrent;
+#else
+using Lucene.Net.Support.Compatibility;
+#endif
+using System.Collections.Generic;
+using Lucene.Net.Analysis;
+using Lucene.Net.Analysis.Tokenattributes;
+using Lucene.Net.Documents;
+using Lucene.Net.Search.Function;
+using Lucene.Net.Spatial.Prefix.Tree;
+using Lucene.Net.Spatial.Queries;
+using Lucene.Net.Spatial.Util;
+using Spatial4n.Core.Shapes;
+
+namespace Lucene.Net.Spatial.Prefix
+{
+    /// <summary>
+    /// Abstract SpatialStrategy which provides common functionality for those 
+    /// Strategys which use {@link SpatialPrefixTree}s
+    /// </summary>
+    public abstract class PrefixTreeStrategy : SpatialStrategy
+    {
+        protected readonly SpatialPrefixTree grid;
+
+        private readonly IDictionary<String, PointPrefixTreeFieldCacheProvider> provider =
+            new ConcurrentDictionary<string, PointPrefixTreeFieldCacheProvider>();
+
+        protected int defaultFieldValuesArrayLen = 2;
+        protected double distErrPct = SpatialArgs.DEFAULT_DISTERRPCT; // [ 0 TO 0.5 ]
+
+        protected PrefixTreeStrategy(SpatialPrefixTree grid, String fieldName)
+            : base(grid.GetSpatialContext(), fieldName)
+        {
+            this.grid = grid;
+        }
+
+        /* Used in the in-memory ValueSource as a default ArrayList length for this field's array of values, per doc. */
+
+        public void SetDefaultFieldValuesArrayLen(int defaultFieldValuesArrayLen)
+        {
+            this.defaultFieldValuesArrayLen = defaultFieldValuesArrayLen;
+        }
+
+        /// <summary>
+        /// The default measure of shape precision affecting indexed and query shapes.
+        /// Specific shapes at index and query time can use something different.
+        /// @see org.apache.lucene.spatial.query.SpatialArgs#getDistErrPct()
+        /// </summary>
+        public double DistErrPct { get; set; }
+
+        public override AbstractField[] CreateIndexableFields(Shape shape)
+        {
+            double distErr = SpatialArgs.CalcDistanceFromErrPct(shape, distErrPct, ctx);
+            return CreateIndexableFields(shape, distErr);
+        }
+
+        public AbstractField[] CreateIndexableFields(Shape shape, double distErr)
+        {
+            int detailLevel = grid.GetLevelForDistance(distErr);
+            var cells = grid.GetNodes(shape, detailLevel, true);//true=intermediates cells
+            //If shape isn't a point, add a full-resolution center-point so that
+            // PointPrefixTreeFieldCacheProvider has the center-points.
+            // TODO index each center of a multi-point? Yes/no?
+            if (!(shape is Point))
+            {
+                Point ctr = shape.GetCenter();
+                //TODO should be smarter; don't index 2 tokens for this in CellTokenStream. Harmless though.
+                cells.Add(grid.GetNodes(ctr, grid.GetMaxLevels(), false)[0]);
+            }
+
+            //TODO is CellTokenStream supposed to be re-used somehow? see Uwe's comments:
+            //  http://code.google.com/p/lucene-spatial-playground/issues/detail?id=4
+
+            return new AbstractField[]
+                       {
+                           new Field(GetFieldName(), new CellTokenStream(cells.GetEnumerator()))
+                               {OmitNorms = true, OmitTermFreqAndPositions = true}
+                       };
+        }
+
+        /// <summary>
+        /// Outputs the tokenString of a cell, and if its a leaf, outputs it again with the leaf byte.
+        /// </summary>
+        protected class CellTokenStream : TokenStream
+        {
+            private ITermAttribute termAtt;
+            private readonly IEnumerator<Node> iter;
+
+            public CellTokenStream(IEnumerator<Node> tokens)
+            {
+                this.iter = tokens;
+                Init();
+            }
+
+            private void Init()
+            {
+                termAtt = AddAttribute<ITermAttribute>();
+            }
+
+            private string nextTokenStringNeedingLeaf;
+
+            public override bool IncrementToken()
+            {
+                ClearAttributes();
+                if (nextTokenStringNeedingLeaf != null)
+                {
+                    termAtt.Append(nextTokenStringNeedingLeaf);
+                    termAtt.Append((char)Node.LEAF_BYTE);
+                    nextTokenStringNeedingLeaf = null;
+                    return true;
+                }
+                if (iter.MoveNext())
+                {
+                    Node cell = iter.Current;
+                    var token = cell.GetTokenString();
+                    termAtt.Append(token);
+                    if (cell.IsLeaf())
+                        nextTokenStringNeedingLeaf = token;
+                    return true;
+                }
+                return false;
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+            }
+        }
+
+        public ShapeFieldCacheProvider<Point> GetCacheProvider()
+        {
+            PointPrefixTreeFieldCacheProvider p;
+            if (!provider.TryGetValue(GetFieldName(), out p) || p == null)
+            {
+                lock (this)
+                {//double checked locking idiom is okay since provider is threadsafe
+                    if (!provider.ContainsKey(GetFieldName()))
+                    {
+                        p = new PointPrefixTreeFieldCacheProvider(grid, GetFieldName(), defaultFieldValuesArrayLen);
+                        provider[GetFieldName()] = p;
+                    }
+                }
+            }
+            return p;
+        }
+
+        public override ValueSource MakeDistanceValueSource(Point queryPoint)
+        {
+            var p = (PointPrefixTreeFieldCacheProvider)GetCacheProvider();
+            return new ShapeFieldCacheDistanceValueSource(ctx, p, queryPoint);
+        }
+
+        public SpatialPrefixTree GetGrid()
+        {
+            return grid;
+        }
+    }
+}


Mime
View raw message